@bradygaster/squad-sdk 0.9.1 → 0.9.2-insider.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 +340 -296
- package/dist/agents/history-shadow.d.ts +7 -5
- package/dist/agents/history-shadow.d.ts.map +1 -1
- package/dist/agents/history-shadow.js +69 -78
- package/dist/agents/history-shadow.js.map +1 -1
- package/dist/agents/index.d.ts +12 -1
- package/dist/agents/index.d.ts.map +1 -1
- package/dist/agents/index.js +62 -9
- package/dist/agents/index.js.map +1 -1
- package/dist/agents/lifecycle.d.ts +4 -0
- package/dist/agents/lifecycle.d.ts.map +1 -1
- package/dist/agents/lifecycle.js +6 -7
- package/dist/agents/lifecycle.js.map +1 -1
- package/dist/agents/onboarding.d.ts +4 -2
- package/dist/agents/onboarding.d.ts.map +1 -1
- package/dist/agents/onboarding.js +26 -16
- package/dist/agents/onboarding.js.map +1 -1
- package/dist/agents/personal.d.ts +2 -1
- package/dist/agents/personal.d.ts.map +1 -1
- package/dist/agents/personal.js +11 -12
- package/dist/agents/personal.js.map +1 -1
- package/dist/build/bundle.d.ts.map +1 -1
- package/dist/build/bundle.js +6 -6
- package/dist/build/bundle.js.map +1 -1
- package/dist/build/github-dist.js +42 -42
- package/dist/build/release.d.ts.map +1 -1
- package/dist/build/release.js +7 -5
- package/dist/build/release.js.map +1 -1
- package/dist/casting/index.d.ts.map +1 -1
- package/dist/casting/index.js +4 -3
- package/dist/casting/index.js.map +1 -1
- package/dist/config/agent-source.d.ts +5 -1
- package/dist/config/agent-source.d.ts.map +1 -1
- package/dist/config/agent-source.js +85 -41
- package/dist/config/agent-source.js.map +1 -1
- package/dist/config/init.d.ts +4 -3
- package/dist/config/init.d.ts.map +1 -1
- package/dist/config/init.js +257 -236
- package/dist/config/init.js.map +1 -1
- package/dist/config/legacy-fallback.d.ts +3 -2
- package/dist/config/legacy-fallback.d.ts.map +1 -1
- package/dist/config/legacy-fallback.js +16 -14
- package/dist/config/legacy-fallback.js.map +1 -1
- package/dist/config/models.d.ts +9 -6
- package/dist/config/models.d.ts.map +1 -1
- package/dist/config/models.js +35 -25
- package/dist/config/models.js.map +1 -1
- package/dist/index.d.ts +5 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +14 -1
- package/dist/index.js.map +1 -1
- package/dist/marketplace/packaging.d.ts.map +1 -1
- package/dist/marketplace/packaging.js +18 -16
- package/dist/marketplace/packaging.js.map +1 -1
- package/dist/multi-squad.d.ts.map +1 -1
- package/dist/multi-squad.js +10 -9
- package/dist/multi-squad.js.map +1 -1
- package/dist/platform/comms-file-log.d.ts.map +1 -1
- package/dist/platform/comms-file-log.js +7 -6
- package/dist/platform/comms-file-log.js.map +1 -1
- package/dist/platform/comms.d.ts.map +1 -1
- package/dist/platform/comms.js +6 -5
- package/dist/platform/comms.js.map +1 -1
- package/dist/platform/index.d.ts.map +1 -1
- package/dist/platform/index.js +4 -3
- package/dist/platform/index.js.map +1 -1
- package/dist/ralph/capabilities.d.ts +30 -1
- package/dist/ralph/capabilities.d.ts.map +1 -1
- package/dist/ralph/capabilities.js +51 -6
- package/dist/ralph/capabilities.js.map +1 -1
- package/dist/ralph/index.d.ts +1 -1
- package/dist/ralph/index.d.ts.map +1 -1
- package/dist/ralph/index.js +4 -3
- package/dist/ralph/index.js.map +1 -1
- package/dist/ralph/rate-limiting.d.ts.map +1 -1
- package/dist/ralph/rate-limiting.js +4 -4
- package/dist/ralph/rate-limiting.js.map +1 -1
- package/dist/remote/bridge.d.ts.map +1 -1
- package/dist/remote/bridge.js +2 -2
- package/dist/remote/bridge.js.map +1 -1
- package/dist/resolution.d.ts +9 -0
- package/dist/resolution.d.ts.map +1 -1
- package/dist/resolution.js +39 -16
- package/dist/resolution.js.map +1 -1
- package/dist/roles/catalog.d.ts +1 -1
- package/dist/runtime/config.d.ts.map +1 -1
- package/dist/runtime/config.js +8 -7
- package/dist/runtime/config.js.map +1 -1
- package/dist/runtime/cross-squad.d.ts.map +1 -1
- package/dist/runtime/cross-squad.js +8 -7
- package/dist/runtime/cross-squad.js.map +1 -1
- package/dist/runtime/scheduler.d.ts.map +1 -1
- package/dist/runtime/scheduler.js +8 -8
- package/dist/runtime/scheduler.js.map +1 -1
- package/dist/runtime/squad-observer.d.ts.map +1 -1
- package/dist/runtime/squad-observer.js +7 -4
- package/dist/runtime/squad-observer.js.map +1 -1
- package/dist/sharing/consult.d.ts +1 -1
- package/dist/sharing/consult.d.ts.map +1 -1
- package/dist/sharing/consult.js +144 -142
- package/dist/sharing/consult.js.map +1 -1
- package/dist/sharing/export.d.ts.map +1 -1
- package/dist/sharing/export.js +16 -16
- package/dist/sharing/export.js.map +1 -1
- package/dist/sharing/import.d.ts.map +1 -1
- package/dist/sharing/import.js +13 -12
- package/dist/sharing/import.js.map +1 -1
- package/dist/skills/skill-loader.d.ts.map +1 -1
- package/dist/skills/skill-loader.js +10 -9
- package/dist/skills/skill-loader.js.map +1 -1
- package/dist/skills/skill-script-loader.d.ts.map +1 -1
- package/dist/skills/skill-script-loader.js +6 -4
- package/dist/skills/skill-script-loader.js.map +1 -1
- package/dist/skills/skill-source.d.ts +3 -1
- package/dist/skills/skill-source.d.ts.map +1 -1
- package/dist/skills/skill-source.js +18 -16
- package/dist/skills/skill-source.js.map +1 -1
- package/dist/state/collection-map.d.ts +43 -0
- package/dist/state/collection-map.d.ts.map +1 -0
- package/dist/state/collection-map.js +9 -0
- package/dist/state/collection-map.js.map +1 -0
- package/dist/state/collections.d.ts +102 -0
- package/dist/state/collections.d.ts.map +1 -0
- package/dist/state/collections.js +317 -0
- package/dist/state/collections.js.map +1 -0
- package/dist/state/domain-types.d.ts +122 -0
- package/dist/state/domain-types.d.ts.map +1 -0
- package/dist/state/domain-types.js +54 -0
- package/dist/state/domain-types.js.map +1 -0
- package/dist/state/handles.d.ts +16 -0
- package/dist/state/handles.d.ts.map +1 -0
- package/dist/state/handles.js +161 -0
- package/dist/state/handles.js.map +1 -0
- package/dist/state/index.d.ts +17 -0
- package/dist/state/index.d.ts.map +1 -0
- package/dist/state/index.js +15 -0
- package/dist/state/index.js.map +1 -0
- package/dist/state/io/charter-io.d.ts +28 -0
- package/dist/state/io/charter-io.d.ts.map +1 -0
- package/dist/state/io/charter-io.js +94 -0
- package/dist/state/io/charter-io.js.map +1 -0
- package/dist/state/io/decisions-io.d.ts +42 -0
- package/dist/state/io/decisions-io.d.ts.map +1 -0
- package/dist/state/io/decisions-io.js +66 -0
- package/dist/state/io/decisions-io.js.map +1 -0
- package/dist/state/io/history-io.d.ts +37 -0
- package/dist/state/io/history-io.d.ts.map +1 -0
- package/dist/state/io/history-io.js +102 -0
- package/dist/state/io/history-io.js.map +1 -0
- package/dist/state/io/index.d.ts +19 -0
- package/dist/state/io/index.d.ts.map +1 -0
- package/dist/state/io/index.js +19 -0
- package/dist/state/io/index.js.map +1 -0
- package/dist/state/io/routing-io.d.ts +37 -0
- package/dist/state/io/routing-io.d.ts.map +1 -0
- package/dist/state/io/routing-io.js +99 -0
- package/dist/state/io/routing-io.js.map +1 -0
- package/dist/state/io/team-io.d.ts +46 -0
- package/dist/state/io/team-io.d.ts.map +1 -0
- package/dist/state/io/team-io.js +82 -0
- package/dist/state/io/team-io.js.map +1 -0
- package/dist/state/schema.d.ts +24 -0
- package/dist/state/schema.d.ts.map +1 -0
- package/dist/state/schema.js +41 -0
- package/dist/state/schema.js.map +1 -0
- package/dist/state/squad-state.d.ts +42 -0
- package/dist/state/squad-state.d.ts.map +1 -0
- package/dist/state/squad-state.js +68 -0
- package/dist/state/squad-state.js.map +1 -0
- package/dist/storage/fs-storage-provider.d.ts +60 -0
- package/dist/storage/fs-storage-provider.d.ts.map +1 -0
- package/dist/storage/fs-storage-provider.js +377 -0
- package/dist/storage/fs-storage-provider.js.map +1 -0
- package/dist/storage/in-memory-storage-provider.d.ts +46 -0
- package/dist/storage/in-memory-storage-provider.d.ts.map +1 -0
- package/dist/storage/in-memory-storage-provider.js +264 -0
- package/dist/storage/in-memory-storage-provider.js.map +1 -0
- package/dist/storage/index.d.ts +6 -0
- package/dist/storage/index.d.ts.map +1 -0
- package/dist/storage/index.js +5 -0
- package/dist/storage/index.js.map +1 -0
- package/dist/storage/sqlite-storage-provider.d.ts +95 -0
- package/dist/storage/sqlite-storage-provider.d.ts.map +1 -0
- package/dist/storage/sqlite-storage-provider.js +383 -0
- package/dist/storage/sqlite-storage-provider.js.map +1 -0
- package/dist/storage/storage-error.d.ts +28 -0
- package/dist/storage/storage-error.d.ts.map +1 -0
- package/dist/storage/storage-error.js +35 -0
- package/dist/storage/storage-error.js.map +1 -0
- package/dist/storage/storage-provider.d.ts +161 -0
- package/dist/storage/storage-provider.d.ts.map +1 -0
- package/dist/storage/storage-provider.js +18 -0
- package/dist/storage/storage-provider.js.map +1 -0
- package/dist/streams/resolver.d.ts.map +1 -1
- package/dist/streams/resolver.js +6 -5
- package/dist/streams/resolver.js.map +1 -1
- package/dist/tools/index.d.ts +5 -1
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +54 -15
- package/dist/tools/index.js.map +1 -1
- package/dist/upstream/resolver.d.ts +3 -2
- package/dist/upstream/resolver.d.ts.map +1 -1
- package/dist/upstream/resolver.js +33 -32
- package/dist/upstream/resolver.js.map +1 -1
- package/package.json +33 -1
- 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/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/schedule.json +19 -19
- package/templates/scribe-charter.md +123 -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-machine-coordination/SKILL.md +434 -0
- 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/error-recovery/SKILL.md +99 -0
- 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/iterative-retrieval/SKILL.md +165 -0
- package/templates/skills/model-selection/SKILL.md +117 -117
- package/templates/skills/nap/SKILL.md +24 -24
- package/templates/skills/notification-routing/SKILL.md +105 -0
- package/templates/skills/personal-squad/SKILL.md +57 -57
- package/templates/skills/pr-screenshots/SKILL.md +149 -0
- package/templates/skills/project-conventions/SKILL.md +56 -56
- package/templates/skills/ralph-two-pass-scan/SKILL.md +35 -0
- package/templates/skills/reflect/SKILL.md +229 -0
- package/templates/skills/release-process/SKILL.md +131 -423
- package/templates/skills/reskill/SKILL.md +92 -92
- package/templates/skills/retro-enforcement/SKILL.md +148 -0
- 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/tiered-memory/SKILL.md +234 -0
- package/templates/skills/windows-compatibility/SKILL.md +98 -74
- package/templates/{squad.agent.md → squad.agent.md.template} +57 -28
- package/templates/workflows/squad-ci.yml +24 -24
- package/templates/workflows/squad-docs.yml +54 -54
- package/templates/workflows/squad-heartbeat.yml +167 -171
- package/templates/workflows/squad-insider-release.yml +61 -61
- package/templates/workflows/squad-issue-assign.yml +161 -161
- package/templates/workflows/squad-label-enforce.yml +181 -181
- package/templates/workflows/squad-preview.yml +55 -55
- package/templates/workflows/squad-promote.yml +120 -120
- package/templates/workflows/squad-release.yml +77 -77
- package/templates/workflows/squad-triage.yml +260 -260
- package/templates/workflows/sync-squad-labels.yml +169 -169
package/dist/sharing/consult.js
CHANGED
|
@@ -14,11 +14,13 @@
|
|
|
14
14
|
*
|
|
15
15
|
* @module sharing/consult
|
|
16
16
|
*/
|
|
17
|
-
import
|
|
17
|
+
import { cpSync } from 'node:fs'; // cpSync retained for recursive directory copy — StorageProvider.copySync is file-only
|
|
18
18
|
import path from 'node:path';
|
|
19
19
|
import { fileURLToPath } from 'node:url';
|
|
20
20
|
import { execSync } from 'node:child_process';
|
|
21
|
+
import { FSStorageProvider } from '../storage/fs-storage-provider.js';
|
|
21
22
|
import { resolveGlobalSquadPath } from '../resolution.js';
|
|
23
|
+
const storage = new FSStorageProvider();
|
|
22
24
|
// ============================================================================
|
|
23
25
|
// Typed Errors
|
|
24
26
|
// ============================================================================
|
|
@@ -51,22 +53,22 @@ export class ExtractionDisabledError extends Error {
|
|
|
51
53
|
* Consult mode preamble to inject after frontmatter in squad.agent.md.
|
|
52
54
|
* This tells Squad it's in consult mode and should skip Init Mode.
|
|
53
55
|
*/
|
|
54
|
-
const CONSULT_MODE_PREAMBLE = `
|
|
55
|
-
<!-- consult-mode: true -->
|
|
56
|
-
|
|
57
|
-
## ⚡ Consult Mode Active
|
|
58
|
-
|
|
59
|
-
This project is in **consult mode**. Your personal squad has been copied into \`.squad/\` for this session.
|
|
60
|
-
|
|
61
|
-
**Key differences from normal mode:**
|
|
62
|
-
- **Skip Init Mode** — The team already exists (copied from your personal squad)
|
|
63
|
-
- **Isolated changes** — All changes stay local until you run \`squad extract\`
|
|
64
|
-
- **Invisible to project** — Both \`.squad/\` and this agent file are in \`.git/info/exclude\`
|
|
65
|
-
|
|
66
|
-
**When done:** Run \`squad extract\` to review learnings and merge generic ones back to your personal squad.
|
|
67
|
-
|
|
68
|
-
---
|
|
69
|
-
|
|
56
|
+
const CONSULT_MODE_PREAMBLE = `
|
|
57
|
+
<!-- consult-mode: true -->
|
|
58
|
+
|
|
59
|
+
## ⚡ Consult Mode Active
|
|
60
|
+
|
|
61
|
+
This project is in **consult mode**. Your personal squad has been copied into \`.squad/\` for this session.
|
|
62
|
+
|
|
63
|
+
**Key differences from normal mode:**
|
|
64
|
+
- **Skip Init Mode** — The team already exists (copied from your personal squad)
|
|
65
|
+
- **Isolated changes** — All changes stay local until you run \`squad extract\`
|
|
66
|
+
- **Invisible to project** — Both \`.squad/\` and this agent file are in \`.git/info/exclude\`
|
|
67
|
+
|
|
68
|
+
**When done:** Run \`squad extract\` to review learnings and merge generic ones back to your personal squad.
|
|
69
|
+
|
|
70
|
+
---
|
|
71
|
+
|
|
70
72
|
`;
|
|
71
73
|
/**
|
|
72
74
|
* Get the full squad.agent.md template path.
|
|
@@ -76,13 +78,13 @@ function getSquadAgentTemplatePath() {
|
|
|
76
78
|
// Use fileURLToPath for cross-platform compatibility (handles Windows drive letters, URL encoding)
|
|
77
79
|
const currentDir = path.dirname(fileURLToPath(import.meta.url));
|
|
78
80
|
// Try relative to this file (in dist/)
|
|
79
|
-
const distPath = path.resolve(currentDir, '../../templates/squad.agent.md');
|
|
80
|
-
if (
|
|
81
|
+
const distPath = path.resolve(currentDir, '../../templates/squad.agent.md.template');
|
|
82
|
+
if (storage.existsSync(distPath)) {
|
|
81
83
|
return distPath;
|
|
82
84
|
}
|
|
83
85
|
// Try relative to package root
|
|
84
|
-
const pkgPath = path.resolve(currentDir, '../../../templates/squad.agent.md');
|
|
85
|
-
if (
|
|
86
|
+
const pkgPath = path.resolve(currentDir, '../../../templates/squad.agent.md.template');
|
|
87
|
+
if (storage.existsSync(pkgPath)) {
|
|
86
88
|
return pkgPath;
|
|
87
89
|
}
|
|
88
90
|
return null;
|
|
@@ -119,8 +121,8 @@ function getGitRemoteUrl(projectRoot) {
|
|
|
119
121
|
*/
|
|
120
122
|
function getConsultAgentContent(projectName) {
|
|
121
123
|
const templatePath = getSquadAgentTemplatePath();
|
|
122
|
-
if (templatePath &&
|
|
123
|
-
const template =
|
|
124
|
+
if (templatePath && storage.existsSync(templatePath)) {
|
|
125
|
+
const template = storage.readSync(templatePath) ?? '';
|
|
124
126
|
// Find the end of frontmatter (second ---)
|
|
125
127
|
const frontmatterEnd = template.indexOf('---', template.indexOf('---') + 3);
|
|
126
128
|
if (frontmatterEnd !== -1) {
|
|
@@ -135,24 +137,24 @@ function getConsultAgentContent(projectName) {
|
|
|
135
137
|
return template + '\n' + CONSULT_MODE_PREAMBLE;
|
|
136
138
|
}
|
|
137
139
|
// Fallback: minimal agent if template not found
|
|
138
|
-
return `---
|
|
139
|
-
name: Squad
|
|
140
|
-
description: "Your AI team. Consulting on ${projectName} using your personal squad."
|
|
141
|
-
---
|
|
142
|
-
|
|
143
|
-
${CONSULT_MODE_PREAMBLE}
|
|
144
|
-
|
|
145
|
-
You are **Squad (Consultant)** — working on **${projectName}** using a copy of your personal squad.
|
|
146
|
-
|
|
147
|
-
### Available Context (local copy in .squad/)
|
|
148
|
-
|
|
149
|
-
- **Team:** \`.squad/team.md\` for roster and roles
|
|
150
|
-
- **Routing:** \`.squad/routing.md\` for task routing rules
|
|
151
|
-
- **Decisions:** \`.squad/decisions.md\` for your established patterns
|
|
152
|
-
- **Skills:** \`.copilot/skills/\` for reusable capabilities
|
|
153
|
-
- **Agents:** \`.squad/agents/\` for your squad agents
|
|
154
|
-
|
|
155
|
-
Work as you would with your personal squad, but in this external codebase.
|
|
140
|
+
return `---
|
|
141
|
+
name: Squad
|
|
142
|
+
description: "Your AI team. Consulting on ${projectName} using your personal squad."
|
|
143
|
+
---
|
|
144
|
+
|
|
145
|
+
${CONSULT_MODE_PREAMBLE}
|
|
146
|
+
|
|
147
|
+
You are **Squad (Consultant)** — working on **${projectName}** using a copy of your personal squad.
|
|
148
|
+
|
|
149
|
+
### Available Context (local copy in .squad/)
|
|
150
|
+
|
|
151
|
+
- **Team:** \`.squad/team.md\` for roster and roles
|
|
152
|
+
- **Routing:** \`.squad/routing.md\` for task routing rules
|
|
153
|
+
- **Decisions:** \`.squad/decisions.md\` for your established patterns
|
|
154
|
+
- **Skills:** \`.copilot/skills/\` for reusable capabilities
|
|
155
|
+
- **Agents:** \`.squad/agents/\` for your squad agents
|
|
156
|
+
|
|
157
|
+
Work as you would with your personal squad, but in this external codebase.
|
|
156
158
|
`;
|
|
157
159
|
}
|
|
158
160
|
// ============================================================================
|
|
@@ -162,65 +164,65 @@ Work as you would with your personal squad, but in this external codebase.
|
|
|
162
164
|
* Consult mode instructions to append to Scribe charter.
|
|
163
165
|
* This enables Scribe to classify decisions as generic or project-specific.
|
|
164
166
|
*/
|
|
165
|
-
const CONSULT_MODE_SCRIBE_PATCH = `
|
|
166
|
-
|
|
167
|
-
---
|
|
168
|
-
|
|
169
|
-
## Consult Mode Extraction
|
|
170
|
-
|
|
171
|
-
**This squad is in consult mode.** When merging decisions from the inbox, also classify each decision:
|
|
172
|
-
|
|
173
|
-
### Classification
|
|
174
|
-
|
|
175
|
-
For each decision in \`.squad/decisions/inbox/\`:
|
|
176
|
-
|
|
177
|
-
1. **Generic** (applies to any project) → Copy to \`.squad/extract/\` with the same filename
|
|
178
|
-
- Signals: "always use", "never use", "prefer X over Y", "best practice", coding standards, patterns that work anywhere
|
|
179
|
-
- These will be extracted to the personal squad via \`squad extract\`
|
|
180
|
-
|
|
181
|
-
2. **Project-specific** (only applies here) → Keep in local \`decisions.md\` only
|
|
182
|
-
- Signals: Contains file paths from this project, references "this project/codebase/repo", mentions project-specific config/APIs/schemas
|
|
183
|
-
|
|
184
|
-
Generic decisions go to BOTH \`.squad/decisions.md\` (for this session) AND \`.squad/extract/\` (for later extraction).
|
|
185
|
-
|
|
186
|
-
### Extract Directory
|
|
187
|
-
|
|
188
|
-
\`\`\`
|
|
189
|
-
.squad/extract/ # Generic learnings staged for personal squad
|
|
190
|
-
├── decision-1.md # Ready for extraction
|
|
191
|
-
└── pattern-auth.md # Ready for extraction
|
|
192
|
-
\`\`\`
|
|
193
|
-
|
|
194
|
-
Run \`squad extract\` to review and merge these to your personal squad.
|
|
167
|
+
const CONSULT_MODE_SCRIBE_PATCH = `
|
|
168
|
+
|
|
169
|
+
---
|
|
170
|
+
|
|
171
|
+
## Consult Mode Extraction
|
|
172
|
+
|
|
173
|
+
**This squad is in consult mode.** When merging decisions from the inbox, also classify each decision:
|
|
174
|
+
|
|
175
|
+
### Classification
|
|
176
|
+
|
|
177
|
+
For each decision in \`.squad/decisions/inbox/\`:
|
|
178
|
+
|
|
179
|
+
1. **Generic** (applies to any project) → Copy to \`.squad/extract/\` with the same filename
|
|
180
|
+
- Signals: "always use", "never use", "prefer X over Y", "best practice", coding standards, patterns that work anywhere
|
|
181
|
+
- These will be extracted to the personal squad via \`squad extract\`
|
|
182
|
+
|
|
183
|
+
2. **Project-specific** (only applies here) → Keep in local \`decisions.md\` only
|
|
184
|
+
- Signals: Contains file paths from this project, references "this project/codebase/repo", mentions project-specific config/APIs/schemas
|
|
185
|
+
|
|
186
|
+
Generic decisions go to BOTH \`.squad/decisions.md\` (for this session) AND \`.squad/extract/\` (for later extraction).
|
|
187
|
+
|
|
188
|
+
### Extract Directory
|
|
189
|
+
|
|
190
|
+
\`\`\`
|
|
191
|
+
.squad/extract/ # Generic learnings staged for personal squad
|
|
192
|
+
├── decision-1.md # Ready for extraction
|
|
193
|
+
└── pattern-auth.md # Ready for extraction
|
|
194
|
+
\`\`\`
|
|
195
|
+
|
|
196
|
+
Run \`squad extract\` to review and merge these to your personal squad.
|
|
195
197
|
`;
|
|
196
198
|
/**
|
|
197
199
|
* Patch the Scribe charter in the copied squad with consult mode instructions.
|
|
198
200
|
*/
|
|
199
201
|
function patchScribeCharterForConsultMode(squadDir) {
|
|
200
202
|
const charterPath = path.join(squadDir, 'agents', 'scribe', 'charter.md');
|
|
201
|
-
if (!
|
|
203
|
+
if (!storage.existsSync(charterPath)) {
|
|
202
204
|
// No scribe charter to patch — skip silently
|
|
203
205
|
return;
|
|
204
206
|
}
|
|
205
|
-
const existing =
|
|
207
|
+
const existing = storage.readSync(charterPath) ?? '';
|
|
206
208
|
// Don't patch if already patched
|
|
207
209
|
if (existing.includes('Consult Mode Extraction')) {
|
|
208
210
|
return;
|
|
209
211
|
}
|
|
210
|
-
|
|
212
|
+
storage.appendSync(charterPath, CONSULT_MODE_SCRIBE_PATCH);
|
|
211
213
|
}
|
|
212
214
|
/**
|
|
213
215
|
* List files recursively in a directory.
|
|
214
216
|
*/
|
|
215
217
|
function listFilesInDir(dir, basePath = '') {
|
|
216
|
-
if (!
|
|
218
|
+
if (!storage.existsSync(dir))
|
|
217
219
|
return [];
|
|
218
220
|
const files = [];
|
|
219
|
-
const entries =
|
|
221
|
+
const entries = storage.listSync(dir);
|
|
220
222
|
for (const entry of entries) {
|
|
221
|
-
const relativePath = basePath ? path.join(basePath, entry
|
|
222
|
-
if (
|
|
223
|
-
files.push(...listFilesInDir(path.join(dir, entry
|
|
223
|
+
const relativePath = basePath ? path.join(basePath, entry) : entry;
|
|
224
|
+
if (storage.isDirectorySync(path.join(dir, entry))) {
|
|
225
|
+
files.push(...listFilesInDir(path.join(dir, entry), relativePath));
|
|
224
226
|
}
|
|
225
227
|
else {
|
|
226
228
|
files.push(relativePath);
|
|
@@ -230,10 +232,10 @@ function listFilesInDir(dir, basePath = '') {
|
|
|
230
232
|
}
|
|
231
233
|
/**
|
|
232
234
|
* Get the personal squad root path.
|
|
233
|
-
* Returns {globalSquadPath}
|
|
235
|
+
* Returns {globalSquadPath}/personal-squad/
|
|
234
236
|
*/
|
|
235
237
|
export function getPersonalSquadRoot() {
|
|
236
|
-
return path.resolve(resolveGlobalSquadPath(), '
|
|
238
|
+
return path.resolve(resolveGlobalSquadPath(), 'personal-squad');
|
|
237
239
|
}
|
|
238
240
|
/**
|
|
239
241
|
* Resolve the git exclude path using git rev-parse (handles worktrees/submodules).
|
|
@@ -272,7 +274,7 @@ export async function setupConsultMode(options = {}) {
|
|
|
272
274
|
const agentFile = path.resolve(projectRoot, '.github', 'agents', 'squad.agent.md');
|
|
273
275
|
// Check if we're in a git repository (handle worktrees/submodules where .git is a file)
|
|
274
276
|
const gitPath = path.resolve(projectRoot, '.git');
|
|
275
|
-
if (!
|
|
277
|
+
if (!storage.existsSync(gitPath)) {
|
|
276
278
|
throw new Error('Not a git repository. Consult mode requires git.');
|
|
277
279
|
}
|
|
278
280
|
// Resolve exclude path via git rev-parse (handles worktrees/submodules)
|
|
@@ -282,16 +284,16 @@ export async function setupConsultMode(options = {}) {
|
|
|
282
284
|
return path.isAbsolute(excludePath) ? excludePath : path.resolve(projectRoot, excludePath);
|
|
283
285
|
})();
|
|
284
286
|
// Check if personal squad exists
|
|
285
|
-
if (!
|
|
287
|
+
if (!storage.existsSync(personalSquadRoot)) {
|
|
286
288
|
throw new PersonalSquadNotFoundError();
|
|
287
289
|
}
|
|
288
290
|
// Read source squad's config to inherit extractionDisabled setting
|
|
289
291
|
// Option takes precedence, then fall back to source config
|
|
290
292
|
let extractionDisabled = options.extractionDisabled ?? false;
|
|
291
293
|
const sourceConfigPath = path.join(personalSquadRoot, 'config.json');
|
|
292
|
-
if (
|
|
294
|
+
if (storage.existsSync(sourceConfigPath)) {
|
|
293
295
|
try {
|
|
294
|
-
const sourceConfig = JSON.parse(
|
|
296
|
+
const sourceConfig = JSON.parse(storage.readSync(sourceConfigPath) ?? '{}');
|
|
295
297
|
// Inherit from source unless explicitly overridden in options
|
|
296
298
|
if (options.extractionDisabled === undefined && sourceConfig.extractionDisabled) {
|
|
297
299
|
extractionDisabled = true;
|
|
@@ -302,7 +304,7 @@ export async function setupConsultMode(options = {}) {
|
|
|
302
304
|
}
|
|
303
305
|
}
|
|
304
306
|
// Check if project already has .squad/
|
|
305
|
-
if (
|
|
307
|
+
if (storage.existsSync(squadDir)) {
|
|
306
308
|
throw new Error('This project already has a .squad/ directory. Cannot use consult mode on squadified projects.');
|
|
307
309
|
}
|
|
308
310
|
// List files in personal squad (for dry run preview or later count)
|
|
@@ -310,7 +312,7 @@ export async function setupConsultMode(options = {}) {
|
|
|
310
312
|
if (!dryRun) {
|
|
311
313
|
// Copy personal squad contents into project's .squad/
|
|
312
314
|
// This isolates changes during the consult session
|
|
313
|
-
|
|
315
|
+
cpSync(personalSquadRoot, squadDir, { recursive: true });
|
|
314
316
|
// Write/overwrite config.json with consult: true
|
|
315
317
|
// Include SquadDirConfig fields so loadDirConfig() can read it
|
|
316
318
|
// Note: version must be numeric for loadDirConfig() compatibility
|
|
@@ -323,30 +325,30 @@ export async function setupConsultMode(options = {}) {
|
|
|
323
325
|
createdAt: new Date().toISOString(),
|
|
324
326
|
extractionDisabled,
|
|
325
327
|
};
|
|
326
|
-
|
|
328
|
+
storage.writeSync(path.join(squadDir, 'config.json'), JSON.stringify(config, null, 2));
|
|
327
329
|
// Create sessions directory for tracking (if not copied)
|
|
328
330
|
const sessionsDir = path.join(squadDir, 'sessions');
|
|
329
|
-
if (!
|
|
330
|
-
|
|
331
|
+
if (!storage.existsSync(sessionsDir)) {
|
|
332
|
+
storage.mkdirSync(sessionsDir, { recursive: true });
|
|
331
333
|
}
|
|
332
334
|
// Create extract/ directory for staging generic learnings
|
|
333
335
|
const extractDir = path.join(squadDir, 'extract');
|
|
334
|
-
|
|
336
|
+
storage.mkdirSync(extractDir, { recursive: true });
|
|
335
337
|
// Patch scribe-charter.md with consult mode extraction instructions
|
|
336
338
|
patchScribeCharterForConsultMode(squadDir);
|
|
337
339
|
// Create .github/agents/squad.agent.md for `gh copilot --agent squad`
|
|
338
340
|
const agentDir = path.dirname(agentFile);
|
|
339
|
-
if (!
|
|
340
|
-
|
|
341
|
+
if (!storage.existsSync(agentDir)) {
|
|
342
|
+
storage.mkdirSync(agentDir, { recursive: true });
|
|
341
343
|
}
|
|
342
|
-
|
|
344
|
+
storage.writeSync(agentFile, getConsultAgentContent(projectName));
|
|
343
345
|
// Add .squad/ and .github/agents/squad.agent.md to .git/info/exclude
|
|
344
346
|
const excludeDir = path.dirname(gitExclude);
|
|
345
|
-
if (!
|
|
346
|
-
|
|
347
|
+
if (!storage.existsSync(excludeDir)) {
|
|
348
|
+
storage.mkdirSync(excludeDir, { recursive: true });
|
|
347
349
|
}
|
|
348
|
-
const excludeContent =
|
|
349
|
-
?
|
|
350
|
+
const excludeContent = storage.existsSync(gitExclude)
|
|
351
|
+
? storage.readSync(gitExclude) ?? ''
|
|
350
352
|
: '';
|
|
351
353
|
const excludeLines = [];
|
|
352
354
|
if (!excludeContent.includes('.squad/')) {
|
|
@@ -356,7 +358,7 @@ export async function setupConsultMode(options = {}) {
|
|
|
356
358
|
excludeLines.push('.github/agents/squad.agent.md');
|
|
357
359
|
}
|
|
358
360
|
if (excludeLines.length > 0) {
|
|
359
|
-
|
|
361
|
+
storage.appendSync(gitExclude, '\n# Squad consult mode (local only)\n' + excludeLines.join('\n') + '\n');
|
|
360
362
|
}
|
|
361
363
|
}
|
|
362
364
|
// List files created (from squad dir after copy, or from source for dry run)
|
|
@@ -381,15 +383,15 @@ export async function setupConsultMode(options = {}) {
|
|
|
381
383
|
export function loadSessionHistory(squadDir) {
|
|
382
384
|
const sessionsDir = path.join(squadDir, 'sessions');
|
|
383
385
|
const entries = [];
|
|
384
|
-
if (!
|
|
386
|
+
if (!storage.existsSync(sessionsDir)) {
|
|
385
387
|
return { entries };
|
|
386
388
|
}
|
|
387
|
-
const files =
|
|
389
|
+
const files = storage.listSync(sessionsDir)
|
|
388
390
|
.filter(f => f.endsWith('.json'))
|
|
389
391
|
.sort();
|
|
390
392
|
for (const file of files) {
|
|
391
393
|
try {
|
|
392
|
-
const content =
|
|
394
|
+
const content = storage.readSync(path.join(sessionsDir, file)) ?? '';
|
|
393
395
|
const session = JSON.parse(content);
|
|
394
396
|
// Extract learnings from session data
|
|
395
397
|
if (session.learnings && Array.isArray(session.learnings)) {
|
|
@@ -442,14 +444,14 @@ export async function extractLearnings(options = {}) {
|
|
|
442
444
|
const squadDir = path.resolve(projectRoot, '.squad');
|
|
443
445
|
const projectName = options.projectName || path.basename(projectRoot);
|
|
444
446
|
// Check if we're in consult mode
|
|
445
|
-
if (!
|
|
447
|
+
if (!storage.existsSync(squadDir)) {
|
|
446
448
|
throw new Error('Not in consult mode. No .squad/ directory found.');
|
|
447
449
|
}
|
|
448
450
|
const configPath = path.join(squadDir, 'config.json');
|
|
449
|
-
if (!
|
|
451
|
+
if (!storage.existsSync(configPath)) {
|
|
450
452
|
throw new Error('Invalid consult mode: missing config.json');
|
|
451
453
|
}
|
|
452
|
-
const config = JSON.parse(
|
|
454
|
+
const config = JSON.parse(storage.readSync(configPath) ?? '{}');
|
|
453
455
|
if (!config.consult) {
|
|
454
456
|
throw new Error('This project has a .squad/ but is not in consult mode. Use normal squad commands.');
|
|
455
457
|
}
|
|
@@ -459,8 +461,8 @@ export async function extractLearnings(options = {}) {
|
|
|
459
461
|
}
|
|
460
462
|
// Detect license
|
|
461
463
|
const licensePath = path.join(projectRoot, 'LICENSE');
|
|
462
|
-
const licenseContent =
|
|
463
|
-
?
|
|
464
|
+
const licenseContent = storage.existsSync(licensePath)
|
|
465
|
+
? storage.readSync(licensePath) ?? ''
|
|
464
466
|
: '';
|
|
465
467
|
const license = detectLicense(licenseContent);
|
|
466
468
|
// Block copyleft extraction unless --accept-risks
|
|
@@ -514,12 +516,12 @@ export async function extractLearnings(options = {}) {
|
|
|
514
516
|
consultationLogPath = await logConsultation(personalSquadRoot, result);
|
|
515
517
|
// Remove extracted files from .squad/extract/
|
|
516
518
|
for (const learning of staged) {
|
|
517
|
-
|
|
519
|
+
storage.deleteSync(learning.filepath);
|
|
518
520
|
}
|
|
519
521
|
}
|
|
520
522
|
// Clean up entire .squad/ if requested
|
|
521
523
|
if (clean && !dryRun) {
|
|
522
|
-
|
|
524
|
+
storage.deleteDirSync(squadDir);
|
|
523
525
|
cleaned = true;
|
|
524
526
|
}
|
|
525
527
|
return {
|
|
@@ -615,14 +617,14 @@ export function detectLicense(licenseContent) {
|
|
|
615
617
|
export function loadStagedLearnings(squadDir) {
|
|
616
618
|
const extractDir = path.join(squadDir, 'extract');
|
|
617
619
|
const learnings = [];
|
|
618
|
-
if (!
|
|
620
|
+
if (!storage.existsSync(extractDir)) {
|
|
619
621
|
return learnings;
|
|
620
622
|
}
|
|
621
|
-
const files =
|
|
623
|
+
const files = storage.listSync(extractDir).filter(f => f.endsWith('.md'));
|
|
622
624
|
for (const file of files) {
|
|
623
625
|
const filepath = path.join(extractDir, file);
|
|
624
626
|
try {
|
|
625
|
-
const content =
|
|
627
|
+
const content = storage.readSync(filepath) ?? '';
|
|
626
628
|
learnings.push({
|
|
627
629
|
filename: file,
|
|
628
630
|
filepath,
|
|
@@ -652,25 +654,25 @@ export async function logConsultation(personalSquadRoot, result) {
|
|
|
652
654
|
const consultDir = path.join(personalSquadRoot, 'consultations');
|
|
653
655
|
const logPath = path.join(consultDir, `${result.projectName}.md`);
|
|
654
656
|
// Create consultations directory if needed
|
|
655
|
-
if (!
|
|
656
|
-
|
|
657
|
+
if (!storage.existsSync(consultDir)) {
|
|
658
|
+
storage.mkdirSync(consultDir, { recursive: true });
|
|
657
659
|
}
|
|
658
660
|
const today = result.timestamp.split('T')[0] ?? new Date().toISOString().split('T')[0]; // YYYY-MM-DD format
|
|
659
|
-
if (
|
|
661
|
+
if (storage.existsSync(logPath)) {
|
|
660
662
|
// Append to existing log — update "Last session" and add new entry
|
|
661
|
-
let content =
|
|
663
|
+
let content = storage.readSync(logPath) ?? '';
|
|
662
664
|
// Update "Last session" date
|
|
663
665
|
content = content.replace(/\*\*Last session:\*\* \d{4}-\d{2}-\d{2}/, `**Last session:** ${today}`);
|
|
664
666
|
// Build session entry
|
|
665
667
|
const sessionEntry = formatSessionEntry(result, today);
|
|
666
668
|
// Append to file
|
|
667
|
-
|
|
669
|
+
storage.writeSync(logPath, content + sessionEntry);
|
|
668
670
|
}
|
|
669
671
|
else {
|
|
670
672
|
// Create new consultation log with full header
|
|
671
673
|
const header = formatLogHeader(result, today);
|
|
672
674
|
const sessionEntry = formatSessionEntry(result, today);
|
|
673
|
-
|
|
675
|
+
storage.writeSync(logPath, header + sessionEntry);
|
|
674
676
|
}
|
|
675
677
|
return logPath;
|
|
676
678
|
}
|
|
@@ -682,14 +684,14 @@ function formatLogHeader(result, date) {
|
|
|
682
684
|
? `**Repository:** ${result.repoUrl}\n`
|
|
683
685
|
: '';
|
|
684
686
|
const licenseName = result.license.spdxId || result.license.name || result.license.type;
|
|
685
|
-
return `# ${result.projectName}
|
|
686
|
-
|
|
687
|
-
${repoLine}**First consulted:** ${date}
|
|
688
|
-
**Last session:** ${date}
|
|
689
|
-
**License:** ${licenseName}
|
|
690
|
-
|
|
691
|
-
## Extracted Learnings
|
|
692
|
-
|
|
687
|
+
return `# ${result.projectName}
|
|
688
|
+
|
|
689
|
+
${repoLine}**First consulted:** ${date}
|
|
690
|
+
**Last session:** ${date}
|
|
691
|
+
**License:** ${licenseName}
|
|
692
|
+
|
|
693
|
+
## Extracted Learnings
|
|
694
|
+
|
|
693
695
|
`;
|
|
694
696
|
}
|
|
695
697
|
/**
|
|
@@ -697,16 +699,16 @@ ${repoLine}**First consulted:** ${date}
|
|
|
697
699
|
*/
|
|
698
700
|
function formatSessionEntry(result, date) {
|
|
699
701
|
if (result.extracted.length === 0) {
|
|
700
|
-
return `### ${date}
|
|
701
|
-
- No learnings extracted
|
|
702
|
-
|
|
702
|
+
return `### ${date}
|
|
703
|
+
- No learnings extracted
|
|
704
|
+
|
|
703
705
|
`;
|
|
704
706
|
}
|
|
705
707
|
// Just list titles/filenames, not content
|
|
706
708
|
const lines = result.extracted.map(l => `- ${l.filename}`);
|
|
707
|
-
return `### ${date}
|
|
708
|
-
${lines.join('\n')}
|
|
709
|
-
|
|
709
|
+
return `### ${date}
|
|
710
|
+
${lines.join('\n')}
|
|
711
|
+
|
|
710
712
|
`;
|
|
711
713
|
}
|
|
712
714
|
// ============================================================================
|
|
@@ -763,20 +765,20 @@ export async function mergeToPersonalSquad(learnings, personalSquadRoot) {
|
|
|
763
765
|
const skillName = extractSkillName(skill.content) || skill.filename.replace('.md', '');
|
|
764
766
|
const skillDir = path.join(skillsDir, skillName);
|
|
765
767
|
// Create skill directory if needed
|
|
766
|
-
if (!
|
|
767
|
-
|
|
768
|
+
if (!storage.existsSync(skillDir)) {
|
|
769
|
+
storage.mkdirSync(skillDir, { recursive: true });
|
|
768
770
|
}
|
|
769
771
|
const skillPath = path.join(skillDir, 'SKILL.md');
|
|
770
772
|
// Write skill (overwrites if exists — newer extraction wins)
|
|
771
|
-
|
|
773
|
+
storage.writeSync(skillPath, skill.content);
|
|
772
774
|
skillsAdded++;
|
|
773
775
|
}
|
|
774
776
|
// Route decisions to personal squad directory at decisions.md
|
|
775
777
|
if (decisions.length > 0) {
|
|
776
778
|
const decisionsPath = path.join(personalSquadRoot, 'decisions.md');
|
|
777
779
|
const newContent = decisions.map(d => d.content.trim()).join('\n\n');
|
|
778
|
-
if (
|
|
779
|
-
const existing =
|
|
780
|
+
if (storage.existsSync(decisionsPath)) {
|
|
781
|
+
const existing = storage.readSync(decisionsPath) ?? '';
|
|
780
782
|
// Check if we already have an "Extracted from Consultations" section
|
|
781
783
|
if (existing.includes('## Extracted from Consultations')) {
|
|
782
784
|
// Append under the existing section (before any subsequent ## heading)
|
|
@@ -789,27 +791,27 @@ export async function mergeToPersonalSquad(learnings, personalSquadRoot) {
|
|
|
789
791
|
// Insert before next section
|
|
790
792
|
const sectionContent = afterSection.slice(0, nextSectionMatch.index);
|
|
791
793
|
const rest = afterSection.slice(nextSectionMatch.index);
|
|
792
|
-
|
|
794
|
+
storage.writeSync(decisionsPath, beforeSection +
|
|
793
795
|
'## Extracted from Consultations' +
|
|
794
796
|
sectionContent.trimEnd() +
|
|
795
797
|
'\n\n' +
|
|
796
798
|
newContent +
|
|
797
799
|
'\n' +
|
|
798
|
-
rest
|
|
800
|
+
rest);
|
|
799
801
|
}
|
|
800
802
|
else {
|
|
801
803
|
// No next section — append to end
|
|
802
|
-
|
|
804
|
+
storage.writeSync(decisionsPath, existing.trimEnd() + '\n\n' + newContent + '\n');
|
|
803
805
|
}
|
|
804
806
|
}
|
|
805
807
|
else {
|
|
806
808
|
// No extraction section yet — create one
|
|
807
|
-
|
|
809
|
+
storage.writeSync(decisionsPath, existing.trimEnd() + '\n\n## Extracted from Consultations\n\n' + newContent + '\n');
|
|
808
810
|
}
|
|
809
811
|
}
|
|
810
812
|
else {
|
|
811
813
|
// Create new decisions file
|
|
812
|
-
|
|
814
|
+
storage.writeSync(decisionsPath, `# Squad Decisions\n\n## Extracted from Consultations\n\n${newContent}\n`);
|
|
813
815
|
}
|
|
814
816
|
decisionsAdded = decisions.length;
|
|
815
817
|
}
|