@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.
Files changed (285) hide show
  1. package/README.md +340 -296
  2. package/dist/agents/history-shadow.d.ts +7 -5
  3. package/dist/agents/history-shadow.d.ts.map +1 -1
  4. package/dist/agents/history-shadow.js +69 -78
  5. package/dist/agents/history-shadow.js.map +1 -1
  6. package/dist/agents/index.d.ts +12 -1
  7. package/dist/agents/index.d.ts.map +1 -1
  8. package/dist/agents/index.js +62 -9
  9. package/dist/agents/index.js.map +1 -1
  10. package/dist/agents/lifecycle.d.ts +4 -0
  11. package/dist/agents/lifecycle.d.ts.map +1 -1
  12. package/dist/agents/lifecycle.js +6 -7
  13. package/dist/agents/lifecycle.js.map +1 -1
  14. package/dist/agents/onboarding.d.ts +4 -2
  15. package/dist/agents/onboarding.d.ts.map +1 -1
  16. package/dist/agents/onboarding.js +26 -16
  17. package/dist/agents/onboarding.js.map +1 -1
  18. package/dist/agents/personal.d.ts +2 -1
  19. package/dist/agents/personal.d.ts.map +1 -1
  20. package/dist/agents/personal.js +11 -12
  21. package/dist/agents/personal.js.map +1 -1
  22. package/dist/build/bundle.d.ts.map +1 -1
  23. package/dist/build/bundle.js +6 -6
  24. package/dist/build/bundle.js.map +1 -1
  25. package/dist/build/github-dist.js +42 -42
  26. package/dist/build/release.d.ts.map +1 -1
  27. package/dist/build/release.js +7 -5
  28. package/dist/build/release.js.map +1 -1
  29. package/dist/casting/index.d.ts.map +1 -1
  30. package/dist/casting/index.js +4 -3
  31. package/dist/casting/index.js.map +1 -1
  32. package/dist/config/agent-source.d.ts +5 -1
  33. package/dist/config/agent-source.d.ts.map +1 -1
  34. package/dist/config/agent-source.js +85 -41
  35. package/dist/config/agent-source.js.map +1 -1
  36. package/dist/config/init.d.ts +4 -3
  37. package/dist/config/init.d.ts.map +1 -1
  38. package/dist/config/init.js +257 -236
  39. package/dist/config/init.js.map +1 -1
  40. package/dist/config/legacy-fallback.d.ts +3 -2
  41. package/dist/config/legacy-fallback.d.ts.map +1 -1
  42. package/dist/config/legacy-fallback.js +16 -14
  43. package/dist/config/legacy-fallback.js.map +1 -1
  44. package/dist/config/models.d.ts +9 -6
  45. package/dist/config/models.d.ts.map +1 -1
  46. package/dist/config/models.js +35 -25
  47. package/dist/config/models.js.map +1 -1
  48. package/dist/index.d.ts +5 -1
  49. package/dist/index.d.ts.map +1 -1
  50. package/dist/index.js +14 -1
  51. package/dist/index.js.map +1 -1
  52. package/dist/marketplace/packaging.d.ts.map +1 -1
  53. package/dist/marketplace/packaging.js +18 -16
  54. package/dist/marketplace/packaging.js.map +1 -1
  55. package/dist/multi-squad.d.ts.map +1 -1
  56. package/dist/multi-squad.js +10 -9
  57. package/dist/multi-squad.js.map +1 -1
  58. package/dist/platform/comms-file-log.d.ts.map +1 -1
  59. package/dist/platform/comms-file-log.js +7 -6
  60. package/dist/platform/comms-file-log.js.map +1 -1
  61. package/dist/platform/comms.d.ts.map +1 -1
  62. package/dist/platform/comms.js +6 -5
  63. package/dist/platform/comms.js.map +1 -1
  64. package/dist/platform/index.d.ts.map +1 -1
  65. package/dist/platform/index.js +4 -3
  66. package/dist/platform/index.js.map +1 -1
  67. package/dist/ralph/capabilities.d.ts +30 -1
  68. package/dist/ralph/capabilities.d.ts.map +1 -1
  69. package/dist/ralph/capabilities.js +51 -6
  70. package/dist/ralph/capabilities.js.map +1 -1
  71. package/dist/ralph/index.d.ts +1 -1
  72. package/dist/ralph/index.d.ts.map +1 -1
  73. package/dist/ralph/index.js +4 -3
  74. package/dist/ralph/index.js.map +1 -1
  75. package/dist/ralph/rate-limiting.d.ts.map +1 -1
  76. package/dist/ralph/rate-limiting.js +4 -4
  77. package/dist/ralph/rate-limiting.js.map +1 -1
  78. package/dist/remote/bridge.d.ts.map +1 -1
  79. package/dist/remote/bridge.js +2 -2
  80. package/dist/remote/bridge.js.map +1 -1
  81. package/dist/resolution.d.ts +9 -0
  82. package/dist/resolution.d.ts.map +1 -1
  83. package/dist/resolution.js +39 -16
  84. package/dist/resolution.js.map +1 -1
  85. package/dist/roles/catalog.d.ts +1 -1
  86. package/dist/runtime/config.d.ts.map +1 -1
  87. package/dist/runtime/config.js +8 -7
  88. package/dist/runtime/config.js.map +1 -1
  89. package/dist/runtime/cross-squad.d.ts.map +1 -1
  90. package/dist/runtime/cross-squad.js +8 -7
  91. package/dist/runtime/cross-squad.js.map +1 -1
  92. package/dist/runtime/scheduler.d.ts.map +1 -1
  93. package/dist/runtime/scheduler.js +8 -8
  94. package/dist/runtime/scheduler.js.map +1 -1
  95. package/dist/runtime/squad-observer.d.ts.map +1 -1
  96. package/dist/runtime/squad-observer.js +7 -4
  97. package/dist/runtime/squad-observer.js.map +1 -1
  98. package/dist/sharing/consult.d.ts +1 -1
  99. package/dist/sharing/consult.d.ts.map +1 -1
  100. package/dist/sharing/consult.js +144 -142
  101. package/dist/sharing/consult.js.map +1 -1
  102. package/dist/sharing/export.d.ts.map +1 -1
  103. package/dist/sharing/export.js +16 -16
  104. package/dist/sharing/export.js.map +1 -1
  105. package/dist/sharing/import.d.ts.map +1 -1
  106. package/dist/sharing/import.js +13 -12
  107. package/dist/sharing/import.js.map +1 -1
  108. package/dist/skills/skill-loader.d.ts.map +1 -1
  109. package/dist/skills/skill-loader.js +10 -9
  110. package/dist/skills/skill-loader.js.map +1 -1
  111. package/dist/skills/skill-script-loader.d.ts.map +1 -1
  112. package/dist/skills/skill-script-loader.js +6 -4
  113. package/dist/skills/skill-script-loader.js.map +1 -1
  114. package/dist/skills/skill-source.d.ts +3 -1
  115. package/dist/skills/skill-source.d.ts.map +1 -1
  116. package/dist/skills/skill-source.js +18 -16
  117. package/dist/skills/skill-source.js.map +1 -1
  118. package/dist/state/collection-map.d.ts +43 -0
  119. package/dist/state/collection-map.d.ts.map +1 -0
  120. package/dist/state/collection-map.js +9 -0
  121. package/dist/state/collection-map.js.map +1 -0
  122. package/dist/state/collections.d.ts +102 -0
  123. package/dist/state/collections.d.ts.map +1 -0
  124. package/dist/state/collections.js +317 -0
  125. package/dist/state/collections.js.map +1 -0
  126. package/dist/state/domain-types.d.ts +122 -0
  127. package/dist/state/domain-types.d.ts.map +1 -0
  128. package/dist/state/domain-types.js +54 -0
  129. package/dist/state/domain-types.js.map +1 -0
  130. package/dist/state/handles.d.ts +16 -0
  131. package/dist/state/handles.d.ts.map +1 -0
  132. package/dist/state/handles.js +161 -0
  133. package/dist/state/handles.js.map +1 -0
  134. package/dist/state/index.d.ts +17 -0
  135. package/dist/state/index.d.ts.map +1 -0
  136. package/dist/state/index.js +15 -0
  137. package/dist/state/index.js.map +1 -0
  138. package/dist/state/io/charter-io.d.ts +28 -0
  139. package/dist/state/io/charter-io.d.ts.map +1 -0
  140. package/dist/state/io/charter-io.js +94 -0
  141. package/dist/state/io/charter-io.js.map +1 -0
  142. package/dist/state/io/decisions-io.d.ts +42 -0
  143. package/dist/state/io/decisions-io.d.ts.map +1 -0
  144. package/dist/state/io/decisions-io.js +66 -0
  145. package/dist/state/io/decisions-io.js.map +1 -0
  146. package/dist/state/io/history-io.d.ts +37 -0
  147. package/dist/state/io/history-io.d.ts.map +1 -0
  148. package/dist/state/io/history-io.js +102 -0
  149. package/dist/state/io/history-io.js.map +1 -0
  150. package/dist/state/io/index.d.ts +19 -0
  151. package/dist/state/io/index.d.ts.map +1 -0
  152. package/dist/state/io/index.js +19 -0
  153. package/dist/state/io/index.js.map +1 -0
  154. package/dist/state/io/routing-io.d.ts +37 -0
  155. package/dist/state/io/routing-io.d.ts.map +1 -0
  156. package/dist/state/io/routing-io.js +99 -0
  157. package/dist/state/io/routing-io.js.map +1 -0
  158. package/dist/state/io/team-io.d.ts +46 -0
  159. package/dist/state/io/team-io.d.ts.map +1 -0
  160. package/dist/state/io/team-io.js +82 -0
  161. package/dist/state/io/team-io.js.map +1 -0
  162. package/dist/state/schema.d.ts +24 -0
  163. package/dist/state/schema.d.ts.map +1 -0
  164. package/dist/state/schema.js +41 -0
  165. package/dist/state/schema.js.map +1 -0
  166. package/dist/state/squad-state.d.ts +42 -0
  167. package/dist/state/squad-state.d.ts.map +1 -0
  168. package/dist/state/squad-state.js +68 -0
  169. package/dist/state/squad-state.js.map +1 -0
  170. package/dist/storage/fs-storage-provider.d.ts +60 -0
  171. package/dist/storage/fs-storage-provider.d.ts.map +1 -0
  172. package/dist/storage/fs-storage-provider.js +377 -0
  173. package/dist/storage/fs-storage-provider.js.map +1 -0
  174. package/dist/storage/in-memory-storage-provider.d.ts +46 -0
  175. package/dist/storage/in-memory-storage-provider.d.ts.map +1 -0
  176. package/dist/storage/in-memory-storage-provider.js +264 -0
  177. package/dist/storage/in-memory-storage-provider.js.map +1 -0
  178. package/dist/storage/index.d.ts +6 -0
  179. package/dist/storage/index.d.ts.map +1 -0
  180. package/dist/storage/index.js +5 -0
  181. package/dist/storage/index.js.map +1 -0
  182. package/dist/storage/sqlite-storage-provider.d.ts +95 -0
  183. package/dist/storage/sqlite-storage-provider.d.ts.map +1 -0
  184. package/dist/storage/sqlite-storage-provider.js +383 -0
  185. package/dist/storage/sqlite-storage-provider.js.map +1 -0
  186. package/dist/storage/storage-error.d.ts +28 -0
  187. package/dist/storage/storage-error.d.ts.map +1 -0
  188. package/dist/storage/storage-error.js +35 -0
  189. package/dist/storage/storage-error.js.map +1 -0
  190. package/dist/storage/storage-provider.d.ts +161 -0
  191. package/dist/storage/storage-provider.d.ts.map +1 -0
  192. package/dist/storage/storage-provider.js +18 -0
  193. package/dist/storage/storage-provider.js.map +1 -0
  194. package/dist/streams/resolver.d.ts.map +1 -1
  195. package/dist/streams/resolver.js +6 -5
  196. package/dist/streams/resolver.js.map +1 -1
  197. package/dist/tools/index.d.ts +5 -1
  198. package/dist/tools/index.d.ts.map +1 -1
  199. package/dist/tools/index.js +54 -15
  200. package/dist/tools/index.js.map +1 -1
  201. package/dist/upstream/resolver.d.ts +3 -2
  202. package/dist/upstream/resolver.d.ts.map +1 -1
  203. package/dist/upstream/resolver.js +33 -32
  204. package/dist/upstream/resolver.js.map +1 -1
  205. package/package.json +33 -1
  206. package/templates/casting/Futurama.json +9 -9
  207. package/templates/casting-history.json +4 -4
  208. package/templates/casting-policy.json +37 -37
  209. package/templates/casting-reference.md +104 -104
  210. package/templates/casting-registry.json +3 -3
  211. package/templates/ceremonies.md +41 -41
  212. package/templates/charter.md +53 -53
  213. package/templates/constraint-tracking.md +38 -38
  214. package/templates/cooperative-rate-limiting.md +229 -229
  215. package/templates/copilot-instructions.md +46 -46
  216. package/templates/history.md +10 -10
  217. package/templates/identity/now.md +9 -9
  218. package/templates/identity/wisdom.md +15 -15
  219. package/templates/issue-lifecycle.md +412 -412
  220. package/templates/keda-scaler.md +164 -164
  221. package/templates/machine-capabilities.md +74 -74
  222. package/templates/mcp-config.md +90 -90
  223. package/templates/multi-agent-format.md +28 -28
  224. package/templates/plugin-marketplace.md +49 -49
  225. package/templates/ralph-circuit-breaker.md +313 -313
  226. package/templates/raw-agent-output.md +37 -37
  227. package/templates/roster.md +60 -60
  228. package/templates/routing.md +39 -39
  229. package/templates/run-output.md +50 -50
  230. package/templates/schedule.json +19 -19
  231. package/templates/scribe-charter.md +123 -119
  232. package/templates/skill.md +24 -24
  233. package/templates/skills/agent-collaboration/SKILL.md +42 -42
  234. package/templates/skills/agent-conduct/SKILL.md +24 -24
  235. package/templates/skills/architectural-proposals/SKILL.md +151 -151
  236. package/templates/skills/ci-validation-gates/SKILL.md +84 -84
  237. package/templates/skills/cli-wiring/SKILL.md +47 -47
  238. package/templates/skills/client-compatibility/SKILL.md +89 -89
  239. package/templates/skills/cross-machine-coordination/SKILL.md +434 -0
  240. package/templates/skills/cross-squad/SKILL.md +114 -114
  241. package/templates/skills/distributed-mesh/SKILL.md +287 -287
  242. package/templates/skills/distributed-mesh/mesh.json.example +30 -30
  243. package/templates/skills/distributed-mesh/sync-mesh.ps1 +111 -111
  244. package/templates/skills/distributed-mesh/sync-mesh.sh +104 -104
  245. package/templates/skills/docs-standards/SKILL.md +71 -71
  246. package/templates/skills/economy-mode/SKILL.md +114 -114
  247. package/templates/skills/error-recovery/SKILL.md +99 -0
  248. package/templates/skills/external-comms/SKILL.md +329 -329
  249. package/templates/skills/gh-auth-isolation/SKILL.md +183 -183
  250. package/templates/skills/git-workflow/SKILL.md +204 -204
  251. package/templates/skills/github-multi-account/SKILL.md +95 -95
  252. package/templates/skills/history-hygiene/SKILL.md +36 -36
  253. package/templates/skills/humanizer/SKILL.md +105 -105
  254. package/templates/skills/init-mode/SKILL.md +102 -102
  255. package/templates/skills/iterative-retrieval/SKILL.md +165 -0
  256. package/templates/skills/model-selection/SKILL.md +117 -117
  257. package/templates/skills/nap/SKILL.md +24 -24
  258. package/templates/skills/notification-routing/SKILL.md +105 -0
  259. package/templates/skills/personal-squad/SKILL.md +57 -57
  260. package/templates/skills/pr-screenshots/SKILL.md +149 -0
  261. package/templates/skills/project-conventions/SKILL.md +56 -56
  262. package/templates/skills/ralph-two-pass-scan/SKILL.md +35 -0
  263. package/templates/skills/reflect/SKILL.md +229 -0
  264. package/templates/skills/release-process/SKILL.md +131 -423
  265. package/templates/skills/reskill/SKILL.md +92 -92
  266. package/templates/skills/retro-enforcement/SKILL.md +148 -0
  267. package/templates/skills/reviewer-protocol/SKILL.md +79 -79
  268. package/templates/skills/secret-handling/SKILL.md +200 -200
  269. package/templates/skills/session-recovery/SKILL.md +155 -155
  270. package/templates/skills/squad-conventions/SKILL.md +69 -69
  271. package/templates/skills/test-discipline/SKILL.md +37 -37
  272. package/templates/skills/tiered-memory/SKILL.md +234 -0
  273. package/templates/skills/windows-compatibility/SKILL.md +98 -74
  274. package/templates/{squad.agent.md → squad.agent.md.template} +57 -28
  275. package/templates/workflows/squad-ci.yml +24 -24
  276. package/templates/workflows/squad-docs.yml +54 -54
  277. package/templates/workflows/squad-heartbeat.yml +167 -171
  278. package/templates/workflows/squad-insider-release.yml +61 -61
  279. package/templates/workflows/squad-issue-assign.yml +161 -161
  280. package/templates/workflows/squad-label-enforce.yml +181 -181
  281. package/templates/workflows/squad-preview.yml +55 -55
  282. package/templates/workflows/squad-promote.yml +120 -120
  283. package/templates/workflows/squad-release.yml +77 -77
  284. package/templates/workflows/squad-triage.yml +260 -260
  285. package/templates/workflows/sync-squad-labels.yml +169 -169
@@ -7,10 +7,9 @@
7
7
  *
8
8
  * @module config/init
9
9
  */
10
- import { mkdir, writeFile, appendFile, unlink } from 'fs/promises';
11
10
  import { join, dirname } from 'path';
12
11
  import { fileURLToPath } from 'url';
13
- import { existsSync, cpSync, statSync, mkdirSync, readFileSync, readdirSync } from 'fs';
12
+ import { FSStorageProvider } from '../storage/index.js';
14
13
  import { execFileSync } from 'node:child_process';
15
14
  import { MODELS } from '../runtime/constants.js';
16
15
  import { getRoleById } from '../roles/index.js';
@@ -20,17 +19,17 @@ import { getRoleById } from '../roles/index.js';
20
19
  /**
21
20
  * Get the SDK templates directory path.
22
21
  */
23
- export function getSDKTemplatesDir() {
22
+ export function getSDKTemplatesDir(storage = new FSStorageProvider()) {
24
23
  // Use fileURLToPath for cross-platform compatibility (handles Windows drive letters, URL encoding)
25
24
  const currentDir = dirname(fileURLToPath(import.meta.url));
26
25
  // Try relative to this file (in dist/)
27
26
  const distPath = join(currentDir, '../../templates');
28
- if (existsSync(distPath)) {
27
+ if (storage.existsSync(distPath)) {
29
28
  return distPath;
30
29
  }
31
30
  // Try relative to package root (for dev)
32
31
  const pkgPath = join(currentDir, '../../../templates');
33
- if (existsSync(pkgPath)) {
32
+ if (storage.existsSync(pkgPath)) {
34
33
  return pkgPath;
35
34
  }
36
35
  return null;
@@ -38,18 +37,18 @@ export function getSDKTemplatesDir() {
38
37
  /**
39
38
  * Copy a directory recursively.
40
39
  */
41
- function copyRecursiveSync(src, dest) {
42
- if (!existsSync(dest)) {
43
- mkdirSync(dest, { recursive: true });
40
+ function copyRecursiveSync(src, dest, storage = new FSStorageProvider()) {
41
+ if (!storage.existsSync(dest)) {
42
+ storage.mkdirSync(dest, { recursive: true });
44
43
  }
45
- for (const entry of statSync(src).isDirectory() ? readdirSync(src) : []) {
44
+ for (const entry of storage.isDirectorySync(src) ? storage.listSync(src) : []) {
46
45
  const srcPath = join(src, entry);
47
46
  const destPath = join(dest, entry);
48
- if (statSync(srcPath).isDirectory()) {
49
- copyRecursiveSync(srcPath, destPath);
47
+ if (storage.isDirectorySync(srcPath)) {
48
+ copyRecursiveSync(srcPath, destPath, storage);
50
49
  }
51
50
  else {
52
- cpSync(srcPath, destPath);
51
+ storage.copySync(srcPath, destPath);
53
52
  }
54
53
  }
55
54
  }
@@ -95,82 +94,82 @@ function formatModelArray(chain) {
95
94
  */
96
95
  function generateTypeScriptConfig(options) {
97
96
  const { projectName, projectDescription, agents } = options;
98
- return `import type { SquadConfig } from '@bradygaster/squad';
99
-
100
- /**
101
- * Squad Configuration for ${projectName}
102
- * ${projectDescription ? `\n * ${projectDescription}` : ''}
103
- */
104
- const config: SquadConfig = {
105
- version: '1.0.0',
106
-
107
- models: {
108
- defaultModel: '${MODELS.DEFAULT}',
109
- defaultTier: 'standard',
110
- fallbackChains: {
111
- premium: ${formatModelArray(MODELS.FALLBACK_CHAINS.premium)},
112
- standard: ${formatModelArray(MODELS.FALLBACK_CHAINS.standard)},
113
- fast: ${formatModelArray(MODELS.FALLBACK_CHAINS.fast)}
114
- },
115
- preferSameProvider: true,
116
- respectTierCeiling: true,
117
- nuclearFallback: {
118
- enabled: false,
119
- model: '${MODELS.NUCLEAR_FALLBACK}',
120
- maxRetriesBeforeNuclear: ${MODELS.NUCLEAR_MAX_RETRIES}
121
- }
122
- },
123
-
124
- routing: {
125
- rules: [
126
- {
127
- workType: 'feature-dev',
128
- agents: ['@${agents[0]?.name || 'coordinator'}'],
129
- confidence: 'high'
130
- },
131
- {
132
- workType: 'bug-fix',
133
- agents: ['@${agents.find(a => a.role === 'developer')?.name || agents[0]?.name || 'coordinator'}'],
134
- confidence: 'high'
135
- },
136
- {
137
- workType: 'testing',
138
- agents: ['@${agents.find(a => a.role === 'tester')?.name || agents[0]?.name || 'coordinator'}'],
139
- confidence: 'high'
140
- },
141
- {
142
- workType: 'documentation',
143
- agents: ['@${agents.find(a => a.role === 'scribe')?.name || agents[0]?.name || 'coordinator'}'],
144
- confidence: 'high'
145
- }
146
- ],
147
- governance: {
148
- eagerByDefault: true,
149
- scribeAutoRuns: false,
150
- allowRecursiveSpawn: false
151
- }
152
- },
153
-
154
- casting: {
155
- allowlistUniverses: [
156
- 'The Usual Suspects',
157
- 'Breaking Bad',
158
- 'The Wire',
159
- 'Firefly'
160
- ],
161
- overflowStrategy: 'generic',
162
- universeCapacity: {}
163
- },
164
-
165
- platforms: {
166
- vscode: {
167
- disableModelSelection: false,
168
- scribeMode: 'sync'
169
- }
170
- }
171
- };
172
-
173
- export default config;
97
+ return `import type { SquadConfig } from '@bradygaster/squad';
98
+
99
+ /**
100
+ * Squad Configuration for ${projectName}
101
+ * ${projectDescription ? `\n * ${projectDescription}` : ''}
102
+ */
103
+ const config: SquadConfig = {
104
+ version: '1.0.0',
105
+
106
+ models: {
107
+ defaultModel: '${MODELS.DEFAULT}',
108
+ defaultTier: 'standard',
109
+ fallbackChains: {
110
+ premium: ${formatModelArray(MODELS.FALLBACK_CHAINS.premium)},
111
+ standard: ${formatModelArray(MODELS.FALLBACK_CHAINS.standard)},
112
+ fast: ${formatModelArray(MODELS.FALLBACK_CHAINS.fast)}
113
+ },
114
+ preferSameProvider: true,
115
+ respectTierCeiling: true,
116
+ nuclearFallback: {
117
+ enabled: false,
118
+ model: '${MODELS.NUCLEAR_FALLBACK}',
119
+ maxRetriesBeforeNuclear: ${MODELS.NUCLEAR_MAX_RETRIES}
120
+ }
121
+ },
122
+
123
+ routing: {
124
+ rules: [
125
+ {
126
+ workType: 'feature-dev',
127
+ agents: ['@${agents[0]?.name || 'coordinator'}'],
128
+ confidence: 'high'
129
+ },
130
+ {
131
+ workType: 'bug-fix',
132
+ agents: ['@${agents.find(a => a.role === 'developer')?.name || agents[0]?.name || 'coordinator'}'],
133
+ confidence: 'high'
134
+ },
135
+ {
136
+ workType: 'testing',
137
+ agents: ['@${agents.find(a => a.role === 'tester')?.name || agents[0]?.name || 'coordinator'}'],
138
+ confidence: 'high'
139
+ },
140
+ {
141
+ workType: 'documentation',
142
+ agents: ['@${agents.find(a => a.role === 'scribe')?.name || agents[0]?.name || 'coordinator'}'],
143
+ confidence: 'high'
144
+ }
145
+ ],
146
+ governance: {
147
+ eagerByDefault: true,
148
+ scribeAutoRuns: false,
149
+ allowRecursiveSpawn: false
150
+ }
151
+ },
152
+
153
+ casting: {
154
+ allowlistUniverses: [
155
+ 'The Usual Suspects',
156
+ 'Breaking Bad',
157
+ 'The Wire',
158
+ 'Firefly'
159
+ ],
160
+ overflowStrategy: 'generic',
161
+ universeCapacity: {}
162
+ },
163
+
164
+ platforms: {
165
+ vscode: {
166
+ disableModelSelection: false,
167
+ scribeMode: 'sync'
168
+ }
169
+ }
170
+ };
171
+
172
+ export default config;
174
173
  `;
175
174
  }
176
175
  /**
@@ -367,26 +366,26 @@ function generateCharter(agent, projectName, projectDescription) {
367
366
  const template = AGENT_TEMPLATES[agent.role];
368
367
  const displayName = agent.displayName || template?.displayName || titleCase(agent.name);
369
368
  const description = template?.description || 'Team member focused on their assigned responsibilities.';
370
- return `# ${displayName} — ${titleCase(agent.role)}
371
-
372
- ${description}
373
-
374
- ## Project Context
375
-
376
- **Project:** ${projectName}
377
- ${projectDescription ? `**Description:** ${projectDescription}\n` : ''}
378
-
379
- ## Responsibilities
380
-
381
- - Collaborate with team members on assigned work
382
- - Maintain code quality and project standards
383
- - Document decisions and progress in history
384
-
385
- ## Work Style
386
-
387
- - Read project context and team decisions before starting work
388
- - Communicate clearly with team members
389
- - Follow established patterns and conventions
369
+ return `# ${displayName} — ${titleCase(agent.role)}
370
+
371
+ ${description}
372
+
373
+ ## Project Context
374
+
375
+ **Project:** ${projectName}
376
+ ${projectDescription ? `**Description:** ${projectDescription}\n` : ''}
377
+
378
+ ## Responsibilities
379
+
380
+ - Collaborate with team members on assigned work
381
+ - Maintain code quality and project standards
382
+ - Document decisions and progress in history
383
+
384
+ ## Work Style
385
+
386
+ - Read project context and team decisions before starting work
387
+ - Communicate clearly with team members
388
+ - Follow established patterns and conventions
390
389
  `;
391
390
  }
392
391
  /**
@@ -395,22 +394,22 @@ ${projectDescription ? `**Description:** ${projectDescription}\n` : ''}
395
394
  function generateInitialHistory(agent, projectName, projectDescription, userName) {
396
395
  const displayName = agent.displayName || AGENT_TEMPLATES[agent.role]?.displayName || titleCase(agent.name);
397
396
  const now = new Date().toISOString().split('T')[0];
398
- return `# Project Context
399
-
400
- ${userName ? `- **Owner:** ${userName}\n` : ''}- **Project:** ${projectName}
401
- ${projectDescription ? `- **Description:** ${projectDescription}\n` : ''}- **Created:** ${now}
402
-
403
- ## Core Context
404
-
405
- Agent ${displayName} initialized and ready for work.
406
-
407
- ## Recent Updates
408
-
409
- 📌 Team initialized on ${now}
410
-
411
- ## Learnings
412
-
413
- Initial setup complete.
397
+ return `# Project Context
398
+
399
+ ${userName ? `- **Owner:** ${userName}\n` : ''}- **Project:** ${projectName}
400
+ ${projectDescription ? `- **Description:** ${projectDescription}\n` : ''}- **Created:** ${now}
401
+
402
+ ## Core Context
403
+
404
+ Agent ${displayName} initialized and ready for work.
405
+
406
+ ## Recent Updates
407
+
408
+ 📌 Team initialized on ${now}
409
+
410
+ ## Learnings
411
+
412
+ Initial setup complete.
414
413
  `;
415
414
  }
416
415
  /**
@@ -467,7 +466,7 @@ const FRAMEWORK_WORKFLOWS = [
467
466
  'squad-triage.yml',
468
467
  'sync-squad-labels.yml',
469
468
  ];
470
- export async function initSquad(options) {
469
+ export async function initSquad(options, storage = new FSStorageProvider()) {
471
470
  const { teamRoot, projectName, projectDescription, agents, configFormat = 'typescript', userName, skipExisting = true, includeWorkflows = true, includeTemplates = true, includeMcpConfig = true, projectType = 'unknown', version = '0.0.0', } = options;
472
471
  const createdFiles = [];
473
472
  const skippedFiles = [];
@@ -498,23 +497,22 @@ export async function initSquad(options) {
498
497
  };
499
498
  // Helper to write file (respects skipExisting)
500
499
  const writeIfNotExists = async (filePath, content) => {
501
- if (existsSync(filePath) && skipExisting) {
500
+ if (storage.existsSync(filePath) && skipExisting) {
502
501
  skippedFiles.push(toRelativePath(filePath));
503
502
  return false;
504
503
  }
505
- await mkdir(dirname(filePath), { recursive: true });
506
- await writeFile(filePath, content, 'utf-8');
504
+ await storage.write(filePath, content);
507
505
  createdFiles.push(toRelativePath(filePath));
508
506
  return true;
509
507
  };
510
508
  // Helper to copy file (respects skipExisting)
511
509
  const copyIfNotExists = async (src, dest) => {
512
- if (existsSync(dest) && skipExisting) {
510
+ if (storage.existsSync(dest) && skipExisting) {
513
511
  skippedFiles.push(toRelativePath(dest));
514
512
  return false;
515
513
  }
516
- await mkdir(dirname(dest), { recursive: true });
517
- cpSync(src, dest);
514
+ await storage.mkdir(dirname(dest), { recursive: true });
515
+ storage.copySync(src, dest);
518
516
  createdFiles.push(toRelativePath(dest));
519
517
  return true;
520
518
  };
@@ -534,19 +532,45 @@ export async function initSquad(options) {
534
532
  join(squadDir, 'log'),
535
533
  ];
536
534
  for (const dir of directories) {
537
- if (!existsSync(dir)) {
538
- await mkdir(dir, { recursive: true });
535
+ if (!storage.existsSync(dir)) {
536
+ await storage.mkdir(dir, { recursive: true });
537
+ }
538
+ }
539
+ // -------------------------------------------------------------------------
540
+ // Scaffold .squad/casting/ files (policy, registry, history)
541
+ // -------------------------------------------------------------------------
542
+ const castingDir = join(squadDir, 'casting');
543
+ const castingFiles = [
544
+ { name: 'policy.json', templateName: 'casting-policy.json', fallback: JSON.stringify({ casting_policy_version: '1.1', allowlist_universes: [], universe_capacity: {} }, null, 2) + '\n' },
545
+ { name: 'registry.json', templateName: 'casting-registry.json', fallback: JSON.stringify({ agents: {} }, null, 2) + '\n' },
546
+ { name: 'history.json', templateName: 'casting-history.json', fallback: JSON.stringify({ universe_usage_history: [], assignment_cast_snapshots: {} }, null, 2) + '\n' },
547
+ ];
548
+ for (const cf of castingFiles) {
549
+ const dest = join(castingDir, cf.name);
550
+ if (!storage.existsSync(dest)) {
551
+ // Try to copy from SDK templates first, fall back to inline defaults
552
+ const templateSrc = templatesDir ? join(templatesDir, cf.templateName) : null;
553
+ if (templateSrc && storage.existsSync(templateSrc)) {
554
+ storage.copySync(templateSrc, dest);
555
+ }
556
+ else {
557
+ await storage.write(dest, cf.fallback);
558
+ }
559
+ createdFiles.push(toRelativePath(dest));
560
+ }
561
+ else {
562
+ skippedFiles.push(toRelativePath(dest));
539
563
  }
540
564
  }
541
565
  // -------------------------------------------------------------------------
542
566
  // Create .squad/config.json for squad settings
543
567
  // -------------------------------------------------------------------------
544
568
  const squadConfigPath = join(squadDir, 'config.json');
545
- if (!existsSync(squadConfigPath)) {
569
+ if (!storage.existsSync(squadConfigPath)) {
546
570
  // Detect platform from git remote for config
547
571
  let detectedPlatform;
548
572
  try {
549
- const remoteUrl = execFileSync('git', ['remote', 'get-url', 'origin'], { cwd: teamRoot, encoding: 'utf-8' }).trim();
573
+ const remoteUrl = execFileSync('git', ['remote', 'get-url', 'origin'], { cwd: teamRoot, encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'] }).trim();
550
574
  const remoteUrlLower = remoteUrl.toLowerCase();
551
575
  if (remoteUrlLower.includes('dev.azure.com') || remoteUrlLower.includes('visualstudio.com') || remoteUrlLower.includes('ssh.dev.azure.com')) {
552
576
  detectedPlatform = 'azure-devops';
@@ -566,7 +590,7 @@ export async function initSquad(options) {
566
590
  // to discover available work item types for the project.
567
591
  let introspectedTypes;
568
592
  try {
569
- const remoteUrl = execFileSync('git', ['remote', 'get-url', 'origin'], { cwd: teamRoot, encoding: 'utf-8' }).trim();
593
+ const remoteUrl = execFileSync('git', ['remote', 'get-url', 'origin'], { cwd: teamRoot, encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'] }).trim();
570
594
  // Parse org/project from remote URL for introspection
571
595
  const httpsMatch = remoteUrl.match(/dev\.azure\.com\/([^/]+)\/([^/]+)\/_git/i);
572
596
  const sshMatch = remoteUrl.match(/ssh\.dev\.azure\.com:v3\/([^/]+)\/([^/]+)\//i);
@@ -605,7 +629,7 @@ export async function initSquad(options) {
605
629
  if (options.extractionDisabled) {
606
630
  squadConfig.extractionDisabled = true;
607
631
  }
608
- await writeFile(squadConfigPath, JSON.stringify(squadConfig, null, 2), 'utf-8');
632
+ await storage.write(squadConfigPath, JSON.stringify(squadConfig, null, 2));
609
633
  createdFiles.push(toRelativePath(squadConfigPath));
610
634
  }
611
635
  // -------------------------------------------------------------------------
@@ -633,7 +657,6 @@ export async function initSquad(options) {
633
657
  const agentsDir = join(squadDir, 'agents');
634
658
  for (const agent of agents) {
635
659
  const agentDir = join(agentsDir, agent.name);
636
- await mkdir(agentDir, { recursive: true });
637
660
  agentDirs.push(agentDir);
638
661
  // Create charter.md
639
662
  const charterPath = join(agentDir, 'charter.md');
@@ -650,27 +673,27 @@ export async function initSquad(options) {
650
673
  const identityDir = join(squadDir, 'identity');
651
674
  const nowMdPath = join(identityDir, 'now.md');
652
675
  const wisdomMdPath = join(identityDir, 'wisdom.md');
653
- const nowContent = `---
654
- updated_at: ${new Date().toISOString()}
655
- focus_area: Initial setup
656
- active_issues: []
657
- ---
658
-
659
- # What We're Focused On
660
-
661
- Getting started. Updated by coordinator at session start.
676
+ const nowContent = `---
677
+ updated_at: ${new Date().toISOString()}
678
+ focus_area: Initial setup
679
+ active_issues: []
680
+ ---
681
+
682
+ # What We're Focused On
683
+
684
+ Getting started. Updated by coordinator at session start.
662
685
  `;
663
- const wisdomContent = `---
664
- last_updated: ${new Date().toISOString()}
665
- ---
666
-
667
- # Team Wisdom
668
-
669
- Reusable patterns and heuristics learned through work. NOT transcripts — each entry is a distilled, actionable insight.
670
-
671
- ## Patterns
672
-
673
- <!-- Append entries below. Format: **Pattern:** description. **Context:** when it applies. -->
686
+ const wisdomContent = `---
687
+ last_updated: ${new Date().toISOString()}
688
+ ---
689
+
690
+ # Team Wisdom
691
+
692
+ Reusable patterns and heuristics learned through work. NOT transcripts — each entry is a distilled, actionable insight.
693
+
694
+ ## Patterns
695
+
696
+ <!-- Append entries below. Format: **Pattern:** description. **Context:** when it applies. -->
674
697
  `;
675
698
  await writeIfNotExists(nowMdPath, nowContent);
676
699
  await writeIfNotExists(wisdomMdPath, wisdomContent);
@@ -678,70 +701,70 @@ Reusable patterns and heuristics learned through work. NOT transcripts — each
678
701
  // Create ceremonies.md
679
702
  // -------------------------------------------------------------------------
680
703
  const ceremoniesDest = join(squadDir, 'ceremonies.md');
681
- if (templatesDir && existsSync(join(templatesDir, 'ceremonies.md'))) {
704
+ if (templatesDir && storage.existsSync(join(templatesDir, 'ceremonies.md'))) {
682
705
  await copyIfNotExists(join(templatesDir, 'ceremonies.md'), ceremoniesDest);
683
706
  }
684
707
  // -------------------------------------------------------------------------
685
708
  // Create decisions.md (canonical location at squad root)
686
709
  // -------------------------------------------------------------------------
687
710
  const decisionsPath = join(squadDir, 'decisions.md');
688
- const decisionsContent = `# Squad Decisions
689
-
690
- ## Active Decisions
691
-
692
- No decisions recorded yet.
693
-
694
- ## Governance
695
-
696
- - All meaningful changes require team consensus
697
- - Document architectural decisions here
698
- - Keep history focused on work, decisions focused on direction
711
+ const decisionsContent = `# Squad Decisions
712
+
713
+ ## Active Decisions
714
+
715
+ No decisions recorded yet.
716
+
717
+ ## Governance
718
+
719
+ - All meaningful changes require team consensus
720
+ - Document architectural decisions here
721
+ - Keep history focused on work, decisions focused on direction
699
722
  `;
700
723
  await writeIfNotExists(decisionsPath, decisionsContent);
701
724
  // -------------------------------------------------------------------------
702
725
  // Create team.md (required by shell lifecycle)
703
726
  // -------------------------------------------------------------------------
704
727
  const teamPath = join(squadDir, 'team.md');
705
- const teamContent = `# Squad Team
706
-
707
- > ${projectDescription || projectName}
708
-
709
- ## Coordinator
710
-
711
- | Name | Role | Notes |
712
- |------|------|-------|
713
- | Squad | Coordinator | Routes work, enforces handoffs and reviewer gates. |
714
-
715
- ## Members
716
-
717
- | Name | Role | Charter | Status |
718
- |------|------|---------|--------|
719
-
720
- ## Project Context
721
-
722
- - **Project:** ${projectName}
723
- ${projectDescription ? `- **Description:** ${projectDescription}\n` : ''}- **Created:** ${new Date().toISOString().split('T')[0]}
728
+ const teamContent = `# Squad Team
729
+
730
+ > ${projectDescription || projectName}
731
+
732
+ ## Coordinator
733
+
734
+ | Name | Role | Notes |
735
+ |------|------|-------|
736
+ | Squad | Coordinator | Routes work, enforces handoffs and reviewer gates. |
737
+
738
+ ## Members
739
+
740
+ | Name | Role | Charter | Status |
741
+ |------|------|---------|--------|
742
+
743
+ ## Project Context
744
+
745
+ - **Project:** ${projectName}
746
+ ${projectDescription ? `- **Description:** ${projectDescription}\n` : ''}- **Created:** ${new Date().toISOString().split('T')[0]}
724
747
  `;
725
748
  await writeIfNotExists(teamPath, teamContent);
726
749
  // -------------------------------------------------------------------------
727
750
  // Create routing.md
728
751
  // -------------------------------------------------------------------------
729
752
  const routingPath = join(squadDir, 'routing.md');
730
- if (templatesDir && existsSync(join(templatesDir, 'routing.md'))) {
753
+ if (templatesDir && storage.existsSync(join(templatesDir, 'routing.md'))) {
731
754
  await copyIfNotExists(join(templatesDir, 'routing.md'), routingPath);
732
755
  }
733
756
  else {
734
- const routingContent = `# Squad Routing
735
-
736
- ## Work Type Rules
737
-
738
- | Work Type | Primary Agent | Fallback |
739
- |-----------|---------------|----------|
740
-
741
- ## Governance
742
-
743
- - Route based on work type and agent expertise
744
- - Update this file as team capabilities evolve
757
+ const routingContent = `# Squad Routing
758
+
759
+ ## Work Type Rules
760
+
761
+ | Work Type | Primary Agent | Fallback |
762
+ |-----------|---------------|----------|
763
+
764
+ ## Governance
765
+
766
+ - Route based on work type and agent expertise
767
+ - Update this file as team capabilities evolve
745
768
  `;
746
769
  await writeIfNotExists(routingPath, routingContent);
747
770
  }
@@ -749,11 +772,11 @@ ${projectDescription ? `- **Description:** ${projectDescription}\n` : ''}- **Cre
749
772
  // Copy starter skills
750
773
  // -------------------------------------------------------------------------
751
774
  const skillsDir = join(teamRoot, '.copilot', 'skills');
752
- if (templatesDir && existsSync(join(templatesDir, 'skills'))) {
775
+ if (templatesDir && storage.existsSync(join(templatesDir, 'skills'))) {
753
776
  const skillsSrc = join(templatesDir, 'skills');
754
- const existingSkills = existsSync(skillsDir) ? readdirSync(skillsDir) : [];
777
+ const existingSkills = storage.existsSync(skillsDir) ? storage.listSync(skillsDir) : [];
755
778
  if (existingSkills.length === 0) {
756
- cpSync(skillsSrc, skillsDir, { recursive: true });
779
+ copyRecursiveSync(skillsSrc, skillsDir, storage);
757
780
  createdFiles.push('.copilot/skills');
758
781
  }
759
782
  }
@@ -768,15 +791,15 @@ ${projectDescription ? `- **Description:** ${projectDescription}\n` : ''}- **Cre
768
791
  '.squad/orchestration-log/** merge=union',
769
792
  ];
770
793
  let existingAttrs = '';
771
- if (existsSync(gitattributesPath)) {
772
- existingAttrs = readFileSync(gitattributesPath, 'utf-8');
794
+ if (storage.existsSync(gitattributesPath)) {
795
+ existingAttrs = storage.readSync(gitattributesPath) ?? '';
773
796
  }
774
797
  const missingRules = unionRules.filter(rule => !existingAttrs.includes(rule));
775
798
  if (missingRules.length > 0) {
776
799
  const block = (existingAttrs && !existingAttrs.endsWith('\n') ? '\n' : '')
777
800
  + '# Squad: union merge for append-only team state files\n'
778
801
  + missingRules.join('\n') + '\n';
779
- await appendFile(gitattributesPath, block);
802
+ await storage.append(gitattributesPath, block);
780
803
  createdFiles.push(toRelativePath(gitattributesPath));
781
804
  }
782
805
  // -------------------------------------------------------------------------
@@ -792,27 +815,26 @@ ${projectDescription ? `- **Description:** ${projectDescription}\n` : ''}- **Cre
792
815
  '.squad/sessions/',
793
816
  ];
794
817
  let existingIgnore = '';
795
- if (existsSync(gitignorePath)) {
796
- existingIgnore = readFileSync(gitignorePath, 'utf-8');
818
+ if (storage.existsSync(gitignorePath)) {
819
+ existingIgnore = storage.readSync(gitignorePath) ?? '';
797
820
  }
798
821
  const missingIgnore = ignoreEntries.filter(entry => !existingIgnore.includes(entry));
799
822
  if (missingIgnore.length > 0) {
800
823
  const block = (existingIgnore && !existingIgnore.endsWith('\n') ? '\n' : '')
801
824
  + '# Squad: ignore runtime state (logs, inbox, sessions)\n'
802
825
  + missingIgnore.join('\n') + '\n';
803
- await appendFile(gitignorePath, block);
826
+ await storage.append(gitignorePath, block);
804
827
  createdFiles.push(toRelativePath(gitignorePath));
805
828
  }
806
829
  // -------------------------------------------------------------------------
807
830
  // Create .github/agents/squad.agent.md
808
831
  // -------------------------------------------------------------------------
809
832
  const agentFile = join(teamRoot, '.github', 'agents', 'squad.agent.md');
810
- if (!existsSync(agentFile) || !skipExisting) {
811
- if (templatesDir && existsSync(join(templatesDir, 'squad.agent.md'))) {
812
- let agentContent = readFileSync(join(templatesDir, 'squad.agent.md'), 'utf-8');
833
+ if (!storage.existsSync(agentFile) || !skipExisting) {
834
+ if (templatesDir && storage.existsSync(join(templatesDir, 'squad.agent.md.template'))) {
835
+ let agentContent = storage.readSync(join(templatesDir, 'squad.agent.md.template')) ?? '';
813
836
  agentContent = stampVersionInContent(agentContent, version);
814
- await mkdir(dirname(agentFile), { recursive: true });
815
- await writeFile(agentFile, agentContent, 'utf-8');
837
+ await storage.write(agentFile, agentContent);
816
838
  createdFiles.push(toRelativePath(agentFile));
817
839
  }
818
840
  }
@@ -824,8 +846,8 @@ ${projectDescription ? `- **Description:** ${projectDescription}\n` : ''}- **Cre
824
846
  // -------------------------------------------------------------------------
825
847
  if (includeTemplates && templatesDir) {
826
848
  const templatesDest = join(teamRoot, '.squad', 'templates');
827
- if (!existsSync(templatesDest)) {
828
- cpSync(templatesDir, templatesDest, { recursive: true });
849
+ if (!storage.existsSync(templatesDest)) {
850
+ copyRecursiveSync(templatesDir, templatesDest, storage);
829
851
  createdFiles.push(toRelativePath(templatesDest));
830
852
  }
831
853
  else {
@@ -837,7 +859,7 @@ ${projectDescription ? `- **Description:** ${projectDescription}\n` : ''}- **Cre
837
859
  // -------------------------------------------------------------------------
838
860
  let isGitHub = true;
839
861
  try {
840
- const remoteUrl = execFileSync('git', ['remote', 'get-url', 'origin'], { cwd: teamRoot, encoding: 'utf-8' }).trim();
862
+ const remoteUrl = execFileSync('git', ['remote', 'get-url', 'origin'], { cwd: teamRoot, encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'] }).trim();
841
863
  const remoteUrlLower = remoteUrl.toLowerCase();
842
864
  if (remoteUrlLower.includes('dev.azure.com') || remoteUrlLower.includes('visualstudio.com') || remoteUrlLower.includes('ssh.dev.azure.com')) {
843
865
  isGitHub = false;
@@ -849,17 +871,17 @@ ${projectDescription ? `- **Description:** ${projectDescription}\n` : ''}- **Cre
849
871
  // -------------------------------------------------------------------------
850
872
  // Copy workflows (optional) — skip for ADO repos
851
873
  // -------------------------------------------------------------------------
852
- if (includeWorkflows && isGitHub && templatesDir && existsSync(join(templatesDir, 'workflows'))) {
874
+ if (includeWorkflows && isGitHub && templatesDir && storage.existsSync(join(templatesDir, 'workflows'))) {
853
875
  const workflowsSrc = join(templatesDir, 'workflows');
854
876
  const workflowsDest = join(teamRoot, '.github', 'workflows');
855
- if (statSync(workflowsSrc).isDirectory()) {
856
- const allWorkflowFiles = readdirSync(workflowsSrc).filter(f => f.endsWith('.yml'));
877
+ if (storage.isDirectorySync(workflowsSrc)) {
878
+ const allWorkflowFiles = storage.listSync(workflowsSrc).filter(f => f.endsWith('.yml'));
857
879
  const workflowFiles = allWorkflowFiles.filter(f => FRAMEWORK_WORKFLOWS.includes(f));
858
- await mkdir(workflowsDest, { recursive: true });
880
+ await storage.mkdir(workflowsDest, { recursive: true });
859
881
  for (const file of workflowFiles) {
860
882
  const destFile = join(workflowsDest, file);
861
- if (!existsSync(destFile) || !skipExisting) {
862
- cpSync(join(workflowsSrc, file), destFile);
883
+ if (!storage.existsSync(destFile) || !skipExisting) {
884
+ storage.copySync(join(workflowsSrc, file), destFile);
863
885
  createdFiles.push(toRelativePath(destFile));
864
886
  }
865
887
  else {
@@ -873,7 +895,7 @@ ${projectDescription ? `- **Description:** ${projectDescription}\n` : ''}- **Cre
873
895
  // -------------------------------------------------------------------------
874
896
  if (includeMcpConfig) {
875
897
  const mcpConfigPath = join(teamRoot, '.copilot', 'mcp-config.json');
876
- if (!existsSync(mcpConfigPath)) {
898
+ if (!storage.existsSync(mcpConfigPath)) {
877
899
  const mcpSample = isGitHub
878
900
  ? {
879
901
  mcpServers: {
@@ -898,8 +920,7 @@ ${projectDescription ? `- **Description:** ${projectDescription}\n` : ''}- **Cre
898
920
  }
899
921
  }
900
922
  };
901
- await mkdir(dirname(mcpConfigPath), { recursive: true });
902
- await writeFile(mcpConfigPath, JSON.stringify(mcpSample, null, 2) + '\n', 'utf-8');
923
+ await storage.write(mcpConfigPath, JSON.stringify(mcpSample, null, 2) + '\n');
903
924
  createdFiles.push(toRelativePath(mcpConfigPath));
904
925
  }
905
926
  else {
@@ -923,14 +944,14 @@ ${projectDescription ? `- **Description:** ${projectDescription}\n` : ''}- **Cre
923
944
  {
924
945
  const workstreamIgnoreEntry = '.squad-workstream';
925
946
  let currentIgnore = '';
926
- if (existsSync(gitignorePath)) {
927
- currentIgnore = readFileSync(gitignorePath, 'utf-8');
947
+ if (storage.existsSync(gitignorePath)) {
948
+ currentIgnore = storage.readSync(gitignorePath) ?? '';
928
949
  }
929
950
  if (!currentIgnore.includes(workstreamIgnoreEntry)) {
930
951
  const block = (currentIgnore && !currentIgnore.endsWith('\n') ? '\n' : '')
931
952
  + '# Squad: SubSquad activation file (local to this machine)\n'
932
953
  + workstreamIgnoreEntry + '\n';
933
- await appendFile(gitignorePath, block);
954
+ await storage.append(gitignorePath, block);
934
955
  createdFiles.push(toRelativePath(gitignorePath));
935
956
  }
936
957
  }
@@ -938,8 +959,8 @@ ${projectDescription ? `- **Description:** ${projectDescription}\n` : ''}- **Cre
938
959
  // Create .first-run marker
939
960
  // -------------------------------------------------------------------------
940
961
  const firstRunMarker = join(squadDir, '.first-run');
941
- if (!existsSync(firstRunMarker)) {
942
- await writeFile(firstRunMarker, new Date().toISOString() + '\n', 'utf-8');
962
+ if (!storage.existsSync(firstRunMarker)) {
963
+ await storage.write(firstRunMarker, new Date().toISOString() + '\n');
943
964
  createdFiles.push(toRelativePath(firstRunMarker));
944
965
  }
945
966
  // -------------------------------------------------------------------------
@@ -947,7 +968,7 @@ ${projectDescription ? `- **Description:** ${projectDescription}\n` : ''}- **Cre
947
968
  // -------------------------------------------------------------------------
948
969
  if (options.prompt) {
949
970
  const promptFile = join(squadDir, '.init-prompt');
950
- await writeFile(promptFile, options.prompt, 'utf-8');
971
+ await storage.write(promptFile, options.prompt);
951
972
  createdFiles.push(toRelativePath(promptFile));
952
973
  }
953
974
  return {
@@ -965,10 +986,10 @@ ${projectDescription ? `- **Description:** ${projectDescription}\n` : ''}- **Cre
965
986
  *
966
987
  * @param squadDir - Path to the .squad directory
967
988
  */
968
- export async function cleanupOrphanInitPrompt(squadDir) {
989
+ export async function cleanupOrphanInitPrompt(squadDir, storage = new FSStorageProvider()) {
969
990
  const promptFile = join(squadDir, '.init-prompt');
970
- if (existsSync(promptFile)) {
971
- await unlink(promptFile);
991
+ if (storage.existsSync(promptFile)) {
992
+ await storage.delete(promptFile);
972
993
  }
973
994
  }
974
995
  //# sourceMappingURL=init.js.map