claude-alfred 0.3.21 → 0.3.23
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-BUfNnVyn.mjs} +1 -1
- package/dist/cli.mjs +3 -3
- package/dist/{directives-DfzKzUAL.mjs → directives-B-imQAUP.mjs} +1 -1
- package/dist/{dispatcher-BDl_Flyx.mjs → dispatcher-DcHtDI_E.mjs} +6 -6
- package/dist/{drift-CKOseTmh.mjs → drift-B5k7Dh4l.mjs} +3 -3
- package/dist/{epic-CfxJ13zy.mjs → epic-BHZ71Dpf.mjs} +1 -1
- package/dist/{living-spec-BfQnawom.mjs → living-spec-CljcxM8t.mjs} +2 -2
- package/dist/post-tool-CFzH1-dY.mjs +11 -0
- package/dist/{post-tool-DpBkq5ik.mjs → post-tool-DPLHW9jK.mjs} +73 -8
- package/dist/{pre-compact-Cncx9q7L.mjs → pre-compact-CMyhPLfd.mjs} +5 -9
- package/dist/{pre-tool-Dyp4S8cV.mjs → pre-tool-PQfosCOP.mjs} +8 -8
- package/dist/{review-gate-7Pfe_A-8.mjs → review-gate-BpjBk-63.mjs} +1 -3
- package/dist/{server-D3b54XYU.mjs → server-BsyPli_m.mjs} +106 -146
- package/dist/{server-CYUJFZhW.mjs → server-zYXME7cg.mjs} +5 -10
- package/dist/{session-start-CU4-KivX.mjs → session-start-CBXKeCj1.mjs} +8 -5
- package/dist/{stop-CGv96IQd.mjs → stop-DOflmlLk.mjs} +2 -2
- package/dist/{types-K2jxpWyU.mjs → types-zr3tpkx_.mjs} +20 -19
- package/dist/{user-prompt-BPAOU8f-.mjs → user-prompt-vC5iWoT9.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-CkrDwuag.js +10 -0
- package/web/dist/assets/{knowledge-Cf76s4T9.js → knowledge-Cdx9JmHO.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-B52O9LSS.js +1 -0
- package/web/dist/assets/tasks._slug-EehLhqoN.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-zr3tpkx_.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-BsyPli_m.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-zYXME7cg.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-DcHtDI_E.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-DcHtDI_E.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-CBXKeCj1.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-CMyhPLfd.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-vC5iWoT9.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-CFzH1-dY.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-PQfosCOP.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-DOflmlLk.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-zr3tpkx_.mjs";
|
|
4
|
+
import { n as init_audit, t as appendAudit } from "./audit-BUfNnVyn.mjs";
|
|
5
|
+
import { extractChangedFiles, n as init_lang_filter, parseDesignFileRefs, r as shouldAutoAppend, t as init_living_spec } from "./living-spec-CljcxM8t.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-zr3tpkx_.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-zr3tpkx_.mjs";
|
|
4
|
+
import { n as init_audit, t as appendAudit } from "./audit-BUfNnVyn.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
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import "./types-zr3tpkx_.mjs";
|
|
3
|
+
import "./audit-BUfNnVyn.mjs";
|
|
4
|
+
import "./dispatcher-DcHtDI_E.mjs";
|
|
5
|
+
import "./directives-B-imQAUP.mjs";
|
|
6
|
+
import { a as postToolUse, n as init_post_tool } from "./post-tool-DPLHW9jK.mjs";
|
|
7
|
+
import "./store-BffM-bi-.mjs";
|
|
8
|
+
import "./review-gate-BpjBk-63.mjs";
|
|
9
|
+
import "./state-Cih-8_Zc.mjs";
|
|
10
|
+
init_post_tool();
|
|
11
|
+
export { postToolUse };
|
|
@@ -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-zr3tpkx_.mjs";
|
|
4
|
+
import { n as init_audit, t as appendAudit } from "./audit-BUfNnVyn.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-DcHtDI_E.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-B-imQAUP.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-BpjBk-63.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";
|
|
@@ -155,14 +155,76 @@ function writeKnowledgeFile(projectPath, subType, id, entry) {
|
|
|
155
155
|
atomicWriteSync(join(projectPath, ".alfred", "knowledge", filePath), `${JSON.stringify(entry, null, 2)}\n`);
|
|
156
156
|
return filePath;
|
|
157
157
|
}
|
|
158
|
+
/**
|
|
159
|
+
* Build embedding text optimized per sub_type for vector search.
|
|
160
|
+
* Truncated to MAX_EMBEDDING_LENGTH to avoid model token limits.
|
|
161
|
+
*/
|
|
162
|
+
function buildEmbeddingText(subType, params) {
|
|
163
|
+
let parts;
|
|
164
|
+
switch (subType) {
|
|
165
|
+
case "decision":
|
|
166
|
+
parts = [
|
|
167
|
+
params.title ?? "",
|
|
168
|
+
params.context_text ?? "",
|
|
169
|
+
params.decision ?? "",
|
|
170
|
+
params.alternatives ?? ""
|
|
171
|
+
];
|
|
172
|
+
break;
|
|
173
|
+
case "pattern":
|
|
174
|
+
parts = [
|
|
175
|
+
params.title ?? "",
|
|
176
|
+
params.context_text ?? "",
|
|
177
|
+
params.pattern ?? "",
|
|
178
|
+
params.application_conditions ?? ""
|
|
179
|
+
];
|
|
180
|
+
break;
|
|
181
|
+
case "rule":
|
|
182
|
+
parts = [
|
|
183
|
+
params.title ?? "",
|
|
184
|
+
params.text ?? "",
|
|
185
|
+
params.rationale ?? "",
|
|
186
|
+
params.category ?? ""
|
|
187
|
+
];
|
|
188
|
+
break;
|
|
189
|
+
default: parts = [params.title ?? "", params.context_text ?? ""];
|
|
190
|
+
}
|
|
191
|
+
const text = parts.filter(Boolean).join(" ");
|
|
192
|
+
return text.length > MAX_EMBEDDING_LENGTH ? text.slice(0, MAX_EMBEDDING_LENGTH) : text;
|
|
193
|
+
}
|
|
158
194
|
function parseTags(tagsStr) {
|
|
159
195
|
return (tagsStr ?? "").split(",").map((t) => t.trim()).filter(Boolean);
|
|
160
196
|
}
|
|
197
|
+
/**
|
|
198
|
+
* Detect serialized JSON objects/arrays dumped into text fields.
|
|
199
|
+
*/
|
|
200
|
+
function looksLikeJSON(s) {
|
|
201
|
+
const t = s.trim();
|
|
202
|
+
return t.startsWith("{") && t.endsWith("}") || t.startsWith("[") && t.endsWith("]");
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* Validate knowledge fields before saving. Rejects garbage data early.
|
|
206
|
+
*/
|
|
207
|
+
function validateKnowledgeFields(params) {
|
|
208
|
+
if (params.title && looksLikeJSON(params.title)) return "title must be natural language, not JSON. Provide a concise summary sentence.";
|
|
209
|
+
if (params.title && params.title.length > MAX_TITLE_LENGTH) return `title must be ${MAX_TITLE_LENGTH} characters or less (got ${params.title.length})`;
|
|
210
|
+
if (params.label && looksLikeJSON(params.label)) return "label must be natural language, not JSON.";
|
|
211
|
+
for (const [field, value] of [
|
|
212
|
+
["decision", params.decision],
|
|
213
|
+
["pattern", params.pattern],
|
|
214
|
+
["text", params.text],
|
|
215
|
+
["reasoning", params.reasoning]
|
|
216
|
+
]) if (value && looksLikeJSON(value)) return `${field} must be natural language, not JSON. Describe the ${field} in plain text.`;
|
|
217
|
+
if (params.title?.trim() === "") return "title must not be empty or whitespace-only";
|
|
218
|
+
if (params.label?.trim() === "") return "label must not be empty or whitespace-only";
|
|
219
|
+
return null;
|
|
220
|
+
}
|
|
161
221
|
async function ledgerSave(store, emb, params) {
|
|
162
222
|
const subType = params.sub_type;
|
|
163
223
|
if (!subType || !VALID_SUB_TYPES.includes(subType)) return errorResult("sub_type must be decision, pattern, or rule");
|
|
164
224
|
if (!params.title) return errorResult("title is required for save");
|
|
165
225
|
if (!params.label) return errorResult("label is required for save");
|
|
226
|
+
const validationError = validateKnowledgeFields(params);
|
|
227
|
+
if (validationError) return errorResult(validationError);
|
|
166
228
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
167
229
|
const lang = toLang();
|
|
168
230
|
const tags = parseTags(params.tags);
|
|
@@ -252,7 +314,7 @@ async function ledgerSave(store, emb, params) {
|
|
|
252
314
|
let embeddingStatus = "none";
|
|
253
315
|
if (emb && changed) {
|
|
254
316
|
const model = emb.model;
|
|
255
|
-
const embText =
|
|
317
|
+
const embText = buildEmbeddingText(subType, params);
|
|
256
318
|
emb.embedForStorage(embText).then(async (vec) => {
|
|
257
319
|
const { insertEmbedding } = await import("./vectors-DHZGQ096.mjs").then((n) => (n.t(), n.i));
|
|
258
320
|
insertEmbedding(store, "knowledge", dbId, model, vec);
|
|
@@ -348,12 +410,15 @@ async function ledgerReflect(store, emb, _params) {
|
|
|
348
410
|
lang
|
|
349
411
|
});
|
|
350
412
|
}
|
|
413
|
+
var MAX_EMBEDDING_LENGTH, MAX_TITLE_LENGTH;
|
|
351
414
|
var init_ledger = __esmMin((() => {
|
|
352
415
|
init_fts();
|
|
353
416
|
init_knowledge();
|
|
354
417
|
init_project();
|
|
355
418
|
init_types();
|
|
356
419
|
init_helpers();
|
|
420
|
+
MAX_EMBEDDING_LENGTH = 1500;
|
|
421
|
+
MAX_TITLE_LENGTH = 200;
|
|
357
422
|
}));
|
|
358
423
|
//#endregion
|
|
359
424
|
//#region src/mcp/knowledge-extractor.ts
|
|
@@ -575,11 +640,11 @@ async function handleBashResult(ev, items, signal) {
|
|
|
575
640
|
if (isGitCommit(response.stdout ?? "") && !signal.aborted) {
|
|
576
641
|
let appendedFiles = /* @__PURE__ */ new Set();
|
|
577
642
|
try {
|
|
578
|
-
const { handleLivingSpec } = await import("./living-spec-
|
|
643
|
+
const { handleLivingSpec } = await import("./living-spec-CljcxM8t.mjs");
|
|
579
644
|
appendedFiles = handleLivingSpec(ev.cwd);
|
|
580
645
|
} catch {}
|
|
581
646
|
try {
|
|
582
|
-
const { detectDrift } = await import("./drift-
|
|
647
|
+
const { detectDrift } = await import("./drift-B5k7Dh4l.mjs");
|
|
583
648
|
detectDrift(ev.cwd, appendedFiles, items);
|
|
584
649
|
} catch {}
|
|
585
650
|
await checkKnowledgeConflicts(items);
|
|
@@ -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-zr3tpkx_.mjs";
|
|
4
|
+
import { r as init_epic, s as syncTaskStatus } from "./epic-BHZ71Dpf.mjs";
|
|
5
|
+
import { n as init_audit, t as appendAudit } from "./audit-BUfNnVyn.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-DcHtDI_E.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-zr3tpkx_.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-BpjBk-63.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-zr3tpkx_.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([
|