@adhdev/daemon-core 0.9.54 → 0.9.56
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/boot/daemon-lifecycle.d.ts +5 -0
- package/dist/cli-adapters/provider-cli-adapter.d.ts +9 -0
- package/dist/cli-adapters/provider-cli-config.d.ts +1 -0
- package/dist/cli-adapters/provider-cli-shared.d.ts +24 -0
- package/dist/commands/handler.d.ts +5 -0
- package/dist/git/git-commands.d.ts +53 -0
- package/dist/git/git-types.d.ts +1 -1
- package/dist/git/index.d.ts +2 -0
- package/dist/git/turn-snapshot-tracker.d.ts +16 -0
- package/dist/index.js +249 -18
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +248 -18
- package/dist/index.mjs.map +1 -1
- package/dist/providers/contracts.d.ts +2 -0
- package/node_modules/@adhdev/session-host-core/package.json +1 -1
- package/package.json +1 -1
- package/src/boot/daemon-lifecycle.ts +6 -0
- package/src/cli-adapters/provider-cli-adapter.ts +62 -4
- package/src/cli-adapters/provider-cli-config.d.ts +1 -0
- package/src/cli-adapters/provider-cli-config.ts +2 -0
- package/src/cli-adapters/provider-cli-shared.d.ts +2 -0
- package/src/cli-adapters/provider-cli-shared.ts +8 -0
- package/src/commands/handler.ts +16 -0
- package/src/git/git-commands.ts +209 -12
- package/src/git/git-types.ts +2 -1
- package/src/git/index.ts +3 -0
- package/src/git/turn-snapshot-tracker.ts +31 -0
- package/src/providers/contracts.d.ts +8 -0
- package/src/providers/contracts.ts +2 -0
- package/src/providers/provider-schema.ts +1 -0
package/dist/index.mjs
CHANGED
|
@@ -1940,6 +1940,7 @@ function resolveCliAdapterConfig(provider) {
|
|
|
1940
1940
|
sendDelayMs: typeof provider.sendDelayMs === "number" ? Math.max(0, provider.sendDelayMs) : 0,
|
|
1941
1941
|
sendKey: typeof provider.sendKey === "string" && provider.sendKey.length > 0 ? provider.sendKey : "\r",
|
|
1942
1942
|
submitStrategy: provider.submitStrategy === "immediate" ? "immediate" : "wait_for_echo",
|
|
1943
|
+
requirePromptEchoBeforeSubmit: provider.requirePromptEchoBeforeSubmit === true,
|
|
1943
1944
|
providerResolutionMeta: {
|
|
1944
1945
|
type: provider.type,
|
|
1945
1946
|
name: provider.name,
|
|
@@ -2204,6 +2205,7 @@ var init_provider_cli_adapter = __esm({
|
|
|
2204
2205
|
this.sendDelayMs = resolvedConfig.sendDelayMs;
|
|
2205
2206
|
this.sendKey = resolvedConfig.sendKey;
|
|
2206
2207
|
this.submitStrategy = resolvedConfig.submitStrategy;
|
|
2208
|
+
this.requirePromptEchoBeforeSubmit = resolvedConfig.requirePromptEchoBeforeSubmit;
|
|
2207
2209
|
this.providerResolutionMeta = resolvedConfig.providerResolutionMeta;
|
|
2208
2210
|
this.cliScripts = provider.scripts || {};
|
|
2209
2211
|
const scriptNames = listCliScriptNames(this.cliScripts);
|
|
@@ -2300,6 +2302,12 @@ var init_provider_cli_adapter = __esm({
|
|
|
2300
2302
|
accumulatedRawBuffer = "";
|
|
2301
2303
|
/** Current visible terminal screen snapshot */
|
|
2302
2304
|
terminalScreen = new TerminalScreen(24, 80);
|
|
2305
|
+
static MAX_RESPONSE_BUFFER = 8e3;
|
|
2306
|
+
static MAX_RECENT_OUTPUT_BUFFER = 1e3;
|
|
2307
|
+
responseBufferDroppedChars = 0;
|
|
2308
|
+
recentOutputDroppedChars = 0;
|
|
2309
|
+
accumulatedBufferDroppedChars = 0;
|
|
2310
|
+
accumulatedRawBufferDroppedChars = 0;
|
|
2303
2311
|
/** Max accumulated buffer size. Sized to comfortably hold a single long
|
|
2304
2312
|
* Hermes turn (tool calls + reasoning + final bubble) without the
|
|
2305
2313
|
* rolling window pushing the turn's ╭─ opening line out of view. */
|
|
@@ -2317,6 +2325,23 @@ var init_provider_cli_adapter = __esm({
|
|
|
2317
2325
|
providerResolutionMeta;
|
|
2318
2326
|
static FINISH_RETRY_DELAY_MS = 300;
|
|
2319
2327
|
static MAX_FINISH_RETRIES = 2;
|
|
2328
|
+
getBufferState() {
|
|
2329
|
+
const build = (droppedChars, maxChars) => droppedChars > 0 ? { truncated: true, droppedChars, maxChars } : void 0;
|
|
2330
|
+
const responseBuffer = build(this.responseBufferDroppedChars, _ProviderCliAdapter.MAX_RESPONSE_BUFFER);
|
|
2331
|
+
const recentOutputBuffer = build(this.recentOutputDroppedChars, _ProviderCliAdapter.MAX_RECENT_OUTPUT_BUFFER);
|
|
2332
|
+
const accumulatedBuffer = build(this.accumulatedBufferDroppedChars, _ProviderCliAdapter.MAX_ACCUMULATED_BUFFER);
|
|
2333
|
+
const accumulatedRawBuffer = build(this.accumulatedRawBufferDroppedChars, _ProviderCliAdapter.MAX_ACCUMULATED_BUFFER);
|
|
2334
|
+
if (!responseBuffer && !recentOutputBuffer && !accumulatedBuffer && !accumulatedRawBuffer) return void 0;
|
|
2335
|
+
return {
|
|
2336
|
+
...responseBuffer ? { responseBuffer } : {},
|
|
2337
|
+
...recentOutputBuffer ? { recentOutputBuffer } : {},
|
|
2338
|
+
...accumulatedBuffer ? { accumulatedBuffer } : {},
|
|
2339
|
+
...accumulatedRawBuffer ? { accumulatedRawBuffer } : {}
|
|
2340
|
+
};
|
|
2341
|
+
}
|
|
2342
|
+
recordBoundedAppendDrop(previousLength, appendedLength, nextLength) {
|
|
2343
|
+
return Math.max(0, previousLength + appendedLength - nextLength);
|
|
2344
|
+
}
|
|
2320
2345
|
buildCommittedMessagesActivitySignature() {
|
|
2321
2346
|
const last = this.committedMessages[this.committedMessages.length - 1];
|
|
2322
2347
|
return [
|
|
@@ -2500,6 +2525,7 @@ var init_provider_cli_adapter = __esm({
|
|
|
2500
2525
|
sendDelayMs;
|
|
2501
2526
|
sendKey;
|
|
2502
2527
|
submitStrategy;
|
|
2528
|
+
requirePromptEchoBeforeSubmit;
|
|
2503
2529
|
static SCRIPT_STATUS_DEBOUNCE_MS = 3e3;
|
|
2504
2530
|
/** Inject CLI scripts after construction (e.g. when resolved by ProviderLoader) */
|
|
2505
2531
|
setCliScripts(scripts) {
|
|
@@ -2681,7 +2707,9 @@ var init_provider_cli_adapter = __esm({
|
|
|
2681
2707
|
this.scheduleStartupSettleCheck();
|
|
2682
2708
|
}
|
|
2683
2709
|
if (this.isWaitingForResponse && cleanData) {
|
|
2684
|
-
|
|
2710
|
+
const previousResponseLen = this.responseBuffer.length;
|
|
2711
|
+
this.responseBuffer = appendBoundedText(this.responseBuffer, cleanData, _ProviderCliAdapter.MAX_RESPONSE_BUFFER);
|
|
2712
|
+
this.responseBufferDroppedChars += this.recordBoundedAppendDrop(previousResponseLen, cleanData.length, this.responseBuffer.length);
|
|
2685
2713
|
}
|
|
2686
2714
|
if (cleanData.trim()) {
|
|
2687
2715
|
if (this.serverConn) {
|
|
@@ -2690,14 +2718,19 @@ var init_provider_cli_adapter = __esm({
|
|
|
2690
2718
|
this.logBuffer.push({ message: cleanData.trim(), level: "info" });
|
|
2691
2719
|
}
|
|
2692
2720
|
}
|
|
2721
|
+
const prevRecentLen = this.recentOutputBuffer.length;
|
|
2693
2722
|
const prevAccumulatedLen = this.accumulatedBuffer.length;
|
|
2694
2723
|
const prevAccumulatedRawLen = this.accumulatedRawBuffer.length;
|
|
2695
|
-
this.recentOutputBuffer = appendBoundedText(this.recentOutputBuffer, cleanData,
|
|
2724
|
+
this.recentOutputBuffer = appendBoundedText(this.recentOutputBuffer, cleanData, _ProviderCliAdapter.MAX_RECENT_OUTPUT_BUFFER);
|
|
2696
2725
|
this.accumulatedBuffer = appendBoundedText(this.accumulatedBuffer, cleanData, _ProviderCliAdapter.MAX_ACCUMULATED_BUFFER);
|
|
2697
2726
|
this.accumulatedRawBuffer = appendBoundedText(this.accumulatedRawBuffer, rawData, _ProviderCliAdapter.MAX_ACCUMULATED_BUFFER);
|
|
2727
|
+
const droppedRecent = this.recordBoundedAppendDrop(prevRecentLen, cleanData.length, this.recentOutputBuffer.length);
|
|
2728
|
+
const droppedClean = this.recordBoundedAppendDrop(prevAccumulatedLen, cleanData.length, this.accumulatedBuffer.length);
|
|
2729
|
+
const droppedRaw = this.recordBoundedAppendDrop(prevAccumulatedRawLen, rawData.length, this.accumulatedRawBuffer.length);
|
|
2730
|
+
this.recentOutputDroppedChars += droppedRecent;
|
|
2731
|
+
this.accumulatedBufferDroppedChars += droppedClean;
|
|
2732
|
+
this.accumulatedRawBufferDroppedChars += droppedRaw;
|
|
2698
2733
|
if (this.currentTurnScope) {
|
|
2699
|
-
const droppedClean = prevAccumulatedLen + cleanData.length - this.accumulatedBuffer.length;
|
|
2700
|
-
const droppedRaw = prevAccumulatedRawLen + rawData.length - this.accumulatedRawBuffer.length;
|
|
2701
2734
|
if (droppedClean > 0) {
|
|
2702
2735
|
this.currentTurnScope.bufferStart = Math.max(0, this.currentTurnScope.bufferStart - droppedClean);
|
|
2703
2736
|
}
|
|
@@ -3527,13 +3560,15 @@ var init_provider_cli_adapter = __esm({
|
|
|
3527
3560
|
effectiveModal = parsedModal;
|
|
3528
3561
|
}
|
|
3529
3562
|
}
|
|
3563
|
+
const bufferState = this.getBufferState();
|
|
3530
3564
|
return {
|
|
3531
3565
|
status: effectiveStatus,
|
|
3532
3566
|
messages: [...this.committedMessages],
|
|
3533
3567
|
workingDir: this.workingDir,
|
|
3534
3568
|
activeModal: effectiveModal,
|
|
3535
3569
|
errorMessage: this.parseErrorMessage || void 0,
|
|
3536
|
-
errorReason: this.parseErrorMessage ? "parse_error" : void 0
|
|
3570
|
+
errorReason: this.parseErrorMessage ? "parse_error" : void 0,
|
|
3571
|
+
...bufferState ? { bufferState } : {}
|
|
3537
3572
|
};
|
|
3538
3573
|
}
|
|
3539
3574
|
seedCommittedMessages(messages) {
|
|
@@ -3715,10 +3750,12 @@ var init_provider_cli_adapter = __esm({
|
|
|
3715
3750
|
messages: hydratedMessages,
|
|
3716
3751
|
activeModal: parsed.activeModal ?? this.activeModal,
|
|
3717
3752
|
providerSessionId: typeof parsed.providerSessionId === "string" ? parsed.providerSessionId : void 0,
|
|
3753
|
+
...this.getBufferState() ? { bufferState: this.getBufferState() } : {},
|
|
3718
3754
|
...this.providerOwnsTranscript() ? { transcriptAuthority: "provider", coverage: this.shouldUseFullProviderTranscriptContext() ? "full" : "tail" } : {}
|
|
3719
3755
|
};
|
|
3720
3756
|
} else {
|
|
3721
3757
|
const messages = [...this.committedMessages];
|
|
3758
|
+
const bufferState = this.getBufferState();
|
|
3722
3759
|
result = {
|
|
3723
3760
|
id: "cli_session",
|
|
3724
3761
|
status: this.currentStatus,
|
|
@@ -3729,7 +3766,8 @@ var init_provider_cli_adapter = __esm({
|
|
|
3729
3766
|
index: typeof message.index === "number" ? message.index : index,
|
|
3730
3767
|
receivedAt: typeof message.receivedAt === "number" ? message.receivedAt : message.timestamp
|
|
3731
3768
|
})),
|
|
3732
|
-
activeModal: this.activeModal
|
|
3769
|
+
activeModal: this.activeModal,
|
|
3770
|
+
...bufferState ? { bufferState } : {}
|
|
3733
3771
|
};
|
|
3734
3772
|
}
|
|
3735
3773
|
const hasVisibleAssistantMessage = Array.isArray(result?.messages) && result.messages.some((message) => message?.role === "assistant" && typeof message?.content === "string" && message.content.trim());
|
|
@@ -4020,6 +4058,22 @@ var init_provider_cli_adapter = __esm({
|
|
|
4020
4058
|
}
|
|
4021
4059
|
}
|
|
4022
4060
|
if (elapsed >= state.maxEchoWaitMs) {
|
|
4061
|
+
const diagnostic = {
|
|
4062
|
+
elapsed,
|
|
4063
|
+
maxEchoWaitMs: state.maxEchoWaitMs,
|
|
4064
|
+
submitDelayMs: state.submitDelayMs,
|
|
4065
|
+
promptSnippet: state.normalizedPromptSnippet,
|
|
4066
|
+
requirePromptEchoBeforeSubmit: this.requirePromptEchoBeforeSubmit,
|
|
4067
|
+
screenText: summarizeCliTraceText(screenText, 1e3)
|
|
4068
|
+
};
|
|
4069
|
+
this.recordTrace("submit_echo_missing", diagnostic);
|
|
4070
|
+
if (this.requirePromptEchoBeforeSubmit) {
|
|
4071
|
+
const message = `${this.cliName} prompt echo was not observed on the PTY screen before submit`;
|
|
4072
|
+
LOG.warn("CLI", `[${this.cliType}] ${message} elapsed=${elapsed}ms maxEchoWaitMs=${state.maxEchoWaitMs} screen=${JSON.stringify(diagnostic.screenText).slice(0, 240)}`);
|
|
4073
|
+
completion.rejectOnce(new Error(message));
|
|
4074
|
+
return;
|
|
4075
|
+
}
|
|
4076
|
+
LOG.warn("CLI", `[${this.cliType}] prompt echo was not observed before submit; sending submit key anyway elapsed=${elapsed}ms maxEchoWaitMs=${state.maxEchoWaitMs}`);
|
|
4023
4077
|
this.submitSendKey(state, completion);
|
|
4024
4078
|
return;
|
|
4025
4079
|
}
|
|
@@ -4484,6 +4538,7 @@ var init_provider_cli_adapter = __esm({
|
|
|
4484
4538
|
sendDelayMs: this.sendDelayMs,
|
|
4485
4539
|
sendKey: this.sendKey,
|
|
4486
4540
|
submitStrategy: this.submitStrategy,
|
|
4541
|
+
requirePromptEchoBeforeSubmit: this.requirePromptEchoBeforeSubmit,
|
|
4487
4542
|
submitPendingUntil: this.submitPendingUntil,
|
|
4488
4543
|
responseSettleIgnoreUntil: this.responseSettleIgnoreUntil,
|
|
4489
4544
|
resizeSuppressUntil: this.resizeSuppressUntil,
|
|
@@ -5406,13 +5461,8 @@ var GIT_COMMAND_NAMES = /* @__PURE__ */ new Set([
|
|
|
5406
5461
|
"git_checkpoint",
|
|
5407
5462
|
"git_stash_push",
|
|
5408
5463
|
"git_stash_pop",
|
|
5409
|
-
"git_checkout_files"
|
|
5410
|
-
|
|
5411
|
-
var MUTATING_COMMAND_NAMES = /* @__PURE__ */ new Set([
|
|
5412
|
-
"git_checkpoint",
|
|
5413
|
-
"git_stash_push",
|
|
5414
|
-
"git_stash_pop",
|
|
5415
|
-
"git_checkout_files"
|
|
5464
|
+
"git_checkout_files",
|
|
5465
|
+
"git_remote_url"
|
|
5416
5466
|
]);
|
|
5417
5467
|
var SNAPSHOT_REASONS = /* @__PURE__ */ new Set([
|
|
5418
5468
|
"session_baseline",
|
|
@@ -5453,7 +5503,12 @@ function createDefaultGitCommandServices() {
|
|
|
5453
5503
|
turnId
|
|
5454
5504
|
}),
|
|
5455
5505
|
compareSnapshots: ({ beforeSnapshotId, afterSnapshotId }) => defaultSnapshotStore.compare(beforeSnapshotId, afterSnapshotId),
|
|
5456
|
-
getLog: ({ workspace, limit, path: filePath, since, until }) => getGitLog(workspace, { limit, path: filePath, since, until })
|
|
5506
|
+
getLog: ({ workspace, limit, path: filePath, since, until }) => getGitLog(workspace, { limit, path: filePath, since, until }),
|
|
5507
|
+
checkpoint: async ({ workspace, message, includeUntracked = false }) => gitCheckpoint(workspace, message, includeUntracked),
|
|
5508
|
+
stashPush: async ({ workspace, message, includeUntracked = false }) => gitStashPush(workspace, message, includeUntracked),
|
|
5509
|
+
stashPop: async ({ workspace, stashRef }) => gitStashPop(workspace, stashRef),
|
|
5510
|
+
checkoutFiles: async ({ workspace, paths }) => gitCheckoutFiles(workspace, paths),
|
|
5511
|
+
getRemoteUrl: async ({ workspace, remote = "origin" }) => gitGetRemoteUrl(workspace, remote)
|
|
5457
5512
|
};
|
|
5458
5513
|
}
|
|
5459
5514
|
var defaultGitCommandServices = createDefaultGitCommandServices();
|
|
@@ -5517,9 +5572,6 @@ async function handleGitCommand(command, args, services = defaultGitCommandServi
|
|
|
5517
5572
|
if (!isGitCommandName(command)) {
|
|
5518
5573
|
return failure("invalid_args", `Unknown Git command: ${command}`);
|
|
5519
5574
|
}
|
|
5520
|
-
if (MUTATING_COMMAND_NAMES.has(command)) {
|
|
5521
|
-
return failure("invalid_args", `${command} is not implemented in daemon-core read-only Git routing`);
|
|
5522
|
-
}
|
|
5523
5575
|
const workspaceResult = validateWorkspace2(args);
|
|
5524
5576
|
if ("success" in workspaceResult) return workspaceResult;
|
|
5525
5577
|
const { workspace } = workspaceResult;
|
|
@@ -5579,10 +5631,153 @@ async function handleGitCommand(command, args, services = defaultGitCommandServi
|
|
|
5579
5631
|
}));
|
|
5580
5632
|
return "success" in log ? log : { success: true, log };
|
|
5581
5633
|
}
|
|
5634
|
+
case "git_checkpoint": {
|
|
5635
|
+
if (!services.checkpoint) return serviceNotImplemented(command);
|
|
5636
|
+
const msg = validateMutatingMessage(args?.message);
|
|
5637
|
+
if (typeof msg !== "string") return msg;
|
|
5638
|
+
const includeUntracked = Boolean(args?.includeUntracked);
|
|
5639
|
+
const checkpoint = await runService(() => services.checkpoint({ workspace, message: msg, includeUntracked }));
|
|
5640
|
+
return "success" in checkpoint ? checkpoint : { success: true, checkpoint };
|
|
5641
|
+
}
|
|
5642
|
+
case "git_stash_push": {
|
|
5643
|
+
if (!services.stashPush) return serviceNotImplemented(command);
|
|
5644
|
+
const msg = validateMutatingMessage(args?.message);
|
|
5645
|
+
if (typeof msg !== "string") return msg;
|
|
5646
|
+
const includeUntracked = Boolean(args?.includeUntracked);
|
|
5647
|
+
const stash = await runService(() => services.stashPush({ workspace, message: msg, includeUntracked }));
|
|
5648
|
+
return "success" in stash ? stash : { success: true, stash };
|
|
5649
|
+
}
|
|
5650
|
+
case "git_stash_pop": {
|
|
5651
|
+
if (!services.stashPop) return serviceNotImplemented(command);
|
|
5652
|
+
const stashRef = optionalString(args?.stashRef);
|
|
5653
|
+
if (stashRef !== void 0 && !/^stash@\{\d+\}$/.test(stashRef)) {
|
|
5654
|
+
return failure("invalid_args", "stashRef must match stash@{N} format");
|
|
5655
|
+
}
|
|
5656
|
+
const popResult = await runService(() => services.stashPop({ workspace, stashRef }));
|
|
5657
|
+
if (popResult !== void 0 && "success" in popResult) return popResult;
|
|
5658
|
+
return { success: true, stashPopped: true };
|
|
5659
|
+
}
|
|
5660
|
+
case "git_checkout_files": {
|
|
5661
|
+
if (!services.checkoutFiles) return serviceNotImplemented(command);
|
|
5662
|
+
const paths = args?.paths;
|
|
5663
|
+
if (!Array.isArray(paths) || paths.length === 0) {
|
|
5664
|
+
return failure("invalid_args", "paths must be a non-empty array");
|
|
5665
|
+
}
|
|
5666
|
+
if (paths.length > 50) {
|
|
5667
|
+
return failure("invalid_args", "paths array exceeds maximum of 50 entries");
|
|
5668
|
+
}
|
|
5669
|
+
const checkoutResult = await runService(() => services.checkoutFiles({ workspace, paths }));
|
|
5670
|
+
return "success" in checkoutResult ? checkoutResult : { success: true, checkedOut: checkoutResult.checkedOut };
|
|
5671
|
+
}
|
|
5672
|
+
case "git_remote_url": {
|
|
5673
|
+
if (!services.getRemoteUrl) return serviceNotImplemented(command);
|
|
5674
|
+
const remote = typeof args?.remote === "string" && args.remote.trim() ? args.remote.trim() : "origin";
|
|
5675
|
+
const remoteResult = await runService(() => services.getRemoteUrl({ workspace, remote }));
|
|
5676
|
+
if ("success" in remoteResult) return remoteResult;
|
|
5677
|
+
return { success: true, remoteUrl: remoteResult.remoteUrl, remote: remoteResult.remote };
|
|
5678
|
+
}
|
|
5582
5679
|
default:
|
|
5583
5680
|
return failure("invalid_args", `Unknown Git command: ${command}`);
|
|
5584
5681
|
}
|
|
5585
5682
|
}
|
|
5683
|
+
function validateMutatingMessage(value) {
|
|
5684
|
+
if (typeof value !== "string" || !value.trim()) {
|
|
5685
|
+
return failure("invalid_args", "message must be a non-empty string");
|
|
5686
|
+
}
|
|
5687
|
+
const msg = value.trim();
|
|
5688
|
+
if (msg.length > 200) {
|
|
5689
|
+
return failure("invalid_args", "message must be 200 characters or fewer");
|
|
5690
|
+
}
|
|
5691
|
+
return msg;
|
|
5692
|
+
}
|
|
5693
|
+
async function gitCheckpoint(workspace, message, includeUntracked) {
|
|
5694
|
+
const repo = await resolveGitRepository(workspace);
|
|
5695
|
+
const repoRoot = repo.repoRoot;
|
|
5696
|
+
const statusResult = await getGitRepoStatus(workspace);
|
|
5697
|
+
if (statusResult.hasConflicts) {
|
|
5698
|
+
throw new GitCommandError("conflict", "Repository has conflicts \u2014 resolve before checkpointing");
|
|
5699
|
+
}
|
|
5700
|
+
const addArgs = includeUntracked ? ["-A"] : ["-u"];
|
|
5701
|
+
await runGit(repo, ["add", ...addArgs], { cwd: repoRoot });
|
|
5702
|
+
const fullMsg = `adhdev: checkpoint ${message}`;
|
|
5703
|
+
let commitSha;
|
|
5704
|
+
try {
|
|
5705
|
+
await runGit(repo, ["commit", "-m", fullMsg], { cwd: repoRoot });
|
|
5706
|
+
const revResult = await runGit(repo, ["rev-parse", "HEAD"], { cwd: repoRoot });
|
|
5707
|
+
commitSha = revResult.stdout.trim();
|
|
5708
|
+
} catch (err) {
|
|
5709
|
+
const output = (err?.stdout || "") + (err?.stderr || "");
|
|
5710
|
+
if (/nothing to commit/i.test(output)) {
|
|
5711
|
+
throw new GitCommandError("git_command_failed", "Nothing to commit");
|
|
5712
|
+
}
|
|
5713
|
+
throw err;
|
|
5714
|
+
}
|
|
5715
|
+
return {
|
|
5716
|
+
workspace: repo.workspace,
|
|
5717
|
+
repoRoot,
|
|
5718
|
+
isGitRepo: true,
|
|
5719
|
+
commit: commitSha,
|
|
5720
|
+
message: fullMsg,
|
|
5721
|
+
lastCheckedAt: Date.now()
|
|
5722
|
+
};
|
|
5723
|
+
}
|
|
5724
|
+
async function gitStashPush(workspace, message, includeUntracked) {
|
|
5725
|
+
const repo = await resolveGitRepository(workspace);
|
|
5726
|
+
const repoRoot = repo.repoRoot;
|
|
5727
|
+
const stashArgs = ["stash", "push", "-m", message];
|
|
5728
|
+
if (includeUntracked) stashArgs.push("--include-untracked");
|
|
5729
|
+
const result = await runGit(repo, stashArgs, { cwd: repoRoot });
|
|
5730
|
+
if (/No local changes to save/i.test(result.stdout + result.stderr)) {
|
|
5731
|
+
throw new GitCommandError("git_command_failed", "Nothing to stash");
|
|
5732
|
+
}
|
|
5733
|
+
return {
|
|
5734
|
+
workspace: repo.workspace,
|
|
5735
|
+
repoRoot,
|
|
5736
|
+
isGitRepo: true,
|
|
5737
|
+
stashRef: "stash@{0}",
|
|
5738
|
+
message,
|
|
5739
|
+
lastCheckedAt: Date.now()
|
|
5740
|
+
};
|
|
5741
|
+
}
|
|
5742
|
+
async function gitStashPop(workspace, stashRef) {
|
|
5743
|
+
const repo = await resolveGitRepository(workspace);
|
|
5744
|
+
const repoRoot = repo.repoRoot;
|
|
5745
|
+
const popArgs = stashRef ? ["stash", "pop", stashRef] : ["stash", "pop"];
|
|
5746
|
+
await runGit(repo, popArgs, { cwd: repoRoot });
|
|
5747
|
+
}
|
|
5748
|
+
async function gitCheckoutFiles(workspace, paths) {
|
|
5749
|
+
const repo = await resolveGitRepository(workspace);
|
|
5750
|
+
const repoRoot = repo.repoRoot;
|
|
5751
|
+
const normalizedPaths = [];
|
|
5752
|
+
for (const p of paths) {
|
|
5753
|
+
if (typeof p !== "string" || !p.trim() || p.includes("\0")) {
|
|
5754
|
+
throw new GitCommandError("invalid_args", `Invalid path: ${String(p)}`);
|
|
5755
|
+
}
|
|
5756
|
+
if (path3.isAbsolute(p)) {
|
|
5757
|
+
throw new GitCommandError("invalid_args", `Path must be repository-relative, not absolute: ${p}`);
|
|
5758
|
+
}
|
|
5759
|
+
const normalized = path3.normalize(p.trim()).split(path3.sep).join("/");
|
|
5760
|
+
if (normalized.startsWith("../") || normalized === "..") {
|
|
5761
|
+
throw new GitCommandError("path_outside_repo", `Path is outside repository root: ${p}`);
|
|
5762
|
+
}
|
|
5763
|
+
const absolutePath = path3.resolve(repoRoot, normalized);
|
|
5764
|
+
if (!isPathInside(repoRoot, absolutePath)) {
|
|
5765
|
+
throw new GitCommandError("path_outside_repo", `Path is outside repository root: ${p}`);
|
|
5766
|
+
}
|
|
5767
|
+
normalizedPaths.push(normalized);
|
|
5768
|
+
}
|
|
5769
|
+
await runGit(repo, ["checkout", "--", ...normalizedPaths], { cwd: repoRoot });
|
|
5770
|
+
return { checkedOut: normalizedPaths };
|
|
5771
|
+
}
|
|
5772
|
+
async function gitGetRemoteUrl(workspace, remote) {
|
|
5773
|
+
const repo = await resolveGitRepository(workspace);
|
|
5774
|
+
const result = await runGit(repo, ["remote", "get-url", remote], { cwd: repo.repoRoot });
|
|
5775
|
+
const remoteUrl = result.stdout.trim();
|
|
5776
|
+
if (!remoteUrl) {
|
|
5777
|
+
throw new GitCommandError("git_command_failed", `Remote '${remote}' has no URL`);
|
|
5778
|
+
}
|
|
5779
|
+
return { remoteUrl, remote };
|
|
5780
|
+
}
|
|
5586
5781
|
function formatOptionalGitLogRangeArg(flag, value) {
|
|
5587
5782
|
return value ? [`${flag}=${value}`] : [];
|
|
5588
5783
|
}
|
|
@@ -5641,6 +5836,27 @@ function validateGitLogPath(repoRoot, filePath) {
|
|
|
5641
5836
|
return normalized;
|
|
5642
5837
|
}
|
|
5643
5838
|
|
|
5839
|
+
// src/git/turn-snapshot-tracker.ts
|
|
5840
|
+
var BUSY_STATUSES = /* @__PURE__ */ new Set(["streaming", "waiting_approval"]);
|
|
5841
|
+
var TERMINAL_STATUSES = /* @__PURE__ */ new Set(["idle", "error"]);
|
|
5842
|
+
var TurnSnapshotTracker = class {
|
|
5843
|
+
lastStatus = /* @__PURE__ */ new Map();
|
|
5844
|
+
onTurnCompleted;
|
|
5845
|
+
constructor(onTurnCompleted) {
|
|
5846
|
+
this.onTurnCompleted = onTurnCompleted;
|
|
5847
|
+
}
|
|
5848
|
+
record(sessionId, status, workspace) {
|
|
5849
|
+
const prev = this.lastStatus.get(sessionId);
|
|
5850
|
+
this.lastStatus.set(sessionId, status);
|
|
5851
|
+
if (workspace && prev && BUSY_STATUSES.has(prev) && TERMINAL_STATUSES.has(status)) {
|
|
5852
|
+
this.onTurnCompleted({ sessionId, workspace });
|
|
5853
|
+
}
|
|
5854
|
+
}
|
|
5855
|
+
forget(sessionId) {
|
|
5856
|
+
this.lastStatus.delete(sessionId);
|
|
5857
|
+
}
|
|
5858
|
+
};
|
|
5859
|
+
|
|
5644
5860
|
// src/index.ts
|
|
5645
5861
|
init_config();
|
|
5646
5862
|
|
|
@@ -14528,6 +14744,16 @@ var DaemonCommandHandler = class {
|
|
|
14528
14744
|
return result;
|
|
14529
14745
|
}
|
|
14530
14746
|
}
|
|
14747
|
+
if (cmd === "send_chat" && this._ctx.onBeforeSendChat) {
|
|
14748
|
+
const sessionId = this._currentRoute.session?.sessionId;
|
|
14749
|
+
const workspace = sessionId ? this._ctx.instanceManager?.getInstance(sessionId)?.getState?.()?.workspace : void 0;
|
|
14750
|
+
if (workspace && sessionId) {
|
|
14751
|
+
try {
|
|
14752
|
+
this._ctx.onBeforeSendChat({ workspace, sessionId });
|
|
14753
|
+
} catch {
|
|
14754
|
+
}
|
|
14755
|
+
}
|
|
14756
|
+
}
|
|
14531
14757
|
try {
|
|
14532
14758
|
result = await this.dispatch(cmd, args);
|
|
14533
14759
|
this.logCommandEnd(cmd, result, startedAt);
|
|
@@ -17768,6 +17994,7 @@ var KNOWN_PROVIDER_FIELDS = /* @__PURE__ */ new Set([
|
|
|
17768
17994
|
"sendDelayMs",
|
|
17769
17995
|
"sendKey",
|
|
17770
17996
|
"submitStrategy",
|
|
17997
|
+
"requirePromptEchoBeforeSubmit",
|
|
17771
17998
|
"timeouts",
|
|
17772
17999
|
"disableUpstream"
|
|
17773
18000
|
]);
|
|
@@ -29292,6 +29519,7 @@ async function initDaemonComponents(config) {
|
|
|
29292
29519
|
providerLoader,
|
|
29293
29520
|
instanceManager,
|
|
29294
29521
|
sessionRegistry,
|
|
29522
|
+
gitCommandServices: createDefaultGitCommandServices(),
|
|
29295
29523
|
onProviderSettingChanged: async (providerType) => {
|
|
29296
29524
|
await refreshProviderAvailability(providerType);
|
|
29297
29525
|
config.onStatusChange?.();
|
|
@@ -29299,7 +29527,8 @@ async function initDaemonComponents(config) {
|
|
|
29299
29527
|
onProviderSourceConfigChanged: async () => {
|
|
29300
29528
|
await refreshProviderAvailability();
|
|
29301
29529
|
config.onStatusChange?.();
|
|
29302
|
-
}
|
|
29530
|
+
},
|
|
29531
|
+
onBeforeSendChat: config.onBeforeSendChat
|
|
29303
29532
|
});
|
|
29304
29533
|
agentStreamManager = new DaemonAgentStreamManager(
|
|
29305
29534
|
LOG.forComponent("AgentStream").asLogFn(),
|
|
@@ -29450,6 +29679,7 @@ export {
|
|
|
29450
29679
|
ProviderLoader,
|
|
29451
29680
|
STANDALONE_CDP_SCAN_INTERVAL_MS,
|
|
29452
29681
|
SessionHostPtyTransportFactory,
|
|
29682
|
+
TurnSnapshotTracker,
|
|
29453
29683
|
VersionArchive,
|
|
29454
29684
|
appendRecentActivity,
|
|
29455
29685
|
buildAssistantChatMessage,
|