@bradygaster/squad-sdk 0.8.25 → 0.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +296 -296
- package/dist/adapter/client.d.ts +17 -0
- package/dist/adapter/client.d.ts.map +1 -1
- package/dist/adapter/client.js +101 -1
- package/dist/adapter/client.js.map +1 -1
- package/dist/agents/history-shadow.d.ts.map +1 -1
- package/dist/agents/history-shadow.js +129 -62
- package/dist/agents/history-shadow.js.map +1 -1
- package/dist/agents/index.d.ts +1 -0
- package/dist/agents/index.d.ts.map +1 -1
- package/dist/agents/index.js +2 -0
- package/dist/agents/index.js.map +1 -1
- package/dist/agents/model-selector.d.ts +2 -0
- package/dist/agents/model-selector.d.ts.map +1 -1
- package/dist/agents/model-selector.js +41 -35
- package/dist/agents/model-selector.js.map +1 -1
- package/dist/agents/personal.d.ts +35 -0
- package/dist/agents/personal.d.ts.map +1 -0
- package/dist/agents/personal.js +67 -0
- package/dist/agents/personal.js.map +1 -0
- package/dist/build/github-dist.js +42 -42
- package/dist/builders/index.d.ts +3 -2
- package/dist/builders/index.d.ts.map +1 -1
- package/dist/builders/index.js +28 -0
- package/dist/builders/index.js.map +1 -1
- package/dist/builders/types.d.ts +13 -0
- package/dist/builders/types.d.ts.map +1 -1
- package/dist/config/init.d.ts +8 -0
- package/dist/config/init.d.ts.map +1 -1
- package/dist/config/init.js +304 -193
- package/dist/config/init.js.map +1 -1
- package/dist/config/models.d.ts +112 -0
- package/dist/config/models.d.ts.map +1 -1
- package/dist/config/models.js +329 -18
- package/dist/config/models.js.map +1 -1
- package/dist/coordinator/index.js +2 -2
- package/dist/coordinator/index.js.map +1 -1
- package/dist/index.d.ts +8 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -2
- package/dist/index.js.map +1 -1
- package/dist/platform/azure-devops.d.ts +42 -0
- package/dist/platform/azure-devops.d.ts.map +1 -1
- package/dist/platform/azure-devops.js +75 -0
- package/dist/platform/azure-devops.js.map +1 -1
- package/dist/platform/comms-file-log.d.ts.map +1 -1
- package/dist/platform/comms-file-log.js +2 -1
- package/dist/platform/comms-file-log.js.map +1 -1
- package/dist/platform/index.d.ts +2 -1
- package/dist/platform/index.d.ts.map +1 -1
- package/dist/platform/index.js +1 -0
- package/dist/platform/index.js.map +1 -1
- package/dist/ralph/capabilities.d.ts +67 -0
- package/dist/ralph/capabilities.d.ts.map +1 -0
- package/dist/ralph/capabilities.js +111 -0
- package/dist/ralph/capabilities.js.map +1 -0
- package/dist/ralph/index.d.ts +2 -0
- package/dist/ralph/index.d.ts.map +1 -1
- package/dist/ralph/index.js +6 -5
- package/dist/ralph/index.js.map +1 -1
- package/dist/ralph/rate-limiting.d.ts +99 -0
- package/dist/ralph/rate-limiting.d.ts.map +1 -0
- package/dist/ralph/rate-limiting.js +170 -0
- package/dist/ralph/rate-limiting.js.map +1 -0
- package/dist/resolution.d.ts +24 -2
- package/dist/resolution.d.ts.map +1 -1
- package/dist/resolution.js +106 -6
- package/dist/resolution.js.map +1 -1
- package/dist/roles/catalog-categories.d.ts +146 -0
- package/dist/roles/catalog-categories.d.ts.map +1 -0
- package/dist/roles/catalog-categories.js +374 -0
- package/dist/roles/catalog-categories.js.map +1 -0
- package/dist/roles/catalog-engineering.d.ts +212 -0
- package/dist/roles/catalog-engineering.d.ts.map +1 -0
- package/dist/roles/catalog-engineering.js +549 -0
- package/dist/roles/catalog-engineering.js.map +1 -0
- package/dist/roles/catalog.d.ts +24 -0
- package/dist/roles/catalog.d.ts.map +1 -0
- package/dist/roles/catalog.js +28 -0
- package/dist/roles/catalog.js.map +1 -0
- package/dist/roles/index.d.ts +69 -0
- package/dist/roles/index.d.ts.map +1 -0
- package/dist/roles/index.js +197 -0
- package/dist/roles/index.js.map +1 -0
- package/dist/roles/types.d.ts +87 -0
- package/dist/roles/types.d.ts.map +1 -0
- package/dist/roles/types.js +14 -0
- package/dist/roles/types.js.map +1 -0
- package/dist/runtime/benchmarks.js +5 -5
- package/dist/runtime/benchmarks.js.map +1 -1
- package/dist/runtime/constants.d.ts +2 -2
- package/dist/runtime/constants.d.ts.map +1 -1
- package/dist/runtime/constants.js +5 -3
- package/dist/runtime/constants.js.map +1 -1
- package/dist/runtime/cross-squad.d.ts +118 -0
- package/dist/runtime/cross-squad.d.ts.map +1 -0
- package/dist/runtime/cross-squad.js +234 -0
- package/dist/runtime/cross-squad.js.map +1 -0
- package/dist/runtime/otel-init.d.ts +24 -17
- package/dist/runtime/otel-init.d.ts.map +1 -1
- package/dist/runtime/otel-init.js +29 -20
- package/dist/runtime/otel-init.js.map +1 -1
- package/dist/runtime/otel-metrics.d.ts +5 -0
- package/dist/runtime/otel-metrics.d.ts.map +1 -1
- package/dist/runtime/otel-metrics.js +54 -0
- package/dist/runtime/otel-metrics.js.map +1 -1
- package/dist/runtime/rework.d.ts +71 -0
- package/dist/runtime/rework.d.ts.map +1 -0
- package/dist/runtime/rework.js +107 -0
- package/dist/runtime/rework.js.map +1 -0
- package/dist/runtime/scheduler.d.ts +128 -0
- package/dist/runtime/scheduler.d.ts.map +1 -0
- package/dist/runtime/scheduler.js +427 -0
- package/dist/runtime/scheduler.js.map +1 -0
- package/dist/runtime/squad-observer.d.ts.map +1 -1
- package/dist/runtime/squad-observer.js +4 -0
- package/dist/runtime/squad-observer.js.map +1 -1
- package/dist/runtime/streaming.d.ts +2 -0
- package/dist/runtime/streaming.d.ts.map +1 -1
- package/dist/runtime/streaming.js +6 -0
- package/dist/runtime/streaming.js.map +1 -1
- package/dist/runtime/telemetry.d.ts +2 -0
- package/dist/runtime/telemetry.d.ts.map +1 -1
- package/dist/runtime/telemetry.js +6 -0
- package/dist/runtime/telemetry.js.map +1 -1
- package/dist/sharing/consult.d.ts +2 -2
- package/dist/sharing/consult.js +83 -83
- package/dist/sharing/consult.js.map +1 -1
- package/dist/sharing/export.d.ts.map +1 -1
- package/dist/sharing/export.js +17 -4
- package/dist/sharing/export.js.map +1 -1
- package/dist/skills/handler-types.d.ts +271 -0
- package/dist/skills/handler-types.d.ts.map +1 -0
- package/dist/skills/handler-types.js +31 -0
- package/dist/skills/handler-types.js.map +1 -0
- package/dist/skills/index.d.ts +3 -0
- package/dist/skills/index.d.ts.map +1 -1
- package/dist/skills/index.js +3 -0
- package/dist/skills/index.js.map +1 -1
- package/dist/skills/skill-script-loader.d.ts +65 -0
- package/dist/skills/skill-script-loader.d.ts.map +1 -0
- package/dist/skills/skill-script-loader.js +227 -0
- package/dist/skills/skill-script-loader.js.map +1 -0
- package/dist/skills/skill-source.d.ts.map +1 -1
- package/dist/skills/skill-source.js +5 -1
- package/dist/skills/skill-source.js.map +1 -1
- package/dist/tools/index.d.ts +10 -1
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +49 -8
- package/dist/tools/index.js.map +1 -1
- package/dist/upstream/resolver.d.ts.map +1 -1
- package/dist/upstream/resolver.js +14 -5
- package/dist/upstream/resolver.js.map +1 -1
- package/package.json +34 -3
- package/templates/casting/Futurama.json +10 -0
- package/templates/casting-history.json +4 -4
- package/templates/casting-policy.json +37 -35
- package/templates/casting-reference.md +104 -0
- package/templates/casting-registry.json +3 -3
- package/templates/ceremonies.md +41 -41
- package/templates/charter.md +53 -53
- package/templates/constraint-tracking.md +38 -38
- package/templates/cooperative-rate-limiting.md +229 -0
- package/templates/copilot-instructions.md +46 -46
- package/templates/history.md +10 -10
- package/templates/identity/now.md +9 -9
- package/templates/identity/wisdom.md +15 -15
- package/templates/issue-lifecycle.md +412 -0
- package/templates/keda-scaler.md +164 -0
- package/templates/machine-capabilities.md +75 -0
- package/templates/mcp-config.md +90 -98
- package/templates/multi-agent-format.md +28 -28
- package/templates/orchestration-log.md +27 -27
- package/templates/package.json +3 -0
- package/templates/plugin-marketplace.md +49 -49
- package/templates/ralph-circuit-breaker.md +313 -0
- package/templates/ralph-triage.js +543 -0
- package/templates/raw-agent-output.md +37 -37
- package/templates/roster.md +60 -60
- package/templates/routing.md +39 -54
- package/templates/run-output.md +50 -50
- package/templates/schedule.json +19 -0
- package/templates/scribe-charter.md +119 -119
- package/templates/skill.md +24 -24
- package/templates/skills/agent-collaboration/SKILL.md +42 -0
- package/templates/skills/agent-conduct/SKILL.md +24 -0
- package/templates/skills/architectural-proposals/SKILL.md +151 -0
- package/templates/skills/ci-validation-gates/SKILL.md +84 -0
- package/templates/skills/cli-wiring/SKILL.md +47 -0
- package/templates/skills/client-compatibility/SKILL.md +89 -0
- package/templates/skills/cross-squad/SKILL.md +114 -0
- package/templates/skills/distributed-mesh/SKILL.md +287 -0
- package/templates/skills/distributed-mesh/mesh.json.example +30 -0
- package/templates/skills/distributed-mesh/sync-mesh.ps1 +111 -0
- package/templates/skills/distributed-mesh/sync-mesh.sh +104 -0
- package/templates/skills/docs-standards/SKILL.md +71 -0
- package/templates/skills/economy-mode/SKILL.md +114 -0
- package/templates/skills/external-comms/SKILL.md +329 -0
- package/templates/skills/gh-auth-isolation/SKILL.md +183 -0
- package/templates/skills/git-workflow/SKILL.md +204 -0
- package/templates/skills/github-multi-account/SKILL.md +95 -0
- package/templates/skills/history-hygiene/SKILL.md +36 -0
- package/templates/skills/humanizer/SKILL.md +105 -0
- package/templates/skills/init-mode/SKILL.md +102 -0
- package/templates/skills/model-selection/SKILL.md +117 -0
- package/templates/skills/nap/SKILL.md +24 -0
- package/templates/skills/personal-squad/SKILL.md +57 -0
- package/templates/skills/project-conventions/SKILL.md +56 -56
- package/templates/skills/release-process/SKILL.md +423 -0
- package/templates/skills/reskill/SKILL.md +92 -0
- package/templates/skills/reviewer-protocol/SKILL.md +79 -0
- package/templates/skills/secret-handling/SKILL.md +200 -0
- package/templates/skills/session-recovery/SKILL.md +155 -0
- package/templates/skills/squad-conventions/SKILL.md +69 -0
- package/templates/skills/test-discipline/SKILL.md +37 -0
- package/templates/skills/windows-compatibility/SKILL.md +74 -0
- package/templates/squad.agent.md +1287 -1146
- package/templates/workflows/squad-ci.yml +24 -24
- package/templates/workflows/squad-docs.yml +54 -50
- package/templates/workflows/squad-heartbeat.yml +171 -316
- package/templates/workflows/squad-insider-release.yml +61 -61
- package/templates/workflows/squad-issue-assign.yml +161 -161
- package/templates/workflows/squad-label-enforce.yml +181 -181
- package/templates/workflows/squad-preview.yml +55 -55
- package/templates/workflows/squad-promote.yml +120 -120
- package/templates/workflows/squad-release.yml +77 -77
- package/templates/workflows/squad-triage.yml +260 -260
- package/templates/workflows/sync-squad-labels.yml +169 -169
|
@@ -1,24 +1,24 @@
|
|
|
1
|
-
name: Squad CI
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
pull_request:
|
|
5
|
-
branches: [dev, preview, main, insider]
|
|
6
|
-
types: [opened, synchronize, reopened]
|
|
7
|
-
push:
|
|
8
|
-
branches: [dev, insider]
|
|
9
|
-
|
|
10
|
-
permissions:
|
|
11
|
-
contents: read
|
|
12
|
-
|
|
13
|
-
jobs:
|
|
14
|
-
test:
|
|
15
|
-
runs-on: ubuntu-latest
|
|
16
|
-
steps:
|
|
17
|
-
- uses: actions/checkout@v4
|
|
18
|
-
|
|
19
|
-
- uses: actions/setup-node@v4
|
|
20
|
-
with:
|
|
21
|
-
node-version: 22
|
|
22
|
-
|
|
23
|
-
- name: Run tests
|
|
24
|
-
run: node --test test/*.test.js
|
|
1
|
+
name: Squad CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
pull_request:
|
|
5
|
+
branches: [dev, preview, main, insider]
|
|
6
|
+
types: [opened, synchronize, reopened]
|
|
7
|
+
push:
|
|
8
|
+
branches: [dev, insider]
|
|
9
|
+
|
|
10
|
+
permissions:
|
|
11
|
+
contents: read
|
|
12
|
+
|
|
13
|
+
jobs:
|
|
14
|
+
test:
|
|
15
|
+
runs-on: ubuntu-latest
|
|
16
|
+
steps:
|
|
17
|
+
- uses: actions/checkout@v4
|
|
18
|
+
|
|
19
|
+
- uses: actions/setup-node@v4
|
|
20
|
+
with:
|
|
21
|
+
node-version: 22
|
|
22
|
+
|
|
23
|
+
- name: Run tests
|
|
24
|
+
run: node --test test/*.test.js
|
|
@@ -1,50 +1,54 @@
|
|
|
1
|
-
name: Squad Docs — Build & Deploy
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
workflow_dispatch:
|
|
5
|
-
push:
|
|
6
|
-
branches: [preview]
|
|
7
|
-
paths:
|
|
8
|
-
- 'docs/**'
|
|
9
|
-
- '.github/workflows/squad-docs.yml'
|
|
10
|
-
|
|
11
|
-
permissions:
|
|
12
|
-
contents: read
|
|
13
|
-
pages: write
|
|
14
|
-
id-token: write
|
|
15
|
-
|
|
16
|
-
concurrency:
|
|
17
|
-
group: pages
|
|
18
|
-
cancel-in-progress: true
|
|
19
|
-
|
|
20
|
-
jobs:
|
|
21
|
-
build:
|
|
22
|
-
runs-on: ubuntu-latest
|
|
23
|
-
steps:
|
|
24
|
-
- uses: actions/checkout@v4
|
|
25
|
-
|
|
26
|
-
- uses: actions/setup-node@v4
|
|
27
|
-
with:
|
|
28
|
-
node-version: '22'
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
run:
|
|
35
|
-
|
|
36
|
-
- name:
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
1
|
+
name: Squad Docs — Build & Deploy
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
workflow_dispatch:
|
|
5
|
+
push:
|
|
6
|
+
branches: [preview]
|
|
7
|
+
paths:
|
|
8
|
+
- 'docs/**'
|
|
9
|
+
- '.github/workflows/squad-docs.yml'
|
|
10
|
+
|
|
11
|
+
permissions:
|
|
12
|
+
contents: read
|
|
13
|
+
pages: write
|
|
14
|
+
id-token: write
|
|
15
|
+
|
|
16
|
+
concurrency:
|
|
17
|
+
group: pages
|
|
18
|
+
cancel-in-progress: true
|
|
19
|
+
|
|
20
|
+
jobs:
|
|
21
|
+
build:
|
|
22
|
+
runs-on: ubuntu-latest
|
|
23
|
+
steps:
|
|
24
|
+
- uses: actions/checkout@v4
|
|
25
|
+
|
|
26
|
+
- uses: actions/setup-node@v4
|
|
27
|
+
with:
|
|
28
|
+
node-version: '22'
|
|
29
|
+
cache: npm
|
|
30
|
+
cache-dependency-path: docs/package-lock.json
|
|
31
|
+
|
|
32
|
+
- name: Install docs dependencies
|
|
33
|
+
working-directory: docs
|
|
34
|
+
run: npm ci
|
|
35
|
+
|
|
36
|
+
- name: Build docs site
|
|
37
|
+
working-directory: docs
|
|
38
|
+
run: npm run build
|
|
39
|
+
|
|
40
|
+
- name: Upload Pages artifact
|
|
41
|
+
uses: actions/upload-pages-artifact@v3
|
|
42
|
+
with:
|
|
43
|
+
path: docs/dist
|
|
44
|
+
|
|
45
|
+
deploy:
|
|
46
|
+
needs: build
|
|
47
|
+
runs-on: ubuntu-latest
|
|
48
|
+
environment:
|
|
49
|
+
name: github-pages
|
|
50
|
+
url: ${{ steps.deployment.outputs.page_url }}
|
|
51
|
+
steps:
|
|
52
|
+
- name: Deploy to GitHub Pages
|
|
53
|
+
id: deployment
|
|
54
|
+
uses: actions/deploy-pages@v4
|
|
@@ -1,316 +1,171 @@
|
|
|
1
|
-
name: Squad Heartbeat (Ralph)
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
const
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
return;
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
core.info(`🔄 Ralph found work:\n${summary.join('\n')}`);
|
|
176
|
-
|
|
177
|
-
// Auto-triage untriaged issues
|
|
178
|
-
for (const issue of untriaged) {
|
|
179
|
-
const issueText = `${issue.title}\n${issue.body || ''}`.toLowerCase();
|
|
180
|
-
let assignedMember = null;
|
|
181
|
-
let reason = '';
|
|
182
|
-
|
|
183
|
-
// Simple keyword-based routing
|
|
184
|
-
for (const member of members) {
|
|
185
|
-
const role = member.role.toLowerCase();
|
|
186
|
-
if ((role.includes('frontend') || role.includes('ui')) &&
|
|
187
|
-
(issueText.includes('ui') || issueText.includes('frontend') ||
|
|
188
|
-
issueText.includes('css') || issueText.includes('component'))) {
|
|
189
|
-
assignedMember = member;
|
|
190
|
-
reason = 'Matches frontend/UI domain';
|
|
191
|
-
break;
|
|
192
|
-
}
|
|
193
|
-
if ((role.includes('backend') || role.includes('api') || role.includes('server')) &&
|
|
194
|
-
(issueText.includes('api') || issueText.includes('backend') ||
|
|
195
|
-
issueText.includes('database') || issueText.includes('endpoint'))) {
|
|
196
|
-
assignedMember = member;
|
|
197
|
-
reason = 'Matches backend/API domain';
|
|
198
|
-
break;
|
|
199
|
-
}
|
|
200
|
-
if ((role.includes('test') || role.includes('qa')) &&
|
|
201
|
-
(issueText.includes('test') || issueText.includes('bug') ||
|
|
202
|
-
issueText.includes('fix') || issueText.includes('regression'))) {
|
|
203
|
-
assignedMember = member;
|
|
204
|
-
reason = 'Matches testing/QA domain';
|
|
205
|
-
break;
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
// Default to Lead
|
|
210
|
-
if (!assignedMember) {
|
|
211
|
-
const lead = members.find(m =>
|
|
212
|
-
m.role.toLowerCase().includes('lead') ||
|
|
213
|
-
m.role.toLowerCase().includes('architect')
|
|
214
|
-
);
|
|
215
|
-
if (lead) {
|
|
216
|
-
assignedMember = lead;
|
|
217
|
-
reason = 'No domain match — routed to Lead';
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
if (assignedMember) {
|
|
222
|
-
// Add member label
|
|
223
|
-
await github.rest.issues.addLabels({
|
|
224
|
-
owner: context.repo.owner,
|
|
225
|
-
repo: context.repo.repo,
|
|
226
|
-
issue_number: issue.number,
|
|
227
|
-
labels: [assignedMember.label]
|
|
228
|
-
});
|
|
229
|
-
|
|
230
|
-
// Post triage comment
|
|
231
|
-
await github.rest.issues.createComment({
|
|
232
|
-
owner: context.repo.owner,
|
|
233
|
-
repo: context.repo.repo,
|
|
234
|
-
issue_number: issue.number,
|
|
235
|
-
body: [
|
|
236
|
-
`### 🔄 Ralph — Auto-Triage`,
|
|
237
|
-
'',
|
|
238
|
-
`**Assigned to:** ${assignedMember.name} (${assignedMember.role})`,
|
|
239
|
-
`**Reason:** ${reason}`,
|
|
240
|
-
'',
|
|
241
|
-
`> Ralph auto-triaged this issue via the squad heartbeat. To reassign, swap the \`squad:*\` label.`
|
|
242
|
-
].join('\n')
|
|
243
|
-
});
|
|
244
|
-
|
|
245
|
-
core.info(`Auto-triaged #${issue.number} → ${assignedMember.name}`);
|
|
246
|
-
}
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
# Copilot auto-assign step (uses PAT if available)
|
|
250
|
-
- name: Ralph — Assign @copilot issues
|
|
251
|
-
if: success()
|
|
252
|
-
uses: actions/github-script@v7
|
|
253
|
-
with:
|
|
254
|
-
github-token: ${{ secrets.COPILOT_ASSIGN_TOKEN || secrets.GITHUB_TOKEN }}
|
|
255
|
-
script: |
|
|
256
|
-
const fs = require('fs');
|
|
257
|
-
|
|
258
|
-
let teamFile = '.squad/team.md';
|
|
259
|
-
if (!fs.existsSync(teamFile)) {
|
|
260
|
-
teamFile = '.ai-team/team.md';
|
|
261
|
-
}
|
|
262
|
-
if (!fs.existsSync(teamFile)) return;
|
|
263
|
-
|
|
264
|
-
const content = fs.readFileSync(teamFile, 'utf8');
|
|
265
|
-
|
|
266
|
-
// Check if @copilot is on the team with auto-assign
|
|
267
|
-
const hasCopilot = content.includes('🤖 Coding Agent') || content.includes('@copilot');
|
|
268
|
-
const autoAssign = content.includes('<!-- copilot-auto-assign: true -->');
|
|
269
|
-
if (!hasCopilot || !autoAssign) return;
|
|
270
|
-
|
|
271
|
-
// Find issues labeled squad:copilot with no assignee
|
|
272
|
-
try {
|
|
273
|
-
const { data: copilotIssues } = await github.rest.issues.listForRepo({
|
|
274
|
-
owner: context.repo.owner,
|
|
275
|
-
repo: context.repo.repo,
|
|
276
|
-
labels: 'squad:copilot',
|
|
277
|
-
state: 'open',
|
|
278
|
-
per_page: 5
|
|
279
|
-
});
|
|
280
|
-
|
|
281
|
-
const unassigned = copilotIssues.filter(i =>
|
|
282
|
-
!i.assignees || i.assignees.length === 0
|
|
283
|
-
);
|
|
284
|
-
|
|
285
|
-
if (unassigned.length === 0) {
|
|
286
|
-
core.info('No unassigned squad:copilot issues');
|
|
287
|
-
return;
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
// Get repo default branch
|
|
291
|
-
const { data: repoData } = await github.rest.repos.get({
|
|
292
|
-
owner: context.repo.owner,
|
|
293
|
-
repo: context.repo.repo
|
|
294
|
-
});
|
|
295
|
-
|
|
296
|
-
for (const issue of unassigned) {
|
|
297
|
-
try {
|
|
298
|
-
await github.request('POST /repos/{owner}/{repo}/issues/{issue_number}/assignees', {
|
|
299
|
-
owner: context.repo.owner,
|
|
300
|
-
repo: context.repo.repo,
|
|
301
|
-
issue_number: issue.number,
|
|
302
|
-
assignees: ['copilot-swe-agent[bot]'],
|
|
303
|
-
agent_assignment: {
|
|
304
|
-
target_repo: `${context.repo.owner}/${context.repo.repo}`,
|
|
305
|
-
base_branch: repoData.default_branch,
|
|
306
|
-
custom_instructions: `Read .squad/team.md (or .ai-team/team.md) for team context and .squad/routing.md (or .ai-team/routing.md) for routing rules.`
|
|
307
|
-
}
|
|
308
|
-
});
|
|
309
|
-
core.info(`Assigned copilot-swe-agent[bot] to #${issue.number}`);
|
|
310
|
-
} catch (e) {
|
|
311
|
-
core.warning(`Failed to assign @copilot to #${issue.number}: ${e.message}`);
|
|
312
|
-
}
|
|
313
|
-
}
|
|
314
|
-
} catch (e) {
|
|
315
|
-
core.info(`No squad:copilot label found or error: ${e.message}`);
|
|
316
|
-
}
|
|
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.
|
|
8
|
+
|
|
9
|
+
on:
|
|
10
|
+
schedule:
|
|
11
|
+
# Every 30 minutes — adjust via cron expression as needed
|
|
12
|
+
- cron: '*/30 * * * *'
|
|
13
|
+
|
|
14
|
+
# React to completed work or new squad work
|
|
15
|
+
issues:
|
|
16
|
+
types: [closed, labeled]
|
|
17
|
+
pull_request:
|
|
18
|
+
types: [closed]
|
|
19
|
+
|
|
20
|
+
# Manual trigger
|
|
21
|
+
workflow_dispatch:
|
|
22
|
+
|
|
23
|
+
permissions:
|
|
24
|
+
issues: write
|
|
25
|
+
contents: read
|
|
26
|
+
pull-requests: read
|
|
27
|
+
|
|
28
|
+
jobs:
|
|
29
|
+
heartbeat:
|
|
30
|
+
runs-on: ubuntu-latest
|
|
31
|
+
steps:
|
|
32
|
+
- uses: actions/checkout@v4
|
|
33
|
+
|
|
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') != ''
|
|
55
|
+
uses: actions/github-script@v7
|
|
56
|
+
with:
|
|
57
|
+
script: |
|
|
58
|
+
const fs = require('fs');
|
|
59
|
+
const path = 'triage-results.json';
|
|
60
|
+
if (!fs.existsSync(path)) {
|
|
61
|
+
core.info('No triage results — board is clear');
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
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');
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
for (const decision of results) {
|
|
72
|
+
try {
|
|
73
|
+
await github.rest.issues.addLabels({
|
|
74
|
+
owner: context.repo.owner,
|
|
75
|
+
repo: context.repo.repo,
|
|
76
|
+
issue_number: decision.issueNumber,
|
|
77
|
+
labels: [decision.label]
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
await github.rest.issues.createComment({
|
|
81
|
+
owner: context.repo.owner,
|
|
82
|
+
repo: context.repo.repo,
|
|
83
|
+
issue_number: decision.issueNumber,
|
|
84
|
+
body: [
|
|
85
|
+
'### 🔄 Ralph — Auto-Triage',
|
|
86
|
+
'',
|
|
87
|
+
`**Assigned to:** ${decision.assignTo}`,
|
|
88
|
+
`**Reason:** ${decision.reason}`,
|
|
89
|
+
`**Source:** ${decision.source}`,
|
|
90
|
+
'',
|
|
91
|
+
'> Ralph auto-triaged this issue using routing rules.',
|
|
92
|
+
'> To reassign, swap the `squad:*` label.'
|
|
93
|
+
].join('\n')
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
core.info(`Triaged #${decision.issueNumber} → ${decision.assignTo} (${decision.source})`);
|
|
97
|
+
} catch (e) {
|
|
98
|
+
core.warning(`Failed to triage #${decision.issueNumber}: ${e.message}`);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
core.info(`🔄 Ralph triaged ${results.length} issue(s)`);
|
|
103
|
+
|
|
104
|
+
# Copilot auto-assign step (uses PAT if available)
|
|
105
|
+
- name: Ralph — Assign @copilot issues
|
|
106
|
+
if: success()
|
|
107
|
+
uses: actions/github-script@v7
|
|
108
|
+
with:
|
|
109
|
+
github-token: ${{ secrets.COPILOT_ASSIGN_TOKEN || secrets.GITHUB_TOKEN }}
|
|
110
|
+
script: |
|
|
111
|
+
const fs = require('fs');
|
|
112
|
+
|
|
113
|
+
let teamFile = '.squad/team.md';
|
|
114
|
+
if (!fs.existsSync(teamFile)) {
|
|
115
|
+
teamFile = '.ai-team/team.md';
|
|
116
|
+
}
|
|
117
|
+
if (!fs.existsSync(teamFile)) return;
|
|
118
|
+
|
|
119
|
+
const content = fs.readFileSync(teamFile, 'utf8');
|
|
120
|
+
|
|
121
|
+
// Check if @copilot is on the team with auto-assign
|
|
122
|
+
const hasCopilot = content.includes('🤖 Coding Agent') || content.includes('@copilot');
|
|
123
|
+
const autoAssign = content.includes('<!-- copilot-auto-assign: true -->');
|
|
124
|
+
if (!hasCopilot || !autoAssign) return;
|
|
125
|
+
|
|
126
|
+
// Find issues labeled squad:copilot with no assignee
|
|
127
|
+
try {
|
|
128
|
+
const { data: copilotIssues } = await github.rest.issues.listForRepo({
|
|
129
|
+
owner: context.repo.owner,
|
|
130
|
+
repo: context.repo.repo,
|
|
131
|
+
labels: 'squad:copilot',
|
|
132
|
+
state: 'open',
|
|
133
|
+
per_page: 5
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
const unassigned = copilotIssues.filter(i =>
|
|
137
|
+
!i.assignees || i.assignees.length === 0
|
|
138
|
+
);
|
|
139
|
+
|
|
140
|
+
if (unassigned.length === 0) {
|
|
141
|
+
core.info('No unassigned squad:copilot issues');
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// Get repo default branch
|
|
146
|
+
const { data: repoData } = await github.rest.repos.get({
|
|
147
|
+
owner: context.repo.owner,
|
|
148
|
+
repo: context.repo.repo
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
for (const issue of unassigned) {
|
|
152
|
+
try {
|
|
153
|
+
await github.request('POST /repos/{owner}/{repo}/issues/{issue_number}/assignees', {
|
|
154
|
+
owner: context.repo.owner,
|
|
155
|
+
repo: context.repo.repo,
|
|
156
|
+
issue_number: issue.number,
|
|
157
|
+
assignees: ['copilot-swe-agent[bot]'],
|
|
158
|
+
agent_assignment: {
|
|
159
|
+
target_repo: `${context.repo.owner}/${context.repo.repo}`,
|
|
160
|
+
base_branch: repoData.default_branch,
|
|
161
|
+
custom_instructions: `Read .squad/team.md (or .ai-team/team.md) for team context and .squad/routing.md (or .ai-team/routing.md) for routing rules.`
|
|
162
|
+
}
|
|
163
|
+
});
|
|
164
|
+
core.info(`Assigned copilot-swe-agent[bot] to #${issue.number}`);
|
|
165
|
+
} catch (e) {
|
|
166
|
+
core.warning(`Failed to assign @copilot to #${issue.number}: ${e.message}`);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
} catch (e) {
|
|
170
|
+
core.info(`No squad:copilot label found or error: ${e.message}`);
|
|
171
|
+
}
|