@dv.nghiem/flowdeck 0.3.7 → 0.3.9
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.md +0 -101
- package/dist/dashboard/server.mjs +789 -868
- package/dist/hooks/command-ref-guard.d.ts +21 -0
- package/dist/hooks/command-ref-guard.d.ts.map +1 -0
- package/dist/hooks/compaction-hook.d.ts +2 -1
- package/dist/hooks/compaction-hook.d.ts.map +1 -1
- package/dist/hooks/session-start.d.ts.map +1 -1
- package/dist/index.js +33 -14
- package/dist/lib/impact-radar.d.ts +2 -2
- package/dist/mcp/index.d.ts +3 -2
- package/dist/mcp/index.d.ts.map +1 -1
- package/dist/services/command-validator.d.ts +61 -0
- package/dist/services/command-validator.d.ts.map +1 -0
- package/dist/services/command-validator.test.d.ts +2 -0
- package/dist/services/command-validator.test.d.ts.map +1 -0
- package/dist/services/preflight-explorer.d.ts +130 -0
- package/dist/services/preflight-explorer.d.ts.map +1 -0
- package/dist/services/preflight-explorer.test.d.ts +25 -0
- package/dist/services/preflight-explorer.test.d.ts.map +1 -0
- package/dist/services/question-guard.d.ts +92 -0
- package/dist/services/question-guard.d.ts.map +1 -0
- package/dist/services/quick-router.d.ts +157 -0
- package/dist/services/quick-router.d.ts.map +1 -0
- package/dist/services/quick-router.test.d.ts +13 -0
- package/dist/services/quick-router.test.d.ts.map +1 -0
- package/docs/commands.md +43 -23
- package/docs/quick-start.md +2 -0
- package/docs/workflows.md +1 -1
- package/package.json +8 -8
- package/src/commands/fd-deploy-check.md +2 -2
- package/src/commands/fd-discuss.md +61 -4
- package/src/commands/fd-map-codebase.md +1 -1
- package/src/commands/fd-multi-repo.md +3 -3
- package/src/commands/fd-plan.md +1 -1
- package/src/commands/fd-quick.md +303 -55
- package/src/rules/common/behavioral.md +63 -0
- package/src/skills/blast-radius-preview/SKILL.md +1 -1
- package/src/skills/change-impact-radar/SKILL.md +2 -2
- package/src/skills/codebase-mapping/SKILL.md +1 -1
- package/src/skills/confidence-aware-planning/SKILL.md +1 -1
- package/src/skills/context-load/SKILL.md +1 -1
- package/src/skills/human-review-routing/SKILL.md +3 -3
- package/src/skills/intent-translator/SKILL.md +2 -2
- package/src/skills/multi-repo/SKILL.md +1 -1
- package/src/skills/regression-prediction/SKILL.md +1 -1
- package/src/skills/repo-memory-graph/SKILL.md +1 -1
- package/src/skills/test-gap-detector/SKILL.md +1 -1
- package/src/skills/volatility-map/SKILL.md +1 -1
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HOOK: Command Reference Guard
|
|
3
|
+
* Post-response hook that scans agent output for /fd-* slash command references
|
|
4
|
+
* and warns when an invalid (unregistered) command is found.
|
|
5
|
+
*
|
|
6
|
+
* This is a lightweight advisory guardrail — it emits a warning comment
|
|
7
|
+
* at the top of the response rather than blocking it, preserving usability
|
|
8
|
+
* while surfacing drift for developers to fix.
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Scan an agent response string and return a warning prefix if any invalid
|
|
12
|
+
* command references are detected. Returns null if response is clean.
|
|
13
|
+
*/
|
|
14
|
+
export declare function buildCommandRefWarning(response: string): string | null;
|
|
15
|
+
/**
|
|
16
|
+
* Apply the command reference guardrail to an agent response.
|
|
17
|
+
* If invalid command references are found, prepend a warning block.
|
|
18
|
+
* If clean, return the response unchanged.
|
|
19
|
+
*/
|
|
20
|
+
export declare function applyCommandRefGuard(response: string): string;
|
|
21
|
+
//# sourceMappingURL=command-ref-guard.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"command-ref-guard.d.ts","sourceRoot":"","sources":["../../src/hooks/command-ref-guard.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAwBtE;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAI7D"}
|
|
@@ -6,7 +6,8 @@
|
|
|
6
6
|
* Context includes:
|
|
7
7
|
* 1. FlowDeck planning state (phase, status, pending steps)
|
|
8
8
|
* 2. Recently edited files (from SessionFileTracker)
|
|
9
|
-
* 3.
|
|
9
|
+
* 3. Historical session summaries from memory store
|
|
10
|
+
* 4. Structured 8-section summary prompt
|
|
10
11
|
*
|
|
11
12
|
* Inspired by oh-my-openagent's compaction-context-injector and
|
|
12
13
|
* ECC's experimental.session.compacting handler.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"compaction-hook.d.ts","sourceRoot":"","sources":["../../src/hooks/compaction-hook.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"compaction-hook.d.ts","sourceRoot":"","sources":["../../src/hooks/compaction-hook.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAIH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAA;AAqDxD,wBAAgB,oBAAoB,CAClC,GAAG,EAAE;IAAE,SAAS,EAAE,MAAM,CAAA;CAAE,EAC1B,OAAO,EAAE,kBAAkB,IAGzB,QAAQ;IAAE,SAAS,EAAE,MAAM,CAAA;CAAE,EAC7B,QAAQ;IAAE,OAAO,EAAE,MAAM,EAAE,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,mBAsCjD"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session-start.d.ts","sourceRoot":"","sources":["../../src/hooks/session-start.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"session-start.d.ts","sourceRoot":"","sources":["../../src/hooks/session-start.ts"],"names":[],"mappings":"AAMA;;;;;GAKG;AACH,wBAAsB,gBAAgB,CACpC,GAAG,EAAE;IAAE,SAAS,EAAE,MAAM,CAAA;CAAE,GACzB,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAwElC"}
|
package/dist/index.js
CHANGED
|
@@ -2452,7 +2452,7 @@ async function guardRailsHook(ctx, input, _output) {
|
|
|
2452
2452
|
if (!existsSync18(planningDirPath))
|
|
2453
2453
|
return;
|
|
2454
2454
|
if (!existsSync18(codebaseDirectory)) {
|
|
2455
|
-
throw new Error(`[flowdeck] WARNING: .codebase/ not found. Run /map-codebase to map the codebase.`);
|
|
2455
|
+
throw new Error(`[flowdeck] WARNING: .codebase/ not found. Run /fd-map-codebase to map the codebase.`);
|
|
2456
2456
|
}
|
|
2457
2457
|
const execMode = resolveExecutionMode(configPath, null);
|
|
2458
2458
|
if (execMode === "review-only") {
|
|
@@ -2480,7 +2480,7 @@ async function guardRailsHook(ctx, input, _output) {
|
|
|
2480
2480
|
for (const pattern of BUILD_DEPLOY_PATTERNS) {
|
|
2481
2481
|
if (cmd.includes(pattern)) {
|
|
2482
2482
|
if (!getPlanConfirmed(statePath2)) {
|
|
2483
|
-
throw new Error(`[flowdeck] WARNING: Build/deploy command detected but plan is not confirmed. Run /plan first.`);
|
|
2483
|
+
throw new Error(`[flowdeck] WARNING: Build/deploy command detected but plan is not confirmed. Run /fd-plan first.`);
|
|
2484
2484
|
}
|
|
2485
2485
|
break;
|
|
2486
2486
|
}
|
|
@@ -2543,15 +2543,15 @@ function getPlanConfirmed(statePath2) {
|
|
|
2543
2543
|
}
|
|
2544
2544
|
function getWarningMessage(planningDir2) {
|
|
2545
2545
|
if (!existsSync18(join18(planningDir2, STATE_FILE2))) {
|
|
2546
|
-
return "No .planning/ found. Run /new-project first.";
|
|
2546
|
+
return "No .planning/ found. Run /fd-new-project first.";
|
|
2547
2547
|
}
|
|
2548
|
-
return "Plan not confirmed. Run /plan and confirm to enable execution.";
|
|
2548
|
+
return "Plan not confirmed. Run /fd-plan and confirm to enable execution.";
|
|
2549
2549
|
}
|
|
2550
2550
|
function getBlockMessage(planningDir2) {
|
|
2551
2551
|
if (!existsSync18(join18(planningDir2, STATE_FILE2))) {
|
|
2552
|
-
return "No .planning/ found. Run /new-project first.";
|
|
2552
|
+
return "No .planning/ found. Run /fd-new-project first.";
|
|
2553
2553
|
}
|
|
2554
|
-
return "Plan not confirmed. Run /plan and confirm to enable execution.";
|
|
2554
|
+
return "Plan not confirmed. Run /fd-plan and confirm to enable execution.";
|
|
2555
2555
|
}
|
|
2556
2556
|
|
|
2557
2557
|
// src/hooks/tool-guard.ts
|
|
@@ -2689,8 +2689,9 @@ async function sessionStartHook(ctx) {
|
|
|
2689
2689
|
return {
|
|
2690
2690
|
flowdeck_phase: null,
|
|
2691
2691
|
flowdeck_status: "no_plan",
|
|
2692
|
-
flowdeck_warning: "Run /new-project or /map-codebase to initialize.",
|
|
2692
|
+
flowdeck_warning: "Run /fd-new-project or /fd-map-codebase to initialize.",
|
|
2693
2693
|
flowdeck_has_codebase: existsSync20(codebaseDirectory),
|
|
2694
|
+
flowdeck_session_context: getContextForDirectory(ctx.directory),
|
|
2694
2695
|
...workspaceRoot && config?.sub_repos ? {
|
|
2695
2696
|
flowdeck_workspace_root: workspaceRoot,
|
|
2696
2697
|
flowdeck_sub_repos: config.sub_repos,
|
|
@@ -2704,12 +2705,14 @@ async function sessionStartHook(ctx) {
|
|
|
2704
2705
|
const content = readFileSync17(stateFilePath, "utf-8");
|
|
2705
2706
|
const state = parseState(content);
|
|
2706
2707
|
const currentPhase = state["current_phase"] || {};
|
|
2708
|
+
const sessionContext = getContextForDirectory(ctx.directory);
|
|
2707
2709
|
const result = {
|
|
2708
2710
|
flowdeck_phase: currentPhase["phase"] ?? null,
|
|
2709
2711
|
flowdeck_status: currentPhase["status"] ?? null,
|
|
2710
2712
|
flowdeck_steps_pending: currentPhase["steps_pending"] ?? null,
|
|
2711
2713
|
flowdeck_last_action: currentPhase["last_action"] ?? null,
|
|
2712
|
-
flowdeck_has_codebase: existsSync20(codebaseDirectory)
|
|
2714
|
+
flowdeck_has_codebase: existsSync20(codebaseDirectory),
|
|
2715
|
+
flowdeck_session_context: sessionContext
|
|
2713
2716
|
};
|
|
2714
2717
|
if (workspaceRoot && config?.sub_repos && config.sub_repos.length > 0) {
|
|
2715
2718
|
result.flowdeck_workspace_root = workspaceRoot;
|
|
@@ -2724,7 +2727,8 @@ async function sessionStartHook(ctx) {
|
|
|
2724
2727
|
flowdeck_phase: null,
|
|
2725
2728
|
flowdeck_status: "error",
|
|
2726
2729
|
flowdeck_warning: "State file unreadable. Continuing without flowdeck context.",
|
|
2727
|
-
flowdeck_has_codebase: existsSync20(codebaseDirectory)
|
|
2730
|
+
flowdeck_has_codebase: existsSync20(codebaseDirectory),
|
|
2731
|
+
flowdeck_session_context: getContextForDirectory(ctx.directory)
|
|
2728
2732
|
};
|
|
2729
2733
|
if (workspaceRoot && config?.sub_repos && config.sub_repos.length > 0) {
|
|
2730
2734
|
result.flowdeck_workspace_root = workspaceRoot;
|
|
@@ -3366,6 +3370,12 @@ function createCompactionHook(ctx, tracker) {
|
|
|
3366
3370
|
sections.push(`- … and ${edited.length - 20} more`);
|
|
3367
3371
|
sections.push("");
|
|
3368
3372
|
}
|
|
3373
|
+
const sessionContext = getContextForDirectory(ctx.directory);
|
|
3374
|
+
if (sessionContext) {
|
|
3375
|
+
sections.push("## Previous Sessions Context");
|
|
3376
|
+
sections.push(sessionContext);
|
|
3377
|
+
sections.push("");
|
|
3378
|
+
}
|
|
3369
3379
|
output.context.push(sections.join(`
|
|
3370
3380
|
`));
|
|
3371
3381
|
output.prompt = STRUCTURED_SUMMARY_PROMPT.trim();
|
|
@@ -3568,6 +3578,15 @@ function createFlowDeckMcps() {
|
|
|
3568
3578
|
oauth: false
|
|
3569
3579
|
};
|
|
3570
3580
|
}
|
|
3581
|
+
if (!disabled.has("github")) {
|
|
3582
|
+
mcps.github = {
|
|
3583
|
+
type: "remote",
|
|
3584
|
+
url: "https://api.githubcopilot.com/mcp/",
|
|
3585
|
+
enabled: true,
|
|
3586
|
+
...process.env.GITHUB_TOKEN ? { headers: { Authorization: `Bearer ${process.env.GITHUB_TOKEN}` } } : {},
|
|
3587
|
+
oauth: false
|
|
3588
|
+
};
|
|
3589
|
+
}
|
|
3571
3590
|
return mcps;
|
|
3572
3591
|
}
|
|
3573
3592
|
|
|
@@ -3605,16 +3624,16 @@ MUST execute at session start:
|
|
|
3605
3624
|
3. Check which steps are marked complete
|
|
3606
3625
|
4. Begin execution from the first incomplete step
|
|
3607
3626
|
|
|
3608
|
-
If STATE.md does not exist, tell the user: "No STATE.md found. Run \`/new-project\` to initialize."
|
|
3627
|
+
If STATE.md does not exist, tell the user: "No STATE.md found. Run \`/fd-new-project\` to initialize."
|
|
3609
3628
|
|
|
3610
3629
|
## Phase Gating
|
|
3611
3630
|
|
|
3612
3631
|
Only orchestrate in the **execute** phase.
|
|
3613
3632
|
|
|
3614
3633
|
If the project is in another phase:
|
|
3615
|
-
- **discuss** phase: "Run \`/discuss\` to complete requirements gathering first."
|
|
3616
|
-
- **plan** phase: "Run \`/plan\` to create the implementation plan first."
|
|
3617
|
-
- **review** phase: "Run \`/
|
|
3634
|
+
- **discuss** phase: "Run \`/fd-discuss\` to complete requirements gathering first."
|
|
3635
|
+
- **plan** phase: "Run \`/fd-plan\` to create the implementation plan first."
|
|
3636
|
+
- **review** phase: "Run \`/fd-verify\` to complete the review phase."
|
|
3618
3637
|
|
|
3619
3638
|
## Step Execution
|
|
3620
3639
|
|
|
@@ -5539,7 +5558,7 @@ Discussion is complete when:
|
|
|
5539
5558
|
- All decisions recorded in DISCUSS.md
|
|
5540
5559
|
- No open questions remain
|
|
5541
5560
|
|
|
5542
|
-
Report: "Requirements gathering complete. N decisions recorded. Ready for /plan."`;
|
|
5561
|
+
Report: "Requirements gathering complete. N decisions recorded. Ready for /fd-plan."`;
|
|
5543
5562
|
var createTaskSplitterAgent = (model, customPrompt, customAppendPrompt) => {
|
|
5544
5563
|
const prompt = resolvePrompt(TASK_SPLITTER_PROMPT, customPrompt, customAppendPrompt);
|
|
5545
5564
|
return {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Shared Impact Radar utility.
|
|
3
3
|
* Scans .codebase/ data stores for risk signals relevant to a change description.
|
|
4
|
-
* Used by /discuss, /plan, /new-feature, and /fix-bug.
|
|
4
|
+
* Used by /fd-discuss, /fd-plan, /fd-new-feature, and /fd-fix-bug.
|
|
5
5
|
*/
|
|
6
6
|
import type { FailureEntry } from "../tools/failure-replay";
|
|
7
7
|
export interface ImpactRadarResult {
|
|
@@ -29,7 +29,7 @@ export declare function impactRadarSummaryLines(radar: ImpactRadarResult): strin
|
|
|
29
29
|
/**
|
|
30
30
|
* Look up prior failures from FAILURES.json that match by path prefix or keyword.
|
|
31
31
|
* Returns full FailureEntry objects (including root_cause and fix_applied) sorted by recurrence desc.
|
|
32
|
-
* Used by /fix-bug to surface lessons learned before the fix begins.
|
|
32
|
+
* Used by /fd-fix-bug to surface lessons learned before the fix begins.
|
|
33
33
|
*/
|
|
34
34
|
export declare function lookupPriorFailures(dir: string, scope: string, bugText: string, limit?: number): FailureEntry[];
|
|
35
35
|
//# sourceMappingURL=impact-radar.d.ts.map
|
package/dist/mcp/index.d.ts
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* FlowDeck built-in MCP server configurations.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
4
|
+
* Four free, read-only remote MCPs are enabled by default:
|
|
5
5
|
* - context7 https://mcp.context7.com/mcp (library docs lookup)
|
|
6
6
|
* - websearch https://mcp.exa.ai/mcp (web search via Exa)
|
|
7
7
|
* - grep_app https://mcp.grep.app (code search)
|
|
8
|
+
* - github https://api.githubcopilot.com/mcp/ (GitHub code search)
|
|
8
9
|
*
|
|
9
|
-
* Disable individual MCPs with: FLOWDECK_DISABLE_MCP=context7,websearch,grep_app
|
|
10
|
+
* Disable individual MCPs with: FLOWDECK_DISABLE_MCP=context7,websearch,grep_app,github
|
|
10
11
|
*/
|
|
11
12
|
type RemoteMcp = {
|
|
12
13
|
type: "remote";
|
package/dist/mcp/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/mcp/index.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/mcp/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,KAAK,SAAS,GAAG;IACf,IAAI,EAAE,QAAQ,CAAA;IACd,GAAG,EAAE,MAAM,CAAA;IACX,OAAO,EAAE,OAAO,CAAA;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAChC,KAAK,CAAC,EAAE,KAAK,CAAA;CACd,CAAA;AAOD,wBAAgB,kBAAkB,IAAI,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAmD9D"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Command reference validator.
|
|
3
|
+
* Source of truth: REGISTERED_COMMANDS from supervisor-binding.
|
|
4
|
+
* Used at startup, in tests, and by the response guardrail to prevent
|
|
5
|
+
* agents from suggesting slash commands that don't exist.
|
|
6
|
+
*/
|
|
7
|
+
export interface CommandValidationResult {
|
|
8
|
+
valid: boolean;
|
|
9
|
+
command: string;
|
|
10
|
+
reason?: string;
|
|
11
|
+
}
|
|
12
|
+
export interface AuditResult {
|
|
13
|
+
text: string;
|
|
14
|
+
references: string[];
|
|
15
|
+
invalid: CommandValidationResult[];
|
|
16
|
+
valid: CommandValidationResult[];
|
|
17
|
+
hasInvalid: boolean;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Returns true if the given slash command (with or without leading slash) is registered.
|
|
21
|
+
*/
|
|
22
|
+
export declare function isValidCommand(ref: string): boolean;
|
|
23
|
+
/**
|
|
24
|
+
* Validate a single command reference string (e.g. "/fd-plan" or "fd-plan").
|
|
25
|
+
*/
|
|
26
|
+
export declare function validateCommandReference(ref: string): CommandValidationResult;
|
|
27
|
+
/**
|
|
28
|
+
* Extract all /fd-* slash command references from a text string.
|
|
29
|
+
*/
|
|
30
|
+
export declare function extractCommandReferences(text: string): string[];
|
|
31
|
+
/**
|
|
32
|
+
* Extract bare /word references that are missing the fd- prefix.
|
|
33
|
+
* Returns only those that would be valid if prefixed with fd-.
|
|
34
|
+
*/
|
|
35
|
+
export declare function extractBarePrefixErrors(text: string): string[];
|
|
36
|
+
/**
|
|
37
|
+
* Audit a text string for invalid command references.
|
|
38
|
+
* Checks all /fd-* patterns against the registered command set.
|
|
39
|
+
*/
|
|
40
|
+
export declare function auditTextForInvalidCommands(text: string): AuditResult;
|
|
41
|
+
/**
|
|
42
|
+
* Rewrite a text string by replacing invalid /fd-* command references with
|
|
43
|
+
* a note that the command is unavailable. Leaves valid commands untouched.
|
|
44
|
+
*/
|
|
45
|
+
export declare function rewriteInvalidCommandRefs(text: string): string;
|
|
46
|
+
/**
|
|
47
|
+
* Combined full audit: checks both invalid /fd-* command references AND
|
|
48
|
+
* bare /word references missing the fd- prefix. Use this for file integrity tests.
|
|
49
|
+
*/
|
|
50
|
+
export interface FullAuditResult extends AuditResult {
|
|
51
|
+
/** Bare /word references that are missing the fd- prefix (e.g. /plan → /fd-plan) */
|
|
52
|
+
barePrefixErrors: string[];
|
|
53
|
+
/** True if any issue was found — either invalid /fd-* refs or bare prefix errors */
|
|
54
|
+
hasAnyIssue: boolean;
|
|
55
|
+
}
|
|
56
|
+
export declare function auditTextFull(text: string): FullAuditResult;
|
|
57
|
+
/**
|
|
58
|
+
* Return the full canonical command inventory for inspection/testing.
|
|
59
|
+
*/
|
|
60
|
+
export declare function getCommandInventory(): readonly string[];
|
|
61
|
+
//# sourceMappingURL=command-validator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"command-validator.d.ts","sourceRoot":"","sources":["../../src/services/command-validator.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,MAAM,WAAW,uBAAuB;IACtC,KAAK,EAAE,OAAO,CAAA;IACd,OAAO,EAAE,MAAM,CAAA;IACf,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAA;IACZ,UAAU,EAAE,MAAM,EAAE,CAAA;IACpB,OAAO,EAAE,uBAAuB,EAAE,CAAA;IAClC,KAAK,EAAE,uBAAuB,EAAE,CAAA;IAChC,UAAU,EAAE,OAAO,CAAA;CACpB;AAYD;;GAEG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAGnD;AAED;;GAEG;AACH,wBAAgB,wBAAwB,CAAC,GAAG,EAAE,MAAM,GAAG,uBAAuB,CAmB7E;AAED;;GAEG;AACH,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAG/D;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAY9D;AAED;;;GAGG;AACH,wBAAgB,2BAA2B,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,CAqBrE;AAED;;;GAGG;AACH,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAK9D;AAED;;;GAGG;AACH,MAAM,WAAW,eAAgB,SAAQ,WAAW;IAClD,oFAAoF;IACpF,gBAAgB,EAAE,MAAM,EAAE,CAAA;IAC1B,oFAAoF;IACpF,WAAW,EAAE,OAAO,CAAA;CACrB;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,eAAe,CAQ3D;AAED;;GAEG;AACH,wBAAgB,mBAAmB,IAAI,SAAS,MAAM,EAAE,CAEvD"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"command-validator.test.d.ts","sourceRoot":"","sources":["../../src/services/command-validator.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Preflight Explorer Service
|
|
3
|
+
*
|
|
4
|
+
* Performs autonomous codebase exploration before any clarifying question is
|
|
5
|
+
* emitted to the user. Both /fd-quick and /fd-discuss run this first.
|
|
6
|
+
*
|
|
7
|
+
* Contract:
|
|
8
|
+
* 1. exploreRepo(dir) → ExplorationResult (what exists in the project)
|
|
9
|
+
* 2. canAnswerFromEvidence(question, result) → boolean (suppress logic)
|
|
10
|
+
* 3. shouldSuppressQuestion(q, result, history) → SuppressResult
|
|
11
|
+
* 4. deriveTaskContext(task, result) → DerivedTaskContext (task-relative findings)
|
|
12
|
+
*
|
|
13
|
+
* This module reads the filesystem synchronously so it can be used in both
|
|
14
|
+
* synchronous test harnesses and async agent runtimes.
|
|
15
|
+
*/
|
|
16
|
+
export interface ExplorationResult {
|
|
17
|
+
/** Whether .planning/STATE.md was found */
|
|
18
|
+
hasStateMD: boolean;
|
|
19
|
+
/** Whether .planning/PROJECT.md was found */
|
|
20
|
+
hasProjectMD: boolean;
|
|
21
|
+
/** Whether AGENTS.md was found at repo root */
|
|
22
|
+
hasAgentsMD: boolean;
|
|
23
|
+
/** Whether .planning/phases/ has any prior phase directories */
|
|
24
|
+
hasPriorPhases: boolean;
|
|
25
|
+
/** Whether .planning/phases/ has any DISCUSS.md from prior sessions */
|
|
26
|
+
hasPriorDiscussions: boolean;
|
|
27
|
+
/** fd-* command names found on disk (from src/commands/*.md) */
|
|
28
|
+
availableCommands: string[];
|
|
29
|
+
/** Agent names registered in this FlowDeck installation */
|
|
30
|
+
availableAgents: string[];
|
|
31
|
+
/** Skill directory names found on disk (from src/skills/ subdirectories) */
|
|
32
|
+
availableSkills: string[];
|
|
33
|
+
/** Tech stack indicators inferred from package.json / go.mod / Cargo.toml etc. */
|
|
34
|
+
techStack: string[];
|
|
35
|
+
/** Config keys present in flowdeck.json if it exists */
|
|
36
|
+
configKeys: string[];
|
|
37
|
+
/** Rules / governance keys declared in flowdeck.json */
|
|
38
|
+
governanceEnabled: boolean;
|
|
39
|
+
/** Implementation pattern hints inferred from src/ directory layout */
|
|
40
|
+
implementationPatterns: string[];
|
|
41
|
+
/** Relative paths of files that seem relevant to the task keywords */
|
|
42
|
+
relevantFiles: string[];
|
|
43
|
+
/** Evidence items that can answer common scoping questions */
|
|
44
|
+
evidenceItems: EvidenceItem[];
|
|
45
|
+
/** ISO timestamp when exploration ran */
|
|
46
|
+
exploredAt: string;
|
|
47
|
+
}
|
|
48
|
+
export interface EvidenceItem {
|
|
49
|
+
/** The kind of question this evidence answers */
|
|
50
|
+
answersQuestion: EvidenceQuestionKind;
|
|
51
|
+
/** Human-readable evidence summary */
|
|
52
|
+
summary: string;
|
|
53
|
+
/** Source path (relative) */
|
|
54
|
+
source: string;
|
|
55
|
+
}
|
|
56
|
+
export type EvidenceQuestionKind = "what-tech-stack" | "is-project-initialized" | "what-is-current-phase" | "what-patterns-exist" | "is-ui-heavy" | "has-existing-tests" | "has-existing-docs" | "has-ci-cd" | "what-agents-available" | "what-commands-available" | "what-skills-available" | "has-prior-decisions" | "has-governance";
|
|
57
|
+
export interface DerivedTaskContext {
|
|
58
|
+
/** Whether the task appears to touch frontend/UI code based on repo evidence */
|
|
59
|
+
likelyUITask: boolean;
|
|
60
|
+
/** Whether the task appears to touch API/backend based on repo evidence */
|
|
61
|
+
likelyBackendTask: boolean;
|
|
62
|
+
/** Whether CI/CD config exists (relevant for deploy tasks) */
|
|
63
|
+
hasCICD: boolean;
|
|
64
|
+
/** Whether existing tests exist in the project */
|
|
65
|
+
hasTests: boolean;
|
|
66
|
+
/** Whether existing documentation exists */
|
|
67
|
+
hasDocs: boolean;
|
|
68
|
+
/** Whether governance layer is active */
|
|
69
|
+
hasGovernance: boolean;
|
|
70
|
+
/** Relevant files for this specific task */
|
|
71
|
+
relevantFiles: string[];
|
|
72
|
+
/** Tech stack summary */
|
|
73
|
+
techStack: string[];
|
|
74
|
+
}
|
|
75
|
+
export interface SuppressResult {
|
|
76
|
+
/** Whether the question should be suppressed */
|
|
77
|
+
suppress: boolean;
|
|
78
|
+
/** Reason for suppression (if suppressed) */
|
|
79
|
+
reason?: string;
|
|
80
|
+
/** True when the question was answered by repo evidence (vs. session dedup) */
|
|
81
|
+
answeredByEvidence?: boolean;
|
|
82
|
+
/** The evidence that answers the question (if suppressed) */
|
|
83
|
+
evidence?: EvidenceItem[];
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Explore the repository at `dir` and return structured findings.
|
|
87
|
+
* All filesystem reads are synchronous so this can be called in test harnesses.
|
|
88
|
+
*
|
|
89
|
+
* @param dir - Absolute path to repo root (or closest available directory)
|
|
90
|
+
*/
|
|
91
|
+
export declare function exploreRepo(dir: string): ExplorationResult;
|
|
92
|
+
/**
|
|
93
|
+
* Narrow the exploration result to what is specifically relevant for a given task.
|
|
94
|
+
* Populates `relevantFiles` based on task keywords.
|
|
95
|
+
*/
|
|
96
|
+
export declare function deriveTaskContext(taskDescription: string, result: ExplorationResult, dir: string): DerivedTaskContext;
|
|
97
|
+
/**
|
|
98
|
+
* Determine whether a candidate question should be suppressed because it can
|
|
99
|
+
* already be answered from repo evidence.
|
|
100
|
+
*
|
|
101
|
+
* A question is suppressed when:
|
|
102
|
+
* 1. The repo contains direct evidence that answers it, OR
|
|
103
|
+
* 2. It was already asked in the current session history, OR
|
|
104
|
+
* 3. It is a trivially answerable question given known project state
|
|
105
|
+
*/
|
|
106
|
+
export declare function shouldSuppressQuestion(question: string, result: ExplorationResult, sessionHistory: string[]): SuppressResult;
|
|
107
|
+
/**
|
|
108
|
+
* Check if a specific question can be answered from the exploration result alone.
|
|
109
|
+
*/
|
|
110
|
+
export declare function canAnswerFromEvidence(question: string, result: ExplorationResult): boolean;
|
|
111
|
+
/**
|
|
112
|
+
* Attempt to resolve a `clarificationNeeded` classification using exploration
|
|
113
|
+
* context. Returns an updated `clarificationNeeded` flag and an optional
|
|
114
|
+
* resolved task type hint.
|
|
115
|
+
*
|
|
116
|
+
* Called by quick-router after classifyTask when clarificationNeeded=true.
|
|
117
|
+
*/
|
|
118
|
+
export interface ExplorationRefinement {
|
|
119
|
+
/** Whether clarification is still required after applying exploration data */
|
|
120
|
+
clarificationStillNeeded: boolean;
|
|
121
|
+
/** Reason clarification is no longer needed (if resolved) */
|
|
122
|
+
resolvedReason?: string;
|
|
123
|
+
/**
|
|
124
|
+
* Evidence-based context to pass to @supervisor if clarification is still needed.
|
|
125
|
+
* This lets the supervisor ask a tighter question.
|
|
126
|
+
*/
|
|
127
|
+
supervisorContext?: string;
|
|
128
|
+
}
|
|
129
|
+
export declare function refineClassification(clarificationPrompt: string, result: ExplorationResult, sessionHistory: string[]): ExplorationRefinement;
|
|
130
|
+
//# sourceMappingURL=preflight-explorer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"preflight-explorer.d.ts","sourceRoot":"","sources":["../../src/services/preflight-explorer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Preflight Explorer Tests
|
|
3
|
+
*
|
|
4
|
+
* Covers:
|
|
5
|
+
* - exploreRepo: discovers commands, agents, skills, tech stack from filesystem
|
|
6
|
+
* - canAnswerFromEvidence: correctly identifies suppressible questions
|
|
7
|
+
* - shouldSuppressQuestion: suppresses answered / duplicate questions
|
|
8
|
+
* - deriveTaskContext: narrows findings to task-relevant context
|
|
9
|
+
* - refineClassification: resolves ambiguous classification via evidence
|
|
10
|
+
* - createQuestionGuard: tracks asked questions and prevents duplicates
|
|
11
|
+
* - filterQuestions: returns only questions that pass the guard
|
|
12
|
+
* - needsSupervisorClarification: returns false when all questions are answered
|
|
13
|
+
* - classifyTaskWithContext: uses exploration to resolve ambiguity
|
|
14
|
+
* - createQuickRunState: persists exploration snapshot
|
|
15
|
+
* - /fd-quick performs codebase exploration before asking questions
|
|
16
|
+
* - /fd-discuss performs codebase exploration before asking questions
|
|
17
|
+
* - repo evidence prevents unnecessary human questions
|
|
18
|
+
* - supervisor-agent receives only genuine ambiguity
|
|
19
|
+
* - worker agents do not ask ad hoc questions
|
|
20
|
+
* - feature/bug/UI/docs tasks route correctly after preflight
|
|
21
|
+
* - exploration results are stored and reused
|
|
22
|
+
* - repeated question suppression works
|
|
23
|
+
*/
|
|
24
|
+
export {};
|
|
25
|
+
//# sourceMappingURL=preflight-explorer.test.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"preflight-explorer.test.d.ts","sourceRoot":"","sources":["../../src/services/preflight-explorer.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG"}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Question Guard Service
|
|
3
|
+
*
|
|
4
|
+
* Prevents redundant or unnecessary questions from being emitted to the user.
|
|
5
|
+
*
|
|
6
|
+
* Both /fd-quick and /fd-discuss use this guard before forwarding any
|
|
7
|
+
* clarifying question to @supervisor. Worker agents MUST NOT call ask_user
|
|
8
|
+
* directly — they check this guard first, and if the answer exists in repo
|
|
9
|
+
* evidence or session history, the question is dropped.
|
|
10
|
+
*
|
|
11
|
+
* Contract:
|
|
12
|
+
* 1. createQuestionGuard(history?) → QuestionGuard instance
|
|
13
|
+
* 2. guard.check(question, evidence) → CheckResult
|
|
14
|
+
* 3. guard.record(question) → void
|
|
15
|
+
* 4. guard.getAsked() → string[]
|
|
16
|
+
*
|
|
17
|
+
* Only questions that pass the guard should be forwarded to @supervisor.
|
|
18
|
+
* @supervisor asks the human. Worker agents never ask the human directly.
|
|
19
|
+
*/
|
|
20
|
+
import type { ExplorationResult } from "./preflight-explorer";
|
|
21
|
+
export interface CheckResult {
|
|
22
|
+
/** Whether the question should be allowed through to @supervisor */
|
|
23
|
+
allow: boolean;
|
|
24
|
+
/** Reason the question was blocked (when allow=false) */
|
|
25
|
+
blockReason?: string;
|
|
26
|
+
/** Whether the block was due to repo evidence answering it */
|
|
27
|
+
answeredByEvidence?: boolean;
|
|
28
|
+
/** Whether the block was due to a duplicate question */
|
|
29
|
+
duplicate?: boolean;
|
|
30
|
+
}
|
|
31
|
+
export interface QuestionGuard {
|
|
32
|
+
/**
|
|
33
|
+
* Check whether a question should be forwarded to @supervisor.
|
|
34
|
+
*
|
|
35
|
+
* Returns allow=true only when:
|
|
36
|
+
* - The question has not been asked before in this session
|
|
37
|
+
* - The question cannot be answered from repo evidence
|
|
38
|
+
* - The question is not trivially implied by known state
|
|
39
|
+
*/
|
|
40
|
+
check(question: string, exploration: ExplorationResult | null): CheckResult;
|
|
41
|
+
/**
|
|
42
|
+
* Record that a question was asked. Call this after forwarding to @supervisor
|
|
43
|
+
* so future identical questions are suppressed.
|
|
44
|
+
*/
|
|
45
|
+
record(question: string): void;
|
|
46
|
+
/** Return all questions recorded in this guard instance. */
|
|
47
|
+
getAsked(): string[];
|
|
48
|
+
/** Reset the guard (for new session/run). */
|
|
49
|
+
reset(): void;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Create a QuestionGuard.
|
|
53
|
+
*
|
|
54
|
+
* @param initialHistory - Questions already asked in this session (for
|
|
55
|
+
* persistence across restarts). Pass an empty array for new sessions.
|
|
56
|
+
*/
|
|
57
|
+
export declare function createQuestionGuard(initialHistory?: string[]): QuestionGuard;
|
|
58
|
+
/**
|
|
59
|
+
* Convenience: check a list of candidate questions and return only those
|
|
60
|
+
* that should be forwarded to @supervisor. Records allowed questions.
|
|
61
|
+
*/
|
|
62
|
+
export declare function filterQuestions(candidates: string[], guard: QuestionGuard, exploration: ExplorationResult | null): string[];
|
|
63
|
+
/**
|
|
64
|
+
* Determine whether supervisor clarification is warranted at all.
|
|
65
|
+
* Returns false when:
|
|
66
|
+
* - No questions remain after evidence filtering
|
|
67
|
+
* - All questions were answered by the exploration result
|
|
68
|
+
*
|
|
69
|
+
* Call this before invoking @supervisor to avoid empty escalations.
|
|
70
|
+
*/
|
|
71
|
+
export declare function needsSupervisorClarification(questions: string[], guard: QuestionGuard, exploration: ExplorationResult | null): boolean;
|
|
72
|
+
/**
|
|
73
|
+
* Strict check for worker agents (coder, planner, tester, etc.).
|
|
74
|
+
*
|
|
75
|
+
* Worker agents MUST NOT ask the human directly. They must either:
|
|
76
|
+
* a) use repo evidence (this returns { canProceed: true, evidence })
|
|
77
|
+
* b) report missing data to orchestrator/supervisor
|
|
78
|
+
*
|
|
79
|
+
* This function decides which path to take.
|
|
80
|
+
*/
|
|
81
|
+
export interface WorkerAgentDecision {
|
|
82
|
+
/** True when the worker can proceed using evidence alone */
|
|
83
|
+
canProceed: boolean;
|
|
84
|
+
/** True when the worker must stop and report missing data upward */
|
|
85
|
+
mustEscalate: boolean;
|
|
86
|
+
/** Evidence that allows the worker to proceed (when canProceed=true) */
|
|
87
|
+
evidence?: string;
|
|
88
|
+
/** What data is missing (when mustEscalate=true) */
|
|
89
|
+
missingData?: string;
|
|
90
|
+
}
|
|
91
|
+
export declare function workerAgentDecision(requiredInfo: string, exploration: ExplorationResult): WorkerAgentDecision;
|
|
92
|
+
//# sourceMappingURL=question-guard.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"question-guard.d.ts","sourceRoot":"","sources":["../../src/services/question-guard.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAA;AAG7D,MAAM,WAAW,WAAW;IAC1B,oEAAoE;IACpE,KAAK,EAAE,OAAO,CAAA;IACd,yDAAyD;IACzD,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,8DAA8D;IAC9D,kBAAkB,CAAC,EAAE,OAAO,CAAA;IAC5B,wDAAwD;IACxD,SAAS,CAAC,EAAE,OAAO,CAAA;CACpB;AAED,MAAM,WAAW,aAAa;IAC5B;;;;;;;OAOG;IACH,KAAK,CAAC,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,iBAAiB,GAAG,IAAI,GAAG,WAAW,CAAA;IAC3E;;;OAGG;IACH,MAAM,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;IAC9B,4DAA4D;IAC5D,QAAQ,IAAI,MAAM,EAAE,CAAA;IACpB,6CAA6C;IAC7C,KAAK,IAAI,IAAI,CAAA;CACd;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,cAAc,GAAE,MAAM,EAAO,GAAG,aAAa,CA0ChF;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAC7B,UAAU,EAAE,MAAM,EAAE,EACpB,KAAK,EAAE,aAAa,EACpB,WAAW,EAAE,iBAAiB,GAAG,IAAI,GACpC,MAAM,EAAE,CASV;AAED;;;;;;;GAOG;AACH,wBAAgB,4BAA4B,CAC1C,SAAS,EAAE,MAAM,EAAE,EACnB,KAAK,EAAE,aAAa,EACpB,WAAW,EAAE,iBAAiB,GAAG,IAAI,GACpC,OAAO,CAGT;AAMD;;;;;;;;GAQG;AACH,MAAM,WAAW,mBAAmB;IAClC,4DAA4D;IAC5D,UAAU,EAAE,OAAO,CAAA;IACnB,oEAAoE;IACpE,YAAY,EAAE,OAAO,CAAA;IACrB,wEAAwE;IACxE,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,oDAAoD;IACpD,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB;AAED,wBAAgB,mBAAmB,CACjC,YAAY,EAAE,MAAM,EACpB,WAAW,EAAE,iBAAiB,GAC7B,mBAAmB,CAmBrB"}
|