@dv.nghiem/flowdeck 0.3.6 → 0.3.7

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 (41) hide show
  1. package/dist/agents/index.d.ts +2 -1
  2. package/dist/agents/index.d.ts.map +1 -1
  3. package/dist/agents/supervisor.d.ts +3 -0
  4. package/dist/agents/supervisor.d.ts.map +1 -0
  5. package/dist/config/schema.d.ts +36 -0
  6. package/dist/config/schema.d.ts.map +1 -1
  7. package/dist/dashboard/lib/state-reader.d.ts.map +1 -1
  8. package/dist/dashboard/server.mjs +0 -37
  9. package/dist/dashboard/types.d.ts +0 -2
  10. package/dist/dashboard/types.d.ts.map +1 -1
  11. package/dist/dashboard/views/index.ejs +0 -6
  12. package/dist/dashboard/views/partials/header.ejs +0 -4
  13. package/dist/index.d.ts.map +1 -1
  14. package/dist/index.js +808 -1
  15. package/dist/services/agent-contract-registry.d.ts.map +1 -1
  16. package/dist/services/supervisor-binding.d.ts +114 -0
  17. package/dist/services/supervisor-binding.d.ts.map +1 -0
  18. package/dist/services/supervisor.test.d.ts +14 -0
  19. package/dist/services/supervisor.test.d.ts.map +1 -0
  20. package/dist/services/telemetry.d.ts +1 -1
  21. package/dist/services/telemetry.d.ts.map +1 -1
  22. package/dist/services/workflow-scorecard.d.ts +20 -0
  23. package/dist/services/workflow-scorecard.d.ts.map +1 -1
  24. package/docs/agents.md +1 -1
  25. package/docs/commands/fd-ask.md +1 -1
  26. package/docs/commands/fd-deploy-check.md +1 -1
  27. package/docs/commands/fd-discuss.md +1 -1
  28. package/docs/commands/fd-fix-bug.md +1 -1
  29. package/docs/commands/fd-new-feature.md +1 -1
  30. package/docs/commands/fd-verify.md +18 -0
  31. package/docs/commands/fd-write-docs.md +1 -1
  32. package/docs/feature-integration-architecture.md +1 -1
  33. package/docs/notifications.md +2 -2
  34. package/docs/quick-start.md +1 -1
  35. package/docs/skills.md +1 -1
  36. package/package.json +1 -1
  37. package/src/commands/fd-new-project.md +0 -1
  38. package/src/rules/common/agent-orchestration.md +1 -1
  39. package/src/skills/design-tokens/SKILL.md +250 -0
  40. package/src/skills/git-release/SKILL.md +1 -1
  41. package/src/skills/ui-design/SKILL.md +313 -0
package/dist/index.js CHANGED
@@ -6278,6 +6278,133 @@ var createDesignAgent = (model, customPrompt, customAppendPrompt) => {
6278
6278
  };
6279
6279
  };
6280
6280
 
6281
+ // src/agents/supervisor.ts
6282
+ var SUPERVISOR_PROMPT = `You are the FlowDeck Supervisor Agent — a governance layer that reviews existing commands and agents before or after execution.
6283
+
6284
+ ## Role and Hard Constraints
6285
+
6286
+ **You review. You do not execute.**
6287
+
6288
+ You sit above the orchestrator's execution path. Your only job is to inspect an already-selected command or agent, validate it against policy, and return a structured decision.
6289
+
6290
+ ### You MUST NEVER:
6291
+ - Invent a new command name
6292
+ - Invent a new workflow definition
6293
+ - Suggest creating a new agent
6294
+ - Replace or duplicate the orchestrator
6295
+ - Execute implementation tasks
6296
+ - Become a second dispatcher
6297
+ - Modify the intent of an existing command
6298
+
6299
+ ### You MAY:
6300
+ - Inspect an existing registered command or agent
6301
+ - Validate that required stages are present
6302
+ - Detect policy violations in the selected target
6303
+ - Flag risk before execution
6304
+ - Decide: approve / revise / block / escalate
6305
+ - Request that the orchestrator obtain missing prerequisites
6306
+
6307
+ ## Registered Commands (source of truth — do not add to this list)
6308
+
6309
+ fd-ask, fd-checkpoint, fd-deploy-check, fd-design, fd-discuss, fd-doctor,
6310
+ fd-execute, fd-fix-bug, fd-map-codebase, fd-multi-repo, fd-new-feature,
6311
+ fd-new-project, fd-plan, fd-quick, fd-reflect, fd-resume, fd-status,
6312
+ fd-suggest, fd-translate-intent, fd-verify, fd-write-docs
6313
+
6314
+ ## Registered Agents (source of truth — do not add to this list)
6315
+
6316
+ orchestrator, planner, backend-coder, frontend-coder, devops, plan-checker,
6317
+ tester, reviewer, researcher, writer, security-auditor, doc-updater, mapper,
6318
+ code-explorer, debug-specialist, build-error-resolver, task-splitter, discusser,
6319
+ architect, risk-analyst, policy-enforcer, performance-optimizer, refactor-guide,
6320
+ auto-learner, design, supervisor
6321
+
6322
+ ## Policy Checks
6323
+
6324
+ When reviewing a command or agent, evaluate ONLY the following against what already exists:
6325
+
6326
+ ### Design-first policy
6327
+ - If the task is UI-heavy (dashboard, landing page, web app, UI, UX, admin panel) and the current phase is "execute", the design stage MUST have completed with approval.
6328
+ - If design approval is absent: decision = revise | required change = complete design stage first.
6329
+
6330
+ ### Bugfix regression policy
6331
+ - If the command is fd-fix-bug, a regression test MUST exist before implementation.
6332
+ - If no regression test: decision = revise | required change = write failing regression test first.
6333
+
6334
+ ### Phase ordering policy
6335
+ - fd-execute must only run in the "execute" phase.
6336
+ - If invoked in a different phase: decision = revise.
6337
+
6338
+ ### Missing inputs policy
6339
+ - If a registered agent has required inputs listed in its contract and they are absent: decision = revise.
6340
+
6341
+ ### Approval gate policy
6342
+ - If an operation requires explicit human approval and none was granted: decision = escalate.
6343
+
6344
+ ### Unregistered target policy
6345
+ - If the requested command or agent is NOT in the registered lists above: decision = block.
6346
+ - Do NOT suggest or create a replacement. Report that the target is unavailable.
6347
+
6348
+ ## Decision Output Format
6349
+
6350
+ Always respond with a valid JSON object matching this schema exactly:
6351
+
6352
+ \`\`\`json
6353
+ {
6354
+ "decision": "approve" | "revise" | "block" | "escalate",
6355
+ "targetType": "command" | "agent" | "workflow",
6356
+ "targetName": "<exact registered name>",
6357
+ "exists": true | false,
6358
+ "reasons": ["<human-readable reason>"],
6359
+ "missingRequirements": ["<what is absent>"],
6360
+ "riskFlags": ["<risk description>"],
6361
+ "requiredChanges": ["<what must change before proceeding>"],
6362
+ "approvalStatus": "approved" | "pending" | "denied" | "escalated",
6363
+ "confidenceScore": 0.0–1.0,
6364
+ "reviewPhase": "preflight" | "post-stage",
6365
+ "timestamp": "<ISO 8601>"
6366
+ }
6367
+ \`\`\`
6368
+
6369
+ ### Decision rules:
6370
+ - **approve**: target exists, all policy checks pass, confidence ≥ threshold
6371
+ - **revise**: target exists, fixable issues found — list requiredChanges so caller can resolve
6372
+ - **block**: target does not exist OR critical unfixable policy violation
6373
+ - **escalate**: human approval required OR confidence below threshold
6374
+
6375
+ ### On unregistered targets:
6376
+ If a requested command or workflow is not in the registered lists, set:
6377
+ - decision: "block"
6378
+ - exists: false
6379
+ - reasons: explain the target is not registered
6380
+ - requiredChanges: list valid registered alternatives
6381
+ - Do NOT invent a new command or workflow to substitute
6382
+
6383
+ ## Diagnostics
6384
+
6385
+ Before issuing a decision, log:
6386
+ 1. Which existing command/agent was reviewed
6387
+ 2. Whether it exists in the registry
6388
+ 3. Which policy checks ran
6389
+ 4. Why the decision was reached
6390
+ 5. Whether review is preflight or post-stage
6391
+ 6. Whether human escalation is recommended`;
6392
+ function createSupervisorAgent(model, customPrompt, customAppendPrompt) {
6393
+ const prompt = resolvePrompt(SUPERVISOR_PROMPT, customPrompt, customAppendPrompt);
6394
+ const definition = {
6395
+ name: "supervisor",
6396
+ description: "Governance supervisor that reviews existing commands and agents before execution. Approves, revises, blocks, or escalates — never creates new commands or workflows.",
6397
+ config: {
6398
+ temperature: 0.1,
6399
+ prompt
6400
+ }
6401
+ };
6402
+ if (typeof model === "string" && model) {
6403
+ definition.config.model = model;
6404
+ }
6405
+ return definition;
6406
+ }
6407
+
6281
6408
  // src/agents/index.ts
6282
6409
  var AGENT_NAMES = [
6283
6410
  "orchestrator",
@@ -6304,7 +6431,8 @@ var AGENT_NAMES = [
6304
6431
  "performance-optimizer",
6305
6432
  "refactor-guide",
6306
6433
  "auto-learner",
6307
- "design"
6434
+ "design",
6435
+ "supervisor"
6308
6436
  ];
6309
6437
  var PRIMARY_AGENTS = new Set(["orchestrator"]);
6310
6438
  var ALL_MODES_AGENTS = new Set;
@@ -6370,6 +6498,8 @@ function createAgent(name, model, customPrompt, customAppendPrompt) {
6370
6498
  return createAutoLearnerAgent(model);
6371
6499
  case "design":
6372
6500
  return createDesignAgent(model, customPrompt, customAppendPrompt);
6501
+ case "supervisor":
6502
+ return createSupervisorAgent(model, customPrompt, customAppendPrompt);
6373
6503
  default:
6374
6504
  console.warn(`[flowdeck] Unknown agent: ${name}`);
6375
6505
  return;
@@ -6407,6 +6537,632 @@ function getAgentConfigs(agentModels) {
6407
6537
  return configs;
6408
6538
  }
6409
6539
 
6540
+ // src/services/agent-contract-registry.ts
6541
+ var CONTRACTS = [
6542
+ {
6543
+ agent: "orchestrator",
6544
+ role: "Coordinate multi-agent execution. Delegates all work — never implements directly.",
6545
+ allowedTaskTypes: ["orchestration", "coordination", "delegation", "phase-management"],
6546
+ requiredInputs: ["STATE.md", "PLAN.md"],
6547
+ expectedOutputFields: ["delegated_steps", "completed_steps", "current_phase"],
6548
+ allowedTools: [
6549
+ "delegate",
6550
+ "run-pipeline",
6551
+ "council",
6552
+ "planning-state",
6553
+ "codebase-state",
6554
+ "workspace-state",
6555
+ "repo-memory",
6556
+ "decision-trace",
6557
+ "policy-engine",
6558
+ "context-generator",
6559
+ "create-skill",
6560
+ "reflect"
6561
+ ],
6562
+ forbiddenActions: [
6563
+ "write_file",
6564
+ "edit_file",
6565
+ "create_file",
6566
+ "bash",
6567
+ "patch",
6568
+ "apply_patch",
6569
+ "read source files directly"
6570
+ ],
6571
+ escalationConditions: [
6572
+ "delegated agent fails twice",
6573
+ "delegation budget exhausted",
6574
+ "deadlock detected",
6575
+ "all agents blocked on the same step"
6576
+ ],
6577
+ stopConditions: [
6578
+ "all PLAN.md steps completed",
6579
+ "user requests stop",
6580
+ "budget exceeded with no fallback"
6581
+ ],
6582
+ successCriteria: [
6583
+ "all plan steps delegated and completed",
6584
+ "STATE.md phase updated to review",
6585
+ "no implementation performed directly by orchestrator"
6586
+ ]
6587
+ },
6588
+ {
6589
+ agent: "planner",
6590
+ role: "Create detailed implementation plans. Output PLAN.md with numbered steps.",
6591
+ allowedTaskTypes: ["planning", "task-breakdown", "step-decomposition"],
6592
+ requiredInputs: ["task description or STATE.md"],
6593
+ expectedOutputFields: ["steps", "phase"],
6594
+ allowedTools: ["read", "glob", "grep", "planning-state", "workspace-state"],
6595
+ forbiddenActions: [
6596
+ "write source files",
6597
+ "run bash commands",
6598
+ "edit application code",
6599
+ "implement features"
6600
+ ],
6601
+ escalationConditions: [
6602
+ "requirements are ambiguous",
6603
+ "dependencies between steps unclear",
6604
+ "conflicting constraints"
6605
+ ],
6606
+ stopConditions: ["PLAN.md written and reviewed by plan-checker", "user confirms plan"],
6607
+ successCriteria: [
6608
+ "PLAN.md contains numbered steps with assigned agents",
6609
+ "each step has clear success criteria",
6610
+ "no implementation performed"
6611
+ ]
6612
+ },
6613
+ {
6614
+ agent: "plan-checker",
6615
+ role: "Review PLAN.md quality before execution. Read-only.",
6616
+ allowedTaskTypes: ["plan-review", "quality-check"],
6617
+ requiredInputs: ["PLAN.md"],
6618
+ expectedOutputFields: ["verdict", "issues", "recommendations"],
6619
+ allowedTools: ["read", "glob", "grep"],
6620
+ forbiddenActions: ["write or edit any files", "modify PLAN.md"],
6621
+ escalationConditions: ["plan is fundamentally flawed", "critical gaps found"],
6622
+ stopConditions: ["review complete", "verdict issued"],
6623
+ successCriteria: ["structured review output", "no file modifications"]
6624
+ },
6625
+ {
6626
+ agent: "design",
6627
+ role: "Design UX, wireframes, and visual systems for UI-heavy tasks.",
6628
+ allowedTaskTypes: ["ux-design", "wireframe", "visual-system", "design-handoff", "frontend-handoff"],
6629
+ requiredInputs: ["task description", "requirements"],
6630
+ expectedOutputFields: ["design_stage", "wireframes", "component_structure", "design_tokens"],
6631
+ allowedTools: ["read", "write", "glob", "grep", "planning-state"],
6632
+ forbiddenActions: [
6633
+ "run bash commands",
6634
+ "write application logic",
6635
+ "implement backend code",
6636
+ "implement React components"
6637
+ ],
6638
+ escalationConditions: [
6639
+ "design requirements unclear",
6640
+ "conflicting UX requirements",
6641
+ "brand guidelines missing"
6642
+ ],
6643
+ stopConditions: ["design_stage=handoff_complete", "design_approved=true"],
6644
+ successCriteria: [
6645
+ "design document written",
6646
+ "design_stage set to handoff_complete",
6647
+ "design_approved set to true",
6648
+ "no application code written"
6649
+ ]
6650
+ },
6651
+ {
6652
+ agent: "backend-coder",
6653
+ role: "Implement backend features: API, services, data layer, business logic.",
6654
+ allowedTaskTypes: ["implementation", "backend", "api", "database", "service", "bugfix"],
6655
+ requiredInputs: ["PLAN.md step description", "relevant context files"],
6656
+ expectedOutputFields: ["files_modified", "summary"],
6657
+ allowedTools: ["read", "write", "edit", "bash", "glob", "grep"],
6658
+ forbiddenActions: [
6659
+ "modify frontend UI component files",
6660
+ "change CI/CD config without devops involvement"
6661
+ ],
6662
+ escalationConditions: [
6663
+ "architecture decision needed",
6664
+ "security-sensitive change without audit",
6665
+ "database migration required"
6666
+ ],
6667
+ stopConditions: ["step implementation complete", "tests pass", "reviewer approves"],
6668
+ successCriteria: [
6669
+ "code written per plan step",
6670
+ "no regressions introduced",
6671
+ "tests exist or updated"
6672
+ ]
6673
+ },
6674
+ {
6675
+ agent: "frontend-coder",
6676
+ role: "Implement frontend features: UI components, client state, rendering.",
6677
+ allowedTaskTypes: ["implementation", "frontend", "ui", "component", "styling", "bugfix"],
6678
+ requiredInputs: ["PLAN.md step description", "design handoff for UI-heavy tasks"],
6679
+ expectedOutputFields: ["files_modified", "summary"],
6680
+ allowedTools: ["read", "write", "edit", "bash", "glob", "grep"],
6681
+ forbiddenActions: [
6682
+ "modify backend API files",
6683
+ "change server configuration",
6684
+ "implement without approved design for UI-heavy tasks"
6685
+ ],
6686
+ escalationConditions: [
6687
+ "design handoff missing for UI-heavy task",
6688
+ "component library or design system unclear"
6689
+ ],
6690
+ stopConditions: ["step implementation complete", "tests pass", "reviewer approves"],
6691
+ successCriteria: [
6692
+ "components implemented per approved design",
6693
+ "no regressions introduced",
6694
+ "tests exist or updated"
6695
+ ]
6696
+ },
6697
+ {
6698
+ agent: "devops",
6699
+ role: "Implement DevOps and infrastructure changes: CI/CD, deployment, infra scripts.",
6700
+ allowedTaskTypes: ["implementation", "ci-cd", "deployment", "infrastructure", "operations"],
6701
+ requiredInputs: ["PLAN.md step description"],
6702
+ expectedOutputFields: ["files_modified", "summary"],
6703
+ allowedTools: ["read", "write", "edit", "bash", "glob", "grep"],
6704
+ forbiddenActions: [
6705
+ "modify application source code",
6706
+ "deploy to production without approval"
6707
+ ],
6708
+ escalationConditions: [
6709
+ "production deployment requires approval",
6710
+ "destructive infra change"
6711
+ ],
6712
+ stopConditions: ["pipeline or infra change complete", "reviewer approves"],
6713
+ successCriteria: ["infrastructure code written per plan", "no prod deployment without approval"]
6714
+ },
6715
+ {
6716
+ agent: "tester",
6717
+ role: "Write and run tests following TDD principles. Tests before implementation.",
6718
+ allowedTaskTypes: ["testing", "tdd", "regression", "integration-test", "unit-test"],
6719
+ requiredInputs: ["feature or step description", "relevant source files"],
6720
+ expectedOutputFields: ["test_files_written", "tests_passing", "coverage_summary"],
6721
+ allowedTools: ["read", "write", "edit", "bash", "glob", "grep"],
6722
+ forbiddenActions: [
6723
+ "delete failing tests to make suite pass",
6724
+ "implement application features",
6725
+ "skip TDD cycle (red → green → refactor)"
6726
+ ],
6727
+ escalationConditions: [
6728
+ "test infrastructure broken",
6729
+ "flaky tests blocking all progress"
6730
+ ],
6731
+ stopConditions: ["all tests pass", "coverage meets threshold"],
6732
+ successCriteria: [
6733
+ "tests written before implementation",
6734
+ "all new tests pass",
6735
+ "no test deletions to fix failures"
6736
+ ]
6737
+ },
6738
+ {
6739
+ agent: "reviewer",
6740
+ role: "Review code quality, security, and convention adherence. Read-only.",
6741
+ allowedTaskTypes: ["review", "code-review", "quality-check"],
6742
+ requiredInputs: ["files to review", "context of changes"],
6743
+ expectedOutputFields: ["verdict", "issues", "recommendations"],
6744
+ allowedTools: ["read", "glob", "grep"],
6745
+ forbiddenActions: [
6746
+ "write or edit any files",
6747
+ "make code changes",
6748
+ "approve security-sensitive changes without security audit"
6749
+ ],
6750
+ escalationConditions: [
6751
+ "security issues found",
6752
+ "critical bugs found",
6753
+ "architectural violations"
6754
+ ],
6755
+ stopConditions: ["review complete", "verdict issued"],
6756
+ successCriteria: [
6757
+ "structured review output with severity levels",
6758
+ "issues categorized",
6759
+ "no file modifications"
6760
+ ]
6761
+ },
6762
+ {
6763
+ agent: "security-auditor",
6764
+ role: "Security audit: OWASP Top 10, injection, auth vulnerabilities. Read-only.",
6765
+ allowedTaskTypes: ["security-audit", "vulnerability-scan", "auth-review"],
6766
+ requiredInputs: ["files to audit", "change context"],
6767
+ expectedOutputFields: ["findings", "severity_breakdown", "recommendations"],
6768
+ allowedTools: ["read", "glob", "grep"],
6769
+ forbiddenActions: [
6770
+ "write or edit files",
6771
+ "make changes to fix vulnerabilities directly"
6772
+ ],
6773
+ escalationConditions: [
6774
+ "CRITICAL vulnerability found",
6775
+ "auth bypass detected",
6776
+ "data exposure found"
6777
+ ],
6778
+ stopConditions: ["audit complete", "all findings documented"],
6779
+ successCriteria: [
6780
+ "OWASP checklist evaluated",
6781
+ "findings documented with severity levels",
6782
+ "no file modifications"
6783
+ ]
6784
+ },
6785
+ {
6786
+ agent: "researcher",
6787
+ role: "Research documentation, APIs, best practices. Read-only analysis.",
6788
+ allowedTaskTypes: ["research", "api-lookup", "documentation", "best-practices"],
6789
+ requiredInputs: ["research topic or question"],
6790
+ expectedOutputFields: ["findings", "references", "recommendations"],
6791
+ allowedTools: ["read", "glob", "grep", "web-search"],
6792
+ forbiddenActions: ["write or edit files", "implement solutions"],
6793
+ escalationConditions: [
6794
+ "critical information unavailable",
6795
+ "conflicting official documentation"
6796
+ ],
6797
+ stopConditions: ["research question answered", "findings documented"],
6798
+ successCriteria: [
6799
+ "findings clearly summarized",
6800
+ "sources cited",
6801
+ "no file modifications"
6802
+ ]
6803
+ },
6804
+ {
6805
+ agent: "architect",
6806
+ role: "Design system architecture, create ADRs, define API contracts.",
6807
+ allowedTaskTypes: ["architecture", "adr", "api-design", "system-design"],
6808
+ requiredInputs: ["feature or system description", "existing codebase context"],
6809
+ expectedOutputFields: ["architecture_document", "adr", "api_contracts"],
6810
+ allowedTools: ["read", "write", "glob", "grep", "planning-state"],
6811
+ forbiddenActions: ["write application code", "run bash commands"],
6812
+ escalationConditions: [
6813
+ "major architectural conflict with existing system",
6814
+ "breaking API change required"
6815
+ ],
6816
+ stopConditions: ["ADR written", "architecture reviewed"],
6817
+ successCriteria: [
6818
+ "architecture documented with tradeoffs",
6819
+ "no application code written"
6820
+ ]
6821
+ },
6822
+ {
6823
+ agent: "writer",
6824
+ role: "Draft project documentation: README, API docs, user guides.",
6825
+ allowedTaskTypes: ["documentation", "readme", "api-docs", "user-guide"],
6826
+ requiredInputs: ["feature description or codebase context"],
6827
+ expectedOutputFields: ["documentation_files"],
6828
+ allowedTools: ["read", "write", "edit", "glob", "grep"],
6829
+ forbiddenActions: ["modify application code", "run bash commands"],
6830
+ escalationConditions: ["documentation scope unclear"],
6831
+ stopConditions: ["docs written", "user confirms completeness"],
6832
+ successCriteria: [
6833
+ "documentation written and accurate",
6834
+ "no application code changed"
6835
+ ]
6836
+ },
6837
+ {
6838
+ agent: "doc-updater",
6839
+ role: "Update existing documentation after code changes.",
6840
+ allowedTaskTypes: ["documentation-update", "doc-sync"],
6841
+ requiredInputs: ["changed files", "change summary"],
6842
+ expectedOutputFields: ["updated_docs"],
6843
+ allowedTools: ["read", "write", "edit", "glob", "grep"],
6844
+ forbiddenActions: [
6845
+ "modify application code",
6846
+ "delete documentation without replacement"
6847
+ ],
6848
+ escalationConditions: ["documentation conflicts with implementation"],
6849
+ stopConditions: ["docs updated and synced"],
6850
+ successCriteria: ["docs reflect current code", "no application code changed"]
6851
+ },
6852
+ {
6853
+ agent: "supervisor",
6854
+ role: "Governance review layer. Inspects existing commands/agents, validates policy, returns structured approve/revise/block/escalate decision. Never creates new commands or workflows.",
6855
+ allowedTaskTypes: ["governance-review", "policy-check", "pre-execution-review", "post-stage-review"],
6856
+ requiredInputs: ["target name (command or agent)", "task context"],
6857
+ expectedOutputFields: ["decision", "targetType", "targetName", "exists", "reasons", "missingRequirements", "riskFlags", "requiredChanges", "approvalStatus", "confidenceScore"],
6858
+ allowedTools: ["read", "glob", "grep", "planning-state", "policy-engine"],
6859
+ forbiddenActions: [
6860
+ "create new commands",
6861
+ "create new workflows",
6862
+ "invent new agent names",
6863
+ "modify command intent",
6864
+ "replace orchestrator",
6865
+ "become second dispatcher",
6866
+ "execute implementation tasks",
6867
+ "write or edit source files",
6868
+ "run bash commands",
6869
+ "modify PLAN.md or STATE.md"
6870
+ ],
6871
+ escalationConditions: [
6872
+ "human approval required and not granted",
6873
+ "confidence below threshold",
6874
+ "critical policy violation with no safe path forward"
6875
+ ],
6876
+ stopConditions: ["structured decision issued", "review complete"],
6877
+ successCriteria: [
6878
+ "structured SupervisorDecision returned",
6879
+ "no new commands or workflows created",
6880
+ "existing registry not modified",
6881
+ "decision is one of: approve, revise, block, escalate"
6882
+ ]
6883
+ }
6884
+ ];
6885
+ var REGISTRY = new Map(CONTRACTS.map((c) => [c.agent, c]));
6886
+ function getContract(agent) {
6887
+ return REGISTRY.get(agent) ?? null;
6888
+ }
6889
+
6890
+ // src/services/supervisor-binding.ts
6891
+ var REGISTERED_COMMANDS = [
6892
+ "fd-ask",
6893
+ "fd-checkpoint",
6894
+ "fd-deploy-check",
6895
+ "fd-design",
6896
+ "fd-discuss",
6897
+ "fd-doctor",
6898
+ "fd-execute",
6899
+ "fd-fix-bug",
6900
+ "fd-map-codebase",
6901
+ "fd-multi-repo",
6902
+ "fd-new-feature",
6903
+ "fd-new-project",
6904
+ "fd-plan",
6905
+ "fd-quick",
6906
+ "fd-reflect",
6907
+ "fd-resume",
6908
+ "fd-status",
6909
+ "fd-suggest",
6910
+ "fd-translate-intent",
6911
+ "fd-verify",
6912
+ "fd-write-docs"
6913
+ ];
6914
+ function resolveSupervisorConfig(directory) {
6915
+ try {
6916
+ const config = loadFlowDeckConfig(directory);
6917
+ const sup = config?.governance?.supervisor ?? {};
6918
+ return {
6919
+ enabled: sup.enabled ?? false,
6920
+ mode: sup.mode ?? "advisory",
6921
+ reviewedTargets: sup.reviewedTargets ?? [],
6922
+ canBlock: sup.canBlock ?? true,
6923
+ confidenceThreshold: sup.confidenceThreshold ?? 0.7,
6924
+ postExecutionReview: sup.postExecutionReview ?? false
6925
+ };
6926
+ } catch {
6927
+ return {
6928
+ enabled: false,
6929
+ mode: "advisory",
6930
+ reviewedTargets: [],
6931
+ canBlock: true,
6932
+ confidenceThreshold: 0.7,
6933
+ postExecutionReview: false
6934
+ };
6935
+ }
6936
+ }
6937
+ function isRegisteredCommand(name) {
6938
+ return REGISTERED_COMMANDS.includes(name);
6939
+ }
6940
+ function isRegisteredAgent(name) {
6941
+ return AGENT_NAMES.includes(name);
6942
+ }
6943
+ function isRegisteredTarget(name) {
6944
+ if (isRegisteredCommand(name))
6945
+ return { exists: true, type: "command" };
6946
+ if (isRegisteredAgent(name))
6947
+ return { exists: true, type: "agent" };
6948
+ return { exists: false, type: "agent" };
6949
+ }
6950
+ function checkCommandPolicy(commandName, ctx) {
6951
+ const reasons = [];
6952
+ const riskFlags = [];
6953
+ const missingRequirements = [];
6954
+ const requiredChanges = [];
6955
+ if (commandName === "fd-new-feature" || commandName === "fd-execute") {
6956
+ const taskLower = (ctx.taskDescription ?? "").toLowerCase();
6957
+ const isUiHeavy = /landing page|dashboard|admin panel|website|web app|ui|ux|interface|frontend|component/.test(taskLower);
6958
+ if (isUiHeavy && ctx.currentPhase === "execute" && ctx.designApprovalPresent === false) {
6959
+ missingRequirements.push("design approval (design stage must complete before execute for UI-heavy tasks)");
6960
+ riskFlags.push("UI-heavy task entering execute phase without design approval");
6961
+ requiredChanges.push("Run /fd-design first and obtain design approval before proceeding to execute");
6962
+ }
6963
+ }
6964
+ if (commandName === "fd-fix-bug") {
6965
+ if (ctx.regressionTestPresent === false) {
6966
+ missingRequirements.push("regression test (required before bugfix implementation)");
6967
+ riskFlags.push("Bugfix command invoked without a regression test");
6968
+ requiredChanges.push("Write a failing regression test before implementing the fix");
6969
+ }
6970
+ }
6971
+ if (commandName === "fd-deploy-check") {
6972
+ if (ctx.prerequisitesMet === false && ctx.missingInputs && ctx.missingInputs.length > 0) {
6973
+ missingRequirements.push(...ctx.missingInputs);
6974
+ riskFlags.push("Deploy check attempted with unmet prerequisites");
6975
+ }
6976
+ }
6977
+ if (commandName === "fd-execute" && ctx.currentPhase && ctx.currentPhase !== "execute") {
6978
+ riskFlags.push(`fd-execute invoked in phase "${ctx.currentPhase}" instead of "execute"`);
6979
+ requiredChanges.push(`Ensure project phase is "execute" before running fd-execute (currently: ${ctx.currentPhase})`);
6980
+ }
6981
+ if (ctx.approvalRequired && !ctx.approvalGranted) {
6982
+ missingRequirements.push("human approval (required for this command)");
6983
+ riskFlags.push("Approval gate not satisfied");
6984
+ requiredChanges.push("Obtain explicit human approval before proceeding");
6985
+ }
6986
+ const passed = missingRequirements.length === 0 && riskFlags.length === 0 && requiredChanges.length === 0;
6987
+ if (passed) {
6988
+ reasons.push(`Command "${commandName}" passed all policy checks`);
6989
+ }
6990
+ return { passed, reasons, riskFlags, missingRequirements, requiredChanges };
6991
+ }
6992
+ function checkAgentPolicy(agentName, ctx) {
6993
+ const reasons = [];
6994
+ const riskFlags = [];
6995
+ const missingRequirements = [];
6996
+ const requiredChanges = [];
6997
+ const contract = getContract(agentName);
6998
+ if (!contract) {
6999
+ riskFlags.push(`Agent "${agentName}" has no registered capability contract`);
7000
+ return { passed: false, reasons, riskFlags, missingRequirements, requiredChanges };
7001
+ }
7002
+ if (ctx.missingInputs && ctx.missingInputs.length > 0) {
7003
+ for (const missing of ctx.missingInputs) {
7004
+ const isRequired = contract.requiredInputs.some((r) => r.toLowerCase().includes(missing.toLowerCase()) || missing.toLowerCase().includes(r.toLowerCase()));
7005
+ if (isRequired) {
7006
+ missingRequirements.push(missing);
7007
+ requiredChanges.push(`Provide "${missing}" before delegating to ${agentName}`);
7008
+ }
7009
+ }
7010
+ }
7011
+ if (ctx.approvalRequired && !ctx.approvalGranted) {
7012
+ const needsApproval = contract.escalationConditions.some((c) => c.toLowerCase().includes("approval") || c.toLowerCase().includes("approve"));
7013
+ if (needsApproval) {
7014
+ missingRequirements.push("human approval");
7015
+ riskFlags.push(`Agent "${agentName}" requires approval via escalation condition`);
7016
+ requiredChanges.push("Obtain explicit human approval before proceeding");
7017
+ }
7018
+ }
7019
+ if (agentName === "design" || agentName === "frontend-coder") {
7020
+ const taskLower = (ctx.taskDescription ?? "").toLowerCase();
7021
+ const isUiHeavy = /landing page|dashboard|admin panel|website|web app|ui|ux|interface|frontend|component/.test(taskLower);
7022
+ if (agentName === "frontend-coder" && isUiHeavy && ctx.designApprovalPresent === false) {
7023
+ missingRequirements.push("design handoff approval");
7024
+ riskFlags.push("frontend-coder invoked for UI-heavy task without approved design handoff");
7025
+ requiredChanges.push("Complete design stage and obtain design approval before delegating to frontend-coder");
7026
+ }
7027
+ }
7028
+ const passed = missingRequirements.length === 0 && riskFlags.length === 0;
7029
+ if (passed) {
7030
+ reasons.push(`Agent "${agentName}" passed all policy checks`);
7031
+ }
7032
+ return { passed, reasons, riskFlags, missingRequirements, requiredChanges };
7033
+ }
7034
+ function computeConfidence(exists, policyResult, ctx) {
7035
+ if (!exists)
7036
+ return 0;
7037
+ if (policyResult.riskFlags.length >= 3)
7038
+ return 0.2;
7039
+ if (policyResult.riskFlags.length === 2)
7040
+ return 0.4;
7041
+ if (policyResult.riskFlags.length === 1)
7042
+ return 0.6;
7043
+ if (policyResult.missingRequirements.length > 0)
7044
+ return 0.5;
7045
+ if (ctx.prerequisitesMet === false)
7046
+ return 0.45;
7047
+ return 0.95;
7048
+ }
7049
+ function resolveDecision(exists, policyResult, confidenceScore, threshold, ctx) {
7050
+ if (!exists) {
7051
+ return { decision: "block", approvalStatus: "denied" };
7052
+ }
7053
+ if (ctx.approvalRequired && !ctx.approvalGranted) {
7054
+ return { decision: "escalate", approvalStatus: "escalated" };
7055
+ }
7056
+ if (!policyResult.passed) {
7057
+ if (policyResult.requiredChanges.length > 0) {
7058
+ return { decision: "revise", approvalStatus: "pending" };
7059
+ }
7060
+ return { decision: "block", approvalStatus: "denied" };
7061
+ }
7062
+ if (confidenceScore < threshold) {
7063
+ return { decision: "escalate", approvalStatus: "escalated" };
7064
+ }
7065
+ return { decision: "approve", approvalStatus: "approved" };
7066
+ }
7067
+ function runSupervisorReview(directory, targetName, ctx = {}) {
7068
+ const config = resolveSupervisorConfig(directory);
7069
+ const reviewPhase = ctx.reviewPhase ?? "preflight";
7070
+ const timestamp2 = new Date().toISOString();
7071
+ if (config.reviewedTargets.length > 0 && !config.reviewedTargets.includes(targetName)) {
7072
+ return {
7073
+ decision: "approve",
7074
+ targetType: "agent",
7075
+ targetName,
7076
+ exists: true,
7077
+ reasons: [`Target "${targetName}" is not in the reviewed targets list — auto-approved`],
7078
+ missingRequirements: [],
7079
+ riskFlags: [],
7080
+ requiredChanges: [],
7081
+ approvalStatus: "approved",
7082
+ confidenceScore: 1,
7083
+ reviewPhase,
7084
+ timestamp: timestamp2
7085
+ };
7086
+ }
7087
+ const { exists, type: targetType } = isRegisteredTarget(targetName);
7088
+ if (!exists) {
7089
+ const decision2 = {
7090
+ decision: "block",
7091
+ targetType,
7092
+ targetName,
7093
+ exists: false,
7094
+ reasons: [
7095
+ `Target "${targetName}" is not registered in the FlowDeck command or agent registry.`,
7096
+ "The supervisor does not create new commands or workflows.",
7097
+ "Only registered targets can be executed."
7098
+ ],
7099
+ missingRequirements: [],
7100
+ riskFlags: [`Unregistered target: "${targetName}"`],
7101
+ requiredChanges: [
7102
+ `Use one of the registered commands: ${REGISTERED_COMMANDS.join(", ")}`,
7103
+ `Or use one of the registered agents: ${AGENT_NAMES.join(", ")}`
7104
+ ],
7105
+ approvalStatus: "denied",
7106
+ confidenceScore: 0,
7107
+ reviewPhase,
7108
+ timestamp: timestamp2
7109
+ };
7110
+ _emitTelemetry(directory, decision2, ctx);
7111
+ return decision2;
7112
+ }
7113
+ const policyResult = targetType === "command" ? checkCommandPolicy(targetName, ctx) : checkAgentPolicy(targetName, ctx);
7114
+ const confidenceScore = computeConfidence(exists, policyResult, ctx);
7115
+ const { decision, approvalStatus } = resolveDecision(exists, policyResult, confidenceScore, config.confidenceThreshold, ctx);
7116
+ const reasons = policyResult.reasons.length > 0 ? policyResult.reasons : decision === "approve" ? [`Target "${targetName}" reviewed and approved for execution`] : [`Target "${targetName}" reviewed — decision: ${decision}`];
7117
+ const supervisorDecision = {
7118
+ decision,
7119
+ targetType,
7120
+ targetName,
7121
+ exists,
7122
+ reasons,
7123
+ missingRequirements: policyResult.missingRequirements,
7124
+ riskFlags: policyResult.riskFlags,
7125
+ requiredChanges: policyResult.requiredChanges,
7126
+ approvalStatus,
7127
+ confidenceScore,
7128
+ reviewPhase,
7129
+ timestamp: timestamp2
7130
+ };
7131
+ _emitTelemetry(directory, supervisorDecision, ctx);
7132
+ return supervisorDecision;
7133
+ }
7134
+ function shouldProceed(decision, mode, canBlock) {
7135
+ if (!decision.exists)
7136
+ return false;
7137
+ if (!canBlock)
7138
+ return true;
7139
+ if (mode === "strict") {
7140
+ return decision.decision === "approve" || decision.decision === "revise";
7141
+ }
7142
+ return decision.decision !== "block" || decision.confidenceScore > 0.3;
7143
+ }
7144
+ function _emitTelemetry(directory, decision, ctx) {
7145
+ try {
7146
+ appendEvent(directory, {
7147
+ session_id: ctx.session_id ?? "session-0",
7148
+ run_id: ctx.run_id ?? "unknown",
7149
+ event: "supervisor.review",
7150
+ agent: "supervisor",
7151
+ status: decision.decision === "approve" ? "ok" : decision.decision === "block" ? "blocked" : decision.decision === "escalate" ? "approved" : "ok",
7152
+ meta: {
7153
+ targetName: decision.targetName,
7154
+ targetType: decision.targetType,
7155
+ exists: decision.exists,
7156
+ decision: decision.decision,
7157
+ confidenceScore: decision.confidenceScore,
7158
+ riskFlags: decision.riskFlags,
7159
+ missingRequirements: decision.missingRequirements,
7160
+ reviewPhase: decision.reviewPhase
7161
+ }
7162
+ });
7163
+ } catch {}
7164
+ }
7165
+
6410
7166
  // src/index.ts
6411
7167
  function loadRulePaths() {
6412
7168
  const __dir = dirname4(fileURLToPath2(import.meta.url));
@@ -6626,6 +7382,33 @@ var plugin = async (input, _options) => {
6626
7382
  }
6627
7383
  }
6628
7384
  orchestratorGuard.check(toolInput.sessionID ?? "", toolInput.tool ?? toolInput.name ?? "");
7385
+ const toolName = toolInput.tool ?? toolInput.name ?? "";
7386
+ if (toolName === "delegate" || toolName === "run-pipeline") {
7387
+ const supConfig = resolveSupervisorConfig(directory);
7388
+ if (supConfig.enabled) {
7389
+ const args = toolOutput?.args ?? toolInput?.args ?? {};
7390
+ const agentTarget = typeof args.agent === "string" ? args.agent.replace(/^@/, "") : Array.isArray(args.steps) && args.steps[0]?.agent ? String(args.steps[0].agent).replace(/^@/, "") : "";
7391
+ if (agentTarget) {
7392
+ const decision = runSupervisorReview(directory, agentTarget, {
7393
+ taskDescription: typeof args.prompt === "string" ? args.prompt : undefined,
7394
+ reviewPhase: "preflight",
7395
+ session_id: toolInput.sessionID ?? toolInput.sessionId ?? ""
7396
+ });
7397
+ const proceed = shouldProceed(decision, supConfig.mode, supConfig.canBlock);
7398
+ appLog(`[Supervisor] ${decision.reviewPhase} review of "${decision.targetName}": ` + `decision=${decision.decision} exists=${decision.exists} confidence=${decision.confidenceScore.toFixed(2)} ` + `${decision.riskFlags.length > 0 ? `risks=[${decision.riskFlags.join("; ")}]` : ""}`);
7399
+ if (!proceed) {
7400
+ const summary = [
7401
+ `[Supervisor] Execution blocked for target "${decision.targetName}".`,
7402
+ ...decision.reasons,
7403
+ ...decision.missingRequirements.length > 0 ? [`Missing: ${decision.missingRequirements.join(", ")}`] : [],
7404
+ ...decision.requiredChanges.length > 0 ? [`Required changes: ${decision.requiredChanges.join("; ")}`] : []
7405
+ ].join(`
7406
+ `);
7407
+ throw new Error(summary);
7408
+ }
7409
+ }
7410
+ }
7411
+ }
6629
7412
  await telemetryHook({ directory }, toolInput, toolOutput);
6630
7413
  await approvalHook({ directory }, toolInput, toolOutput);
6631
7414
  await guardRailsHook({ directory }, toolInput, toolOutput);
@@ -6643,6 +7426,30 @@ var plugin = async (input, _options) => {
6643
7426
  } catch (err) {
6644
7427
  console.error("[FlowDeck Memory] Tool execution error:", err);
6645
7428
  }
7429
+ const afterToolName = toolInput.tool ?? toolInput.name ?? "";
7430
+ if (afterToolName === "delegate" || afterToolName === "run-pipeline") {
7431
+ try {
7432
+ const supConfig = resolveSupervisorConfig(directory);
7433
+ if (supConfig.enabled && supConfig.postExecutionReview) {
7434
+ const args = toolOutput?.args ?? toolInput?.args ?? {};
7435
+ const agentTarget = typeof args.agent === "string" ? args.agent.replace(/^@/, "") : Array.isArray(args.steps) && args.steps[0]?.agent ? String(args.steps[0].agent).replace(/^@/, "") : "";
7436
+ if (agentTarget) {
7437
+ const executionErrored = toolOutput?.error != null || toolOutput?.status === "error" || typeof toolOutput?.output === "string" && toolOutput.output.startsWith("Error:");
7438
+ const decision = runSupervisorReview(directory, agentTarget, {
7439
+ taskDescription: typeof args.prompt === "string" ? args.prompt : undefined,
7440
+ reviewPhase: "post-stage",
7441
+ session_id: toolInput.sessionID ?? toolInput.sessionId ?? "",
7442
+ prerequisitesMet: !executionErrored
7443
+ });
7444
+ const logLevel = decision.decision === "block" || decision.decision === "escalate" ? "[Supervisor][WARN]" : "[Supervisor]";
7445
+ appLog(`${logLevel} post-stage review of "${decision.targetName}": ` + `decision=${decision.decision} exists=${decision.exists} confidence=${decision.confidenceScore.toFixed(2)} ` + `executionErrored=${executionErrored} ` + `${decision.riskFlags.length > 0 ? `risks=[${decision.riskFlags.join("; ")}]` : ""}`);
7446
+ if (supConfig.mode === "strict" && !shouldProceed(decision, "strict", supConfig.canBlock)) {
7447
+ appLog(`[Supervisor][STRICT] Post-execution governance violation detected for "${decision.targetName}". ` + `Review the scorecard and telemetry for this run. ` + `Reasons: ${decision.reasons.join("; ")}`);
7448
+ }
7449
+ }
7450
+ }
7451
+ } catch {}
7452
+ }
6646
7453
  await contextMonitor["tool.execute.after"](toolInput, toolOutput);
6647
7454
  }
6648
7455
  };