@bradygaster/squad-cli 0.6.2 → 0.8.0
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 +77 -77
- package/dist/cli/commands/copilot.d.ts +13 -0
- package/dist/cli/commands/copilot.d.ts.map +1 -0
- package/dist/cli/commands/copilot.js +86 -0
- package/dist/cli/commands/copilot.js.map +1 -0
- package/dist/cli/commands/export.d.ts +9 -0
- package/dist/cli/commands/export.d.ts.map +1 -0
- package/dist/cli/commands/export.js +89 -0
- package/dist/cli/commands/export.js.map +1 -0
- package/dist/cli/commands/import.d.ts +9 -0
- package/dist/cli/commands/import.d.ts.map +1 -0
- package/dist/cli/commands/import.js +116 -0
- package/dist/cli/commands/import.js.map +1 -0
- package/dist/cli/commands/plugin.d.ts +14 -0
- package/dist/cli/commands/plugin.d.ts.map +1 -0
- package/dist/cli/commands/plugin.js +134 -0
- package/dist/cli/commands/plugin.js.map +1 -0
- package/dist/cli/commands/watch.d.ts +8 -0
- package/dist/cli/commands/watch.d.ts.map +1 -0
- package/dist/cli/commands/watch.js +178 -0
- package/dist/cli/commands/watch.js.map +1 -0
- package/dist/cli/copilot-install.d.ts +73 -0
- package/dist/cli/copilot-install.d.ts.map +1 -0
- package/dist/cli/copilot-install.js +117 -0
- package/dist/cli/copilot-install.js.map +1 -0
- package/dist/cli/core/detect-squad-dir.d.ts +13 -0
- package/dist/cli/core/detect-squad-dir.d.ts.map +1 -0
- package/dist/cli/core/detect-squad-dir.js +21 -0
- package/dist/cli/core/detect-squad-dir.js.map +1 -0
- package/dist/cli/core/email-scrub.d.ts +10 -0
- package/dist/cli/core/email-scrub.d.ts.map +1 -0
- package/dist/cli/core/email-scrub.js +103 -0
- package/dist/cli/core/email-scrub.js.map +1 -0
- package/dist/cli/core/errors.d.ts +17 -0
- package/dist/cli/core/errors.d.ts.map +1 -0
- package/dist/cli/core/errors.js +22 -0
- package/dist/cli/core/errors.js.map +1 -0
- package/dist/cli/core/gh-cli.d.ts +41 -0
- package/dist/cli/core/gh-cli.d.ts.map +1 -0
- package/dist/cli/core/gh-cli.js +67 -0
- package/dist/cli/core/gh-cli.js.map +1 -0
- package/dist/cli/core/history-split.d.ts +9 -0
- package/dist/cli/core/history-split.d.ts.map +1 -0
- package/dist/cli/core/history-split.js +65 -0
- package/dist/cli/core/history-split.js.map +1 -0
- package/dist/cli/core/init.d.ts +9 -0
- package/dist/cli/core/init.d.ts.map +1 -0
- package/dist/cli/core/init.js +296 -0
- package/dist/cli/core/init.js.map +1 -0
- package/dist/cli/core/migrate-directory.d.ts +11 -0
- package/dist/cli/core/migrate-directory.d.ts.map +1 -0
- package/dist/cli/core/migrate-directory.js +71 -0
- package/dist/cli/core/migrate-directory.js.map +1 -0
- package/dist/cli/core/migrations.d.ts +11 -0
- package/dist/cli/core/migrations.d.ts.map +1 -0
- package/dist/cli/core/migrations.js +78 -0
- package/dist/cli/core/migrations.js.map +1 -0
- package/dist/cli/core/output.d.ts +34 -0
- package/dist/cli/core/output.d.ts.map +1 -0
- package/dist/cli/core/output.js +47 -0
- package/dist/cli/core/output.js.map +1 -0
- package/dist/cli/core/project-type.d.ts +9 -0
- package/dist/cli/core/project-type.d.ts.map +1 -0
- package/dist/cli/core/project-type.js +29 -0
- package/dist/cli/core/project-type.js.map +1 -0
- package/dist/cli/core/team-md.d.ts +28 -0
- package/dist/cli/core/team-md.d.ts.map +1 -0
- package/dist/cli/core/team-md.js +91 -0
- package/dist/cli/core/team-md.js.map +1 -0
- package/dist/cli/core/templates.d.ts +30 -0
- package/dist/cli/core/templates.d.ts.map +1 -0
- package/dist/cli/core/templates.js +247 -0
- package/dist/cli/core/templates.js.map +1 -0
- package/dist/cli/core/upgrade.d.ts +20 -0
- package/dist/cli/core/upgrade.d.ts.map +1 -0
- package/dist/cli/core/upgrade.js +399 -0
- package/dist/cli/core/upgrade.js.map +1 -0
- package/dist/cli/core/version.d.ts +18 -0
- package/dist/cli/core/version.d.ts.map +1 -0
- package/dist/cli/core/version.js +61 -0
- package/dist/cli/core/version.js.map +1 -0
- package/dist/cli/core/workflows.d.ts +10 -0
- package/dist/cli/core/workflows.d.ts.map +1 -0
- package/dist/cli/core/workflows.js +155 -0
- package/dist/cli/core/workflows.js.map +1 -0
- package/dist/cli/index.d.ts +26 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +26 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/shell/autocomplete.d.ts +12 -0
- package/dist/cli/shell/autocomplete.d.ts.map +1 -0
- package/dist/cli/shell/autocomplete.js +39 -0
- package/dist/cli/shell/autocomplete.js.map +1 -0
- package/dist/cli/shell/commands.d.ts +19 -0
- package/dist/cli/shell/commands.d.ts.map +1 -0
- package/dist/cli/shell/commands.js +87 -0
- package/dist/cli/shell/commands.js.map +1 -0
- package/dist/cli/shell/components/AgentPanel.d.ts +8 -0
- package/dist/cli/shell/components/AgentPanel.d.ts.map +1 -0
- package/dist/cli/shell/components/AgentPanel.js +17 -0
- package/dist/cli/shell/components/AgentPanel.js.map +1 -0
- package/dist/cli/shell/components/InputPrompt.d.ts +9 -0
- package/dist/cli/shell/components/InputPrompt.d.ts.map +1 -0
- package/dist/cli/shell/components/InputPrompt.js +50 -0
- package/dist/cli/shell/components/InputPrompt.js.map +1 -0
- package/dist/cli/shell/components/MessageStream.d.ts +13 -0
- package/dist/cli/shell/components/MessageStream.d.ts.map +1 -0
- package/dist/cli/shell/components/MessageStream.js +7 -0
- package/dist/cli/shell/components/MessageStream.js.map +1 -0
- package/dist/cli/shell/components/index.d.ts +4 -0
- package/dist/cli/shell/components/index.d.ts.map +1 -0
- package/dist/cli/shell/components/index.js +4 -0
- package/dist/cli/shell/components/index.js.map +1 -0
- package/dist/cli/shell/coordinator.d.ts +32 -0
- package/dist/cli/shell/coordinator.d.ts.map +1 -0
- package/dist/cli/shell/coordinator.js +113 -0
- package/dist/cli/shell/coordinator.js.map +1 -0
- package/dist/cli/shell/index.d.ts +28 -0
- package/dist/cli/shell/index.d.ts.map +1 -0
- package/dist/cli/shell/index.js +66 -0
- package/dist/cli/shell/index.js.map +1 -0
- package/dist/cli/shell/lifecycle.d.ts +52 -0
- package/dist/cli/shell/lifecycle.d.ts.map +1 -0
- package/dist/cli/shell/lifecycle.js +168 -0
- package/dist/cli/shell/lifecycle.js.map +1 -0
- package/dist/cli/shell/memory.d.ts +36 -0
- package/dist/cli/shell/memory.d.ts.map +1 -0
- package/dist/cli/shell/memory.js +53 -0
- package/dist/cli/shell/memory.js.map +1 -0
- package/dist/cli/shell/render.d.ts +22 -0
- package/dist/cli/shell/render.d.ts.map +1 -0
- package/dist/cli/shell/render.js +44 -0
- package/dist/cli/shell/render.js.map +1 -0
- package/dist/cli/shell/router.d.ts +17 -0
- package/dist/cli/shell/router.d.ts.map +1 -0
- package/dist/cli/shell/router.js +55 -0
- package/dist/cli/shell/router.js.map +1 -0
- package/dist/cli/shell/sessions.d.ts +15 -0
- package/dist/cli/shell/sessions.d.ts.map +1 -0
- package/dist/cli/shell/sessions.js +37 -0
- package/dist/cli/shell/sessions.js.map +1 -0
- package/dist/cli/shell/spawn.d.ts +47 -0
- package/dist/cli/shell/spawn.d.ts.map +1 -0
- package/dist/cli/shell/spawn.js +77 -0
- package/dist/cli/shell/spawn.js.map +1 -0
- package/dist/cli/shell/stream-bridge.d.ts +60 -0
- package/dist/cli/shell/stream-bridge.d.ts.map +1 -0
- package/dist/cli/shell/stream-bridge.js +98 -0
- package/dist/cli/shell/stream-bridge.js.map +1 -0
- package/dist/cli/shell/terminal.d.ts +30 -0
- package/dist/cli/shell/terminal.d.ts.map +1 -0
- package/dist/cli/shell/terminal.js +34 -0
- package/dist/cli/shell/terminal.js.map +1 -0
- package/dist/cli/shell/types.d.ts +21 -0
- package/dist/cli/shell/types.d.ts.map +1 -0
- package/dist/cli/shell/types.js +5 -0
- package/dist/cli/shell/types.js.map +1 -0
- package/dist/cli/upgrade.d.ts +141 -0
- package/dist/cli/upgrade.d.ts.map +1 -0
- package/dist/cli/upgrade.js +226 -0
- package/dist/cli/upgrade.js.map +1 -0
- package/dist/cli-entry.d.ts +10 -0
- package/dist/cli-entry.d.ts.map +1 -0
- package/dist/cli-entry.js +213 -0
- package/dist/cli-entry.js.map +1 -0
- package/package.json +44 -34
- 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 +90 -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/squad-conventions/SKILL.md +69 -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 +315 -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-main-guard.yml +129 -0
- package/templates/workflows/squad-preview.yml +55 -0
- package/templates/workflows/squad-promote.yml +121 -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
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Email scrubbing utility — removes PII from Squad state files
|
|
3
|
+
* @module cli/core/email-scrub
|
|
4
|
+
*/
|
|
5
|
+
import fs from 'node:fs';
|
|
6
|
+
import path from 'node:path';
|
|
7
|
+
const EMAIL_PATTERN = /([a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,})/g;
|
|
8
|
+
const NAME_WITH_EMAIL_PATTERN = /([a-zA-Z0-9_-]+)\s*\(([a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,})\)/g;
|
|
9
|
+
/**
|
|
10
|
+
* Scrub email addresses from all files in a directory
|
|
11
|
+
* Returns count of files scrubbed
|
|
12
|
+
*/
|
|
13
|
+
export async function scrubEmails(dir) {
|
|
14
|
+
const scrubbedFiles = [];
|
|
15
|
+
const filesToScrub = [
|
|
16
|
+
'team.md',
|
|
17
|
+
'decisions.md',
|
|
18
|
+
'routing.md',
|
|
19
|
+
'ceremonies.md'
|
|
20
|
+
];
|
|
21
|
+
// Scrub root-level files
|
|
22
|
+
for (const file of filesToScrub) {
|
|
23
|
+
const filePath = path.join(dir, file);
|
|
24
|
+
if (fs.existsSync(filePath)) {
|
|
25
|
+
if (scrubFile(filePath)) {
|
|
26
|
+
scrubbedFiles.push(file);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
// Scrub agent history files
|
|
31
|
+
const agentsDir = path.join(dir, 'agents');
|
|
32
|
+
if (fs.existsSync(agentsDir)) {
|
|
33
|
+
try {
|
|
34
|
+
for (const agentName of fs.readdirSync(agentsDir)) {
|
|
35
|
+
const historyPath = path.join(agentsDir, agentName, 'history.md');
|
|
36
|
+
if (fs.existsSync(historyPath)) {
|
|
37
|
+
if (scrubFile(historyPath)) {
|
|
38
|
+
scrubbedFiles.push(path.join('agents', agentName, 'history.md'));
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
// Ignore errors reading agents directory
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
// Scrub log files
|
|
48
|
+
const logDir = path.join(dir, 'log');
|
|
49
|
+
if (fs.existsSync(logDir)) {
|
|
50
|
+
try {
|
|
51
|
+
const logFiles = fs.readdirSync(logDir)
|
|
52
|
+
.filter(f => f.endsWith('.md') || f.endsWith('.txt') || f.endsWith('.log'));
|
|
53
|
+
for (const file of logFiles) {
|
|
54
|
+
const filePath = path.join(logDir, file);
|
|
55
|
+
if (scrubFile(filePath)) {
|
|
56
|
+
scrubbedFiles.push(path.join('log', file));
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
catch {
|
|
61
|
+
// Ignore errors reading log directory
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return scrubbedFiles.length;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Scrub emails from a single file
|
|
68
|
+
* Returns true if file was modified
|
|
69
|
+
*/
|
|
70
|
+
function scrubFile(filePath) {
|
|
71
|
+
try {
|
|
72
|
+
let content = fs.readFileSync(filePath, 'utf8');
|
|
73
|
+
let modified = false;
|
|
74
|
+
// Replace "name (email)" → "name"
|
|
75
|
+
const beforeNameEmail = content;
|
|
76
|
+
content = content.replace(NAME_WITH_EMAIL_PATTERN, '$1');
|
|
77
|
+
if (content !== beforeNameEmail)
|
|
78
|
+
modified = true;
|
|
79
|
+
// Replace bare emails in identity contexts (preserve in URLs and code)
|
|
80
|
+
const lines = content.split('\n');
|
|
81
|
+
const scrubbed = lines.map(line => {
|
|
82
|
+
// Skip lines that look like URLs, code blocks, or examples
|
|
83
|
+
if (line.includes('http://') || line.includes('https://') ||
|
|
84
|
+
line.includes('```') || line.includes('example.com') ||
|
|
85
|
+
line.trim().startsWith('//') || line.trim().startsWith('#')) {
|
|
86
|
+
return line;
|
|
87
|
+
}
|
|
88
|
+
const before = line;
|
|
89
|
+
const after = line.replace(EMAIL_PATTERN, '[email scrubbed]');
|
|
90
|
+
if (before !== after)
|
|
91
|
+
modified = true;
|
|
92
|
+
return after;
|
|
93
|
+
});
|
|
94
|
+
if (modified) {
|
|
95
|
+
fs.writeFileSync(filePath, scrubbed.join('\n'));
|
|
96
|
+
}
|
|
97
|
+
return modified;
|
|
98
|
+
}
|
|
99
|
+
catch {
|
|
100
|
+
return false;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
//# sourceMappingURL=email-scrub.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"email-scrub.js","sourceRoot":"","sources":["../../../src/cli/core/email-scrub.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Error handling utilities — zero dependencies
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Error class for fatal CLI errors.
|
|
6
|
+
* CLI entry points catch these and call process.exit(1).
|
|
7
|
+
* Library consumers can catch the SquadError normally.
|
|
8
|
+
*/
|
|
9
|
+
export declare class SquadError extends Error {
|
|
10
|
+
constructor(message: string);
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Throw a fatal error. In CLI context, the entry point catches and exits.
|
|
14
|
+
* In library context, callers can catch the SquadError normally.
|
|
15
|
+
*/
|
|
16
|
+
export declare function fatal(msg: string): never;
|
|
17
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../../src/cli/core/errors.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;;;GAIG;AACH,qBAAa,UAAW,SAAQ,KAAK;gBACvB,OAAO,EAAE,MAAM;CAI5B;AAED;;;GAGG;AACH,wBAAgB,KAAK,CAAC,GAAG,EAAE,MAAM,GAAG,KAAK,CAExC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Error handling utilities — zero dependencies
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Error class for fatal CLI errors.
|
|
6
|
+
* CLI entry points catch these and call process.exit(1).
|
|
7
|
+
* Library consumers can catch the SquadError normally.
|
|
8
|
+
*/
|
|
9
|
+
export class SquadError extends Error {
|
|
10
|
+
constructor(message) {
|
|
11
|
+
super(message);
|
|
12
|
+
this.name = 'SquadError';
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Throw a fatal error. In CLI context, the entry point catches and exits.
|
|
17
|
+
* In library context, callers can catch the SquadError normally.
|
|
18
|
+
*/
|
|
19
|
+
export function fatal(msg) {
|
|
20
|
+
throw new SquadError(msg);
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../../../src/cli/core/errors.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;;;GAIG;AACH,MAAM,OAAO,UAAW,SAAQ,KAAK;IACnC,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,YAAY,CAAC;IAC3B,CAAC;CACF;AAED;;;GAGG;AACH,MAAM,UAAU,KAAK,CAAC,GAAW;IAC/B,MAAM,IAAI,UAAU,CAAC,GAAG,CAAC,CAAC;AAC5B,CAAC"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GitHub CLI wrapper utilities — zero dependencies
|
|
3
|
+
*/
|
|
4
|
+
export interface GhIssue {
|
|
5
|
+
number: number;
|
|
6
|
+
title: string;
|
|
7
|
+
labels: Array<{
|
|
8
|
+
name: string;
|
|
9
|
+
}>;
|
|
10
|
+
assignees: Array<{
|
|
11
|
+
login: string;
|
|
12
|
+
}>;
|
|
13
|
+
}
|
|
14
|
+
export interface GhListOptions {
|
|
15
|
+
label?: string;
|
|
16
|
+
state?: 'open' | 'closed' | 'all';
|
|
17
|
+
limit?: number;
|
|
18
|
+
}
|
|
19
|
+
export interface GhEditOptions {
|
|
20
|
+
addLabel?: string;
|
|
21
|
+
removeLabel?: string;
|
|
22
|
+
addAssignee?: string;
|
|
23
|
+
removeAssignee?: string;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Check if gh CLI is available
|
|
27
|
+
*/
|
|
28
|
+
export declare function ghAvailable(): Promise<boolean>;
|
|
29
|
+
/**
|
|
30
|
+
* Check if gh CLI is authenticated
|
|
31
|
+
*/
|
|
32
|
+
export declare function ghAuthenticated(): Promise<boolean>;
|
|
33
|
+
/**
|
|
34
|
+
* List issues with optional filters
|
|
35
|
+
*/
|
|
36
|
+
export declare function ghIssueList(options?: GhListOptions): Promise<GhIssue[]>;
|
|
37
|
+
/**
|
|
38
|
+
* Edit an issue (add/remove labels or assignees)
|
|
39
|
+
*/
|
|
40
|
+
export declare function ghIssueEdit(issueNumber: number, options: GhEditOptions): Promise<void>;
|
|
41
|
+
//# sourceMappingURL=gh-cli.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gh-cli.d.ts","sourceRoot":"","sources":["../../../src/cli/core/gh-cli.ts"],"names":[],"mappings":"AAAA;;GAEG;AAOH,MAAM,WAAW,OAAO;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAChC,SAAS,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACrC;AAED,MAAM,WAAW,aAAa;IAC5B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,GAAG,QAAQ,GAAG,KAAK,CAAC;IAClC,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED;;GAEG;AACH,wBAAsB,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC,CAOpD;AAED;;GAEG;AACH,wBAAsB,eAAe,IAAI,OAAO,CAAC,OAAO,CAAC,CAOxD;AAED;;GAEG;AACH,wBAAsB,WAAW,CAAC,OAAO,GAAE,aAAkB,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,CAejF;AAED;;GAEG;AACH,wBAAsB,WAAW,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAiB5F"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GitHub CLI wrapper utilities — zero dependencies
|
|
3
|
+
*/
|
|
4
|
+
import { execFile } from 'node:child_process';
|
|
5
|
+
import { promisify } from 'node:util';
|
|
6
|
+
const execFileAsync = promisify(execFile);
|
|
7
|
+
/**
|
|
8
|
+
* Check if gh CLI is available
|
|
9
|
+
*/
|
|
10
|
+
export async function ghAvailable() {
|
|
11
|
+
try {
|
|
12
|
+
await execFileAsync('gh', ['--version']);
|
|
13
|
+
return true;
|
|
14
|
+
}
|
|
15
|
+
catch {
|
|
16
|
+
return false;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Check if gh CLI is authenticated
|
|
21
|
+
*/
|
|
22
|
+
export async function ghAuthenticated() {
|
|
23
|
+
try {
|
|
24
|
+
await execFileAsync('gh', ['auth', 'status']);
|
|
25
|
+
return true;
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* List issues with optional filters
|
|
33
|
+
*/
|
|
34
|
+
export async function ghIssueList(options = {}) {
|
|
35
|
+
const args = ['issue', 'list', '--json', 'number,title,labels,assignees'];
|
|
36
|
+
if (options.label) {
|
|
37
|
+
args.push('--label', options.label);
|
|
38
|
+
}
|
|
39
|
+
if (options.state) {
|
|
40
|
+
args.push('--state', options.state);
|
|
41
|
+
}
|
|
42
|
+
if (options.limit) {
|
|
43
|
+
args.push('--limit', String(options.limit));
|
|
44
|
+
}
|
|
45
|
+
const { stdout } = await execFileAsync('gh', args);
|
|
46
|
+
return JSON.parse(stdout || '[]');
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Edit an issue (add/remove labels or assignees)
|
|
50
|
+
*/
|
|
51
|
+
export async function ghIssueEdit(issueNumber, options) {
|
|
52
|
+
const args = ['issue', 'edit', String(issueNumber)];
|
|
53
|
+
if (options.addLabel) {
|
|
54
|
+
args.push('--add-label', options.addLabel);
|
|
55
|
+
}
|
|
56
|
+
if (options.removeLabel) {
|
|
57
|
+
args.push('--remove-label', options.removeLabel);
|
|
58
|
+
}
|
|
59
|
+
if (options.addAssignee) {
|
|
60
|
+
args.push('--add-assignee', options.addAssignee);
|
|
61
|
+
}
|
|
62
|
+
if (options.removeAssignee) {
|
|
63
|
+
args.push('--remove-assignee', options.removeAssignee);
|
|
64
|
+
}
|
|
65
|
+
await execFileAsync('gh', args);
|
|
66
|
+
}
|
|
67
|
+
//# sourceMappingURL=gh-cli.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gh-cli.js","sourceRoot":"","sources":["../../../src/cli/core/gh-cli.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAEtC,MAAM,aAAa,GAAG,SAAS,CAAC,QAAQ,CAAC,CAAC;AAsB1C;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW;IAC/B,IAAI,CAAC;QACH,MAAM,aAAa,CAAC,IAAI,EAAE,CAAC,WAAW,CAAC,CAAC,CAAC;QACzC,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe;IACnC,IAAI,CAAC;QACH,MAAM,aAAa,CAAC,IAAI,EAAE,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC;QAC9C,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,UAAyB,EAAE;IAC3D,MAAM,IAAI,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,+BAA+B,CAAC,CAAC;IAE1E,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;QAClB,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC;IACtC,CAAC;IACD,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;QAClB,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC;IACtC,CAAC;IACD,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;QAClB,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC;IAC9C,CAAC;IAED,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,aAAa,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IACnD,OAAO,IAAI,CAAC,KAAK,CAAC,MAAM,IAAI,IAAI,CAAC,CAAC;AACpC,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,WAAmB,EAAE,OAAsB;IAC3E,MAAM,IAAI,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC;IAEpD,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;QACrB,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC;IAC7C,CAAC;IACD,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC;QACxB,IAAI,CAAC,IAAI,CAAC,gBAAgB,EAAE,OAAO,CAAC,WAAW,CAAC,CAAC;IACnD,CAAC;IACD,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC;QACxB,IAAI,CAAC,IAAI,CAAC,gBAAgB,EAAE,OAAO,CAAC,WAAW,CAAC,CAAC;IACnD,CAAC;IACD,IAAI,OAAO,CAAC,cAAc,EAAE,CAAC;QAC3B,IAAI,CAAC,IAAI,CAAC,mBAAmB,EAAE,OAAO,CAAC,cAAc,CAAC,CAAC;IACzD,CAAC;IAED,MAAM,aAAa,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;AAClC,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* History split utility — port from beta CLI
|
|
3
|
+
* Separates portable knowledge from project-specific data
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Split history into portable knowledge and project learnings
|
|
7
|
+
*/
|
|
8
|
+
export declare function splitHistory(history: string, sourceProject: string): string;
|
|
9
|
+
//# sourceMappingURL=history-split.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"history-split.d.ts","sourceRoot":"","sources":["../../../src/cli/core/history-split.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;GAEG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,MAAM,CA6D3E"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* History split utility — port from beta CLI
|
|
3
|
+
* Separates portable knowledge from project-specific data
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Split history into portable knowledge and project learnings
|
|
7
|
+
*/
|
|
8
|
+
export function splitHistory(history, sourceProject) {
|
|
9
|
+
const lines = history.split('\n');
|
|
10
|
+
const portable = [];
|
|
11
|
+
const projectLearnings = [];
|
|
12
|
+
// Sections that are project-specific by nature
|
|
13
|
+
const projectSectionPatterns = [
|
|
14
|
+
/^##\s*key file paths/i,
|
|
15
|
+
/^##\s*sprint/i,
|
|
16
|
+
/^##\s*pr\s*#/i,
|
|
17
|
+
/^##\s*file system/i,
|
|
18
|
+
/^##\s*session/i,
|
|
19
|
+
/^###\s*key file paths/i,
|
|
20
|
+
/^###\s*sprint/i,
|
|
21
|
+
/^###\s*pr\s*#/i,
|
|
22
|
+
/^###\s*file system/i,
|
|
23
|
+
/^###\s*session/i,
|
|
24
|
+
];
|
|
25
|
+
// Sections that are portable by nature
|
|
26
|
+
const portableSectionPatterns = [
|
|
27
|
+
/^##\s*learnings/i,
|
|
28
|
+
/^##\s*portable knowledge/i,
|
|
29
|
+
/^###\s*runtime architecture/i,
|
|
30
|
+
/^###\s*windows compatibility/i,
|
|
31
|
+
/^###\s*critical paths/i,
|
|
32
|
+
/^###\s*forwardability/i,
|
|
33
|
+
/^##\s*team updates/i,
|
|
34
|
+
];
|
|
35
|
+
let inProjectSection = false;
|
|
36
|
+
for (const line of lines) {
|
|
37
|
+
// Check if this line starts a new section
|
|
38
|
+
if (/^#{1,3}\s/.test(line)) {
|
|
39
|
+
const isProjectSection = projectSectionPatterns.some(p => p.test(line));
|
|
40
|
+
const isPortableSection = portableSectionPatterns.some(p => p.test(line));
|
|
41
|
+
if (isProjectSection) {
|
|
42
|
+
inProjectSection = true;
|
|
43
|
+
}
|
|
44
|
+
else if (isPortableSection) {
|
|
45
|
+
inProjectSection = false;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
if (inProjectSection) {
|
|
49
|
+
projectLearnings.push(line);
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
portable.push(line);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
let result = '';
|
|
56
|
+
if (portable.length > 0) {
|
|
57
|
+
result += portable.join('\n');
|
|
58
|
+
}
|
|
59
|
+
if (projectLearnings.length > 0) {
|
|
60
|
+
result += `\n\n## Project Learnings (from import — ${sourceProject})\n\n`;
|
|
61
|
+
result += projectLearnings.join('\n');
|
|
62
|
+
}
|
|
63
|
+
return result;
|
|
64
|
+
}
|
|
65
|
+
//# sourceMappingURL=history-split.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"history-split.js","sourceRoot":"","sources":["../../../src/cli/core/history-split.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;GAEG;AACH,MAAM,UAAU,YAAY,CAAC,OAAe,EAAE,aAAqB;IACjE,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAClC,MAAM,QAAQ,GAAa,EAAE,CAAC;IAC9B,MAAM,gBAAgB,GAAa,EAAE,CAAC;IAEtC,+CAA+C;IAC/C,MAAM,sBAAsB,GAAG;QAC7B,uBAAuB;QACvB,eAAe;QACf,eAAe;QACf,oBAAoB;QACpB,gBAAgB;QAChB,wBAAwB;QACxB,gBAAgB;QAChB,gBAAgB;QAChB,qBAAqB;QACrB,iBAAiB;KAClB,CAAC;IAEF,uCAAuC;IACvC,MAAM,uBAAuB,GAAG;QAC9B,kBAAkB;QAClB,2BAA2B;QAC3B,8BAA8B;QAC9B,+BAA+B;QAC/B,wBAAwB;QACxB,wBAAwB;QACxB,qBAAqB;KACtB,CAAC;IAEF,IAAI,gBAAgB,GAAG,KAAK,CAAC;IAE7B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,0CAA0C;QAC1C,IAAI,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;YAC3B,MAAM,gBAAgB,GAAG,sBAAsB,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;YACxE,MAAM,iBAAiB,GAAG,uBAAuB,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;YAE1E,IAAI,gBAAgB,EAAE,CAAC;gBACrB,gBAAgB,GAAG,IAAI,CAAC;YAC1B,CAAC;iBAAM,IAAI,iBAAiB,EAAE,CAAC;gBAC7B,gBAAgB,GAAG,KAAK,CAAC;YAC3B,CAAC;QACH,CAAC;QAED,IAAI,gBAAgB,EAAE,CAAC;YACrB,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC9B,CAAC;aAAM,CAAC;YACN,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACtB,CAAC;IACH,CAAC;IAED,IAAI,MAAM,GAAG,EAAE,CAAC;IAChB,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACxB,MAAM,IAAI,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAChC,CAAC;IACD,IAAI,gBAAgB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAChC,MAAM,IAAI,2CAA2C,aAAa,OAAO,CAAC;QAC1E,MAAM,IAAI,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACxC,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Init command implementation — zero dependencies
|
|
3
|
+
* Scaffolds a new Squad project with templates, workflows, and directory structure
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Main init command handler
|
|
7
|
+
*/
|
|
8
|
+
export declare function runInit(dest: string): Promise<void>;
|
|
9
|
+
//# sourceMappingURL=init.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../../src/cli/core/init.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAuDH;;GAEG;AACH,wBAAsB,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAsPzD"}
|
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Init command implementation — zero dependencies
|
|
3
|
+
* Scaffolds a new Squad project with templates, workflows, and directory structure
|
|
4
|
+
*/
|
|
5
|
+
import fs from 'node:fs/promises';
|
|
6
|
+
import fsSync from 'node:fs';
|
|
7
|
+
import path from 'node:path';
|
|
8
|
+
import { detectSquadDir } from './detect-squad-dir.js';
|
|
9
|
+
import { getTemplatesDir } from './templates.js';
|
|
10
|
+
import { success, BOLD, RESET, YELLOW, DIM } from './output.js';
|
|
11
|
+
import { fatal } from './errors.js';
|
|
12
|
+
import { detectProjectType } from './project-type.js';
|
|
13
|
+
import { getPackageVersion, stampVersion } from './version.js';
|
|
14
|
+
import { generateProjectWorkflowStub, PROJECT_TYPE_SENSITIVE_WORKFLOWS } from './workflows.js';
|
|
15
|
+
/**
|
|
16
|
+
* Show deprecation warning for .ai-team/ directory
|
|
17
|
+
*/
|
|
18
|
+
function showDeprecationWarning() {
|
|
19
|
+
console.log();
|
|
20
|
+
console.log(`${YELLOW}⚠️ DEPRECATION: .ai-team/ is deprecated and will be removed in v1.0.0${RESET}`);
|
|
21
|
+
console.log(`${YELLOW} Run 'npx github:bradygaster/squad-sdk upgrade --migrate-directory' to migrate to .squad/${RESET}`);
|
|
22
|
+
console.log(`${YELLOW} Details: https://github.com/bradygaster/squad/issues/101${RESET}`);
|
|
23
|
+
console.log();
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Recursively copy files from src to target
|
|
27
|
+
*/
|
|
28
|
+
async function copyRecursive(src, target) {
|
|
29
|
+
const stat = await fs.stat(src);
|
|
30
|
+
if (stat.isDirectory()) {
|
|
31
|
+
await fs.mkdir(target, { recursive: true });
|
|
32
|
+
const entries = await fs.readdir(src);
|
|
33
|
+
for (const entry of entries) {
|
|
34
|
+
await copyRecursive(path.join(src, entry), path.join(target, entry));
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
await fs.mkdir(path.dirname(target), { recursive: true });
|
|
39
|
+
await fs.copyFile(src, target);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Write a workflow file: verbatim copy for npm projects, stub for others
|
|
44
|
+
*/
|
|
45
|
+
async function writeWorkflowFile(file, srcPath, destPath, projectType) {
|
|
46
|
+
if (projectType !== 'npm' && PROJECT_TYPE_SENSITIVE_WORKFLOWS.has(file)) {
|
|
47
|
+
const stub = generateProjectWorkflowStub(file, projectType);
|
|
48
|
+
if (stub) {
|
|
49
|
+
await fs.writeFile(destPath, stub);
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
await fs.copyFile(srcPath, destPath);
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Main init command handler
|
|
57
|
+
*/
|
|
58
|
+
export async function runInit(dest) {
|
|
59
|
+
const version = getPackageVersion();
|
|
60
|
+
// Detect project type
|
|
61
|
+
const projectType = detectProjectType(dest);
|
|
62
|
+
// Validate destination is writable
|
|
63
|
+
try {
|
|
64
|
+
await fs.access(dest, fsSync.constants.W_OK);
|
|
65
|
+
}
|
|
66
|
+
catch {
|
|
67
|
+
fatal(`Cannot write to ${dest} — check directory permissions`);
|
|
68
|
+
}
|
|
69
|
+
// Validate templates exist
|
|
70
|
+
const templatesDir = getTemplatesDir();
|
|
71
|
+
const agentSrc = path.join(templatesDir, 'squad.agent.md');
|
|
72
|
+
try {
|
|
73
|
+
await fs.access(templatesDir);
|
|
74
|
+
await fs.access(agentSrc);
|
|
75
|
+
}
|
|
76
|
+
catch {
|
|
77
|
+
fatal(`Templates directory missing or corrupted — installation may be corrupted`);
|
|
78
|
+
}
|
|
79
|
+
// Detect squad directory
|
|
80
|
+
const squadInfo = detectSquadDir(dest);
|
|
81
|
+
// Show deprecation warning if using .ai-team/
|
|
82
|
+
if (squadInfo.isLegacy) {
|
|
83
|
+
showDeprecationWarning();
|
|
84
|
+
}
|
|
85
|
+
// Install squad.agent.md
|
|
86
|
+
const agentDest = path.join(dest, '.github', 'agents', 'squad.agent.md');
|
|
87
|
+
if (fsSync.existsSync(agentDest)) {
|
|
88
|
+
console.log(`${DIM}squad.agent.md already exists — skipping (run 'upgrade' to update)${RESET}`);
|
|
89
|
+
}
|
|
90
|
+
else {
|
|
91
|
+
try {
|
|
92
|
+
await fs.mkdir(path.dirname(agentDest), { recursive: true });
|
|
93
|
+
await fs.copyFile(agentSrc, agentDest);
|
|
94
|
+
stampVersion(agentDest, version);
|
|
95
|
+
success(`.github/agents/squad.agent.md (v${version})`);
|
|
96
|
+
}
|
|
97
|
+
catch (err) {
|
|
98
|
+
fatal(`Failed to create squad.agent.md: ${err.message}`);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
// Create directory structure
|
|
102
|
+
const inboxDir = path.join(squadInfo.path, 'decisions', 'inbox');
|
|
103
|
+
const orchLogDir = path.join(squadInfo.path, 'orchestration-log');
|
|
104
|
+
const castingDir = path.join(squadInfo.path, 'casting');
|
|
105
|
+
const skillsDir = path.join(squadInfo.path, 'skills');
|
|
106
|
+
const pluginsDir = path.join(squadInfo.path, 'plugins');
|
|
107
|
+
const identityDir = path.join(squadInfo.path, 'identity');
|
|
108
|
+
try {
|
|
109
|
+
await fs.mkdir(inboxDir, { recursive: true });
|
|
110
|
+
await fs.mkdir(orchLogDir, { recursive: true });
|
|
111
|
+
await fs.mkdir(castingDir, { recursive: true });
|
|
112
|
+
await fs.mkdir(skillsDir, { recursive: true });
|
|
113
|
+
await fs.mkdir(pluginsDir, { recursive: true });
|
|
114
|
+
await fs.mkdir(identityDir, { recursive: true });
|
|
115
|
+
}
|
|
116
|
+
catch (err) {
|
|
117
|
+
fatal(`Failed to create ${squadInfo.name}/ directories: ${err.message}`);
|
|
118
|
+
}
|
|
119
|
+
// Copy starter skills (skip if any skills already exist)
|
|
120
|
+
const skillsSrc = path.join(templatesDir, 'skills');
|
|
121
|
+
try {
|
|
122
|
+
if (fsSync.existsSync(skillsSrc)) {
|
|
123
|
+
const existingSkills = await fs.readdir(skillsDir);
|
|
124
|
+
if (existingSkills.length === 0) {
|
|
125
|
+
await copyRecursive(skillsSrc, skillsDir);
|
|
126
|
+
success(`${squadInfo.name}/skills/ (starter skills)`);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
catch { }
|
|
131
|
+
// Scaffold identity files (now.md, wisdom.md)
|
|
132
|
+
const nowMdPath = path.join(identityDir, 'now.md');
|
|
133
|
+
const wisdomMdPath = path.join(identityDir, 'wisdom.md');
|
|
134
|
+
if (!fsSync.existsSync(nowMdPath)) {
|
|
135
|
+
const nowTemplate = `---
|
|
136
|
+
updated_at: ${new Date().toISOString()}
|
|
137
|
+
focus_area: Initial setup
|
|
138
|
+
active_issues: []
|
|
139
|
+
---
|
|
140
|
+
|
|
141
|
+
# What We're Focused On
|
|
142
|
+
|
|
143
|
+
Getting started. Updated by coordinator at session start.
|
|
144
|
+
`;
|
|
145
|
+
await fs.mkdir(identityDir, { recursive: true });
|
|
146
|
+
await fs.writeFile(nowMdPath, nowTemplate);
|
|
147
|
+
success(`${squadInfo.name}/identity/now.md`);
|
|
148
|
+
}
|
|
149
|
+
if (!fsSync.existsSync(wisdomMdPath)) {
|
|
150
|
+
const wisdomTemplate = `---
|
|
151
|
+
last_updated: ${new Date().toISOString()}
|
|
152
|
+
---
|
|
153
|
+
|
|
154
|
+
# Team Wisdom
|
|
155
|
+
|
|
156
|
+
Reusable patterns and heuristics learned through work. NOT transcripts — each entry is a distilled, actionable insight.
|
|
157
|
+
|
|
158
|
+
## Patterns
|
|
159
|
+
|
|
160
|
+
<!-- Append entries below. Format: **Pattern:** description. **Context:** when it applies. -->
|
|
161
|
+
|
|
162
|
+
## Anti-Patterns
|
|
163
|
+
|
|
164
|
+
<!-- Things we tried that didn't work. **Avoid:** description. **Why:** reason. -->
|
|
165
|
+
`;
|
|
166
|
+
await fs.mkdir(identityDir, { recursive: true });
|
|
167
|
+
await fs.writeFile(wisdomMdPath, wisdomTemplate);
|
|
168
|
+
success(`${squadInfo.name}/identity/wisdom.md`);
|
|
169
|
+
}
|
|
170
|
+
// Create sample MCP config (skip if .copilot/mcp-config.json already exists)
|
|
171
|
+
const mcpDir = path.join(dest, '.copilot');
|
|
172
|
+
const mcpConfigPath = path.join(mcpDir, 'mcp-config.json');
|
|
173
|
+
if (!fsSync.existsSync(mcpConfigPath)) {
|
|
174
|
+
try {
|
|
175
|
+
await fs.mkdir(mcpDir, { recursive: true });
|
|
176
|
+
const mcpSample = {
|
|
177
|
+
mcpServers: {
|
|
178
|
+
"EXAMPLE-trello": {
|
|
179
|
+
command: "npx",
|
|
180
|
+
args: ["-y", "@trello/mcp-server"],
|
|
181
|
+
env: {
|
|
182
|
+
TRELLO_API_KEY: "${TRELLO_API_KEY}",
|
|
183
|
+
TRELLO_TOKEN: "${TRELLO_TOKEN}"
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
};
|
|
188
|
+
await fs.writeFile(mcpConfigPath, JSON.stringify(mcpSample, null, 2) + '\n');
|
|
189
|
+
success('.copilot/mcp-config.json (MCP sample — rename EXAMPLE-trello to enable)');
|
|
190
|
+
}
|
|
191
|
+
catch (err) {
|
|
192
|
+
// Non-fatal — MCP config is optional
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
else {
|
|
196
|
+
console.log(`${DIM}mcp-config.json already exists — skipping${RESET}`);
|
|
197
|
+
}
|
|
198
|
+
// Copy default ceremonies config
|
|
199
|
+
const ceremoniesDest = path.join(squadInfo.path, 'ceremonies.md');
|
|
200
|
+
if (!fsSync.existsSync(ceremoniesDest)) {
|
|
201
|
+
const ceremoniesSrc = path.join(templatesDir, 'ceremonies.md');
|
|
202
|
+
await fs.copyFile(ceremoniesSrc, ceremoniesDest);
|
|
203
|
+
success(`${squadInfo.name}/ceremonies.md`);
|
|
204
|
+
}
|
|
205
|
+
else {
|
|
206
|
+
console.log(`${DIM}ceremonies.md already exists — skipping${RESET}`);
|
|
207
|
+
}
|
|
208
|
+
// Append merge=union rules for append-only squad state files
|
|
209
|
+
const gitattributesPath = path.join(dest, '.gitattributes');
|
|
210
|
+
const unionRules = [
|
|
211
|
+
`${squadInfo.name}/decisions.md merge=union`,
|
|
212
|
+
`${squadInfo.name}/agents/*/history.md merge=union`,
|
|
213
|
+
`${squadInfo.name}/log/** merge=union`,
|
|
214
|
+
`${squadInfo.name}/orchestration-log/** merge=union`,
|
|
215
|
+
];
|
|
216
|
+
let existing = '';
|
|
217
|
+
try {
|
|
218
|
+
existing = await fs.readFile(gitattributesPath, 'utf8');
|
|
219
|
+
}
|
|
220
|
+
catch { }
|
|
221
|
+
const missing = unionRules.filter(rule => !existing.includes(rule));
|
|
222
|
+
if (missing.length) {
|
|
223
|
+
const block = (existing && !existing.endsWith('\n') ? '\n' : '')
|
|
224
|
+
+ '# Squad: union merge for append-only team state files\n'
|
|
225
|
+
+ missing.join('\n') + '\n';
|
|
226
|
+
await fs.appendFile(gitattributesPath, block);
|
|
227
|
+
success('.gitattributes (merge=union rules)');
|
|
228
|
+
}
|
|
229
|
+
else {
|
|
230
|
+
console.log(`${DIM}.gitattributes merge rules already present — skipping${RESET}`);
|
|
231
|
+
}
|
|
232
|
+
// Append .gitignore entries
|
|
233
|
+
const gitignorePath = path.join(dest, '.gitignore');
|
|
234
|
+
const ignoreEntries = [
|
|
235
|
+
`${squadInfo.name}/orchestration-log/`,
|
|
236
|
+
`${squadInfo.name}/log/`,
|
|
237
|
+
];
|
|
238
|
+
let existingIgnore = '';
|
|
239
|
+
try {
|
|
240
|
+
existingIgnore = await fs.readFile(gitignorePath, 'utf8');
|
|
241
|
+
}
|
|
242
|
+
catch { }
|
|
243
|
+
const missingIgnore = ignoreEntries.filter(entry => !existingIgnore.includes(entry));
|
|
244
|
+
if (missingIgnore.length) {
|
|
245
|
+
const block = (existingIgnore && !existingIgnore.endsWith('\n') ? '\n' : '')
|
|
246
|
+
+ '# Squad: ignore generated logs\n'
|
|
247
|
+
+ missingIgnore.join('\n') + '\n';
|
|
248
|
+
await fs.appendFile(gitignorePath, block);
|
|
249
|
+
success('.gitignore (log exclusions)');
|
|
250
|
+
}
|
|
251
|
+
// Copy templates directory
|
|
252
|
+
const templatesDestName = squadInfo.isLegacy ? '.ai-team-templates' : '.squad-templates';
|
|
253
|
+
const templatesDest = path.join(dest, templatesDestName);
|
|
254
|
+
if (fsSync.existsSync(templatesDest)) {
|
|
255
|
+
console.log(`${DIM}${templatesDestName}/ already exists — skipping (run 'upgrade' to update)${RESET}`);
|
|
256
|
+
}
|
|
257
|
+
else {
|
|
258
|
+
await copyRecursive(templatesDir, templatesDest);
|
|
259
|
+
success(`${templatesDestName}/`);
|
|
260
|
+
}
|
|
261
|
+
// Copy workflow templates
|
|
262
|
+
const workflowsSrc = path.join(templatesDir, 'workflows');
|
|
263
|
+
const workflowsDest = path.join(dest, '.github', 'workflows');
|
|
264
|
+
if (fsSync.existsSync(workflowsSrc) && fsSync.statSync(workflowsSrc).isDirectory()) {
|
|
265
|
+
const workflowFiles = (await fs.readdir(workflowsSrc)).filter(f => f.endsWith('.yml'));
|
|
266
|
+
await fs.mkdir(workflowsDest, { recursive: true });
|
|
267
|
+
let copied = 0;
|
|
268
|
+
for (const file of workflowFiles) {
|
|
269
|
+
const destFile = path.join(workflowsDest, file);
|
|
270
|
+
if (fsSync.existsSync(destFile)) {
|
|
271
|
+
console.log(`${DIM}${file} already exists — skipping (run 'upgrade' to update)${RESET}`);
|
|
272
|
+
}
|
|
273
|
+
else {
|
|
274
|
+
await writeWorkflowFile(file, path.join(workflowsSrc, file), destFile, projectType);
|
|
275
|
+
success(`.github/workflows/${file}`);
|
|
276
|
+
copied++;
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
if (copied === 0 && workflowFiles.length > 0) {
|
|
280
|
+
console.log(`${DIM}all squad workflows already exist — skipping${RESET}`);
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
// Final output
|
|
284
|
+
console.log();
|
|
285
|
+
console.log(`${BOLD}Squad is ready.${RESET}`);
|
|
286
|
+
console.log();
|
|
287
|
+
if (squadInfo.isLegacy) {
|
|
288
|
+
showDeprecationWarning();
|
|
289
|
+
}
|
|
290
|
+
console.log(`Next steps:`);
|
|
291
|
+
console.log(` 1. Open Copilot: ${DIM}copilot${RESET}`);
|
|
292
|
+
console.log(` 2. Type ${BOLD}/agent${RESET} (CLI) or ${BOLD}/agents${RESET} (VS Code) and select ${BOLD}Squad${RESET}`);
|
|
293
|
+
console.log(` 3. Tell it what you're building`);
|
|
294
|
+
console.log();
|
|
295
|
+
}
|
|
296
|
+
//# sourceMappingURL=init.js.map
|