@sayknow-cli/coding-agent 0.5.2 → 0.5.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/CHANGELOG.md +55 -16
- package/dist/types/cli/update-cli.d.ts +8 -1
- package/dist/types/config/atomic-yaml-patch.d.ts +20 -1
- package/dist/types/config/keybindings.d.ts +10 -0
- package/dist/types/config/model-registry.d.ts +1 -1
- package/dist/types/config/models-config-schema.d.ts +4 -0
- package/dist/types/config/settings-schema.d.ts +9 -0
- package/dist/types/dap/client.d.ts +1 -0
- package/dist/types/lsp/client.d.ts +5 -0
- package/dist/types/modes/components/welcome.d.ts +1 -0
- package/dist/types/modes/controllers/selector-controller.d.ts +3 -1
- package/dist/types/modes/interactive-mode.d.ts +13 -1
- package/dist/types/modes/types.d.ts +7 -1
- package/dist/types/runtime-mcp/transports/stdio.d.ts +2 -0
- package/dist/types/session/agent-session.d.ts +8 -0
- package/dist/types/session/internal/managed-session-scope.d.ts +3 -1
- package/dist/types/session/internal/managed-session-storage.d.ts +2 -0
- package/dist/types/session/session-manager.d.ts +9 -0
- package/dist/types/session/session-storage.d.ts +17 -0
- package/dist/types/session-import/claude.d.ts +26 -0
- package/dist/types/session-import/codex.d.ts +22 -0
- package/dist/types/session-import/command.d.ts +20 -0
- package/dist/types/session-import/detect.d.ts +22 -0
- package/dist/types/session-import/index.d.ts +7 -0
- package/dist/types/session-import/redact.d.ts +23 -0
- package/dist/types/session-import/service.d.ts +28 -0
- package/dist/types/session-import/types.d.ts +125 -0
- package/dist/types/skc-runtime/launch-worktree.d.ts +17 -1
- package/dist/types/slash-commands/builtin-registry.d.ts +4 -0
- package/dist/types/slash-commands/types.d.ts +5 -0
- package/dist/types/tools/ask.d.ts +5 -0
- package/package.json +13 -7
- package/scripts/generate-sdk-operation-inventory.ts +5 -6
- package/src/cli/config-cli.ts +23 -8
- package/src/cli/update-cli.ts +265 -21
- package/src/config/atomic-yaml-patch.ts +167 -30
- package/src/config/keybindings.ts +10 -0
- package/src/config/model-profiles.ts +69 -1
- package/src/config/model-registry.ts +60 -38
- package/src/config/models-config-schema.ts +1 -1
- package/src/config/settings-schema.ts +9 -0
- package/src/config/settings.ts +13 -2
- package/src/dap/client.ts +78 -30
- package/src/internal-urls/docs-index.generated.ts +5 -4
- package/src/lsp/client.ts +17 -29
- package/src/modes/action-registry.ts +2 -0
- package/src/modes/components/welcome.ts +5 -0
- package/src/modes/controllers/goal-mode-controller.ts +7 -2
- package/src/modes/controllers/input-controller.ts +71 -6
- package/src/modes/controllers/plan-mode-controller.ts +8 -1
- package/src/modes/controllers/runtime-mcp-command-controller.ts +14 -0
- package/src/modes/controllers/selector-controller.ts +47 -19
- package/src/modes/interactive-mode.ts +54 -4
- package/src/modes/types.ts +5 -1
- package/src/runtime-mcp/transports/stdio.ts +96 -33
- package/src/sdk/broker/lifecycle.ts +6 -5
- package/src/sdk/protocol/operation-inventory.generated.json +33 -0
- package/src/sdk/session.ts +25 -18
- package/src/session/agent-session.ts +89 -14
- package/src/session/internal/managed-session-scope.ts +41 -6
- package/src/session/internal/managed-session-storage.ts +14 -0
- package/src/session/session-manager.ts +113 -11
- package/src/session/session-storage.ts +70 -0
- package/src/session-import/claude.ts +382 -0
- package/src/session-import/codex.ts +458 -0
- package/src/session-import/command.ts +61 -0
- package/src/session-import/detect.ts +133 -0
- package/src/session-import/index.ts +27 -0
- package/src/session-import/redact.ts +125 -0
- package/src/session-import/service.ts +749 -0
- package/src/session-import/types.ts +163 -0
- package/src/skc-runtime/launch-worktree.ts +277 -4
- package/src/slash-commands/acp-builtins.ts +5 -1
- package/src/slash-commands/builtin-registry.ts +100 -1
- package/src/slash-commands/types.ts +5 -0
- package/src/tools/ask.ts +5 -0
- package/src/export/html/template.css +0 -1060
- package/src/export/html/template.html +0 -47
- package/src/export/html/template.js +0 -2348
- package/vendor/insane-search/engine/tests/test_hardening.py +0 -57
- package/vendor/insane-search/engine/tests/test_smoke.py +0 -152
- package/vendor/insane-search/engine/tests/test_u1.py +0 -200
- package/vendor/insane-search/engine/tests/test_u4.py +0 -131
- package/vendor/insane-search/engine/tests/test_u5.py +0 -163
- package/vendor/insane-search/engine/tests/test_u7.py +0 -124
- package/vendor/insane-search/engine/tests/test_u8.py +0 -216
package/src/dap/client.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { existsSync } from "node:fs";
|
|
2
2
|
import * as fs from "node:fs/promises";
|
|
3
|
-
import { logger } from "@sayknow-cli/utils";
|
|
3
|
+
import { isKnownSinkPeerClosedError, logger } from "@sayknow-cli/utils";
|
|
4
4
|
import { formatCrashDiagnosticNotice, writeCrashReport } from "../debug/crash-diagnostics";
|
|
5
5
|
import { NON_INTERACTIVE_ENV } from "../exec/non-interactive-env";
|
|
6
6
|
import { type OwnedProcess, spawnOwnedProcess } from "../runtime/process-lifecycle";
|
|
@@ -62,9 +62,9 @@ function parseMessage(
|
|
|
62
62
|
|
|
63
63
|
async function writeMessage(sink: DapWriteSink, message: DapRequestMessage | DapResponseMessage): Promise<void> {
|
|
64
64
|
const content = JSON.stringify(message);
|
|
65
|
-
|
|
66
|
-
sink.write(
|
|
67
|
-
await sink.flush();
|
|
65
|
+
const frame = `Content-Length: ${Buffer.byteLength(content, "utf-8")}\r\n\r\n${content}`;
|
|
66
|
+
await Promise.resolve(sink.write(frame));
|
|
67
|
+
await Promise.resolve(sink.flush());
|
|
68
68
|
}
|
|
69
69
|
|
|
70
70
|
function toErrorMessage(value: unknown): string {
|
|
@@ -98,6 +98,9 @@ export class DapClient {
|
|
|
98
98
|
#messageBuffer = Buffer.alloc(0);
|
|
99
99
|
#isReading = false;
|
|
100
100
|
#disposed = false;
|
|
101
|
+
#terminalError: Error | undefined;
|
|
102
|
+
#disposePromise: Promise<void> | undefined;
|
|
103
|
+
#writeQueue: Promise<void> = Promise.resolve();
|
|
101
104
|
#lastActivity = Date.now();
|
|
102
105
|
#capabilities?: DapCapabilities;
|
|
103
106
|
#eventHandlers = new Map<string, Set<DapEventHandler>>();
|
|
@@ -119,6 +122,18 @@ export class DapClient {
|
|
|
119
122
|
this.#socket = options?.socket;
|
|
120
123
|
}
|
|
121
124
|
|
|
125
|
+
#queueWriteMessage(message: DapRequestMessage | DapResponseMessage): Promise<void> {
|
|
126
|
+
const write = this.#writeQueue
|
|
127
|
+
.catch(() => {})
|
|
128
|
+
.then(() => {
|
|
129
|
+
if (this.#terminalError) throw this.#terminalError;
|
|
130
|
+
if (this.#disposed) throw new Error(`DAP adapter ${this.adapter.name} is not running`);
|
|
131
|
+
return writeMessage(this.#writeSink, message);
|
|
132
|
+
});
|
|
133
|
+
this.#writeQueue = write.catch(() => {});
|
|
134
|
+
return write;
|
|
135
|
+
}
|
|
136
|
+
|
|
122
137
|
static async spawn({ adapter, cwd }: DapSpawnOptions): Promise<DapClient> {
|
|
123
138
|
if (adapter.connectMode === "socket") {
|
|
124
139
|
return DapClient.#spawnSocket({ adapter, cwd });
|
|
@@ -142,7 +157,7 @@ export class DapClient {
|
|
|
142
157
|
proc.exited.then(() => {
|
|
143
158
|
client.#handleProcessExit();
|
|
144
159
|
});
|
|
145
|
-
void client
|
|
160
|
+
void client.startMessageReader();
|
|
146
161
|
return client;
|
|
147
162
|
}
|
|
148
163
|
|
|
@@ -199,7 +214,7 @@ export class DapClient {
|
|
|
199
214
|
transport = await connectSocket({ unix: socketPath }, 10_000);
|
|
200
215
|
const client = new DapClient(adapter, cwd, owner, transport);
|
|
201
216
|
proc.exited.then(() => client.#handleProcessExit());
|
|
202
|
-
void client
|
|
217
|
+
void client.startMessageReader();
|
|
203
218
|
return client;
|
|
204
219
|
} catch (err) {
|
|
205
220
|
transport?.socket.end();
|
|
@@ -268,7 +283,7 @@ export class DapClient {
|
|
|
268
283
|
const { readable, writeSink, socket } = wrapBunSocket(rawSocket);
|
|
269
284
|
const client = new DapClient(adapter, cwd, owner, { readable, writeSink, socket });
|
|
270
285
|
proc.exited.then(() => client.#handleProcessExit());
|
|
271
|
-
void client
|
|
286
|
+
void client.startMessageReader();
|
|
272
287
|
return client;
|
|
273
288
|
}
|
|
274
289
|
|
|
@@ -364,6 +379,7 @@ export class DapClient {
|
|
|
364
379
|
signal?: AbortSignal,
|
|
365
380
|
timeoutMs: number = DEFAULT_REQUEST_TIMEOUT_MS,
|
|
366
381
|
): Promise<TBody> {
|
|
382
|
+
if (this.#terminalError) throw this.#terminalError;
|
|
367
383
|
if (signal?.aborted) {
|
|
368
384
|
throw signal.reason instanceof Error ? signal.reason : new ToolAbortError();
|
|
369
385
|
}
|
|
@@ -412,10 +428,11 @@ export class DapClient {
|
|
|
412
428
|
});
|
|
413
429
|
this.#lastActivity = Date.now();
|
|
414
430
|
try {
|
|
415
|
-
await
|
|
431
|
+
await this.#queueWriteMessage(request);
|
|
416
432
|
} catch (error) {
|
|
417
433
|
this.#pendingRequests.delete(requestSeq);
|
|
418
434
|
cleanup();
|
|
435
|
+
if (isKnownSinkPeerClosedError(error)) throw this.#terminalizeTransport(error);
|
|
419
436
|
throw error;
|
|
420
437
|
}
|
|
421
438
|
return promise;
|
|
@@ -431,37 +448,30 @@ export class DapClient {
|
|
|
431
448
|
...(message ? { message } : {}),
|
|
432
449
|
...(body !== undefined ? { body } : {}),
|
|
433
450
|
};
|
|
434
|
-
await
|
|
451
|
+
await this.#queueWriteMessage(response);
|
|
435
452
|
}
|
|
436
453
|
|
|
437
454
|
async dispose(): Promise<void> {
|
|
438
|
-
if (this.#disposed)
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
this.#
|
|
443
|
-
} catch {
|
|
444
|
-
/* socket may already be closed */
|
|
445
|
-
}
|
|
446
|
-
try {
|
|
447
|
-
await this.#owner.dispose();
|
|
448
|
-
await this.#owner.awaitExit({ timeoutMs: 1_000 });
|
|
449
|
-
} catch (error) {
|
|
450
|
-
logger.debug("Failed to dispose DAP adapter", {
|
|
451
|
-
adapter: this.adapter.name,
|
|
452
|
-
error: toErrorMessage(error),
|
|
453
|
-
});
|
|
455
|
+
if (!this.#disposed) {
|
|
456
|
+
const error = new Error(`DAP adapter ${this.adapter.name} disposed`);
|
|
457
|
+
this.#disposed = true;
|
|
458
|
+
this.#terminalError = error;
|
|
459
|
+
this.#rejectPendingRequests(error);
|
|
454
460
|
}
|
|
461
|
+
await this.#beginOwnerDisposal();
|
|
455
462
|
}
|
|
456
463
|
|
|
457
|
-
async
|
|
464
|
+
async startMessageReader(): Promise<void> {
|
|
458
465
|
if (this.#isReading) return;
|
|
459
466
|
this.#isReading = true;
|
|
460
467
|
const reader = this.#readable.getReader();
|
|
461
468
|
try {
|
|
462
469
|
while (true) {
|
|
463
470
|
const { done, value } = await reader.read();
|
|
464
|
-
if (done)
|
|
471
|
+
if (done) {
|
|
472
|
+
this.#terminalizeTransport(new Error("DAP readable closed"));
|
|
473
|
+
break;
|
|
474
|
+
}
|
|
465
475
|
const currentBuffer = Buffer.concat([this.#messageBuffer, value]);
|
|
466
476
|
this.#messageBuffer = currentBuffer;
|
|
467
477
|
let workingBuffer = currentBuffer;
|
|
@@ -482,7 +492,7 @@ export class DapClient {
|
|
|
482
492
|
this.#messageBuffer = workingBuffer;
|
|
483
493
|
}
|
|
484
494
|
} catch (error) {
|
|
485
|
-
this.#
|
|
495
|
+
this.#terminalizeTransport(error);
|
|
486
496
|
} finally {
|
|
487
497
|
reader.releaseLock();
|
|
488
498
|
this.#isReading = false;
|
|
@@ -523,9 +533,9 @@ export class DapClient {
|
|
|
523
533
|
try {
|
|
524
534
|
const handler = this.#reverseRequestHandlers.get(message.command);
|
|
525
535
|
if (handler) {
|
|
536
|
+
let body: unknown;
|
|
526
537
|
try {
|
|
527
|
-
|
|
528
|
-
await this.sendResponse(message, true, body);
|
|
538
|
+
body = await handler(message.arguments);
|
|
529
539
|
} catch (error) {
|
|
530
540
|
const errorMessage = toErrorMessage(error);
|
|
531
541
|
await this.sendResponse(
|
|
@@ -539,7 +549,9 @@ export class DapClient {
|
|
|
539
549
|
},
|
|
540
550
|
errorMessage,
|
|
541
551
|
);
|
|
552
|
+
return;
|
|
542
553
|
}
|
|
554
|
+
await this.sendResponse(message, true, body);
|
|
543
555
|
return;
|
|
544
556
|
}
|
|
545
557
|
const errorMessage = `Unsupported DAP request: ${message.command}`;
|
|
@@ -555,6 +567,10 @@ export class DapClient {
|
|
|
555
567
|
errorMessage,
|
|
556
568
|
);
|
|
557
569
|
} catch (error) {
|
|
570
|
+
if (isKnownSinkPeerClosedError(error)) {
|
|
571
|
+
this.#terminalizeTransport(error);
|
|
572
|
+
return;
|
|
573
|
+
}
|
|
558
574
|
logger.warn("Failed to answer DAP adapter request", {
|
|
559
575
|
adapter: this.adapter.name,
|
|
560
576
|
command: message.command,
|
|
@@ -586,9 +602,41 @@ export class DapClient {
|
|
|
586
602
|
? `DAP adapter exited (code ${exitCode}): ${stderr}${diagnosticSuffix}`
|
|
587
603
|
: `DAP adapter exited unexpectedly (code ${exitCode})${diagnosticSuffix}`,
|
|
588
604
|
);
|
|
605
|
+
this.#terminalError = error;
|
|
589
606
|
this.#rejectPendingRequests(error);
|
|
590
607
|
}
|
|
591
608
|
|
|
609
|
+
#terminalizeTransport(cause: unknown): Error {
|
|
610
|
+
if (this.#terminalError) return this.#terminalError;
|
|
611
|
+
const error = new Error(`DAP adapter ${this.adapter.name} transport closed`, { cause });
|
|
612
|
+
this.#terminalError = error;
|
|
613
|
+
this.#disposed = true;
|
|
614
|
+
this.#rejectPendingRequests(error);
|
|
615
|
+
void this.#beginOwnerDisposal();
|
|
616
|
+
return error;
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
#beginOwnerDisposal(): Promise<void> {
|
|
620
|
+
if (this.#disposePromise) return this.#disposePromise;
|
|
621
|
+
this.#disposePromise = (async () => {
|
|
622
|
+
try {
|
|
623
|
+
this.#socket?.end();
|
|
624
|
+
} catch {
|
|
625
|
+
/* socket may already be closed */
|
|
626
|
+
}
|
|
627
|
+
try {
|
|
628
|
+
await this.#owner.dispose();
|
|
629
|
+
await this.#owner.awaitExit({ timeoutMs: 1_000 });
|
|
630
|
+
} catch (disposeError) {
|
|
631
|
+
logger.debug("Failed to dispose DAP adapter", {
|
|
632
|
+
adapter: this.adapter.name,
|
|
633
|
+
error: toErrorMessage(disposeError),
|
|
634
|
+
});
|
|
635
|
+
}
|
|
636
|
+
})();
|
|
637
|
+
return this.#disposePromise;
|
|
638
|
+
}
|
|
639
|
+
|
|
592
640
|
#rejectPendingRequests(error: Error): void {
|
|
593
641
|
for (const pending of this.#pendingRequests.values()) {
|
|
594
642
|
pending.reject(error);
|