@bradygaster/squad-sdk 0.8.0 → 0.8.2-1.4
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 +25 -4
- package/dist/adapter/client.d.ts.map +1 -1
- package/dist/adapter/client.js +377 -75
- package/dist/adapter/client.js.map +1 -1
- package/dist/adapter/errors.js.map +1 -1
- package/dist/adapter/types.d.ts +38 -0
- package/dist/adapter/types.d.ts.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/history-shadow.js.map +1 -1
- package/dist/agents/index.d.ts +6 -3
- package/dist/agents/index.d.ts.map +1 -1
- package/dist/agents/index.js +132 -23
- package/dist/agents/index.js.map +1 -1
- package/dist/agents/lifecycle.d.ts.map +1 -1
- package/dist/agents/lifecycle.js +28 -2
- package/dist/agents/lifecycle.js.map +1 -1
- package/dist/agents/model-selector.d.ts.map +1 -1
- package/dist/agents/model-selector.js +10 -37
- package/dist/agents/model-selector.js.map +1 -1
- package/dist/agents/onboarding.js +12 -12
- package/dist/agents/onboarding.js.map +1 -1
- package/dist/build/ci-pipeline.js.map +1 -1
- package/dist/build/github-dist.d.ts +2 -2
- package/dist/build/github-dist.js +45 -45
- package/dist/build/github-dist.js.map +1 -1
- package/dist/build/install-migration.js +2 -2
- package/dist/build/install-migration.js.map +1 -1
- package/dist/build/release.js.map +1 -1
- package/dist/build/versioning.js.map +1 -1
- 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/casting/index.d.ts.map +1 -1
- package/dist/casting/index.js +10 -2
- package/dist/casting/index.js.map +1 -1
- package/dist/client/event-bus.d.ts.map +1 -1
- package/dist/client/event-bus.js +0 -1
- package/dist/client/event-bus.js.map +1 -1
- package/dist/client/index.d.ts +7 -4
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +22 -10
- package/dist/client/index.js.map +1 -1
- package/dist/config/agent-doc.js.map +1 -1
- package/dist/config/agent-source.js.map +1 -1
- package/dist/config/doc-sync.js.map +1 -1
- package/dist/config/init.d.ts +38 -13
- package/dist/config/init.d.ts.map +1 -1
- package/dist/config/init.js +615 -177
- package/dist/config/init.js.map +1 -1
- package/dist/config/legacy-fallback.js.map +1 -1
- package/dist/config/markdown-migration.js.map +1 -1
- package/dist/config/migration.js.map +1 -1
- package/dist/config/routing.js.map +1 -1
- package/dist/coordinator/coordinator.d.ts.map +1 -1
- package/dist/coordinator/coordinator.js +73 -55
- package/dist/coordinator/coordinator.js.map +1 -1
- package/dist/coordinator/fan-out.js.map +1 -1
- package/dist/coordinator/index.d.ts +19 -4
- package/dist/coordinator/index.d.ts.map +1 -1
- package/dist/coordinator/index.js +144 -21
- package/dist/coordinator/index.js.map +1 -1
- package/dist/index.d.ts +15 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +16 -2
- package/dist/index.js.map +1 -1
- package/dist/multi-squad.d.ts +89 -0
- package/dist/multi-squad.d.ts.map +1 -0
- package/dist/multi-squad.js +233 -0
- package/dist/multi-squad.js.map +1 -0
- package/dist/ralph/index.d.ts +3 -1
- package/dist/ralph/index.d.ts.map +1 -1
- package/dist/ralph/index.js +83 -16
- package/dist/ralph/index.js.map +1 -1
- package/dist/ralph/triage.d.ts +48 -0
- package/dist/ralph/triage.d.ts.map +1 -0
- package/dist/ralph/triage.js +310 -0
- package/dist/ralph/triage.js.map +1 -0
- package/dist/remote/bridge.d.ts +79 -0
- package/dist/remote/bridge.d.ts.map +1 -0
- package/dist/remote/bridge.js +583 -0
- package/dist/remote/bridge.js.map +1 -0
- package/dist/remote/index.d.ts +7 -0
- package/dist/remote/index.d.ts.map +1 -0
- package/dist/remote/index.js +6 -0
- package/dist/remote/index.js.map +1 -0
- package/dist/remote/protocol.d.ts +130 -0
- package/dist/remote/protocol.d.ts.map +1 -0
- package/dist/remote/protocol.js +25 -0
- package/dist/remote/protocol.js.map +1 -0
- package/dist/remote/types.d.ts +34 -0
- package/dist/remote/types.d.ts.map +1 -0
- package/dist/remote/types.js +5 -0
- package/dist/remote/types.js.map +1 -0
- package/dist/resolution.d.ts +72 -0
- package/dist/resolution.d.ts.map +1 -1
- package/dist/resolution.js +153 -0
- package/dist/resolution.js.map +1 -1
- package/dist/runtime/benchmarks.js.map +1 -1
- package/dist/runtime/config.d.ts +3 -2
- package/dist/runtime/config.d.ts.map +1 -1
- package/dist/runtime/config.js +7 -6
- package/dist/runtime/config.js.map +1 -1
- package/dist/runtime/constants.d.ts +37 -0
- package/dist/runtime/constants.d.ts.map +1 -0
- package/dist/runtime/constants.js +60 -0
- package/dist/runtime/constants.js.map +1 -0
- package/dist/runtime/event-bus-ws-bridge.d.ts +35 -0
- package/dist/runtime/event-bus-ws-bridge.d.ts.map +1 -0
- package/dist/runtime/event-bus-ws-bridge.js +55 -0
- package/dist/runtime/event-bus-ws-bridge.js.map +1 -0
- package/dist/runtime/event-payloads.d.ts +108 -0
- package/dist/runtime/event-payloads.d.ts.map +1 -0
- package/dist/runtime/event-payloads.js +28 -0
- package/dist/runtime/event-payloads.js.map +1 -0
- package/dist/runtime/health.d.ts.map +1 -1
- package/dist/runtime/health.js +2 -1
- package/dist/runtime/health.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.d.ts +52 -0
- package/dist/runtime/otel-bridge.d.ts.map +1 -0
- package/dist/runtime/otel-bridge.js +132 -0
- package/dist/runtime/otel-bridge.js.map +1 -0
- package/dist/runtime/otel-init.d.ts +84 -0
- package/dist/runtime/otel-init.d.ts.map +1 -0
- package/dist/runtime/otel-init.js +86 -0
- package/dist/runtime/otel-init.js.map +1 -0
- package/dist/runtime/otel-metrics.d.ts +42 -0
- package/dist/runtime/otel-metrics.d.ts.map +1 -0
- package/dist/runtime/otel-metrics.js +196 -0
- package/dist/runtime/otel-metrics.js.map +1 -0
- package/dist/runtime/otel.d.ts +55 -0
- package/dist/runtime/otel.d.ts.map +1 -0
- package/dist/runtime/otel.js +165 -0
- package/dist/runtime/otel.js.map +1 -0
- package/dist/runtime/squad-observer.d.ts +75 -0
- package/dist/runtime/squad-observer.d.ts.map +1 -0
- package/dist/runtime/squad-observer.js +190 -0
- package/dist/runtime/squad-observer.js.map +1 -0
- package/dist/runtime/streaming.d.ts +9 -0
- package/dist/runtime/streaming.d.ts.map +1 -1
- package/dist/runtime/streaming.js +37 -1
- package/dist/runtime/streaming.js.map +1 -1
- package/dist/sharing/conflicts.js +7 -5
- package/dist/sharing/conflicts.js.map +1 -1
- package/dist/sharing/consult.d.ts +226 -0
- package/dist/sharing/consult.d.ts.map +1 -0
- package/dist/sharing/consult.js +818 -0
- package/dist/sharing/consult.js.map +1 -0
- package/dist/sharing/export.js.map +1 -1
- package/dist/sharing/import.js.map +1 -1
- package/dist/sharing/index.d.ts +2 -1
- package/dist/sharing/index.d.ts.map +1 -1
- package/dist/sharing/index.js +2 -1
- package/dist/sharing/index.js.map +1 -1
- package/dist/skills/skill-loader.js.map +1 -1
- 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.d.ts +8 -0
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +57 -1
- package/dist/tools/index.js.map +1 -1
- package/dist/types.d.ts +23 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/upstream/index.d.ts +8 -0
- package/dist/upstream/index.d.ts.map +1 -0
- package/dist/upstream/index.js +7 -0
- package/dist/upstream/index.js.map +1 -0
- package/dist/upstream/resolver.d.ts +37 -0
- package/dist/upstream/resolver.d.ts.map +1 -0
- package/dist/upstream/resolver.js +234 -0
- package/dist/upstream/resolver.js.map +1 -0
- package/dist/upstream/types.d.ts +55 -0
- package/dist/upstream/types.d.ts.map +1 -0
- package/dist/upstream/types.js +11 -0
- package/dist/upstream/types.js.map +1 -0
- package/dist/utils/safe-timestamp.d.ts +6 -0
- package/dist/utils/safe-timestamp.d.ts.map +1 -0
- package/dist/utils/safe-timestamp.js +8 -0
- package/dist/utils/safe-timestamp.js.map +1 -0
- package/package.json +208 -115
- package/templates/casting-history.json +4 -0
- package/templates/casting-policy.json +35 -0
- package/templates/casting-registry.json +3 -0
- package/templates/ceremonies.md +41 -0
- package/templates/charter.md +53 -0
- package/templates/constraint-tracking.md +38 -0
- package/templates/copilot-instructions.md +46 -0
- package/templates/history.md +10 -0
- package/templates/identity/now.md +9 -0
- package/templates/identity/wisdom.md +15 -0
- package/templates/mcp-config.md +98 -0
- package/templates/multi-agent-format.md +28 -0
- package/templates/orchestration-log.md +27 -0
- package/templates/plugin-marketplace.md +49 -0
- package/templates/raw-agent-output.md +37 -0
- package/templates/roster.md +60 -0
- package/templates/routing.md +54 -0
- package/templates/run-output.md +50 -0
- package/templates/scribe-charter.md +119 -0
- package/templates/skill.md +24 -0
- package/templates/skills/project-conventions/SKILL.md +56 -0
- package/templates/squad.agent.md +1146 -0
- package/templates/workflows/squad-ci.yml +24 -0
- package/templates/workflows/squad-docs.yml +50 -0
- package/templates/workflows/squad-heartbeat.yml +316 -0
- package/templates/workflows/squad-insider-release.yml +61 -0
- package/templates/workflows/squad-issue-assign.yml +161 -0
- package/templates/workflows/squad-label-enforce.yml +181 -0
- package/templates/workflows/squad-preview.yml +55 -0
- package/templates/workflows/squad-promote.yml +120 -0
- package/templates/workflows/squad-release.yml +77 -0
- package/templates/workflows/squad-triage.yml +260 -0
- package/templates/workflows/sync-squad-labels.yml +169 -0
package/dist/config/init.js
CHANGED
|
@@ -3,12 +3,54 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Creates new Squad projects with typed configuration.
|
|
5
5
|
* Generates squad.config.ts or squad.config.json with agent definitions.
|
|
6
|
+
* Scaffolds directory structure, templates, workflows, and agent files.
|
|
6
7
|
*
|
|
7
8
|
* @module config/init
|
|
8
9
|
*/
|
|
9
|
-
import { mkdir, writeFile } from 'fs/promises';
|
|
10
|
-
import { join } from 'path';
|
|
11
|
-
import {
|
|
10
|
+
import { mkdir, writeFile, appendFile, unlink } from 'fs/promises';
|
|
11
|
+
import { join, dirname } from 'path';
|
|
12
|
+
import { fileURLToPath } from 'url';
|
|
13
|
+
import { existsSync, cpSync, statSync, mkdirSync, readFileSync, readdirSync } from 'fs';
|
|
14
|
+
import { MODELS } from '../runtime/constants.js';
|
|
15
|
+
// ============================================================================
|
|
16
|
+
// Template Resolution
|
|
17
|
+
// ============================================================================
|
|
18
|
+
/**
|
|
19
|
+
* Get the SDK templates directory path.
|
|
20
|
+
*/
|
|
21
|
+
export function getSDKTemplatesDir() {
|
|
22
|
+
// Use fileURLToPath for cross-platform compatibility (handles Windows drive letters, URL encoding)
|
|
23
|
+
const currentDir = dirname(fileURLToPath(import.meta.url));
|
|
24
|
+
// Try relative to this file (in dist/)
|
|
25
|
+
const distPath = join(currentDir, '../../templates');
|
|
26
|
+
if (existsSync(distPath)) {
|
|
27
|
+
return distPath;
|
|
28
|
+
}
|
|
29
|
+
// Try relative to package root (for dev)
|
|
30
|
+
const pkgPath = join(currentDir, '../../../templates');
|
|
31
|
+
if (existsSync(pkgPath)) {
|
|
32
|
+
return pkgPath;
|
|
33
|
+
}
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Copy a directory recursively.
|
|
38
|
+
*/
|
|
39
|
+
function copyRecursiveSync(src, dest) {
|
|
40
|
+
if (!existsSync(dest)) {
|
|
41
|
+
mkdirSync(dest, { recursive: true });
|
|
42
|
+
}
|
|
43
|
+
for (const entry of statSync(src).isDirectory() ? readdirSync(src) : []) {
|
|
44
|
+
const srcPath = join(src, entry);
|
|
45
|
+
const destPath = join(dest, entry);
|
|
46
|
+
if (statSync(srcPath).isDirectory()) {
|
|
47
|
+
copyRecursiveSync(srcPath, destPath);
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
cpSync(srcPath, destPath);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
12
54
|
// ============================================================================
|
|
13
55
|
// Default Agent Templates
|
|
14
56
|
// ============================================================================
|
|
@@ -40,87 +82,93 @@ const AGENT_TEMPLATES = {
|
|
|
40
82
|
// ============================================================================
|
|
41
83
|
// Configuration Templates
|
|
42
84
|
// ============================================================================
|
|
85
|
+
/**
|
|
86
|
+
* Format a readonly string array as a single-quoted TypeScript array literal.
|
|
87
|
+
*/
|
|
88
|
+
function formatModelArray(chain) {
|
|
89
|
+
return `[${chain.map(m => `'${m}'`).join(', ')}]`;
|
|
90
|
+
}
|
|
43
91
|
/**
|
|
44
92
|
* Generate TypeScript config file content.
|
|
45
93
|
*/
|
|
46
94
|
function generateTypeScriptConfig(options) {
|
|
47
95
|
const { projectName, projectDescription, agents } = options;
|
|
48
|
-
return `import type { SquadConfig } from '@bradygaster/squad';
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* Squad Configuration for ${projectName}
|
|
52
|
-
* ${projectDescription ? `\n * ${projectDescription}` : ''}
|
|
53
|
-
*/
|
|
54
|
-
const config: SquadConfig = {
|
|
55
|
-
version: '1.0.0',
|
|
56
|
-
|
|
57
|
-
models: {
|
|
58
|
-
defaultModel: '
|
|
59
|
-
defaultTier: 'standard',
|
|
60
|
-
fallbackChains: {
|
|
61
|
-
premium:
|
|
62
|
-
standard:
|
|
63
|
-
fast:
|
|
64
|
-
},
|
|
65
|
-
preferSameProvider: true,
|
|
66
|
-
respectTierCeiling: true,
|
|
67
|
-
nuclearFallback: {
|
|
68
|
-
enabled: false,
|
|
69
|
-
model: '
|
|
70
|
-
maxRetriesBeforeNuclear:
|
|
71
|
-
}
|
|
72
|
-
},
|
|
73
|
-
|
|
74
|
-
routing: {
|
|
75
|
-
rules: [
|
|
76
|
-
{
|
|
77
|
-
workType: 'feature-dev',
|
|
78
|
-
agents: ['@${agents[0]?.name || 'coordinator'}'],
|
|
79
|
-
confidence: 'high'
|
|
80
|
-
},
|
|
81
|
-
{
|
|
82
|
-
workType: 'bug-fix',
|
|
83
|
-
agents: ['@${agents.find(a => a.role === 'developer')?.name || agents[0]?.name || 'coordinator'}'],
|
|
84
|
-
confidence: 'high'
|
|
85
|
-
},
|
|
86
|
-
{
|
|
87
|
-
workType: 'testing',
|
|
88
|
-
agents: ['@${agents.find(a => a.role === 'tester')?.name || agents[0]?.name || 'coordinator'}'],
|
|
89
|
-
confidence: 'high'
|
|
90
|
-
},
|
|
91
|
-
{
|
|
92
|
-
workType: 'documentation',
|
|
93
|
-
agents: ['@${agents.find(a => a.role === 'scribe')?.name || agents[0]?.name || 'coordinator'}'],
|
|
94
|
-
confidence: 'high'
|
|
95
|
-
}
|
|
96
|
-
],
|
|
97
|
-
governance: {
|
|
98
|
-
eagerByDefault: true,
|
|
99
|
-
scribeAutoRuns: false,
|
|
100
|
-
allowRecursiveSpawn: false
|
|
101
|
-
}
|
|
102
|
-
},
|
|
103
|
-
|
|
104
|
-
casting: {
|
|
105
|
-
allowlistUniverses: [
|
|
106
|
-
'The Usual Suspects',
|
|
107
|
-
'Breaking Bad',
|
|
108
|
-
'The Wire',
|
|
109
|
-
'Firefly'
|
|
110
|
-
],
|
|
111
|
-
overflowStrategy: 'generic',
|
|
112
|
-
universeCapacity: {}
|
|
113
|
-
},
|
|
114
|
-
|
|
115
|
-
platforms: {
|
|
116
|
-
vscode: {
|
|
117
|
-
disableModelSelection: false,
|
|
118
|
-
scribeMode: 'sync'
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
};
|
|
122
|
-
|
|
123
|
-
export default config;
|
|
96
|
+
return `import type { SquadConfig } from '@bradygaster/squad';
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Squad Configuration for ${projectName}
|
|
100
|
+
* ${projectDescription ? `\n * ${projectDescription}` : ''}
|
|
101
|
+
*/
|
|
102
|
+
const config: SquadConfig = {
|
|
103
|
+
version: '1.0.0',
|
|
104
|
+
|
|
105
|
+
models: {
|
|
106
|
+
defaultModel: '${MODELS.DEFAULT}',
|
|
107
|
+
defaultTier: 'standard',
|
|
108
|
+
fallbackChains: {
|
|
109
|
+
premium: ${formatModelArray(MODELS.FALLBACK_CHAINS.premium)},
|
|
110
|
+
standard: ${formatModelArray(MODELS.FALLBACK_CHAINS.standard)},
|
|
111
|
+
fast: ${formatModelArray(MODELS.FALLBACK_CHAINS.fast)}
|
|
112
|
+
},
|
|
113
|
+
preferSameProvider: true,
|
|
114
|
+
respectTierCeiling: true,
|
|
115
|
+
nuclearFallback: {
|
|
116
|
+
enabled: false,
|
|
117
|
+
model: '${MODELS.NUCLEAR_FALLBACK}',
|
|
118
|
+
maxRetriesBeforeNuclear: ${MODELS.NUCLEAR_MAX_RETRIES}
|
|
119
|
+
}
|
|
120
|
+
},
|
|
121
|
+
|
|
122
|
+
routing: {
|
|
123
|
+
rules: [
|
|
124
|
+
{
|
|
125
|
+
workType: 'feature-dev',
|
|
126
|
+
agents: ['@${agents[0]?.name || 'coordinator'}'],
|
|
127
|
+
confidence: 'high'
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
workType: 'bug-fix',
|
|
131
|
+
agents: ['@${agents.find(a => a.role === 'developer')?.name || agents[0]?.name || 'coordinator'}'],
|
|
132
|
+
confidence: 'high'
|
|
133
|
+
},
|
|
134
|
+
{
|
|
135
|
+
workType: 'testing',
|
|
136
|
+
agents: ['@${agents.find(a => a.role === 'tester')?.name || agents[0]?.name || 'coordinator'}'],
|
|
137
|
+
confidence: 'high'
|
|
138
|
+
},
|
|
139
|
+
{
|
|
140
|
+
workType: 'documentation',
|
|
141
|
+
agents: ['@${agents.find(a => a.role === 'scribe')?.name || agents[0]?.name || 'coordinator'}'],
|
|
142
|
+
confidence: 'high'
|
|
143
|
+
}
|
|
144
|
+
],
|
|
145
|
+
governance: {
|
|
146
|
+
eagerByDefault: true,
|
|
147
|
+
scribeAutoRuns: false,
|
|
148
|
+
allowRecursiveSpawn: false
|
|
149
|
+
}
|
|
150
|
+
},
|
|
151
|
+
|
|
152
|
+
casting: {
|
|
153
|
+
allowlistUniverses: [
|
|
154
|
+
'The Usual Suspects',
|
|
155
|
+
'Breaking Bad',
|
|
156
|
+
'The Wire',
|
|
157
|
+
'Firefly'
|
|
158
|
+
],
|
|
159
|
+
overflowStrategy: 'generic',
|
|
160
|
+
universeCapacity: {}
|
|
161
|
+
},
|
|
162
|
+
|
|
163
|
+
platforms: {
|
|
164
|
+
vscode: {
|
|
165
|
+
disableModelSelection: false,
|
|
166
|
+
scribeMode: 'sync'
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
export default config;
|
|
124
172
|
`;
|
|
125
173
|
}
|
|
126
174
|
/**
|
|
@@ -131,19 +179,19 @@ function generateJsonConfig(options) {
|
|
|
131
179
|
const config = {
|
|
132
180
|
version: '1.0.0',
|
|
133
181
|
models: {
|
|
134
|
-
defaultModel:
|
|
182
|
+
defaultModel: MODELS.DEFAULT,
|
|
135
183
|
defaultTier: 'standard',
|
|
136
184
|
fallbackChains: {
|
|
137
|
-
premium: [
|
|
138
|
-
standard: [
|
|
139
|
-
fast: [
|
|
185
|
+
premium: [...MODELS.FALLBACK_CHAINS.premium],
|
|
186
|
+
standard: [...MODELS.FALLBACK_CHAINS.standard],
|
|
187
|
+
fast: [...MODELS.FALLBACK_CHAINS.fast]
|
|
140
188
|
},
|
|
141
189
|
preferSameProvider: true,
|
|
142
190
|
respectTierCeiling: true,
|
|
143
191
|
nuclearFallback: {
|
|
144
192
|
enabled: false,
|
|
145
|
-
model:
|
|
146
|
-
maxRetriesBeforeNuclear:
|
|
193
|
+
model: MODELS.NUCLEAR_FALLBACK,
|
|
194
|
+
maxRetriesBeforeNuclear: MODELS.NUCLEAR_MAX_RETRIES
|
|
147
195
|
}
|
|
148
196
|
},
|
|
149
197
|
routing: {
|
|
@@ -194,6 +242,42 @@ function generateJsonConfig(options) {
|
|
|
194
242
|
};
|
|
195
243
|
return JSON.stringify(config, null, 2);
|
|
196
244
|
}
|
|
245
|
+
/**
|
|
246
|
+
* Generate SDK builder config file content (new defineSquad() format).
|
|
247
|
+
*/
|
|
248
|
+
function generateSDKBuilderConfig(options) {
|
|
249
|
+
const { projectName, projectDescription, agents } = options;
|
|
250
|
+
// Generate imports
|
|
251
|
+
let code = `import {\n defineSquad,\n defineTeam,\n defineAgent,\n} from '@bradygaster/squad-sdk';\n\n`;
|
|
252
|
+
code += `/**\n * Squad Configuration — ${projectName}\n`;
|
|
253
|
+
if (projectDescription) {
|
|
254
|
+
code += ` *\n * ${projectDescription}\n`;
|
|
255
|
+
}
|
|
256
|
+
code += ` */\n`;
|
|
257
|
+
// Generate agent definitions
|
|
258
|
+
for (const agent of agents) {
|
|
259
|
+
const displayName = agent.displayName || titleCase(agent.name);
|
|
260
|
+
code += `const ${agent.name} = defineAgent({\n`;
|
|
261
|
+
code += ` name: '${agent.name}',\n`;
|
|
262
|
+
code += ` role: '${agent.role}',\n`;
|
|
263
|
+
code += ` description: '${displayName}',\n`;
|
|
264
|
+
code += ` status: 'active',\n`;
|
|
265
|
+
code += `});\n\n`;
|
|
266
|
+
}
|
|
267
|
+
// Generate squad config
|
|
268
|
+
code += `export default defineSquad({\n`;
|
|
269
|
+
code += ` version: '1.0.0',\n\n`;
|
|
270
|
+
code += ` team: defineTeam({\n`;
|
|
271
|
+
code += ` name: '${projectName}',\n`;
|
|
272
|
+
if (projectDescription) {
|
|
273
|
+
code += ` description: '${projectDescription.replace(/'/g, "\\'")}',\n`;
|
|
274
|
+
}
|
|
275
|
+
code += ` members: [${agents.map(a => `'${a.name}'`).join(', ')}],\n`;
|
|
276
|
+
code += ` }),\n\n`;
|
|
277
|
+
code += ` agents: [${agents.map(a => a.name).join(', ')}],\n`;
|
|
278
|
+
code += `});\n`;
|
|
279
|
+
return code;
|
|
280
|
+
}
|
|
197
281
|
// ============================================================================
|
|
198
282
|
// Agent Template Generation
|
|
199
283
|
// ============================================================================
|
|
@@ -204,26 +288,26 @@ function generateCharter(agent, projectName, projectDescription) {
|
|
|
204
288
|
const template = AGENT_TEMPLATES[agent.role];
|
|
205
289
|
const displayName = agent.displayName || template?.displayName || titleCase(agent.name);
|
|
206
290
|
const description = template?.description || 'Team member focused on their assigned responsibilities.';
|
|
207
|
-
return `# ${displayName} — ${titleCase(agent.role)}
|
|
208
|
-
|
|
209
|
-
${description}
|
|
210
|
-
|
|
211
|
-
## Project Context
|
|
212
|
-
|
|
213
|
-
**Project:** ${projectName}
|
|
214
|
-
${projectDescription ? `**Description:** ${projectDescription}\n` : ''}
|
|
215
|
-
|
|
216
|
-
## Responsibilities
|
|
217
|
-
|
|
218
|
-
- Collaborate with team members on assigned work
|
|
219
|
-
- Maintain code quality and project standards
|
|
220
|
-
- Document decisions and progress in history
|
|
221
|
-
|
|
222
|
-
## Work Style
|
|
223
|
-
|
|
224
|
-
- Read project context and team decisions before starting work
|
|
225
|
-
- Communicate clearly with team members
|
|
226
|
-
- Follow established patterns and conventions
|
|
291
|
+
return `# ${displayName} — ${titleCase(agent.role)}
|
|
292
|
+
|
|
293
|
+
${description}
|
|
294
|
+
|
|
295
|
+
## Project Context
|
|
296
|
+
|
|
297
|
+
**Project:** ${projectName}
|
|
298
|
+
${projectDescription ? `**Description:** ${projectDescription}\n` : ''}
|
|
299
|
+
|
|
300
|
+
## Responsibilities
|
|
301
|
+
|
|
302
|
+
- Collaborate with team members on assigned work
|
|
303
|
+
- Maintain code quality and project standards
|
|
304
|
+
- Document decisions and progress in history
|
|
305
|
+
|
|
306
|
+
## Work Style
|
|
307
|
+
|
|
308
|
+
- Read project context and team decisions before starting work
|
|
309
|
+
- Communicate clearly with team members
|
|
310
|
+
- Follow established patterns and conventions
|
|
227
311
|
`;
|
|
228
312
|
}
|
|
229
313
|
/**
|
|
@@ -232,22 +316,22 @@ ${projectDescription ? `**Description:** ${projectDescription}\n` : ''}
|
|
|
232
316
|
function generateInitialHistory(agent, projectName, projectDescription, userName) {
|
|
233
317
|
const displayName = agent.displayName || AGENT_TEMPLATES[agent.role]?.displayName || titleCase(agent.name);
|
|
234
318
|
const now = new Date().toISOString().split('T')[0];
|
|
235
|
-
return `# Project Context
|
|
236
|
-
|
|
237
|
-
${userName ? `- **Owner:** ${userName}\n` : ''}- **Project:** ${projectName}
|
|
238
|
-
${projectDescription ? `- **Description:** ${projectDescription}\n` : ''}- **Created:** ${now}
|
|
239
|
-
|
|
240
|
-
## Core Context
|
|
241
|
-
|
|
242
|
-
Agent ${displayName} initialized and ready for work.
|
|
243
|
-
|
|
244
|
-
## Recent Updates
|
|
245
|
-
|
|
246
|
-
📌 Team initialized on ${now}
|
|
247
|
-
|
|
248
|
-
## Learnings
|
|
249
|
-
|
|
250
|
-
Initial setup complete.
|
|
319
|
+
return `# Project Context
|
|
320
|
+
|
|
321
|
+
${userName ? `- **Owner:** ${userName}\n` : ''}- **Project:** ${projectName}
|
|
322
|
+
${projectDescription ? `- **Description:** ${projectDescription}\n` : ''}- **Created:** ${now}
|
|
323
|
+
|
|
324
|
+
## Core Context
|
|
325
|
+
|
|
326
|
+
Agent ${displayName} initialized and ready for work.
|
|
327
|
+
|
|
328
|
+
## Recent Updates
|
|
329
|
+
|
|
330
|
+
📌 Team initialized on ${now}
|
|
331
|
+
|
|
332
|
+
## Learnings
|
|
333
|
+
|
|
334
|
+
Initial setup complete.
|
|
251
335
|
`;
|
|
252
336
|
}
|
|
253
337
|
/**
|
|
@@ -262,21 +346,45 @@ function titleCase(str) {
|
|
|
262
346
|
// ============================================================================
|
|
263
347
|
// Initialization Functions
|
|
264
348
|
// ============================================================================
|
|
349
|
+
/**
|
|
350
|
+
* Stamp version into squad.agent.md content.
|
|
351
|
+
*/
|
|
352
|
+
function stampVersionInContent(content, version) {
|
|
353
|
+
return content.replace(/<!-- version: [^>]* -->/, `<!-- version: ${version} -->`);
|
|
354
|
+
}
|
|
265
355
|
/**
|
|
266
356
|
* Initialize a new Squad project.
|
|
267
357
|
*
|
|
268
358
|
* Creates:
|
|
269
|
-
* - .squad/ directory structure
|
|
359
|
+
* - .squad/ directory structure (agents, casting, decisions, skills, identity, etc.)
|
|
270
360
|
* - squad.config.ts or squad.config.json
|
|
271
361
|
* - Agent directories with charter.md and history.md
|
|
272
362
|
* - .gitattributes for merge drivers
|
|
363
|
+
* - .gitignore entries for logs
|
|
364
|
+
* - .github/agents/squad.agent.md
|
|
365
|
+
* - .github/workflows/ (optional)
|
|
366
|
+
* - .squad/templates/ (optional)
|
|
367
|
+
* - .copilot/mcp-config.json (optional)
|
|
368
|
+
* - Identity files (now.md, wisdom.md)
|
|
369
|
+
* - ceremonies.md
|
|
273
370
|
*
|
|
274
371
|
* @param options - Initialization options
|
|
275
372
|
* @returns Result with created file paths
|
|
276
373
|
*/
|
|
374
|
+
/**
|
|
375
|
+
* Workflow files that are part of the Squad framework and should always be installed.
|
|
376
|
+
* Other workflows in templates/workflows/ are generic CI/CD scaffolding and are opt-in.
|
|
377
|
+
*/
|
|
378
|
+
const FRAMEWORK_WORKFLOWS = [
|
|
379
|
+
'squad-heartbeat.yml',
|
|
380
|
+
'squad-issue-assign.yml',
|
|
381
|
+
'squad-triage.yml',
|
|
382
|
+
'sync-squad-labels.yml',
|
|
383
|
+
];
|
|
277
384
|
export async function initSquad(options) {
|
|
278
|
-
const { teamRoot, projectName, projectDescription, agents, configFormat = 'typescript', userName } = options;
|
|
385
|
+
const { teamRoot, projectName, projectDescription, agents, configFormat = 'typescript', userName, skipExisting = true, includeWorkflows = true, includeTemplates = true, includeMcpConfig = true, projectType = 'unknown', version = '0.0.0', } = options;
|
|
279
386
|
const createdFiles = [];
|
|
387
|
+
const skippedFiles = [];
|
|
280
388
|
const agentDirs = [];
|
|
281
389
|
// Validate inputs
|
|
282
390
|
if (!teamRoot) {
|
|
@@ -288,40 +396,100 @@ export async function initSquad(options) {
|
|
|
288
396
|
if (!agents || agents.length === 0) {
|
|
289
397
|
throw new Error('At least one agent is required');
|
|
290
398
|
}
|
|
291
|
-
//
|
|
399
|
+
// Get templates directory
|
|
400
|
+
const templatesDir = getSDKTemplatesDir();
|
|
401
|
+
// Helper to convert absolute path to relative
|
|
402
|
+
const toRelativePath = (absolutePath) => {
|
|
403
|
+
// Use path separator-agnostic approach
|
|
404
|
+
if (absolutePath.startsWith(teamRoot)) {
|
|
405
|
+
const relative = absolutePath.slice(teamRoot.length);
|
|
406
|
+
// Remove leading separator if present
|
|
407
|
+
return relative.startsWith('/') || relative.startsWith('\\')
|
|
408
|
+
? relative.slice(1)
|
|
409
|
+
: relative;
|
|
410
|
+
}
|
|
411
|
+
return absolutePath;
|
|
412
|
+
};
|
|
413
|
+
// Helper to write file (respects skipExisting)
|
|
414
|
+
const writeIfNotExists = async (filePath, content) => {
|
|
415
|
+
if (existsSync(filePath) && skipExisting) {
|
|
416
|
+
skippedFiles.push(toRelativePath(filePath));
|
|
417
|
+
return false;
|
|
418
|
+
}
|
|
419
|
+
await mkdir(dirname(filePath), { recursive: true });
|
|
420
|
+
await writeFile(filePath, content, 'utf-8');
|
|
421
|
+
createdFiles.push(toRelativePath(filePath));
|
|
422
|
+
return true;
|
|
423
|
+
};
|
|
424
|
+
// Helper to copy file (respects skipExisting)
|
|
425
|
+
const copyIfNotExists = async (src, dest) => {
|
|
426
|
+
if (existsSync(dest) && skipExisting) {
|
|
427
|
+
skippedFiles.push(toRelativePath(dest));
|
|
428
|
+
return false;
|
|
429
|
+
}
|
|
430
|
+
await mkdir(dirname(dest), { recursive: true });
|
|
431
|
+
cpSync(src, dest);
|
|
432
|
+
createdFiles.push(toRelativePath(dest));
|
|
433
|
+
return true;
|
|
434
|
+
};
|
|
435
|
+
// -------------------------------------------------------------------------
|
|
436
|
+
// Create .squad/ directory structure
|
|
437
|
+
// -------------------------------------------------------------------------
|
|
292
438
|
const squadDir = join(teamRoot, '.squad');
|
|
293
|
-
|
|
294
|
-
|
|
439
|
+
const directories = [
|
|
440
|
+
join(squadDir, 'agents'),
|
|
441
|
+
join(squadDir, 'casting'),
|
|
442
|
+
join(squadDir, 'decisions'),
|
|
443
|
+
join(squadDir, 'decisions', 'inbox'),
|
|
444
|
+
join(squadDir, 'skills'),
|
|
445
|
+
join(squadDir, 'plugins'),
|
|
446
|
+
join(squadDir, 'identity'),
|
|
447
|
+
join(squadDir, 'orchestration-log'),
|
|
448
|
+
join(squadDir, 'log'),
|
|
449
|
+
];
|
|
450
|
+
for (const dir of directories) {
|
|
451
|
+
if (!existsSync(dir)) {
|
|
452
|
+
await mkdir(dir, { recursive: true });
|
|
453
|
+
}
|
|
295
454
|
}
|
|
296
|
-
//
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
455
|
+
// -------------------------------------------------------------------------
|
|
456
|
+
// Create .squad/config.json for squad settings
|
|
457
|
+
// -------------------------------------------------------------------------
|
|
458
|
+
const squadConfigPath = join(squadDir, 'config.json');
|
|
459
|
+
if (!existsSync(squadConfigPath)) {
|
|
460
|
+
const squadConfig = {
|
|
461
|
+
version: 1,
|
|
462
|
+
teamRoot: teamRoot,
|
|
463
|
+
};
|
|
464
|
+
// Only include extractionDisabled if explicitly set
|
|
465
|
+
if (options.extractionDisabled) {
|
|
466
|
+
squadConfig.extractionDisabled = true;
|
|
467
|
+
}
|
|
468
|
+
await writeFile(squadConfigPath, JSON.stringify(squadConfig, null, 2), 'utf-8');
|
|
469
|
+
createdFiles.push(toRelativePath(squadConfigPath));
|
|
300
470
|
}
|
|
301
|
-
//
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
471
|
+
// -------------------------------------------------------------------------
|
|
472
|
+
// Create configuration file
|
|
473
|
+
// -------------------------------------------------------------------------
|
|
474
|
+
// When configFormat is 'markdown', skip config file generation entirely
|
|
475
|
+
let configPath;
|
|
476
|
+
if (configFormat !== 'markdown') {
|
|
477
|
+
const configFileName = configFormat === 'sdk' ? 'squad.config.ts' :
|
|
478
|
+
configFormat === 'typescript' ? 'squad.config.ts' : 'squad.config.json';
|
|
479
|
+
configPath = join(teamRoot, configFileName);
|
|
480
|
+
const configContent = configFormat === 'sdk' ? generateSDKBuilderConfig(options) :
|
|
481
|
+
configFormat === 'typescript' ? generateTypeScriptConfig(options) :
|
|
482
|
+
generateJsonConfig(options);
|
|
483
|
+
await writeIfNotExists(configPath, configContent);
|
|
305
484
|
}
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
await mkdir(decisionsDir, { recursive: true });
|
|
485
|
+
else {
|
|
486
|
+
// No config file for markdown-only mode
|
|
487
|
+
configPath = '';
|
|
310
488
|
}
|
|
311
|
-
//
|
|
312
|
-
const skillsDir = join(squadDir, 'skills');
|
|
313
|
-
if (!existsSync(skillsDir)) {
|
|
314
|
-
await mkdir(skillsDir, { recursive: true });
|
|
315
|
-
}
|
|
316
|
-
// Generate configuration file
|
|
317
|
-
const configFileName = configFormat === 'typescript' ? 'squad.config.ts' : 'squad.config.json';
|
|
318
|
-
const configPath = join(teamRoot, configFileName);
|
|
319
|
-
const configContent = configFormat === 'typescript'
|
|
320
|
-
? generateTypeScriptConfig(options)
|
|
321
|
-
: generateJsonConfig(options);
|
|
322
|
-
await writeFile(configPath, configContent, 'utf-8');
|
|
323
|
-
createdFiles.push(configPath);
|
|
489
|
+
// -------------------------------------------------------------------------
|
|
324
490
|
// Create agent directories and files
|
|
491
|
+
// -------------------------------------------------------------------------
|
|
492
|
+
const agentsDir = join(squadDir, 'agents');
|
|
325
493
|
for (const agent of agents) {
|
|
326
494
|
const agentDir = join(agentsDir, agent.name);
|
|
327
495
|
await mkdir(agentDir, { recursive: true });
|
|
@@ -329,41 +497,311 @@ export async function initSquad(options) {
|
|
|
329
497
|
// Create charter.md
|
|
330
498
|
const charterPath = join(agentDir, 'charter.md');
|
|
331
499
|
const charterContent = generateCharter(agent, projectName, projectDescription);
|
|
332
|
-
await
|
|
333
|
-
createdFiles.push(charterPath);
|
|
500
|
+
await writeIfNotExists(charterPath, charterContent);
|
|
334
501
|
// Create history.md
|
|
335
502
|
const historyPath = join(agentDir, 'history.md');
|
|
336
503
|
const historyContent = generateInitialHistory(agent, projectName, projectDescription, userName);
|
|
337
|
-
await
|
|
338
|
-
createdFiles.push(historyPath);
|
|
504
|
+
await writeIfNotExists(historyPath, historyContent);
|
|
339
505
|
}
|
|
340
|
-
//
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
506
|
+
// -------------------------------------------------------------------------
|
|
507
|
+
// Create identity files (now.md, wisdom.md)
|
|
508
|
+
// -------------------------------------------------------------------------
|
|
509
|
+
const identityDir = join(squadDir, 'identity');
|
|
510
|
+
const nowMdPath = join(identityDir, 'now.md');
|
|
511
|
+
const wisdomMdPath = join(identityDir, 'wisdom.md');
|
|
512
|
+
const nowContent = `---
|
|
513
|
+
updated_at: ${new Date().toISOString()}
|
|
514
|
+
focus_area: Initial setup
|
|
515
|
+
active_issues: []
|
|
516
|
+
---
|
|
517
|
+
|
|
518
|
+
# What We're Focused On
|
|
519
|
+
|
|
520
|
+
Getting started. Updated by coordinator at session start.
|
|
521
|
+
`;
|
|
522
|
+
const wisdomContent = `---
|
|
523
|
+
last_updated: ${new Date().toISOString()}
|
|
524
|
+
---
|
|
525
|
+
|
|
526
|
+
# Team Wisdom
|
|
527
|
+
|
|
528
|
+
Reusable patterns and heuristics learned through work. NOT transcripts — each entry is a distilled, actionable insight.
|
|
529
|
+
|
|
530
|
+
## Patterns
|
|
531
|
+
|
|
532
|
+
<!-- Append entries below. Format: **Pattern:** description. **Context:** when it applies. -->
|
|
533
|
+
`;
|
|
534
|
+
await writeIfNotExists(nowMdPath, nowContent);
|
|
535
|
+
await writeIfNotExists(wisdomMdPath, wisdomContent);
|
|
536
|
+
// -------------------------------------------------------------------------
|
|
537
|
+
// Create ceremonies.md
|
|
538
|
+
// -------------------------------------------------------------------------
|
|
539
|
+
const ceremoniesDest = join(squadDir, 'ceremonies.md');
|
|
540
|
+
if (templatesDir && existsSync(join(templatesDir, 'ceremonies.md'))) {
|
|
541
|
+
await copyIfNotExists(join(templatesDir, 'ceremonies.md'), ceremoniesDest);
|
|
542
|
+
}
|
|
543
|
+
// -------------------------------------------------------------------------
|
|
544
|
+
// Create decisions.md (canonical location at squad root)
|
|
545
|
+
// -------------------------------------------------------------------------
|
|
546
|
+
const decisionsPath = join(squadDir, 'decisions.md');
|
|
547
|
+
const decisionsContent = `# Squad Decisions
|
|
548
|
+
|
|
549
|
+
## Active Decisions
|
|
550
|
+
|
|
551
|
+
No decisions recorded yet.
|
|
552
|
+
|
|
553
|
+
## Governance
|
|
554
|
+
|
|
555
|
+
- All meaningful changes require team consensus
|
|
556
|
+
- Document architectural decisions here
|
|
557
|
+
- Keep history focused on work, decisions focused on direction
|
|
558
|
+
`;
|
|
559
|
+
await writeIfNotExists(decisionsPath, decisionsContent);
|
|
560
|
+
// -------------------------------------------------------------------------
|
|
561
|
+
// Create team.md (required by shell lifecycle)
|
|
562
|
+
// -------------------------------------------------------------------------
|
|
563
|
+
const teamPath = join(squadDir, 'team.md');
|
|
564
|
+
const teamContent = `# Squad Team
|
|
565
|
+
|
|
566
|
+
> ${projectDescription || projectName}
|
|
567
|
+
|
|
568
|
+
## Coordinator
|
|
569
|
+
|
|
570
|
+
| Name | Role | Notes |
|
|
571
|
+
|------|------|-------|
|
|
572
|
+
| Squad | Coordinator | Routes work, enforces handoffs and reviewer gates. |
|
|
573
|
+
|
|
574
|
+
## Members
|
|
575
|
+
|
|
576
|
+
| Name | Role | Charter | Status |
|
|
577
|
+
|------|------|---------|--------|
|
|
578
|
+
|
|
579
|
+
## Project Context
|
|
580
|
+
|
|
581
|
+
- **Project:** ${projectName}
|
|
582
|
+
${projectDescription ? `- **Description:** ${projectDescription}\n` : ''}- **Created:** ${new Date().toISOString().split('T')[0]}
|
|
344
583
|
`;
|
|
345
|
-
await
|
|
346
|
-
|
|
347
|
-
// Create
|
|
348
|
-
|
|
349
|
-
const
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
584
|
+
await writeIfNotExists(teamPath, teamContent);
|
|
585
|
+
// -------------------------------------------------------------------------
|
|
586
|
+
// Create routing.md
|
|
587
|
+
// -------------------------------------------------------------------------
|
|
588
|
+
const routingPath = join(squadDir, 'routing.md');
|
|
589
|
+
if (templatesDir && existsSync(join(templatesDir, 'routing.md'))) {
|
|
590
|
+
await copyIfNotExists(join(templatesDir, 'routing.md'), routingPath);
|
|
591
|
+
}
|
|
592
|
+
else {
|
|
593
|
+
const routingContent = `# Squad Routing
|
|
594
|
+
|
|
595
|
+
## Work Type Rules
|
|
596
|
+
|
|
597
|
+
| Work Type | Primary Agent | Fallback |
|
|
598
|
+
|-----------|---------------|----------|
|
|
599
|
+
|
|
600
|
+
## Governance
|
|
601
|
+
|
|
602
|
+
- Route based on work type and agent expertise
|
|
603
|
+
- Update this file as team capabilities evolve
|
|
360
604
|
`;
|
|
361
|
-
|
|
362
|
-
|
|
605
|
+
await writeIfNotExists(routingPath, routingContent);
|
|
606
|
+
}
|
|
607
|
+
// -------------------------------------------------------------------------
|
|
608
|
+
// Copy starter skills
|
|
609
|
+
// -------------------------------------------------------------------------
|
|
610
|
+
const skillsDir = join(squadDir, 'skills');
|
|
611
|
+
if (templatesDir && existsSync(join(templatesDir, 'skills'))) {
|
|
612
|
+
const skillsSrc = join(templatesDir, 'skills');
|
|
613
|
+
const existingSkills = existsSync(skillsDir) ? readdirSync(skillsDir) : [];
|
|
614
|
+
if (existingSkills.length === 0) {
|
|
615
|
+
cpSync(skillsSrc, skillsDir, { recursive: true });
|
|
616
|
+
createdFiles.push('.squad/skills');
|
|
617
|
+
}
|
|
618
|
+
}
|
|
619
|
+
// -------------------------------------------------------------------------
|
|
620
|
+
// Create .gitattributes for merge drivers
|
|
621
|
+
// -------------------------------------------------------------------------
|
|
622
|
+
const gitattributesPath = join(teamRoot, '.gitattributes');
|
|
623
|
+
const unionRules = [
|
|
624
|
+
'.squad/decisions.md merge=union',
|
|
625
|
+
'.squad/agents/*/history.md merge=union',
|
|
626
|
+
'.squad/log/** merge=union',
|
|
627
|
+
'.squad/orchestration-log/** merge=union',
|
|
628
|
+
];
|
|
629
|
+
let existingAttrs = '';
|
|
630
|
+
if (existsSync(gitattributesPath)) {
|
|
631
|
+
existingAttrs = readFileSync(gitattributesPath, 'utf-8');
|
|
632
|
+
}
|
|
633
|
+
const missingRules = unionRules.filter(rule => !existingAttrs.includes(rule));
|
|
634
|
+
if (missingRules.length > 0) {
|
|
635
|
+
const block = (existingAttrs && !existingAttrs.endsWith('\n') ? '\n' : '')
|
|
636
|
+
+ '# Squad: union merge for append-only team state files\n'
|
|
637
|
+
+ missingRules.join('\n') + '\n';
|
|
638
|
+
await appendFile(gitattributesPath, block);
|
|
639
|
+
createdFiles.push(toRelativePath(gitattributesPath));
|
|
640
|
+
}
|
|
641
|
+
// -------------------------------------------------------------------------
|
|
642
|
+
// Create .gitignore entries for runtime state (logs, inbox, sessions)
|
|
643
|
+
// These paths are written during normal squad operation but should not be
|
|
644
|
+
// committed to version control (they are runtime state).
|
|
645
|
+
// -------------------------------------------------------------------------
|
|
646
|
+
const gitignorePath = join(teamRoot, '.gitignore');
|
|
647
|
+
const ignoreEntries = [
|
|
648
|
+
'.squad/orchestration-log/',
|
|
649
|
+
'.squad/log/',
|
|
650
|
+
'.squad/decisions/inbox/',
|
|
651
|
+
'.squad/sessions/',
|
|
652
|
+
];
|
|
653
|
+
let existingIgnore = '';
|
|
654
|
+
if (existsSync(gitignorePath)) {
|
|
655
|
+
existingIgnore = readFileSync(gitignorePath, 'utf-8');
|
|
656
|
+
}
|
|
657
|
+
const missingIgnore = ignoreEntries.filter(entry => !existingIgnore.includes(entry));
|
|
658
|
+
if (missingIgnore.length > 0) {
|
|
659
|
+
const block = (existingIgnore && !existingIgnore.endsWith('\n') ? '\n' : '')
|
|
660
|
+
+ '# Squad: ignore runtime state (logs, inbox, sessions)\n'
|
|
661
|
+
+ missingIgnore.join('\n') + '\n';
|
|
662
|
+
await appendFile(gitignorePath, block);
|
|
663
|
+
createdFiles.push(toRelativePath(gitignorePath));
|
|
664
|
+
}
|
|
665
|
+
// -------------------------------------------------------------------------
|
|
666
|
+
// Create .github/agents/squad.agent.md
|
|
667
|
+
// -------------------------------------------------------------------------
|
|
668
|
+
const agentFile = join(teamRoot, '.github', 'agents', 'squad.agent.md');
|
|
669
|
+
if (!existsSync(agentFile) || !skipExisting) {
|
|
670
|
+
if (templatesDir && existsSync(join(templatesDir, 'squad.agent.md'))) {
|
|
671
|
+
let agentContent = readFileSync(join(templatesDir, 'squad.agent.md'), 'utf-8');
|
|
672
|
+
agentContent = stampVersionInContent(agentContent, version);
|
|
673
|
+
await mkdir(dirname(agentFile), { recursive: true });
|
|
674
|
+
await writeFile(agentFile, agentContent, 'utf-8');
|
|
675
|
+
createdFiles.push(toRelativePath(agentFile));
|
|
676
|
+
}
|
|
677
|
+
}
|
|
678
|
+
else {
|
|
679
|
+
skippedFiles.push(toRelativePath(agentFile));
|
|
680
|
+
}
|
|
681
|
+
// -------------------------------------------------------------------------
|
|
682
|
+
// Copy .squad/templates/ (optional)
|
|
683
|
+
// -------------------------------------------------------------------------
|
|
684
|
+
if (includeTemplates && templatesDir) {
|
|
685
|
+
const templatesDest = join(teamRoot, '.squad', 'templates');
|
|
686
|
+
if (!existsSync(templatesDest)) {
|
|
687
|
+
cpSync(templatesDir, templatesDest, { recursive: true });
|
|
688
|
+
createdFiles.push(toRelativePath(templatesDest));
|
|
689
|
+
}
|
|
690
|
+
else {
|
|
691
|
+
skippedFiles.push(toRelativePath(templatesDest));
|
|
692
|
+
}
|
|
693
|
+
}
|
|
694
|
+
// -------------------------------------------------------------------------
|
|
695
|
+
// Copy workflows (optional)
|
|
696
|
+
// -------------------------------------------------------------------------
|
|
697
|
+
if (includeWorkflows && templatesDir && existsSync(join(templatesDir, 'workflows'))) {
|
|
698
|
+
const workflowsSrc = join(templatesDir, 'workflows');
|
|
699
|
+
const workflowsDest = join(teamRoot, '.github', 'workflows');
|
|
700
|
+
if (statSync(workflowsSrc).isDirectory()) {
|
|
701
|
+
const allWorkflowFiles = readdirSync(workflowsSrc).filter(f => f.endsWith('.yml'));
|
|
702
|
+
const workflowFiles = allWorkflowFiles.filter(f => FRAMEWORK_WORKFLOWS.includes(f));
|
|
703
|
+
await mkdir(workflowsDest, { recursive: true });
|
|
704
|
+
for (const file of workflowFiles) {
|
|
705
|
+
const destFile = join(workflowsDest, file);
|
|
706
|
+
if (!existsSync(destFile) || !skipExisting) {
|
|
707
|
+
cpSync(join(workflowsSrc, file), destFile);
|
|
708
|
+
createdFiles.push(toRelativePath(destFile));
|
|
709
|
+
}
|
|
710
|
+
else {
|
|
711
|
+
skippedFiles.push(toRelativePath(destFile));
|
|
712
|
+
}
|
|
713
|
+
}
|
|
714
|
+
}
|
|
715
|
+
}
|
|
716
|
+
// -------------------------------------------------------------------------
|
|
717
|
+
// Create sample MCP config (optional)
|
|
718
|
+
// -------------------------------------------------------------------------
|
|
719
|
+
if (includeMcpConfig) {
|
|
720
|
+
const mcpConfigPath = join(teamRoot, '.copilot', 'mcp-config.json');
|
|
721
|
+
if (!existsSync(mcpConfigPath)) {
|
|
722
|
+
const mcpSample = {
|
|
723
|
+
mcpServers: {
|
|
724
|
+
"EXAMPLE-trello": {
|
|
725
|
+
command: "npx",
|
|
726
|
+
args: ["-y", "@trello/mcp-server"],
|
|
727
|
+
env: {
|
|
728
|
+
TRELLO_API_KEY: "${TRELLO_API_KEY}",
|
|
729
|
+
TRELLO_TOKEN: "${TRELLO_TOKEN}"
|
|
730
|
+
}
|
|
731
|
+
}
|
|
732
|
+
}
|
|
733
|
+
};
|
|
734
|
+
await mkdir(dirname(mcpConfigPath), { recursive: true });
|
|
735
|
+
await writeFile(mcpConfigPath, JSON.stringify(mcpSample, null, 2) + '\n', 'utf-8');
|
|
736
|
+
createdFiles.push(toRelativePath(mcpConfigPath));
|
|
737
|
+
}
|
|
738
|
+
else {
|
|
739
|
+
skippedFiles.push(toRelativePath(mcpConfigPath));
|
|
740
|
+
}
|
|
741
|
+
}
|
|
742
|
+
// -------------------------------------------------------------------------
|
|
743
|
+
// Generate .squad/workstreams.json (when streams provided)
|
|
744
|
+
// -------------------------------------------------------------------------
|
|
745
|
+
if (options.streams && options.streams.length > 0) {
|
|
746
|
+
const workstreamsConfig = {
|
|
747
|
+
workstreams: options.streams,
|
|
748
|
+
defaultWorkflow: 'branch-per-issue',
|
|
749
|
+
};
|
|
750
|
+
const workstreamsPath = join(squadDir, 'workstreams.json');
|
|
751
|
+
await writeIfNotExists(workstreamsPath, JSON.stringify(workstreamsConfig, null, 2) + '\n');
|
|
752
|
+
}
|
|
753
|
+
// -------------------------------------------------------------------------
|
|
754
|
+
// Add .squad-workstream to .gitignore
|
|
755
|
+
// -------------------------------------------------------------------------
|
|
756
|
+
{
|
|
757
|
+
const workstreamIgnoreEntry = '.squad-workstream';
|
|
758
|
+
let currentIgnore = '';
|
|
759
|
+
if (existsSync(gitignorePath)) {
|
|
760
|
+
currentIgnore = readFileSync(gitignorePath, 'utf-8');
|
|
761
|
+
}
|
|
762
|
+
if (!currentIgnore.includes(workstreamIgnoreEntry)) {
|
|
763
|
+
const block = (currentIgnore && !currentIgnore.endsWith('\n') ? '\n' : '')
|
|
764
|
+
+ '# Squad: workstream activation file (local to this machine)\n'
|
|
765
|
+
+ workstreamIgnoreEntry + '\n';
|
|
766
|
+
await appendFile(gitignorePath, block);
|
|
767
|
+
createdFiles.push(toRelativePath(gitignorePath));
|
|
768
|
+
}
|
|
769
|
+
}
|
|
770
|
+
// -------------------------------------------------------------------------
|
|
771
|
+
// Create .first-run marker
|
|
772
|
+
// -------------------------------------------------------------------------
|
|
773
|
+
const firstRunMarker = join(squadDir, '.first-run');
|
|
774
|
+
if (!existsSync(firstRunMarker)) {
|
|
775
|
+
await writeFile(firstRunMarker, new Date().toISOString() + '\n', 'utf-8');
|
|
776
|
+
createdFiles.push(toRelativePath(firstRunMarker));
|
|
777
|
+
}
|
|
778
|
+
// -------------------------------------------------------------------------
|
|
779
|
+
// Store init prompt for REPL auto-casting
|
|
780
|
+
// -------------------------------------------------------------------------
|
|
781
|
+
if (options.prompt) {
|
|
782
|
+
const promptFile = join(squadDir, '.init-prompt');
|
|
783
|
+
await writeFile(promptFile, options.prompt, 'utf-8');
|
|
784
|
+
createdFiles.push(toRelativePath(promptFile));
|
|
785
|
+
}
|
|
363
786
|
return {
|
|
364
787
|
createdFiles,
|
|
788
|
+
skippedFiles,
|
|
365
789
|
configPath,
|
|
366
|
-
agentDirs
|
|
790
|
+
agentDirs,
|
|
791
|
+
agentFile,
|
|
792
|
+
squadDir,
|
|
367
793
|
};
|
|
368
794
|
}
|
|
795
|
+
/**
|
|
796
|
+
* Clean up orphan .init-prompt file.
|
|
797
|
+
* Called by CLI on Ctrl+C abort to remove partial state.
|
|
798
|
+
*
|
|
799
|
+
* @param squadDir - Path to the .squad directory
|
|
800
|
+
*/
|
|
801
|
+
export async function cleanupOrphanInitPrompt(squadDir) {
|
|
802
|
+
const promptFile = join(squadDir, '.init-prompt');
|
|
803
|
+
if (existsSync(promptFile)) {
|
|
804
|
+
await unlink(promptFile);
|
|
805
|
+
}
|
|
806
|
+
}
|
|
369
807
|
//# sourceMappingURL=init.js.map
|