@bradygaster/squad-sdk 0.8.20 → 0.8.21

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 (105) hide show
  1. package/README.md +296 -296
  2. package/dist/adapter/client.js +1 -1
  3. package/dist/adapter/client.js.map +1 -1
  4. package/dist/agents/charter-compiler.d.ts +4 -0
  5. package/dist/agents/charter-compiler.d.ts.map +1 -1
  6. package/dist/agents/charter-compiler.js +8 -0
  7. package/dist/agents/charter-compiler.js.map +1 -1
  8. package/dist/agents/history-shadow.js +30 -30
  9. package/dist/agents/index.js +1 -1
  10. package/dist/agents/index.js.map +1 -1
  11. package/dist/agents/lifecycle.js +1 -1
  12. package/dist/agents/lifecycle.js.map +1 -1
  13. package/dist/build/github-dist.js +42 -42
  14. package/dist/builders/index.d.ts +156 -0
  15. package/dist/builders/index.d.ts.map +1 -0
  16. package/dist/builders/index.js +404 -0
  17. package/dist/builders/index.js.map +1 -0
  18. package/dist/builders/types.d.ts +187 -0
  19. package/dist/builders/types.d.ts.map +1 -0
  20. package/dist/builders/types.js +12 -0
  21. package/dist/builders/types.js.map +1 -0
  22. package/dist/config/init.d.ts +5 -21
  23. package/dist/config/init.d.ts.map +1 -1
  24. package/dist/config/init.js +270 -182
  25. package/dist/config/init.js.map +1 -1
  26. package/dist/coordinator/coordinator.js +1 -1
  27. package/dist/coordinator/coordinator.js.map +1 -1
  28. package/dist/coordinator/index.js +1 -1
  29. package/dist/coordinator/index.js.map +1 -1
  30. package/dist/index.d.ts +3 -0
  31. package/dist/index.d.ts.map +1 -1
  32. package/dist/index.js +3 -0
  33. package/dist/index.js.map +1 -1
  34. package/dist/runtime/otel-api.d.ts +38 -0
  35. package/dist/runtime/otel-api.d.ts.map +1 -0
  36. package/dist/runtime/otel-api.js +94 -0
  37. package/dist/runtime/otel-api.js.map +1 -0
  38. package/dist/runtime/otel-bridge.js +1 -1
  39. package/dist/runtime/otel-bridge.js.map +1 -1
  40. package/dist/runtime/otel.d.ts +1 -1
  41. package/dist/runtime/otel.d.ts.map +1 -1
  42. package/dist/runtime/otel.js +28 -12
  43. package/dist/runtime/otel.js.map +1 -1
  44. package/dist/runtime/squad-observer.js +1 -1
  45. package/dist/runtime/squad-observer.js.map +1 -1
  46. package/dist/sharing/consult.js +78 -78
  47. package/dist/streams/filter.d.ts +33 -0
  48. package/dist/streams/filter.d.ts.map +1 -0
  49. package/dist/streams/filter.js +29 -0
  50. package/dist/streams/filter.js.map +1 -0
  51. package/dist/streams/index.d.ts +9 -0
  52. package/dist/streams/index.d.ts.map +1 -0
  53. package/dist/streams/index.js +9 -0
  54. package/dist/streams/index.js.map +1 -0
  55. package/dist/streams/resolver.d.ts +40 -0
  56. package/dist/streams/resolver.d.ts.map +1 -0
  57. package/dist/streams/resolver.js +162 -0
  58. package/dist/streams/resolver.js.map +1 -0
  59. package/dist/streams/types.d.ts +44 -0
  60. package/dist/streams/types.d.ts.map +1 -0
  61. package/dist/streams/types.js +10 -0
  62. package/dist/streams/types.js.map +1 -0
  63. package/dist/tools/index.js +1 -1
  64. package/dist/tools/index.js.map +1 -1
  65. package/dist/types.d.ts +20 -0
  66. package/dist/types.d.ts.map +1 -1
  67. package/package.json +12 -11
  68. package/templates/casting-history.json +4 -4
  69. package/templates/casting-policy.json +35 -35
  70. package/templates/casting-registry.json +3 -3
  71. package/templates/ceremonies.md +41 -41
  72. package/templates/charter.md +53 -53
  73. package/templates/constraint-tracking.md +38 -38
  74. package/templates/copilot-instructions.md +46 -46
  75. package/templates/history.md +10 -10
  76. package/templates/identity/now.md +9 -9
  77. package/templates/identity/wisdom.md +15 -15
  78. package/templates/mcp-config.md +98 -98
  79. package/templates/multi-agent-format.md +28 -28
  80. package/templates/orchestration-log.md +27 -27
  81. package/templates/plugin-marketplace.md +49 -49
  82. package/templates/raw-agent-output.md +37 -37
  83. package/templates/roster.md +60 -60
  84. package/templates/routing.md +54 -54
  85. package/templates/run-output.md +50 -50
  86. package/templates/scribe-charter.md +119 -119
  87. package/templates/skill.md +24 -24
  88. package/templates/skills/project-conventions/SKILL.md +56 -56
  89. package/templates/squad.agent.md +1146 -1146
  90. package/templates/workflows/squad-ci.yml +24 -24
  91. package/templates/workflows/squad-docs.yml +50 -50
  92. package/templates/workflows/squad-heartbeat.yml +316 -316
  93. package/templates/workflows/squad-insider-release.yml +61 -61
  94. package/templates/workflows/squad-issue-assign.yml +161 -161
  95. package/templates/workflows/squad-label-enforce.yml +181 -181
  96. package/templates/workflows/squad-preview.yml +55 -55
  97. package/templates/workflows/squad-promote.yml +120 -120
  98. package/templates/workflows/squad-release.yml +77 -77
  99. package/templates/workflows/squad-triage.yml +260 -260
  100. package/templates/workflows/sync-squad-labels.yml +169 -169
  101. package/dist/runtime/event-bus-otel-bridge.d.ts +0 -19
  102. package/dist/runtime/event-bus-otel-bridge.d.ts.map +0 -1
  103. package/dist/runtime/event-bus-otel-bridge.js +0 -61
  104. package/dist/runtime/event-bus-otel-bridge.js.map +0 -1
  105. package/templates/workflows/squad-main-guard.yml +0 -129
@@ -51,22 +51,22 @@ export class ExtractionDisabledError extends Error {
51
51
  * Consult mode preamble to inject after frontmatter in squad.agent.md.
52
52
  * This tells Squad it's in consult mode and should skip Init Mode.
53
53
  */
54
- const CONSULT_MODE_PREAMBLE = `
55
- <!-- consult-mode: true -->
56
-
57
- ## ⚡ Consult Mode Active
58
-
59
- This project is in **consult mode**. Your personal squad has been copied into \`.squad/\` for this session.
60
-
61
- **Key differences from normal mode:**
62
- - **Skip Init Mode** — The team already exists (copied from your personal squad)
63
- - **Isolated changes** — All changes stay local until you run \`squad extract\`
64
- - **Invisible to project** — Both \`.squad/\` and this agent file are in \`.git/info/exclude\`
65
-
66
- **When done:** Run \`squad extract\` to review learnings and merge generic ones back to your personal squad.
67
-
68
- ---
69
-
54
+ const CONSULT_MODE_PREAMBLE = `
55
+ <!-- consult-mode: true -->
56
+
57
+ ## ⚡ Consult Mode Active
58
+
59
+ This project is in **consult mode**. Your personal squad has been copied into \`.squad/\` for this session.
60
+
61
+ **Key differences from normal mode:**
62
+ - **Skip Init Mode** — The team already exists (copied from your personal squad)
63
+ - **Isolated changes** — All changes stay local until you run \`squad extract\`
64
+ - **Invisible to project** — Both \`.squad/\` and this agent file are in \`.git/info/exclude\`
65
+
66
+ **When done:** Run \`squad extract\` to review learnings and merge generic ones back to your personal squad.
67
+
68
+ ---
69
+
70
70
  `;
71
71
  /**
72
72
  * Get the full squad.agent.md template path.
@@ -135,24 +135,24 @@ function getConsultAgentContent(projectName) {
135
135
  return template + '\n' + CONSULT_MODE_PREAMBLE;
136
136
  }
137
137
  // Fallback: minimal agent if template not found
138
- return `---
139
- name: Squad
140
- description: "Your AI team. Consulting on ${projectName} using your personal squad."
141
- ---
142
-
143
- ${CONSULT_MODE_PREAMBLE}
144
-
145
- You are **Squad (Consultant)** — working on **${projectName}** using a copy of your personal squad.
146
-
147
- ### Available Context (local copy in .squad/)
148
-
149
- - **Team:** \`.squad/team.md\` for roster and roles
150
- - **Routing:** \`.squad/routing.md\` for task routing rules
151
- - **Decisions:** \`.squad/decisions.md\` for your established patterns
152
- - **Skills:** \`.squad/skills/\` for reusable capabilities
153
- - **Agents:** \`.squad/agents/\` for your squad agents
154
-
155
- Work as you would with your personal squad, but in this external codebase.
138
+ return `---
139
+ name: Squad
140
+ description: "Your AI team. Consulting on ${projectName} using your personal squad."
141
+ ---
142
+
143
+ ${CONSULT_MODE_PREAMBLE}
144
+
145
+ You are **Squad (Consultant)** — working on **${projectName}** using a copy of your personal squad.
146
+
147
+ ### Available Context (local copy in .squad/)
148
+
149
+ - **Team:** \`.squad/team.md\` for roster and roles
150
+ - **Routing:** \`.squad/routing.md\` for task routing rules
151
+ - **Decisions:** \`.squad/decisions.md\` for your established patterns
152
+ - **Skills:** \`.squad/skills/\` for reusable capabilities
153
+ - **Agents:** \`.squad/agents/\` for your squad agents
154
+
155
+ Work as you would with your personal squad, but in this external codebase.
156
156
  `;
157
157
  }
158
158
  // ============================================================================
@@ -162,36 +162,36 @@ Work as you would with your personal squad, but in this external codebase.
162
162
  * Consult mode instructions to append to Scribe charter.
163
163
  * This enables Scribe to classify decisions as generic or project-specific.
164
164
  */
165
- const CONSULT_MODE_SCRIBE_PATCH = `
166
-
167
- ---
168
-
169
- ## Consult Mode Extraction
170
-
171
- **This squad is in consult mode.** When merging decisions from the inbox, also classify each decision:
172
-
173
- ### Classification
174
-
175
- For each decision in \`.squad/decisions/inbox/\`:
176
-
177
- 1. **Generic** (applies to any project) → Copy to \`.squad/extract/\` with the same filename
178
- - Signals: "always use", "never use", "prefer X over Y", "best practice", coding standards, patterns that work anywhere
179
- - These will be extracted to the personal squad via \`squad extract\`
180
-
181
- 2. **Project-specific** (only applies here) → Keep in local \`decisions.md\` only
182
- - Signals: Contains file paths from this project, references "this project/codebase/repo", mentions project-specific config/APIs/schemas
183
-
184
- Generic decisions go to BOTH \`.squad/decisions.md\` (for this session) AND \`.squad/extract/\` (for later extraction).
185
-
186
- ### Extract Directory
187
-
188
- \`\`\`
189
- .squad/extract/ # Generic learnings staged for personal squad
190
- ├── decision-1.md # Ready for extraction
191
- └── pattern-auth.md # Ready for extraction
192
- \`\`\`
193
-
194
- Run \`squad extract\` to review and merge these to your personal squad.
165
+ const CONSULT_MODE_SCRIBE_PATCH = `
166
+
167
+ ---
168
+
169
+ ## Consult Mode Extraction
170
+
171
+ **This squad is in consult mode.** When merging decisions from the inbox, also classify each decision:
172
+
173
+ ### Classification
174
+
175
+ For each decision in \`.squad/decisions/inbox/\`:
176
+
177
+ 1. **Generic** (applies to any project) → Copy to \`.squad/extract/\` with the same filename
178
+ - Signals: "always use", "never use", "prefer X over Y", "best practice", coding standards, patterns that work anywhere
179
+ - These will be extracted to the personal squad via \`squad extract\`
180
+
181
+ 2. **Project-specific** (only applies here) → Keep in local \`decisions.md\` only
182
+ - Signals: Contains file paths from this project, references "this project/codebase/repo", mentions project-specific config/APIs/schemas
183
+
184
+ Generic decisions go to BOTH \`.squad/decisions.md\` (for this session) AND \`.squad/extract/\` (for later extraction).
185
+
186
+ ### Extract Directory
187
+
188
+ \`\`\`
189
+ .squad/extract/ # Generic learnings staged for personal squad
190
+ ├── decision-1.md # Ready for extraction
191
+ └── pattern-auth.md # Ready for extraction
192
+ \`\`\`
193
+
194
+ Run \`squad extract\` to review and merge these to your personal squad.
195
195
  `;
196
196
  /**
197
197
  * Patch the Scribe charter in the copied squad with consult mode instructions.
@@ -682,14 +682,14 @@ function formatLogHeader(result, date) {
682
682
  ? `**Repository:** ${result.repoUrl}\n`
683
683
  : '';
684
684
  const licenseName = result.license.spdxId || result.license.name || result.license.type;
685
- return `# ${result.projectName}
686
-
687
- ${repoLine}**First consulted:** ${date}
688
- **Last session:** ${date}
689
- **License:** ${licenseName}
690
-
691
- ## Extracted Learnings
692
-
685
+ return `# ${result.projectName}
686
+
687
+ ${repoLine}**First consulted:** ${date}
688
+ **Last session:** ${date}
689
+ **License:** ${licenseName}
690
+
691
+ ## Extracted Learnings
692
+
693
693
  `;
694
694
  }
695
695
  /**
@@ -697,16 +697,16 @@ ${repoLine}**First consulted:** ${date}
697
697
  */
698
698
  function formatSessionEntry(result, date) {
699
699
  if (result.extracted.length === 0) {
700
- return `### ${date}
701
- - No learnings extracted
702
-
700
+ return `### ${date}
701
+ - No learnings extracted
702
+
703
703
  `;
704
704
  }
705
705
  // Just list titles/filenames, not content
706
706
  const lines = result.extracted.map(l => `- ${l.filename}`);
707
- return `### ${date}
708
- ${lines.join('\n')}
709
-
707
+ return `### ${date}
708
+ ${lines.join('\n')}
709
+
710
710
  `;
711
711
  }
712
712
  // ============================================================================
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Workstream-Aware Issue Filtering
3
+ *
4
+ * Filters GitHub issues to only those matching a workstream's labelFilter.
5
+ * Intended to scope work to the active workstream during triage.
6
+ *
7
+ * @module streams/filter
8
+ */
9
+ import type { ResolvedWorkstream } from './types.js';
10
+ /** Minimal issue shape for filtering. */
11
+ export interface WorkstreamIssue {
12
+ number: number;
13
+ title: string;
14
+ labels: Array<{
15
+ name: string;
16
+ }>;
17
+ }
18
+ /** @deprecated Use WorkstreamIssue instead */
19
+ export type StreamIssue = WorkstreamIssue;
20
+ /**
21
+ * Filter issues to only those matching the workstream's label filter.
22
+ *
23
+ * Matching is case-insensitive. If the workstream has no labelFilter,
24
+ * all issues are returned (passthrough).
25
+ *
26
+ * @param issues - Array of issues to filter
27
+ * @param workstream - The resolved workstream to filter by
28
+ * @returns Filtered array of issues matching the workstream's label
29
+ */
30
+ export declare function filterIssuesByWorkstream(issues: WorkstreamIssue[], workstream: ResolvedWorkstream): WorkstreamIssue[];
31
+ /** @deprecated Use filterIssuesByWorkstream instead */
32
+ export declare const filterIssuesByStream: typeof filterIssuesByWorkstream;
33
+ //# sourceMappingURL=filter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"filter.d.ts","sourceRoot":"","sources":["../../src/streams/filter.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAErD,yCAAyC;AACzC,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACjC;AAED,8CAA8C;AAC9C,MAAM,MAAM,WAAW,GAAG,eAAe,CAAC;AAE1C;;;;;;;;;GASG;AACH,wBAAgB,wBAAwB,CACtC,MAAM,EAAE,eAAe,EAAE,EACzB,UAAU,EAAE,kBAAkB,GAC7B,eAAe,EAAE,CAUnB;AAED,uDAAuD;AACvD,eAAO,MAAM,oBAAoB,iCAA2B,CAAC"}
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Workstream-Aware Issue Filtering
3
+ *
4
+ * Filters GitHub issues to only those matching a workstream's labelFilter.
5
+ * Intended to scope work to the active workstream during triage.
6
+ *
7
+ * @module streams/filter
8
+ */
9
+ /**
10
+ * Filter issues to only those matching the workstream's label filter.
11
+ *
12
+ * Matching is case-insensitive. If the workstream has no labelFilter,
13
+ * all issues are returned (passthrough).
14
+ *
15
+ * @param issues - Array of issues to filter
16
+ * @param workstream - The resolved workstream to filter by
17
+ * @returns Filtered array of issues matching the workstream's label
18
+ */
19
+ export function filterIssuesByWorkstream(issues, workstream) {
20
+ const filter = workstream.definition.labelFilter;
21
+ if (!filter) {
22
+ return issues;
23
+ }
24
+ const normalizedFilter = filter.toLowerCase();
25
+ return issues.filter(issue => issue.labels.some(label => label.name.toLowerCase() === normalizedFilter));
26
+ }
27
+ /** @deprecated Use filterIssuesByWorkstream instead */
28
+ export const filterIssuesByStream = filterIssuesByWorkstream;
29
+ //# sourceMappingURL=filter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"filter.js","sourceRoot":"","sources":["../../src/streams/filter.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAcH;;;;;;;;;GASG;AACH,MAAM,UAAU,wBAAwB,CACtC,MAAyB,EACzB,UAA8B;IAE9B,MAAM,MAAM,GAAG,UAAU,CAAC,UAAU,CAAC,WAAW,CAAC;IACjD,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,MAAM,gBAAgB,GAAG,MAAM,CAAC,WAAW,EAAE,CAAC;IAC9C,OAAO,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAC3B,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,WAAW,EAAE,KAAK,gBAAgB,CAAC,CAC1E,CAAC;AACJ,CAAC;AAED,uDAAuD;AACvD,MAAM,CAAC,MAAM,oBAAoB,GAAG,wBAAwB,CAAC"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Workstreams module — barrel exports.
3
+ *
4
+ * @module streams
5
+ */
6
+ export * from './types.js';
7
+ export * from './resolver.js';
8
+ export * from './filter.js';
9
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/streams/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,cAAc,YAAY,CAAC;AAC3B,cAAc,eAAe,CAAC;AAC9B,cAAc,aAAa,CAAC"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Workstreams module — barrel exports.
3
+ *
4
+ * @module streams
5
+ */
6
+ export * from './types.js';
7
+ export * from './resolver.js';
8
+ export * from './filter.js';
9
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/streams/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,cAAc,YAAY,CAAC;AAC3B,cAAc,eAAe,CAAC;AAC9B,cAAc,aAAa,CAAC"}
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Workstream Resolver — Resolves which workstream is active.
3
+ *
4
+ * Resolution order:
5
+ * 1. SQUAD_TEAM env var → look up in workstreams config
6
+ * 2. .squad-workstream file (gitignored) → contains workstream name
7
+ * 3. If exactly one workstream is defined in the config, auto-select that workstream
8
+ * 4. null (no active workstream — single-squad mode / no workstreams)
9
+ *
10
+ * @module streams/resolver
11
+ */
12
+ import type { WorkstreamConfig, ResolvedWorkstream } from './types.js';
13
+ /**
14
+ * Load workstreams configuration from .squad/workstreams.json.
15
+ *
16
+ * @param squadRoot - Root directory of the project (where .squad/ lives)
17
+ * @returns Parsed WorkstreamConfig or null if not found / invalid
18
+ */
19
+ export declare function loadWorkstreamsConfig(squadRoot: string): WorkstreamConfig | null;
20
+ /** @deprecated Use loadWorkstreamsConfig instead */
21
+ export declare const loadStreamsConfig: typeof loadWorkstreamsConfig;
22
+ /**
23
+ * Resolve which workstream is active for the current environment.
24
+ *
25
+ * @param squadRoot - Root directory of the project
26
+ * @returns ResolvedWorkstream or null if no workstream is active
27
+ */
28
+ export declare function resolveWorkstream(squadRoot: string): ResolvedWorkstream | null;
29
+ /** @deprecated Use resolveWorkstream instead */
30
+ export declare const resolveStream: typeof resolveWorkstream;
31
+ /**
32
+ * Get the GitHub label filter string for a resolved workstream.
33
+ *
34
+ * @param workstream - The resolved workstream
35
+ * @returns Label filter string (e.g., "team:ui")
36
+ */
37
+ export declare function getWorkstreamLabelFilter(workstream: ResolvedWorkstream): string;
38
+ /** @deprecated Use getWorkstreamLabelFilter instead */
39
+ export declare const getStreamLabelFilter: typeof getWorkstreamLabelFilter;
40
+ //# sourceMappingURL=resolver.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolver.d.ts","sourceRoot":"","sources":["../../src/streams/resolver.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAIH,OAAO,KAAK,EAAE,gBAAgB,EAAwB,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAE7F;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,SAAS,EAAE,MAAM,GAAG,gBAAgB,GAAG,IAAI,CA8EhF;AAED,oDAAoD;AACpD,eAAO,MAAM,iBAAiB,8BAAwB,CAAC;AASvD;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,kBAAkB,GAAG,IAAI,CA0D9E;AAED,gDAAgD;AAChD,eAAO,MAAM,aAAa,0BAAoB,CAAC;AAE/C;;;;;GAKG;AACH,wBAAgB,wBAAwB,CAAC,UAAU,EAAE,kBAAkB,GAAG,MAAM,CAE/E;AAED,uDAAuD;AACvD,eAAO,MAAM,oBAAoB,iCAA2B,CAAC"}
@@ -0,0 +1,162 @@
1
+ /**
2
+ * Workstream Resolver — Resolves which workstream is active.
3
+ *
4
+ * Resolution order:
5
+ * 1. SQUAD_TEAM env var → look up in workstreams config
6
+ * 2. .squad-workstream file (gitignored) → contains workstream name
7
+ * 3. If exactly one workstream is defined in the config, auto-select that workstream
8
+ * 4. null (no active workstream — single-squad mode / no workstreams)
9
+ *
10
+ * @module streams/resolver
11
+ */
12
+ import { existsSync, readFileSync } from 'fs';
13
+ import { join } from 'path';
14
+ /**
15
+ * Load workstreams configuration from .squad/workstreams.json.
16
+ *
17
+ * @param squadRoot - Root directory of the project (where .squad/ lives)
18
+ * @returns Parsed WorkstreamConfig or null if not found / invalid
19
+ */
20
+ export function loadWorkstreamsConfig(squadRoot) {
21
+ const configPath = join(squadRoot, '.squad', 'workstreams.json');
22
+ if (!existsSync(configPath)) {
23
+ return null;
24
+ }
25
+ try {
26
+ const raw = readFileSync(configPath, 'utf-8');
27
+ const rawConfig = JSON.parse(raw);
28
+ if (!rawConfig || typeof rawConfig !== 'object') {
29
+ return null;
30
+ }
31
+ const configLike = rawConfig;
32
+ // Derive a sane defaultWorkflow value
33
+ const validWorkflows = ['branch-per-issue', 'direct'];
34
+ const rawWorkflow = typeof configLike.defaultWorkflow === 'string' && configLike.defaultWorkflow.trim() !== ''
35
+ ? configLike.defaultWorkflow
36
+ : 'branch-per-issue';
37
+ const defaultWorkflow = validWorkflows.includes(rawWorkflow)
38
+ ? rawWorkflow
39
+ : 'branch-per-issue';
40
+ const workstreamsRaw = configLike.workstreams;
41
+ if (!Array.isArray(workstreamsRaw)) {
42
+ return null;
43
+ }
44
+ const workstreams = workstreamsRaw
45
+ .filter(entry => entry && typeof entry === 'object')
46
+ .map(entry => {
47
+ const e = entry;
48
+ if (typeof e.name !== 'string' || typeof e.labelFilter !== 'string') {
49
+ return null;
50
+ }
51
+ const normalized = {
52
+ name: e.name,
53
+ labelFilter: e.labelFilter,
54
+ };
55
+ if (Array.isArray(e.folderScope) && e.folderScope.every(item => typeof item === 'string')) {
56
+ normalized.folderScope = e.folderScope;
57
+ }
58
+ if (typeof e.workflow === 'string' && e.workflow.trim() !== '') {
59
+ normalized.workflow = e.workflow;
60
+ }
61
+ else {
62
+ normalized.workflow = defaultWorkflow;
63
+ }
64
+ if (typeof e.description === 'string') {
65
+ normalized.description = e.description;
66
+ }
67
+ return normalized;
68
+ })
69
+ .filter((s) => s !== null);
70
+ if (workstreams.length === 0) {
71
+ return null;
72
+ }
73
+ return { defaultWorkflow, workstreams };
74
+ }
75
+ catch {
76
+ return null;
77
+ }
78
+ }
79
+ /** @deprecated Use loadWorkstreamsConfig instead */
80
+ export const loadStreamsConfig = loadWorkstreamsConfig;
81
+ /**
82
+ * Find a workstream definition by name in a config.
83
+ */
84
+ function findWorkstream(config, name) {
85
+ return config.workstreams.find(s => s.name === name);
86
+ }
87
+ /**
88
+ * Resolve which workstream is active for the current environment.
89
+ *
90
+ * @param squadRoot - Root directory of the project
91
+ * @returns ResolvedWorkstream or null if no workstream is active
92
+ */
93
+ export function resolveWorkstream(squadRoot) {
94
+ const config = loadWorkstreamsConfig(squadRoot);
95
+ // 1. SQUAD_TEAM env var
96
+ const envTeam = process.env.SQUAD_TEAM;
97
+ if (envTeam) {
98
+ if (config) {
99
+ const def = findWorkstream(config, envTeam);
100
+ if (def) {
101
+ return { name: envTeam, definition: def, source: 'env' };
102
+ }
103
+ }
104
+ // Env var set but no matching workstream config — synthesize a minimal definition
105
+ return {
106
+ name: envTeam,
107
+ definition: {
108
+ name: envTeam,
109
+ labelFilter: `team:${envTeam}`,
110
+ },
111
+ source: 'env',
112
+ };
113
+ }
114
+ // 2. .squad-workstream file
115
+ const workstreamFilePath = join(squadRoot, '.squad-workstream');
116
+ if (existsSync(workstreamFilePath)) {
117
+ try {
118
+ const workstreamName = readFileSync(workstreamFilePath, 'utf-8').trim();
119
+ if (workstreamName) {
120
+ if (config) {
121
+ const def = findWorkstream(config, workstreamName);
122
+ if (def) {
123
+ return { name: workstreamName, definition: def, source: 'file' };
124
+ }
125
+ }
126
+ // File exists but no config — synthesize
127
+ return {
128
+ name: workstreamName,
129
+ definition: {
130
+ name: workstreamName,
131
+ labelFilter: `team:${workstreamName}`,
132
+ },
133
+ source: 'file',
134
+ };
135
+ }
136
+ }
137
+ catch {
138
+ // Ignore read errors
139
+ }
140
+ }
141
+ // 3. If exactly one workstream is defined, auto-select it
142
+ if (config && config.workstreams.length === 1) {
143
+ const def = config.workstreams[0];
144
+ return { name: def.name, definition: def, source: 'config' };
145
+ }
146
+ // 4. No workstream detected
147
+ return null;
148
+ }
149
+ /** @deprecated Use resolveWorkstream instead */
150
+ export const resolveStream = resolveWorkstream;
151
+ /**
152
+ * Get the GitHub label filter string for a resolved workstream.
153
+ *
154
+ * @param workstream - The resolved workstream
155
+ * @returns Label filter string (e.g., "team:ui")
156
+ */
157
+ export function getWorkstreamLabelFilter(workstream) {
158
+ return workstream.definition.labelFilter;
159
+ }
160
+ /** @deprecated Use getWorkstreamLabelFilter instead */
161
+ export const getStreamLabelFilter = getWorkstreamLabelFilter;
162
+ //# sourceMappingURL=resolver.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolver.js","sourceRoot":"","sources":["../../src/streams/resolver.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Workstream Types — Type definitions for Squad Workstreams.
3
+ *
4
+ * Workstreams enable horizontal scaling by allowing multiple Squad instances
5
+ * (e.g., in different Codespaces) to each handle a scoped subset of work.
6
+ *
7
+ * @module streams/types
8
+ */
9
+ /** Definition of a single workstream (team partition). */
10
+ export interface WorkstreamDefinition {
11
+ /** Workstream name, e.g., "ui-team", "backend-team" */
12
+ name: string;
13
+ /** GitHub label to filter issues by, e.g., "team:ui" */
14
+ labelFilter: string;
15
+ /** Optional folder restrictions, e.g., ["apps/web"] */
16
+ folderScope?: string[];
17
+ /** Workflow mode. Default: branch-per-issue */
18
+ workflow?: 'branch-per-issue' | 'direct';
19
+ /** Human-readable description of this workstream's purpose */
20
+ description?: string;
21
+ }
22
+ /** @deprecated Use WorkstreamDefinition instead */
23
+ export type StreamDefinition = WorkstreamDefinition;
24
+ /** Top-level workstreams configuration (stored in .squad/workstreams.json). */
25
+ export interface WorkstreamConfig {
26
+ /** All configured workstreams */
27
+ workstreams: WorkstreamDefinition[];
28
+ /** Default workflow for workstreams that don't specify one */
29
+ defaultWorkflow: 'branch-per-issue' | 'direct';
30
+ }
31
+ /** @deprecated Use WorkstreamConfig instead */
32
+ export type StreamConfig = WorkstreamConfig;
33
+ /** A resolved workstream with provenance information. */
34
+ export interface ResolvedWorkstream {
35
+ /** Workstream name */
36
+ name: string;
37
+ /** Full workstream definition */
38
+ definition: WorkstreamDefinition;
39
+ /** How this workstream was resolved */
40
+ source: 'env' | 'file' | 'config';
41
+ }
42
+ /** @deprecated Use ResolvedWorkstream instead */
43
+ export type ResolvedStream = ResolvedWorkstream;
44
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/streams/types.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,0DAA0D;AAC1D,MAAM,WAAW,oBAAoB;IACnC,uDAAuD;IACvD,IAAI,EAAE,MAAM,CAAC;IACb,wDAAwD;IACxD,WAAW,EAAE,MAAM,CAAC;IACpB,uDAAuD;IACvD,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,+CAA+C;IAC/C,QAAQ,CAAC,EAAE,kBAAkB,GAAG,QAAQ,CAAC;IACzC,8DAA8D;IAC9D,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,mDAAmD;AACnD,MAAM,MAAM,gBAAgB,GAAG,oBAAoB,CAAC;AAEpD,+EAA+E;AAC/E,MAAM,WAAW,gBAAgB;IAC/B,iCAAiC;IACjC,WAAW,EAAE,oBAAoB,EAAE,CAAC;IACpC,8DAA8D;IAC9D,eAAe,EAAE,kBAAkB,GAAG,QAAQ,CAAC;CAChD;AAED,+CAA+C;AAC/C,MAAM,MAAM,YAAY,GAAG,gBAAgB,CAAC;AAE5C,yDAAyD;AACzD,MAAM,WAAW,kBAAkB;IACjC,sBAAsB;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,iCAAiC;IACjC,UAAU,EAAE,oBAAoB,CAAC;IACjC,uCAAuC;IACvC,MAAM,EAAE,KAAK,GAAG,MAAM,GAAG,QAAQ,CAAC;CACnC;AAED,iDAAiD;AACjD,MAAM,MAAM,cAAc,GAAG,kBAAkB,CAAC"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Workstream Types — Type definitions for Squad Workstreams.
3
+ *
4
+ * Workstreams enable horizontal scaling by allowing multiple Squad instances
5
+ * (e.g., in different Codespaces) to each handle a scoped subset of work.
6
+ *
7
+ * @module streams/types
8
+ */
9
+ export {};
10
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/streams/types.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG"}
@@ -12,7 +12,7 @@
12
12
  import * as fs from 'node:fs';
13
13
  import * as path from 'node:path';
14
14
  import { randomUUID } from 'node:crypto';
15
- import { trace, SpanStatusCode } from '@opentelemetry/api';
15
+ import { trace, SpanStatusCode } from '../runtime/otel-api.js';
16
16
  const tracer = trace.getTracer('squad-sdk');
17
17
  // --- Argument Sanitization ---
18
18
  /** Sensitive field patterns — strip before recording as span attributes. */