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
|
@@ -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-zr3tpkx_.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-BHZ71Dpf.mjs";
|
|
5
|
+
import { n as init_audit, t as appendAudit } from "./audit-BUfNnVyn.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-DcHtDI_E.mjs";
|
|
10
|
+
import { o as truncate, r as init_helpers } from "./directives-B-imQAUP.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-DPLHW9jK.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-BpjBk-63.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",
|
|
@@ -18325,7 +18273,10 @@ function validateSpec(projectPath, taskSlug, size, specType, opts) {
|
|
|
18325
18273
|
let currentTask = "";
|
|
18326
18274
|
for (const line of taskLines) {
|
|
18327
18275
|
const taskMatch = line.match(/(?:###\s+|[-*]\s+\[[ x]\]\s+)(T-\d+\.\d+)/);
|
|
18328
|
-
if (taskMatch)
|
|
18276
|
+
if (taskMatch) {
|
|
18277
|
+
currentTask = taskMatch[1];
|
|
18278
|
+
if (extractIDs(line, ID.FR).length > 0) tasksWithFR.add(currentTask);
|
|
18279
|
+
}
|
|
18329
18280
|
if (currentTask && /(?:^[-\s]*|_)Requirements:\s*FR-/i.test(line)) tasksWithFR.add(currentTask);
|
|
18330
18281
|
}
|
|
18331
18282
|
const orphanTasks = taskIDs.filter((t) => !tasksWithFR.has(t));
|
|
@@ -18460,7 +18411,7 @@ function validateSpec(projectPath, taskSlug, size, specType, opts) {
|
|
|
18460
18411
|
message: `${confidenceCount}/${frIDs.length} FRs have confidence annotations`
|
|
18461
18412
|
});
|
|
18462
18413
|
}
|
|
18463
|
-
if (size === "L"
|
|
18414
|
+
if (size === "L") {
|
|
18464
18415
|
const nfrIDs = extractIDs(primaryContent, ID.NFR);
|
|
18465
18416
|
const taskNFRs = extractIDs(tasksContent, ID.NFR);
|
|
18466
18417
|
const unreferencedNFR = nfrIDs.filter((n) => !taskNFRs.includes(n));
|
|
@@ -18484,41 +18435,7 @@ function validateSpec(projectPath, taskSlug, size, specType, opts) {
|
|
|
18484
18435
|
message: "Research content may be insufficient"
|
|
18485
18436
|
});
|
|
18486
18437
|
}
|
|
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:")) {
|
|
18438
|
+
if (size === "L" && primaryContent.includes("grounding:")) {
|
|
18522
18439
|
const groundingMatches = primaryContent.match(/grounding:\s*(\w+)/g) ?? [];
|
|
18523
18440
|
const speculative = groundingMatches.filter((g) => /speculative/i.test(g)).length;
|
|
18524
18441
|
const ratio = groundingMatches.length > 0 ? speculative / groundingMatches.length : 0;
|
|
@@ -18605,6 +18522,13 @@ function dossierUpdate(projectPath, store, params) {
|
|
|
18605
18522
|
};
|
|
18606
18523
|
const lang = process.env.ALFRED_LANG || "en";
|
|
18607
18524
|
if (lang !== "en") result.lang = lang;
|
|
18525
|
+
try {
|
|
18526
|
+
const task = readActiveState(projectPath).tasks.find((t) => t.slug === taskSlug);
|
|
18527
|
+
const size = task?.size ?? "L";
|
|
18528
|
+
const specType = task?.spec_type ?? "feature";
|
|
18529
|
+
const issues = validateSpec(projectPath, taskSlug, size, specType).checks.filter((c) => c.status === "fail" || c.status === "warn").map((c) => `[${c.status}] ${c.message}`);
|
|
18530
|
+
if (issues.length > 0) result.validation_hints = issues;
|
|
18531
|
+
} catch {}
|
|
18608
18532
|
return jsonResult$1(result);
|
|
18609
18533
|
}
|
|
18610
18534
|
function dossierStatus(projectPath) {
|
|
@@ -18813,9 +18737,6 @@ var requirements_default$1 = "# Requirements: {{taskSlug}}\n\n> {{description}}\
|
|
|
18813
18737
|
//#region src/spec/templates/en/bugfix.tmpl
|
|
18814
18738
|
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
18739
|
//#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
18740
|
//#region src/spec/templates/en/design.tmpl
|
|
18820
18741
|
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
18742
|
//#endregion
|
|
@@ -18834,9 +18755,6 @@ var requirements_default = "# 要件定義: {{taskSlug}}\n\n> {{description}}\n\
|
|
|
18834
18755
|
//#region src/spec/templates/ja/bugfix.tmpl
|
|
18835
18756
|
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
18757
|
//#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
18758
|
//#region src/spec/templates/ja/design.tmpl
|
|
18841
18759
|
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
18760
|
//#endregion
|
|
@@ -18854,7 +18772,6 @@ init_types();
|
|
|
18854
18772
|
const EN_TEMPLATES = {
|
|
18855
18773
|
"requirements.md": requirements_default$1,
|
|
18856
18774
|
"bugfix.md": bugfix_default$1,
|
|
18857
|
-
"delta.md": delta_default$1,
|
|
18858
18775
|
"design.md": design_default$1,
|
|
18859
18776
|
"tasks.md": tasks_default$1,
|
|
18860
18777
|
"test-specs.md": test_specs_default$1,
|
|
@@ -18863,7 +18780,6 @@ const EN_TEMPLATES = {
|
|
|
18863
18780
|
const JA_TEMPLATES = {
|
|
18864
18781
|
"requirements.md": requirements_default,
|
|
18865
18782
|
"bugfix.md": bugfix_default,
|
|
18866
|
-
"delta.md": delta_default,
|
|
18867
18783
|
"design.md": design_default,
|
|
18868
18784
|
"tasks.md": tasks_default,
|
|
18869
18785
|
"test-specs.md": test_specs_default,
|
|
@@ -18892,18 +18808,16 @@ init_types();
|
|
|
18892
18808
|
function initSpec(projectPath, taskSlug, description, opts) {
|
|
18893
18809
|
if (!VALID_SLUG.test(taskSlug)) throw new Error(`invalid task_slug "${taskSlug}": must be lowercase alphanumeric with hyphens (e.g., 'add-auth')`);
|
|
18894
18810
|
const size = opts?.size ?? detectSize(description);
|
|
18895
|
-
|
|
18896
|
-
if (size === "D") specType = "delta";
|
|
18811
|
+
const specType = opts?.specType ?? "feature";
|
|
18897
18812
|
const sd = new SpecDir(projectPath, taskSlug);
|
|
18898
18813
|
if (sd.exists()) throw new Error(`spec already exists for '${taskSlug}'; use dossier action=update to modify`);
|
|
18899
18814
|
mkdirSync(sd.dir(), { recursive: true });
|
|
18900
|
-
const
|
|
18815
|
+
const rendered = renderForSize(size, specType, {
|
|
18901
18816
|
taskSlug,
|
|
18902
18817
|
description,
|
|
18903
18818
|
date: (/* @__PURE__ */ new Date()).toISOString().slice(0, 10),
|
|
18904
18819
|
specType
|
|
18905
|
-
};
|
|
18906
|
-
const rendered = renderForSize(size, specType, data);
|
|
18820
|
+
});
|
|
18907
18821
|
const files = filesForSize(size, specType);
|
|
18908
18822
|
try {
|
|
18909
18823
|
for (const f of files) {
|
|
@@ -19003,11 +18917,7 @@ async function dossierInit(projectPath, store, emb, params) {
|
|
|
19003
18917
|
const lang = process.env.ALFRED_LANG || "en";
|
|
19004
18918
|
result.lang = lang;
|
|
19005
18919
|
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.`;
|
|
18920
|
+
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
18921
|
try {
|
|
19012
18922
|
writeReviewGate(projectPath, {
|
|
19013
18923
|
gate: "spec-review",
|
|
@@ -19071,11 +18981,7 @@ function dossierComplete(projectPath, store, params) {
|
|
|
19071
18981
|
const task = readActiveState(projectPath).tasks.find((t) => t.slug === taskSlug);
|
|
19072
18982
|
if (task) {
|
|
19073
18983
|
const size = task.size ?? "L";
|
|
19074
|
-
if ([
|
|
19075
|
-
"M",
|
|
19076
|
-
"L",
|
|
19077
|
-
"XL"
|
|
19078
|
-
].includes(size)) {
|
|
18984
|
+
if (["M", "L"].includes(size)) {
|
|
19079
18985
|
const reviewStatus = reviewStatusFor(projectPath, taskSlug);
|
|
19080
18986
|
if (reviewStatus !== "approved") return errorResult$1(`completion requires review_status="approved" for ${size} specs (current: "${reviewStatus || "pending"}"). Review in alfred dashboard.`);
|
|
19081
18987
|
const verification = verifyReviewFile(projectPath, taskSlug);
|
|
@@ -19603,7 +19509,7 @@ function createMCPServer(store, emb, version) {
|
|
|
19603
19509
|
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
19510
|
|
|
19605
19511
|
task_slug format: lowercase alphanumeric with hyphens (e.g. "my-feature", max 64 chars).
|
|
19606
|
-
Size-based scaling: init accepts size (S/M/L
|
|
19512
|
+
Size-based scaling: init accepts size (S/M/L) and spec_type (feature/bugfix). S=3 files, M=4 files, L=5 files.`, {
|
|
19607
19513
|
action: enumType([
|
|
19608
19514
|
"init",
|
|
19609
19515
|
"update",
|
|
@@ -19638,8 +19544,7 @@ Size-based scaling: init accepts size (S/M/L/XL) and spec_type (feature/bugfix).
|
|
|
19638
19544
|
size: enumType([
|
|
19639
19545
|
"S",
|
|
19640
19546
|
"M",
|
|
19641
|
-
"L"
|
|
19642
|
-
"XL"
|
|
19547
|
+
"L"
|
|
19643
19548
|
]).optional().describe("Spec size for init"),
|
|
19644
19549
|
spec_type: enumType(["feature", "bugfix"]).optional().describe("Spec type for init"),
|
|
19645
19550
|
version: stringType().optional().describe("Version timestamp for rollback"),
|
|
@@ -19680,15 +19585,70 @@ Actions: init, status, link, unlink, order, list, update, delete (2-phase: previ
|
|
|
19680
19585
|
}, async (params) => {
|
|
19681
19586
|
return handleRoster(store, params);
|
|
19682
19587
|
});
|
|
19683
|
-
|
|
19588
|
+
const ledgerDesc = (process.env.ALFRED_LANG || "en").toLowerCase() === "ja" ? `ナレッジの検索・保存・管理。セッションやプロジェクトを跨いで検索可能。
|
|
19589
|
+
|
|
19590
|
+
Actions:
|
|
19591
|
+
- search: 過去のナレッジを検索
|
|
19592
|
+
- save: 新しいナレッジを保存(下記ガイドに従うこと)
|
|
19593
|
+
- promote: pattern→rule に昇格
|
|
19594
|
+
- candidates: 昇格候補の一覧
|
|
19595
|
+
- reflect: ヘルスレポート(統計、矛盾検出、昇格候補)
|
|
19596
|
+
|
|
19597
|
+
## save ガイド(全フィールドを日本語で記述すること)
|
|
19598
|
+
|
|
19599
|
+
### decision(意思決定)— 技術的な選択とその根拠
|
|
19600
|
+
- title: 1行の要約(例: 「認証にJWTではなくセッションCookieを採用」)
|
|
19601
|
+
- decision: 何を決めたか(例: 「セッションCookieベースの認証を採用する」)
|
|
19602
|
+
- reasoning: なぜその選択か、具体的な根拠(例: 「XSSリスク軽減のため。HttpOnly + SameSiteで保護可能」)
|
|
19603
|
+
- alternatives: 却下した選択肢と理由を改行区切りで(例: 「JWT: トークン失効管理が複雑」)
|
|
19604
|
+
- context_text: 背景・制約条件
|
|
19605
|
+
|
|
19606
|
+
### pattern(パターン)— 再利用可能な手法・アンチパターン
|
|
19607
|
+
- title: 1行の要約(例: 「大規模リファクタリング前にgrepで影響範囲を列挙する」)
|
|
19608
|
+
- pattern_type: good(推奨)/ bad(アンチパターン)/ error-solution(エラー解決策)
|
|
19609
|
+
- pattern: 問題と解決策を具体的に(例: 「問題: 変更漏れによるランタイムエラー。解決: grep -r で全参照を列挙してからリファクタ開始」)
|
|
19610
|
+
- application_conditions: いつ適用するか / しないか
|
|
19611
|
+
- expected_outcomes: 期待される結果
|
|
19612
|
+
|
|
19613
|
+
### rule(ルール)— 常に従うべき規約
|
|
19614
|
+
- title: 1行の要約(例: 「テストではモックDBではなく実DBを使用する」)
|
|
19615
|
+
- key: 機械可読キー(例: use-real-db-in-tests)
|
|
19616
|
+
- text: 命令形のルール本文(例: 「テストでは常に実データベースに接続すること。モックDBは使用禁止」)
|
|
19617
|
+
- priority: p0(必須)/ p1(推奨)/ p2(参考)
|
|
19618
|
+
- rationale: なぜこのルールが必要か
|
|
19619
|
+
- category: 分類(style / security / architecture / testing)` : `Long-term knowledge search, save, and management — searchable across sessions and projects.
|
|
19684
19620
|
|
|
19685
19621
|
Actions:
|
|
19686
|
-
- search
|
|
19687
|
-
- save: Save a new
|
|
19688
|
-
- promote: Promote
|
|
19689
|
-
- candidates: List
|
|
19622
|
+
- search: Search past knowledge entries
|
|
19623
|
+
- save: Save a new knowledge entry (follow the guide below)
|
|
19624
|
+
- promote: Promote pattern→rule
|
|
19625
|
+
- candidates: List promotion candidates
|
|
19690
19626
|
- reflect: Health report — stats, conflicts, promotion candidates
|
|
19691
|
-
|
|
19627
|
+
|
|
19628
|
+
## save guide (write all fields in English)
|
|
19629
|
+
|
|
19630
|
+
### decision — Technical choices and their rationale
|
|
19631
|
+
- title: One-line summary (e.g. "Adopt session cookies over JWT for auth")
|
|
19632
|
+
- decision: What was decided (e.g. "Use session cookie-based authentication")
|
|
19633
|
+
- reasoning: Why this choice, with specific rationale (e.g. "Reduces XSS risk. HttpOnly + SameSite provides protection")
|
|
19634
|
+
- alternatives: Rejected alternatives with reasons, newline-separated (e.g. "JWT: token revocation management is complex")
|
|
19635
|
+
- context_text: Background and constraints
|
|
19636
|
+
|
|
19637
|
+
### pattern — Reusable techniques or anti-patterns
|
|
19638
|
+
- title: One-line summary (e.g. "Grep all references before large-scale refactoring")
|
|
19639
|
+
- pattern_type: good (recommended) / bad (anti-pattern) / error-solution (error fix)
|
|
19640
|
+
- pattern: Problem and solution concretely (e.g. "Problem: runtime errors from missed references. Solution: grep -r all references before starting refactor")
|
|
19641
|
+
- application_conditions: When to apply / when NOT to apply
|
|
19642
|
+
- expected_outcomes: Expected results
|
|
19643
|
+
|
|
19644
|
+
### rule — Conventions to always follow
|
|
19645
|
+
- title: One-line summary (e.g. "Use real DB, not mocks, in tests")
|
|
19646
|
+
- key: Machine-readable key (e.g. use-real-db-in-tests)
|
|
19647
|
+
- text: Imperative rule text (e.g. "Always connect to a real database in tests. Mock DBs are prohibited")
|
|
19648
|
+
- priority: p0 (must) / p1 (should) / p2 (reference)
|
|
19649
|
+
- rationale: Why this rule is needed
|
|
19650
|
+
- category: Classification (style / security / architecture / testing)`;
|
|
19651
|
+
server.tool("ledger", ledgerDesc, {
|
|
19692
19652
|
action: enumType([
|
|
19693
19653
|
"search",
|
|
19694
19654
|
"save",
|
|
@@ -19700,7 +19660,7 @@ Actions:
|
|
|
19700
19660
|
]).describe("Action to perform"),
|
|
19701
19661
|
id: numberType().optional().describe("Record ID (required for promote)"),
|
|
19702
19662
|
query: stringType().optional().describe("Search query"),
|
|
19703
|
-
label: stringType().optional().describe("Short label for saved entry (REQUIRED for save)"),
|
|
19663
|
+
label: stringType().optional().describe("Short label for saved entry, natural language (REQUIRED for save)"),
|
|
19704
19664
|
limit: numberType().optional().describe("Maximum search results (default: 10)"),
|
|
19705
19665
|
detail: enumType([
|
|
19706
19666
|
"compact",
|
|
@@ -19712,30 +19672,30 @@ Actions:
|
|
|
19712
19672
|
"pattern",
|
|
19713
19673
|
"rule"
|
|
19714
19674
|
]).optional().describe("Knowledge type (REQUIRED for save)"),
|
|
19715
|
-
title: stringType().optional().describe("
|
|
19716
|
-
decision: stringType().optional().describe("Decision: what was decided (REQUIRED for decision)"),
|
|
19717
|
-
reasoning: stringType().optional().describe("Decision: why this choice (REQUIRED for decision)"),
|
|
19718
|
-
alternatives: stringType().optional().describe("Decision:
|
|
19719
|
-
context_text: stringType().optional().describe("
|
|
19675
|
+
title: stringType().optional().describe("Natural language title, max 200 chars. NOT JSON. (REQUIRED for save)"),
|
|
19676
|
+
decision: stringType().optional().describe("Decision: what was decided, in plain text (REQUIRED for decision)"),
|
|
19677
|
+
reasoning: stringType().optional().describe("Decision: why this choice, with specific rationale (REQUIRED for decision)"),
|
|
19678
|
+
alternatives: stringType().optional().describe("Decision: rejected alternatives with reasons, newline-separated"),
|
|
19679
|
+
context_text: stringType().optional().describe("Background, constraints, or trigger for this knowledge entry"),
|
|
19720
19680
|
pattern_type: enumType([
|
|
19721
19681
|
"good",
|
|
19722
19682
|
"bad",
|
|
19723
19683
|
"error-solution"
|
|
19724
|
-
]).optional().describe("Pattern
|
|
19725
|
-
pattern: stringType().optional().describe("Pattern:
|
|
19726
|
-
application_conditions: stringType().optional().describe("Pattern: when to apply"),
|
|
19727
|
-
expected_outcomes: stringType().optional().describe("Pattern: expected results"),
|
|
19728
|
-
key: stringType().optional().describe("Rule: machine-readable key (REQUIRED for rule)"),
|
|
19729
|
-
text: stringType().optional().describe("Rule: imperative text (REQUIRED for rule)"),
|
|
19730
|
-
category: stringType().optional().describe("Rule: category"),
|
|
19684
|
+
]).optional().describe("Pattern classification (REQUIRED for pattern)"),
|
|
19685
|
+
pattern: stringType().optional().describe("Pattern: problem and solution in plain text (REQUIRED for pattern)"),
|
|
19686
|
+
application_conditions: stringType().optional().describe("Pattern: when to apply / when NOT to apply"),
|
|
19687
|
+
expected_outcomes: stringType().optional().describe("Pattern: expected results when applied"),
|
|
19688
|
+
key: stringType().optional().describe("Rule: machine-readable key, kebab-case (REQUIRED for rule)"),
|
|
19689
|
+
text: stringType().optional().describe("Rule: imperative text — what to do or not do (REQUIRED for rule)"),
|
|
19690
|
+
category: stringType().optional().describe("Rule: category (style / security / architecture / testing)"),
|
|
19731
19691
|
priority: enumType([
|
|
19732
19692
|
"p0",
|
|
19733
19693
|
"p1",
|
|
19734
19694
|
"p2"
|
|
19735
|
-
]).optional().describe("Rule:
|
|
19736
|
-
rationale: stringType().optional().describe("Rule:
|
|
19695
|
+
]).optional().describe("Rule: p0=must, p1=should, p2=reference"),
|
|
19696
|
+
rationale: stringType().optional().describe("Rule: why this rule is needed"),
|
|
19737
19697
|
source_ref: stringType().optional().describe("Rule: source reference JSON {\"type\":\"pattern\",\"id\":\"...\"}"),
|
|
19738
|
-
tags: stringType().optional().describe("Comma-separated tags"),
|
|
19698
|
+
tags: stringType().optional().describe("Comma-separated tags for search"),
|
|
19739
19699
|
project_path: stringType().optional().describe("Project root path")
|
|
19740
19700
|
}, async (params) => {
|
|
19741
19701
|
return handleLedger(store, emb, params);
|
|
@@ -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-zr3tpkx_.mjs";
|
|
3
|
+
import { i as listAllEpics, r as init_epic } from "./epic-BHZ71Dpf.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, 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,18 +1,21 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { n as __esmMin } from "./chunk-CAm0Jl7e.mjs";
|
|
3
|
-
import { c as readActive, l as readActiveState, s as init_types, t as SpecDir } from "./types-
|
|
3
|
+
import { c as readActive, l as readActiveState, s as init_types, t as SpecDir } from "./types-zr3tpkx_.mjs";
|
|
4
4
|
import { l as init_knowledge, m as upsertKnowledge, n as deleteOrphanKnowledge, s as getRecentDecisions, t as countKnowledge } from "./knowledge-C7rEfFSX.mjs";
|
|
5
5
|
import { n as init_project, t as detectProject } from "./project-DCKke4_Q.mjs";
|
|
6
|
-
import { a as notifyUser, i as init_dispatcher, r as extractSection } from "./dispatcher-
|
|
7
|
-
import { n as init_directives, o as truncate, r as init_helpers, t as emitDirectives } from "./directives-
|
|
6
|
+
import { a as notifyUser, i as init_dispatcher, r as extractSection } from "./dispatcher-DcHtDI_E.mjs";
|
|
7
|
+
import { n as init_directives, o as truncate, r as init_helpers, t as emitDirectives } from "./directives-B-imQAUP.mjs";
|
|
8
8
|
import { n as openDefaultCached, t as init_store } from "./store-BffM-bi-.mjs";
|
|
9
|
-
import { l as resetWorkedSlugs, r as init_state } from "./state-Cih-8_Zc.mjs";
|
|
9
|
+
import { d as writeStateJSON, l as resetWorkedSlugs, r as init_state } from "./state-Cih-8_Zc.mjs";
|
|
10
10
|
import { existsSync, readFileSync, readdirSync } from "node:fs";
|
|
11
11
|
import { join } from "node:path";
|
|
12
12
|
//#region src/hooks/session-start.ts
|
|
13
13
|
async function sessionStart(ev, _signal) {
|
|
14
14
|
if (!ev.cwd) return;
|
|
15
|
-
if (existsSync(join(ev.cwd, ".alfred")))
|
|
15
|
+
if (existsSync(join(ev.cwd, ".alfred"))) {
|
|
16
|
+
resetWorkedSlugs(ev.cwd);
|
|
17
|
+
writeStateJSON(ev.cwd, "spec-prompt.json", {});
|
|
18
|
+
}
|
|
16
19
|
let store;
|
|
17
20
|
try {
|
|
18
21
|
store = openDefaultCached();
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { n as __esmMin } from "./chunk-CAm0Jl7e.mjs";
|
|
3
|
-
import "./types-
|
|
4
|
-
import { c as countUncheckedTasks, d as init_spec_guard, m as tryReadActiveSpec, n as init_review_gate, r as isGateActive, s as blockStop, u as hasUncheckedSelfReview } from "./review-gate-
|
|
3
|
+
import "./types-zr3tpkx_.mjs";
|
|
4
|
+
import { c as countUncheckedTasks, d as init_spec_guard, m as tryReadActiveSpec, n as init_review_gate, r as isGateActive, s as blockStop, u as hasUncheckedSelfReview } from "./review-gate-BpjBk-63.mjs";
|
|
5
5
|
import { c as readWorkedSlugs, r as init_state } from "./state-Cih-8_Zc.mjs";
|
|
6
6
|
//#region src/hooks/stop.ts
|
|
7
7
|
/**
|
|
@@ -6592,23 +6592,20 @@ function detectSize(description) {
|
|
|
6592
6592
|
return "L";
|
|
6593
6593
|
}
|
|
6594
6594
|
function filesForSize(size, specType) {
|
|
6595
|
-
if (size === "D") return ["delta.md"];
|
|
6596
6595
|
const primary = specType === "bugfix" ? "bugfix.md" : "requirements.md";
|
|
6597
6596
|
switch (size) {
|
|
6598
|
-
case "S": return [
|
|
6599
|
-
|
|
6600
|
-
|
|
6601
|
-
|
|
6602
|
-
|
|
6603
|
-
|
|
6604
|
-
|
|
6605
|
-
|
|
6606
|
-
|
|
6607
|
-
|
|
6608
|
-
|
|
6609
|
-
|
|
6610
|
-
];
|
|
6611
|
-
default: return [
|
|
6597
|
+
case "S": return [
|
|
6598
|
+
primary,
|
|
6599
|
+
"design.md",
|
|
6600
|
+
"tasks.md"
|
|
6601
|
+
];
|
|
6602
|
+
case "M": return [
|
|
6603
|
+
primary,
|
|
6604
|
+
"design.md",
|
|
6605
|
+
"tasks.md",
|
|
6606
|
+
"test-specs.md"
|
|
6607
|
+
];
|
|
6608
|
+
case "L": return [
|
|
6612
6609
|
primary,
|
|
6613
6610
|
"design.md",
|
|
6614
6611
|
"tasks.md",
|
|
@@ -6678,12 +6675,17 @@ function completeTask(projectPath, taskSlug) {
|
|
|
6678
6675
|
const current = effectiveStatus(task.status);
|
|
6679
6676
|
if (current === "done") throw new Error(`task "${taskSlug}" is already done`);
|
|
6680
6677
|
if (current === "cancelled") throw new Error(`task "${taskSlug}" is cancelled`);
|
|
6681
|
-
task.status = "done";
|
|
6682
|
-
task.completed_at = (/* @__PURE__ */ new Date()).toISOString();
|
|
6683
6678
|
if (state.primary === taskSlug) state.primary = state.tasks.find((t) => {
|
|
6684
6679
|
const s = effectiveStatus(t.status);
|
|
6685
6680
|
return s !== "done" && s !== "cancelled" && t.slug !== taskSlug;
|
|
6686
6681
|
})?.slug ?? "";
|
|
6682
|
+
state.tasks = state.tasks.filter((t) => t.slug !== taskSlug);
|
|
6683
|
+
if (state.tasks.length === 0) {
|
|
6684
|
+
try {
|
|
6685
|
+
rmSync(activePath(projectPath));
|
|
6686
|
+
} catch {}
|
|
6687
|
+
return state.primary;
|
|
6688
|
+
}
|
|
6687
6689
|
writeActiveState(projectPath, state);
|
|
6688
6690
|
return state.primary;
|
|
6689
6691
|
}
|
|
@@ -6858,8 +6860,7 @@ var init_types = __esmMin((() => {
|
|
|
6858
6860
|
"decisions.md",
|
|
6859
6861
|
"research.md",
|
|
6860
6862
|
"session.md",
|
|
6861
|
-
"bugfix.md"
|
|
6862
|
-
"delta.md"
|
|
6863
|
+
"bugfix.md"
|
|
6863
6864
|
];
|
|
6864
6865
|
const sections = [];
|
|
6865
6866
|
for (const f of allFiles) try {
|
|
@@ -1,10 +1,10 @@
|
|
|
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 subTypeBoost, r as init_fts } from "./fts-DICqcpG_.mjs";
|
|
5
5
|
import { Embedder, t as init_embedder } from "./embedder-D3hJoryD.mjs";
|
|
6
|
-
import "./dispatcher-
|
|
7
|
-
import { a as trackHitCounts, i as searchPipeline, n as init_directives, o as truncate, r as init_helpers, t as emitDirectives } from "./directives-
|
|
6
|
+
import "./dispatcher-DcHtDI_E.mjs";
|
|
7
|
+
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";
|
|
8
8
|
import { n as openDefaultCached, t as init_store } from "./store-BffM-bi-.mjs";
|
|
9
9
|
import { a as readStateJSON, c as readWorkedSlugs, d as writeStateJSON, r as init_state } from "./state-Cih-8_Zc.mjs";
|
|
10
10
|
import { existsSync } from "node:fs";
|
|
@@ -142,7 +142,7 @@ function classifyIntent(prompt) {
|
|
|
142
142
|
* FR-5/FR-7: Check if spec is required or unapproved before implementation.
|
|
143
143
|
* Stage 1: No spec exists → DIRECTIVE to create one.
|
|
144
144
|
* Stage 1.5: Spec exists + implement intent → WARNING to confirm or create new spec.
|
|
145
|
-
* Stage 2: Spec exists but not approved (M/L
|
|
145
|
+
* Stage 2: Spec exists but not approved (M/L) → DIRECTIVE to get review.
|
|
146
146
|
*/
|
|
147
147
|
function checkSpecRequired(cwd, intent) {
|
|
148
148
|
if (!intent || ![
|
|
@@ -155,25 +155,23 @@ function checkSpecRequired(cwd, intent) {
|
|
|
155
155
|
try {
|
|
156
156
|
state = readActiveState(cwd);
|
|
157
157
|
} catch {
|
|
158
|
+
if (readStateJSON(cwd, "spec-prompt.json", {}).prompted) return null;
|
|
159
|
+
const lang = (process.env.ALFRED_LANG || "en").toLowerCase();
|
|
160
|
+
writeStateJSON(cwd, "spec-prompt.json", {
|
|
161
|
+
prompted: true,
|
|
162
|
+
at: (/* @__PURE__ */ new Date()).toISOString()
|
|
163
|
+
});
|
|
158
164
|
return {
|
|
159
165
|
level: "DIRECTIVE",
|
|
160
|
-
message: "
|
|
161
|
-
rationalizations: [
|
|
162
|
-
"\"I already have enough context to proceed\" → Specs catch assumptions you don't know you're making",
|
|
163
|
-
"\"The spec would just restate the request\" → Specs add structure, traceability, and test criteria",
|
|
164
|
-
"\"Creating a spec would slow things down\" → S-size adds <2min. Bugs from no spec cost hours"
|
|
165
|
-
],
|
|
166
|
+
message: lang.startsWith("ja") ? "新しい実装タスクです。AskUserQuestion で「spec を作成しますか? (S/M/L/スキップ)」とユーザーに確認してください。ユーザーが「スキップ」を選んだ場合、そのまま実装に進んでください。" : "New implementation task. Use AskUserQuestion to ask the user: 'Create a spec? (S/M/L/Skip)'. If the user selects Skip, proceed without a spec.",
|
|
167
|
+
rationalizations: ["\"I already know what to build\" → A quick S-size spec takes <2min and catches assumptions", "\"The user just wants me to code\" → Ask first. If they say Skip, proceed freely"],
|
|
166
168
|
spiritVsLetter: true
|
|
167
169
|
};
|
|
168
170
|
}
|
|
169
171
|
try {
|
|
170
172
|
const taskSlug = state.primary;
|
|
171
173
|
const task = taskSlug ? state.tasks.find((t) => t.slug === taskSlug) : void 0;
|
|
172
|
-
if (task && [
|
|
173
|
-
"M",
|
|
174
|
-
"L",
|
|
175
|
-
"XL"
|
|
176
|
-
].includes(task.size ?? "") && task.review_status !== "approved") return {
|
|
174
|
+
if (task && ["M", "L"].includes(task.size ?? "") && task.review_status !== "approved") return {
|
|
177
175
|
level: "DIRECTIVE",
|
|
178
176
|
message: `Spec '${taskSlug}' (size ${task.size}) requires review approval before implementation. Submit review via \`alfred dashboard\` or run spec self-review first.`,
|
|
179
177
|
rationalizations: [
|