@bradygaster/squad-cli 0.9.0 → 0.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +329 -329
- package/dist/cli/commands/personal.js +45 -45
- package/dist/cli/core/team-md.js +34 -34
- package/package.json +2 -2
- package/scripts/patch-esm-imports.mjs +105 -105
- package/scripts/patch-ink-rendering.mjs +115 -115
- package/templates/casting/Futurama.json +9 -9
- package/templates/casting-history.json +4 -4
- package/templates/casting-policy.json +37 -37
- package/templates/casting-reference.md +104 -104
- package/templates/casting-registry.json +3 -3
- package/templates/ceremonies.md +41 -41
- package/templates/charter.md +53 -53
- package/templates/constraint-tracking.md +38 -38
- package/templates/cooperative-rate-limiting.md +229 -229
- package/templates/copilot-instructions.md +46 -46
- package/templates/history.md +10 -10
- package/templates/identity/now.md +9 -9
- package/templates/identity/wisdom.md +15 -15
- package/templates/issue-lifecycle.md +412 -412
- package/templates/keda-scaler.md +164 -164
- package/templates/machine-capabilities.md +74 -74
- package/templates/mcp-config.md +90 -90
- package/templates/multi-agent-format.md +28 -28
- package/templates/orchestration-log.md +27 -27
- package/templates/plugin-marketplace.md +49 -49
- package/templates/ralph-circuit-breaker.md +313 -313
- package/templates/raw-agent-output.md +37 -37
- package/templates/roster.md +60 -60
- package/templates/routing.md +39 -39
- package/templates/run-output.md +50 -50
- package/templates/scribe-charter.md +119 -119
- package/templates/skill.md +24 -24
- package/templates/skills/agent-collaboration/SKILL.md +42 -42
- package/templates/skills/agent-conduct/SKILL.md +24 -24
- package/templates/skills/architectural-proposals/SKILL.md +151 -151
- package/templates/skills/ci-validation-gates/SKILL.md +84 -84
- package/templates/skills/cli-wiring/SKILL.md +47 -47
- package/templates/skills/client-compatibility/SKILL.md +89 -89
- package/templates/skills/cross-squad/SKILL.md +114 -114
- package/templates/skills/distributed-mesh/SKILL.md +287 -287
- package/templates/skills/distributed-mesh/mesh.json.example +30 -30
- package/templates/skills/distributed-mesh/sync-mesh.ps1 +111 -111
- package/templates/skills/distributed-mesh/sync-mesh.sh +104 -104
- package/templates/skills/docs-standards/SKILL.md +71 -71
- package/templates/skills/economy-mode/SKILL.md +114 -114
- package/templates/skills/external-comms/SKILL.md +329 -329
- package/templates/skills/gh-auth-isolation/SKILL.md +183 -183
- package/templates/skills/git-workflow/SKILL.md +204 -204
- package/templates/skills/github-multi-account/SKILL.md +95 -95
- package/templates/skills/history-hygiene/SKILL.md +36 -36
- package/templates/skills/humanizer/SKILL.md +105 -105
- package/templates/skills/init-mode/SKILL.md +102 -102
- package/templates/skills/model-selection/SKILL.md +117 -117
- package/templates/skills/nap/SKILL.md +24 -24
- package/templates/skills/personal-squad/SKILL.md +57 -57
- package/templates/skills/release-process/SKILL.md +423 -423
- package/templates/skills/reskill/SKILL.md +92 -92
- package/templates/skills/reviewer-protocol/SKILL.md +79 -79
- package/templates/skills/secret-handling/SKILL.md +200 -200
- package/templates/skills/session-recovery/SKILL.md +155 -155
- package/templates/skills/squad-conventions/SKILL.md +69 -69
- package/templates/skills/test-discipline/SKILL.md +37 -37
- package/templates/skills/windows-compatibility/SKILL.md +74 -74
- package/templates/workflows/squad-ci.yml +24 -24
- package/templates/workflows/squad-docs.yml +54 -54
- 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
|
@@ -163,51 +163,51 @@ async function personalRemove(name) {
|
|
|
163
163
|
* For now, we use a simplified inline template.
|
|
164
164
|
*/
|
|
165
165
|
function generatePersonalCharterTemplate(name, role) {
|
|
166
|
-
return `# ${name} — ${role}
|
|
167
|
-
|
|
168
|
-
> Your one-line personality statement — what makes you tick
|
|
169
|
-
|
|
170
|
-
## Identity
|
|
171
|
-
|
|
172
|
-
- **Name:** ${name}
|
|
173
|
-
- **Role:** ${role}
|
|
174
|
-
- **Expertise:** [Your 2-3 specific skills]
|
|
175
|
-
- **Style:** [How you communicate — direct? thorough? opinionated?]
|
|
176
|
-
|
|
177
|
-
## What I Own
|
|
178
|
-
|
|
179
|
-
- [Area of responsibility 1]
|
|
180
|
-
- [Area of responsibility 2]
|
|
181
|
-
- [Area of responsibility 3]
|
|
182
|
-
|
|
183
|
-
## How I Work
|
|
184
|
-
|
|
185
|
-
- [Key approach or principle 1]
|
|
186
|
-
- [Key approach or principle 2]
|
|
187
|
-
- [Pattern or convention I follow]
|
|
188
|
-
|
|
189
|
-
## Boundaries
|
|
190
|
-
|
|
191
|
-
**I handle:** [types of work this agent does]
|
|
192
|
-
|
|
193
|
-
**I don't handle:** [types of work that belong to other team members]
|
|
194
|
-
|
|
195
|
-
**When I'm unsure:** I say so and suggest who might know.
|
|
196
|
-
|
|
197
|
-
## Model
|
|
198
|
-
|
|
199
|
-
- **Preferred:** auto
|
|
200
|
-
- **Rationale:** Coordinator selects the best model based on task type
|
|
201
|
-
|
|
202
|
-
## Collaboration
|
|
203
|
-
|
|
204
|
-
This is a personal agent — you're ambient across all projects.
|
|
205
|
-
Ghost protocol is enforced in project contexts (observe, suggest, never modify).
|
|
206
|
-
|
|
207
|
-
## Voice
|
|
208
|
-
|
|
209
|
-
[1-2 sentences describing personality. Be specific — you have opinions,
|
|
210
|
-
preferences, and a style that's distinctly yours.]
|
|
166
|
+
return `# ${name} — ${role}
|
|
167
|
+
|
|
168
|
+
> Your one-line personality statement — what makes you tick
|
|
169
|
+
|
|
170
|
+
## Identity
|
|
171
|
+
|
|
172
|
+
- **Name:** ${name}
|
|
173
|
+
- **Role:** ${role}
|
|
174
|
+
- **Expertise:** [Your 2-3 specific skills]
|
|
175
|
+
- **Style:** [How you communicate — direct? thorough? opinionated?]
|
|
176
|
+
|
|
177
|
+
## What I Own
|
|
178
|
+
|
|
179
|
+
- [Area of responsibility 1]
|
|
180
|
+
- [Area of responsibility 2]
|
|
181
|
+
- [Area of responsibility 3]
|
|
182
|
+
|
|
183
|
+
## How I Work
|
|
184
|
+
|
|
185
|
+
- [Key approach or principle 1]
|
|
186
|
+
- [Key approach or principle 2]
|
|
187
|
+
- [Pattern or convention I follow]
|
|
188
|
+
|
|
189
|
+
## Boundaries
|
|
190
|
+
|
|
191
|
+
**I handle:** [types of work this agent does]
|
|
192
|
+
|
|
193
|
+
**I don't handle:** [types of work that belong to other team members]
|
|
194
|
+
|
|
195
|
+
**When I'm unsure:** I say so and suggest who might know.
|
|
196
|
+
|
|
197
|
+
## Model
|
|
198
|
+
|
|
199
|
+
- **Preferred:** auto
|
|
200
|
+
- **Rationale:** Coordinator selects the best model based on task type
|
|
201
|
+
|
|
202
|
+
## Collaboration
|
|
203
|
+
|
|
204
|
+
This is a personal agent — you're ambient across all projects.
|
|
205
|
+
Ghost protocol is enforced in project contexts (observe, suggest, never modify).
|
|
206
|
+
|
|
207
|
+
## Voice
|
|
208
|
+
|
|
209
|
+
[1-2 sentences describing personality. Be specific — you have opinions,
|
|
210
|
+
preferences, and a style that's distinctly yours.]
|
|
211
211
|
`;
|
|
212
212
|
}
|
|
213
213
|
//# sourceMappingURL=personal.js.map
|
package/dist/cli/core/team-md.js
CHANGED
|
@@ -31,40 +31,40 @@ export function hasCopilot(content) {
|
|
|
31
31
|
*/
|
|
32
32
|
export function insertCopilotSection(content, autoAssign = false) {
|
|
33
33
|
const autoAssignValue = autoAssign ? 'true' : 'false';
|
|
34
|
-
const copilotSection = `
|
|
35
|
-
## Coding Agent
|
|
36
|
-
|
|
37
|
-
<!-- copilot-auto-assign: ${autoAssignValue} -->
|
|
38
|
-
|
|
39
|
-
| Name | Role | Charter | Status |
|
|
40
|
-
|------|------|---------|--------|
|
|
41
|
-
| @copilot | Coding Agent | — | 🤖 Coding Agent |
|
|
42
|
-
|
|
43
|
-
### Capabilities
|
|
44
|
-
|
|
45
|
-
**🟢 Good fit — auto-route when enabled:**
|
|
46
|
-
- Bug fixes with clear reproduction steps
|
|
47
|
-
- Test coverage (adding missing tests, fixing flaky tests)
|
|
48
|
-
- Lint/format fixes and code style cleanup
|
|
49
|
-
- Dependency updates and version bumps
|
|
50
|
-
- Small isolated features with clear specs
|
|
51
|
-
- Boilerplate/scaffolding generation
|
|
52
|
-
- Documentation fixes and README updates
|
|
53
|
-
|
|
54
|
-
**🟡 Needs review — route to @copilot but flag for squad member PR review:**
|
|
55
|
-
- Medium features with clear specs and acceptance criteria
|
|
56
|
-
- Refactoring with existing test coverage
|
|
57
|
-
- API endpoint additions following established patterns
|
|
58
|
-
- Migration scripts with well-defined schemas
|
|
59
|
-
|
|
60
|
-
**🔴 Not suitable — route to squad member instead:**
|
|
61
|
-
- Architecture decisions and system design
|
|
62
|
-
- Multi-system integration requiring coordination
|
|
63
|
-
- Ambiguous requirements needing clarification
|
|
64
|
-
- Security-critical changes (auth, encryption, access control)
|
|
65
|
-
- Performance-critical paths requiring benchmarking
|
|
66
|
-
- Changes requiring cross-team discussion
|
|
67
|
-
|
|
34
|
+
const copilotSection = `
|
|
35
|
+
## Coding Agent
|
|
36
|
+
|
|
37
|
+
<!-- copilot-auto-assign: ${autoAssignValue} -->
|
|
38
|
+
|
|
39
|
+
| Name | Role | Charter | Status |
|
|
40
|
+
|------|------|---------|--------|
|
|
41
|
+
| @copilot | Coding Agent | — | 🤖 Coding Agent |
|
|
42
|
+
|
|
43
|
+
### Capabilities
|
|
44
|
+
|
|
45
|
+
**🟢 Good fit — auto-route when enabled:**
|
|
46
|
+
- Bug fixes with clear reproduction steps
|
|
47
|
+
- Test coverage (adding missing tests, fixing flaky tests)
|
|
48
|
+
- Lint/format fixes and code style cleanup
|
|
49
|
+
- Dependency updates and version bumps
|
|
50
|
+
- Small isolated features with clear specs
|
|
51
|
+
- Boilerplate/scaffolding generation
|
|
52
|
+
- Documentation fixes and README updates
|
|
53
|
+
|
|
54
|
+
**🟡 Needs review — route to @copilot but flag for squad member PR review:**
|
|
55
|
+
- Medium features with clear specs and acceptance criteria
|
|
56
|
+
- Refactoring with existing test coverage
|
|
57
|
+
- API endpoint additions following established patterns
|
|
58
|
+
- Migration scripts with well-defined schemas
|
|
59
|
+
|
|
60
|
+
**🔴 Not suitable — route to squad member instead:**
|
|
61
|
+
- Architecture decisions and system design
|
|
62
|
+
- Multi-system integration requiring coordination
|
|
63
|
+
- Ambiguous requirements needing clarification
|
|
64
|
+
- Security-critical changes (auth, encryption, access control)
|
|
65
|
+
- Performance-critical paths requiring benchmarking
|
|
66
|
+
- Changes requiring cross-team discussion
|
|
67
|
+
|
|
68
68
|
`;
|
|
69
69
|
// Insert before "## Project Context" if it exists, otherwise append
|
|
70
70
|
if (content.includes('## Project Context')) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bradygaster/squad-cli",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.1",
|
|
4
4
|
"description": "Squad CLI — Command-line interface for the Squad multi-agent runtime",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -173,7 +173,7 @@
|
|
|
173
173
|
"node": ">=22.5.0"
|
|
174
174
|
},
|
|
175
175
|
"dependencies": {
|
|
176
|
-
"@bradygaster/squad-sdk": "
|
|
176
|
+
"@bradygaster/squad-sdk": ">=0.9.0",
|
|
177
177
|
"ink": "^6.8.0",
|
|
178
178
|
"react": "^19.2.4",
|
|
179
179
|
"vscode-jsonrpc": "^8.2.1"
|
|
@@ -1,106 +1,106 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* ESM Import Patcher — dual-layer fix for Node 22/24+ compatibility
|
|
5
|
-
*
|
|
6
|
-
* Layer 1: Patch vscode-jsonrpc/package.json with `exports` field
|
|
7
|
-
* vscode-jsonrpc@8.2.1 has no `exports` field. Node 22+ strict ESM
|
|
8
|
-
* rejects subpath imports like 'vscode-jsonrpc/node' without it.
|
|
9
|
-
* Injecting the exports map from v9.x fixes ALL subpath imports at once.
|
|
10
|
-
*
|
|
11
|
-
* Layer 2: Patch @github/copilot-sdk session.js (defense-in-depth)
|
|
12
|
-
* copilot-sdk@0.1.32 imports 'vscode-jsonrpc/node' without .js extension.
|
|
13
|
-
* This layer ensures the import works even if Layer 1 somehow fails.
|
|
14
|
-
*
|
|
15
|
-
* Issue: bradygaster/squad#449
|
|
16
|
-
* Upstream: https://github.com/github/copilot-sdk/issues/707
|
|
17
|
-
*/
|
|
18
|
-
|
|
19
|
-
import { readFileSync, writeFileSync, existsSync } from 'fs';
|
|
20
|
-
import { join, dirname } from 'path';
|
|
21
|
-
import { fileURLToPath } from 'url';
|
|
22
|
-
|
|
23
|
-
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
24
|
-
|
|
25
|
-
// Locations where npm workspaces / global install may place dependencies
|
|
26
|
-
const SEARCH_ROOTS = [
|
|
27
|
-
join(__dirname, '..', 'node_modules'), // squad-cli local
|
|
28
|
-
join(__dirname, '..', '..', '..', 'node_modules'), // workspace root
|
|
29
|
-
join(__dirname, '..', '..'), // global install (sibling)
|
|
30
|
-
];
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* Layer 1 — Inject `exports` field into vscode-jsonrpc/package.json.
|
|
34
|
-
* This is the canonical fix: once the package has proper exports, Node's
|
|
35
|
-
* ESM resolver handles every subpath ('vscode-jsonrpc/node', '/browser', etc.)
|
|
36
|
-
* without needing per-file patches.
|
|
37
|
-
*/
|
|
38
|
-
function patchVscodeJsonrpcExports() {
|
|
39
|
-
const exportsField = {
|
|
40
|
-
'.': { types: './lib/common/api.d.ts', default: './lib/node/main.js' },
|
|
41
|
-
'./node': { node: './lib/node/main.js', types: './lib/node/main.d.ts' },
|
|
42
|
-
'./node.js': { node: './lib/node/main.js', types: './lib/node/main.d.ts' },
|
|
43
|
-
'./browser': { types: './lib/browser/main.d.ts', browser: './lib/browser/main.js' },
|
|
44
|
-
};
|
|
45
|
-
|
|
46
|
-
for (const root of SEARCH_ROOTS) {
|
|
47
|
-
const pkgPath = join(root, 'vscode-jsonrpc', 'package.json');
|
|
48
|
-
if (!existsSync(pkgPath)) continue;
|
|
49
|
-
|
|
50
|
-
try {
|
|
51
|
-
const raw = readFileSync(pkgPath, 'utf8');
|
|
52
|
-
const pkg = JSON.parse(raw);
|
|
53
|
-
|
|
54
|
-
if (pkg.exports && pkg.exports['./node.js']) {
|
|
55
|
-
console.log('⏭️ vscode-jsonrpc already has complete exports field — skipping');
|
|
56
|
-
return false;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
pkg.exports = exportsField;
|
|
60
|
-
writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + '\n', 'utf8');
|
|
61
|
-
console.log('✅ Patched vscode-jsonrpc/package.json with exports field (Node 22/24+ ESM fix)');
|
|
62
|
-
return true;
|
|
63
|
-
} catch (err) {
|
|
64
|
-
console.warn('⚠️ Failed to patch vscode-jsonrpc exports:', err.message);
|
|
65
|
-
return false;
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
return false;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
/**
|
|
73
|
-
* Layer 2 — Patch copilot-sdk session.js import (defense-in-depth).
|
|
74
|
-
* Rewrites extensionless 'vscode-jsonrpc/node' to 'vscode-jsonrpc/node.js'.
|
|
75
|
-
*/
|
|
76
|
-
function patchCopilotSdkSessionJs() {
|
|
77
|
-
for (const root of SEARCH_ROOTS) {
|
|
78
|
-
const sessionJsPath = join(root, '@github', 'copilot-sdk', 'dist', 'session.js');
|
|
79
|
-
if (!existsSync(sessionJsPath)) continue;
|
|
80
|
-
|
|
81
|
-
try {
|
|
82
|
-
const content = readFileSync(sessionJsPath, 'utf8');
|
|
83
|
-
|
|
84
|
-
const patched = content.replace(
|
|
85
|
-
/from\s+["']vscode-jsonrpc\/node["']/g,
|
|
86
|
-
'from "vscode-jsonrpc/node.js"'
|
|
87
|
-
);
|
|
88
|
-
|
|
89
|
-
if (patched !== content) {
|
|
90
|
-
writeFileSync(sessionJsPath, patched, 'utf8');
|
|
91
|
-
console.log('✅ Patched @github/copilot-sdk session.js ESM imports');
|
|
92
|
-
return true;
|
|
93
|
-
}
|
|
94
|
-
return false;
|
|
95
|
-
} catch (err) {
|
|
96
|
-
console.warn('⚠️ Failed to patch copilot-sdk session.js:', err.message);
|
|
97
|
-
return false;
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
return false;
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
// Run both layers
|
|
105
|
-
patchVscodeJsonrpcExports();
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* ESM Import Patcher — dual-layer fix for Node 22/24+ compatibility
|
|
5
|
+
*
|
|
6
|
+
* Layer 1: Patch vscode-jsonrpc/package.json with `exports` field
|
|
7
|
+
* vscode-jsonrpc@8.2.1 has no `exports` field. Node 22+ strict ESM
|
|
8
|
+
* rejects subpath imports like 'vscode-jsonrpc/node' without it.
|
|
9
|
+
* Injecting the exports map from v9.x fixes ALL subpath imports at once.
|
|
10
|
+
*
|
|
11
|
+
* Layer 2: Patch @github/copilot-sdk session.js (defense-in-depth)
|
|
12
|
+
* copilot-sdk@0.1.32 imports 'vscode-jsonrpc/node' without .js extension.
|
|
13
|
+
* This layer ensures the import works even if Layer 1 somehow fails.
|
|
14
|
+
*
|
|
15
|
+
* Issue: bradygaster/squad#449
|
|
16
|
+
* Upstream: https://github.com/github/copilot-sdk/issues/707
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
import { readFileSync, writeFileSync, existsSync } from 'fs';
|
|
20
|
+
import { join, dirname } from 'path';
|
|
21
|
+
import { fileURLToPath } from 'url';
|
|
22
|
+
|
|
23
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
24
|
+
|
|
25
|
+
// Locations where npm workspaces / global install may place dependencies
|
|
26
|
+
const SEARCH_ROOTS = [
|
|
27
|
+
join(__dirname, '..', 'node_modules'), // squad-cli local
|
|
28
|
+
join(__dirname, '..', '..', '..', 'node_modules'), // workspace root
|
|
29
|
+
join(__dirname, '..', '..'), // global install (sibling)
|
|
30
|
+
];
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Layer 1 — Inject `exports` field into vscode-jsonrpc/package.json.
|
|
34
|
+
* This is the canonical fix: once the package has proper exports, Node's
|
|
35
|
+
* ESM resolver handles every subpath ('vscode-jsonrpc/node', '/browser', etc.)
|
|
36
|
+
* without needing per-file patches.
|
|
37
|
+
*/
|
|
38
|
+
function patchVscodeJsonrpcExports() {
|
|
39
|
+
const exportsField = {
|
|
40
|
+
'.': { types: './lib/common/api.d.ts', default: './lib/node/main.js' },
|
|
41
|
+
'./node': { node: './lib/node/main.js', types: './lib/node/main.d.ts' },
|
|
42
|
+
'./node.js': { node: './lib/node/main.js', types: './lib/node/main.d.ts' },
|
|
43
|
+
'./browser': { types: './lib/browser/main.d.ts', browser: './lib/browser/main.js' },
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
for (const root of SEARCH_ROOTS) {
|
|
47
|
+
const pkgPath = join(root, 'vscode-jsonrpc', 'package.json');
|
|
48
|
+
if (!existsSync(pkgPath)) continue;
|
|
49
|
+
|
|
50
|
+
try {
|
|
51
|
+
const raw = readFileSync(pkgPath, 'utf8');
|
|
52
|
+
const pkg = JSON.parse(raw);
|
|
53
|
+
|
|
54
|
+
if (pkg.exports && pkg.exports['./node.js']) {
|
|
55
|
+
console.log('⏭️ vscode-jsonrpc already has complete exports field — skipping');
|
|
56
|
+
return false;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
pkg.exports = exportsField;
|
|
60
|
+
writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + '\n', 'utf8');
|
|
61
|
+
console.log('✅ Patched vscode-jsonrpc/package.json with exports field (Node 22/24+ ESM fix)');
|
|
62
|
+
return true;
|
|
63
|
+
} catch (err) {
|
|
64
|
+
console.warn('⚠️ Failed to patch vscode-jsonrpc exports:', err.message);
|
|
65
|
+
return false;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return false;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Layer 2 — Patch copilot-sdk session.js import (defense-in-depth).
|
|
74
|
+
* Rewrites extensionless 'vscode-jsonrpc/node' to 'vscode-jsonrpc/node.js'.
|
|
75
|
+
*/
|
|
76
|
+
function patchCopilotSdkSessionJs() {
|
|
77
|
+
for (const root of SEARCH_ROOTS) {
|
|
78
|
+
const sessionJsPath = join(root, '@github', 'copilot-sdk', 'dist', 'session.js');
|
|
79
|
+
if (!existsSync(sessionJsPath)) continue;
|
|
80
|
+
|
|
81
|
+
try {
|
|
82
|
+
const content = readFileSync(sessionJsPath, 'utf8');
|
|
83
|
+
|
|
84
|
+
const patched = content.replace(
|
|
85
|
+
/from\s+["']vscode-jsonrpc\/node["']/g,
|
|
86
|
+
'from "vscode-jsonrpc/node.js"'
|
|
87
|
+
);
|
|
88
|
+
|
|
89
|
+
if (patched !== content) {
|
|
90
|
+
writeFileSync(sessionJsPath, patched, 'utf8');
|
|
91
|
+
console.log('✅ Patched @github/copilot-sdk session.js ESM imports');
|
|
92
|
+
return true;
|
|
93
|
+
}
|
|
94
|
+
return false;
|
|
95
|
+
} catch (err) {
|
|
96
|
+
console.warn('⚠️ Failed to patch copilot-sdk session.js:', err.message);
|
|
97
|
+
return false;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
return false;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// Run both layers
|
|
105
|
+
patchVscodeJsonrpcExports();
|
|
106
106
|
patchCopilotSdkSessionJs();
|
|
@@ -1,115 +1,115 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Ink Rendering Patcher for Squad CLI
|
|
5
|
-
*
|
|
6
|
-
* Patches ink/build/ink.js to fix scroll flicker on Windows Terminal.
|
|
7
|
-
* Three patches are applied:
|
|
8
|
-
*
|
|
9
|
-
* 1. Remove trailing newline — the extra '\n' appended to output causes
|
|
10
|
-
* logUpdate's previousLineCount to be off by one, pushing the bottom of
|
|
11
|
-
* the UI below the viewport.
|
|
12
|
-
*
|
|
13
|
-
* 2. Disable clearTerminal fullscreen path — when output fills the terminal,
|
|
14
|
-
* Ink clears the entire screen, causing violent scroll-to-top flicker.
|
|
15
|
-
* We force the condition to `false` so logUpdate's incremental
|
|
16
|
-
* erase-and-rewrite is always used instead.
|
|
17
|
-
*
|
|
18
|
-
* 3. Verify incrementalRendering passthrough — confirms that Ink forwards
|
|
19
|
-
* the incrementalRendering option to logUpdate.create(). No code change
|
|
20
|
-
* needed if already wired up.
|
|
21
|
-
*
|
|
22
|
-
* All patches are idempotent (safe to run multiple times).
|
|
23
|
-
*/
|
|
24
|
-
|
|
25
|
-
import { readFileSync, writeFileSync, existsSync } from 'fs';
|
|
26
|
-
import { join, dirname } from 'path';
|
|
27
|
-
import { fileURLToPath } from 'url';
|
|
28
|
-
|
|
29
|
-
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
30
|
-
|
|
31
|
-
function patchInkRendering() {
|
|
32
|
-
// Try multiple possible locations (npm workspaces can hoist dependencies)
|
|
33
|
-
const possiblePaths = [
|
|
34
|
-
// squad-cli package node_modules
|
|
35
|
-
join(__dirname, '..', 'node_modules', 'ink', 'build', 'ink.js'),
|
|
36
|
-
// Workspace root node_modules (common with npm workspaces)
|
|
37
|
-
join(__dirname, '..', '..', '..', 'node_modules', 'ink', 'build', 'ink.js'),
|
|
38
|
-
// Global install location (node_modules at parent of package)
|
|
39
|
-
join(__dirname, '..', '..', 'ink', 'build', 'ink.js'),
|
|
40
|
-
];
|
|
41
|
-
|
|
42
|
-
const inkJsPath = possiblePaths.find(p => existsSync(p)) ?? null;
|
|
43
|
-
|
|
44
|
-
if (!inkJsPath) {
|
|
45
|
-
// ink not installed yet — exit silently
|
|
46
|
-
return false;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
try {
|
|
50
|
-
let content = readFileSync(inkJsPath, 'utf8');
|
|
51
|
-
let patchCount = 0;
|
|
52
|
-
|
|
53
|
-
// --- Patch 1: Remove trailing newline ---
|
|
54
|
-
// Original: const outputToRender = output + '\n';
|
|
55
|
-
// Patched: const outputToRender = output;
|
|
56
|
-
const trailingNewlineSearch = "const outputToRender = output + '\\n';";
|
|
57
|
-
const trailingNewlineReplace = 'const outputToRender = output;';
|
|
58
|
-
if (content.includes(trailingNewlineSearch)) {
|
|
59
|
-
content = content.replace(trailingNewlineSearch, trailingNewlineReplace);
|
|
60
|
-
console.log(' ✅ Patch 1/3: Removed trailing newline from outputToRender');
|
|
61
|
-
patchCount++;
|
|
62
|
-
} else if (content.includes(trailingNewlineReplace)) {
|
|
63
|
-
console.log(' ⏭️ Patch 1/3: Trailing newline already removed');
|
|
64
|
-
} else {
|
|
65
|
-
console.warn(' ⚠️ Patch 1/3: Could not find outputToRender pattern — Ink version may have changed');
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
// --- Patch 2: Disable clearTerminal fullscreen path ---
|
|
69
|
-
// Original: if (isFullscreen) {
|
|
70
|
-
// const sync = shouldSynchronize(this.options.stdout);
|
|
71
|
-
// ...
|
|
72
|
-
// this.options.stdout.write(ansiEscapes.clearTerminal + ...
|
|
73
|
-
// Patched: if (false) {
|
|
74
|
-
//
|
|
75
|
-
// We match `if (isFullscreen) {` only when followed by the clearTerminal
|
|
76
|
-
// usage to avoid replacing unrelated isFullscreen references.
|
|
77
|
-
const fullscreenSearch = /if \(isFullscreen\) \{\s*\n\s*const sync = shouldSynchronize/;
|
|
78
|
-
const fullscreenAlreadyPatched = /if \(false\) \{\s*\n\s*const sync = shouldSynchronize/;
|
|
79
|
-
if (fullscreenSearch.test(content)) {
|
|
80
|
-
content = content.replace(
|
|
81
|
-
/if \(isFullscreen\) (\{\s*\n\s*const sync = shouldSynchronize)/,
|
|
82
|
-
'if (false) $1'
|
|
83
|
-
);
|
|
84
|
-
console.log(' ✅ Patch 2/3: Disabled clearTerminal fullscreen path');
|
|
85
|
-
patchCount++;
|
|
86
|
-
} else if (fullscreenAlreadyPatched.test(content)) {
|
|
87
|
-
console.log(' ⏭️ Patch 2/3: clearTerminal path already disabled');
|
|
88
|
-
} else {
|
|
89
|
-
console.warn(' ⚠️ Patch 2/3: Could not find isFullscreen pattern — Ink version may have changed');
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
// --- Patch 3: Verify incrementalRendering passthrough ---
|
|
93
|
-
const incrementalPattern = 'incremental: options.incrementalRendering';
|
|
94
|
-
if (content.includes(incrementalPattern)) {
|
|
95
|
-
console.log(' ✅ Patch 3/3: incrementalRendering passthrough verified (no change needed)');
|
|
96
|
-
} else {
|
|
97
|
-
console.warn(' ⚠️ Patch 3/3: incrementalRendering passthrough not found — Ink version may have changed');
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
if (patchCount > 0) {
|
|
101
|
-
writeFileSync(inkJsPath, content, 'utf8');
|
|
102
|
-
console.log(`✅ Patched ink.js with ${patchCount} rendering fix(es) for scroll flicker`);
|
|
103
|
-
return true;
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
return false;
|
|
107
|
-
} catch (err) {
|
|
108
|
-
console.warn('⚠️ Failed to patch ink.js rendering:', err.message);
|
|
109
|
-
console.warn(' Scroll flicker may occur on Windows Terminal.');
|
|
110
|
-
return false;
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
// Run patch
|
|
115
|
-
patchInkRendering();
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Ink Rendering Patcher for Squad CLI
|
|
5
|
+
*
|
|
6
|
+
* Patches ink/build/ink.js to fix scroll flicker on Windows Terminal.
|
|
7
|
+
* Three patches are applied:
|
|
8
|
+
*
|
|
9
|
+
* 1. Remove trailing newline — the extra '\n' appended to output causes
|
|
10
|
+
* logUpdate's previousLineCount to be off by one, pushing the bottom of
|
|
11
|
+
* the UI below the viewport.
|
|
12
|
+
*
|
|
13
|
+
* 2. Disable clearTerminal fullscreen path — when output fills the terminal,
|
|
14
|
+
* Ink clears the entire screen, causing violent scroll-to-top flicker.
|
|
15
|
+
* We force the condition to `false` so logUpdate's incremental
|
|
16
|
+
* erase-and-rewrite is always used instead.
|
|
17
|
+
*
|
|
18
|
+
* 3. Verify incrementalRendering passthrough — confirms that Ink forwards
|
|
19
|
+
* the incrementalRendering option to logUpdate.create(). No code change
|
|
20
|
+
* needed if already wired up.
|
|
21
|
+
*
|
|
22
|
+
* All patches are idempotent (safe to run multiple times).
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
import { readFileSync, writeFileSync, existsSync } from 'fs';
|
|
26
|
+
import { join, dirname } from 'path';
|
|
27
|
+
import { fileURLToPath } from 'url';
|
|
28
|
+
|
|
29
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
30
|
+
|
|
31
|
+
function patchInkRendering() {
|
|
32
|
+
// Try multiple possible locations (npm workspaces can hoist dependencies)
|
|
33
|
+
const possiblePaths = [
|
|
34
|
+
// squad-cli package node_modules
|
|
35
|
+
join(__dirname, '..', 'node_modules', 'ink', 'build', 'ink.js'),
|
|
36
|
+
// Workspace root node_modules (common with npm workspaces)
|
|
37
|
+
join(__dirname, '..', '..', '..', 'node_modules', 'ink', 'build', 'ink.js'),
|
|
38
|
+
// Global install location (node_modules at parent of package)
|
|
39
|
+
join(__dirname, '..', '..', 'ink', 'build', 'ink.js'),
|
|
40
|
+
];
|
|
41
|
+
|
|
42
|
+
const inkJsPath = possiblePaths.find(p => existsSync(p)) ?? null;
|
|
43
|
+
|
|
44
|
+
if (!inkJsPath) {
|
|
45
|
+
// ink not installed yet — exit silently
|
|
46
|
+
return false;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
try {
|
|
50
|
+
let content = readFileSync(inkJsPath, 'utf8');
|
|
51
|
+
let patchCount = 0;
|
|
52
|
+
|
|
53
|
+
// --- Patch 1: Remove trailing newline ---
|
|
54
|
+
// Original: const outputToRender = output + '\n';
|
|
55
|
+
// Patched: const outputToRender = output;
|
|
56
|
+
const trailingNewlineSearch = "const outputToRender = output + '\\n';";
|
|
57
|
+
const trailingNewlineReplace = 'const outputToRender = output;';
|
|
58
|
+
if (content.includes(trailingNewlineSearch)) {
|
|
59
|
+
content = content.replace(trailingNewlineSearch, trailingNewlineReplace);
|
|
60
|
+
console.log(' ✅ Patch 1/3: Removed trailing newline from outputToRender');
|
|
61
|
+
patchCount++;
|
|
62
|
+
} else if (content.includes(trailingNewlineReplace)) {
|
|
63
|
+
console.log(' ⏭️ Patch 1/3: Trailing newline already removed');
|
|
64
|
+
} else {
|
|
65
|
+
console.warn(' ⚠️ Patch 1/3: Could not find outputToRender pattern — Ink version may have changed');
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// --- Patch 2: Disable clearTerminal fullscreen path ---
|
|
69
|
+
// Original: if (isFullscreen) {
|
|
70
|
+
// const sync = shouldSynchronize(this.options.stdout);
|
|
71
|
+
// ...
|
|
72
|
+
// this.options.stdout.write(ansiEscapes.clearTerminal + ...
|
|
73
|
+
// Patched: if (false) {
|
|
74
|
+
//
|
|
75
|
+
// We match `if (isFullscreen) {` only when followed by the clearTerminal
|
|
76
|
+
// usage to avoid replacing unrelated isFullscreen references.
|
|
77
|
+
const fullscreenSearch = /if \(isFullscreen\) \{\s*\n\s*const sync = shouldSynchronize/;
|
|
78
|
+
const fullscreenAlreadyPatched = /if \(false\) \{\s*\n\s*const sync = shouldSynchronize/;
|
|
79
|
+
if (fullscreenSearch.test(content)) {
|
|
80
|
+
content = content.replace(
|
|
81
|
+
/if \(isFullscreen\) (\{\s*\n\s*const sync = shouldSynchronize)/,
|
|
82
|
+
'if (false) $1'
|
|
83
|
+
);
|
|
84
|
+
console.log(' ✅ Patch 2/3: Disabled clearTerminal fullscreen path');
|
|
85
|
+
patchCount++;
|
|
86
|
+
} else if (fullscreenAlreadyPatched.test(content)) {
|
|
87
|
+
console.log(' ⏭️ Patch 2/3: clearTerminal path already disabled');
|
|
88
|
+
} else {
|
|
89
|
+
console.warn(' ⚠️ Patch 2/3: Could not find isFullscreen pattern — Ink version may have changed');
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// --- Patch 3: Verify incrementalRendering passthrough ---
|
|
93
|
+
const incrementalPattern = 'incremental: options.incrementalRendering';
|
|
94
|
+
if (content.includes(incrementalPattern)) {
|
|
95
|
+
console.log(' ✅ Patch 3/3: incrementalRendering passthrough verified (no change needed)');
|
|
96
|
+
} else {
|
|
97
|
+
console.warn(' ⚠️ Patch 3/3: incrementalRendering passthrough not found — Ink version may have changed');
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
if (patchCount > 0) {
|
|
101
|
+
writeFileSync(inkJsPath, content, 'utf8');
|
|
102
|
+
console.log(`✅ Patched ink.js with ${patchCount} rendering fix(es) for scroll flicker`);
|
|
103
|
+
return true;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
return false;
|
|
107
|
+
} catch (err) {
|
|
108
|
+
console.warn('⚠️ Failed to patch ink.js rendering:', err.message);
|
|
109
|
+
console.warn(' Scroll flicker may occur on Windows Terminal.');
|
|
110
|
+
return false;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// Run patch
|
|
115
|
+
patchInkRendering();
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
[
|
|
2
|
-
"Fry",
|
|
3
|
-
"Leela",
|
|
4
|
-
"Bender",
|
|
5
|
-
"Farnsworth",
|
|
6
|
-
"Zoidberg",
|
|
7
|
-
"Amy",
|
|
8
|
-
"Zapp",
|
|
9
|
-
"Kif"
|
|
1
|
+
[
|
|
2
|
+
"Fry",
|
|
3
|
+
"Leela",
|
|
4
|
+
"Bender",
|
|
5
|
+
"Farnsworth",
|
|
6
|
+
"Zoidberg",
|
|
7
|
+
"Amy",
|
|
8
|
+
"Zapp",
|
|
9
|
+
"Kif"
|
|
10
10
|
]
|