maestro-flow 0.3.10 → 0.3.11

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 (184) hide show
  1. package/.claude/agents/workflow-collab-planner.md +1 -1
  2. package/.claude/agents/workflow-executor.md +1 -1
  3. package/.claude/agents/workflow-plan-checker.md +1 -1
  4. package/.claude/agents/workflow-planner.md +1 -1
  5. package/.claude/commands/learn-decompose.md +176 -176
  6. package/.claude/commands/learn-follow.md +167 -167
  7. package/.claude/commands/learn-retro.md +1 -1
  8. package/.claude/commands/maestro-coordinate.md +1 -3
  9. package/.claude/commands/manage-harvest.md +131 -131
  10. package/.claude/commands/manage-issue.md +2 -2
  11. package/.claude/commands/spec-add.md +67 -56
  12. package/.claude/commands/spec-load.md +66 -64
  13. package/.claude/commands/spec-setup.md +5 -9
  14. package/.codex/skills/learn-decompose/SKILL.md +119 -0
  15. package/.codex/skills/learn-follow/SKILL.md +83 -0
  16. package/.codex/skills/learn-investigate/SKILL.md +83 -0
  17. package/.codex/skills/learn-retro/SKILL.md +83 -0
  18. package/.codex/skills/learn-second-opinion/SKILL.md +86 -0
  19. package/.codex/skills/maestro/SKILL.md +151 -279
  20. package/.codex/skills/maestro-analyze/SKILL.md +59 -71
  21. package/.codex/skills/maestro-brainstorm/SKILL.md +452 -463
  22. package/.codex/skills/maestro-chain/SKILL.md +95 -110
  23. package/.codex/skills/maestro-coordinate/SKILL.md +68 -234
  24. package/.codex/skills/maestro-execute/SKILL.md +435 -446
  25. package/.codex/skills/maestro-fork/SKILL.md +68 -0
  26. package/.codex/skills/maestro-init/SKILL.md +171 -167
  27. package/.codex/skills/maestro-learn/SKILL.md +80 -0
  28. package/.codex/skills/maestro-link-coordinate/SKILL.md +224 -220
  29. package/.codex/skills/maestro-merge/SKILL.md +62 -0
  30. package/.codex/skills/maestro-milestone-audit/SKILL.md +108 -103
  31. package/.codex/skills/maestro-milestone-complete/SKILL.md +155 -149
  32. package/.codex/skills/maestro-milestone-release/SKILL.md +70 -0
  33. package/.codex/skills/maestro-overlay/SKILL.md +188 -185
  34. package/.codex/skills/maestro-plan/SKILL.md +58 -69
  35. package/.codex/skills/maestro-quick/SKILL.md +26 -23
  36. package/.codex/skills/maestro-roadmap/SKILL.md +65 -73
  37. package/.codex/skills/maestro-spec-generate/SKILL.md +66 -74
  38. package/.codex/skills/maestro-ui-design/SKILL.md +34 -31
  39. package/.codex/skills/maestro-verify/SKILL.md +556 -566
  40. package/.codex/skills/manage-codebase-rebuild/SKILL.md +397 -405
  41. package/.codex/skills/manage-codebase-refresh/SKILL.md +93 -82
  42. package/.codex/skills/manage-harvest/SKILL.md +82 -0
  43. package/.codex/skills/manage-issue/SKILL.md +80 -65
  44. package/.codex/skills/manage-issue-discover/SKILL.md +491 -503
  45. package/.codex/skills/manage-learn/SKILL.md +190 -186
  46. package/.codex/skills/manage-memory/SKILL.md +95 -72
  47. package/.codex/skills/manage-memory-capture/SKILL.md +99 -86
  48. package/.codex/skills/manage-status/SKILL.md +102 -89
  49. package/.codex/skills/quality-business-test/SKILL.md +228 -223
  50. package/.codex/skills/quality-debug/SKILL.md +54 -66
  51. package/.codex/skills/quality-integration-test/SKILL.md +532 -544
  52. package/.codex/skills/quality-refactor/SKILL.md +197 -191
  53. package/.codex/skills/quality-retrospective/SKILL.md +512 -505
  54. package/.codex/skills/quality-review/SKILL.md +93 -105
  55. package/.codex/skills/quality-sync/SKILL.md +101 -89
  56. package/.codex/skills/quality-test/SKILL.md +202 -198
  57. package/.codex/skills/quality-test-gen/SKILL.md +93 -104
  58. package/.codex/skills/spec-add/SKILL.md +58 -39
  59. package/.codex/skills/spec-load/SKILL.md +45 -40
  60. package/.codex/skills/spec-map/SKILL.md +180 -182
  61. package/.codex/skills/spec-setup/SKILL.md +94 -76
  62. package/.codex/skills/team-coordinate/SKILL.md +346 -357
  63. package/.codex/skills/team-executor/SKILL.md +70 -112
  64. package/.codex/skills/team-lifecycle-v4/SKILL.md +311 -299
  65. package/.codex/skills/team-quality-assurance/SKILL.md +234 -227
  66. package/.codex/skills/team-review/SKILL.md +232 -225
  67. package/.codex/skills/team-tech-debt/SKILL.md +78 -100
  68. package/.codex/skills/team-testing/SKILL.md +242 -235
  69. package/.codex/skills/wiki-connect/SKILL.md +75 -0
  70. package/.codex/skills/wiki-digest/SKILL.md +87 -0
  71. package/README.md +7 -4
  72. package/README.zh-CN.md +7 -4
  73. package/dashboard/dist-server/dashboard/src/server/routes/specs.d.ts +1 -1
  74. package/dashboard/dist-server/dashboard/src/server/routes/specs.js +75 -30
  75. package/dashboard/dist-server/dashboard/src/server/routes/specs.js.map +1 -1
  76. package/dashboard/dist-server/dashboard/src/server/state/event-bus.d.ts +5 -0
  77. package/dashboard/dist-server/dashboard/src/server/state/event-bus.js +5 -0
  78. package/dashboard/dist-server/dashboard/src/server/state/event-bus.js.map +1 -1
  79. package/dashboard/dist-server/dashboard/src/shared/constants.js +5 -0
  80. package/dashboard/dist-server/dashboard/src/shared/constants.js.map +1 -1
  81. package/dashboard/dist-server/dashboard/src/shared/team-types.d.ts +21 -0
  82. package/dashboard/dist-server/dashboard/src/shared/team-types.js.map +1 -1
  83. package/dashboard/dist-server/dashboard/src/shared/types.d.ts +3 -2
  84. package/dashboard/dist-server/dashboard/src/shared/ws-protocol.d.ts +1 -1
  85. package/dashboard/dist-server/dashboard/src/shared/ws-protocol.js.map +1 -1
  86. package/dashboard/dist-server/src/hooks/constants.d.ts +2 -0
  87. package/dashboard/dist-server/src/hooks/constants.js +2 -0
  88. package/dashboard/dist-server/src/hooks/constants.js.map +1 -1
  89. package/dist/src/commands/collab.js +4 -4
  90. package/dist/src/commands/collab.js.map +1 -1
  91. package/dist/src/commands/hooks.d.ts.map +1 -1
  92. package/dist/src/commands/hooks.js +66 -1
  93. package/dist/src/commands/hooks.js.map +1 -1
  94. package/dist/src/commands/spec.d.ts.map +1 -1
  95. package/dist/src/commands/spec.js +7 -2
  96. package/dist/src/commands/spec.js.map +1 -1
  97. package/dist/src/hooks/constants.d.ts +2 -0
  98. package/dist/src/hooks/constants.d.ts.map +1 -1
  99. package/dist/src/hooks/constants.js +2 -0
  100. package/dist/src/hooks/constants.js.map +1 -1
  101. package/dist/src/hooks/guards/index.d.ts +1 -0
  102. package/dist/src/hooks/guards/index.d.ts.map +1 -1
  103. package/dist/src/hooks/guards/index.js +1 -0
  104. package/dist/src/hooks/guards/index.js.map +1 -1
  105. package/dist/src/hooks/guards/spec-validator.d.ts +25 -0
  106. package/dist/src/hooks/guards/spec-validator.d.ts.map +1 -0
  107. package/dist/src/hooks/guards/spec-validator.js +66 -0
  108. package/dist/src/hooks/guards/spec-validator.js.map +1 -0
  109. package/dist/src/hooks/keyword-spec-injector.d.ts +21 -0
  110. package/dist/src/hooks/keyword-spec-injector.d.ts.map +1 -0
  111. package/dist/src/hooks/keyword-spec-injector.js +96 -0
  112. package/dist/src/hooks/keyword-spec-injector.js.map +1 -0
  113. package/dist/src/hooks/plugins/spec-injection-plugin.d.ts +2 -1
  114. package/dist/src/hooks/plugins/spec-injection-plugin.d.ts.map +1 -1
  115. package/dist/src/hooks/plugins/spec-injection-plugin.js +21 -12
  116. package/dist/src/hooks/plugins/spec-injection-plugin.js.map +1 -1
  117. package/dist/src/hooks/spec-bridge.d.ts +40 -0
  118. package/dist/src/hooks/spec-bridge.d.ts.map +1 -0
  119. package/dist/src/hooks/spec-bridge.js +97 -0
  120. package/dist/src/hooks/spec-bridge.js.map +1 -0
  121. package/dist/src/hooks/spec-injector.d.ts.map +1 -1
  122. package/dist/src/hooks/spec-injector.js +18 -12
  123. package/dist/src/hooks/spec-injector.js.map +1 -1
  124. package/dist/src/team/phase-orchestrator.d.ts +52 -0
  125. package/dist/src/team/phase-orchestrator.d.ts.map +1 -0
  126. package/dist/src/team/phase-orchestrator.js +165 -0
  127. package/dist/src/team/phase-orchestrator.js.map +1 -0
  128. package/dist/src/team/phase-types.d.ts +51 -0
  129. package/dist/src/team/phase-types.d.ts.map +1 -0
  130. package/dist/src/team/phase-types.js +41 -0
  131. package/dist/src/team/phase-types.js.map +1 -0
  132. package/dist/src/tools/index.d.ts.map +1 -1
  133. package/dist/src/tools/index.js +6 -0
  134. package/dist/src/tools/index.js.map +1 -1
  135. package/dist/src/tools/spec-entry-parser.d.ts +56 -0
  136. package/dist/src/tools/spec-entry-parser.d.ts.map +1 -0
  137. package/dist/src/tools/spec-entry-parser.js +196 -0
  138. package/dist/src/tools/spec-entry-parser.js.map +1 -0
  139. package/dist/src/tools/spec-init.d.ts.map +1 -1
  140. package/dist/src/tools/spec-init.js +66 -92
  141. package/dist/src/tools/spec-init.js.map +1 -1
  142. package/dist/src/tools/spec-keyword-index.d.ts +30 -0
  143. package/dist/src/tools/spec-keyword-index.d.ts.map +1 -0
  144. package/dist/src/tools/spec-keyword-index.js +101 -0
  145. package/dist/src/tools/spec-keyword-index.js.map +1 -0
  146. package/dist/src/tools/spec-loader.d.ts +3 -3
  147. package/dist/src/tools/spec-loader.d.ts.map +1 -1
  148. package/dist/src/tools/spec-loader.js +49 -23
  149. package/dist/src/tools/spec-loader.js.map +1 -1
  150. package/dist/src/tools/team-agents.d.ts +27 -0
  151. package/dist/src/tools/team-agents.d.ts.map +1 -0
  152. package/dist/src/tools/team-agents.js +362 -0
  153. package/dist/src/tools/team-agents.js.map +1 -0
  154. package/dist/src/tools/team-mailbox.d.ts +40 -0
  155. package/dist/src/tools/team-mailbox.d.ts.map +1 -0
  156. package/dist/src/tools/team-mailbox.js +384 -0
  157. package/dist/src/tools/team-mailbox.js.map +1 -0
  158. package/dist/src/tools/team-msg.d.ts +17 -8
  159. package/dist/src/tools/team-msg.d.ts.map +1 -1
  160. package/dist/src/tools/team-msg.js +110 -13
  161. package/dist/src/tools/team-msg.js.map +1 -1
  162. package/dist/src/tools/team-tasks-mcp.d.ts +27 -0
  163. package/dist/src/tools/team-tasks-mcp.d.ts.map +1 -0
  164. package/dist/src/tools/team-tasks-mcp.js +408 -0
  165. package/dist/src/tools/team-tasks-mcp.js.map +1 -0
  166. package/package.json +2 -1
  167. package/workflows/analyze.md +816 -816
  168. package/workflows/brainstorm.md +471 -471
  169. package/workflows/codebase-rebuild.md +332 -332
  170. package/workflows/codebase-refresh.md +240 -240
  171. package/workflows/execute.md +1 -1
  172. package/workflows/harvest.md +420 -420
  173. package/workflows/integration-test.md +343 -343
  174. package/workflows/issue-discover.md +414 -414
  175. package/workflows/map.md +111 -111
  176. package/workflows/milestone-complete.md +176 -176
  177. package/workflows/plan.md +1 -1
  178. package/workflows/quick.md +497 -497
  179. package/workflows/refactor.md +300 -300
  180. package/workflows/roadmap.md +335 -335
  181. package/workflows/spec-generate.md +640 -640
  182. package/workflows/specs-add.md +46 -81
  183. package/workflows/specs-load.md +15 -17
  184. package/workflows/specs-setup.md +40 -161
@@ -0,0 +1,66 @@
1
+ /**
2
+ * Spec Validator Guard — PreToolUse: Write|Edit
3
+ *
4
+ * Validates that spec file entries use the <spec-entry> closed-tag format.
5
+ * Pure evaluation function — no I/O, follows workflow-guard.ts pattern.
6
+ *
7
+ * Only activates when the file path targets .workflow/specs/.
8
+ */
9
+ import { parseSpecEntries, validateCategoryMatch } from '../../tools/spec-entry-parser.js';
10
+ import { CATEGORY_MAP } from '../../tools/spec-loader.js';
11
+ import { basename } from 'node:path';
12
+ // ============================================================================
13
+ // Public API
14
+ // ============================================================================
15
+ /**
16
+ * Evaluate spec file content for format compliance.
17
+ *
18
+ * @param filePath Absolute or relative file path being written
19
+ * @param content The full file content after the write/edit
20
+ * @param mode 'warn' (advisory) or 'block' (reject write)
21
+ */
22
+ export function evaluateSpecValidator(filePath, content, mode = 'warn') {
23
+ // Only validate files in .workflow/specs/
24
+ if (!isSpecFile(filePath)) {
25
+ return { valid: true, mode, errors: [] };
26
+ }
27
+ const errors = [];
28
+ // Determine expected category from filename
29
+ const fileName = basename(filePath);
30
+ const expectedCategory = CATEGORY_MAP[fileName];
31
+ // Parse entries
32
+ const result = parseSpecEntries(content);
33
+ // Collect parser-level errors
34
+ errors.push(...result.errors);
35
+ // Validate category match per entry
36
+ if (expectedCategory) {
37
+ for (const entry of result.entries) {
38
+ const mismatch = validateCategoryMatch(entry, expectedCategory);
39
+ if (mismatch) {
40
+ errors.push({ line: entry.lineStart, message: mismatch });
41
+ }
42
+ }
43
+ }
44
+ // Check for unclosed tags
45
+ const openCount = (content.match(/<spec-entry\b/g) || []).length;
46
+ const closeCount = (content.match(/<\/spec-entry>/g) || []).length;
47
+ if (openCount !== closeCount) {
48
+ errors.push({
49
+ line: 1,
50
+ message: `Unbalanced tags: ${openCount} opening <spec-entry> vs ${closeCount} closing </spec-entry>`,
51
+ });
52
+ }
53
+ return {
54
+ valid: errors.length === 0,
55
+ mode,
56
+ errors,
57
+ };
58
+ }
59
+ // ============================================================================
60
+ // Internal
61
+ // ============================================================================
62
+ function isSpecFile(filePath) {
63
+ const normalized = filePath.replace(/\\/g, '/');
64
+ return normalized.includes('.workflow/specs/') && normalized.endsWith('.md');
65
+ }
66
+ //# sourceMappingURL=spec-validator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spec-validator.js","sourceRoot":"","sources":["../../../../src/hooks/guards/spec-validator.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,gBAAgB,EAAqB,qBAAqB,EAAoB,MAAM,kCAAkC,CAAC;AAChI,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAC1D,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAYrC,+EAA+E;AAC/E,aAAa;AACb,+EAA+E;AAE/E;;;;;;GAMG;AACH,MAAM,UAAU,qBAAqB,CACnC,QAAgB,EAChB,OAAe,EACf,OAAyB,MAAM;IAE/B,0CAA0C;IAC1C,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC1B,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;IAC3C,CAAC;IAED,MAAM,MAAM,GAA6C,EAAE,CAAC;IAE5D,4CAA4C;IAC5C,MAAM,QAAQ,GAAG,QAAQ,CAAC,QAAQ,CAAC,CAAC;IACpC,MAAM,gBAAgB,GAAG,YAAY,CAAC,QAAQ,CAAC,CAAC;IAEhD,gBAAgB;IAChB,MAAM,MAAM,GAAG,gBAAgB,CAAC,OAAO,CAAC,CAAC;IAEzC,8BAA8B;IAC9B,MAAM,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC;IAE9B,oCAAoC;IACpC,IAAI,gBAAgB,EAAE,CAAC;QACrB,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;YACnC,MAAM,QAAQ,GAAG,qBAAqB,CAAC,KAAK,EAAE,gBAAgB,CAAC,CAAC;YAChE,IAAI,QAAQ,EAAE,CAAC;gBACb,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,SAAS,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC,CAAC;YAC5D,CAAC;QACH,CAAC;IACH,CAAC;IAED,0BAA0B;IAC1B,MAAM,SAAS,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,gBAAgB,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC;IACjE,MAAM,UAAU,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,iBAAiB,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC;IACnE,IAAI,SAAS,KAAK,UAAU,EAAE,CAAC;QAC7B,MAAM,CAAC,IAAI,CAAC;YACV,IAAI,EAAE,CAAC;YACP,OAAO,EAAE,oBAAoB,SAAS,4BAA4B,UAAU,wBAAwB;SACrG,CAAC,CAAC;IACL,CAAC;IAED,OAAO;QACL,KAAK,EAAE,MAAM,CAAC,MAAM,KAAK,CAAC;QAC1B,IAAI;QACJ,MAAM;KACP,CAAC;AACJ,CAAC;AAED,+EAA+E;AAC/E,WAAW;AACX,+EAA+E;AAE/E,SAAS,UAAU,CAAC,QAAgB;IAClC,MAAM,UAAU,GAAG,QAAQ,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;IAChD,OAAO,UAAU,CAAC,QAAQ,CAAC,kBAAkB,CAAC,IAAI,UAAU,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;AAC/E,CAAC"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Keyword Spec Injector — UserPromptSubmit hook
3
+ *
4
+ * Scans user prompt for keywords, matches against <spec-entry> keyword attributes,
5
+ * injects matching entries as additionalContext. Session dedup prevents re-injection.
6
+ */
7
+ export interface KeywordInjectionResult {
8
+ inject: boolean;
9
+ content?: string;
10
+ matchedKeywords?: string[];
11
+ matchedEntries?: number;
12
+ }
13
+ /**
14
+ * Evaluate whether to inject keyword-matched spec entries for a user prompt.
15
+ *
16
+ * @param prompt The user's prompt text
17
+ * @param projectPath Working directory for spec file resolution
18
+ * @param sessionId Session ID for dedup bridge
19
+ */
20
+ export declare function evaluateKeywordInjection(prompt: string, projectPath: string, sessionId: string): KeywordInjectionResult;
21
+ //# sourceMappingURL=keyword-spec-injector.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"keyword-spec-injector.d.ts","sourceRoot":"","sources":["../../../src/hooks/keyword-spec-injector.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AASH,MAAM,WAAW,sBAAsB;IACrC,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;IAC3B,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AA+BD;;;;;;GAMG;AACH,wBAAgB,wBAAwB,CACtC,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,MAAM,GAChB,sBAAsB,CAqCxB"}
@@ -0,0 +1,96 @@
1
+ /**
2
+ * Keyword Spec Injector — UserPromptSubmit hook
3
+ *
4
+ * Scans user prompt for keywords, matches against <spec-entry> keyword attributes,
5
+ * injects matching entries as additionalContext. Session dedup prevents re-injection.
6
+ */
7
+ import { buildKeywordIndex, lookupKeywords } from '../tools/spec-keyword-index.js';
8
+ import { markInjected, filterUnjected } from './spec-bridge.js';
9
+ // ============================================================================
10
+ // Config
11
+ // ============================================================================
12
+ const MIN_KEYWORD_LENGTH = 3;
13
+ /** Common words to skip when tokenizing prompt */
14
+ const STOP_WORDS = new Set([
15
+ 'the', 'and', 'for', 'are', 'but', 'not', 'you', 'all', 'can', 'had',
16
+ 'her', 'was', 'one', 'our', 'out', 'has', 'his', 'how', 'its', 'may',
17
+ 'new', 'now', 'old', 'see', 'way', 'who', 'did', 'get', 'let', 'say',
18
+ 'she', 'too', 'use', 'this', 'that', 'with', 'have', 'from', 'they',
19
+ 'been', 'said', 'each', 'make', 'like', 'just', 'over', 'such', 'take',
20
+ 'than', 'them', 'very', 'when', 'what', 'some', 'time', 'will', 'into',
21
+ 'look', 'only', 'come', 'also', 'back', 'after', 'work', 'first', 'well',
22
+ 'then', 'year', 'your', 'them', 'would', 'there', 'their', 'which',
23
+ 'about', 'could', 'other', 'these', 'think', 'should', 'please',
24
+ // code-related common words to skip
25
+ 'file', 'code', 'function', 'class', 'import', 'export', 'const', 'return',
26
+ 'true', 'false', 'null', 'undefined', 'string', 'number', 'type', 'interface',
27
+ ]);
28
+ /** Max entries to inject per prompt to avoid context bloat */
29
+ const MAX_ENTRIES_PER_INJECTION = 5;
30
+ // ============================================================================
31
+ // Public API
32
+ // ============================================================================
33
+ /**
34
+ * Evaluate whether to inject keyword-matched spec entries for a user prompt.
35
+ *
36
+ * @param prompt The user's prompt text
37
+ * @param projectPath Working directory for spec file resolution
38
+ * @param sessionId Session ID for dedup bridge
39
+ */
40
+ export function evaluateKeywordInjection(prompt, projectPath, sessionId) {
41
+ // 1. Tokenize prompt into candidate keywords
42
+ const promptKeywords = tokenizePrompt(prompt);
43
+ if (promptKeywords.length === 0)
44
+ return { inject: false };
45
+ // 2. Build keyword index from spec files
46
+ const index = buildKeywordIndex(projectPath);
47
+ if (index.size === 0)
48
+ return { inject: false };
49
+ // 3. Look up matching entries
50
+ const matchedAll = lookupKeywords(index, promptKeywords);
51
+ if (matchedAll.length === 0)
52
+ return { inject: false };
53
+ // 4. Filter out already-injected entries (session dedup)
54
+ const unjected = filterUnjected(sessionId, matchedAll);
55
+ if (unjected.length === 0)
56
+ return { inject: false };
57
+ // 5. Limit to avoid context bloat
58
+ const toInject = unjected.slice(0, MAX_ENTRIES_PER_INJECTION);
59
+ // 6. Build injection content
60
+ const content = formatInjectionContent(toInject);
61
+ // 7. Mark as injected
62
+ const injectedKeywords = [...new Set(toInject.flatMap(e => e.keywords))];
63
+ const injectedIds = toInject.map(e => e.id);
64
+ markInjected(sessionId, injectedKeywords, injectedIds);
65
+ // 8. Determine which prompt keywords actually matched
66
+ const matchedKws = promptKeywords.filter(kw => index.has(kw));
67
+ return {
68
+ inject: true,
69
+ content,
70
+ matchedKeywords: matchedKws,
71
+ matchedEntries: toInject.length,
72
+ };
73
+ }
74
+ // ============================================================================
75
+ // Internal
76
+ // ============================================================================
77
+ /**
78
+ * Tokenize prompt into candidate keywords for index lookup.
79
+ * Lowercase, deduplicate, filter by length and stop words.
80
+ */
81
+ function tokenizePrompt(prompt) {
82
+ const words = prompt
83
+ .toLowerCase()
84
+ .replace(/[^a-z0-9\u4e00-\u9fff_-]/g, ' ')
85
+ .split(/\s+/)
86
+ .filter(w => w.length >= MIN_KEYWORD_LENGTH && !STOP_WORDS.has(w));
87
+ return [...new Set(words)];
88
+ }
89
+ /**
90
+ * Format matched entries for injection as context.
91
+ */
92
+ function formatInjectionContent(entries) {
93
+ const sections = entries.map(e => `--- ${e.file} (${e.category}) [${e.keywords.join(', ')}] ---\n\n${e.content}`);
94
+ return `<spec-keyword-match count="${entries.length}">\n\n${sections.join('\n\n---\n\n')}\n\n</spec-keyword-match>`;
95
+ }
96
+ //# sourceMappingURL=keyword-spec-injector.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"keyword-spec-injector.js","sourceRoot":"","sources":["../../../src/hooks/keyword-spec-injector.ts"],"names":[],"mappings":"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"}
@@ -9,8 +9,9 @@ import type { WorkflowHookRegistry } from '../workflow-hooks.js';
9
9
  */
10
10
  export declare class SpecInjectionPlugin implements MaestroPlugin {
11
11
  private readonly projectPath;
12
+ private readonly sessionId;
12
13
  readonly name = "specInjection";
13
- constructor(projectPath?: string);
14
+ constructor(projectPath?: string, sessionId?: string);
14
15
  apply(registry: WorkflowHookRegistry): void;
15
16
  }
16
17
  //# sourceMappingURL=spec-injection-plugin.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"spec-injection-plugin.d.ts","sourceRoot":"","sources":["../../../../src/hooks/plugins/spec-injection-plugin.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAIjE;;;;;;GAMG;AACH,qBAAa,mBAAoB,YAAW,aAAa;IAG3C,OAAO,CAAC,QAAQ,CAAC,WAAW;IAFxC,QAAQ,CAAC,IAAI,mBAAmB;gBAEH,WAAW,GAAE,MAAsB;IAEhE,KAAK,CAAC,QAAQ,EAAE,oBAAoB,GAAG,IAAI;CAc5C"}
1
+ {"version":3,"file":"spec-injection-plugin.d.ts","sourceRoot":"","sources":["../../../../src/hooks/plugins/spec-injection-plugin.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAKjE;;;;;;GAMG;AACH,qBAAa,mBAAoB,YAAW,aAAa;IAIrD,OAAO,CAAC,QAAQ,CAAC,WAAW;IAC5B,OAAO,CAAC,QAAQ,CAAC,SAAS;IAJ5B,QAAQ,CAAC,IAAI,mBAAmB;gBAGb,WAAW,GAAE,MAAsB,EACnC,SAAS,GAAE,MAAW;IAGzC,KAAK,CAAC,QAAQ,EAAE,oBAAoB,GAAG,IAAI;CAuB5C"}
@@ -3,6 +3,7 @@
3
3
  // ---------------------------------------------------------------------------
4
4
  import { loadSpecs } from '../../tools/spec-loader.js';
5
5
  import { resolveSelf } from '../../tools/team-members.js';
6
+ import { evaluateKeywordInjection } from '../keyword-spec-injector.js';
6
7
  /**
7
8
  * In-process plugin for `maestro coordinate` — injects relevant specs
8
9
  * into the prompt via the `transformPrompt` waterfall hook.
@@ -12,20 +13,30 @@ import { resolveSelf } from '../../tools/team-members.js';
12
13
  */
13
14
  export class SpecInjectionPlugin {
14
15
  projectPath;
16
+ sessionId;
15
17
  name = 'specInjection';
16
- constructor(projectPath = process.cwd()) {
18
+ constructor(projectPath = process.cwd(), sessionId = '') {
17
19
  this.projectPath = projectPath;
20
+ this.sessionId = sessionId;
18
21
  }
19
22
  apply(registry) {
20
23
  registry.transformPrompt.tap(this.name, (prompt) => {
21
- // Infer category from prompt content heuristics
24
+ const parts = [prompt];
25
+ // Category-based injection
22
26
  const category = inferCategory(prompt);
23
- // Best-effort uid resolution for personal spec layer
24
27
  const uid = resolveUidSafe();
25
- const result = loadSpecs(this.projectPath, category, uid);
26
- if (!result.content)
27
- return prompt;
28
- return `${prompt}\n\n---\n\n${result.content}`;
28
+ const catResult = loadSpecs(this.projectPath, category, uid);
29
+ if (catResult.content) {
30
+ parts.push(catResult.content);
31
+ }
32
+ // Keyword-based injection (with session dedup)
33
+ if (this.sessionId) {
34
+ const kwResult = evaluateKeywordInjection(prompt, this.projectPath, this.sessionId);
35
+ if (kwResult.inject && kwResult.content) {
36
+ parts.push(kwResult.content);
37
+ }
38
+ }
39
+ return parts.length > 1 ? parts.join('\n\n---\n\n') : prompt;
29
40
  });
30
41
  }
31
42
  }
@@ -55,10 +66,8 @@ function inferCategory(prompt) {
55
66
  return 'test';
56
67
  if (/\b(debug|diagnose|fix|error|bug)\b/.test(lower))
57
68
  return 'debug';
58
- if (/\b(plan|design|architect|decompose)\b/.test(lower))
59
- return 'planning';
60
- if (/\b(explore|discover|search|analyze)\b/.test(lower))
61
- return 'exploration';
62
- return 'execution'; // Default for implementation work
69
+ if (/\b(plan|design|architect|decompose|explore|discover|search|analyze)\b/.test(lower))
70
+ return 'arch';
71
+ return 'coding'; // Default for implementation work
63
72
  }
64
73
  //# sourceMappingURL=spec-injection-plugin.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"spec-injection-plugin.js","sourceRoot":"","sources":["../../../../src/hooks/plugins/spec-injection-plugin.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,uEAAuE;AACvE,8EAA8E;AAI9E,OAAO,EAAE,SAAS,EAAqB,MAAM,4BAA4B,CAAC;AAC1E,OAAO,EAAE,WAAW,EAAE,MAAM,6BAA6B,CAAC;AAE1D;;;;;;GAMG;AACH,MAAM,OAAO,mBAAmB;IAGD;IAFpB,IAAI,GAAG,eAAe,CAAC;IAEhC,YAA6B,cAAsB,OAAO,CAAC,GAAG,EAAE;QAAnC,gBAAW,GAAX,WAAW,CAAwB;IAAG,CAAC;IAEpE,KAAK,CAAC,QAA8B;QAClC,QAAQ,CAAC,eAAe,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,MAAc,EAAE,EAAE;YACzD,gDAAgD;YAChD,MAAM,QAAQ,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC;YAEvC,qDAAqD;YACrD,MAAM,GAAG,GAAG,cAAc,EAAE,CAAC;YAC7B,MAAM,MAAM,GAAG,SAAS,CAAC,IAAI,CAAC,WAAW,EAAE,QAAQ,EAAE,GAAG,CAAC,CAAC;YAE1D,IAAI,CAAC,MAAM,CAAC,OAAO;gBAAE,OAAO,MAAM,CAAC;YAEnC,OAAO,GAAG,MAAM,cAAc,MAAM,CAAC,OAAO,EAAE,CAAC;QACjD,CAAC,CAAC,CAAC;IACL,CAAC;CACF;AAED;;;GAGG;AACH,SAAS,cAAc;IACrB,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,WAAW,EAAE,CAAC;QAC3B,OAAO,IAAI,EAAE,GAAG,IAAI,SAAS,CAAC;IAChC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAC;IACnB,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,SAAS,aAAa,CAAC,MAAc;IACnC,MAAM,KAAK,GAAG,MAAM,CAAC,WAAW,EAAE,CAAC;IACnC,IAAI,kCAAkC,CAAC,IAAI,CAAC,KAAK,CAAC;QAAE,OAAO,QAAQ,CAAC;IACpE,IAAI,iCAAiC,CAAC,IAAI,CAAC,KAAK,CAAC;QAAE,OAAO,MAAM,CAAC;IACjE,IAAI,oCAAoC,CAAC,IAAI,CAAC,KAAK,CAAC;QAAE,OAAO,OAAO,CAAC;IACrE,IAAI,uCAAuC,CAAC,IAAI,CAAC,KAAK,CAAC;QAAE,OAAO,UAAU,CAAC;IAC3E,IAAI,uCAAuC,CAAC,IAAI,CAAC,KAAK,CAAC;QAAE,OAAO,aAAa,CAAC;IAC9E,OAAO,WAAW,CAAC,CAAC,kCAAkC;AACxD,CAAC"}
1
+ {"version":3,"file":"spec-injection-plugin.js","sourceRoot":"","sources":["../../../../src/hooks/plugins/spec-injection-plugin.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,uEAAuE;AACvE,8EAA8E;AAI9E,OAAO,EAAE,SAAS,EAAqB,MAAM,4BAA4B,CAAC;AAC1E,OAAO,EAAE,WAAW,EAAE,MAAM,6BAA6B,CAAC;AAC1D,OAAO,EAAE,wBAAwB,EAAE,MAAM,6BAA6B,CAAC;AAEvE;;;;;;GAMG;AACH,MAAM,OAAO,mBAAmB;IAIX;IACA;IAJV,IAAI,GAAG,eAAe,CAAC;IAEhC,YACmB,cAAsB,OAAO,CAAC,GAAG,EAAE,EACnC,YAAoB,EAAE;QADtB,gBAAW,GAAX,WAAW,CAAwB;QACnC,cAAS,GAAT,SAAS,CAAa;IACtC,CAAC;IAEJ,KAAK,CAAC,QAA8B;QAClC,QAAQ,CAAC,eAAe,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,MAAc,EAAE,EAAE;YACzD,MAAM,KAAK,GAAa,CAAC,MAAM,CAAC,CAAC;YAEjC,2BAA2B;YAC3B,MAAM,QAAQ,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC;YACvC,MAAM,GAAG,GAAG,cAAc,EAAE,CAAC;YAC7B,MAAM,SAAS,GAAG,SAAS,CAAC,IAAI,CAAC,WAAW,EAAE,QAAQ,EAAE,GAAG,CAAC,CAAC;YAC7D,IAAI,SAAS,CAAC,OAAO,EAAE,CAAC;gBACtB,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;YAChC,CAAC;YAED,+CAA+C;YAC/C,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;gBACnB,MAAM,QAAQ,GAAG,wBAAwB,CAAC,MAAM,EAAE,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC;gBACpF,IAAI,QAAQ,CAAC,MAAM,IAAI,QAAQ,CAAC,OAAO,EAAE,CAAC;oBACxC,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;gBAC/B,CAAC;YACH,CAAC;YAED,OAAO,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;QAC/D,CAAC,CAAC,CAAC;IACL,CAAC;CACF;AAED;;;GAGG;AACH,SAAS,cAAc;IACrB,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,WAAW,EAAE,CAAC;QAC3B,OAAO,IAAI,EAAE,GAAG,IAAI,SAAS,CAAC;IAChC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAC;IACnB,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,SAAS,aAAa,CAAC,MAAc;IACnC,MAAM,KAAK,GAAG,MAAM,CAAC,WAAW,EAAE,CAAC;IACnC,IAAI,kCAAkC,CAAC,IAAI,CAAC,KAAK,CAAC;QAAE,OAAO,QAAQ,CAAC;IACpE,IAAI,iCAAiC,CAAC,IAAI,CAAC,KAAK,CAAC;QAAE,OAAO,MAAM,CAAC;IACjE,IAAI,oCAAoC,CAAC,IAAI,CAAC,KAAK,CAAC;QAAE,OAAO,OAAO,CAAC;IACrE,IAAI,uEAAuE,CAAC,IAAI,CAAC,KAAK,CAAC;QAAE,OAAO,MAAM,CAAC;IACvG,OAAO,QAAQ,CAAC,CAAC,kCAAkC;AACrD,CAAC"}
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Spec Keyword Bridge — Session-based dedup for keyword-triggered spec injection.
3
+ *
4
+ * Tracks which keywords and entries have already been injected in the current session
5
+ * to prevent duplicate injection when the same keyword appears in multiple prompts.
6
+ *
7
+ * Bridge file: {tmpdir}/maestro-spec-kw-{sessionId}.json
8
+ */
9
+ export interface SpecKeywordBridge {
10
+ session_id: string;
11
+ injected_keywords: string[];
12
+ injected_entries: string[];
13
+ updated_at: number;
14
+ }
15
+ /**
16
+ * Read the spec keyword bridge file for a session.
17
+ * Returns null if the file does not exist or is unreadable.
18
+ */
19
+ export declare function readSpecBridge(sessionId: string): SpecKeywordBridge | null;
20
+ /**
21
+ * Mark keywords and entry IDs as injected for this session.
22
+ * Merges with existing bridge data (additive, never removes).
23
+ */
24
+ export declare function markInjected(sessionId: string, keywords: string[], entryIds: string[]): void;
25
+ /**
26
+ * Check if a keyword has already been injected this session.
27
+ */
28
+ export declare function isKeywordInjected(sessionId: string, keyword: string): boolean;
29
+ /**
30
+ * Check if an entry has already been injected this session.
31
+ */
32
+ export declare function isEntryInjected(sessionId: string, entryId: string): boolean;
33
+ /**
34
+ * Filter entries to only those not yet injected in this session.
35
+ * An entry is considered "already injected" if its ID is in the bridge.
36
+ */
37
+ export declare function filterUnjected<T extends {
38
+ id: string;
39
+ }>(sessionId: string, entries: T[]): T[];
40
+ //# sourceMappingURL=spec-bridge.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spec-bridge.d.ts","sourceRoot":"","sources":["../../../src/hooks/spec-bridge.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAWH,MAAM,WAAW,iBAAiB;IAChC,UAAU,EAAE,MAAM,CAAC;IACnB,iBAAiB,EAAE,MAAM,EAAE,CAAC;IAC5B,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,UAAU,EAAE,MAAM,CAAC;CACpB;AAMD;;;GAGG;AACH,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,iBAAiB,GAAG,IAAI,CAU1E;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAC1B,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,MAAM,EAAE,EAClB,QAAQ,EAAE,MAAM,EAAE,GACjB,IAAI,CA0BN;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAI7E;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAI3E;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,CAAC,SAAS;IAAE,EAAE,EAAE,MAAM,CAAA;CAAE,EACrD,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,CAAC,EAAE,GACX,CAAC,EAAE,CAML"}
@@ -0,0 +1,97 @@
1
+ /**
2
+ * Spec Keyword Bridge — Session-based dedup for keyword-triggered spec injection.
3
+ *
4
+ * Tracks which keywords and entries have already been injected in the current session
5
+ * to prevent duplicate injection when the same keyword appears in multiple prompts.
6
+ *
7
+ * Bridge file: {tmpdir}/maestro-spec-kw-{sessionId}.json
8
+ */
9
+ import { readFileSync, writeFileSync, existsSync } from 'node:fs';
10
+ import { join } from 'node:path';
11
+ import { tmpdir } from 'node:os';
12
+ import { SPEC_KW_BRIDGE_PREFIX } from './constants.js';
13
+ // ============================================================================
14
+ // Public API
15
+ // ============================================================================
16
+ /**
17
+ * Read the spec keyword bridge file for a session.
18
+ * Returns null if the file does not exist or is unreadable.
19
+ */
20
+ export function readSpecBridge(sessionId) {
21
+ const path = bridgePath(sessionId);
22
+ if (!existsSync(path))
23
+ return null;
24
+ try {
25
+ const raw = readFileSync(path, 'utf-8');
26
+ return JSON.parse(raw);
27
+ }
28
+ catch {
29
+ return null;
30
+ }
31
+ }
32
+ /**
33
+ * Mark keywords and entry IDs as injected for this session.
34
+ * Merges with existing bridge data (additive, never removes).
35
+ */
36
+ export function markInjected(sessionId, keywords, entryIds) {
37
+ const existing = readSpecBridge(sessionId) ?? {
38
+ session_id: sessionId,
39
+ injected_keywords: [],
40
+ injected_entries: [],
41
+ updated_at: 0,
42
+ };
43
+ const kwSet = new Set(existing.injected_keywords);
44
+ for (const kw of keywords)
45
+ kwSet.add(kw.toLowerCase());
46
+ const entrySet = new Set(existing.injected_entries);
47
+ for (const id of entryIds)
48
+ entrySet.add(id);
49
+ const updated = {
50
+ session_id: sessionId,
51
+ injected_keywords: [...kwSet],
52
+ injected_entries: [...entrySet],
53
+ updated_at: Math.floor(Date.now() / 1000),
54
+ };
55
+ try {
56
+ writeFileSync(bridgePath(sessionId), JSON.stringify(updated), 'utf-8');
57
+ }
58
+ catch {
59
+ // Best-effort — don't fail the hook if bridge write fails
60
+ }
61
+ }
62
+ /**
63
+ * Check if a keyword has already been injected this session.
64
+ */
65
+ export function isKeywordInjected(sessionId, keyword) {
66
+ const bridge = readSpecBridge(sessionId);
67
+ if (!bridge)
68
+ return false;
69
+ return bridge.injected_keywords.includes(keyword.toLowerCase());
70
+ }
71
+ /**
72
+ * Check if an entry has already been injected this session.
73
+ */
74
+ export function isEntryInjected(sessionId, entryId) {
75
+ const bridge = readSpecBridge(sessionId);
76
+ if (!bridge)
77
+ return false;
78
+ return bridge.injected_entries.includes(entryId);
79
+ }
80
+ /**
81
+ * Filter entries to only those not yet injected in this session.
82
+ * An entry is considered "already injected" if its ID is in the bridge.
83
+ */
84
+ export function filterUnjected(sessionId, entries) {
85
+ const bridge = readSpecBridge(sessionId);
86
+ if (!bridge)
87
+ return entries;
88
+ const injectedSet = new Set(bridge.injected_entries);
89
+ return entries.filter(e => !injectedSet.has(e.id));
90
+ }
91
+ // ============================================================================
92
+ // Internal
93
+ // ============================================================================
94
+ function bridgePath(sessionId) {
95
+ return join(tmpdir(), `${SPEC_KW_BRIDGE_PREFIX}${sessionId}.json`);
96
+ }
97
+ //# sourceMappingURL=spec-bridge.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spec-bridge.js","sourceRoot":"","sources":["../../../src/hooks/spec-bridge.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"spec-injector.d.ts","sourceRoot":"","sources":["../../../src/hooks/spec-injector.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAa,KAAK,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAGvE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAM7D,MAAM,WAAW,iBAAiB;IAChC,UAAU,EAAE,YAAY,EAAE,CAAC;IAC3B,qDAAqD;IACrD,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAED,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAkCD;;;;;;;;GAQG;AACH,wBAAgB,qBAAqB,CACnC,SAAS,EAAE,MAAM,EACjB,WAAW,EAAE,MAAM,EACnB,SAAS,CAAC,EAAE,MAAM,EAClB,MAAM,CAAC,EAAE,mBAAmB,EAC5B,GAAG,CAAC,EAAE,MAAM,GACX,mBAAmB,CA0CrB"}
1
+ {"version":3,"file":"spec-injector.d.ts","sourceRoot":"","sources":["../../../src/hooks/spec-injector.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAa,KAAK,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAIvE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAM7D,MAAM,WAAW,iBAAiB;IAChC,UAAU,EAAE,YAAY,EAAE,CAAC;IAC3B,qDAAqD;IACrD,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAED,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AA+BD;;;;;;;;GAQG;AACH,wBAAgB,qBAAqB,CACnC,SAAS,EAAE,MAAM,EACjB,WAAW,EAAE,MAAM,EACnB,SAAS,CAAC,EAAE,MAAM,EAClB,MAAM,CAAC,EAAE,mBAAmB,EAC5B,GAAG,CAAC,EAAE,MAAM,GACX,mBAAmB,CAmDrB"}
@@ -15,23 +15,21 @@ import { resolveSelf } from '../tools/team-members.js';
15
15
  // Default agent-type → spec-category mapping
16
16
  // ---------------------------------------------------------------------------
17
17
  const DEFAULT_AGENT_SPEC_MAP = {
18
- // Execution agents → execution specs
19
- 'code-developer': { categories: ['execution'], extras: [] },
20
- 'tdd-developer': { categories: ['execution', 'test'], extras: [] },
21
- 'workflow-executor': { categories: ['execution'], extras: [] },
22
- 'universal-executor': { categories: ['execution'], extras: [] },
23
- 'test-fix-agent': { categories: ['execution', 'test'], extras: [] },
24
- // Planning agents → planning specs
25
- 'cli-lite-planning-agent': { categories: ['planning'], extras: [] },
26
- 'action-planning-agent': { categories: ['planning'], extras: [] },
27
- 'workflow-planner': { categories: ['planning'], extras: [] },
18
+ // Execution agents → coding specs
19
+ 'code-developer': { categories: ['coding'], extras: [] },
20
+ 'tdd-developer': { categories: ['coding', 'test'], extras: [] },
21
+ 'workflow-executor': { categories: ['coding'], extras: [] },
22
+ 'universal-executor': { categories: ['coding'], extras: [] },
23
+ 'test-fix-agent': { categories: ['coding', 'test'], extras: [] },
24
+ // Planning agents → arch specs
25
+ 'cli-lite-planning-agent': { categories: ['arch'], extras: [] },
26
+ 'action-planning-agent': { categories: ['arch'], extras: [] },
27
+ 'workflow-planner': { categories: ['arch'], extras: [] },
28
28
  // Review agents → review specs
29
29
  'workflow-reviewer': { categories: ['review'], extras: [] },
30
30
  // Debug agents → debug specs
31
31
  'debug-explore-agent': { categories: ['debug'], extras: [] },
32
32
  'workflow-debugger': { categories: ['debug'], extras: [] },
33
- // Explore agents → exploration (lightweight)
34
- 'Explore': { categories: ['exploration'], extras: [] },
35
33
  };
36
34
  // ---------------------------------------------------------------------------
37
35
  // Public API
@@ -65,6 +63,14 @@ export function evaluateSpecInjection(agentType, projectPath, sessionId, config,
65
63
  totalCount += result.totalLoaded;
66
64
  }
67
65
  }
66
+ if (sections.length === 0 && !sessionId)
67
+ return { inject: false };
68
+ // Keyword-based injection from agent prompt (if sessionId available)
69
+ if (sessionId && projectPath) {
70
+ // Extract prompt from the original function context — the caller should pass it
71
+ // For now, keyword injection from agent prompts is handled at the hook runner level
72
+ // via evaluateKeywordInjection(), not here. This keeps the two concerns separate.
73
+ }
68
74
  if (sections.length === 0)
69
75
  return { inject: false };
70
76
  const rawContent = sections.join('\n\n---\n\n');
@@ -1 +1 @@
1
- {"version":3,"file":"spec-injector.js","sourceRoot":"","sources":["../../../src/hooks/spec-injector.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"spec-injector.js","sourceRoot":"","sources":["../../../src/hooks/spec-injector.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Phase Orchestrator - Structured team phase management.
3
+ *
4
+ * Manages phase transitions with guard evaluation, fix retry counting,
5
+ * state broadcast via team-msg, and transition persistence.
6
+ */
7
+ import { TeamPhase, type PhaseGateConfig, type PhaseStatus } from './phase-types.js';
8
+ export interface TransitionResult {
9
+ success: boolean;
10
+ from: TeamPhase;
11
+ to: TeamPhase;
12
+ /** Non-empty when success=false, explains why the transition was rejected */
13
+ reason?: string;
14
+ /** Gate evaluation reasons (populated even on success if gates were soft-blocked and forced) */
15
+ gateReasons: string[];
16
+ }
17
+ export declare class PhaseOrchestrator {
18
+ private readonly sessionId;
19
+ private _currentPhase;
20
+ private _fixAttempts;
21
+ private readonly _history;
22
+ constructor(sessionId: string);
23
+ /** Current phase of the team workflow */
24
+ get currentPhase(): TeamPhase;
25
+ /** Number of fix attempts in the current fix loop */
26
+ get fixAttempts(): number;
27
+ /**
28
+ * Attempt to transition to `targetPhase`.
29
+ *
30
+ * Steps:
31
+ * 1. Validate the transition exists in TRANSITIONS map
32
+ * 2. Check fix retry limit for fix->review transitions
33
+ * 3. Evaluate phase-gate guard (if gateConfig provided)
34
+ * 4. Apply the transition, update counters, record history
35
+ * 5. Broadcast state_update via team-msg opLog
36
+ * 6. Persist transition to transitions.jsonl
37
+ */
38
+ transitionTo(targetPhase: TeamPhase, options?: {
39
+ trigger?: string;
40
+ force?: boolean;
41
+ gateConfig?: PhaseGateConfig;
42
+ /** Callback to broadcast via team-msg (decoupled from direct import) */
43
+ broadcast?: (sessionId: string, phase: TeamPhase, fixAttempts: number) => void;
44
+ }): TransitionResult;
45
+ getPhaseStatus(): PhaseStatus;
46
+ private applyTransition;
47
+ /**
48
+ * Append transition record to .workflow/.team/{session}/transitions.jsonl
49
+ */
50
+ private persistTransition;
51
+ }
52
+ //# sourceMappingURL=phase-orchestrator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"phase-orchestrator.d.ts","sourceRoot":"","sources":["../../../src/team/phase-orchestrator.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAOH,OAAO,EACL,SAAS,EAET,KAAK,eAAe,EACpB,KAAK,WAAW,EAEjB,MAAM,kBAAkB,CAAC;AAa1B,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE,SAAS,CAAC;IAChB,EAAE,EAAE,SAAS,CAAC;IACd,6EAA6E;IAC7E,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,gGAAgG;IAChG,WAAW,EAAE,MAAM,EAAE,CAAC;CACvB;AAMD,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,aAAa,CAAY;IACjC,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAA0B;gBAEvC,SAAS,EAAE,MAAM;IAO7B,yCAAyC;IACzC,IAAI,YAAY,IAAI,SAAS,CAE5B;IAED,qDAAqD;IACrD,IAAI,WAAW,IAAI,MAAM,CAExB;IAMD;;;;;;;;;;OAUG;IACH,YAAY,CACV,WAAW,EAAE,SAAS,EACtB,OAAO,CAAC,EAAE;QACR,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,KAAK,CAAC,EAAE,OAAO,CAAC;QAChB,UAAU,CAAC,EAAE,eAAe,CAAC;QAC7B,wEAAwE;QACxE,SAAS,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC;KAChF,GACA,gBAAgB;IA8DnB,cAAc,IAAI,WAAW;IAc7B,OAAO,CAAC,eAAe;IAwCvB;;OAEG;IACH,OAAO,CAAC,iBAAiB;CAa1B"}