@adhdev/daemon-core 0.8.4 → 0.8.6
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/dist/index.js +76 -7
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +76 -7
- package/dist/index.mjs.map +1 -1
- package/node_modules/@adhdev/session-host-core/package.json +1 -1
- package/package.json +1 -1
- package/src/commands/cdp-commands.ts +46 -7
- package/src/daemon/dev-auto-implement.ts +40 -0
package/package.json
CHANGED
|
@@ -215,6 +215,42 @@ function resolveSafePath(requestedPath: string): string {
|
|
|
215
215
|
return resolved;
|
|
216
216
|
}
|
|
217
217
|
|
|
218
|
+
function listDirectoryEntriesSafe(dirPath: string): Array<{ name: string; type: 'directory' | 'file'; size?: number }> {
|
|
219
|
+
const entries = fs.readdirSync(dirPath, { withFileTypes: true });
|
|
220
|
+
const files: Array<{ name: string; type: 'directory' | 'file'; size?: number }> = [];
|
|
221
|
+
|
|
222
|
+
for (const entry of entries) {
|
|
223
|
+
const entryPath = path.join(dirPath, entry.name);
|
|
224
|
+
try {
|
|
225
|
+
if (entry.isDirectory()) {
|
|
226
|
+
files.push({ name: entry.name, type: 'directory' });
|
|
227
|
+
continue;
|
|
228
|
+
}
|
|
229
|
+
if (entry.isFile()) {
|
|
230
|
+
let size: number | undefined;
|
|
231
|
+
try {
|
|
232
|
+
size = fs.statSync(entryPath).size;
|
|
233
|
+
} catch {
|
|
234
|
+
size = undefined;
|
|
235
|
+
}
|
|
236
|
+
files.push({ name: entry.name, type: 'file', size });
|
|
237
|
+
continue;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
const stat = fs.statSync(entryPath);
|
|
241
|
+
files.push({
|
|
242
|
+
name: entry.name,
|
|
243
|
+
type: stat.isDirectory() ? 'directory' : 'file',
|
|
244
|
+
size: stat.isFile() ? stat.size : undefined,
|
|
245
|
+
});
|
|
246
|
+
} catch {
|
|
247
|
+
// Skip inaccessible entries such as protected Windows root files.
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
return files;
|
|
252
|
+
}
|
|
253
|
+
|
|
218
254
|
export async function handleFileRead(h: CommandHelpers, args: any): Promise<CommandResult> {
|
|
219
255
|
try {
|
|
220
256
|
const filePath = resolveSafePath(args?.path);
|
|
@@ -239,12 +275,7 @@ export async function handleFileWrite(h: CommandHelpers, args: any): Promise<Com
|
|
|
239
275
|
export async function handleFileList(h: CommandHelpers, args: any): Promise<CommandResult> {
|
|
240
276
|
try {
|
|
241
277
|
const dirPath = resolveSafePath(args?.path || '.');
|
|
242
|
-
const
|
|
243
|
-
const files = entries.map(e => ({
|
|
244
|
-
name: e.name,
|
|
245
|
-
type: e.isDirectory() ? 'directory' : 'file',
|
|
246
|
-
size: e.isFile() ? fs.statSync(path.join(dirPath, e.name)).size : undefined,
|
|
247
|
-
}));
|
|
278
|
+
const files = listDirectoryEntriesSafe(dirPath);
|
|
248
279
|
return { success: true, files, path: dirPath };
|
|
249
280
|
} catch (e: any) {
|
|
250
281
|
return { success: false, error: e.message };
|
|
@@ -252,5 +283,13 @@ export async function handleFileList(h: CommandHelpers, args: any): Promise<Comm
|
|
|
252
283
|
}
|
|
253
284
|
|
|
254
285
|
export async function handleFileListBrowse(h: CommandHelpers, args: any): Promise<CommandResult> {
|
|
255
|
-
|
|
286
|
+
try {
|
|
287
|
+
const dirPath = resolveSafePath(args?.path || '.');
|
|
288
|
+
const files = listDirectoryEntriesSafe(dirPath)
|
|
289
|
+
.filter(entry => entry.type === 'directory')
|
|
290
|
+
.sort((a, b) => a.name.localeCompare(b.name));
|
|
291
|
+
return { success: true, files, path: dirPath };
|
|
292
|
+
} catch (e: any) {
|
|
293
|
+
return { success: false, error: e.message };
|
|
294
|
+
}
|
|
256
295
|
}
|
|
@@ -516,6 +516,8 @@ export async function handleAutoImplement(ctx: DevServerContext, type: string, r
|
|
|
516
516
|
let approvalBuffer = '';
|
|
517
517
|
let lastApprovalTime = 0;
|
|
518
518
|
let completionSignalSeen = false;
|
|
519
|
+
let autoStopTimer: ReturnType<typeof setTimeout> | null = null;
|
|
520
|
+
let autoStopIssued = false;
|
|
519
521
|
|
|
520
522
|
try {
|
|
521
523
|
const { normalizeCliProviderForRuntime } = await import('../cli-adapters/provider-cli-adapter.js');
|
|
@@ -566,8 +568,40 @@ export async function handleAutoImplement(ctx: DevServerContext, type: string, r
|
|
|
566
568
|
}
|
|
567
569
|
};
|
|
568
570
|
|
|
571
|
+
const clearAutoStopTimer = () => {
|
|
572
|
+
if (autoStopTimer) {
|
|
573
|
+
clearTimeout(autoStopTimer);
|
|
574
|
+
autoStopTimer = null;
|
|
575
|
+
}
|
|
576
|
+
};
|
|
577
|
+
|
|
578
|
+
const scheduleAutoStopForVerification = () => {
|
|
579
|
+
if (!verification || command !== 'codex' || completionSignalSeen || autoStopIssued) return;
|
|
580
|
+
const elapsed = Date.now() - spawnedAt;
|
|
581
|
+
if (elapsed < 30000) return;
|
|
582
|
+
clearAutoStopTimer();
|
|
583
|
+
autoStopTimer = setTimeout(() => {
|
|
584
|
+
if (!ctx.autoImplProcess || completionSignalSeen || autoStopIssued) return;
|
|
585
|
+
autoStopIssued = true;
|
|
586
|
+
ctx.log(`Auto-implement output quiet for 30s after ${Math.round((Date.now() - spawnedAt) / 1000)}s. Interrupting agent and switching to daemon verification.`);
|
|
587
|
+
sendAutoImplSSE(ctx, {
|
|
588
|
+
event: 'output',
|
|
589
|
+
data: {
|
|
590
|
+
chunk: '\n[🤖 ADHDev Pipeline] Agent output quiet. Interrupting and running daemon verification...\n',
|
|
591
|
+
stream: 'stdout',
|
|
592
|
+
},
|
|
593
|
+
});
|
|
594
|
+
try {
|
|
595
|
+
(ctx.autoImplProcess as any).kill('SIGINT');
|
|
596
|
+
} catch {
|
|
597
|
+
// ignore
|
|
598
|
+
}
|
|
599
|
+
}, 30000);
|
|
600
|
+
};
|
|
601
|
+
|
|
569
602
|
const finalizeCliAutoImpl = async (code: number | null) => {
|
|
570
603
|
ctx.autoImplProcess = null;
|
|
604
|
+
clearAutoStopTimer();
|
|
571
605
|
let success = completionSignalSeen || code === 0;
|
|
572
606
|
let message = success
|
|
573
607
|
? (completionSignalSeen && code !== 0 ? '✅ Auto-implement complete (completion signal)' : '✅ Auto-implement complete')
|
|
@@ -620,12 +654,14 @@ export async function handleAutoImplement(ctx: DevServerContext, type: string, r
|
|
|
620
654
|
if (isPty) {
|
|
621
655
|
child.onData((data: string) => {
|
|
622
656
|
stdout += data;
|
|
657
|
+
clearAutoStopTimer();
|
|
623
658
|
if (data.includes('\x1b[6n')) {
|
|
624
659
|
child.write('\x1b[12;1R');
|
|
625
660
|
ctx.log('Terminal CPR request (\\x1b[6n) intercepted in PTY, responding with dummy coordinates [12;1R]');
|
|
626
661
|
}
|
|
627
662
|
checkAutoApproval(data, (s) => child.write(s));
|
|
628
663
|
sendAutoImplSSE(ctx, { event: 'output', data: { chunk: data, stream: 'stdout' } });
|
|
664
|
+
scheduleAutoStopForVerification();
|
|
629
665
|
});
|
|
630
666
|
child.onExit(({ exitCode: code }: { exitCode: number }) => {
|
|
631
667
|
void finalizeCliAutoImpl(code);
|
|
@@ -634,15 +670,19 @@ export async function handleAutoImplement(ctx: DevServerContext, type: string, r
|
|
|
634
670
|
child.stdout?.on('data', (d: Buffer) => {
|
|
635
671
|
const chunk = d.toString();
|
|
636
672
|
stdout += chunk;
|
|
673
|
+
clearAutoStopTimer();
|
|
637
674
|
if (chunk.includes('\x1b[6n')) child.stdin?.write('\x1b[1;1R');
|
|
638
675
|
checkAutoApproval(chunk, (s) => child.stdin?.write(s));
|
|
639
676
|
sendAutoImplSSE(ctx, { event: 'output', data: { chunk, stream: 'stdout' } });
|
|
677
|
+
scheduleAutoStopForVerification();
|
|
640
678
|
});
|
|
641
679
|
child.stderr?.on('data', (d: Buffer) => {
|
|
642
680
|
const chunk = d.toString();
|
|
643
681
|
stderr += chunk;
|
|
682
|
+
clearAutoStopTimer();
|
|
644
683
|
checkAutoApproval(chunk, (s) => child.stdin?.write(s));
|
|
645
684
|
sendAutoImplSSE(ctx, { event: 'output', data: { chunk, stream: 'stderr' } });
|
|
685
|
+
scheduleAutoStopForVerification();
|
|
646
686
|
});
|
|
647
687
|
child.on('exit', (code: number) => {
|
|
648
688
|
void finalizeCliAutoImpl(code);
|