Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
status: todo
status: pending
---

# Instruction: close what the live backlog runs left open
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
status: planned
status: pending
backlog: ai-driven-dev/framework#703
spec: ./spec.md
---
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
status: framed
status: proposed
backlog: ai-driven-dev/framework#703
branch: fix/install-surfaces-agree
base: next@627408fb
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
status: delivered
status: done
backlog: ai-driven-dev/framework#746
spec: ./spec.md
---
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
status: delivered
status: done
backlog: ai-driven-dev/framework#746
branch: fix/trailer-survives-a-regenerated-hook
base: next@919aee30
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
date: 2026-05-25
scope: framework-build-copilot-flat MVP1
status: ready
status: done
references_spec: aidd_docs/tasks/2026_05/2026_05_25-framework-build-copilot-flat-spec.md
branch: feat/framework-build-copilot-flat
---
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
name: framework-build-copilot-flat
status: frozen
status: done
date: 2026-05-25
target: copilot
scope: MVP1-flat
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
date: 2026-05-25
scope: MVP1
target_plugin: copilot
status: ready-for-implementation
status: done
kind: delta
spec: ./2026_05_25-framework-build-copilot-spec.md
supersedes: ./2026_05_25-framework-build-copilot-plan.md
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ date: 2026-05-25
scope: MVP1
target_plugin: copilot
spec: ./2026_05_25-framework-build-copilot-spec.md
status: ready-for-implementation
status: done
---

# Plan — `aidd framework build --target copilot`
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
name: framework-build-copilot
status: frozen-v2
status: done
date: 2026-05-25
target: copilot
scope: MVP1
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
name: 271-setup-cache-version-fix-plan
status: ready
status: done
date: 2026-05-26
release: v4.5.1 (patch)
issue: https://github.com/ai-driven-dev/aidd-cli/issues/271
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
name: 271-setup-cache-version-fix
status: frozen
status: done
date: 2026-05-26
release: v4.5.1 (patch)
issue: https://github.com/ai-driven-dev/aidd-cli/issues/271
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
name: framework-build-codex
status: planned
status: done
date: 2026-05-26
scope: MVP1 (Mode A + agents hybrid)
target: codex
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
name: framework-build-codex
status: frozen
status: done
date: 2026-05-26
target: codex
scope: MVP1 (Mode A + agents hybrid)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
name: framework-build-multi-target-marketplace
status: planned
status: done
objective: Extend `aidd framework build` marketplace mode to cover claude + cursor (copilot + codex already shipped; opencode deferred), and replace the framework.ts if/else strategy ladder with a (target,mode)→factory registry — copilot/codex output stays byte-identical.
success_condition: "pnpm biome check && pnpm typecheck && pnpm vitest run all green, AND `node dist/cli.js framework build --source tests/fixtures/framework-real --target cursor --out /tmp/dist-cursor` exits 0 producing `.cursor-plugin/marketplace.json` + `plugins/<p>/.cursor-plugin/plugin.json` (no `tools`/`color` in agent .md), AND `--target claude` produces `.claude-plugin/marketplace.json` + `plugins/<p>/.claude-plugin/plugin.json`, AND copilot+codex golden snapshots are byte-identical to pre-refactor baseline."
iteration: 0
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
name: framework-build-multi-target-marketplace-smoke
date: 2026-05-30
targets: [claude, cursor]
status: documented
status: done
---

# Smoke test — `aidd framework build` claude + cursor targets
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
name: framework-build-multi-target-marketplace
status: draft
status: done
date: 2026-05-30
targets: [claude, cursor] # codex + copilot already shipped; opencode deferred to flat phase
mode: marketplace (Mode A)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
name: framework-build-conformance-matrix
status: verified
status: reviewed
date: 2026-05-31
scope: aidd framework build — 5 tools × 2 modes (marketplace + flat)
evidence: 34/34 live conformance checks pass (this doc), golden 9-cell matrix, integration + e2e suites, /tmp smoke
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
name: framework-build-unified-contract-flat
status: draft
status: done
date: 2026-05-31
supersedes-architecture-of: 2026_05_30-framework-build-multi-target-marketplace (PR #279, marketplace claude+cursor)
targets: [claude, cursor, copilot, codex, opencode]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
name: flat-hooks-per-tool
status: draft
status: done
date: 2026-06-01
scope: framework build --flat — correct hook config registration per tool
follows: fix/flat-plugin-prefixed-names (#281)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
objective: "Restore tells the truth about what it did, and marketplace-mode plugins are handled the same way on every command."
status: findings-1-2-done
status: done
---

# Plan: three findings surfaced during the cartography backlog
Expand Down
9 changes: 9 additions & 0 deletions lefthook.yml
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,15 @@ pre-commit:
fi
node scripts/check-doc-duplication.js

task-status:
glob: "{aidd_docs,cli/aidd_docs,kanban/aidd_docs}/**/*.md"
run: |
if ! command -v node >/dev/null 2>&1; then
echo "ℹ️ node not available; skipping task-status"
exit 0
fi
node scripts/check-task-status.js

markdown-links:
glob: "**/*.md"
run: |
Expand Down
114 changes: 114 additions & 0 deletions scripts/__tests__/a-task-status-the-board-can-place.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
const assert = require("node:assert/strict");
const fs = require("node:fs");
const path = require("node:path");
const test = require("node:test");

const {
ALLOWED_STATUSES,
BANKS,
declaredStatus,
markdownFiles,
offVocabularyStatuses,
} = require("../check-task-status.js");

const root = path.resolve(__dirname, "../..");

test("declaredStatus reads the status from the frontmatter block only", () => {
const content = [
"---",
"objective: ship it",
"status: pending",
"---",
"",
"# Plan",
"",
"status: garbage in the body is prose, not a declaration",
].join("\n");

assert.deepEqual(declaredStatus(content), { value: "pending", line: 3 });
});

test("declaredStatus reports nothing for a document without frontmatter or without status", () => {
assert.equal(declaredStatus("# Memory page\n\nNo frontmatter here."), undefined);
assert.equal(declaredStatus("---\nname: brief\n---\n\n# Brief"), undefined);
});

test("declaredStatus reads a CRLF document the way the board's parser does", () => {
// A Windows checkout's core.autocrlf writes CRLF (the CLI golden test normalizes it for
// the same reason); gray-matter parses it, so a CRLF status must not slip past the gate.
assert.deepEqual(declaredStatus("---\r\nstatus: draft\r\n---\r\n"), {
value: "draft",
line: 2,
});
});

test("declaredStatus reads quoted values and inline comments the way YAML does", () => {
// gray-matter sees `pending` in both; flagging them would reject a document the board places.
assert.deepEqual(declaredStatus('---\nstatus: "pending"\n---\n'), {
value: "pending",
line: 2,
});
assert.deepEqual(declaredStatus("---\nstatus: 'pending'\n---\n"), {
value: "pending",
line: 2,
});
assert.deepEqual(declaredStatus("---\nstatus: pending # wip note\n---\n"), {
value: "pending",
line: 2,
});
});

test("every lifecycle and creation status passes", () => {
for (const status of ALLOWED_STATUSES) {
const content = `---\nstatus: ${status}\n---\n`;
assert.deepEqual(offVocabularyStatuses(content), [], `"${status}" should be allowed`);
}
});

test("a status the board cannot place is flagged with its line", () => {
const content = "---\ntype: plan\nstatus: delivered\n---\n";

assert.deepEqual(offVocabularyStatuses(content), [{ value: "delivered", line: 3 }]);
});

test("every status the kanban maps onto a column is allowed here", () => {
// One-way: the board may map more than documents write, never less. A value the
// kanban places that this gate rejects would force authors off the board's own vocabulary.
const mappingSource = fs.readFileSync(
path.join(root, "kanban/src/domain/models/progress-status.ts"),
"utf-8"
);
const mappingBlock = mappingSource.match(
/RAW_STATUS_TO_PROGRESS_STATUS[^=]*=\s*\{([^}]*)\}/u
);
assert.ok(mappingBlock, "kanban raw-status mapping not found");

const mappedStatuses = [...mappingBlock[1].matchAll(/^\s*"?([\w-]+)"?:/gmu)]
.map((match) => match[1])
.filter((status) => status !== "unknown");

assert.ok(mappedStatuses.length > 0, "no mapped statuses parsed");
for (const status of mappedStatuses) {
assert.ok(
ALLOWED_STATUSES.includes(status),
`kanban maps "${status}" but the gate rejects it`
);
}
});

test("the repository's own banks hold no off-vocabulary status", () => {
const violations = [];

for (const bank of BANKS) {
const bankPath = path.join(root, bank);
if (!fs.existsSync(bankPath)) continue;

for (const filePath of markdownFiles(bankPath)) {
for (const finding of offVocabularyStatuses(fs.readFileSync(filePath, "utf-8"))) {
violations.push(`${path.relative(root, filePath)}:${finding.line} "${finding.value}"`);
}
}
}

assert.deepEqual(violations, []);
});
Loading
Loading