claude-alfred 0.3.21 → 0.3.22
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.ja.md +5 -6
- package/README.md +5 -6
- package/dist/{audit-e13xK9Fr.mjs → audit-DmNpxVt4.mjs} +1 -1
- package/dist/cli.mjs +3 -3
- package/dist/{directives-DfzKzUAL.mjs → directives-Drv78LF2.mjs} +1 -1
- package/dist/{dispatcher-BDl_Flyx.mjs → dispatcher-Bm43S1GQ.mjs} +6 -6
- package/dist/{drift-CKOseTmh.mjs → drift-PySAVqkr.mjs} +3 -3
- package/dist/{epic-CfxJ13zy.mjs → epic-DJZgRHFr.mjs} +1 -1
- package/dist/{living-spec-BfQnawom.mjs → living-spec-C5kafrYy.mjs} +2 -2
- package/dist/{post-tool-DpBkq5ik.mjs → post-tool-CXbKGLOa.mjs} +7 -7
- package/dist/post-tool-CiV4IiYH.mjs +11 -0
- package/dist/{pre-compact-Cncx9q7L.mjs → pre-compact-p_eqH4vL.mjs} +5 -9
- package/dist/{pre-tool-Dyp4S8cV.mjs → pre-tool-CnoF_sta.mjs} +8 -8
- package/dist/{review-gate-7Pfe_A-8.mjs → review-gate-P_eycqEX.mjs} +1 -3
- package/dist/{server-CYUJFZhW.mjs → server-AL3qcEqy.mjs} +5 -10
- package/dist/{server-D3b54XYU.mjs → server-BJ1jUEm2.mjs} +18 -123
- package/dist/{session-start-CU4-KivX.mjs → session-start-CS4gyHMH.mjs} +8 -5
- package/dist/{stop-CGv96IQd.mjs → stop-DJgb2wrf.mjs} +2 -2
- package/dist/{types-K2jxpWyU.mjs → types-DyBixMZ0.mjs} +13 -17
- package/dist/{user-prompt-BPAOU8f-.mjs → user-prompt-vSVUeux8.mjs} +13 -15
- package/package.json +1 -1
- package/web/dist/assets/activity-CXCppRFo.js +1 -0
- package/web/dist/assets/alert-dialog-EwyZzvus.js +20 -0
- package/web/dist/assets/{badge-C_nJR3_P.js → badge-LeU66vxM.js} +1936 -1934
- package/web/dist/assets/butler-empty-DDWZ5SlJ.js +1 -0
- package/web/dist/assets/button-9A03BFB6.js +1 -0
- package/web/dist/assets/{card-D-KKTUrZ.js → card-C6aK9m3p.js} +1 -1
- package/web/dist/assets/{es2015-C0wv2Iox.js → es2015-DCAVxrl_.js} +1 -1
- package/web/dist/assets/index-BWInN_tm.css +1 -0
- package/web/dist/assets/index-uOCUo7Eo.js +10 -0
- package/web/dist/assets/{knowledge-Cf76s4T9.js → knowledge-CB_kjUsk.js} +15 -15
- package/web/dist/assets/{link-CfxeT0ji.js → link-DBmH_08w.js} +1 -1
- package/web/dist/assets/motion-BYjuf98F.js +1 -0
- package/web/dist/assets/preload-helper-BmUhu0Y-.js +1 -0
- package/web/dist/assets/progress-qFNeU9jW.js +6 -0
- package/web/dist/assets/routes-Dgq6wgCk.js +1 -0
- package/web/dist/assets/separator-mtcJeU26.js +5 -0
- package/web/dist/assets/{skeleton-ByYY54GV.js → skeleton-Cwiwlof_.js} +1 -1
- package/web/dist/assets/stagger-container-GyT5nb39.js +9 -0
- package/web/dist/assets/tasks-CVVDa650.js +1 -0
- package/web/dist/assets/tasks._slug-BccdO-CH.js +44 -0
- package/web/dist/assets/tooltip-CAuNczLe.js +1 -0
- package/web/dist/index.html +9 -7
- package/dist/post-tool-BawR4gHR.mjs +0 -11
- package/web/dist/assets/activity-BMH0Gseq.js +0 -3
- package/web/dist/assets/alert-dialog-Df-NKKik.js +0 -20
- package/web/dist/assets/button-BC81_2hy.js +0 -1
- package/web/dist/assets/dist-CCslGrjS.js +0 -1
- package/web/dist/assets/dist-CbLvV7YE.js +0 -1
- package/web/dist/assets/index-BedjjxO2.css +0 -1
- package/web/dist/assets/index-ClD5S_3_.js +0 -138
- package/web/dist/assets/progress-3fcfVnZl.js +0 -6
- package/web/dist/assets/routes-DZR7VbL6.js +0 -1
- package/web/dist/assets/stagger-container-ClpnejW9.js +0 -9
- package/web/dist/assets/tasks-Byg4aFbV.js +0 -1
- package/web/dist/assets/tasks._slug-jxqMGzVd.js +0 -44
- package/web/dist/assets/useParams-BHiGLTRd.js +0 -1
- /package/web/dist/assets/{types-CkMKNgId.js → types-Gr5neTyu.js} +0 -0
package/README.ja.md
CHANGED
|
@@ -44,7 +44,7 @@ Claude Code で:
|
|
|
44
44
|
|
|
45
45
|
多くの spec ツールは「先に仕様を書いた方がいいですよ」と slash command で提案する。alfred は Claude Code の Hook システムで Edit/Write を**物理的にブロック**する。提案ではなく、ツールレベルでの強制 — それが根本的な違い。
|
|
46
46
|
|
|
47
|
-
**提案ではなく強制。** 3層のゲートがコード編集を制御する。spec なしの実装を防ぐインテントガード。前の Wave をレビューするまで次を止めるレビューゲート。ダッシュボードで人間が承認するまで M/L
|
|
47
|
+
**提案ではなく強制。** 3層のゲートがコード編集を制御する。spec なしの実装を防ぐインテントガード。前の Wave をレビューするまで次を止めるレビューゲート。ダッシュボードで人間が承認するまで M/L の実装を止める承認ゲート。YAML を手で書き換えてもダメ — 署名済みレビューファイルまで検証する。
|
|
48
48
|
|
|
49
49
|
**記憶が育つ。** 「あの時なぜこう決めた」「このパターンは前もうまくいった」「X は試してダメだった」— `.alfred/knowledge/` に JSON で残る。15回以上検索ヒットしたパターンはルールに自動昇格。知識タイプごとに半減期が違う — ルールは120日、仮定は30日で鮮度が落ちる。矛盾は自動検出。Git に入れてチームで共有できる。次に似た状況が来たら、聞く前に出てくる。
|
|
50
50
|
|
|
@@ -70,7 +70,7 @@ Claude Code は強力だが、構造なき AI コーディングには既知の
|
|
|
70
70
|
|
|
71
71
|
業界は **Spec-Driven Development**(構造化仕様)と **Intent-Driven Development**(Why と What だけ、How は AI 任せ)の2つに収束しつつある。alfred は両方を橋渡し:
|
|
72
72
|
|
|
73
|
-
- **フル SDD** — M/L
|
|
73
|
+
- **フル SDD** — M/L 機能向け。要件、設計、タスク、テスト、トレーサビリティ、レビューゲート
|
|
74
74
|
- **軽量 IDD** — S/D 変更向け。要件 + 判断記録のみ、設計のオーバーヘッドなし
|
|
75
75
|
- **不変の判断記録** — `ledger save` で ADR ライクな意思決定を保存。プロジェクト・セッションを超えてセマンティック検索可能
|
|
76
76
|
|
|
@@ -148,10 +148,9 @@ JSON ファイルとして Git にコミットし、PR でレビューし、チ
|
|
|
148
148
|
|
|
149
149
|
| サイズ | ファイル数 | 用途 |
|
|
150
150
|
|--------|-----------|------|
|
|
151
|
-
| **S** |
|
|
152
|
-
| **M** |
|
|
153
|
-
| **L
|
|
154
|
-
| **D** | 1 | 既存コードへの差分変更 |
|
|
151
|
+
| **S** | 3 | バグ修正、小さな機能 |
|
|
152
|
+
| **M** | 4 | 新エンドポイント、リファクタ |
|
|
153
|
+
| **L** | 5 | アーキテクチャ変更、新サブシステム |
|
|
155
154
|
|
|
156
155
|
## アップデート
|
|
157
156
|
|
package/README.md
CHANGED
|
@@ -44,7 +44,7 @@ Optional: add `export VOYAGE_API_KEY=your-key` to `~/.zshrc` for semantic search
|
|
|
44
44
|
|
|
45
45
|
Most spec tools give you slash commands that say "you should write a spec first." alfred uses Claude Code's hook system to **physically block** Edit and Write until you do. That's the core difference — enforcement happens at the tool level, not the prompt level.
|
|
46
46
|
|
|
47
|
-
**Enforcement, not suggestions.** Three layers gate your code edits. An intent guard blocks implementation without a spec. A review gate blocks the next wave until you've reviewed the last one. An approval gate blocks M/L
|
|
47
|
+
**Enforcement, not suggestions.** Three layers gate your code edits. An intent guard blocks implementation without a spec. A review gate blocks the next wave until you've reviewed the last one. An approval gate blocks M/L specs until a human signs off in the dashboard. You can't YAML-edit your way past it — the signed review file gets checked too.
|
|
48
48
|
|
|
49
49
|
**Knowledge that grows up.** Every decision, pattern, and hard-won lesson goes to `.alfred/knowledge/` as structured JSON. Patterns auto-promote to rules after 15+ search hits. Each knowledge type has its own half-life — rules stay relevant for 120 days, assumptions fade after 30. Contradictions are detected automatically. Git-friendly, team-shareable, and alfred surfaces relevant experience before you ask.
|
|
50
50
|
|
|
@@ -70,7 +70,7 @@ Claude Code is powerful, but unstructured AI coding has well-documented failure
|
|
|
70
70
|
|
|
71
71
|
The industry is converging on two complementary paradigms: **Spec-Driven Development** (structured specs as source of truth) and **Intent-Driven Development** (capture *why* and *what*, let AI handle *how*). alfred bridges both:
|
|
72
72
|
|
|
73
|
-
- **Full SDD** for M/L
|
|
73
|
+
- **Full SDD** for M/L features — requirements, design, tasks, tests, with traceability and review gates
|
|
74
74
|
- **Lightweight IDD** for S/D changes — just requirements + decisions, no design overhead
|
|
75
75
|
- **Immutable decisions** via `ledger save` — like ADRs, but semantically searchable across projects and sessions
|
|
76
76
|
|
|
@@ -148,10 +148,9 @@ Search pipeline: Voyage AI vectors with reranking > FTS5 with fuzzy matching > k
|
|
|
148
148
|
|
|
149
149
|
| Size | Files | Good for |
|
|
150
150
|
|------|-------|----------|
|
|
151
|
-
| **S** |
|
|
152
|
-
| **M** |
|
|
153
|
-
| **L
|
|
154
|
-
| **D** | 1 | Brownfield delta change |
|
|
151
|
+
| **S** | 3 | Bug fix, small feature |
|
|
152
|
+
| **M** | 4 | New endpoint, moderate refactor |
|
|
153
|
+
| **L** | 5 | Architecture change, new subsystem |
|
|
155
154
|
|
|
156
155
|
## Updating
|
|
157
156
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { n as __esmMin } from "./chunk-CAm0Jl7e.mjs";
|
|
3
|
-
import { f as rootDir, s as init_types } from "./types-
|
|
3
|
+
import { f as rootDir, s as init_types } from "./types-DyBixMZ0.mjs";
|
|
4
4
|
import { appendFileSync, mkdirSync } from "node:fs";
|
|
5
5
|
import { join } from "node:path";
|
|
6
6
|
//#region src/spec/audit.ts
|
package/dist/cli.mjs
CHANGED
|
@@ -371,7 +371,7 @@ const main = defineCommand({
|
|
|
371
371
|
async run() {
|
|
372
372
|
const { Store } = await import("./store-BffM-bi-.mjs").then((n) => (n.t(), n.r));
|
|
373
373
|
const { Embedder } = await import("./embedder-D3hJoryD.mjs");
|
|
374
|
-
const { serveMCP } = await import("./server-
|
|
374
|
+
const { serveMCP } = await import("./server-BJ1jUEm2.mjs");
|
|
375
375
|
const store = Store.openDefault();
|
|
376
376
|
let emb = null;
|
|
377
377
|
try {
|
|
@@ -399,7 +399,7 @@ const main = defineCommand({
|
|
|
399
399
|
async run({ args }) {
|
|
400
400
|
const { Store } = await import("./store-BffM-bi-.mjs").then((n) => (n.t(), n.r));
|
|
401
401
|
const { Embedder } = await import("./embedder-D3hJoryD.mjs");
|
|
402
|
-
const { startDashboard } = await import("./server-
|
|
402
|
+
const { startDashboard } = await import("./server-AL3qcEqy.mjs");
|
|
403
403
|
const projectPath = process.cwd();
|
|
404
404
|
const store = Store.openDefault();
|
|
405
405
|
let emb = null;
|
|
@@ -422,7 +422,7 @@ const main = defineCommand({
|
|
|
422
422
|
description: "Event name"
|
|
423
423
|
} },
|
|
424
424
|
async run({ args }) {
|
|
425
|
-
const { runHook } = await import("./dispatcher-
|
|
425
|
+
const { runHook } = await import("./dispatcher-Bm43S1GQ.mjs").then((n) => (n.i(), n.t));
|
|
426
426
|
await runHook(args.event);
|
|
427
427
|
}
|
|
428
428
|
}),
|
|
@@ -3,7 +3,7 @@ import { n as __esmMin } from "./chunk-CAm0Jl7e.mjs";
|
|
|
3
3
|
import { c as incrementHitCount, f as searchKnowledgeKeyword, i as getKnowledgeByIDs, l as init_knowledge } from "./knowledge-C7rEfFSX.mjs";
|
|
4
4
|
import { r as vectorSearchKnowledge, t as init_vectors } from "./vectors-DHZGQ096.mjs";
|
|
5
5
|
import { a as subTypeBoost, i as searchKnowledgeFTS, o as subTypeHalfLife, r as init_fts } from "./fts-DICqcpG_.mjs";
|
|
6
|
-
import { i as init_dispatcher, n as emitAdditionalContext } from "./dispatcher-
|
|
6
|
+
import { i as init_dispatcher, n as emitAdditionalContext } from "./dispatcher-Bm43S1GQ.mjs";
|
|
7
7
|
//#region src/mcp/helpers.ts
|
|
8
8
|
function truncate(s, maxLen) {
|
|
9
9
|
const runes = [...s];
|
|
@@ -89,27 +89,27 @@ async function runHook(event) {
|
|
|
89
89
|
}
|
|
90
90
|
}
|
|
91
91
|
async function handleSessionStart(ev, signal) {
|
|
92
|
-
const { sessionStart } = await import("./session-start-
|
|
92
|
+
const { sessionStart } = await import("./session-start-CS4gyHMH.mjs");
|
|
93
93
|
await sessionStart(ev, signal);
|
|
94
94
|
}
|
|
95
95
|
async function handlePreCompact(ev, signal) {
|
|
96
|
-
const { preCompact } = await import("./pre-compact-
|
|
96
|
+
const { preCompact } = await import("./pre-compact-p_eqH4vL.mjs");
|
|
97
97
|
await preCompact(ev, signal);
|
|
98
98
|
}
|
|
99
99
|
async function handleUserPromptSubmit(ev, signal) {
|
|
100
|
-
const { userPromptSubmit } = await import("./user-prompt-
|
|
100
|
+
const { userPromptSubmit } = await import("./user-prompt-vSVUeux8.mjs");
|
|
101
101
|
await userPromptSubmit(ev, signal);
|
|
102
102
|
}
|
|
103
103
|
async function handlePostToolUse(ev, signal) {
|
|
104
|
-
const { postToolUse } = await import("./post-tool-
|
|
104
|
+
const { postToolUse } = await import("./post-tool-CiV4IiYH.mjs");
|
|
105
105
|
await postToolUse(ev, signal);
|
|
106
106
|
}
|
|
107
107
|
async function handlePreToolUse(ev, _signal) {
|
|
108
|
-
const { preToolUse } = await import("./pre-tool-
|
|
108
|
+
const { preToolUse } = await import("./pre-tool-CnoF_sta.mjs");
|
|
109
109
|
await preToolUse(ev);
|
|
110
110
|
}
|
|
111
111
|
async function handleStop(ev, _signal) {
|
|
112
|
-
const { stop } = await import("./stop-
|
|
112
|
+
const { stop } = await import("./stop-DJgb2wrf.mjs");
|
|
113
113
|
await stop(ev);
|
|
114
114
|
}
|
|
115
115
|
var init_dispatcher = __esmMin((() => {}));
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { n as __esmMin } from "./chunk-CAm0Jl7e.mjs";
|
|
3
|
-
import { c as readActive, s as init_types, t as SpecDir } from "./types-
|
|
4
|
-
import { n as init_audit, t as appendAudit } from "./audit-
|
|
5
|
-
import { extractChangedFiles, n as init_lang_filter, parseDesignFileRefs, r as shouldAutoAppend, t as init_living_spec } from "./living-spec-
|
|
3
|
+
import { c as readActive, s as init_types, t as SpecDir } from "./types-DyBixMZ0.mjs";
|
|
4
|
+
import { n as init_audit, t as appendAudit } from "./audit-DmNpxVt4.mjs";
|
|
5
|
+
import { extractChangedFiles, n as init_lang_filter, parseDesignFileRefs, r as shouldAutoAppend, t as init_living_spec } from "./living-spec-C5kafrYy.mjs";
|
|
6
6
|
//#region src/hooks/drift.ts
|
|
7
7
|
/**
|
|
8
8
|
* Detect source files changed in the last commit that are not referenced in the active spec.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { n as __esmMin } from "./chunk-CAm0Jl7e.mjs";
|
|
3
|
-
import { _ as require_dist, n as VALID_SLUG, s as init_types } from "./types-
|
|
3
|
+
import { _ as require_dist, n as VALID_SLUG, s as init_types } from "./types-DyBixMZ0.mjs";
|
|
4
4
|
import { mkdirSync, readFileSync, readdirSync, renameSync, rmSync, statSync, writeFileSync } from "node:fs";
|
|
5
5
|
import { join } from "node:path";
|
|
6
6
|
//#region src/epic/index.ts
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { n as __esmMin } from "./chunk-CAm0Jl7e.mjs";
|
|
3
|
-
import { c as readActive, s as init_types, t as SpecDir } from "./types-
|
|
4
|
-
import { n as init_audit, t as appendAudit } from "./audit-
|
|
3
|
+
import { c as readActive, s as init_types, t as SpecDir } from "./types-DyBixMZ0.mjs";
|
|
4
|
+
import { n as init_audit, t as appendAudit } from "./audit-DmNpxVt4.mjs";
|
|
5
5
|
import { basename, dirname, extname } from "node:path";
|
|
6
6
|
import { execSync } from "node:child_process";
|
|
7
7
|
//#region src/hooks/lang-filter.ts
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { n as __esmMin, r as __exportAll } from "./chunk-CAm0Jl7e.mjs";
|
|
3
|
-
import { a as effectiveStatus, c as readActive, g as writeActiveState, l as readActiveState, m as transitionStatus, s as init_types$1, t as SpecDir } from "./types-
|
|
4
|
-
import { n as init_audit, t as appendAudit } from "./audit-
|
|
3
|
+
import { a as effectiveStatus, c as readActive, g as writeActiveState, l as readActiveState, m as transitionStatus, s as init_types$1, t as SpecDir } from "./types-DyBixMZ0.mjs";
|
|
4
|
+
import { n as init_audit, t as appendAudit } from "./audit-DmNpxVt4.mjs";
|
|
5
5
|
import { a as getKnowledgeStats, d as promoteSubType, l as init_knowledge, m as upsertKnowledge, o as getPromotionCandidates, r as getKnowledgeByID } from "./knowledge-C7rEfFSX.mjs";
|
|
6
6
|
import { i as searchKnowledgeFTS, r as init_fts, t as detectKnowledgeConflicts } from "./fts-DICqcpG_.mjs";
|
|
7
7
|
import { n as init_project, t as detectProject } from "./project-DCKke4_Q.mjs";
|
|
8
|
-
import { a as notifyUser, i as init_dispatcher } from "./dispatcher-
|
|
9
|
-
import { a as trackHitCounts, i as searchPipeline, n as init_directives, o as truncate, r as init_helpers, t as emitDirectives } from "./directives-
|
|
8
|
+
import { a as notifyUser, i as init_dispatcher } from "./dispatcher-Bm43S1GQ.mjs";
|
|
9
|
+
import { a as trackHitCounts, i as searchPipeline, n as init_directives, o as truncate, r as init_helpers, t as emitDirectives } from "./directives-Drv78LF2.mjs";
|
|
10
10
|
import { n as openDefaultCached, t as init_store } from "./store-BffM-bi-.mjs";
|
|
11
|
-
import { a as writeReviewGate, d as init_spec_guard, n as init_review_gate, p as isSpecFilePath } from "./review-gate-
|
|
11
|
+
import { a as writeReviewGate, d as init_spec_guard, n as init_review_gate, p as isSpecFilePath } from "./review-gate-P_eycqEX.mjs";
|
|
12
12
|
import { f as writeStateText, i as parseWaveProgress, o as readStateText, p as writeWaveProgress, r as init_state, s as readWaveProgress, t as addWorkedSlug } from "./state-Cih-8_Zc.mjs";
|
|
13
13
|
import { mkdirSync, renameSync, unlinkSync, writeFileSync } from "node:fs";
|
|
14
14
|
import { join } from "node:path";
|
|
@@ -575,11 +575,11 @@ async function handleBashResult(ev, items, signal) {
|
|
|
575
575
|
if (isGitCommit(response.stdout ?? "") && !signal.aborted) {
|
|
576
576
|
let appendedFiles = /* @__PURE__ */ new Set();
|
|
577
577
|
try {
|
|
578
|
-
const { handleLivingSpec } = await import("./living-spec-
|
|
578
|
+
const { handleLivingSpec } = await import("./living-spec-C5kafrYy.mjs");
|
|
579
579
|
appendedFiles = handleLivingSpec(ev.cwd);
|
|
580
580
|
} catch {}
|
|
581
581
|
try {
|
|
582
|
-
const { detectDrift } = await import("./drift-
|
|
582
|
+
const { detectDrift } = await import("./drift-PySAVqkr.mjs");
|
|
583
583
|
detectDrift(ev.cwd, appendedFiles, items);
|
|
584
584
|
} catch {}
|
|
585
585
|
await checkKnowledgeConflicts(items);
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import "./types-DyBixMZ0.mjs";
|
|
3
|
+
import "./audit-DmNpxVt4.mjs";
|
|
4
|
+
import "./dispatcher-Bm43S1GQ.mjs";
|
|
5
|
+
import "./directives-Drv78LF2.mjs";
|
|
6
|
+
import { a as postToolUse, n as init_post_tool } from "./post-tool-CXbKGLOa.mjs";
|
|
7
|
+
import "./store-BffM-bi-.mjs";
|
|
8
|
+
import "./review-gate-P_eycqEX.mjs";
|
|
9
|
+
import "./state-Cih-8_Zc.mjs";
|
|
10
|
+
init_post_tool();
|
|
11
|
+
export { postToolUse };
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { n as __esmMin } from "./chunk-CAm0Jl7e.mjs";
|
|
3
|
-
import { c as readActive, d as reviewStatusFor, h as verifyReviewFile, l as readActiveState, r as completeTask, s as init_types, t as SpecDir } from "./types-
|
|
4
|
-
import { r as init_epic, s as syncTaskStatus } from "./epic-
|
|
5
|
-
import { n as init_audit, t as appendAudit } from "./audit-
|
|
3
|
+
import { c as readActive, d as reviewStatusFor, h as verifyReviewFile, l as readActiveState, r as completeTask, s as init_types, t as SpecDir } from "./types-DyBixMZ0.mjs";
|
|
4
|
+
import { r as init_epic, s as syncTaskStatus } from "./epic-DJZgRHFr.mjs";
|
|
5
|
+
import { n as init_audit, t as appendAudit } from "./audit-DmNpxVt4.mjs";
|
|
6
6
|
import { l as init_knowledge, m as upsertKnowledge } from "./knowledge-C7rEfFSX.mjs";
|
|
7
7
|
import { n as init_project, t as detectProject } from "./project-DCKke4_Q.mjs";
|
|
8
|
-
import { a as notifyUser, i as init_dispatcher } from "./dispatcher-
|
|
8
|
+
import { a as notifyUser, i as init_dispatcher } from "./dispatcher-Bm43S1GQ.mjs";
|
|
9
9
|
import { n as openDefaultCached, t as init_store } from "./store-BffM-bi-.mjs";
|
|
10
10
|
import { readFileSync, writeFileSync } from "node:fs";
|
|
11
11
|
import { join } from "node:path";
|
|
@@ -89,11 +89,7 @@ async function preCompact(ev, _signal) {
|
|
|
89
89
|
const taskSlug = readActive(projectPath);
|
|
90
90
|
if (isTasksCompleted(new SpecDir(projectPath, taskSlug).readFile("tasks.md"))) {
|
|
91
91
|
const size = readActiveState(projectPath).tasks.find((t) => t.slug === taskSlug)?.size ?? "L";
|
|
92
|
-
if ([
|
|
93
|
-
"M",
|
|
94
|
-
"L",
|
|
95
|
-
"XL"
|
|
96
|
-
].includes(size)) {
|
|
92
|
+
if (["M", "L"].includes(size)) {
|
|
97
93
|
const reviewStatus = reviewStatusFor(projectPath, taskSlug);
|
|
98
94
|
const verification = verifyReviewFile(projectPath, taskSlug);
|
|
99
95
|
if (reviewStatus !== "approved" || !verification.valid) notifyUser("skipped auto-complete: review not approved for %s spec '%s'", size, taskSlug);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { n as __esmMin } from "./chunk-CAm0Jl7e.mjs";
|
|
3
|
-
import { a as effectiveStatus, s as init_types } from "./types-
|
|
4
|
-
import { d as init_spec_guard, f as isActiveSpecMalformed, l as denyTool, m as tryReadActiveSpec, n as init_review_gate, o as allowTool, p as isSpecFilePath, r as isGateActive } from "./review-gate-
|
|
3
|
+
import { a as effectiveStatus, s as init_types } from "./types-DyBixMZ0.mjs";
|
|
4
|
+
import { d as init_spec_guard, f as isActiveSpecMalformed, l as denyTool, m as tryReadActiveSpec, n as init_review_gate, o as allowTool, p as isSpecFilePath, r as isGateActive } from "./review-gate-P_eycqEX.mjs";
|
|
5
5
|
import { a as readStateJSON, r as init_state } from "./state-Cih-8_Zc.mjs";
|
|
6
6
|
import { resolve } from "node:path";
|
|
7
7
|
//#region src/hooks/pre-tool.ts
|
|
@@ -72,19 +72,19 @@ async function preToolUse(ev) {
|
|
|
72
72
|
allowTool(`Polish mode (post-complete '${polish.slug}')`);
|
|
73
73
|
return;
|
|
74
74
|
}
|
|
75
|
+
if (readStateJSON(ev.cwd, "spec-prompt.json", {}).prompted) {
|
|
76
|
+
allowTool("Spec prompt already issued (implicit skip)");
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
75
79
|
process.stderr.write("[alfred] No active spec. Consider creating one: dossier action=init\n");
|
|
76
80
|
allowTool("No active spec (advisory warning emitted)");
|
|
77
81
|
return;
|
|
78
82
|
}
|
|
79
|
-
if ([
|
|
80
|
-
"M",
|
|
81
|
-
"L",
|
|
82
|
-
"XL"
|
|
83
|
-
].includes(spec.size) && spec.reviewStatus !== "approved") {
|
|
83
|
+
if (["M", "L"].includes(spec.size) && spec.reviewStatus !== "approved") {
|
|
84
84
|
denyTool([
|
|
85
85
|
`Spec '${spec.slug}' (size ${spec.size}) is not approved. Submit review via \`alfred dashboard\` or run self-review before implementation.`,
|
|
86
86
|
"- \"I'll get the review after implementation\" → The Stop hook will block you from finishing anyway",
|
|
87
|
-
"- \"This edit is trivial\" → All M/L
|
|
87
|
+
"- \"This edit is trivial\" → All M/L edits are gated. Use dossier init size=S for trivial changes"
|
|
88
88
|
].join("\n"));
|
|
89
89
|
return;
|
|
90
90
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { n as __esmMin } from "./chunk-CAm0Jl7e.mjs";
|
|
3
|
-
import { l as readActiveState, s as init_types } from "./types-
|
|
3
|
+
import { l as readActiveState, s as init_types } from "./types-DyBixMZ0.mjs";
|
|
4
4
|
import { a as readStateJSON, d as writeStateJSON, r as init_state } from "./state-Cih-8_Zc.mjs";
|
|
5
5
|
import { existsSync, readFileSync } from "node:fs";
|
|
6
6
|
import { join, resolve } from "node:path";
|
|
@@ -122,8 +122,6 @@ var init_spec_guard = __esmMin((() => {
|
|
|
122
122
|
"S",
|
|
123
123
|
"M",
|
|
124
124
|
"L",
|
|
125
|
-
"XL",
|
|
126
|
-
"D",
|
|
127
125
|
""
|
|
128
126
|
]);
|
|
129
127
|
VALID_REVIEW_STATUSES = new Set([
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { g as writeActiveState, h as verifyReviewFile, l as readActiveState, n as VALID_SLUG, o as filesForSize, r as completeTask, s as init_types, t as SpecDir } from "./types-
|
|
3
|
-
import { i as listAllEpics, r as init_epic } from "./epic-
|
|
4
|
-
import { n as init_audit, t as appendAudit } from "./audit-
|
|
2
|
+
import { g as writeActiveState, h as verifyReviewFile, l as readActiveState, n as VALID_SLUG, o as filesForSize, r as completeTask, s as init_types, t as SpecDir } from "./types-DyBixMZ0.mjs";
|
|
3
|
+
import { i as listAllEpics, r as init_epic } from "./epic-DJZgRHFr.mjs";
|
|
4
|
+
import { n as init_audit, t as appendAudit } from "./audit-DmNpxVt4.mjs";
|
|
5
5
|
import { a as getKnowledgeStats, d as promoteSubType, l as init_knowledge, o as getPromotionCandidates, p as setKnowledgeEnabled } from "./knowledge-C7rEfFSX.mjs";
|
|
6
6
|
import { n as pairwiseSimilarity, t as init_vectors } from "./vectors-DHZGQ096.mjs";
|
|
7
7
|
import { i as searchKnowledgeFTS, n as expandAliases, r as init_fts } from "./fts-DICqcpG_.mjs";
|
|
@@ -2553,8 +2553,7 @@ function createApp(projectPath, store, _emb, version) {
|
|
|
2553
2553
|
"decisions.md",
|
|
2554
2554
|
"research.md",
|
|
2555
2555
|
"session.md",
|
|
2556
|
-
"bugfix.md"
|
|
2557
|
-
"delta.md"
|
|
2556
|
+
"bugfix.md"
|
|
2558
2557
|
]);
|
|
2559
2558
|
function enrichTask(task, projPath, projectName) {
|
|
2560
2559
|
const detail = {
|
|
@@ -2968,11 +2967,7 @@ function createApp(projectPath, store, _emb, version) {
|
|
|
2968
2967
|
const task = state.tasks.find((t) => t.slug === slug);
|
|
2969
2968
|
if (!task) return c.json({ error: "task not found" }, 404);
|
|
2970
2969
|
if (task.status === "completed") return c.json({ error: "task already completed" }, 400);
|
|
2971
|
-
if ([
|
|
2972
|
-
"M",
|
|
2973
|
-
"L",
|
|
2974
|
-
"XL"
|
|
2975
|
-
].includes(task.size ?? "")) {
|
|
2970
|
+
if (["M", "L"].includes(task.size ?? "")) {
|
|
2976
2971
|
if (task.review_status !== "approved") return c.json({ error: `${task.size} spec requires approval before completion` }, 400);
|
|
2977
2972
|
const verification = verifyReviewFile(projectPath, slug);
|
|
2978
2973
|
if (!verification.valid) return c.json({ error: `review verification failed: ${verification.reason}` }, 400);
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { a as __toCommonJS, o as __toESM, t as __commonJSMin } from "./chunk-CAm0Jl7e.mjs";
|
|
3
|
-
import { a as effectiveStatus, c as readActive, d as reviewStatusFor, g as writeActiveState, h as verifyReviewFile, i as detectSize, l as readActiveState, n as VALID_SLUG, o as filesForSize, p as switchActive, r as completeTask, s as init_types, t as SpecDir, u as removeTask } from "./types-
|
|
4
|
-
import { a as nextActionable, c as topologicalOrder, i as listAllEpics, l as unlinkTaskFromAllEpics, n as initEpic, o as removeEpic, r as init_epic, s as syncTaskStatus, t as EpicDir } from "./epic-
|
|
5
|
-
import { n as init_audit, t as appendAudit } from "./audit-
|
|
3
|
+
import { a as effectiveStatus, c as readActive, d as reviewStatusFor, g as writeActiveState, h as verifyReviewFile, i as detectSize, l as readActiveState, n as VALID_SLUG, o as filesForSize, p as switchActive, r as completeTask, s as init_types, t as SpecDir, u as removeTask } from "./types-DyBixMZ0.mjs";
|
|
4
|
+
import { a as nextActionable, c as topologicalOrder, i as listAllEpics, l as unlinkTaskFromAllEpics, n as initEpic, o as removeEpic, r as init_epic, s as syncTaskStatus, t as EpicDir } from "./epic-DJZgRHFr.mjs";
|
|
5
|
+
import { n as init_audit, t as appendAudit } from "./audit-DmNpxVt4.mjs";
|
|
6
6
|
import { i as getKnowledgeByIDs, l as init_knowledge } from "./knowledge-C7rEfFSX.mjs";
|
|
7
7
|
import { r as vectorSearchKnowledge, t as init_vectors } from "./vectors-DHZGQ096.mjs";
|
|
8
8
|
import { a as subTypeBoost, i as searchKnowledgeFTS, r as init_fts } from "./fts-DICqcpG_.mjs";
|
|
9
|
-
import "./dispatcher-
|
|
10
|
-
import { o as truncate, r as init_helpers } from "./directives-
|
|
11
|
-
import { c as updateTaskStatus, l as handleLedger, n as init_post_tool, o as post_tool_exports, s as init_status, u as init_ledger } from "./post-tool-
|
|
9
|
+
import "./dispatcher-Bm43S1GQ.mjs";
|
|
10
|
+
import { o as truncate, r as init_helpers } from "./directives-Drv78LF2.mjs";
|
|
11
|
+
import { c as updateTaskStatus, l as handleLedger, n as init_post_tool, o as post_tool_exports, s as init_status, u as init_ledger } from "./post-tool-CXbKGLOa.mjs";
|
|
12
12
|
import "./store-BffM-bi-.mjs";
|
|
13
|
-
import { a as writeReviewGate, i as readReviewGate, n as init_review_gate, t as clearReviewGate } from "./review-gate-
|
|
13
|
+
import { a as writeReviewGate, i as readReviewGate, n as init_review_gate, t as clearReviewGate } from "./review-gate-P_eycqEX.mjs";
|
|
14
14
|
import { d as writeStateJSON, n as ensureStateDir, p as writeWaveProgress, r as init_state, s as readWaveProgress, u as stateDir } from "./state-Cih-8_Zc.mjs";
|
|
15
15
|
import { existsSync, mkdirSync, readFileSync, readdirSync, rmSync, unlinkSync, writeFileSync } from "node:fs";
|
|
16
16
|
import { join, resolve } from "node:path";
|
|
@@ -18214,63 +18214,11 @@ function validateSpec(projectPath, taskSlug, size, specType, opts) {
|
|
|
18214
18214
|
status: "fail",
|
|
18215
18215
|
message: `${f} missing`
|
|
18216
18216
|
});
|
|
18217
|
-
const primaryContent = readFile(specType === "bugfix" ? "bugfix.md" :
|
|
18217
|
+
const primaryContent = readFile(specType === "bugfix" ? "bugfix.md" : "requirements.md") ?? "";
|
|
18218
18218
|
const tasksContent = readFile("tasks.md") ?? "";
|
|
18219
18219
|
const designContent = readFile("design.md") ?? "";
|
|
18220
18220
|
const testSpecsContent = readFile("test-specs.md") ?? "";
|
|
18221
18221
|
const researchContent = readFile("research.md") ?? "";
|
|
18222
|
-
if (size === "D") {
|
|
18223
|
-
const deltaContent = readFile("delta.md") ?? "";
|
|
18224
|
-
const requiredSectionsEN = [
|
|
18225
|
-
"Change Summary",
|
|
18226
|
-
"Files Affected",
|
|
18227
|
-
"Rationale",
|
|
18228
|
-
"Impact Scope",
|
|
18229
|
-
"Test Plan",
|
|
18230
|
-
"Rollback Strategy"
|
|
18231
|
-
];
|
|
18232
|
-
const requiredSectionsJA = [
|
|
18233
|
-
"変更概要",
|
|
18234
|
-
"影響ファイル",
|
|
18235
|
-
"変更理由",
|
|
18236
|
-
"影響範囲",
|
|
18237
|
-
"テスト計画",
|
|
18238
|
-
"ロールバック手順"
|
|
18239
|
-
];
|
|
18240
|
-
const enCount = requiredSectionsEN.filter((s) => deltaContent.includes(`## ${s}`)).length;
|
|
18241
|
-
const jaCount = requiredSectionsJA.filter((s) => deltaContent.includes(`## ${s}`)).length;
|
|
18242
|
-
const bestCount = Math.max(enCount, jaCount);
|
|
18243
|
-
checks.push(bestCount >= 6 ? {
|
|
18244
|
-
name: "delta_sections_present",
|
|
18245
|
-
status: "pass",
|
|
18246
|
-
message: "All delta sections present"
|
|
18247
|
-
} : {
|
|
18248
|
-
name: "delta_sections_present",
|
|
18249
|
-
status: "fail",
|
|
18250
|
-
message: `Only ${bestCount}/6 delta sections found`
|
|
18251
|
-
});
|
|
18252
|
-
const chgIDs = extractIDs(deltaContent, ID.CHG);
|
|
18253
|
-
checks.push(chgIDs.length > 0 ? {
|
|
18254
|
-
name: "delta_change_ids",
|
|
18255
|
-
status: "pass",
|
|
18256
|
-
message: `${chgIDs.length} CHG-N IDs found`
|
|
18257
|
-
} : {
|
|
18258
|
-
name: "delta_change_ids",
|
|
18259
|
-
status: "fail",
|
|
18260
|
-
message: "No CHG-N IDs found in delta.md"
|
|
18261
|
-
});
|
|
18262
|
-
const hasBeforeAfter = /\bBefore:\s*/i.test(deltaContent) && /\bAfter:\s*/i.test(deltaContent);
|
|
18263
|
-
checks.push(hasBeforeAfter ? {
|
|
18264
|
-
name: "delta_before_after",
|
|
18265
|
-
status: "pass",
|
|
18266
|
-
message: "Before/After blocks found"
|
|
18267
|
-
} : {
|
|
18268
|
-
name: "delta_before_after",
|
|
18269
|
-
status: "fail",
|
|
18270
|
-
message: "Missing Before/After blocks in delta.md"
|
|
18271
|
-
});
|
|
18272
|
-
return buildResult(checks, opts);
|
|
18273
|
-
}
|
|
18274
18222
|
if (specType === "bugfix") checks.push(primaryContent.length > 200 ? {
|
|
18275
18223
|
name: "min_fr_count",
|
|
18276
18224
|
status: "pass",
|
|
@@ -18282,7 +18230,7 @@ function validateSpec(projectPath, taskSlug, size, specType, opts) {
|
|
|
18282
18230
|
});
|
|
18283
18231
|
else {
|
|
18284
18232
|
const frIDs = extractIDs(primaryContent, ID.FR);
|
|
18285
|
-
const minCount = size === "S" ? 1 : size === "M" ? 3 :
|
|
18233
|
+
const minCount = size === "S" ? 1 : size === "M" ? 3 : 5;
|
|
18286
18234
|
const status = frIDs.length >= minCount ? "pass" : frIDs.length > 0 ? "warn" : "fail";
|
|
18287
18235
|
checks.push({
|
|
18288
18236
|
name: "min_fr_count",
|
|
@@ -18460,7 +18408,7 @@ function validateSpec(projectPath, taskSlug, size, specType, opts) {
|
|
|
18460
18408
|
message: `${confidenceCount}/${frIDs.length} FRs have confidence annotations`
|
|
18461
18409
|
});
|
|
18462
18410
|
}
|
|
18463
|
-
if (size === "L"
|
|
18411
|
+
if (size === "L") {
|
|
18464
18412
|
const nfrIDs = extractIDs(primaryContent, ID.NFR);
|
|
18465
18413
|
const taskNFRs = extractIDs(tasksContent, ID.NFR);
|
|
18466
18414
|
const unreferencedNFR = nfrIDs.filter((n) => !taskNFRs.includes(n));
|
|
@@ -18484,41 +18432,7 @@ function validateSpec(projectPath, taskSlug, size, specType, opts) {
|
|
|
18484
18432
|
message: "Research content may be insufficient"
|
|
18485
18433
|
});
|
|
18486
18434
|
}
|
|
18487
|
-
if (size === "
|
|
18488
|
-
const frIDs = extractIDs(primaryContent, ID.FR);
|
|
18489
|
-
const confidenceCount = (primaryContent.match(/<!--\s*confidence:/g) ?? []).length;
|
|
18490
|
-
const coverage = frIDs.length > 0 ? confidenceCount / frIDs.length : 1;
|
|
18491
|
-
checks.push(coverage >= .8 ? {
|
|
18492
|
-
name: "confidence_coverage",
|
|
18493
|
-
status: "pass",
|
|
18494
|
-
message: `${Math.round(coverage * 100)}% confidence coverage`
|
|
18495
|
-
} : {
|
|
18496
|
-
name: "confidence_coverage",
|
|
18497
|
-
status: "fail",
|
|
18498
|
-
message: `${Math.round(coverage * 100)}% confidence coverage (required: ≥80%)`
|
|
18499
|
-
});
|
|
18500
|
-
const waveHeaders = tasksContent.match(/## Wave\s+\d+/g) ?? [];
|
|
18501
|
-
checks.push(waveHeaders.length >= 4 ? {
|
|
18502
|
-
name: "xl_wave_count",
|
|
18503
|
-
status: "pass",
|
|
18504
|
-
message: `${waveHeaders.length} waves found`
|
|
18505
|
-
} : {
|
|
18506
|
-
name: "xl_wave_count",
|
|
18507
|
-
status: "fail",
|
|
18508
|
-
message: `${waveHeaders.length} waves found (required: ≥4 for XL)`
|
|
18509
|
-
});
|
|
18510
|
-
const nfrIDs = extractIDs(primaryContent, ID.NFR);
|
|
18511
|
-
checks.push(nfrIDs.length > 0 ? {
|
|
18512
|
-
name: "xl_nfr_required",
|
|
18513
|
-
status: "pass",
|
|
18514
|
-
message: `${nfrIDs.length} NFR-N found`
|
|
18515
|
-
} : {
|
|
18516
|
-
name: "xl_nfr_required",
|
|
18517
|
-
status: "fail",
|
|
18518
|
-
message: "No NFR-N found (required for XL)"
|
|
18519
|
-
});
|
|
18520
|
-
}
|
|
18521
|
-
if ((size === "L" || size === "XL") && primaryContent.includes("grounding:")) {
|
|
18435
|
+
if (size === "L" && primaryContent.includes("grounding:")) {
|
|
18522
18436
|
const groundingMatches = primaryContent.match(/grounding:\s*(\w+)/g) ?? [];
|
|
18523
18437
|
const speculative = groundingMatches.filter((g) => /speculative/i.test(g)).length;
|
|
18524
18438
|
const ratio = groundingMatches.length > 0 ? speculative / groundingMatches.length : 0;
|
|
@@ -18813,9 +18727,6 @@ var requirements_default$1 = "# Requirements: {{taskSlug}}\n\n> {{description}}\
|
|
|
18813
18727
|
//#region src/spec/templates/en/bugfix.tmpl
|
|
18814
18728
|
var bugfix_default$1 = "# Bugfix: {{taskSlug}}\n\n> {{description}}\n\n## Bug Summary\n\n<!-- 1-2 sentences. What happens vs. what should happen. -->\n\n## Severity & Impact\n\n| Field | Value |\n|-------|-------|\n| Severity | P0 (service down) / P1 (major feature broken) / P2 (workaround exists) / P3 (minor) |\n| Impact | |\n| Frequency | Always / under specific conditions / rare |\n| Workaround | Yes (describe) / None |\n\n## Reproduction Steps\n\n1.\n2.\n3.\n\n## Root Cause Analysis\n\n### 5 Whys\n\n1. Why? →\n2. Why? →\n3. Why? →\n4. Why? →\n5. Why (root cause)? →\n\n### Code Trace\n\n<!-- Exact paths and line numbers so implementor can locate the cause immediately. -->\n\n- **Symptom location**: `src/path/to/file.ts:line` — what happens\n- **Root cause location**: `src/path/to/file.ts:line` — why it happens\n- **Data flow**: input → processing → point of failure\n\n## Fix Strategy\n\n- **Target file**: `src/path/to/file.ts` — concrete change description\n- **Rejected alternatives**: other approaches and why dismissed\n- **Side-effect risk**: potential impact on other functionality\n\n## Unchanged Behavior\n\n<!-- What MUST NOT break. Implementor checks these BEFORE applying fix. -->\n\n- [ ] All existing tests pass\n- [ ]\n\n## Regression Prevention Test\n\n<!-- Test to detect recurrence. Also add to test-specs.md.\n Test MUST describe external-observable behavior only (no internal implementation references). -->\n\n```gherkin\nScenario: [Bug does not recur]\n Given [precondition that triggered the bug]\n When [action that caused the bug]\n Then [correct behavior]\n```\n";
|
|
18815
18729
|
//#endregion
|
|
18816
|
-
//#region src/spec/templates/en/delta.tmpl
|
|
18817
|
-
var delta_default$1 = "# Delta: {{taskSlug}}\n\n> {{description}}\n\n## Change Summary\n\n<!-- 1-2 sentences. What changes and why. -->\n\n## Files Affected\n\n### CHG-1: [Change description]\n\n- File: `src/path/to/file.ts`\n- Before: [current code or behavior]\n- After: [changed code or behavior]\n\n## Rationale\n\n<!-- Why this change is necessary. If alternatives exist, list them with rejection reasons.\n Important decisions MUST be persisted via `ledger save sub_type=decision`. -->\n\n## Impact Scope\n\n<!-- What else this change affects. If nothing, explicitly state \"no impact\". -->\n\n- **API compatibility**: Changed / Unchanged\n- **UI**: Changed / Unchanged\n- **Tests**: Modification needed / Not needed\n- **Performance**: Impacted / Not impacted\n\n## Unchanged Behavior\n\n<!-- What MUST NOT break. -->\n\n- [ ] All existing tests pass\n- [ ]\n\n## Test Plan\n\n<!-- How to verify the change is correct. Concrete commands or steps. -->\n\n## Rollback Strategy\n\n<!-- Recovery steps if problems occur. Is `git revert` sufficient, or is data migration needed? -->\n";
|
|
18818
|
-
//#endregion
|
|
18819
18730
|
//#region src/spec/templates/en/design.tmpl
|
|
18820
18731
|
var design_default$1 = "# Design: {{taskSlug}}\n\n## Architecture Overview\n\n<!-- ASCII diagram showing component structure and data flow.\n Implementor MUST create/modify files according to this diagram. -->\n\n## Component Design\n\n<!-- For each component: write Why and What. Minimize How — implementor decides. -->\n\n### [Component Name] (`src/path/to/file.ts`)\n\n- **Responsibility**: One sentence.\n- **Interface**:\n```typescript\n// Public function signatures and types. Implementor MUST follow this contract.\n```\n- **Dependencies**: Existing modules used\n- **Error handling**: Errors this component throws/returns\n\n## Data Models\n\n<!-- New/changed tables, type definitions. Write both SQL DDL and TypeScript types.\n Implementor uses these definitions directly in code. -->\n\n## API Contracts\n\n<!-- New/changed endpoints.\n Implementor MUST follow this contract exactly. No ad-hoc field additions. -->\n\n| Method | Path | Request | Response | Error |\n|--------|------|---------|----------|-------|\n| | | | | |\n\n## Error Scenarios\n\n<!-- List errors that CAN happen and HOW to handle them.\n AI tends to implement happy-path only. Errors not listed here will NOT be handled. -->\n\n| Scenario | Input/State | Expected Handling | HTTP/Exit |\n|----------|------------|-------------------|-----------|\n| | | | |\n\n## Boundary Conditions\n\n<!-- Typical edge cases AI misses. Implementation MUST cover these. -->\n\n- [ ] Empty input (null, undefined, \"\", [], {})\n- [ ] Maximum values (MAX_INT, very long strings, 1000+ records)\n- [ ] Concurrent access (simultaneous writes, race conditions)\n- [ ] Unicode / CJK / special characters\n- [ ] Unauthorized / expired auth\n- [ ] Network error / timeout\n- [ ] Remove non-applicable items\n\n## Design Decisions\n\n<!-- Important decisions MUST be persisted via `ledger save sub_type=decision`. -->\n\n| Decision | Choice | Rationale | Alternatives |\n|----------|--------|-----------|--------------|\n| | | | |\n\n## Non-Goals\n\n<!-- Align with Out of Scope in requirements.md.\n If implementor starts building out-of-scope features, refer here to stop. -->\n\n-\n\n## Traceability Matrix\n\n<!-- Every FR must map to component → task → test. No orphans allowed. -->\n\n| Req ID | Component | Task ID | Test ID |\n|--------|-----------|---------|---------|\n| FR-1 | | T-1.1 | TS-1.1 |\n";
|
|
18821
18732
|
//#endregion
|
|
@@ -18834,9 +18745,6 @@ var requirements_default = "# 要件定義: {{taskSlug}}\n\n> {{description}}\n\
|
|
|
18834
18745
|
//#region src/spec/templates/ja/bugfix.tmpl
|
|
18835
18746
|
var bugfix_default = "# バグ修正: {{taskSlug}}\n\n> {{description}}\n\n## バグ概要\n\n<!-- 1-2 文。何が起きるか vs 何が正しい動作か。 -->\n\n## 重要度と影響範囲\n\n| 項目 | 内容 |\n|------|------|\n| 重要度 | P0 (サービス停止) / P1 (主要機能障害) / P2 (回避策あり) / P3 (軽微) |\n| 影響範囲 | |\n| 頻度 | 常に / 特定条件下 / 稀 |\n| 回避策 | あり (内容) / なし |\n\n## 再現手順\n\n1.\n2.\n3.\n\n## 原因分析\n\n### 5 Whys\n\n1. なぜ?→\n2. なぜ?→\n3. なぜ?→\n4. なぜ?→\n5. なぜ(根本原因)?→\n\n### コードトレース\n\n<!-- 実装者が原因箇所を即座に特定できるよう、正確なパスと行番号を書く。 -->\n\n- **発症箇所**: `src/path/to/file.ts:line` — 何が起きるか\n- **原因箇所**: `src/path/to/file.ts:line` — なぜ起きるか\n- **データフロー**: 入力 → 処理 → 問題が生じるポイント\n\n## 修正方針\n\n- **変更対象**: `src/path/to/file.ts` — 具体的にどう変えるか\n- **選択しなかった方法**: 代替案と却下理由\n- **副作用リスク**: 修正が他に影響する可能性\n\n## 変更不可の動作\n\n<!-- 修正で壊してはいけないもの。実装者はここを確認してから修正すること。 -->\n\n- [ ] 既存テスト全件パス\n- [ ]\n\n## リグレッション防止テスト\n\n<!-- このバグの再発を検知するテスト。test-specs.md にも追加すること。\n テストは外部観測可能な振る舞いのみ(内部実装を参照しない)。 -->\n\n```gherkin\nScenario: [バグの再発防止]\n Given [バグ発生の前提条件]\n When [バグを引き起こす操作]\n Then [正常な動作]\n```\n";
|
|
18836
18747
|
//#endregion
|
|
18837
|
-
//#region src/spec/templates/ja/delta.tmpl
|
|
18838
|
-
var delta_default = "# 差分変更: {{taskSlug}}\n\n> {{description}}\n\n## 変更概要\n\n<!-- 1-2 文。何を変えるか、なぜ変えるか。 -->\n\n## 影響ファイル\n\n### CHG-1: [変更内容]\n\n- File: `src/path/to/file.ts`\n- Before: [現在のコードまたは動作]\n- After: [変更後のコードまたは動作]\n\n## 変更理由\n\n<!-- なぜこの変更が必要か。代替案があれば記載し却下理由も書く。\n 重要な判断は `ledger save sub_type=decision` で永続化。 -->\n\n## 影響範囲\n\n<!-- この変更が影響する他の機能/コンポーネント。\n 影響なしの場合も「影響なし」と明記する。 -->\n\n- **API 互換性**: 変更あり / なし\n- **UI**: 変更あり / なし\n- **テスト**: 修正必要 / 不要\n- **パフォーマンス**: 影響あり / なし\n\n## 変更不可の動作\n\n<!-- この変更で壊してはいけないもの。 -->\n\n- [ ] 既存テスト全件パス\n- [ ]\n\n## テスト計画\n\n<!-- 変更の正しさをどう確認するか。具体的なコマンドまたは手順。 -->\n\n## ロールバック手順\n\n<!-- 問題が起きた場合の復旧手順。`git revert` で十分か、データ migration が必要か。 -->\n";
|
|
18839
|
-
//#endregion
|
|
18840
18748
|
//#region src/spec/templates/ja/design.tmpl
|
|
18841
18749
|
var design_default = "# 設計: {{taskSlug}}\n\n## アーキテクチャ概要\n\n<!-- ASCII ダイアグラムでコンポーネント構成とデータフローを示す。\n 実装者はこの図に従ってファイルを作成/変更すること。 -->\n\n## コンポーネント設計\n\n<!-- 各コンポーネントに以下を記載。Why と What を書く。How は最小限 — 実装者が判断する。 -->\n\n### [コンポーネント名] (`src/path/to/file.ts`)\n\n- **責務**: 1文で。\n- **インターフェース**:\n```typescript\n// 公開する関数シグネチャと型を書く。実装者はこの契約に従う。\n```\n- **依存**: 使用する既存モジュール\n- **エラー処理**: このコンポーネントが throw/return するエラー\n\n## データモデル\n\n<!-- 新規/変更テーブル、型定義。SQL DDL + TypeScript 型を両方書く。\n 実装者はここの定義をそのままコードに使う。 -->\n\n## API 契約\n\n<!-- 新規/変更エンドポイント。\n 実装者はこの契約に正確に従うこと。勝手なフィールド追加禁止。 -->\n\n| Method | Path | Request | Response | Error |\n|--------|------|---------|----------|-------|\n| | | | | |\n\n## エラーシナリオ\n\n<!-- 正常系だけでなく、発生しうるエラーとその処理方法を列挙する。\n AI は happy-path のみ実装する傾向がある。ここで明示しないエラーは処理されない。 -->\n\n| シナリオ | 入力/状態 | 期待する処理 | HTTP/Exit |\n|----------|----------|-------------|-----------|\n| | | | |\n\n## 境界条件\n\n<!-- AI が見落とす典型的なエッジケース。実装時に必ずカバーすること。 -->\n\n- [ ] 空入力 (null, undefined, \"\", [], {})\n- [ ] 最大値 (MAX_INT, 長大文字列, 1000+ レコード)\n- [ ] 並行アクセス (同時書き込み, レース条件)\n- [ ] Unicode / 日本語 / 特殊文字\n- [ ] 権限なし / 認証切れ\n- [ ] ネットワークエラー / タイムアウト\n- [ ] 該当なし項目は削除すること\n\n## 設計判断\n\n<!-- 重要な判断は `ledger save sub_type=decision` で永続化すること。 -->\n\n| 判断 | 選択 | 理由 | 代替案 |\n|------|------|------|--------|\n| | | | |\n\n## やらないこと\n\n<!-- requirements.md の Out of Scope と整合。\n 実装者がスコープ外の機能を作り始めたらここを参照して止める。 -->\n\n-\n\n## トレーサビリティマトリクス\n\n<!-- 全 FR がコンポーネント → タスク → テストに紐づくこと。孤立禁止。 -->\n\n| Req ID | Component | Task ID | Test ID |\n|--------|-----------|---------|---------|\n| FR-1 | | T-1.1 | TS-1.1 |\n";
|
|
18842
18750
|
//#endregion
|
|
@@ -18854,7 +18762,6 @@ init_types();
|
|
|
18854
18762
|
const EN_TEMPLATES = {
|
|
18855
18763
|
"requirements.md": requirements_default$1,
|
|
18856
18764
|
"bugfix.md": bugfix_default$1,
|
|
18857
|
-
"delta.md": delta_default$1,
|
|
18858
18765
|
"design.md": design_default$1,
|
|
18859
18766
|
"tasks.md": tasks_default$1,
|
|
18860
18767
|
"test-specs.md": test_specs_default$1,
|
|
@@ -18863,7 +18770,6 @@ const EN_TEMPLATES = {
|
|
|
18863
18770
|
const JA_TEMPLATES = {
|
|
18864
18771
|
"requirements.md": requirements_default,
|
|
18865
18772
|
"bugfix.md": bugfix_default,
|
|
18866
|
-
"delta.md": delta_default,
|
|
18867
18773
|
"design.md": design_default,
|
|
18868
18774
|
"tasks.md": tasks_default,
|
|
18869
18775
|
"test-specs.md": test_specs_default,
|
|
@@ -18892,18 +18798,16 @@ init_types();
|
|
|
18892
18798
|
function initSpec(projectPath, taskSlug, description, opts) {
|
|
18893
18799
|
if (!VALID_SLUG.test(taskSlug)) throw new Error(`invalid task_slug "${taskSlug}": must be lowercase alphanumeric with hyphens (e.g., 'add-auth')`);
|
|
18894
18800
|
const size = opts?.size ?? detectSize(description);
|
|
18895
|
-
|
|
18896
|
-
if (size === "D") specType = "delta";
|
|
18801
|
+
const specType = opts?.specType ?? "feature";
|
|
18897
18802
|
const sd = new SpecDir(projectPath, taskSlug);
|
|
18898
18803
|
if (sd.exists()) throw new Error(`spec already exists for '${taskSlug}'; use dossier action=update to modify`);
|
|
18899
18804
|
mkdirSync(sd.dir(), { recursive: true });
|
|
18900
|
-
const
|
|
18805
|
+
const rendered = renderForSize(size, specType, {
|
|
18901
18806
|
taskSlug,
|
|
18902
18807
|
description,
|
|
18903
18808
|
date: (/* @__PURE__ */ new Date()).toISOString().slice(0, 10),
|
|
18904
18809
|
specType
|
|
18905
|
-
};
|
|
18906
|
-
const rendered = renderForSize(size, specType, data);
|
|
18810
|
+
});
|
|
18907
18811
|
const files = filesForSize(size, specType);
|
|
18908
18812
|
try {
|
|
18909
18813
|
for (const f of files) {
|
|
@@ -19003,11 +18907,7 @@ async function dossierInit(projectPath, store, emb, params) {
|
|
|
19003
18907
|
const lang = process.env.ALFRED_LANG || "en";
|
|
19004
18908
|
result.lang = lang;
|
|
19005
18909
|
if (lang !== "en") result.lang_directive = `Write ALL spec content in ${lang === "ja" ? "Japanese (日本語)" : lang}. Technical terms and IDs (FR-N, T-N.N, etc.) stay in English.`;
|
|
19006
|
-
result.onboarding_hint = `Spec '${params.task_slug}' created (size: ${initResult.size}). Next: write spec files → self-review → ${[
|
|
19007
|
-
"M",
|
|
19008
|
-
"L",
|
|
19009
|
-
"XL"
|
|
19010
|
-
].includes(initResult.size) ? "dashboard approval → " : ""}implement per wave.`;
|
|
18910
|
+
result.onboarding_hint = `Spec '${params.task_slug}' created (size: ${initResult.size}). Next: write spec files → self-review → ${["M", "L"].includes(initResult.size) ? "dashboard approval → " : ""}implement per wave.`;
|
|
19011
18911
|
try {
|
|
19012
18912
|
writeReviewGate(projectPath, {
|
|
19013
18913
|
gate: "spec-review",
|
|
@@ -19071,11 +18971,7 @@ function dossierComplete(projectPath, store, params) {
|
|
|
19071
18971
|
const task = readActiveState(projectPath).tasks.find((t) => t.slug === taskSlug);
|
|
19072
18972
|
if (task) {
|
|
19073
18973
|
const size = task.size ?? "L";
|
|
19074
|
-
if ([
|
|
19075
|
-
"M",
|
|
19076
|
-
"L",
|
|
19077
|
-
"XL"
|
|
19078
|
-
].includes(size)) {
|
|
18974
|
+
if (["M", "L"].includes(size)) {
|
|
19079
18975
|
const reviewStatus = reviewStatusFor(projectPath, taskSlug);
|
|
19080
18976
|
if (reviewStatus !== "approved") return errorResult$1(`completion requires review_status="approved" for ${size} specs (current: "${reviewStatus || "pending"}"). Review in alfred dashboard.`);
|
|
19081
18977
|
const verification = verifyReviewFile(projectPath, taskSlug);
|
|
@@ -19603,7 +19499,7 @@ function createMCPServer(store, emb, version) {
|
|
|
19603
19499
|
Actions: status (read-only), init, update, switch, complete, delete (2-phase: preview then confirm=true), history, rollback, review, validate (read-only), gate (review gate management), check (mark task completed), defer (toggle deferred/resume), cancel.
|
|
19604
19500
|
|
|
19605
19501
|
task_slug format: lowercase alphanumeric with hyphens (e.g. "my-feature", max 64 chars).
|
|
19606
|
-
Size-based scaling: init accepts size (S/M/L
|
|
19502
|
+
Size-based scaling: init accepts size (S/M/L) and spec_type (feature/bugfix). S=3 files, M=4 files, L=5 files.`, {
|
|
19607
19503
|
action: enumType([
|
|
19608
19504
|
"init",
|
|
19609
19505
|
"update",
|
|
@@ -19638,8 +19534,7 @@ Size-based scaling: init accepts size (S/M/L/XL) and spec_type (feature/bugfix).
|
|
|
19638
19534
|
size: enumType([
|
|
19639
19535
|
"S",
|
|
19640
19536
|
"M",
|
|
19641
|
-
"L"
|
|
19642
|
-
"XL"
|
|
19537
|
+
"L"
|
|
19643
19538
|
]).optional().describe("Spec size for init"),
|
|
19644
19539
|
spec_type: enumType(["feature", "bugfix"]).optional().describe("Spec type for init"),
|
|
19645
19540
|
version: stringType().optional().describe("Version timestamp for rollback"),
|