Compare commits
15 Commits
8a187b45b9
...
v1.4.3
| Author | SHA1 | Date | |
|---|---|---|---|
| 31bcc1cc82 | |||
| 1166e8c5d3 | |||
| 8e94c232b4 | |||
| b00c52baa3 | |||
| 0dc350d534 | |||
| ac565e4b85 | |||
| 0808e027a5 | |||
| fc48b37ee7 | |||
| 026467c6db | |||
| e852c773e7 | |||
| 69a4d5a084 | |||
| e13a81e31e | |||
| 0624795370 | |||
| e4a77fdea3 | |||
| 22e8717e0c |
@@ -65,18 +65,20 @@ jobs:
|
|||||||
api-unit:
|
api-unit:
|
||||||
name: API Unit Tests
|
name: API Unit Tests
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
container:
|
||||||
|
image: ghcr.io/astral-sh/uv:python3.12-bookworm
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- name: Install Node (for JS actions)
|
||||||
|
|
||||||
- name: Install uv
|
|
||||||
run: |
|
run: |
|
||||||
curl -LsSf https://astral.sh/uv/install.sh | sh
|
apt-get update -qq
|
||||||
echo "$HOME/.local/bin" >> $GITHUB_PATH
|
apt-get install -y --no-install-recommends nodejs ca-certificates curl
|
||||||
|
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Cache uv store
|
- name: Cache uv store
|
||||||
uses: actions/cache@v3
|
uses: actions/cache@v3
|
||||||
with:
|
with:
|
||||||
path: ~/.cache/uv
|
path: /root/.cache/uv
|
||||||
key: uv-${{ hashFiles('api/uv.lock') }}
|
key: uv-${{ hashFiles('api/uv.lock') }}
|
||||||
restore-keys: uv-
|
restore-keys: uv-
|
||||||
|
|
||||||
@@ -95,25 +97,32 @@ jobs:
|
|||||||
S3_SECRET_ACCESS_KEY: secret
|
S3_SECRET_ACCESS_KEY: secret
|
||||||
S3_REGION: us-east-1
|
S3_REGION: us-east-1
|
||||||
API_BASE_URL: http://localhost:8000
|
API_BASE_URL: http://localhost:8000
|
||||||
JWT_SECRET_KEY: test-secret
|
JWT_SECRET_KEY: d34db33fc4f3b00bd34db33fc4f3b00b
|
||||||
OWNER_USERNAME: testowner
|
OWNER_USERNAME: testowner
|
||||||
OWNER_PASSWORD: testpass
|
OWNER_PASSWORD: testpassword
|
||||||
|
|
||||||
api-lint:
|
api-lint:
|
||||||
name: API Lint
|
name: API Lint
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
container:
|
||||||
|
image: ghcr.io/astral-sh/uv:python3.12-bookworm
|
||||||
steps:
|
steps:
|
||||||
|
- name: Install Node (for JS actions)
|
||||||
|
run: |
|
||||||
|
apt-get update -qq
|
||||||
|
apt-get install -y --no-install-recommends nodejs ca-certificates curl
|
||||||
|
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Run Ruff
|
- name: Run Ruff
|
||||||
run: |
|
run: uvx ruff check .
|
||||||
curl -LsSf https://astral.sh/uv/install.sh | sh
|
|
||||||
~/.local/bin/uvx ruff check .
|
|
||||||
working-directory: api
|
working-directory: api
|
||||||
|
|
||||||
api-integration:
|
api-integration:
|
||||||
name: API Integration Tests
|
name: API Integration Tests
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
container:
|
||||||
|
image: ghcr.io/astral-sh/uv:python3.12-bookworm
|
||||||
services:
|
services:
|
||||||
postgres:
|
postgres:
|
||||||
image: postgres:16
|
image: postgres:16
|
||||||
@@ -121,40 +130,34 @@ jobs:
|
|||||||
POSTGRES_USER: reactbin
|
POSTGRES_USER: reactbin
|
||||||
POSTGRES_PASSWORD: reactbin
|
POSTGRES_PASSWORD: reactbin
|
||||||
POSTGRES_DB: reactbin_test
|
POSTGRES_DB: reactbin_test
|
||||||
ports:
|
|
||||||
- 5432:5432
|
|
||||||
options: >-
|
options: >-
|
||||||
--health-cmd pg_isready
|
--health-cmd "pg_isready -U reactbin -d reactbin_test"
|
||||||
|
--health-interval 5s
|
||||||
|
--health-timeout 5s
|
||||||
|
--health-retries 10
|
||||||
|
minio:
|
||||||
|
image: bitnamilegacy/minio:2025.7.23-debian-12-r5
|
||||||
|
env:
|
||||||
|
MINIO_ROOT_USER: minioadmin
|
||||||
|
MINIO_ROOT_PASSWORD: minioadmin
|
||||||
|
MINIO_DEFAULT_BUCKETS: reactbin-test
|
||||||
|
options: >-
|
||||||
|
--health-cmd "mc ready local || exit 1"
|
||||||
--health-interval 5s
|
--health-interval 5s
|
||||||
--health-timeout 5s
|
--health-timeout 5s
|
||||||
--health-retries 10
|
--health-retries 10
|
||||||
steps:
|
steps:
|
||||||
|
- name: Install Node and curl (for JS actions and mc)
|
||||||
|
run: |
|
||||||
|
apt-get update -qq
|
||||||
|
apt-get install -y --no-install-recommends nodejs ca-certificates curl
|
||||||
|
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Start MinIO
|
|
||||||
run: |
|
|
||||||
docker run -d --name ci-minio \
|
|
||||||
--network container:$(hostname) \
|
|
||||||
-e MINIO_ROOT_USER=minioadmin \
|
|
||||||
-e MINIO_ROOT_PASSWORD=minioadmin \
|
|
||||||
quay.io/minio/minio server /data
|
|
||||||
|
|
||||||
- name: Create MinIO bucket
|
|
||||||
run: |
|
|
||||||
curl -fsSL https://dl.min.io/client/mc/release/linux-amd64/mc -o /tmp/mc
|
|
||||||
chmod +x /tmp/mc
|
|
||||||
until /tmp/mc alias set local http://localhost:9000 minioadmin minioadmin; do sleep 2; done
|
|
||||||
/tmp/mc mb local/reactbin-test
|
|
||||||
|
|
||||||
- name: Install uv
|
|
||||||
run: |
|
|
||||||
curl -LsSf https://astral.sh/uv/install.sh | sh
|
|
||||||
echo "$HOME/.local/bin" >> $GITHUB_PATH
|
|
||||||
|
|
||||||
- name: Cache uv store
|
- name: Cache uv store
|
||||||
uses: actions/cache@v3
|
uses: actions/cache@v3
|
||||||
with:
|
with:
|
||||||
path: ~/.cache/uv
|
path: /root/.cache/uv
|
||||||
key: uv-${{ hashFiles('api/uv.lock') }}
|
key: uv-${{ hashFiles('api/uv.lock') }}
|
||||||
restore-keys: uv-
|
restore-keys: uv-
|
||||||
|
|
||||||
@@ -166,21 +169,17 @@ jobs:
|
|||||||
run: uv run pytest tests/integration/ -q
|
run: uv run pytest tests/integration/ -q
|
||||||
working-directory: api
|
working-directory: api
|
||||||
env:
|
env:
|
||||||
TEST_DATABASE_URL: postgresql+asyncpg://reactbin:reactbin@localhost/reactbin_test
|
TEST_DATABASE_URL: postgresql+asyncpg://reactbin:reactbin@postgres/reactbin_test
|
||||||
DATABASE_URL: postgresql+asyncpg://reactbin:reactbin@localhost/reactbin_test
|
DATABASE_URL: postgresql+asyncpg://reactbin:reactbin@postgres/reactbin_test
|
||||||
S3_ENDPOINT_URL: http://localhost:9000
|
S3_ENDPOINT_URL: http://minio:9000
|
||||||
S3_BUCKET_NAME: reactbin-test
|
S3_BUCKET_NAME: reactbin-test
|
||||||
S3_ACCESS_KEY_ID: minioadmin
|
S3_ACCESS_KEY_ID: minioadmin
|
||||||
S3_SECRET_ACCESS_KEY: minioadmin
|
S3_SECRET_ACCESS_KEY: minioadmin
|
||||||
S3_REGION: us-east-1
|
S3_REGION: us-east-1
|
||||||
API_BASE_URL: http://localhost:8000
|
API_BASE_URL: http://localhost:8000
|
||||||
JWT_SECRET_KEY: test-secret
|
JWT_SECRET_KEY: d34db33fc4f3b00bd34db33fc4f3b00b
|
||||||
OWNER_USERNAME: testowner
|
OWNER_USERNAME: testowner
|
||||||
OWNER_PASSWORD: testpass
|
OWNER_PASSWORD: testpassword
|
||||||
|
|
||||||
- name: Stop MinIO
|
|
||||||
if: always()
|
|
||||||
run: docker stop ci-minio && docker rm ci-minio || true
|
|
||||||
|
|
||||||
# ── Image builds (tag-only, gated on all jobs) ────────────────────────────────
|
# ── Image builds (tag-only, gated on all jobs) ────────────────────────────────
|
||||||
|
|
||||||
|
|||||||
@@ -18,6 +18,13 @@ hooks:
|
|||||||
prompt: Execute speckit.git.feature?
|
prompt: Execute speckit.git.feature?
|
||||||
description: Create feature branch before specification
|
description: Create feature branch before specification
|
||||||
condition: null
|
condition: null
|
||||||
|
- extension: memory-loader
|
||||||
|
command: speckit.memory-loader.load
|
||||||
|
enabled: true
|
||||||
|
optional: false
|
||||||
|
prompt: Execute speckit.memory-loader.load?
|
||||||
|
description: Load project memory files before specification
|
||||||
|
condition: null
|
||||||
before_clarify:
|
before_clarify:
|
||||||
- extension: git
|
- extension: git
|
||||||
command: speckit.git.commit
|
command: speckit.git.commit
|
||||||
@@ -26,6 +33,13 @@ hooks:
|
|||||||
prompt: Commit outstanding changes before clarification?
|
prompt: Commit outstanding changes before clarification?
|
||||||
description: Auto-commit before spec clarification
|
description: Auto-commit before spec clarification
|
||||||
condition: null
|
condition: null
|
||||||
|
- extension: memory-loader
|
||||||
|
command: speckit.memory-loader.load
|
||||||
|
enabled: true
|
||||||
|
optional: false
|
||||||
|
prompt: Execute speckit.memory-loader.load?
|
||||||
|
description: Load project memory files before clarification
|
||||||
|
condition: null
|
||||||
before_plan:
|
before_plan:
|
||||||
- extension: git
|
- extension: git
|
||||||
command: speckit.git.commit
|
command: speckit.git.commit
|
||||||
@@ -34,6 +48,13 @@ hooks:
|
|||||||
prompt: Commit outstanding changes before planning?
|
prompt: Commit outstanding changes before planning?
|
||||||
description: Auto-commit before implementation planning
|
description: Auto-commit before implementation planning
|
||||||
condition: null
|
condition: null
|
||||||
|
- extension: memory-loader
|
||||||
|
command: speckit.memory-loader.load
|
||||||
|
enabled: true
|
||||||
|
optional: false
|
||||||
|
prompt: Execute speckit.memory-loader.load?
|
||||||
|
description: Load project memory files before planning
|
||||||
|
condition: null
|
||||||
before_tasks:
|
before_tasks:
|
||||||
- extension: git
|
- extension: git
|
||||||
command: speckit.git.commit
|
command: speckit.git.commit
|
||||||
@@ -42,6 +63,13 @@ hooks:
|
|||||||
prompt: Commit outstanding changes before task generation?
|
prompt: Commit outstanding changes before task generation?
|
||||||
description: Auto-commit before task generation
|
description: Auto-commit before task generation
|
||||||
condition: null
|
condition: null
|
||||||
|
- extension: memory-loader
|
||||||
|
command: speckit.memory-loader.load
|
||||||
|
enabled: true
|
||||||
|
optional: false
|
||||||
|
prompt: Execute speckit.memory-loader.load?
|
||||||
|
description: Load project memory files before task generation
|
||||||
|
condition: null
|
||||||
before_implement:
|
before_implement:
|
||||||
- extension: git
|
- extension: git
|
||||||
command: speckit.git.commit
|
command: speckit.git.commit
|
||||||
@@ -50,6 +78,13 @@ hooks:
|
|||||||
prompt: Commit outstanding changes before implementation?
|
prompt: Commit outstanding changes before implementation?
|
||||||
description: Auto-commit before implementation
|
description: Auto-commit before implementation
|
||||||
condition: null
|
condition: null
|
||||||
|
- extension: memory-loader
|
||||||
|
command: speckit.memory-loader.load
|
||||||
|
enabled: true
|
||||||
|
optional: false
|
||||||
|
prompt: Execute speckit.memory-loader.load?
|
||||||
|
description: Load project memory files before implementation
|
||||||
|
condition: null
|
||||||
before_checklist:
|
before_checklist:
|
||||||
- extension: git
|
- extension: git
|
||||||
command: speckit.git.commit
|
command: speckit.git.commit
|
||||||
@@ -58,6 +93,13 @@ hooks:
|
|||||||
prompt: Commit outstanding changes before checklist?
|
prompt: Commit outstanding changes before checklist?
|
||||||
description: Auto-commit before checklist generation
|
description: Auto-commit before checklist generation
|
||||||
condition: null
|
condition: null
|
||||||
|
- extension: memory-loader
|
||||||
|
command: speckit.memory-loader.load
|
||||||
|
enabled: true
|
||||||
|
optional: false
|
||||||
|
prompt: Execute speckit.memory-loader.load?
|
||||||
|
description: Load project memory files before checklist generation
|
||||||
|
condition: null
|
||||||
before_analyze:
|
before_analyze:
|
||||||
- extension: git
|
- extension: git
|
||||||
command: speckit.git.commit
|
command: speckit.git.commit
|
||||||
@@ -66,6 +108,13 @@ hooks:
|
|||||||
prompt: Commit outstanding changes before analysis?
|
prompt: Commit outstanding changes before analysis?
|
||||||
description: Auto-commit before analysis
|
description: Auto-commit before analysis
|
||||||
condition: null
|
condition: null
|
||||||
|
- extension: memory-loader
|
||||||
|
command: speckit.memory-loader.load
|
||||||
|
enabled: true
|
||||||
|
optional: false
|
||||||
|
prompt: Execute speckit.memory-loader.load?
|
||||||
|
description: Load project memory files before analysis
|
||||||
|
condition: null
|
||||||
before_taskstoissues:
|
before_taskstoissues:
|
||||||
- extension: git
|
- extension: git
|
||||||
command: speckit.git.commit
|
command: speckit.git.commit
|
||||||
|
|||||||
@@ -18,6 +18,20 @@
|
|||||||
},
|
},
|
||||||
"registered_skills": [],
|
"registered_skills": [],
|
||||||
"installed_at": "2026-05-02T15:15:14.534434+00:00"
|
"installed_at": "2026-05-02T15:15:14.534434+00:00"
|
||||||
|
},
|
||||||
|
"memory-loader": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"source": "local",
|
||||||
|
"manifest_hash": "sha256:d1caef45965accd4316d8aede0a4ac67f910017ea3c501814cfc7e2d8177ab0b",
|
||||||
|
"enabled": true,
|
||||||
|
"priority": 10,
|
||||||
|
"registered_commands": {
|
||||||
|
"claude": [
|
||||||
|
"speckit.memory-loader.load"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"registered_skills": [],
|
||||||
|
"installed_at": "2026-05-11T20:50:02.702659+00:00"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
9
.specify/extensions/memory-loader/CHANGELOG.md
Normal file
9
.specify/extensions/memory-loader/CHANGELOG.md
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
# Changelog
|
||||||
|
|
||||||
|
## [1.0.0] - 2026-04-20
|
||||||
|
|
||||||
|
### Added
|
||||||
|
- Initial release
|
||||||
|
- `speckit.memory-loader.load` command to read all `.specify/memory/*.md` files
|
||||||
|
- `before_*` hooks for specify, plan, tasks, implement, clarify, checklist, and analyze lifecycle commands
|
||||||
|
- Graceful degradation when memory directory is missing or files are unreadable
|
||||||
21
.specify/extensions/memory-loader/LICENSE
Normal file
21
.specify/extensions/memory-loader/LICENSE
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2026 KevinBrown5280
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
81
.specify/extensions/memory-loader/README.md
Normal file
81
.specify/extensions/memory-loader/README.md
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
# spec-kit-memory-loader
|
||||||
|
|
||||||
|
A [Spec Kit](https://github.com/github/spec-kit) extension that loads `.specify/memory/` files before spec-kit lifecycle commands so LLM agents have project governance context (constitution, glossary, conventions, resource standards).
|
||||||
|
|
||||||
|
## Problem
|
||||||
|
|
||||||
|
Spec-kit lifecycle commands (`/speckit.specify`, `/speckit.plan`, `/speckit.implement`, etc.) execute without awareness of project-specific governance documents stored in `.specify/memory/`. This means:
|
||||||
|
|
||||||
|
- Constitution principles are not consulted during specification
|
||||||
|
- Glossary terms are not available during planning
|
||||||
|
- Coding conventions are missed during implementation
|
||||||
|
- Resource standards are ignored during task generation
|
||||||
|
|
||||||
|
## Solution
|
||||||
|
|
||||||
|
The Memory Loader extension registers `before_*` hooks on all major spec-kit lifecycle commands. Before each command runs, it reads every `.md` file from `.specify/memory/` and outputs their contents, giving the LLM agent full governance context.
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# From release
|
||||||
|
specify extension add memory-loader --from https://github.com/KevinBrown5280/spec-kit-memory-loader/archive/refs/tags/v1.0.0.zip
|
||||||
|
|
||||||
|
# From main branch
|
||||||
|
specify extension add memory-loader --from https://github.com/KevinBrown5280/spec-kit-memory-loader/archive/refs/heads/main.zip
|
||||||
|
|
||||||
|
# Development mode (local clone)
|
||||||
|
specify extension add --dev /path/to/spec-kit-memory-loader
|
||||||
|
```
|
||||||
|
|
||||||
|
## Commands
|
||||||
|
|
||||||
|
| Command | Description | Modifies Files? |
|
||||||
|
|---------|-------------|-----------------|
|
||||||
|
| `speckit.memory-loader.load` | Read all project memory files and output their contents for context | No — read-only |
|
||||||
|
|
||||||
|
## How It Works
|
||||||
|
|
||||||
|
1. **Gather**: Reads every `.md` file from `.specify/memory/`
|
||||||
|
- If the directory does not exist, skips silently
|
||||||
|
- If a file cannot be read, skips it and continues
|
||||||
|
|
||||||
|
2. **Output**: For each file, prints a headed section:
|
||||||
|
```
|
||||||
|
## Memory: {filename}
|
||||||
|
|
||||||
|
{file contents}
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **Summarize**: After all files, outputs:
|
||||||
|
```
|
||||||
|
Context loaded: {memory_count} memory files
|
||||||
|
```
|
||||||
|
|
||||||
|
## Hooks
|
||||||
|
|
||||||
|
The extension fires automatically before these lifecycle commands:
|
||||||
|
|
||||||
|
| Hook | Command | Description |
|
||||||
|
|------|---------|-------------|
|
||||||
|
| `before_specify` | `speckit.memory-loader.load` | Load context before specification |
|
||||||
|
| `before_plan` | `speckit.memory-loader.load` | Load context before planning |
|
||||||
|
| `before_tasks` | `speckit.memory-loader.load` | Load context before task generation |
|
||||||
|
| `before_implement` | `speckit.memory-loader.load` | Load context before implementation |
|
||||||
|
| `before_clarify` | `speckit.memory-loader.load` | Load context before clarification |
|
||||||
|
| `before_checklist` | `speckit.memory-loader.load` | Load context before checklist generation |
|
||||||
|
| `before_analyze` | `speckit.memory-loader.load` | Load context before analysis |
|
||||||
|
|
||||||
|
## Design Decisions
|
||||||
|
|
||||||
|
- **Read-only** — never modifies any files
|
||||||
|
- **Graceful degradation** — missing directory or unreadable files are skipped silently
|
||||||
|
- **Governance only** — loads project-level memory; feature-specific reference docs are handled separately by a companion extension
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
|
||||||
|
- Spec Kit >= 0.6.0
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
MIT
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
---
|
||||||
|
description: "Read all project memory files and output their contents for LLM context"
|
||||||
|
---
|
||||||
|
|
||||||
|
# Load Project Memory
|
||||||
|
|
||||||
|
Read ALL `.md` files in `.specify/memory/` and output their contents. This gives you project governance context (constitution, glossary, conventions, resource standards) for the command that follows.
|
||||||
|
|
||||||
|
## Steps
|
||||||
|
|
||||||
|
1. **Gather**: Read every `.md` file from `.specify/memory/`.
|
||||||
|
- If the directory does not exist, skip it silently.
|
||||||
|
- If a file cannot be read, skip it and continue.
|
||||||
|
|
||||||
|
2. **Output**: For each file, print a headed section:
|
||||||
|
|
||||||
|
```
|
||||||
|
## Memory: {filename}
|
||||||
|
|
||||||
|
{file contents}
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **Summarize**: After all files, output:
|
||||||
|
|
||||||
|
```
|
||||||
|
Context loaded: {memory_count} memory files
|
||||||
|
```
|
||||||
|
|
||||||
|
## Usage Notes
|
||||||
|
|
||||||
|
- Designed as a mandatory `before_*` hook that fires before spec-kit lifecycle commands.
|
||||||
|
- Loads governance context only. Feature-specific reference docs are loaded by the `spec-reference-loader` extension.
|
||||||
|
- This is a read-only operation — do NOT modify any files.
|
||||||
61
.specify/extensions/memory-loader/extension.yml
Normal file
61
.specify/extensions/memory-loader/extension.yml
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
schema_version: "1.0"
|
||||||
|
|
||||||
|
extension:
|
||||||
|
id: "memory-loader"
|
||||||
|
name: "Memory Loader"
|
||||||
|
version: "1.0.0"
|
||||||
|
description: "Loads .specify/memory/ files before spec-kit lifecycle commands so LLM agents have project governance context"
|
||||||
|
author: "KevinBrown5280"
|
||||||
|
repository: "https://github.com/KevinBrown5280/spec-kit-memory-loader"
|
||||||
|
license: "MIT"
|
||||||
|
homepage: "https://github.com/KevinBrown5280/spec-kit-memory-loader"
|
||||||
|
|
||||||
|
requires:
|
||||||
|
speckit_version: ">=0.6.0"
|
||||||
|
|
||||||
|
provides:
|
||||||
|
commands:
|
||||||
|
- name: "speckit.memory-loader.load"
|
||||||
|
file: "commands/speckit.memory-loader.load.md"
|
||||||
|
description: "Read all project memory files and output their contents for context"
|
||||||
|
|
||||||
|
hooks:
|
||||||
|
before_specify:
|
||||||
|
command: "speckit.memory-loader.load"
|
||||||
|
optional: false
|
||||||
|
description: "Load project memory files before specification"
|
||||||
|
|
||||||
|
before_plan:
|
||||||
|
command: "speckit.memory-loader.load"
|
||||||
|
optional: false
|
||||||
|
description: "Load project memory files before planning"
|
||||||
|
|
||||||
|
before_tasks:
|
||||||
|
command: "speckit.memory-loader.load"
|
||||||
|
optional: false
|
||||||
|
description: "Load project memory files before task generation"
|
||||||
|
|
||||||
|
before_implement:
|
||||||
|
command: "speckit.memory-loader.load"
|
||||||
|
optional: false
|
||||||
|
description: "Load project memory files before implementation"
|
||||||
|
|
||||||
|
before_clarify:
|
||||||
|
command: "speckit.memory-loader.load"
|
||||||
|
optional: false
|
||||||
|
description: "Load project memory files before clarification"
|
||||||
|
|
||||||
|
before_checklist:
|
||||||
|
command: "speckit.memory-loader.load"
|
||||||
|
optional: false
|
||||||
|
description: "Load project memory files before checklist generation"
|
||||||
|
|
||||||
|
before_analyze:
|
||||||
|
command: "speckit.memory-loader.load"
|
||||||
|
optional: false
|
||||||
|
description: "Load project memory files before analysis"
|
||||||
|
|
||||||
|
tags:
|
||||||
|
- "memory"
|
||||||
|
- "context"
|
||||||
|
- "governance"
|
||||||
@@ -6,5 +6,5 @@
|
|||||||
"here": true,
|
"here": true,
|
||||||
"integration": "claude",
|
"integration": "claude",
|
||||||
"script": "sh",
|
"script": "sh",
|
||||||
"speckit_version": "0.8.2.dev0"
|
"speckit_version": "0.8.8"
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,15 @@
|
|||||||
{
|
{
|
||||||
|
"version": "0.8.8",
|
||||||
|
"integration_state_schema": 1,
|
||||||
|
"installed_integrations": [
|
||||||
|
"claude"
|
||||||
|
],
|
||||||
|
"integration_settings": {
|
||||||
|
"claude": {
|
||||||
|
"script": "sh",
|
||||||
|
"invoke_separator": "-"
|
||||||
|
}
|
||||||
|
},
|
||||||
"integration": "claude",
|
"integration": "claude",
|
||||||
"version": "0.8.2.dev0"
|
"default_integration": "claude"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,16 +1,16 @@
|
|||||||
{
|
{
|
||||||
"integration": "claude",
|
"integration": "claude",
|
||||||
"version": "0.8.2.dev0",
|
"version": "0.8.8",
|
||||||
"installed_at": "2026-05-02T15:15:14.461699+00:00",
|
"installed_at": "2026-05-11T20:40:51.902830+00:00",
|
||||||
"files": {
|
"files": {
|
||||||
".claude/skills/speckit-analyze/SKILL.md": "2eef0fbff6cad15c9d4714d8986192387811c971a82a1135ab0404f3db0c5e90",
|
".claude/skills/speckit-analyze/SKILL.md": "2eef0fbff6cad15c9d4714d8986192387811c971a82a1135ab0404f3db0c5e90",
|
||||||
".claude/skills/speckit-checklist/SKILL.md": "26419fc118dcd9c4e1e977460696a04b7757b8fb0a2d1ff9c64732669deb7977",
|
".claude/skills/speckit-checklist/SKILL.md": "26419fc118dcd9c4e1e977460696a04b7757b8fb0a2d1ff9c64732669deb7977",
|
||||||
".claude/skills/speckit-clarify/SKILL.md": "f2560f9f2007b4e995130f0c42633f08837a76a35d94e84091713a6f39bb1064",
|
".claude/skills/speckit-clarify/SKILL.md": "f2560f9f2007b4e995130f0c42633f08837a76a35d94e84091713a6f39bb1064",
|
||||||
".claude/skills/speckit-constitution/SKILL.md": "c1a044aba243ca6aff627fb5e4404feb6f1108d4f7dd174631bee3ae477d6c15",
|
".claude/skills/speckit-constitution/SKILL.md": "c1a044aba243ca6aff627fb5e4404feb6f1108d4f7dd174631bee3ae477d6c15",
|
||||||
".claude/skills/speckit-implement/SKILL.md": "da9b4d6f9894d300515c66c057cee74025b27f2238895e3c22b59c6266b5be74",
|
".claude/skills/speckit-implement/SKILL.md": "6029565c1a56de8919d1846b187cd644f734a0e30a6067a709803e6bc0d2abf7",
|
||||||
".claude/skills/speckit-plan/SKILL.md": "8141ebbce228ad0b422a84e3b995d2bd85de917b96eadd02b5fcb56fb23f2594",
|
".claude/skills/speckit-plan/SKILL.md": "8141ebbce228ad0b422a84e3b995d2bd85de917b96eadd02b5fcb56fb23f2594",
|
||||||
".claude/skills/speckit-specify/SKILL.md": "8599f8e2e3463de7d4f47591565340be2f775fd61b7dd9d2175503bc3b713b77",
|
".claude/skills/speckit-specify/SKILL.md": "caadc05119eca453709a0425ed88d253883f9c55da4c13a4898367653a859483",
|
||||||
".claude/skills/speckit-tasks/SKILL.md": "792589edf0ebf89af797c6bdda4e9d2c9938c696181d6f1484bf7a7cd090efaa",
|
".claude/skills/speckit-tasks/SKILL.md": "54c4665be61818ed50aa528bb4c51db3627079b2c67d47f2b01046268288c4a5",
|
||||||
".claude/skills/speckit-taskstoissues/SKILL.md": "99bf5ffd90dcb57b63007c7f659a5160a18ce6feb82889895808e2d277abe83b"
|
".claude/skills/speckit-taskstoissues/SKILL.md": "99bf5ffd90dcb57b63007c7f659a5160a18ce6feb82889895808e2d277abe83b"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"integration": "speckit",
|
"integration": "speckit",
|
||||||
"version": "0.8.2.dev0",
|
"version": "0.8.8",
|
||||||
"installed_at": "2026-05-02T15:15:14.478105+00:00",
|
"installed_at": "2026-05-02T15:15:14.478105+00:00",
|
||||||
"files": {
|
"files": {
|
||||||
".specify/scripts/bash/create-new-feature.sh": "bcf4964ca0c6c78717bb42d9e66b8c7e5ee82779cd96afc5aa7b08b75abe5790",
|
".specify/scripts/bash/create-new-feature.sh": "bcf4964ca0c6c78717bb42d9e66b8c7e5ee82779cd96afc5aa7b08b75abe5790",
|
||||||
@@ -11,6 +11,7 @@
|
|||||||
".specify/templates/plan-template.md": "5ad267630e370c73fe957dafa61bf76d633f3aea9d2f0b5195087d729cdd1e41",
|
".specify/templates/plan-template.md": "5ad267630e370c73fe957dafa61bf76d633f3aea9d2f0b5195087d729cdd1e41",
|
||||||
".specify/templates/constitution-template.md": "ce7549540fa45543cca797a150201d868e64495fdff39dc38246fb17bd4024b3",
|
".specify/templates/constitution-template.md": "ce7549540fa45543cca797a150201d868e64495fdff39dc38246fb17bd4024b3",
|
||||||
".specify/templates/spec-template.md": "785dc50d856dd92d6515eca0761e16dce0c9ba0a3cd07154fd33eae77932422a",
|
".specify/templates/spec-template.md": "785dc50d856dd92d6515eca0761e16dce0c9ba0a3cd07154fd33eae77932422a",
|
||||||
".specify/templates/checklist-template.md": "c37695297e5d3153d64f82c21223509940b13932046c7961c42d1d669516130c"
|
".specify/templates/checklist-template.md": "c37695297e5d3153d64f82c21223509940b13932046c7961c42d1d669516130c",
|
||||||
|
".specify/scripts/bash/setup-tasks.sh": "e8d050c63c5afb664a8b671b0b0155513fb9cab0567b335e16b9eb035482aad2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
96
.specify/scripts/bash/setup-tasks.sh
Executable file
96
.specify/scripts/bash/setup-tasks.sh
Executable file
@@ -0,0 +1,96 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# Parse command line arguments
|
||||||
|
JSON_MODE=false
|
||||||
|
|
||||||
|
for arg in "$@"; do
|
||||||
|
case "$arg" in
|
||||||
|
--json) JSON_MODE=true ;;
|
||||||
|
--help|-h)
|
||||||
|
echo "Usage: $0 [--json]"
|
||||||
|
echo " --json Output results in JSON format"
|
||||||
|
echo " --help Show this help message"
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
*) echo "ERROR: Unknown option '$arg'" >&2; exit 1 ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
# Source common functions
|
||||||
|
SCRIPT_DIR="$(CDPATH="" cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
source "$SCRIPT_DIR/common.sh"
|
||||||
|
|
||||||
|
# Get feature paths
|
||||||
|
_paths_output=$(get_feature_paths) || { echo "ERROR: Failed to resolve feature paths" >&2; exit 1; }
|
||||||
|
eval "$_paths_output"
|
||||||
|
unset _paths_output
|
||||||
|
|
||||||
|
# Validate branch
|
||||||
|
# If feature.json pins an existing feature directory, branch naming is not required.
|
||||||
|
if ! feature_json_matches_feature_dir "$REPO_ROOT" "$FEATURE_DIR"; then
|
||||||
|
check_feature_branch "$CURRENT_BRANCH" "$HAS_GIT" || exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ ! -f "$IMPL_PLAN" ]]; then
|
||||||
|
echo "ERROR: plan.md not found in $FEATURE_DIR" >&2
|
||||||
|
echo "Run /speckit.plan first to create the implementation plan." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ ! -f "$FEATURE_SPEC" ]]; then
|
||||||
|
echo "ERROR: spec.md not found in $FEATURE_DIR" >&2
|
||||||
|
echo "Run /speckit.specify first to create the feature structure." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Build available docs list
|
||||||
|
docs=()
|
||||||
|
[[ -f "$RESEARCH" ]] && docs+=("research.md")
|
||||||
|
[[ -f "$DATA_MODEL" ]] && docs+=("data-model.md")
|
||||||
|
if [[ -d "$CONTRACTS_DIR" ]] && [[ -n "$(ls -A "$CONTRACTS_DIR" 2>/dev/null)" ]]; then
|
||||||
|
docs+=("contracts/")
|
||||||
|
fi
|
||||||
|
[[ -f "$QUICKSTART" ]] && docs+=("quickstart.md")
|
||||||
|
|
||||||
|
# Resolve tasks template through override stack
|
||||||
|
TASKS_TEMPLATE=$(resolve_template "tasks-template" "$REPO_ROOT") || true
|
||||||
|
if [[ -z "$TASKS_TEMPLATE" ]] || [[ ! -f "$TASKS_TEMPLATE" ]]; then
|
||||||
|
echo "ERROR: Could not resolve required tasks-template from the template override stack for $REPO_ROOT" >&2
|
||||||
|
echo "Template 'tasks-template' was not found in any supported location (overrides, presets, extensions, or shared core). Add an override at .specify/templates/overrides/tasks-template.md, or run 'specify init' / reinstall shared infra to restore the core .specify/templates/tasks-template.md template." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Output results
|
||||||
|
if $JSON_MODE; then
|
||||||
|
if has_jq; then
|
||||||
|
if [[ ${#docs[@]} -eq 0 ]]; then
|
||||||
|
json_docs="[]"
|
||||||
|
else
|
||||||
|
json_docs=$(printf '%s\n' "${docs[@]}" | jq -R . | jq -s .)
|
||||||
|
fi
|
||||||
|
jq -cn \
|
||||||
|
--arg feature_dir "$FEATURE_DIR" \
|
||||||
|
--argjson docs "$json_docs" \
|
||||||
|
--arg tasks_template "${TASKS_TEMPLATE:-}" \
|
||||||
|
'{FEATURE_DIR:$feature_dir,AVAILABLE_DOCS:$docs,TASKS_TEMPLATE:$tasks_template}'
|
||||||
|
else
|
||||||
|
if [[ ${#docs[@]} -eq 0 ]]; then
|
||||||
|
json_docs="[]"
|
||||||
|
else
|
||||||
|
json_docs=$(for d in "${docs[@]}"; do printf '"%s",' "$(json_escape "$d")"; done)
|
||||||
|
json_docs="[${json_docs%,}]"
|
||||||
|
fi
|
||||||
|
printf '{"FEATURE_DIR":"%s","AVAILABLE_DOCS":%s,"TASKS_TEMPLATE":"%s"}\n' \
|
||||||
|
"$(json_escape "$FEATURE_DIR")" "$json_docs" "$(json_escape "${TASKS_TEMPLATE:-}")"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "FEATURE_DIR: $FEATURE_DIR"
|
||||||
|
echo "TASKS_TEMPLATE: ${TASKS_TEMPLATE:-not found}"
|
||||||
|
echo "AVAILABLE_DOCS:"
|
||||||
|
check_file "$RESEARCH" "research.md"
|
||||||
|
check_file "$DATA_MODEL" "data-model.md"
|
||||||
|
check_dir "$CONTRACTS_DIR" "contracts/"
|
||||||
|
check_file "$QUICKSTART" "quickstart.md"
|
||||||
|
fi
|
||||||
@@ -8,7 +8,7 @@ description: "Task list template for feature implementation"
|
|||||||
**Input**: Design documents from `/specs/[###-feature-name]/`
|
**Input**: Design documents from `/specs/[###-feature-name]/`
|
||||||
**Prerequisites**: plan.md (required), spec.md (required for user stories), research.md, data-model.md, contracts/
|
**Prerequisites**: plan.md (required), spec.md (required for user stories), research.md, data-model.md, contracts/
|
||||||
|
|
||||||
**Tests**: The examples below include test tasks. Per §5.1 of the constitution, TDD is non-negotiable — test tasks MUST appear before every implementation task. The test task labels below marked "OPTIONAL" refer to the *type* of test (E2E is best-effort per §5.2), not whether tests are written at all.
|
**Tests**: The examples below include test tasks. Tests are OPTIONAL - only include them if explicitly requested in the feature specification.
|
||||||
|
|
||||||
**Organization**: Tasks are grouped by user story to enable independent implementation and testing of each story.
|
**Organization**: Tasks are grouped by user story to enable independent implementation and testing of each story.
|
||||||
|
|
||||||
@@ -79,7 +79,7 @@ Examples of foundational tasks (adjust based on your project):
|
|||||||
|
|
||||||
**Independent Test**: [How to verify this story works on its own]
|
**Independent Test**: [How to verify this story works on its own]
|
||||||
|
|
||||||
### Tests for User Story 1 (REQUIRED per §5.1 — TDD) ⚠️
|
### Tests for User Story 1 (OPTIONAL - only if tests requested) ⚠️
|
||||||
|
|
||||||
> **NOTE: Write these tests FIRST, ensure they FAIL before implementation**
|
> **NOTE: Write these tests FIRST, ensure they FAIL before implementation**
|
||||||
|
|
||||||
@@ -105,7 +105,7 @@ Examples of foundational tasks (adjust based on your project):
|
|||||||
|
|
||||||
**Independent Test**: [How to verify this story works on its own]
|
**Independent Test**: [How to verify this story works on its own]
|
||||||
|
|
||||||
### Tests for User Story 2 (REQUIRED per §5.1 — TDD) ⚠️
|
### Tests for User Story 2 (OPTIONAL - only if tests requested) ⚠️
|
||||||
|
|
||||||
- [ ] T018 [P] [US2] Contract test for [endpoint] in tests/contract/test_[name].py
|
- [ ] T018 [P] [US2] Contract test for [endpoint] in tests/contract/test_[name].py
|
||||||
- [ ] T019 [P] [US2] Integration test for [user journey] in tests/integration/test_[name].py
|
- [ ] T019 [P] [US2] Integration test for [user journey] in tests/integration/test_[name].py
|
||||||
@@ -127,7 +127,7 @@ Examples of foundational tasks (adjust based on your project):
|
|||||||
|
|
||||||
**Independent Test**: [How to verify this story works on its own]
|
**Independent Test**: [How to verify this story works on its own]
|
||||||
|
|
||||||
### Tests for User Story 3 (REQUIRED per §5.1 — TDD) ⚠️
|
### Tests for User Story 3 (OPTIONAL - only if tests requested) ⚠️
|
||||||
|
|
||||||
- [ ] T024 [P] [US3] Contract test for [endpoint] in tests/contract/test_[name].py
|
- [ ] T024 [P] [US3] Contract test for [endpoint] in tests/contract/test_[name].py
|
||||||
- [ ] T025 [P] [US3] Integration test for [user journey] in tests/integration/test_[name].py
|
- [ ] T025 [P] [US3] Integration test for [user journey] in tests/integration/test_[name].py
|
||||||
@@ -198,7 +198,7 @@ Examples of foundational tasks (adjust based on your project):
|
|||||||
## Parallel Example: User Story 1
|
## Parallel Example: User Story 1
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Launch all tests for User Story 1 together (TDD — write before implementation):
|
# Launch all tests for User Story 1 together (if tests requested):
|
||||||
Task: "Contract test for [endpoint] in tests/contract/test_[name].py"
|
Task: "Contract test for [endpoint] in tests/contract/test_[name].py"
|
||||||
Task: "Integration test for [user journey] in tests/integration/test_[name].py"
|
Task: "Integration test for [user journey] in tests/integration/test_[name].py"
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
<!-- SPECKIT START -->
|
<!-- SPECKIT START -->
|
||||||
For additional context about technologies to be used, project structure,
|
For additional context about technologies to be used, project structure,
|
||||||
shell commands, and other important information, read the current plan at
|
shell commands, and other important information, read the current plan
|
||||||
`specs/018-pagination-controls/plan.md`.
|
|
||||||
<!-- SPECKIT END -->
|
<!-- SPECKIT END -->
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ dev = [
|
|||||||
[tool.ruff]
|
[tool.ruff]
|
||||||
line-length = 100
|
line-length = 100
|
||||||
target-version = "py312"
|
target-version = "py312"
|
||||||
|
exclude = ["alembic/"]
|
||||||
|
|
||||||
[tool.ruff.lint]
|
[tool.ruff.lint]
|
||||||
select = ["E", "F", "I", "UP", "B", "SIM"]
|
select = ["E", "F", "I", "UP", "B", "SIM"]
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ spec:
|
|||||||
spec:
|
spec:
|
||||||
initContainers:
|
initContainers:
|
||||||
- name: migrate
|
- name: migrate
|
||||||
image: git.juggalol.com/juggalol/reactbin-api:v1.4.1
|
image: git.juggalol.com/juggalol/reactbin-api:v1.4.3
|
||||||
command: ["alembic", "upgrade", "head"]
|
command: ["alembic", "upgrade", "head"]
|
||||||
workingDir: /app
|
workingDir: /app
|
||||||
envFrom:
|
envFrom:
|
||||||
@@ -26,7 +26,7 @@ spec:
|
|||||||
runAsUser: 1001
|
runAsUser: 1001
|
||||||
containers:
|
containers:
|
||||||
- name: api
|
- name: api
|
||||||
image: git.juggalol.com/juggalol/reactbin-api:v1.4.1
|
image: git.juggalol.com/juggalol/reactbin-api:v1.4.3
|
||||||
ports:
|
ports:
|
||||||
- containerPort: 8000
|
- containerPort: 8000
|
||||||
envFrom:
|
envFrom:
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ spec:
|
|||||||
spec:
|
spec:
|
||||||
containers:
|
containers:
|
||||||
- name: ui
|
- name: ui
|
||||||
image: git.juggalol.com/juggalol/reactbin-ui:v1.4.1
|
image: git.juggalol.com/juggalol/reactbin-ui:v1.4.3
|
||||||
ports:
|
ports:
|
||||||
- containerPort: 8080
|
- containerPort: 8080
|
||||||
livenessProbe:
|
livenessProbe:
|
||||||
|
|||||||
@@ -10,12 +10,12 @@
|
|||||||
<meta property="og:title" content="Reactbin">
|
<meta property="og:title" content="Reactbin">
|
||||||
<meta property="og:description" content="Find your perfect reaction image.">
|
<meta property="og:description" content="Find your perfect reaction image.">
|
||||||
<meta property="og:url" content="https://reactbin.juggalol.com">
|
<meta property="og:url" content="https://reactbin.juggalol.com">
|
||||||
<meta property="og:image" content="https://cdn.reactbin.juggalol.com/0bdaf046f534a1c913629d7ce8069ce407898c19794527bf842524ff4c0073de">
|
<meta property="og:image" content="https://cdn.reactbin.juggalol.com/baYB6eiC">
|
||||||
<!-- Twitter Card -->
|
<!-- Twitter Card -->
|
||||||
<meta name="twitter:card" content="summary_large_image">
|
<meta name="twitter:card" content="summary_large_image">
|
||||||
<meta name="twitter:title" content="Reactbin">
|
<meta name="twitter:title" content="Reactbin">
|
||||||
<meta name="twitter:description" content="Find your perfect reaction image.">
|
<meta name="twitter:description" content="Find your perfect reaction image.">
|
||||||
<meta name="twitter:image" content="https://cdn.reactbin.juggalol.com/0bdaf046f534a1c913629d7ce8069ce407898c19794527bf842524ff4c0073de">
|
<meta name="twitter:image" content="https://cdn.reactbin.juggalol.com/baYB6eiC">
|
||||||
<link rel="apple-touch-icon" sizes="180x180" href="apple-touch-icon.png">
|
<link rel="apple-touch-icon" sizes="180x180" href="apple-touch-icon.png">
|
||||||
<link rel="icon" type="image/png" sizes="32x32" href="favicon-32x32.png">
|
<link rel="icon" type="image/png" sizes="32x32" href="favicon-32x32.png">
|
||||||
<link rel="icon" type="image/png" sizes="16x16" href="favicon-16x16.png">
|
<link rel="icon" type="image/png" sizes="16x16" href="favicon-16x16.png">
|
||||||
|
|||||||
Reference in New Issue
Block a user