deplyze-code 0.1.1 → 0.1.3

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.
@@ -0,0 +1,491 @@
1
+ import { randomUUID } from 'crypto'
2
+ import { spawn } from 'child_process'
3
+ import { mkdir, mkdtemp, readFile, rm, unlink, writeFile } from 'fs/promises'
4
+ import { tmpdir } from 'os'
5
+ import { dirname, join } from 'path'
6
+ import { fileURLToPath } from 'url'
7
+ import { getSessionId, setOriginalCwd } from '../src/bootstrap/state.js'
8
+ import peersCommand from '../src/commands/peers/index.ts'
9
+ import { getBuiltInAgents } from '../src/tools/AgentTool/builtInAgents.ts'
10
+ import { ListPeersTool } from '../src/tools/ListPeersTool/ListPeersTool.ts'
11
+ import { executeAutoDream, initAutoDream } from '../src/services/autoDream/autoDream.ts'
12
+ import {
13
+ AUTO_DREAM_SMOKE_ENV,
14
+ isAutoDreamSmokeEnabled,
15
+ isAutoDreamSupported,
16
+ } from '../src/services/autoDream/config.ts'
17
+ import { getDefaultAppState, type AppState } from '../src/state/AppStateStore.ts'
18
+ import { ASYNC_AGENT_ALLOWED_TOOLS } from '../src/constants/tools.ts'
19
+ import { enableConfigs } from '../src/utils/config.ts'
20
+ import { getModelOptions } from '../src/utils/model/modelOptions.ts'
21
+ import { getPlatform } from '../src/utils/platform.ts'
22
+ import { getProjectDir } from '../src/utils/sessionStorage.js'
23
+ import { buildEffectiveSystemPrompt } from '../src/utils/systemPrompt.ts'
24
+ import { listLocalPeers, sendToUdsSocket } from '../src/utils/udsClient.ts'
25
+ import { getUdsMessagingSocketPath, startUdsMessaging } from '../src/utils/udsMessaging.ts'
26
+
27
+ type SmokePhase = 'common' | 'phase1' | 'phase2' | 'phase3'
28
+
29
+ const GEMINI_API_KEY = process.env.GEMINI_API_KEY || process.env.GOOGLE_API_KEY
30
+ const ROOT = dirname(dirname(fileURLToPath(import.meta.url)))
31
+ const MEMORY_SELECTOR_PATH = join(
32
+ ROOT,
33
+ 'src',
34
+ 'components',
35
+ 'memory',
36
+ 'MemoryFileSelector.tsx',
37
+ )
38
+
39
+ function stripAnsi(value: string): string {
40
+ return value.replace(/\u001B\[[0-9;]*[A-Za-z]/g, '')
41
+ }
42
+
43
+ function normalizePathForComparison(value: string): string {
44
+ const withForwardSlashes = value.replaceAll('\\', '/').toLowerCase()
45
+ return withForwardSlashes.replace(/^([a-z]):/, (_match, drive: string) => {
46
+ return `/${drive}`
47
+ })
48
+ }
49
+
50
+ function assert(condition: unknown, message: string): asserts condition {
51
+ if (!condition) {
52
+ throw new Error(message)
53
+ }
54
+ }
55
+
56
+ async function runProcess(
57
+ args: string[],
58
+ options?: {
59
+ env?: NodeJS.ProcessEnv
60
+ stdin?: string
61
+ timeoutMs?: number
62
+ cwd?: string
63
+ expectExitCode?: number
64
+ },
65
+ ): Promise<{ stdout: string; stderr: string; code: number | null }> {
66
+ const child = spawn(process.execPath, args, {
67
+ cwd: options?.cwd ?? ROOT,
68
+ env: options?.env ?? process.env,
69
+ stdio: 'pipe',
70
+ })
71
+
72
+ let stdout = ''
73
+ let stderr = ''
74
+ child.stdout.on('data', chunk => {
75
+ stdout += chunk.toString()
76
+ })
77
+ child.stderr.on('data', chunk => {
78
+ stderr += chunk.toString()
79
+ })
80
+
81
+ if (options?.stdin) {
82
+ child.stdin.write(options.stdin)
83
+ }
84
+ child.stdin.end()
85
+
86
+ const result = await new Promise<{
87
+ stdout: string
88
+ stderr: string
89
+ code: number | null
90
+ }>((resolve, reject) => {
91
+ const timeout = setTimeout(() => {
92
+ child.kill()
93
+ reject(
94
+ new Error(
95
+ `Timed out after ${options?.timeoutMs ?? 60_000}ms: bun ${args.join(' ')}`,
96
+ ),
97
+ )
98
+ }, options?.timeoutMs ?? 60_000)
99
+
100
+ child.on('error', error => {
101
+ clearTimeout(timeout)
102
+ reject(error)
103
+ })
104
+
105
+ child.on('exit', code => {
106
+ clearTimeout(timeout)
107
+ resolve({
108
+ stdout: stripAnsi(stdout),
109
+ stderr: stripAnsi(stderr),
110
+ code,
111
+ })
112
+ })
113
+ })
114
+
115
+ if (
116
+ options?.expectExitCode !== undefined &&
117
+ result.code !== options.expectExitCode
118
+ ) {
119
+ throw new Error(
120
+ [
121
+ `Unexpected exit code ${result.code} for bun ${args.join(' ')}`,
122
+ result.stdout && `stdout:\n${result.stdout}`,
123
+ result.stderr && `stderr:\n${result.stderr}`,
124
+ ]
125
+ .filter(Boolean)
126
+ .join('\n\n'),
127
+ )
128
+ }
129
+
130
+ return result
131
+ }
132
+
133
+ async function launchStabilityCheck(env: NodeJS.ProcessEnv): Promise<void> {
134
+ const child = spawn(process.execPath, ['run', './bin/deplyze'], {
135
+ cwd: ROOT,
136
+ env,
137
+ stdio: 'pipe',
138
+ })
139
+
140
+ let stderr = ''
141
+ child.stderr.on('data', chunk => {
142
+ stderr += chunk.toString()
143
+ })
144
+
145
+ const exitEarly = await new Promise<{ code: number | null; signal: NodeJS.Signals | null } | null>(
146
+ resolve => {
147
+ const timer = setTimeout(() => resolve(null), 1_500)
148
+ child.on('exit', (code, signal) => {
149
+ clearTimeout(timer)
150
+ resolve({ code, signal })
151
+ })
152
+ },
153
+ )
154
+
155
+ if (exitEarly) {
156
+ throw new Error(
157
+ `Interactive launch exited early (code=${exitEarly.code}, signal=${exitEarly.signal ?? 'none'})\n${stripAnsi(stderr)}`,
158
+ )
159
+ }
160
+
161
+ child.kill()
162
+ await new Promise(resolve => child.on('exit', resolve))
163
+ }
164
+
165
+ async function runCommonSmoke(phase: string): Promise<void> {
166
+ assert(
167
+ GEMINI_API_KEY,
168
+ 'GEMINI_API_KEY or GOOGLE_API_KEY must be set for live smoke tests.',
169
+ )
170
+
171
+ const env = {
172
+ ...process.env,
173
+ GEMINI_API_KEY,
174
+ }
175
+
176
+ await launchStabilityCheck(env)
177
+
178
+ const plain = await runProcess(
179
+ ['run', './bin/deplyze', '-p', 'Reply exactly OK.'],
180
+ { env, expectExitCode: 0, timeoutMs: 120_000 },
181
+ )
182
+ assert(plain.stdout.includes('OK'), 'Plain prompt smoke did not return OK.')
183
+
184
+ const bash = await runProcess(
185
+ [
186
+ 'run',
187
+ './bin/deplyze',
188
+ '-p',
189
+ 'Use Bash to print the current working directory and answer with only that path.',
190
+ '--allowedTools',
191
+ 'Bash',
192
+ '--dangerously-skip-permissions',
193
+ ],
194
+ { env, expectExitCode: 0, timeoutMs: 120_000 },
195
+ )
196
+ const bashOut = normalizePathForComparison(bash.stdout.trim())
197
+ const rootPath = normalizePathForComparison(ROOT)
198
+ assert(
199
+ bashOut.includes(rootPath),
200
+ `Bash smoke did not include workspace path.\n${bash.stdout}`,
201
+ )
202
+
203
+ const smokeDir = join(ROOT, '.tmp-smoke')
204
+ const smokeFile = join(smokeDir, `${phase}.txt`)
205
+ await mkdir(smokeDir, { recursive: true })
206
+ await unlink(smokeFile).catch(() => {})
207
+ const fileWrite = await runProcess(
208
+ [
209
+ 'run',
210
+ './bin/deplyze',
211
+ '-p',
212
+ `Use Write to create ${smokeFile} containing PHASE_OK and answer only DONE.`,
213
+ '--allowedTools',
214
+ 'Write',
215
+ '--dangerously-skip-permissions',
216
+ ],
217
+ { env, expectExitCode: 0, timeoutMs: 120_000 },
218
+ )
219
+ assert(
220
+ fileWrite.stdout.includes('DONE'),
221
+ `File write smoke did not report DONE.\n${fileWrite.stdout}`,
222
+ )
223
+ const written = await readFile(smokeFile, 'utf8')
224
+ assert(written.includes('PHASE_OK'), 'File write smoke did not write PHASE_OK.')
225
+ await unlink(smokeFile)
226
+
227
+ enableConfigs()
228
+ const modelLabels = getModelOptions()
229
+ .map(option => option.label.toLowerCase())
230
+ .join('\n')
231
+ assert(
232
+ modelLabels.includes('gemini 3.1 pro') &&
233
+ modelLabels.includes('gemini 3 flash') &&
234
+ modelLabels.includes('gemini 3.1 flash-lite'),
235
+ `Model smoke did not surface Gemini options.\n${modelLabels}`,
236
+ )
237
+ }
238
+
239
+ async function runPhase1FeatureSmoke(): Promise<void> {
240
+ const tempDir = await mkdtemp(join(tmpdir(), 'deplyze-smoke-phase1-'))
241
+ const previousConfigDir = process.env.CLAUDE_CONFIG_DIR
242
+ const previousSmokeEnv = process.env[AUTO_DREAM_SMOKE_ENV]
243
+ const previousRemote = process.env.CLAUDE_CODE_REMOTE
244
+
245
+ try {
246
+ process.env.CLAUDE_CONFIG_DIR = join(tempDir, '.claude')
247
+ process.env[AUTO_DREAM_SMOKE_ENV] = '1'
248
+ delete process.env.CLAUDE_CODE_REMOTE
249
+
250
+ const projectDir = join(tempDir, 'project')
251
+ setOriginalCwd(projectDir)
252
+ const transcriptDir = getProjectDir(projectDir)
253
+ await mkdir(transcriptDir, { recursive: true })
254
+ await writeFile(join(transcriptDir, `${randomUUID()}.jsonl`), '')
255
+
256
+ let appState: AppState = getDefaultAppState()
257
+ const setAppState = (updater: (prev: AppState) => AppState) => {
258
+ appState = updater(appState)
259
+ }
260
+
261
+ initAutoDream()
262
+ await executeAutoDream({
263
+ toolUseContext: {
264
+ getAppState: () => appState,
265
+ setAppState,
266
+ },
267
+ } as never)
268
+
269
+ const [task] = Object.values(appState.tasks)
270
+ assert(task, 'Auto-dream smoke did not register a task.')
271
+ assert(task.type === 'dream', 'Auto-dream smoke registered the wrong task type.')
272
+ assert(task.status === 'completed', 'Auto-dream smoke task did not complete.')
273
+ assert(
274
+ task.type === 'dream' && task.turns[0]?.text.includes('smoke trigger'),
275
+ 'Auto-dream smoke task did not record the smoke progress turn.',
276
+ )
277
+ assert(isAutoDreamSmokeEnabled(), 'Auto-dream smoke env was not recognized.')
278
+ assert(isAutoDreamSupported(), 'Auto-dream should be supported in the local Gemini runtime.')
279
+
280
+ const selectorSource = await readFile(MEMORY_SELECTOR_PATH, 'utf8')
281
+ assert(
282
+ !selectorSource.includes('/dream to run'),
283
+ 'Memory selector still advertises the broken /dream path.',
284
+ )
285
+
286
+ await writeFile(join(transcriptDir, `${getSessionId()}.jsonl`), '')
287
+ } finally {
288
+ if (previousConfigDir === undefined) {
289
+ delete process.env.CLAUDE_CONFIG_DIR
290
+ } else {
291
+ process.env.CLAUDE_CONFIG_DIR = previousConfigDir
292
+ }
293
+ if (previousSmokeEnv === undefined) {
294
+ delete process.env[AUTO_DREAM_SMOKE_ENV]
295
+ } else {
296
+ process.env[AUTO_DREAM_SMOKE_ENV] = previousSmokeEnv
297
+ }
298
+ if (previousRemote === undefined) {
299
+ delete process.env.CLAUDE_CODE_REMOTE
300
+ } else {
301
+ process.env.CLAUDE_CODE_REMOTE = previousRemote
302
+ }
303
+ await rm(tempDir, { recursive: true, force: true })
304
+ }
305
+ }
306
+
307
+ async function runPhase2FeatureSmoke(): Promise<void> {
308
+ const previousCoordinatorMode = process.env.CLAUDE_CODE_COORDINATOR_MODE
309
+
310
+ try {
311
+ process.env.CLAUDE_CODE_COORDINATOR_MODE = '1'
312
+
313
+ const coordinatorAgents = getBuiltInAgents()
314
+ assert(
315
+ coordinatorAgents.length === 1,
316
+ `Coordinator mode should expose exactly one worker agent, got ${coordinatorAgents.length}.`,
317
+ )
318
+
319
+ const [worker] = coordinatorAgents
320
+ assert(worker?.agentType === 'worker', 'Coordinator worker agent is missing.')
321
+
322
+ const workerPrompt = worker.getSystemPrompt({
323
+ toolUseContext: { options: {} } as never,
324
+ })
325
+ assert(
326
+ workerPrompt.includes('worker agent operating under a coordinator'),
327
+ 'Coordinator worker prompt did not load.',
328
+ )
329
+ assert(
330
+ !workerPrompt.toLowerCase().includes('claude.ai'),
331
+ 'Coordinator worker prompt should stay provider-agnostic.',
332
+ )
333
+
334
+ assert(
335
+ worker.tools?.length === 1 && worker.tools[0] === '*',
336
+ 'Coordinator worker should rely on the async worker tool pool.',
337
+ )
338
+ assert(
339
+ ASYNC_AGENT_ALLOWED_TOOLS.has('Bash') &&
340
+ ASYNC_AGENT_ALLOWED_TOOLS.has('Read') &&
341
+ ASYNC_AGENT_ALLOWED_TOOLS.has('Edit') &&
342
+ ASYNC_AGENT_ALLOWED_TOOLS.has('Write') &&
343
+ !ASYNC_AGENT_ALLOWED_TOOLS.has('Agent') &&
344
+ !ASYNC_AGENT_ALLOWED_TOOLS.has('SendMessage'),
345
+ 'Coordinator worker async tool pool no longer matches the expected provider-agnostic contract.',
346
+ )
347
+
348
+ const prompt = buildEffectiveSystemPrompt({
349
+ mainThreadAgentDefinition: undefined,
350
+ toolUseContext: { options: {} } as never,
351
+ customSystemPrompt: undefined,
352
+ defaultSystemPrompt: ['default prompt'],
353
+ appendSystemPrompt: undefined,
354
+ overrideSystemPrompt: undefined,
355
+ })
356
+ const promptText = prompt.join('\n')
357
+ assert(
358
+ promptText.includes('You are a **coordinator**'),
359
+ 'Coordinator system prompt did not activate under the env gate.',
360
+ )
361
+ assert(
362
+ promptText.includes('subagent_type `worker`'),
363
+ 'Coordinator system prompt does not describe the worker handoff path.',
364
+ )
365
+ } finally {
366
+ if (previousCoordinatorMode === undefined) {
367
+ delete process.env.CLAUDE_CODE_COORDINATOR_MODE
368
+ } else {
369
+ process.env.CLAUDE_CODE_COORDINATOR_MODE = previousCoordinatorMode
370
+ }
371
+ }
372
+ }
373
+
374
+ async function runPhase3FeatureSmoke(): Promise<void> {
375
+ const tempDir = await mkdtemp(join(tmpdir(), 'deplyze-smoke-phase3-'))
376
+ const previousConfigDir = process.env.CLAUDE_CONFIG_DIR
377
+ const platform = getPlatform()
378
+ const holder = spawn(process.execPath, ['-e', 'setTimeout(() => {}, 30000)'], {
379
+ stdio: 'ignore',
380
+ })
381
+
382
+ try {
383
+ const holderPid = holder.pid
384
+ assert(holderPid, 'Phase 3 smoke could not create a holder process.')
385
+
386
+ process.env.CLAUDE_CONFIG_DIR = join(tempDir, '.claude')
387
+ const sessionsDir = join(process.env.CLAUDE_CONFIG_DIR, 'sessions')
388
+ await mkdir(sessionsDir, { recursive: true })
389
+ const sessionId = randomUUID()
390
+ await writeFile(
391
+ join(sessionsDir, `${holderPid}.json`),
392
+ JSON.stringify(
393
+ {
394
+ pid: holderPid,
395
+ sessionId,
396
+ cwd: ROOT,
397
+ startedAt: Date.now(),
398
+ kind: 'interactive',
399
+ name: 'phase3-peer',
400
+ status: 'idle',
401
+ messagingSocketPath: '/tmp/phase3-peer.sock',
402
+ },
403
+ null,
404
+ 2,
405
+ ),
406
+ )
407
+
408
+ const peers = await listLocalPeers()
409
+ assert(peers.length === 1, 'Phase 3 smoke did not discover the registry peer.')
410
+ assert(peers[0]?.name === 'phase3-peer', 'Phase 3 smoke peer name mismatch.')
411
+
412
+ const toolResult = await ListPeersTool.call(
413
+ {},
414
+ {} as never,
415
+ (() => {
416
+ throw new Error('not used')
417
+ }) as never,
418
+ {} as never,
419
+ )
420
+ assert(
421
+ toolResult.data.peers[0]?.sessionId === sessionId,
422
+ 'ListPeersTool did not return the registry peer.',
423
+ )
424
+
425
+ const commandModule = await peersCommand.load()
426
+ const commandResult = await commandModule.call('', {} as never)
427
+ assert(
428
+ commandResult.type === 'text' &&
429
+ commandResult.value.includes('phase3-peer') &&
430
+ commandResult.value.includes('transport:'),
431
+ '/peers did not return the expected local peer summary.',
432
+ )
433
+
434
+ await startUdsMessaging(join(tempDir, 'sockets', 'phase3.sock'))
435
+ if (platform === 'windows') {
436
+ assert(
437
+ getUdsMessagingSocketPath() === undefined,
438
+ 'Native Windows should not advertise a live UDS socket in Phase 3.',
439
+ )
440
+ await sendToUdsSocket('/tmp/phase3-peer.sock', 'hello').then(
441
+ () => {
442
+ throw new Error('Native Windows transport should remain deferred.')
443
+ },
444
+ error => {
445
+ assert(
446
+ String(error).includes('native windows'),
447
+ `Unexpected Windows UDS error: ${String(error)}`,
448
+ )
449
+ },
450
+ )
451
+ assert(
452
+ peers[0]?.canMessage === false,
453
+ 'Native Windows peers must remain non-messageable in Phase 3.',
454
+ )
455
+ }
456
+ } finally {
457
+ holder.kill()
458
+ if (previousConfigDir === undefined) {
459
+ delete process.env.CLAUDE_CONFIG_DIR
460
+ } else {
461
+ process.env.CLAUDE_CONFIG_DIR = previousConfigDir
462
+ }
463
+ await rm(tempDir, { recursive: true, force: true })
464
+ }
465
+ }
466
+
467
+ async function main(): Promise<void> {
468
+ const phase = (process.argv[2] ?? 'common') as SmokePhase
469
+
470
+ switch (phase) {
471
+ case 'common':
472
+ await runCommonSmoke('common')
473
+ break
474
+ case 'phase1':
475
+ await runCommonSmoke('phase1')
476
+ await runPhase1FeatureSmoke()
477
+ break
478
+ case 'phase2':
479
+ await runCommonSmoke('phase2')
480
+ await runPhase2FeatureSmoke()
481
+ break
482
+ case 'phase3':
483
+ await runCommonSmoke('phase3')
484
+ await runPhase3FeatureSmoke()
485
+ break
486
+ default:
487
+ throw new Error(`Unsupported smoke phase: ${phase}`)
488
+ }
489
+ }
490
+
491
+ await main()
@@ -112,9 +112,8 @@ import {
112
112
  const getCoordinatorUserContext: (
113
113
  mcpClients: ReadonlyArray<{ name: string }>,
114
114
  scratchpadDir?: string,
115
- ) => { [k: string]: string } = feature('COORDINATOR_MODE')
116
- ? require('./coordinator/coordinatorMode.js').getCoordinatorUserContext
117
- : () => ({})
115
+ ) => { [k: string]: string } =
116
+ require('./coordinator/coordinatorMode.js').getCoordinatorUserContext
118
117
  /* eslint-enable @typescript-eslint/no-require-imports */
119
118
 
120
119
  // Dead code elimination: conditional import for snip compaction
@@ -0,0 +1,50 @@
1
+ import type { Command, LocalCommandCall } from '../../types/command.js'
2
+ import { listLocalPeers } from '../../utils/concurrentSessions.js'
3
+ import { getPlatform } from '../../utils/platform.js'
4
+
5
+ const call: LocalCommandCall = async () => {
6
+ const peers = await listLocalPeers()
7
+ if (peers.length === 0) {
8
+ const platform = getPlatform()
9
+ const suffix =
10
+ platform === 'windows'
11
+ ? ' Native Windows live UDS transport remains deferred in this phase.'
12
+ : ''
13
+ return {
14
+ type: 'text',
15
+ value: `No local peers found.${suffix}`,
16
+ }
17
+ }
18
+
19
+ const value = peers
20
+ .map(peer => {
21
+ const header = `${peer.name ?? peer.sessionId} [${peer.kind}]`
22
+ const details = [
23
+ `session: ${peer.sessionId}`,
24
+ `pid: ${peer.pid}`,
25
+ `cwd: ${peer.cwd}`,
26
+ `transport: ${peer.transport}${peer.address ? ` (${peer.address})` : ''}`,
27
+ `messageable: ${peer.canMessage ? 'yes' : `no${peer.reason ? ` - ${peer.reason}` : ''}`}`,
28
+ ]
29
+ if (peer.status) {
30
+ details.splice(3, 0, `status: ${peer.status}`)
31
+ }
32
+ return [header, ...details].join('\n')
33
+ })
34
+ .join('\n\n')
35
+
36
+ return {
37
+ type: 'text',
38
+ value,
39
+ }
40
+ }
41
+
42
+ const peers = {
43
+ type: 'local',
44
+ name: 'peers',
45
+ description: 'List discoverable local peer sessions for inbox coordination',
46
+ supportsNonInteractive: true,
47
+ load: () => Promise.resolve({ call }),
48
+ } satisfies Command
49
+
50
+ export default peers