@bradygaster/squad-cli 0.8.5 → 0.8.16

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 (153) hide show
  1. package/README.md +2 -2
  2. package/dist/cli/commands/copilot-bridge.d.ts +42 -0
  3. package/dist/cli/commands/copilot-bridge.d.ts.map +1 -0
  4. package/dist/cli/commands/copilot-bridge.js +191 -0
  5. package/dist/cli/commands/copilot-bridge.js.map +1 -0
  6. package/dist/cli/commands/import.js.map +1 -1
  7. package/dist/cli/commands/rc-tunnel.d.ts +30 -0
  8. package/dist/cli/commands/rc-tunnel.d.ts.map +1 -0
  9. package/dist/cli/commands/rc-tunnel.js +107 -0
  10. package/dist/cli/commands/rc-tunnel.js.map +1 -0
  11. package/dist/cli/commands/rc.d.ts +13 -0
  12. package/dist/cli/commands/rc.d.ts.map +1 -0
  13. package/dist/cli/commands/rc.js +270 -0
  14. package/dist/cli/commands/rc.js.map +1 -0
  15. package/dist/cli/commands/start.d.ts +18 -0
  16. package/dist/cli/commands/start.d.ts.map +1 -0
  17. package/dist/cli/commands/start.js +219 -0
  18. package/dist/cli/commands/start.js.map +1 -0
  19. package/dist/cli/commands/upstream.js.map +1 -1
  20. package/dist/cli/commands/watch.d.ts +10 -0
  21. package/dist/cli/commands/watch.d.ts.map +1 -1
  22. package/dist/cli/commands/watch.js +181 -65
  23. package/dist/cli/commands/watch.js.map +1 -1
  24. package/dist/cli/core/cast.d.ts +40 -0
  25. package/dist/cli/core/cast.d.ts.map +1 -0
  26. package/dist/cli/core/cast.js +442 -0
  27. package/dist/cli/core/cast.js.map +1 -0
  28. package/dist/cli/core/gh-cli.d.ts +25 -0
  29. package/dist/cli/core/gh-cli.d.ts.map +1 -1
  30. package/dist/cli/core/gh-cli.js +15 -1
  31. package/dist/cli/core/gh-cli.js.map +1 -1
  32. package/dist/cli/core/init.d.ts +9 -1
  33. package/dist/cli/core/init.d.ts.map +1 -1
  34. package/dist/cli/core/init.js +108 -13
  35. package/dist/cli/core/init.js.map +1 -1
  36. package/dist/cli/core/migrations.js.map +1 -1
  37. package/dist/cli/core/nap.d.ts +37 -0
  38. package/dist/cli/core/nap.d.ts.map +1 -0
  39. package/dist/cli/core/nap.js +528 -0
  40. package/dist/cli/core/nap.js.map +1 -0
  41. package/dist/cli/core/output.d.ts +5 -0
  42. package/dist/cli/core/output.d.ts.map +1 -1
  43. package/dist/cli/core/output.js +7 -0
  44. package/dist/cli/core/output.js.map +1 -1
  45. package/dist/cli/core/upgrade.d.ts +0 -1
  46. package/dist/cli/core/upgrade.d.ts.map +1 -1
  47. package/dist/cli/core/upgrade.js.map +1 -1
  48. package/dist/cli/core/version.js.map +1 -1
  49. package/dist/cli/shell/agent-status.d.ts +11 -0
  50. package/dist/cli/shell/agent-status.d.ts.map +1 -0
  51. package/dist/cli/shell/agent-status.js +26 -0
  52. package/dist/cli/shell/agent-status.js.map +1 -0
  53. package/dist/cli/shell/commands.d.ts +10 -0
  54. package/dist/cli/shell/commands.d.ts.map +1 -1
  55. package/dist/cli/shell/commands.js +143 -29
  56. package/dist/cli/shell/commands.js.map +1 -1
  57. package/dist/cli/shell/components/AgentPanel.d.ts +1 -4
  58. package/dist/cli/shell/components/AgentPanel.d.ts.map +1 -1
  59. package/dist/cli/shell/components/AgentPanel.js +88 -6
  60. package/dist/cli/shell/components/AgentPanel.js.map +1 -1
  61. package/dist/cli/shell/components/App.d.ts +11 -6
  62. package/dist/cli/shell/components/App.d.ts.map +1 -1
  63. package/dist/cli/shell/components/App.js +212 -35
  64. package/dist/cli/shell/components/App.js.map +1 -1
  65. package/dist/cli/shell/components/ErrorBoundary.d.ts +22 -0
  66. package/dist/cli/shell/components/ErrorBoundary.d.ts.map +1 -0
  67. package/dist/cli/shell/components/ErrorBoundary.js +31 -0
  68. package/dist/cli/shell/components/ErrorBoundary.js.map +1 -0
  69. package/dist/cli/shell/components/InputPrompt.d.ts +3 -0
  70. package/dist/cli/shell/components/InputPrompt.d.ts.map +1 -1
  71. package/dist/cli/shell/components/InputPrompt.js +155 -13
  72. package/dist/cli/shell/components/InputPrompt.js.map +1 -1
  73. package/dist/cli/shell/components/MessageStream.d.ts +17 -4
  74. package/dist/cli/shell/components/MessageStream.d.ts.map +1 -1
  75. package/dist/cli/shell/components/MessageStream.js +215 -23
  76. package/dist/cli/shell/components/MessageStream.js.map +1 -1
  77. package/dist/cli/shell/components/Separator.d.ts +17 -0
  78. package/dist/cli/shell/components/Separator.d.ts.map +1 -0
  79. package/dist/cli/shell/components/Separator.js +10 -0
  80. package/dist/cli/shell/components/Separator.js.map +1 -0
  81. package/dist/cli/shell/components/ThinkingIndicator.d.ts +21 -0
  82. package/dist/cli/shell/components/ThinkingIndicator.d.ts.map +1 -0
  83. package/dist/cli/shell/components/ThinkingIndicator.js +102 -0
  84. package/dist/cli/shell/components/ThinkingIndicator.js.map +1 -0
  85. package/dist/cli/shell/components/index.d.ts +3 -0
  86. package/dist/cli/shell/components/index.d.ts.map +1 -1
  87. package/dist/cli/shell/components/index.js +2 -0
  88. package/dist/cli/shell/components/index.js.map +1 -1
  89. package/dist/cli/shell/coordinator.d.ts +10 -0
  90. package/dist/cli/shell/coordinator.d.ts.map +1 -1
  91. package/dist/cli/shell/coordinator.js +99 -4
  92. package/dist/cli/shell/coordinator.js.map +1 -1
  93. package/dist/cli/shell/error-messages.d.ts +21 -0
  94. package/dist/cli/shell/error-messages.d.ts.map +1 -0
  95. package/dist/cli/shell/error-messages.js +61 -0
  96. package/dist/cli/shell/error-messages.js.map +1 -0
  97. package/dist/cli/shell/index.d.ts +24 -3
  98. package/dist/cli/shell/index.d.ts.map +1 -1
  99. package/dist/cli/shell/index.js +943 -34
  100. package/dist/cli/shell/index.js.map +1 -1
  101. package/dist/cli/shell/lifecycle.d.ts +2 -0
  102. package/dist/cli/shell/lifecycle.d.ts.map +1 -1
  103. package/dist/cli/shell/lifecycle.js +59 -6
  104. package/dist/cli/shell/lifecycle.js.map +1 -1
  105. package/dist/cli/shell/memory.d.ts +6 -1
  106. package/dist/cli/shell/memory.d.ts.map +1 -1
  107. package/dist/cli/shell/memory.js +12 -1
  108. package/dist/cli/shell/memory.js.map +1 -1
  109. package/dist/cli/shell/router.d.ts +16 -0
  110. package/dist/cli/shell/router.d.ts.map +1 -1
  111. package/dist/cli/shell/router.js +27 -0
  112. package/dist/cli/shell/router.js.map +1 -1
  113. package/dist/cli/shell/session-store.d.ts +47 -0
  114. package/dist/cli/shell/session-store.d.ts.map +1 -0
  115. package/dist/cli/shell/session-store.js +125 -0
  116. package/dist/cli/shell/session-store.js.map +1 -0
  117. package/dist/cli/shell/sessions.d.ts +2 -0
  118. package/dist/cli/shell/sessions.d.ts.map +1 -1
  119. package/dist/cli/shell/sessions.js +19 -5
  120. package/dist/cli/shell/sessions.js.map +1 -1
  121. package/dist/cli/shell/shell-metrics.d.ts +34 -0
  122. package/dist/cli/shell/shell-metrics.d.ts.map +1 -0
  123. package/dist/cli/shell/shell-metrics.js +98 -0
  124. package/dist/cli/shell/shell-metrics.js.map +1 -0
  125. package/dist/cli/shell/spawn.d.ts.map +1 -1
  126. package/dist/cli/shell/spawn.js +20 -6
  127. package/dist/cli/shell/spawn.js.map +1 -1
  128. package/dist/cli/shell/terminal.d.ts +26 -0
  129. package/dist/cli/shell/terminal.d.ts.map +1 -1
  130. package/dist/cli/shell/terminal.js +65 -2
  131. package/dist/cli/shell/terminal.js.map +1 -1
  132. package/dist/cli/shell/theme-colors.d.ts +39 -0
  133. package/dist/cli/shell/theme-colors.d.ts.map +1 -0
  134. package/dist/cli/shell/theme-colors.js +39 -0
  135. package/dist/cli/shell/theme-colors.js.map +1 -0
  136. package/dist/cli/shell/types.d.ts +2 -0
  137. package/dist/cli/shell/types.d.ts.map +1 -1
  138. package/dist/cli/shell/useAnimation.d.ts +42 -0
  139. package/dist/cli/shell/useAnimation.d.ts.map +1 -0
  140. package/dist/cli/shell/useAnimation.js +139 -0
  141. package/dist/cli/shell/useAnimation.js.map +1 -0
  142. package/dist/cli-entry.d.ts +0 -7
  143. package/dist/cli-entry.d.ts.map +1 -1
  144. package/dist/cli-entry.js +701 -96
  145. package/dist/cli-entry.js.map +1 -1
  146. package/package.json +156 -140
  147. package/templates/orchestration-log.md +1 -1
  148. package/templates/package.json +3 -0
  149. package/templates/ralph-triage.js +543 -0
  150. package/templates/scribe-charter.md +1 -1
  151. package/templates/squad.agent.md +10 -10
  152. package/templates/workflows/squad-heartbeat.yml +52 -196
  153. package/templates/workflows/squad-insider-release.yml +1 -1
@@ -1,4 +1,10 @@
1
1
  name: Squad Heartbeat (Ralph)
2
+ # ⚠️ SYNC: This workflow is maintained in 4 locations. Changes must be applied to all:
3
+ # - templates/workflows/squad-heartbeat.yml (source template)
4
+ # - packages/squad-cli/templates/workflows/squad-heartbeat.yml (CLI package)
5
+ # - .squad-templates/workflows/squad-heartbeat.yml (installed template)
6
+ # - .github/workflows/squad-heartbeat.yml (active workflow)
7
+ # Run 'squad upgrade' to sync installed copies from source templates.
2
8
 
3
9
  on:
4
10
  schedule:
@@ -25,225 +31,75 @@ jobs:
25
31
  steps:
26
32
  - uses: actions/checkout@v4
27
33
 
28
- - name: Ralph — Check for squad work
34
+ - name: Check triage script
35
+ id: check-script
36
+ run: |
37
+ if [ -f ".squad-templates/ralph-triage.js" ]; then
38
+ echo "has_script=true" >> $GITHUB_OUTPUT
39
+ else
40
+ echo "has_script=false" >> $GITHUB_OUTPUT
41
+ echo "⚠️ ralph-triage.js not found — run 'squad upgrade' to install"
42
+ fi
43
+
44
+ - name: Ralph — Smart triage
45
+ if: steps.check-script.outputs.has_script == 'true'
46
+ env:
47
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
48
+ run: |
49
+ node .squad-templates/ralph-triage.js \
50
+ --squad-dir .squad \
51
+ --output triage-results.json
52
+
53
+ - name: Ralph — Apply triage decisions
54
+ if: steps.check-script.outputs.has_script == 'true' && hashFiles('triage-results.json') != ''
29
55
  uses: actions/github-script@v7
30
56
  with:
31
57
  script: |
32
58
  const fs = require('fs');
33
-
34
- // Read team roster — check .squad/ first, fall back to .ai-team/
35
- let teamFile = '.squad/team.md';
36
- if (!fs.existsSync(teamFile)) {
37
- teamFile = '.ai-team/team.md';
38
- }
39
- if (!fs.existsSync(teamFile)) {
40
- core.info('No .squad/team.md or .ai-team/team.md found — Ralph has nothing to monitor');
59
+ const path = 'triage-results.json';
60
+ if (!fs.existsSync(path)) {
61
+ core.info('No triage results — board is clear');
41
62
  return;
42
63
  }
43
-
44
- const content = fs.readFileSync(teamFile, 'utf8');
45
-
46
- // Check if Ralph is on the roster
47
- if (!content.includes('Ralph') || !content.includes('🔄')) {
48
- core.info('Ralph not on roster — heartbeat disabled');
64
+
65
+ const results = JSON.parse(fs.readFileSync(path, 'utf8'));
66
+ if (results.length === 0) {
67
+ core.info('📋 Board is clear — Ralph found no untriaged issues');
49
68
  return;
50
69
  }
51
-
52
- // Parse members from roster
53
- const lines = content.split('\n');
54
- const members = [];
55
- let inMembersTable = false;
56
- for (const line of lines) {
57
- if (line.match(/^##\s+(Members|Team Roster)/i)) {
58
- inMembersTable = true;
59
- continue;
60
- }
61
- if (inMembersTable && line.startsWith('## ')) break;
62
- if (inMembersTable && line.startsWith('|') && !line.includes('---') && !line.includes('Name')) {
63
- const cells = line.split('|').map(c => c.trim()).filter(Boolean);
64
- if (cells.length >= 2 && !['Scribe', 'Ralph'].includes(cells[0])) {
65
- members.push({
66
- name: cells[0],
67
- role: cells[1],
68
- label: `squad:${cells[0].toLowerCase()}`
69
- });
70
- }
71
- }
72
- }
73
-
74
- if (members.length === 0) {
75
- core.info('No squad members found — nothing to monitor');
76
- return;
77
- }
78
-
79
- // 1. Find untriaged issues (labeled "squad" but no "squad:{member}" label)
80
- const { data: squadIssues } = await github.rest.issues.listForRepo({
81
- owner: context.repo.owner,
82
- repo: context.repo.repo,
83
- labels: 'squad',
84
- state: 'open',
85
- per_page: 20
86
- });
87
-
88
- const memberLabels = members.map(m => m.label);
89
- const untriaged = squadIssues.filter(issue => {
90
- const issueLabels = issue.labels.map(l => l.name);
91
- return !memberLabels.some(ml => issueLabels.includes(ml));
92
- });
93
-
94
- // 2. Find assigned but unstarted issues (has squad:{member} label, no assignee)
95
- const unstarted = [];
96
- for (const member of members) {
70
+
71
+ for (const decision of results) {
97
72
  try {
98
- const { data: memberIssues } = await github.rest.issues.listForRepo({
99
- owner: context.repo.owner,
100
- repo: context.repo.repo,
101
- labels: member.label,
102
- state: 'open',
103
- per_page: 10
104
- });
105
- for (const issue of memberIssues) {
106
- if (!issue.assignees || issue.assignees.length === 0) {
107
- unstarted.push({ issue, member });
108
- }
109
- }
110
- } catch (e) {
111
- // Label may not exist yet
112
- }
113
- }
114
-
115
- // 3. Find squad issues missing triage verdict (no go:* label)
116
- const missingVerdict = squadIssues.filter(issue => {
117
- const labels = issue.labels.map(l => l.name);
118
- return !labels.some(l => l.startsWith('go:'));
119
- });
120
-
121
- // 4. Find go:yes issues missing release target
122
- const goYesIssues = squadIssues.filter(issue => {
123
- const labels = issue.labels.map(l => l.name);
124
- return labels.includes('go:yes') && !labels.some(l => l.startsWith('release:'));
125
- });
126
-
127
- // 4b. Find issues missing type: label
128
- const missingType = squadIssues.filter(issue => {
129
- const labels = issue.labels.map(l => l.name);
130
- return !labels.some(l => l.startsWith('type:'));
131
- });
132
-
133
- // 5. Find open PRs that need attention
134
- const { data: openPRs } = await github.rest.pulls.list({
135
- owner: context.repo.owner,
136
- repo: context.repo.repo,
137
- state: 'open',
138
- per_page: 20
139
- });
140
-
141
- const squadPRs = openPRs.filter(pr =>
142
- pr.labels.some(l => l.name.startsWith('squad'))
143
- );
144
-
145
- // Build status summary
146
- const summary = [];
147
- if (untriaged.length > 0) {
148
- summary.push(`🔴 **${untriaged.length} untriaged issue(s)** need triage`);
149
- }
150
- if (unstarted.length > 0) {
151
- summary.push(`🟡 **${unstarted.length} assigned issue(s)** have no assignee`);
152
- }
153
- if (missingVerdict.length > 0) {
154
- summary.push(`⚪ **${missingVerdict.length} issue(s)** missing triage verdict (no \`go:\` label)`);
155
- }
156
- if (goYesIssues.length > 0) {
157
- summary.push(`⚪ **${goYesIssues.length} approved issue(s)** missing release target (no \`release:\` label)`);
158
- }
159
- if (missingType.length > 0) {
160
- summary.push(`⚪ **${missingType.length} issue(s)** missing \`type:\` label`);
161
- }
162
- if (squadPRs.length > 0) {
163
- const drafts = squadPRs.filter(pr => pr.draft).length;
164
- const ready = squadPRs.length - drafts;
165
- if (drafts > 0) summary.push(`🟡 **${drafts} draft PR(s)** in progress`);
166
- if (ready > 0) summary.push(`🟢 **${ready} PR(s)** open for review/merge`);
167
- }
168
-
169
- if (summary.length === 0) {
170
- core.info('📋 Board is clear — Ralph found no pending work');
171
- return;
172
- }
173
-
174
- core.info(`🔄 Ralph found work:\n${summary.join('\n')}`);
175
-
176
- // Auto-triage untriaged issues
177
- for (const issue of untriaged) {
178
- const issueText = `${issue.title}\n${issue.body || ''}`.toLowerCase();
179
- let assignedMember = null;
180
- let reason = '';
181
-
182
- // Simple keyword-based routing
183
- for (const member of members) {
184
- const role = member.role.toLowerCase();
185
- if ((role.includes('frontend') || role.includes('ui')) &&
186
- (issueText.includes('ui') || issueText.includes('frontend') ||
187
- issueText.includes('css') || issueText.includes('component'))) {
188
- assignedMember = member;
189
- reason = 'Matches frontend/UI domain';
190
- break;
191
- }
192
- if ((role.includes('backend') || role.includes('api') || role.includes('server')) &&
193
- (issueText.includes('api') || issueText.includes('backend') ||
194
- issueText.includes('database') || issueText.includes('endpoint'))) {
195
- assignedMember = member;
196
- reason = 'Matches backend/API domain';
197
- break;
198
- }
199
- if ((role.includes('test') || role.includes('qa')) &&
200
- (issueText.includes('test') || issueText.includes('bug') ||
201
- issueText.includes('fix') || issueText.includes('regression'))) {
202
- assignedMember = member;
203
- reason = 'Matches testing/QA domain';
204
- break;
205
- }
206
- }
207
-
208
- // Default to Lead
209
- if (!assignedMember) {
210
- const lead = members.find(m =>
211
- m.role.toLowerCase().includes('lead') ||
212
- m.role.toLowerCase().includes('architect')
213
- );
214
- if (lead) {
215
- assignedMember = lead;
216
- reason = 'No domain match — routed to Lead';
217
- }
218
- }
219
-
220
- if (assignedMember) {
221
- // Add member label
222
73
  await github.rest.issues.addLabels({
223
74
  owner: context.repo.owner,
224
75
  repo: context.repo.repo,
225
- issue_number: issue.number,
226
- labels: [assignedMember.label]
76
+ issue_number: decision.issueNumber,
77
+ labels: [decision.label]
227
78
  });
228
-
229
- // Post triage comment
79
+
230
80
  await github.rest.issues.createComment({
231
81
  owner: context.repo.owner,
232
82
  repo: context.repo.repo,
233
- issue_number: issue.number,
83
+ issue_number: decision.issueNumber,
234
84
  body: [
235
- `### 🔄 Ralph — Auto-Triage`,
85
+ '### 🔄 Ralph — Auto-Triage',
236
86
  '',
237
- `**Assigned to:** ${assignedMember.name} (${assignedMember.role})`,
238
- `**Reason:** ${reason}`,
87
+ `**Assigned to:** ${decision.assignTo}`,
88
+ `**Reason:** ${decision.reason}`,
89
+ `**Source:** ${decision.source}`,
239
90
  '',
240
- `> Ralph auto-triaged this issue via the squad heartbeat. To reassign, swap the \`squad:*\` label.`
91
+ '> Ralph auto-triaged this issue using routing rules.',
92
+ '> To reassign, swap the `squad:*` label.'
241
93
  ].join('\n')
242
94
  });
243
-
244
- core.info(`Auto-triaged #${issue.number} → ${assignedMember.name}`);
95
+
96
+ core.info(`Triaged #${decision.issueNumber} → ${decision.assignTo} (${decision.source})`);
97
+ } catch (e) {
98
+ core.warning(`Failed to triage #${decision.issueNumber}: ${e.message}`);
245
99
  }
246
100
  }
101
+
102
+ core.info(`🔄 Ralph triaged ${results.length} issue(s)`);
247
103
 
248
104
  # Copilot auto-assign step (uses PAT if available)
249
105
  - name: Ralph — Assign @copilot issues
@@ -50,7 +50,7 @@ jobs:
50
50
  run: |
51
51
  gh release create "${{ steps.version.outputs.insider_tag }}" \
52
52
  --title "${{ steps.version.outputs.insider_tag }}" \
53
- --notes "This is an insider/development build of Squad. Install with:\`\`\`bash\nnpx github:bradygaster/squad#${{ steps.version.outputs.insider_tag }}\n\`\`\`\n\n**Note:** Insider builds may be unstable and are intended for early adopters and testing only." \
53
+ --notes "This is an insider/development build of Squad. Install with:\`\`\`bash\nnpm install -g @bradygaster/squad-cli@${{ steps.version.outputs.insider_tag }}\n\`\`\`\n\n**Note:** Insider builds may be unstable and are intended for early adopters and testing only." \
54
54
  --prerelease
55
55
 
56
56
  - name: Verify release