claude-alfred 0.3.0 → 0.3.2

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.
Files changed (62) hide show
  1. package/README.ja.md +3 -2
  2. package/README.md +4 -3
  3. package/dist/{audit-DMxi6YnF.mjs → audit-6NSlW0Ut.mjs} +5 -7
  4. package/dist/cli.mjs +10 -12
  5. package/dist/{directives-B23lVUGt.mjs → directives-ko2sX5BW.mjs} +5 -5
  6. package/dist/{dispatcher-bW4qDAhl.mjs → dispatcher-BnBtA4bo.mjs} +9 -9
  7. package/dist/{embedder-qPO74Ar-.mjs → embedder-BRG2Xpr4.mjs} +4 -5
  8. package/dist/{fts-DInh3bOQ.mjs → fts-QWdC_4Zv.mjs} +2 -2
  9. package/dist/{helpers-C6av-rsB.mjs → helpers-BnPVn8Nv.mjs} +6 -6
  10. package/dist/{knowledge-CicKSdup.mjs → knowledge-B0fsJ9SI.mjs} +19 -5
  11. package/dist/{post-tool-CFyBxFlB.mjs → post-tool-gG8qG5Ee.mjs} +19 -28
  12. package/dist/postinstall.mjs +1 -1
  13. package/dist/{pre-compact-CUPQ3Qj-.mjs → pre-compact-CwvBi5op.mjs} +5 -5
  14. package/dist/{pre-tool-BcdaDusF.mjs → pre-tool-BMCYjtHT.mjs} +2 -2
  15. package/dist/{server-B0gr3On1.mjs → server-CHdcikXe.mjs} +41 -41
  16. package/dist/{server-DhEN_dME.mjs → server-Df8fib2F.mjs} +2473 -2346
  17. package/dist/{session-start-l9fkYqD5.mjs → session-start-dPl4lfZw.mjs} +20 -70
  18. package/dist/{spec-guard-ntNzlw8B.mjs → spec-guard-BGwtCxgH.mjs} +4 -4
  19. package/dist/state-CdHO66SV.mjs +53 -0
  20. package/dist/{stop-BEMycnn1.mjs → stop-NL5GdPNy.mjs} +2 -2
  21. package/dist/{user-prompt-COyVgW_-.mjs → user-prompt-o9rlzB2I.mjs} +17 -30
  22. package/dist/{vectors-B5WOzF-3.mjs → vectors-BDQP0gaa.mjs} +2 -2
  23. package/package.json +4 -1
  24. package/web/dist/assets/activity-mXF0VmCt.js +1 -0
  25. package/web/dist/assets/api-BpnabbKu.js +1 -0
  26. package/web/dist/assets/badge-CBFM8JtH.js +1 -0
  27. package/web/dist/assets/button-CBPUE5Y6.js +14 -0
  28. package/web/dist/assets/checkbox-B_KjCpy7.js +1 -0
  29. package/web/dist/assets/{circle-dot-BPxCviEE.js → circle-dot-BMf8wYDE.js} +1 -1
  30. package/web/dist/assets/createLucideIcon-MCX4k61-.js +1 -0
  31. package/web/dist/assets/dist-7qozDZTq.js +1 -0
  32. package/web/dist/assets/index-CNTBHHOa.js +10 -0
  33. package/web/dist/assets/index-uhr7UtxX.css +1 -0
  34. package/web/dist/assets/knowledge-wd_PIN8X.js +59 -0
  35. package/web/dist/assets/{link-DqICqa6t.js → link-D7DRVryP.js} +1 -1
  36. package/web/dist/assets/progress-B0hcYV7D.js +6 -0
  37. package/web/dist/assets/routes-DUyvG12-.js +1 -0
  38. package/web/dist/assets/separator-0fdLqhBM.js +1 -0
  39. package/web/dist/assets/skeleton-CLJEM3zd.js +1 -0
  40. package/web/dist/assets/tasks-pPCS6lSa.js +1 -0
  41. package/web/dist/assets/tasks._slug-C-Z_7eYZ.js +35 -0
  42. package/web/dist/assets/useParams-CJl-SvaR.js +1 -0
  43. package/web/dist/index.html +6 -6
  44. package/web/dist/assets/activity-QgmI9mew.js +0 -1
  45. package/web/dist/assets/api-Cq0fYMlI.js +0 -1
  46. package/web/dist/assets/card-BcSoTIRX.js +0 -1
  47. package/web/dist/assets/circle-BL_hGKys.js +0 -1
  48. package/web/dist/assets/createLucideIcon-BsT1VhJi.js +0 -1
  49. package/web/dist/assets/dist-BoQ-HzPG.js +0 -1
  50. package/web/dist/assets/index-BBgUhwsZ.js +0 -10
  51. package/web/dist/assets/index-D3MHfJUi.css +0 -1
  52. package/web/dist/assets/knowledge-hAa3Wi3j.js +0 -15
  53. package/web/dist/assets/lib-B4Vj6fDL.js +0 -58
  54. package/web/dist/assets/matchContext-Djmy2MvT.js +0 -1
  55. package/web/dist/assets/progress-Dq-nvFJj.js +0 -6
  56. package/web/dist/assets/routes-mB72Gd2i.js +0 -1
  57. package/web/dist/assets/separator-CMQXCJRe.js +0 -1
  58. package/web/dist/assets/skeleton-CG9s_VrV.js +0 -1
  59. package/web/dist/assets/tasks-Dm4Gt0QY.js +0 -1
  60. package/web/dist/assets/tasks._slug-Cjjewclt.js +0 -42
  61. package/web/dist/assets/utils-muoz4bGA.js +0 -1
  62. /package/dist/{store-D-S-ZKaA.mjs → store-CuN3_dWu.mjs} +0 -0
package/README.ja.md CHANGED
@@ -131,7 +131,7 @@ npm update -g claude-alfred # CLI、hooks、MCP サーバー、ダッシ
131
131
 
132
132
  | イベント | 動作 |
133
133
  |----------|------|
134
- | SessionStart | 仕様コンテキスト復元 + CLAUDE.md 取込 + 1%ルール(スキル発動促進)+ 成熟度適応 |
134
+ | SessionStart | 仕様コンテキスト復元 + ナレッジ同期 + 1%ルール(スキル発動促進)+ 成熟度適応 |
135
135
  | PreCompact | スナップショット保存 + 決定抽出 + エピック進捗同期 + 調査パターン検出 |
136
136
  | UserPromptSubmit | セマンティック検索 + スキルナッジ + **spec承認ゲート**(未承認 M/L/XL に DIRECTIVE) |
137
137
  | PostToolUse | エラー検出 + Next Steps 自動チェック + ドリフト検出 + コミット時決定保存 |
@@ -149,7 +149,7 @@ alfred dashboard --url-only # URLだけ出力
149
149
  | タブ | 表示内容 |
150
150
  |------|----------|
151
151
  | **Overview** | プロジェクトの健康状態 — タスク進捗とバリデーション結果、メモリ健康度(陳腐化数・矛盾数)、仕様の信頼度分布、エピック進捗、最近の意思決定 |
152
- | **Tasks** | タスクカード: 現在のフォーカス、次のアクション、エピック、バリデーションバッジ。仕様ファイルの閲覧。Review タブでインラインコメント |
152
+ | **Tasks** | Active/Completed セクション分離。タスクをクリックで2カラム詳細ビュー: 左にメタデータ、右に折りたたみ可能なspecセクション(色分け付き)。Review タブでインラインコメント |
153
153
  | **Knowledge** | メモリ一覧(サブタイプ別タグ付き)。セマンティック検索(Voyage AI、300msデバウンス)。ローカルテキストフィルタ。メモリの有効/無効切り替え |
154
154
  | **Activity** | 操作タイムライン。イベントタイプ別フィルタ(init/complete/review)。エピックドリルダウン |
155
155
 
@@ -281,6 +281,7 @@ Hook(見えない)
281
281
  | `.alfred/epics/` | 最初のエピック作成時 | `roster action=init` |
282
282
  | `.alfred/steering/` | `/alfred:init` 実行時 | プロジェクト初期化スキル |
283
283
  | `.alfred/templates/` | ユーザーが仕様・Steeringテンプレートをカスタマイズする時 | テンプレートオーバーライド用に手動作成 |
284
+ | `.alfred/.state/` | 最初のセッションローカル状態保存時 | ナッジ抑制カウント、探索カウンター(gitignore対象) |
284
285
  | `.alfred/audit.jsonl` | 最初の仕様操作時またはコミット後ドリフト検出時 | `dossier init`、レビュー送信、PostToolUse ドリフト |
285
286
 
286
287
  ## トラブルシューティング
package/README.md CHANGED
@@ -131,7 +131,7 @@ Run automatically. You don't touch these.
131
131
 
132
132
  | Event | What happens |
133
133
  |-------|-------------|
134
- | SessionStart | Restores spec context, ingests CLAUDE.md, adapts injection depth to project maturity, 1% rule skill activation |
134
+ | SessionStart | Restores spec context, syncs knowledge index, adapts injection depth to project maturity, 1% rule skill activation |
135
135
  | PreCompact | Extracts decisions, saves chapter snapshots, syncs epic progress, detects research patterns |
136
136
  | UserPromptSubmit | Semantic search + file context boost + **skill nudge** + **spec approval gate** (blocks implement intent on unapproved M/L/XL specs) |
137
137
  | PostToolUse | Detects Bash errors + searches memory. After commits: spec drift detection + auto-save decisions. Edit/Write: auto-check Next Steps progress |
@@ -149,7 +149,7 @@ alfred dashboard --url-only # print URL only
149
149
  | Tab | What you see |
150
150
  |-----|-------------|
151
151
  | **Overview** | Project health at a glance — task progress with validation badges, memory health (stale count, conflicts), confidence distribution across specs, epic progress, recent decisions |
152
- | **Tasks** | Enriched task cards: current focus, next action, epic context, validation status. Drill into spec files. Switch to Review tab for inline comments |
152
+ | **Tasks** | Active/Completed sections. Drill into any task for a 2-column detail view: metadata on the left, collapsible spec sections (color-coded) on the right. Switch to Review tab for inline comments |
153
153
  | **Knowledge** | Browse all memories with sub-type tags. Semantic search (Voyage AI) with 300ms debounce. Local text filter. Toggle any memory on/off |
154
154
  | **Activity** | Timeline of all operations. Filter by event type (init/complete/review). Epic drill-down with task status badges |
155
155
 
@@ -252,7 +252,7 @@ You
252
252
  |
253
253
  v
254
254
  Hooks (invisible)
255
- |-- SessionStart -> restore context, 1% rule, adapt to project maturity
255
+ |-- SessionStart -> restore context, sync knowledge, 1% rule, adapt to project maturity
256
256
  |-- PreCompact -> save snapshots, extract decisions, epic progress
257
257
  |-- UserPromptSubmit -> vector search + FTS5 + skill nudge + spec approval check
258
258
  |-- PostToolUse -> detect errors, auto-check Next Steps, drift detection
@@ -281,6 +281,7 @@ Nothing is generated at install time. Files appear as you use alfred:
281
281
  | `.alfred/epics/` | First epic is created | `roster action=init` |
282
282
  | `.alfred/steering/` | Running `/alfred:init` | Project initialization skill |
283
283
  | `.alfred/templates/` | User customizes spec or steering templates | Manual creation for template override |
284
+ | `.alfred/.state/` | First hook that needs session-local state | Nudge dismissals, exploration counter (gitignored) |
284
285
  | `.alfred/audit.jsonl` | First spec operation or commit drift detection | `dossier init`, `dossier delete`, review submission, PostToolUse drift |
285
286
 
286
287
  ## Troubleshooting
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { E as require_dist, S as rootDir, m as VALID_SLUG } from "./knowledge-CicKSdup.mjs";
2
+ import { C as rootDir, D as require_dist, h as VALID_SLUG } from "./knowledge-B0fsJ9SI.mjs";
3
3
  import { appendFileSync, mkdirSync, readFileSync, readdirSync, renameSync, rmSync, statSync, writeFileSync } from "node:fs";
4
4
  import { join } from "node:path";
5
5
  //#region src/epic/index.ts
@@ -39,7 +39,7 @@ var EpicDir = class {
39
39
  }
40
40
  save(ep) {
41
41
  const data = (0, import_dist.stringify)(ep);
42
- const tmp = this.epicPath() + ".tmp";
42
+ const tmp = `${this.epicPath()}.tmp`;
43
43
  writeFileSync(tmp, data);
44
44
  renameSync(tmp, this.epicPath());
45
45
  }
@@ -161,9 +161,7 @@ function listAllEpics(projectPath) {
161
161
  total: tasks.length,
162
162
  tasks
163
163
  });
164
- } catch {
165
- continue;
166
- }
164
+ } catch {}
167
165
  }
168
166
  return summaries;
169
167
  }
@@ -219,7 +217,7 @@ function writeActiveEpics(projectPath, state) {
219
217
  mkdirSync(epicsDir(projectPath), { recursive: true });
220
218
  const data = (0, import_dist.stringify)(state);
221
219
  const path = epicActivePath(projectPath);
222
- const tmp = path + ".tmp";
220
+ const tmp = `${path}.tmp`;
223
221
  writeFileSync(tmp, data);
224
222
  renameSync(tmp, path);
225
223
  }
@@ -233,7 +231,7 @@ function appendAudit(projectPath, entry) {
233
231
  ...entry,
234
232
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
235
233
  });
236
- appendFileSync(join(dir, "audit.jsonl"), line + "\n");
234
+ appendFileSync(join(dir, "audit.jsonl"), `${line}\n`);
237
235
  } catch {}
238
236
  }
239
237
  //#endregion
package/dist/cli.mjs CHANGED
@@ -369,9 +369,9 @@ const main = defineCommand({
369
369
  serve: defineCommand({
370
370
  meta: { description: "Start MCP server (stdio)" },
371
371
  async run() {
372
- const { Store } = await import("./store-D-S-ZKaA.mjs");
373
- const { Embedder } = await import("./embedder-qPO74Ar-.mjs");
374
- const { serveMCP } = await import("./server-B0gr3On1.mjs");
372
+ const { Store } = await import("./store-CuN3_dWu.mjs");
373
+ const { Embedder } = await import("./embedder-BRG2Xpr4.mjs");
374
+ const { serveMCP } = await import("./server-CHdcikXe.mjs");
375
375
  const store = Store.openDefault();
376
376
  let emb = null;
377
377
  try {
@@ -397,9 +397,9 @@ const main = defineCommand({
397
397
  }
398
398
  },
399
399
  async run({ args }) {
400
- const { Store } = await import("./store-D-S-ZKaA.mjs");
401
- const { Embedder } = await import("./embedder-qPO74Ar-.mjs");
402
- const { startDashboard } = await import("./server-DhEN_dME.mjs");
400
+ const { Store } = await import("./store-CuN3_dWu.mjs");
401
+ const { Embedder } = await import("./embedder-BRG2Xpr4.mjs");
402
+ const { startDashboard } = await import("./server-Df8fib2F.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-bW4qDAhl.mjs").then((n) => n.t);
425
+ const { runHook } = await import("./dispatcher-BnBtA4bo.mjs").then((n) => n.t);
426
426
  await runHook(args.event);
427
427
  }
428
428
  }),
@@ -456,8 +456,8 @@ const main = defineCommand({
456
456
  }
457
457
  const dbPath = join(home, ".claude-alfred", "alfred.db");
458
458
  check(existsSync(dbPath), `DB: ${dbPath}`, "not found — run: alfred (any command) to create");
459
- check(!!process.env["VOYAGE_API_KEY"], "VOYAGE_API_KEY set", "not set — semantic search disabled, FTS5 fallback active");
460
- const lang = process.env["ALFRED_LANG"];
459
+ check(!!process.env.VOYAGE_API_KEY, "VOYAGE_API_KEY set", "not set — semantic search disabled, FTS5 fallback active");
460
+ const lang = process.env.ALFRED_LANG;
461
461
  check(true, `ALFRED_LANG: ${lang || "(not set, default: en)"}`);
462
462
  const rulesDir = join(home, ".claude", "rules");
463
463
  try {
@@ -498,9 +498,7 @@ async function resolveVersion() {
498
498
  for (const rel of ["..", "../.."]) try {
499
499
  const pkg = JSON.parse(readFileSync(join(thisDir, rel, "package.json"), "utf-8"));
500
500
  if (pkg.version) return pkg.version;
501
- } catch {
502
- continue;
503
- }
501
+ } catch {}
504
502
  } catch {}
505
503
  return "dev";
506
504
  }
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { n as emitAdditionalContext } from "./dispatcher-bW4qDAhl.mjs";
2
+ import { n as emitAdditionalContext } from "./dispatcher-BnBtA4bo.mjs";
3
3
  //#region src/hooks/directives.ts
4
4
  const LEVEL_ORDER = {
5
5
  DIRECTIVE: 0,
@@ -30,16 +30,16 @@ function buildDirectiveOutput(items) {
30
30
  let block = `[${item.level}] ${item.message}`;
31
31
  if (item.level === "DIRECTIVE") {
32
32
  const rats = (item.rationalizations ?? []).slice();
33
- const suffix = item.spiritVsLetter ? "\n" + SPIRIT_VS_LETTER : "";
33
+ const suffix = item.spiritVsLetter ? `\n${SPIRIT_VS_LETTER}` : "";
34
34
  while (rats.length > 0) {
35
- if ((block + "\n" + rats.map((r) => `- ${r}`).join("\n") + suffix).length <= MAX_DIRECTIVE_BLOCK_CHARS) break;
35
+ if (`${block}\n${rats.map((r) => `- ${r}`).join("\n")}${suffix}`.length <= MAX_DIRECTIVE_BLOCK_CHARS) break;
36
36
  rats.pop();
37
37
  }
38
- if (rats.length > 0) block += "\n" + rats.map((r) => `- ${r}`).join("\n");
38
+ if (rats.length > 0) block += `\n${rats.map((r) => `- ${r}`).join("\n")}`;
39
39
  block += suffix;
40
40
  if (block.length > MAX_DIRECTIVE_BLOCK_CHARS) {
41
41
  const messageOnly = `[${item.level}] ${item.message}`;
42
- if (messageOnly.length > MAX_DIRECTIVE_BLOCK_CHARS) block = messageOnly.slice(0, MAX_DIRECTIVE_BLOCK_CHARS - 3) + "...";
42
+ if (messageOnly.length > MAX_DIRECTIVE_BLOCK_CHARS) block = `${messageOnly.slice(0, MAX_DIRECTIVE_BLOCK_CHARS - 3)}...`;
43
43
  else block = messageOnly;
44
44
  }
45
45
  }
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { O as __exportAll } from "./knowledge-CicKSdup.mjs";
2
+ import { k as __exportAll } from "./knowledge-B0fsJ9SI.mjs";
3
3
  import { resolve } from "node:path";
4
4
  //#region src/hooks/dispatcher.ts
5
5
  var dispatcher_exports = /* @__PURE__ */ __exportAll({
@@ -19,7 +19,7 @@ function emitAdditionalContext(eventName, context) {
19
19
  additionalContext: context
20
20
  } };
21
21
  try {
22
- process.stdout.write(JSON.stringify(out) + "\n");
22
+ process.stdout.write(`${JSON.stringify(out)}\n`);
23
23
  } catch {}
24
24
  }
25
25
  function extractSection(content, heading) {
@@ -27,7 +27,7 @@ function extractSection(content, heading) {
27
27
  const result = [];
28
28
  let inSection = false;
29
29
  for (const line of lines) {
30
- if (line === heading || line.startsWith(heading + " ")) {
30
+ if (line === heading || line.startsWith(`${heading} `)) {
31
31
  inSection = true;
32
32
  continue;
33
33
  }
@@ -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-l9fkYqD5.mjs");
92
+ const { sessionStart } = await import("./session-start-dPl4lfZw.mjs");
93
93
  await sessionStart(ev, signal);
94
94
  }
95
95
  async function handlePreCompact(ev, signal) {
96
- const { preCompact } = await import("./pre-compact-CUPQ3Qj-.mjs");
96
+ const { preCompact } = await import("./pre-compact-CwvBi5op.mjs");
97
97
  await preCompact(ev, signal);
98
98
  }
99
99
  async function handleUserPromptSubmit(ev, signal) {
100
- const { userPromptSubmit } = await import("./user-prompt-COyVgW_-.mjs");
100
+ const { userPromptSubmit } = await import("./user-prompt-o9rlzB2I.mjs");
101
101
  await userPromptSubmit(ev, signal);
102
102
  }
103
103
  async function handlePostToolUse(ev, signal) {
104
- const { postToolUse } = await import("./post-tool-CFyBxFlB.mjs");
104
+ const { postToolUse } = await import("./post-tool-gG8qG5Ee.mjs");
105
105
  await postToolUse(ev, signal);
106
106
  }
107
107
  async function handlePreToolUse(ev, _signal) {
108
- const { preToolUse } = await import("./pre-tool-BcdaDusF.mjs");
108
+ const { preToolUse } = await import("./pre-tool-BMCYjtHT.mjs");
109
109
  await preToolUse(ev);
110
110
  }
111
111
  async function handleStop(ev, _signal) {
112
- const { stop } = await import("./stop-BEMycnn1.mjs");
112
+ const { stop } = await import("./stop-NL5GdPNy.mjs");
113
113
  await stop(ev);
114
114
  }
115
115
  //#endregion
@@ -12,7 +12,7 @@ function envIntOr(key, fallback) {
12
12
  const v = process.env[key];
13
13
  if (v) {
14
14
  const n = parseInt(v, 10);
15
- if (!isNaN(n) && n > 0) return n;
15
+ if (!Number.isNaN(n) && n > 0) return n;
16
16
  }
17
17
  return fallback;
18
18
  }
@@ -82,7 +82,6 @@ async function retryVoyage(fn, signal) {
82
82
  if (err.status === 400 && (isVoyageTransient(err.detail) || isVoyageTransientStructured(err.errResp))) continue;
83
83
  throw err;
84
84
  }
85
- continue;
86
85
  }
87
86
  }
88
87
  throw lastErr;
@@ -116,7 +115,7 @@ var VoyageClient = class {
116
115
  method: "POST",
117
116
  headers: {
118
117
  "Content-Type": "application/json",
119
- "Authorization": `Bearer ${this.apiKey}`
118
+ Authorization: `Bearer ${this.apiKey}`
120
119
  },
121
120
  body: JSON.stringify(payload),
122
121
  signal: signal ?? AbortSignal.timeout(3e4)
@@ -157,7 +156,7 @@ var VoyageClient = class {
157
156
  method: "POST",
158
157
  headers: {
159
158
  "Content-Type": "application/json",
160
- "Authorization": `Bearer ${this.apiKey}`
159
+ Authorization: `Bearer ${this.apiKey}`
161
160
  },
162
161
  body: JSON.stringify(payload),
163
162
  signal: signal ?? AbortSignal.timeout(3e4)
@@ -185,7 +184,7 @@ var Embedder = class Embedder {
185
184
  this.client = client;
186
185
  }
187
186
  static create() {
188
- const apiKey = process.env["VOYAGE_API_KEY"];
187
+ const apiKey = process.env.VOYAGE_API_KEY;
189
188
  if (!apiKey) throw new Error("VOYAGE_API_KEY is required but not set (get a key at https://dash.voyageai.com/)");
190
189
  return new Embedder(new VoyageClient(apiKey));
191
190
  }
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
- import { c as mapRow, r as getKnowledgeByIDs, u as searchKnowledgeKeyword } from "./knowledge-CicKSdup.mjs";
3
- import { n as deserializeFloat32, t as cosineSimilarity } from "./vectors-B5WOzF-3.mjs";
2
+ import { d as searchKnowledgeKeyword, i as getKnowledgeByIDs, l as mapRow } from "./knowledge-B0fsJ9SI.mjs";
3
+ import { n as deserializeFloat32, t as cosineSimilarity } from "./vectors-BDQP0gaa.mjs";
4
4
  //#region src/store/fts.ts
5
5
  function subTypeHalfLife(subType) {
6
6
  switch (subType) {
@@ -1,19 +1,19 @@
1
1
  #!/usr/bin/env node
2
- import { r as getKnowledgeByIDs, s as incrementHitCount, u as searchKnowledgeKeyword } from "./knowledge-CicKSdup.mjs";
3
- import { r as vectorSearchKnowledge } from "./vectors-B5WOzF-3.mjs";
4
- import { i as subTypeHalfLife, n as searchKnowledgeFTS, r as subTypeBoost } from "./fts-DInh3bOQ.mjs";
2
+ import { c as incrementHitCount, d as searchKnowledgeKeyword, i as getKnowledgeByIDs } from "./knowledge-B0fsJ9SI.mjs";
3
+ import { r as vectorSearchKnowledge } from "./vectors-BDQP0gaa.mjs";
4
+ import { i as subTypeHalfLife, n as searchKnowledgeFTS, r as subTypeBoost } from "./fts-QWdC_4Zv.mjs";
5
5
  //#region src/mcp/helpers.ts
6
6
  const RECENCY_FLOOR = .5;
7
7
  function truncate(s, maxLen) {
8
8
  const runes = [...s];
9
9
  if (runes.length <= maxLen) return s;
10
- return runes.slice(0, maxLen).join("") + "...";
10
+ return `${runes.slice(0, maxLen).join("")}...`;
11
11
  }
12
12
  function recencyFactor(createdAt, subType, now) {
13
13
  const halfLife = subTypeHalfLife(subType);
14
14
  if (halfLife <= 0) return 1;
15
15
  const parsed = Date.parse(createdAt);
16
- if (isNaN(parsed)) return 1;
16
+ if (Number.isNaN(parsed)) return 1;
17
17
  const ageDays = (now.getTime() - parsed) / (1e3 * 60 * 60 * 24);
18
18
  if (ageDays <= 0) return 1;
19
19
  const factor = Math.exp(-Math.LN2 * ageDays / halfLife);
@@ -55,7 +55,7 @@ async function searchPipeline(store, emb, query, limit, overRetrieve, precompute
55
55
  rawDocs = ordered;
56
56
  res.searchMethod = "vector";
57
57
  if (rawDocs.length > limit) try {
58
- const contents = rawDocs.map((d) => d.title + "\n" + d.content);
58
+ const contents = rawDocs.map((d) => `${d.title}\n${d.content}`);
59
59
  const reranked = await emb.rerank(query, contents, limit);
60
60
  if (reranked.length > 0) {
61
61
  const reorderedDocs = [];
@@ -6606,7 +6606,7 @@ var require_dist = /* @__PURE__ */ __commonJSMin(((exports) => {
6606
6606
  //#endregion
6607
6607
  //#region src/spec/types.ts
6608
6608
  var import_dist = require_dist();
6609
- const VALID_SLUG = /^[a-z0-9][a-z0-9\-]{0,63}$/;
6609
+ const VALID_SLUG = /^[a-z0-9][a-z0-9-]{0,63}$/;
6610
6610
  function detectSize(description) {
6611
6611
  const n = [...description].length;
6612
6612
  if (n < 100) return "S";
@@ -6692,7 +6692,7 @@ var SpecDir = class {
6692
6692
  }
6693
6693
  writeFileRaw(f, content) {
6694
6694
  const path = this.filePath(f);
6695
- const tmp = path + ".tmp";
6695
+ const tmp = `${path}.tmp`;
6696
6696
  writeFileSync(tmp, content);
6697
6697
  renameSync(tmp, path);
6698
6698
  }
@@ -6703,7 +6703,7 @@ var SpecDir = class {
6703
6703
  const histDir = join(this.dir(), ".history");
6704
6704
  mkdirSync(histDir, { recursive: true });
6705
6705
  writeFileSync(join(histDir, `${f}.${(/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "").slice(0, 15)}`), readFileSync(path, "utf-8"));
6706
- const entries = readdirSync(histDir).filter((e) => e.startsWith(f + ".")).sort();
6706
+ const entries = readdirSync(histDir).filter((e) => e.startsWith(`${f}.`)).sort();
6707
6707
  while (entries.length > 20) {
6708
6708
  const old = entries.shift();
6709
6709
  try {
@@ -6753,7 +6753,7 @@ function readActiveState(projectPath) {
6753
6753
  }
6754
6754
  try {
6755
6755
  const state = (0, import_dist.parse)(data);
6756
- if (state?.primary) return state;
6756
+ if (state?.primary != null || state?.tasks) return state;
6757
6757
  } catch {}
6758
6758
  let slug = "", startedAt = "";
6759
6759
  for (const line of data.split("\n")) {
@@ -6999,6 +6999,20 @@ function getRecentDecisions(store, projectRemote, projectPath, sinceISO, limit)
6999
6999
  createdAt: r.created_at
7000
7000
  }));
7001
7001
  }
7002
+ function deleteOrphanKnowledge(store, projectRemote, projectPath, branch, validFilePaths) {
7003
+ const rows = store.db.prepare("SELECT id, file_path FROM knowledge_index WHERE project_remote = ? AND project_path = ? AND branch = ?").all(projectRemote, projectPath, branch);
7004
+ let deleted = 0;
7005
+ const delEmbed = store.db.prepare("DELETE FROM embeddings WHERE source = 'knowledge' AND source_id = ?");
7006
+ const delKnowledge = store.db.prepare("DELETE FROM knowledge_index WHERE id = ?");
7007
+ store.db.transaction(() => {
7008
+ for (const row of rows) if (!validFilePaths.has(row.file_path)) {
7009
+ delEmbed.run(row.id);
7010
+ delKnowledge.run(row.id);
7011
+ deleted++;
7012
+ }
7013
+ })();
7014
+ return deleted;
7015
+ }
7002
7016
  function countKnowledge(store, projectRemote, projectPath) {
7003
7017
  return store.db.prepare("SELECT COUNT(*) as cnt FROM knowledge_index WHERE project_remote = ? AND project_path = ? AND enabled = 1").get(projectRemote, projectPath).cnt;
7004
7018
  }
@@ -7028,4 +7042,4 @@ function mapRow(r) {
7028
7042
  };
7029
7043
  }
7030
7044
  //#endregion
7031
- export { switchActive as C, __commonJSMin as D, require_dist as E, __exportAll as O, rootDir as S, writeActiveState as T, filesForSize as _, getPromotionCandidates as a, removeTask as b, mapRow as c, setKnowledgeEnabled as d, upsertKnowledge as f, detectSize as g, completeTask as h, getKnowledgeStats as i, __toESM as k, promoteSubType as l, VALID_SLUG as m, getKnowledgeByID as n, getRecentDecisions as o, SpecDir as p, getKnowledgeByIDs as r, incrementHitCount as s, countKnowledge as t, searchKnowledgeKeyword as u, readActive as v, verifyReviewFile as w, reviewStatusFor as x, readActiveState as y };
7045
+ export { __toESM as A, rootDir as C, require_dist as D, writeActiveState as E, __commonJSMin as O, reviewStatusFor as S, verifyReviewFile as T, detectSize as _, getKnowledgeStats as a, readActiveState as b, incrementHitCount as c, searchKnowledgeKeyword as d, setKnowledgeEnabled as f, completeTask as g, VALID_SLUG as h, getKnowledgeByIDs as i, __exportAll as k, mapRow as l, SpecDir as m, deleteOrphanKnowledge as n, getPromotionCandidates as o, upsertKnowledge as p, getKnowledgeByID as r, getRecentDecisions as s, countKnowledge as t, promoteSubType as u, filesForSize as v, switchActive as w, removeTask as x, readActive as y };
@@ -1,34 +1,25 @@
1
1
  #!/usr/bin/env node
2
- import { a as getPromotionCandidates, f as upsertKnowledge, l as promoteSubType, p as SpecDir, v as readActive, y as readActiveState } from "./knowledge-CicKSdup.mjs";
3
- import { n as searchKnowledgeFTS, t as detectKnowledgeConflicts } from "./fts-DInh3bOQ.mjs";
2
+ import { b as readActiveState, m as SpecDir, o as getPromotionCandidates, p as upsertKnowledge, u as promoteSubType, y as readActive } from "./knowledge-B0fsJ9SI.mjs";
3
+ import { n as searchKnowledgeFTS, t as detectKnowledgeConflicts } from "./fts-QWdC_4Zv.mjs";
4
4
  import { t as detectProject } from "./project-Djp8-Djz.mjs";
5
- import { i as notifyUser, r as extractSection } from "./dispatcher-bW4qDAhl.mjs";
6
- import { openDefaultCached } from "./store-D-S-ZKaA.mjs";
7
- import { r as truncate } from "./helpers-C6av-rsB.mjs";
8
- import { t as emitDirectives } from "./directives-B23lVUGt.mjs";
9
- import { readFileSync, writeFileSync } from "node:fs";
10
- import { join } from "node:path";
11
- import { tmpdir } from "node:os";
5
+ import { i as notifyUser, r as extractSection } from "./dispatcher-BnBtA4bo.mjs";
6
+ import { r as truncate } from "./helpers-BnPVn8Nv.mjs";
7
+ import { openDefaultCached } from "./store-CuN3_dWu.mjs";
8
+ import { t as emitDirectives } from "./directives-ko2sX5BW.mjs";
9
+ import { i as writeStateText, n as readStateText } from "./state-CdHO66SV.mjs";
12
10
  //#region src/hooks/post-tool.ts
13
- const EXPLORE_COUNTER_PATH = join(tmpdir(), "alfred-explore-count");
14
- function readExploreCount() {
15
- try {
16
- return parseInt(readFileSync(EXPLORE_COUNTER_PATH, "utf-8"), 10) || 0;
17
- } catch {
18
- return 0;
19
- }
11
+ function readExploreCount(cwd) {
12
+ return parseInt(readStateText(cwd, "explore-count", "0"), 10) || 0;
20
13
  }
21
- function writeExploreCount(n) {
22
- try {
23
- writeFileSync(EXPLORE_COUNTER_PATH, String(n));
24
- } catch {}
14
+ function writeExploreCount(cwd, n) {
15
+ writeStateText(cwd, "explore-count", String(n));
25
16
  }
26
17
  async function postToolUse(ev, signal) {
27
18
  if (!ev.cwd || !ev.tool_name) return;
28
19
  const items = [];
29
20
  if (ev.tool_name === "Read" || ev.tool_name === "Grep" || ev.tool_name === "Glob") {
30
- const count = readExploreCount() + 1;
31
- writeExploreCount(count);
21
+ const count = readExploreCount(ev.cwd) + 1;
22
+ writeExploreCount(ev.cwd, count);
32
23
  if (count >= 5) try {
33
24
  readActive(ev.cwd);
34
25
  } catch {
@@ -36,12 +27,12 @@ async function postToolUse(ev, signal) {
36
27
  level: "WARNING",
37
28
  message: `5+ consecutive ${ev.tool_name} calls without a spec. Consider \`/alfred:survey\` to reverse-engineer a spec from the code.`
38
29
  });
39
- writeExploreCount(0);
30
+ writeExploreCount(ev.cwd, 0);
40
31
  }
41
32
  emitDirectives("PostToolUse", items);
42
33
  return;
43
34
  }
44
- writeExploreCount(0);
35
+ writeExploreCount(ev.cwd, 0);
45
36
  if (ev.tool_name === "Bash" && !signal.aborted) await handleBashResult(ev, items, signal);
46
37
  if ((ev.tool_name === "Edit" || ev.tool_name === "Write") && ev.tool_input) {
47
38
  const input = ev.tool_input;
@@ -62,7 +53,7 @@ async function handleBashResult(ev, items, signal) {
62
53
  const errorText = typeof response.stderr === "string" ? response.stderr : "";
63
54
  const stdout = response.stdout ?? "";
64
55
  if (errorText.length > 10) await searchErrorContext(ev.cwd, errorText, items);
65
- if (isTestFailure(stdout + "\n" + errorText)) items.push({
56
+ if (isTestFailure(`${stdout}\n${errorText}`)) items.push({
66
57
  level: "WARNING",
67
58
  message: "Test failure detected. Investigate the root cause before continuing implementation. Consider reverting recent changes with `git stash` or `git diff` to isolate the issue."
68
59
  });
@@ -70,14 +61,14 @@ async function handleBashResult(ev, items, signal) {
70
61
  if (response.exitCode === 0) {
71
62
  const stdout = response.stdout ?? "";
72
63
  const commandStr = typeof ev.tool_input === "object" && ev.tool_input !== null ? ev.tool_input.command ?? "" : "";
73
- autoCheckNextSteps(ev.cwd, stdout + "\n" + commandStr);
64
+ autoCheckNextSteps(ev.cwd, `${stdout}\n${commandStr}`);
74
65
  if (isGitCommit(stdout) && !signal.aborted) {
75
66
  await checkKnowledgeConflicts(items);
76
67
  saveKnowledgeOnCommit(ev.cwd);
77
68
  }
78
69
  }
79
70
  }
80
- async function searchErrorContext(projectPath, errorText, items) {
71
+ async function searchErrorContext(_projectPath, errorText, items) {
81
72
  let store;
82
73
  try {
83
74
  store = openDefaultCached();
@@ -143,7 +134,7 @@ function updateCurrentlyWorkingOn(session, newFocus) {
143
134
  return session.slice(0, afterMarker + 1) + lines.join("\n");
144
135
  }
145
136
  }
146
- return session.slice(0, afterMarker + 1) + "\n" + newFocus + "\n" + session.slice(afterMarker + 1);
137
+ return `${session.slice(0, afterMarker + 1)}\n${newFocus}\n${session.slice(afterMarker + 1)}`;
147
138
  }
148
139
  /**
149
140
  * FR-4: Detect test failure patterns in command output.
@@ -1,6 +1,6 @@
1
1
  import { mkdirSync, readdirSync, writeFileSync } from "node:fs";
2
- import { join } from "node:path";
3
2
  import { homedir } from "node:os";
3
+ import { join } from "node:path";
4
4
  //#region src/postinstall.ts
5
5
  async function main() {
6
6
  const home = homedir();
@@ -1,9 +1,9 @@
1
1
  #!/usr/bin/env node
2
- import { f as upsertKnowledge, h as completeTask, p as SpecDir, v as readActive, w as verifyReviewFile, x as reviewStatusFor, y as readActiveState } from "./knowledge-CicKSdup.mjs";
3
- import { s as syncTaskStatus, t as appendAudit } from "./audit-DMxi6YnF.mjs";
2
+ import { S as reviewStatusFor, T as verifyReviewFile, b as readActiveState, g as completeTask, m as SpecDir, p as upsertKnowledge, y as readActive } from "./knowledge-B0fsJ9SI.mjs";
3
+ import { s as syncTaskStatus, t as appendAudit } from "./audit-6NSlW0Ut.mjs";
4
4
  import { t as detectProject } from "./project-Djp8-Djz.mjs";
5
- import { i as notifyUser } from "./dispatcher-bW4qDAhl.mjs";
6
- import { openDefaultCached } from "./store-D-S-ZKaA.mjs";
5
+ import { i as notifyUser } from "./dispatcher-BnBtA4bo.mjs";
6
+ import { openDefaultCached } from "./store-CuN3_dWu.mjs";
7
7
  import { readFileSync, writeFileSync } from "node:fs";
8
8
  import { join } from "node:path";
9
9
  //#region src/hooks/pre-compact.ts
@@ -71,7 +71,7 @@ async function preCompact(ev, _signal) {
71
71
  };
72
72
  upsertKnowledge(store, row);
73
73
  const breadcrumb = {
74
- claude_session_id: process.env["CLAUDE_SESSION_ID"] ?? "",
74
+ claude_session_id: process.env.CLAUDE_SESSION_ID ?? "",
75
75
  task_slug: taskSlug,
76
76
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
77
77
  };
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
- import "./dispatcher-bW4qDAhl.mjs";
3
- import { a as isSpecFilePath, o as tryReadActiveSpec, r as denyTool } from "./spec-guard-ntNzlw8B.mjs";
2
+ import "./dispatcher-BnBtA4bo.mjs";
3
+ import { a as isSpecFilePath, o as tryReadActiveSpec, r as denyTool } from "./spec-guard-BGwtCxgH.mjs";
4
4
  //#region src/hooks/pre-tool.ts
5
5
  const BLOCKABLE_TOOLS = new Set(["Edit", "Write"]);
6
6
  /**