@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.
- package/README.md +296 -296
- package/dist/adapter/client.js +1 -1
- package/dist/adapter/client.js.map +1 -1
- package/dist/agents/charter-compiler.d.ts +4 -0
- package/dist/agents/charter-compiler.d.ts.map +1 -1
- package/dist/agents/charter-compiler.js +8 -0
- package/dist/agents/charter-compiler.js.map +1 -1
- package/dist/agents/history-shadow.js +30 -30
- package/dist/agents/index.js +1 -1
- package/dist/agents/index.js.map +1 -1
- package/dist/agents/lifecycle.js +1 -1
- package/dist/agents/lifecycle.js.map +1 -1
- package/dist/build/github-dist.js +42 -42
- package/dist/builders/index.d.ts +156 -0
- package/dist/builders/index.d.ts.map +1 -0
- package/dist/builders/index.js +404 -0
- package/dist/builders/index.js.map +1 -0
- package/dist/builders/types.d.ts +187 -0
- package/dist/builders/types.d.ts.map +1 -0
- package/dist/builders/types.js +12 -0
- package/dist/builders/types.js.map +1 -0
- package/dist/config/init.d.ts +5 -21
- package/dist/config/init.d.ts.map +1 -1
- package/dist/config/init.js +270 -182
- package/dist/config/init.js.map +1 -1
- package/dist/coordinator/coordinator.js +1 -1
- package/dist/coordinator/coordinator.js.map +1 -1
- package/dist/coordinator/index.js +1 -1
- package/dist/coordinator/index.js.map +1 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/runtime/otel-api.d.ts +38 -0
- package/dist/runtime/otel-api.d.ts.map +1 -0
- package/dist/runtime/otel-api.js +94 -0
- package/dist/runtime/otel-api.js.map +1 -0
- package/dist/runtime/otel-bridge.js +1 -1
- package/dist/runtime/otel-bridge.js.map +1 -1
- package/dist/runtime/otel.d.ts +1 -1
- package/dist/runtime/otel.d.ts.map +1 -1
- package/dist/runtime/otel.js +28 -12
- package/dist/runtime/otel.js.map +1 -1
- package/dist/runtime/squad-observer.js +1 -1
- package/dist/runtime/squad-observer.js.map +1 -1
- package/dist/sharing/consult.js +78 -78
- package/dist/streams/filter.d.ts +33 -0
- package/dist/streams/filter.d.ts.map +1 -0
- package/dist/streams/filter.js +29 -0
- package/dist/streams/filter.js.map +1 -0
- package/dist/streams/index.d.ts +9 -0
- package/dist/streams/index.d.ts.map +1 -0
- package/dist/streams/index.js +9 -0
- package/dist/streams/index.js.map +1 -0
- package/dist/streams/resolver.d.ts +40 -0
- package/dist/streams/resolver.d.ts.map +1 -0
- package/dist/streams/resolver.js +162 -0
- package/dist/streams/resolver.js.map +1 -0
- package/dist/streams/types.d.ts +44 -0
- package/dist/streams/types.d.ts.map +1 -0
- package/dist/streams/types.js +10 -0
- package/dist/streams/types.js.map +1 -0
- package/dist/tools/index.js +1 -1
- package/dist/tools/index.js.map +1 -1
- package/dist/types.d.ts +20 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +12 -11
- package/templates/casting-history.json +4 -4
- package/templates/casting-policy.json +35 -35
- 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/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/mcp-config.md +98 -98
- package/templates/multi-agent-format.md +28 -28
- package/templates/orchestration-log.md +27 -27
- package/templates/plugin-marketplace.md +49 -49
- package/templates/raw-agent-output.md +37 -37
- package/templates/roster.md +60 -60
- package/templates/routing.md +54 -54
- package/templates/run-output.md +50 -50
- package/templates/scribe-charter.md +119 -119
- package/templates/skill.md +24 -24
- package/templates/skills/project-conventions/SKILL.md +56 -56
- package/templates/squad.agent.md +1146 -1146
- package/templates/workflows/squad-ci.yml +24 -24
- package/templates/workflows/squad-docs.yml +50 -50
- package/templates/workflows/squad-heartbeat.yml +316 -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
- package/dist/runtime/event-bus-otel-bridge.d.ts +0 -19
- package/dist/runtime/event-bus-otel-bridge.d.ts.map +0 -1
- package/dist/runtime/event-bus-otel-bridge.js +0 -61
- package/dist/runtime/event-bus-otel-bridge.js.map +0 -1
- package/templates/workflows/squad-main-guard.yml +0 -129
|
@@ -1,169 +1,169 @@
|
|
|
1
|
-
name: Sync Squad Labels
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
push:
|
|
5
|
-
paths:
|
|
6
|
-
- '.squad/team.md'
|
|
7
|
-
- '.ai-team/team.md'
|
|
8
|
-
workflow_dispatch:
|
|
9
|
-
|
|
10
|
-
permissions:
|
|
11
|
-
issues: write
|
|
12
|
-
contents: read
|
|
13
|
-
|
|
14
|
-
jobs:
|
|
15
|
-
sync-labels:
|
|
16
|
-
runs-on: ubuntu-latest
|
|
17
|
-
steps:
|
|
18
|
-
- uses: actions/checkout@v4
|
|
19
|
-
|
|
20
|
-
- name: Parse roster and sync labels
|
|
21
|
-
uses: actions/github-script@v7
|
|
22
|
-
with:
|
|
23
|
-
script: |
|
|
24
|
-
const fs = require('fs');
|
|
25
|
-
let teamFile = '.squad/team.md';
|
|
26
|
-
if (!fs.existsSync(teamFile)) {
|
|
27
|
-
teamFile = '.ai-team/team.md';
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
if (!fs.existsSync(teamFile)) {
|
|
31
|
-
core.info('No .squad/team.md or .ai-team/team.md found — skipping label sync');
|
|
32
|
-
return;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
const content = fs.readFileSync(teamFile, 'utf8');
|
|
36
|
-
const lines = content.split('\n');
|
|
37
|
-
|
|
38
|
-
// Parse the Members table for agent names
|
|
39
|
-
const members = [];
|
|
40
|
-
let inMembersTable = false;
|
|
41
|
-
for (const line of lines) {
|
|
42
|
-
if (line.match(/^##\s+(Members|Team Roster)/i)) {
|
|
43
|
-
inMembersTable = true;
|
|
44
|
-
continue;
|
|
45
|
-
}
|
|
46
|
-
if (inMembersTable && line.startsWith('## ')) {
|
|
47
|
-
break;
|
|
48
|
-
}
|
|
49
|
-
if (inMembersTable && line.startsWith('|') && !line.includes('---') && !line.includes('Name')) {
|
|
50
|
-
const cells = line.split('|').map(c => c.trim()).filter(Boolean);
|
|
51
|
-
if (cells.length >= 2 && cells[0] !== 'Scribe') {
|
|
52
|
-
members.push({
|
|
53
|
-
name: cells[0],
|
|
54
|
-
role: cells[1]
|
|
55
|
-
});
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
core.info(`Found ${members.length} squad members: ${members.map(m => m.name).join(', ')}`);
|
|
61
|
-
|
|
62
|
-
// Check if @copilot is on the team
|
|
63
|
-
const hasCopilot = content.includes('🤖 Coding Agent');
|
|
64
|
-
|
|
65
|
-
// Define label color palette for squad labels
|
|
66
|
-
const SQUAD_COLOR = '9B8FCC';
|
|
67
|
-
const MEMBER_COLOR = '9B8FCC';
|
|
68
|
-
const COPILOT_COLOR = '10b981';
|
|
69
|
-
|
|
70
|
-
// Define go: and release: labels (static)
|
|
71
|
-
const GO_LABELS = [
|
|
72
|
-
{ name: 'go:yes', color: '0E8A16', description: 'Ready to implement' },
|
|
73
|
-
{ name: 'go:no', color: 'B60205', description: 'Not pursuing' },
|
|
74
|
-
{ name: 'go:needs-research', color: 'FBCA04', description: 'Needs investigation' }
|
|
75
|
-
];
|
|
76
|
-
|
|
77
|
-
const RELEASE_LABELS = [
|
|
78
|
-
{ name: 'release:v0.4.0', color: '6B8EB5', description: 'Targeted for v0.4.0' },
|
|
79
|
-
{ name: 'release:v0.5.0', color: '6B8EB5', description: 'Targeted for v0.5.0' },
|
|
80
|
-
{ name: 'release:v0.6.0', color: '8B7DB5', description: 'Targeted for v0.6.0' },
|
|
81
|
-
{ name: 'release:v1.0.0', color: '8B7DB5', description: 'Targeted for v1.0.0' },
|
|
82
|
-
{ name: 'release:backlog', color: 'D4E5F7', description: 'Not yet targeted' }
|
|
83
|
-
];
|
|
84
|
-
|
|
85
|
-
const TYPE_LABELS = [
|
|
86
|
-
{ name: 'type:feature', color: 'DDD1F2', description: 'New capability' },
|
|
87
|
-
{ name: 'type:bug', color: 'FF0422', description: 'Something broken' },
|
|
88
|
-
{ name: 'type:spike', color: 'F2DDD4', description: 'Research/investigation — produces a plan, not code' },
|
|
89
|
-
{ name: 'type:docs', color: 'D4E5F7', description: 'Documentation work' },
|
|
90
|
-
{ name: 'type:chore', color: 'D4E5F7', description: 'Maintenance, refactoring, cleanup' },
|
|
91
|
-
{ name: 'type:epic', color: 'CC4455', description: 'Parent issue that decomposes into sub-issues' }
|
|
92
|
-
];
|
|
93
|
-
|
|
94
|
-
// High-signal labels — these MUST visually dominate all others
|
|
95
|
-
const SIGNAL_LABELS = [
|
|
96
|
-
{ name: 'bug', color: 'FF0422', description: 'Something isn\'t working' },
|
|
97
|
-
{ name: 'feedback', color: '00E5FF', description: 'User feedback — high signal, needs attention' }
|
|
98
|
-
];
|
|
99
|
-
|
|
100
|
-
const PRIORITY_LABELS = [
|
|
101
|
-
{ name: 'priority:p0', color: 'B60205', description: 'Blocking release' },
|
|
102
|
-
{ name: 'priority:p1', color: 'D93F0B', description: 'This sprint' },
|
|
103
|
-
{ name: 'priority:p2', color: 'FBCA04', description: 'Next sprint' }
|
|
104
|
-
];
|
|
105
|
-
|
|
106
|
-
// Ensure the base "squad" triage label exists
|
|
107
|
-
const labels = [
|
|
108
|
-
{ name: 'squad', color: SQUAD_COLOR, description: 'Squad triage inbox — Lead will assign to a member' }
|
|
109
|
-
];
|
|
110
|
-
|
|
111
|
-
for (const member of members) {
|
|
112
|
-
labels.push({
|
|
113
|
-
name: `squad:${member.name.toLowerCase()}`,
|
|
114
|
-
color: MEMBER_COLOR,
|
|
115
|
-
description: `Assigned to ${member.name} (${member.role})`
|
|
116
|
-
});
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
// Add @copilot label if coding agent is on the team
|
|
120
|
-
if (hasCopilot) {
|
|
121
|
-
labels.push({
|
|
122
|
-
name: 'squad:copilot',
|
|
123
|
-
color: COPILOT_COLOR,
|
|
124
|
-
description: 'Assigned to @copilot (Coding Agent) for autonomous work'
|
|
125
|
-
});
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
// Add go:, release:, type:, priority:, and high-signal labels
|
|
129
|
-
labels.push(...GO_LABELS);
|
|
130
|
-
labels.push(...RELEASE_LABELS);
|
|
131
|
-
labels.push(...TYPE_LABELS);
|
|
132
|
-
labels.push(...PRIORITY_LABELS);
|
|
133
|
-
labels.push(...SIGNAL_LABELS);
|
|
134
|
-
|
|
135
|
-
// Sync labels (create or update)
|
|
136
|
-
for (const label of labels) {
|
|
137
|
-
try {
|
|
138
|
-
await github.rest.issues.getLabel({
|
|
139
|
-
owner: context.repo.owner,
|
|
140
|
-
repo: context.repo.repo,
|
|
141
|
-
name: label.name
|
|
142
|
-
});
|
|
143
|
-
// Label exists — update it
|
|
144
|
-
await github.rest.issues.updateLabel({
|
|
145
|
-
owner: context.repo.owner,
|
|
146
|
-
repo: context.repo.repo,
|
|
147
|
-
name: label.name,
|
|
148
|
-
color: label.color,
|
|
149
|
-
description: label.description
|
|
150
|
-
});
|
|
151
|
-
core.info(`Updated label: ${label.name}`);
|
|
152
|
-
} catch (err) {
|
|
153
|
-
if (err.status === 404) {
|
|
154
|
-
// Label doesn't exist — create it
|
|
155
|
-
await github.rest.issues.createLabel({
|
|
156
|
-
owner: context.repo.owner,
|
|
157
|
-
repo: context.repo.repo,
|
|
158
|
-
name: label.name,
|
|
159
|
-
color: label.color,
|
|
160
|
-
description: label.description
|
|
161
|
-
});
|
|
162
|
-
core.info(`Created label: ${label.name}`);
|
|
163
|
-
} else {
|
|
164
|
-
throw err;
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
core.info(`Label sync complete: ${labels.length} labels synced`);
|
|
1
|
+
name: Sync Squad Labels
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
paths:
|
|
6
|
+
- '.squad/team.md'
|
|
7
|
+
- '.ai-team/team.md'
|
|
8
|
+
workflow_dispatch:
|
|
9
|
+
|
|
10
|
+
permissions:
|
|
11
|
+
issues: write
|
|
12
|
+
contents: read
|
|
13
|
+
|
|
14
|
+
jobs:
|
|
15
|
+
sync-labels:
|
|
16
|
+
runs-on: ubuntu-latest
|
|
17
|
+
steps:
|
|
18
|
+
- uses: actions/checkout@v4
|
|
19
|
+
|
|
20
|
+
- name: Parse roster and sync labels
|
|
21
|
+
uses: actions/github-script@v7
|
|
22
|
+
with:
|
|
23
|
+
script: |
|
|
24
|
+
const fs = require('fs');
|
|
25
|
+
let teamFile = '.squad/team.md';
|
|
26
|
+
if (!fs.existsSync(teamFile)) {
|
|
27
|
+
teamFile = '.ai-team/team.md';
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if (!fs.existsSync(teamFile)) {
|
|
31
|
+
core.info('No .squad/team.md or .ai-team/team.md found — skipping label sync');
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const content = fs.readFileSync(teamFile, 'utf8');
|
|
36
|
+
const lines = content.split('\n');
|
|
37
|
+
|
|
38
|
+
// Parse the Members table for agent names
|
|
39
|
+
const members = [];
|
|
40
|
+
let inMembersTable = false;
|
|
41
|
+
for (const line of lines) {
|
|
42
|
+
if (line.match(/^##\s+(Members|Team Roster)/i)) {
|
|
43
|
+
inMembersTable = true;
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
if (inMembersTable && line.startsWith('## ')) {
|
|
47
|
+
break;
|
|
48
|
+
}
|
|
49
|
+
if (inMembersTable && line.startsWith('|') && !line.includes('---') && !line.includes('Name')) {
|
|
50
|
+
const cells = line.split('|').map(c => c.trim()).filter(Boolean);
|
|
51
|
+
if (cells.length >= 2 && cells[0] !== 'Scribe') {
|
|
52
|
+
members.push({
|
|
53
|
+
name: cells[0],
|
|
54
|
+
role: cells[1]
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
core.info(`Found ${members.length} squad members: ${members.map(m => m.name).join(', ')}`);
|
|
61
|
+
|
|
62
|
+
// Check if @copilot is on the team
|
|
63
|
+
const hasCopilot = content.includes('🤖 Coding Agent');
|
|
64
|
+
|
|
65
|
+
// Define label color palette for squad labels
|
|
66
|
+
const SQUAD_COLOR = '9B8FCC';
|
|
67
|
+
const MEMBER_COLOR = '9B8FCC';
|
|
68
|
+
const COPILOT_COLOR = '10b981';
|
|
69
|
+
|
|
70
|
+
// Define go: and release: labels (static)
|
|
71
|
+
const GO_LABELS = [
|
|
72
|
+
{ name: 'go:yes', color: '0E8A16', description: 'Ready to implement' },
|
|
73
|
+
{ name: 'go:no', color: 'B60205', description: 'Not pursuing' },
|
|
74
|
+
{ name: 'go:needs-research', color: 'FBCA04', description: 'Needs investigation' }
|
|
75
|
+
];
|
|
76
|
+
|
|
77
|
+
const RELEASE_LABELS = [
|
|
78
|
+
{ name: 'release:v0.4.0', color: '6B8EB5', description: 'Targeted for v0.4.0' },
|
|
79
|
+
{ name: 'release:v0.5.0', color: '6B8EB5', description: 'Targeted for v0.5.0' },
|
|
80
|
+
{ name: 'release:v0.6.0', color: '8B7DB5', description: 'Targeted for v0.6.0' },
|
|
81
|
+
{ name: 'release:v1.0.0', color: '8B7DB5', description: 'Targeted for v1.0.0' },
|
|
82
|
+
{ name: 'release:backlog', color: 'D4E5F7', description: 'Not yet targeted' }
|
|
83
|
+
];
|
|
84
|
+
|
|
85
|
+
const TYPE_LABELS = [
|
|
86
|
+
{ name: 'type:feature', color: 'DDD1F2', description: 'New capability' },
|
|
87
|
+
{ name: 'type:bug', color: 'FF0422', description: 'Something broken' },
|
|
88
|
+
{ name: 'type:spike', color: 'F2DDD4', description: 'Research/investigation — produces a plan, not code' },
|
|
89
|
+
{ name: 'type:docs', color: 'D4E5F7', description: 'Documentation work' },
|
|
90
|
+
{ name: 'type:chore', color: 'D4E5F7', description: 'Maintenance, refactoring, cleanup' },
|
|
91
|
+
{ name: 'type:epic', color: 'CC4455', description: 'Parent issue that decomposes into sub-issues' }
|
|
92
|
+
];
|
|
93
|
+
|
|
94
|
+
// High-signal labels — these MUST visually dominate all others
|
|
95
|
+
const SIGNAL_LABELS = [
|
|
96
|
+
{ name: 'bug', color: 'FF0422', description: 'Something isn\'t working' },
|
|
97
|
+
{ name: 'feedback', color: '00E5FF', description: 'User feedback — high signal, needs attention' }
|
|
98
|
+
];
|
|
99
|
+
|
|
100
|
+
const PRIORITY_LABELS = [
|
|
101
|
+
{ name: 'priority:p0', color: 'B60205', description: 'Blocking release' },
|
|
102
|
+
{ name: 'priority:p1', color: 'D93F0B', description: 'This sprint' },
|
|
103
|
+
{ name: 'priority:p2', color: 'FBCA04', description: 'Next sprint' }
|
|
104
|
+
];
|
|
105
|
+
|
|
106
|
+
// Ensure the base "squad" triage label exists
|
|
107
|
+
const labels = [
|
|
108
|
+
{ name: 'squad', color: SQUAD_COLOR, description: 'Squad triage inbox — Lead will assign to a member' }
|
|
109
|
+
];
|
|
110
|
+
|
|
111
|
+
for (const member of members) {
|
|
112
|
+
labels.push({
|
|
113
|
+
name: `squad:${member.name.toLowerCase()}`,
|
|
114
|
+
color: MEMBER_COLOR,
|
|
115
|
+
description: `Assigned to ${member.name} (${member.role})`
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// Add @copilot label if coding agent is on the team
|
|
120
|
+
if (hasCopilot) {
|
|
121
|
+
labels.push({
|
|
122
|
+
name: 'squad:copilot',
|
|
123
|
+
color: COPILOT_COLOR,
|
|
124
|
+
description: 'Assigned to @copilot (Coding Agent) for autonomous work'
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// Add go:, release:, type:, priority:, and high-signal labels
|
|
129
|
+
labels.push(...GO_LABELS);
|
|
130
|
+
labels.push(...RELEASE_LABELS);
|
|
131
|
+
labels.push(...TYPE_LABELS);
|
|
132
|
+
labels.push(...PRIORITY_LABELS);
|
|
133
|
+
labels.push(...SIGNAL_LABELS);
|
|
134
|
+
|
|
135
|
+
// Sync labels (create or update)
|
|
136
|
+
for (const label of labels) {
|
|
137
|
+
try {
|
|
138
|
+
await github.rest.issues.getLabel({
|
|
139
|
+
owner: context.repo.owner,
|
|
140
|
+
repo: context.repo.repo,
|
|
141
|
+
name: label.name
|
|
142
|
+
});
|
|
143
|
+
// Label exists — update it
|
|
144
|
+
await github.rest.issues.updateLabel({
|
|
145
|
+
owner: context.repo.owner,
|
|
146
|
+
repo: context.repo.repo,
|
|
147
|
+
name: label.name,
|
|
148
|
+
color: label.color,
|
|
149
|
+
description: label.description
|
|
150
|
+
});
|
|
151
|
+
core.info(`Updated label: ${label.name}`);
|
|
152
|
+
} catch (err) {
|
|
153
|
+
if (err.status === 404) {
|
|
154
|
+
// Label doesn't exist — create it
|
|
155
|
+
await github.rest.issues.createLabel({
|
|
156
|
+
owner: context.repo.owner,
|
|
157
|
+
repo: context.repo.repo,
|
|
158
|
+
name: label.name,
|
|
159
|
+
color: label.color,
|
|
160
|
+
description: label.description
|
|
161
|
+
});
|
|
162
|
+
core.info(`Created label: ${label.name}`);
|
|
163
|
+
} else {
|
|
164
|
+
throw err;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
core.info(`Label sync complete: ${labels.length} labels synced`);
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* EventBus → OTel Span Bridge (Issue #304)
|
|
3
|
-
*
|
|
4
|
-
* Subscribes to EventBus events and creates OpenTelemetry spans for each.
|
|
5
|
-
* Complements the existing otel-bridge.ts which handles TelemetryEvent
|
|
6
|
-
* (dot-separated names like squad.init). This bridge handles runtime
|
|
7
|
-
* SquadEvent types (colon-separated like session:created).
|
|
8
|
-
*
|
|
9
|
-
* @module runtime/event-bus-otel-bridge
|
|
10
|
-
*/
|
|
11
|
-
import type { EventBus, UnsubscribeFn } from './event-bus.js';
|
|
12
|
-
/**
|
|
13
|
-
* Attach an OTel span bridge to an EventBus.
|
|
14
|
-
* Every event emitted on the bus produces a corresponding OTel span.
|
|
15
|
-
*
|
|
16
|
-
* @returns Unsubscribe function to detach the bridge.
|
|
17
|
-
*/
|
|
18
|
-
export declare function attachOTelBridge(bus: EventBus): UnsubscribeFn;
|
|
19
|
-
//# sourceMappingURL=event-bus-otel-bridge.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"event-bus-otel-bridge.d.ts","sourceRoot":"","sources":["../../src/runtime/event-bus-otel-bridge.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAIH,OAAO,KAAK,EAAE,QAAQ,EAAc,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAG1E;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,QAAQ,GAAG,aAAa,CAuC7D"}
|
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* EventBus → OTel Span Bridge (Issue #304)
|
|
3
|
-
*
|
|
4
|
-
* Subscribes to EventBus events and creates OpenTelemetry spans for each.
|
|
5
|
-
* Complements the existing otel-bridge.ts which handles TelemetryEvent
|
|
6
|
-
* (dot-separated names like squad.init). This bridge handles runtime
|
|
7
|
-
* SquadEvent types (colon-separated like session:created).
|
|
8
|
-
*
|
|
9
|
-
* @module runtime/event-bus-otel-bridge
|
|
10
|
-
*/
|
|
11
|
-
import { SpanStatusCode } from '@opentelemetry/api';
|
|
12
|
-
import { getTracer } from './otel.js';
|
|
13
|
-
import { isSquadEventOfType } from './event-payloads.js';
|
|
14
|
-
/**
|
|
15
|
-
* Attach an OTel span bridge to an EventBus.
|
|
16
|
-
* Every event emitted on the bus produces a corresponding OTel span.
|
|
17
|
-
*
|
|
18
|
-
* @returns Unsubscribe function to detach the bridge.
|
|
19
|
-
*/
|
|
20
|
-
export function attachOTelBridge(bus) {
|
|
21
|
-
return bus.subscribeAll((event) => {
|
|
22
|
-
const tracer = getTracer('squad-sdk');
|
|
23
|
-
const spanName = `squad.event.${event.type.replace(':', '.')}`;
|
|
24
|
-
const attrs = {
|
|
25
|
-
'squad.event.type': event.type,
|
|
26
|
-
};
|
|
27
|
-
if (event.sessionId)
|
|
28
|
-
attrs['squad.session.id'] = event.sessionId;
|
|
29
|
-
if (event.agentName)
|
|
30
|
-
attrs['squad.agent.name'] = event.agentName;
|
|
31
|
-
// Extract payload attributes for known event types
|
|
32
|
-
if (isSquadEventOfType(event, 'session:error')) {
|
|
33
|
-
attrs['squad.error'] = event.payload.error;
|
|
34
|
-
attrs['squad.error.agent'] = event.payload.agentName;
|
|
35
|
-
}
|
|
36
|
-
else if (isSquadEventOfType(event, 'session:tool_call')) {
|
|
37
|
-
attrs['squad.tool.name'] = event.payload.toolName;
|
|
38
|
-
if (event.payload.resultType) {
|
|
39
|
-
attrs['squad.tool.result'] = event.payload.resultType;
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
else if (isSquadEventOfType(event, 'coordinator:routing')) {
|
|
43
|
-
attrs['squad.routing.phase'] = event.payload.phase;
|
|
44
|
-
}
|
|
45
|
-
else if (isSquadEventOfType(event, 'agent:milestone')) {
|
|
46
|
-
attrs['squad.milestone.event'] = event.payload.event;
|
|
47
|
-
attrs['squad.milestone.agent'] = event.payload.agentName;
|
|
48
|
-
}
|
|
49
|
-
else if (isSquadEventOfType(event, 'pool:health')) {
|
|
50
|
-
attrs['squad.pool.active'] = event.payload.activeSessions;
|
|
51
|
-
attrs['squad.pool.available'] = event.payload.availableSlots;
|
|
52
|
-
attrs['squad.pool.queued'] = event.payload.queuedRequests;
|
|
53
|
-
}
|
|
54
|
-
const span = tracer.startSpan(spanName, { attributes: attrs });
|
|
55
|
-
if (event.type === 'session:error') {
|
|
56
|
-
span.setStatus({ code: SpanStatusCode.ERROR });
|
|
57
|
-
}
|
|
58
|
-
span.end();
|
|
59
|
-
});
|
|
60
|
-
}
|
|
61
|
-
//# sourceMappingURL=event-bus-otel-bridge.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"event-bus-otel-bridge.js","sourceRoot":"","sources":["../../src/runtime/event-bus-otel-bridge.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAEtC,OAAO,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAEzD;;;;;GAKG;AACH,MAAM,UAAU,gBAAgB,CAAC,GAAa;IAC5C,OAAO,GAAG,CAAC,YAAY,CAAC,CAAC,KAAiB,EAAE,EAAE;QAC5C,MAAM,MAAM,GAAG,SAAS,CAAC,WAAW,CAAC,CAAC;QACtC,MAAM,QAAQ,GAAG,eAAe,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,EAAE,CAAC;QAE/D,MAAM,KAAK,GAA8C;YACvD,kBAAkB,EAAE,KAAK,CAAC,IAAI;SAC/B,CAAC;QACF,IAAI,KAAK,CAAC,SAAS;YAAE,KAAK,CAAC,kBAAkB,CAAC,GAAG,KAAK,CAAC,SAAS,CAAC;QACjE,IAAI,KAAK,CAAC,SAAS;YAAE,KAAK,CAAC,kBAAkB,CAAC,GAAG,KAAK,CAAC,SAAS,CAAC;QAEjE,mDAAmD;QACnD,IAAI,kBAAkB,CAAC,KAAK,EAAE,eAAe,CAAC,EAAE,CAAC;YAC/C,KAAK,CAAC,aAAa,CAAC,GAAG,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;YAC3C,KAAK,CAAC,mBAAmB,CAAC,GAAG,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC;QACvD,CAAC;aAAM,IAAI,kBAAkB,CAAC,KAAK,EAAE,mBAAmB,CAAC,EAAE,CAAC;YAC1D,KAAK,CAAC,iBAAiB,CAAC,GAAG,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC;YAClD,IAAI,KAAK,CAAC,OAAO,CAAC,UAAU,EAAE,CAAC;gBAC7B,KAAK,CAAC,mBAAmB,CAAC,GAAG,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC;YACxD,CAAC;QACH,CAAC;aAAM,IAAI,kBAAkB,CAAC,KAAK,EAAE,qBAAqB,CAAC,EAAE,CAAC;YAC5D,KAAK,CAAC,qBAAqB,CAAC,GAAG,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QACrD,CAAC;aAAM,IAAI,kBAAkB,CAAC,KAAK,EAAE,iBAAiB,CAAC,EAAE,CAAC;YACxD,KAAK,CAAC,uBAAuB,CAAC,GAAG,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;YACrD,KAAK,CAAC,uBAAuB,CAAC,GAAG,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC;QAC3D,CAAC;aAAM,IAAI,kBAAkB,CAAC,KAAK,EAAE,aAAa,CAAC,EAAE,CAAC;YACpD,KAAK,CAAC,mBAAmB,CAAC,GAAG,KAAK,CAAC,OAAO,CAAC,cAAc,CAAC;YAC1D,KAAK,CAAC,sBAAsB,CAAC,GAAG,KAAK,CAAC,OAAO,CAAC,cAAc,CAAC;YAC7D,KAAK,CAAC,mBAAmB,CAAC,GAAG,KAAK,CAAC,OAAO,CAAC,cAAc,CAAC;QAC5D,CAAC;QAED,MAAM,IAAI,GAAG,MAAM,CAAC,SAAS,CAAC,QAAQ,EAAE,EAAE,UAAU,EAAE,KAAK,EAAE,CAAC,CAAC;QAE/D,IAAI,KAAK,CAAC,IAAI,KAAK,eAAe,EAAE,CAAC;YACnC,IAAI,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,cAAc,CAAC,KAAK,EAAE,CAAC,CAAC;QACjD,CAAC;QAED,IAAI,CAAC,GAAG,EAAE,CAAC;IACb,CAAC,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -1,129 +0,0 @@
|
|
|
1
|
-
name: Squad Protected Branch Guard
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
pull_request:
|
|
5
|
-
branches: [main, preview, insider]
|
|
6
|
-
types: [opened, synchronize, reopened]
|
|
7
|
-
push:
|
|
8
|
-
branches: [main, preview, insider]
|
|
9
|
-
|
|
10
|
-
permissions:
|
|
11
|
-
contents: read
|
|
12
|
-
pull-requests: read
|
|
13
|
-
|
|
14
|
-
jobs:
|
|
15
|
-
guard:
|
|
16
|
-
runs-on: ubuntu-latest
|
|
17
|
-
steps:
|
|
18
|
-
- uses: actions/checkout@v4
|
|
19
|
-
|
|
20
|
-
- name: Check for forbidden paths
|
|
21
|
-
uses: actions/github-script@v7
|
|
22
|
-
with:
|
|
23
|
-
script: |
|
|
24
|
-
// Fetch all files changed - handles both PR and push events
|
|
25
|
-
let files = [];
|
|
26
|
-
|
|
27
|
-
if (context.eventName === 'pull_request') {
|
|
28
|
-
// PR event: use pulls.listFiles API
|
|
29
|
-
let page = 1;
|
|
30
|
-
while (true) {
|
|
31
|
-
const resp = await github.rest.pulls.listFiles({
|
|
32
|
-
owner: context.repo.owner,
|
|
33
|
-
repo: context.repo.repo,
|
|
34
|
-
pull_number: context.payload.pull_request.number,
|
|
35
|
-
per_page: 100,
|
|
36
|
-
page
|
|
37
|
-
});
|
|
38
|
-
files.push(...resp.data);
|
|
39
|
-
if (resp.data.length < 100) break;
|
|
40
|
-
page++;
|
|
41
|
-
}
|
|
42
|
-
} else if (context.eventName === 'push') {
|
|
43
|
-
// Push event: compare against base branch
|
|
44
|
-
const base = context.payload.before;
|
|
45
|
-
const head = context.payload.after;
|
|
46
|
-
|
|
47
|
-
// If this is not a force push and base exists, compare commits
|
|
48
|
-
if (base && base !== '0000000000000000000000000000000000000000') {
|
|
49
|
-
const comparison = await github.rest.repos.compareCommits({
|
|
50
|
-
owner: context.repo.owner,
|
|
51
|
-
repo: context.repo.repo,
|
|
52
|
-
base,
|
|
53
|
-
head
|
|
54
|
-
});
|
|
55
|
-
files = comparison.data.files || [];
|
|
56
|
-
} else {
|
|
57
|
-
// Force push or initial commit: list all files in the current tree
|
|
58
|
-
core.info('Force push detected or initial commit, checking tree state');
|
|
59
|
-
const { data: tree } = await github.rest.git.getTree({
|
|
60
|
-
owner: context.repo.owner,
|
|
61
|
-
repo: context.repo.repo,
|
|
62
|
-
tree_sha: head,
|
|
63
|
-
recursive: 'true'
|
|
64
|
-
});
|
|
65
|
-
files = tree.tree
|
|
66
|
-
.filter(item => item.type === 'blob')
|
|
67
|
-
.map(item => ({ filename: item.path, status: 'added' }));
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
// Check each file against forbidden path rules
|
|
72
|
-
// Allow removals — deleting forbidden files from protected branches is fine
|
|
73
|
-
const forbidden = files
|
|
74
|
-
.filter(f => f.status !== 'removed')
|
|
75
|
-
.map(f => f.filename)
|
|
76
|
-
.filter(f => {
|
|
77
|
-
// .ai-team/** and .squad/** — ALL team state files, zero exceptions
|
|
78
|
-
if (f === '.ai-team' || f.startsWith('.ai-team/') || f === '.squad' || f.startsWith('.squad/')) return true;
|
|
79
|
-
// .ai-team-templates/** — Squad's own templates, stay on dev
|
|
80
|
-
if (f === '.ai-team-templates' || f.startsWith('.ai-team-templates/')) return true;
|
|
81
|
-
// team-docs/** — ALL internal team docs, zero exceptions
|
|
82
|
-
if (f.startsWith('team-docs/')) return true;
|
|
83
|
-
// docs/proposals/** — internal design proposals, stay on dev
|
|
84
|
-
if (f.startsWith('docs/proposals/')) return true;
|
|
85
|
-
return false;
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
if (forbidden.length === 0) {
|
|
89
|
-
core.info('✅ No forbidden paths found in PR — all clear.');
|
|
90
|
-
return;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
// Build a clear, actionable error message
|
|
94
|
-
const lines = [
|
|
95
|
-
'## 🚫 Forbidden files detected in PR to main',
|
|
96
|
-
'',
|
|
97
|
-
'The following files must NOT be merged into `main`.',
|
|
98
|
-
'`.ai-team/` and `.squad/` are runtime team state — they belong on dev branches only.',
|
|
99
|
-
'`.ai-team-templates/` is Squad\'s internal planning — it belongs on dev branches only.',
|
|
100
|
-
'`team-docs/` is internal team content — it belongs on dev branches only.',
|
|
101
|
-
'`docs/proposals/` is internal design proposals — it belongs on dev branches only.',
|
|
102
|
-
'',
|
|
103
|
-
'### Forbidden files found:',
|
|
104
|
-
'',
|
|
105
|
-
...forbidden.map(f => `- \`${f}\``),
|
|
106
|
-
'',
|
|
107
|
-
'### How to fix:',
|
|
108
|
-
'',
|
|
109
|
-
'```bash',
|
|
110
|
-
'# Remove tracked .ai-team/ files (keeps local copies):',
|
|
111
|
-
'git rm --cached -r .ai-team/',
|
|
112
|
-
'',
|
|
113
|
-
'# Remove tracked .squad/ files (keeps local copies):',
|
|
114
|
-
'git rm --cached -r .squad/',
|
|
115
|
-
'',
|
|
116
|
-
'# Remove tracked team-docs/ files:',
|
|
117
|
-
'git rm --cached -r team-docs/',
|
|
118
|
-
'',
|
|
119
|
-
'# Commit the removal and push:',
|
|
120
|
-
'git commit -m "chore: remove forbidden paths from PR"',
|
|
121
|
-
'git push',
|
|
122
|
-
'```',
|
|
123
|
-
'',
|
|
124
|
-
'> ⚠️ `.ai-team/` and `.squad/` are committed on `dev` and feature branches by design.',
|
|
125
|
-
'> The guard workflow is the enforcement mechanism that keeps these files off `main` and `preview`.',
|
|
126
|
-
'> `git rm --cached` untracks them from this PR without deleting your local copies.',
|
|
127
|
-
];
|
|
128
|
-
|
|
129
|
-
core.setFailed(lines.join('\n'));
|