@jingyi0605/codingns 0.1.3 → 0.1.5
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/bin/codingns.mjs +47 -8
- package/dist/public/assets/{TerminalPage-Nq5sPc5c.js → TerminalPage-4p6EBqrR.js} +19 -19
- package/dist/public/assets/gemini-D4G1NbrE.png +0 -0
- package/dist/public/assets/index-CxeghocY.css +1 -0
- package/dist/public/assets/index-DXusStl0.js +108 -0
- package/dist/public/assets/kimi-BWNNSh7e.png +0 -0
- package/dist/public/index.html +2 -2
- package/dist/server/config/env.d.ts +7 -0
- package/dist/server/config/env.js +147 -1
- package/dist/server/config/env.js.map +1 -1
- package/dist/server/config/opencode-system-probe-helper-process.d.ts +24 -0
- package/dist/server/config/opencode-system-probe-helper-process.js +70 -5
- package/dist/server/config/opencode-system-probe-helper-process.js.map +1 -1
- package/dist/server/modules/auth/auth-service.d.ts +7 -1
- package/dist/server/modules/auth/auth-service.js +23 -3
- package/dist/server/modules/auth/auth-service.js.map +1 -1
- package/dist/server/modules/bootstrap/bootstrap-service.d.ts +3 -1
- package/dist/server/modules/bootstrap/bootstrap-service.js +7 -2
- package/dist/server/modules/bootstrap/bootstrap-service.js.map +1 -1
- package/dist/server/modules/butler/butler-action-context-service.d.ts +30 -0
- package/dist/server/modules/butler/butler-action-context-service.js +108 -0
- package/dist/server/modules/butler/butler-action-context-service.js.map +1 -0
- package/dist/server/modules/butler/butler-auth-service.d.ts +17 -0
- package/dist/server/modules/butler/butler-auth-service.js +91 -0
- package/dist/server/modules/butler/butler-auth-service.js.map +1 -0
- package/dist/server/modules/butler/butler-control-action-service.d.ts +65 -0
- package/dist/server/modules/butler/butler-control-action-service.js +296 -0
- package/dist/server/modules/butler/butler-control-action-service.js.map +1 -0
- package/dist/server/modules/butler/butler-control-session-service.d.ts +55 -0
- package/dist/server/modules/butler/butler-control-session-service.js +367 -0
- package/dist/server/modules/butler/butler-control-session-service.js.map +1 -0
- package/dist/server/modules/butler/butler-controller.d.ts +367 -0
- package/dist/server/modules/butler/butler-controller.js +475 -0
- package/dist/server/modules/butler/butler-controller.js.map +1 -0
- package/dist/server/modules/butler/butler-follow-up-evaluation-instruction-adapter.d.ts +34 -0
- package/dist/server/modules/butler/butler-follow-up-evaluation-instruction-adapter.js +77 -0
- package/dist/server/modules/butler/butler-follow-up-evaluation-instruction-adapter.js.map +1 -0
- package/dist/server/modules/butler/butler-follow-up-scheduler.d.ts +23 -0
- package/dist/server/modules/butler/butler-follow-up-scheduler.js +57 -0
- package/dist/server/modules/butler/butler-follow-up-scheduler.js.map +1 -0
- package/dist/server/modules/butler/butler-follow-up-service.d.ts +86 -0
- package/dist/server/modules/butler/butler-follow-up-service.js +948 -0
- package/dist/server/modules/butler/butler-follow-up-service.js.map +1 -0
- package/dist/server/modules/butler/butler-inbox-service.d.ts +35 -0
- package/dist/server/modules/butler/butler-inbox-service.js +136 -0
- package/dist/server/modules/butler/butler-inbox-service.js.map +1 -0
- package/dist/server/modules/butler/butler-notification-service.d.ts +12 -0
- package/dist/server/modules/butler/butler-notification-service.js +45 -0
- package/dist/server/modules/butler/butler-notification-service.js.map +1 -0
- package/dist/server/modules/butler/butler-profile-service.d.ts +26 -0
- package/dist/server/modules/butler/butler-profile-service.js +529 -0
- package/dist/server/modules/butler/butler-profile-service.js.map +1 -0
- package/dist/server/modules/butler/butler-project-service.d.ts +48 -0
- package/dist/server/modules/butler/butler-project-service.js +253 -0
- package/dist/server/modules/butler/butler-project-service.js.map +1 -0
- package/dist/server/modules/butler/butler-session-service.d.ts +79 -0
- package/dist/server/modules/butler/butler-session-service.js +503 -0
- package/dist/server/modules/butler/butler-session-service.js.map +1 -0
- package/dist/server/modules/butler/butler-session-summary-service.d.ts +55 -0
- package/dist/server/modules/butler/butler-session-summary-service.js +382 -0
- package/dist/server/modules/butler/butler-session-summary-service.js.map +1 -0
- package/dist/server/modules/butler/context-aggregator.d.ts +187 -0
- package/dist/server/modules/butler/context-aggregator.js +807 -0
- package/dist/server/modules/butler/context-aggregator.js.map +1 -0
- package/dist/server/modules/butler/instruction-adapter.d.ts +28 -0
- package/dist/server/modules/butler/instruction-adapter.js +101 -0
- package/dist/server/modules/butler/instruction-adapter.js.map +1 -0
- package/dist/server/modules/butler/patrol-execution-service.d.ts +47 -0
- package/dist/server/modules/butler/patrol-execution-service.js +347 -0
- package/dist/server/modules/butler/patrol-execution-service.js.map +1 -0
- package/dist/server/modules/butler/patrol-plan-service.d.ts +54 -0
- package/dist/server/modules/butler/patrol-plan-service.js +272 -0
- package/dist/server/modules/butler/patrol-plan-service.js.map +1 -0
- package/dist/server/modules/butler/patrol-run-service.d.ts +60 -0
- package/dist/server/modules/butler/patrol-run-service.js +185 -0
- package/dist/server/modules/butler/patrol-run-service.js.map +1 -0
- package/dist/server/modules/butler/patrol-scheduler.d.ts +36 -0
- package/dist/server/modules/butler/patrol-scheduler.js +99 -0
- package/dist/server/modules/butler/patrol-scheduler.js.map +1 -0
- package/dist/server/modules/butler/project-memory-service.d.ts +30 -0
- package/dist/server/modules/butler/project-memory-service.js +103 -0
- package/dist/server/modules/butler/project-memory-service.js.map +1 -0
- package/dist/server/modules/butler/provider-adapter-registry.d.ts +61 -0
- package/dist/server/modules/butler/provider-adapter-registry.js +430 -0
- package/dist/server/modules/butler/provider-adapter-registry.js.map +1 -0
- package/dist/server/modules/butler/session-summary-instruction-adapter.d.ts +28 -0
- package/dist/server/modules/butler/session-summary-instruction-adapter.js +79 -0
- package/dist/server/modules/butler/session-summary-instruction-adapter.js.map +1 -0
- package/dist/server/modules/butler/session-summary-scheduler.d.ts +23 -0
- package/dist/server/modules/butler/session-summary-scheduler.js +57 -0
- package/dist/server/modules/butler/session-summary-scheduler.js.map +1 -0
- package/dist/server/modules/butler/verification-run-service.d.ts +73 -0
- package/dist/server/modules/butler/verification-run-service.js +633 -0
- package/dist/server/modules/butler/verification-run-service.js.map +1 -0
- package/dist/server/modules/demo/demo-cleanup-service.d.ts +41 -0
- package/dist/server/modules/demo/demo-cleanup-service.js +111 -0
- package/dist/server/modules/demo/demo-cleanup-service.js.map +1 -0
- package/dist/server/modules/preferences/profile-service.js +8 -2
- package/dist/server/modules/preferences/profile-service.js.map +1 -1
- package/dist/server/modules/sessions/claude-runtime-helper-process.js +1 -1
- package/dist/server/modules/sessions/claude-runtime-helper-process.js.map +1 -1
- package/dist/server/modules/sessions/codex-app-server-helper-client.d.ts +5 -1
- package/dist/server/modules/sessions/codex-app-server-helper-client.js +10 -2
- package/dist/server/modules/sessions/codex-app-server-helper-client.js.map +1 -1
- package/dist/server/modules/sessions/session-controller.d.ts +3 -1
- package/dist/server/modules/sessions/session-controller.js +11 -2
- package/dist/server/modules/sessions/session-controller.js.map +1 -1
- package/dist/server/modules/sessions/session-history-service.d.ts +14 -1
- package/dist/server/modules/sessions/session-history-service.js +291 -30
- package/dist/server/modules/sessions/session-history-service.js.map +1 -1
- package/dist/server/modules/sessions/session-live-runtime-service.d.ts +25 -2
- package/dist/server/modules/sessions/session-live-runtime-service.js +526 -158
- package/dist/server/modules/sessions/session-live-runtime-service.js.map +1 -1
- package/dist/server/modules/sessions/session-provider-error-mapper.js +28 -0
- package/dist/server/modules/sessions/session-provider-error-mapper.js.map +1 -1
- package/dist/server/modules/terminal/terminal-service.js +2 -2
- package/dist/server/modules/terminal/terminal-service.js.map +1 -1
- package/dist/server/modules/workbench/workbench-service.d.ts +7 -1
- package/dist/server/modules/workbench/workbench-service.js +31 -7
- package/dist/server/modules/workbench/workbench-service.js.map +1 -1
- package/dist/server/routes/butler.d.ts +3 -0
- package/dist/server/routes/butler.js +54 -0
- package/dist/server/routes/butler.js.map +1 -0
- package/dist/server/routes/sessions.d.ts +1 -0
- package/dist/server/routes/sessions.js +12 -3
- package/dist/server/routes/sessions.js.map +1 -1
- package/dist/server/server/create-server.d.ts +61 -0
- package/dist/server/server/create-server.js +180 -10
- package/dist/server/server/create-server.js.map +1 -1
- package/dist/server/storage/repositories/butler-control-event-repository.d.ts +8 -0
- package/dist/server/storage/repositories/butler-control-event-repository.js +78 -0
- package/dist/server/storage/repositories/butler-control-event-repository.js.map +1 -0
- package/dist/server/storage/repositories/butler-control-session-repository.d.ts +11 -0
- package/dist/server/storage/repositories/butler-control-session-repository.js +86 -0
- package/dist/server/storage/repositories/butler-control-session-repository.js.map +1 -0
- package/dist/server/storage/repositories/butler-follow-up-task-repository.d.ts +16 -0
- package/dist/server/storage/repositories/butler-follow-up-task-repository.js +252 -0
- package/dist/server/storage/repositories/butler-follow-up-task-repository.js.map +1 -0
- package/dist/server/storage/repositories/butler-inbox-item-repository.d.ts +15 -0
- package/dist/server/storage/repositories/butler-inbox-item-repository.js +111 -0
- package/dist/server/storage/repositories/butler-inbox-item-repository.js.map +1 -0
- package/dist/server/storage/repositories/butler-notification-archive-repository.d.ts +9 -0
- package/dist/server/storage/repositories/butler-notification-archive-repository.js +48 -0
- package/dist/server/storage/repositories/butler-notification-archive-repository.js.map +1 -0
- package/dist/server/storage/repositories/butler-profile-repository.d.ts +9 -0
- package/dist/server/storage/repositories/butler-profile-repository.js +86 -0
- package/dist/server/storage/repositories/butler-profile-repository.js.map +1 -0
- package/dist/server/storage/repositories/butler-project-repository.d.ts +14 -0
- package/dist/server/storage/repositories/butler-project-repository.js +140 -0
- package/dist/server/storage/repositories/butler-project-repository.js.map +1 -0
- package/dist/server/storage/repositories/butler-session-repository.d.ts +11 -0
- package/dist/server/storage/repositories/butler-session-repository.js +106 -0
- package/dist/server/storage/repositories/butler-session-repository.js.map +1 -0
- package/dist/server/storage/repositories/butler-session-summary-state-repository.d.ts +8 -0
- package/dist/server/storage/repositories/butler-session-summary-state-repository.js +62 -0
- package/dist/server/storage/repositories/butler-session-summary-state-repository.js.map +1 -0
- package/dist/server/storage/repositories/patrol-plan-repository.d.ts +27 -0
- package/dist/server/storage/repositories/patrol-plan-repository.js +119 -0
- package/dist/server/storage/repositories/patrol-plan-repository.js.map +1 -0
- package/dist/server/storage/repositories/patrol-run-repository.d.ts +28 -0
- package/dist/server/storage/repositories/patrol-run-repository.js +121 -0
- package/dist/server/storage/repositories/patrol-run-repository.js.map +1 -0
- package/dist/server/storage/repositories/project-memory-repository.d.ts +15 -0
- package/dist/server/storage/repositories/project-memory-repository.js +150 -0
- package/dist/server/storage/repositories/project-memory-repository.js.map +1 -0
- package/dist/server/storage/repositories/session-checkpoint-repository.d.ts +9 -0
- package/dist/server/storage/repositories/session-checkpoint-repository.js +72 -0
- package/dist/server/storage/repositories/session-checkpoint-repository.js.map +1 -0
- package/dist/server/storage/repositories/session-message-origin-repository.d.ts +10 -0
- package/dist/server/storage/repositories/session-message-origin-repository.js +93 -0
- package/dist/server/storage/repositories/session-message-origin-repository.js.map +1 -0
- package/dist/server/storage/repositories/verification-run-repository.d.ts +29 -0
- package/dist/server/storage/repositories/verification-run-repository.js +125 -0
- package/dist/server/storage/repositories/verification-run-repository.js.map +1 -0
- package/dist/server/storage/sqlite/client.js +39 -0
- package/dist/server/storage/sqlite/client.js.map +1 -1
- package/dist/server/storage/sqlite/schema.sql +324 -0
- package/dist/server/types/domain.d.ts +261 -1
- package/dist/server/ws/ws-server.d.ts +2 -1
- package/dist/server/ws/ws-server.js +2 -1
- package/dist/server/ws/ws-server.js.map +1 -1
- package/node_modules/@codingns/session-sync-core/dist/index.d.ts +4 -0
- package/node_modules/@codingns/session-sync-core/dist/index.js +4 -0
- package/node_modules/@codingns/session-sync-core/dist/index.js.map +1 -1
- package/node_modules/@codingns/session-sync-core/dist/kimi-message-normalizer.d.ts +18 -0
- package/node_modules/@codingns/session-sync-core/dist/kimi-message-normalizer.js +659 -0
- package/node_modules/@codingns/session-sync-core/dist/kimi-message-normalizer.js.map +1 -0
- package/node_modules/@codingns/session-sync-core/dist/kimi-shared.d.ts +11 -0
- package/node_modules/@codingns/session-sync-core/dist/kimi-shared.js +72 -0
- package/node_modules/@codingns/session-sync-core/dist/kimi-shared.js.map +1 -0
- package/node_modules/@codingns/session-sync-core/dist/patch-builder.d.ts +8 -0
- package/node_modules/@codingns/session-sync-core/dist/patch-builder.js +89 -0
- package/node_modules/@codingns/session-sync-core/dist/patch-builder.js.map +1 -1
- package/node_modules/@codingns/session-sync-core/dist/providers/codex.js +4 -1
- package/node_modules/@codingns/session-sync-core/dist/providers/codex.js.map +1 -1
- package/node_modules/@codingns/session-sync-core/dist/providers/gemini.d.ts +41 -0
- package/node_modules/@codingns/session-sync-core/dist/providers/gemini.js +1086 -0
- package/node_modules/@codingns/session-sync-core/dist/providers/gemini.js.map +1 -0
- package/node_modules/@codingns/session-sync-core/dist/providers/kimi.d.ts +29 -0
- package/node_modules/@codingns/session-sync-core/dist/providers/kimi.js +578 -0
- package/node_modules/@codingns/session-sync-core/dist/providers/kimi.js.map +1 -0
- package/node_modules/@codingns/session-sync-core/dist/providers/opencode.js +2 -1
- package/node_modules/@codingns/session-sync-core/dist/providers/opencode.js.map +1 -1
- package/node_modules/@codingns/session-sync-core/dist/providers/utils.js +30 -2
- package/node_modules/@codingns/session-sync-core/dist/providers/utils.js.map +1 -1
- package/node_modules/@codingns/session-sync-core/dist/runtime/active-run-registry.d.ts +2 -0
- package/node_modules/@codingns/session-sync-core/dist/runtime/active-run-registry.js +43 -5
- package/node_modules/@codingns/session-sync-core/dist/runtime/active-run-registry.js.map +1 -1
- package/node_modules/@codingns/session-sync-core/dist/runtime/codex-runtime.d.ts +2 -0
- package/node_modules/@codingns/session-sync-core/dist/runtime/codex-runtime.js +320 -69
- package/node_modules/@codingns/session-sync-core/dist/runtime/codex-runtime.js.map +1 -1
- package/node_modules/@codingns/session-sync-core/dist/runtime/gemini-runtime.d.ts +21 -0
- package/node_modules/@codingns/session-sync-core/dist/runtime/gemini-runtime.js +537 -0
- package/node_modules/@codingns/session-sync-core/dist/runtime/gemini-runtime.js.map +1 -0
- package/node_modules/@codingns/session-sync-core/dist/runtime/kimi-runtime.d.ts +38 -0
- package/node_modules/@codingns/session-sync-core/dist/runtime/kimi-runtime.js +911 -0
- package/node_modules/@codingns/session-sync-core/dist/runtime/kimi-runtime.js.map +1 -0
- package/node_modules/@codingns/session-sync-core/dist/sqlite/node-sqlite.d.ts +6 -0
- package/node_modules/@codingns/session-sync-core/dist/sqlite/node-sqlite.js +9 -0
- package/node_modules/@codingns/session-sync-core/dist/sqlite/node-sqlite.js.map +1 -0
- package/node_modules/@codingns/session-sync-core/package.json +8 -0
- package/package.json +1 -1
- package/dist/public/assets/index-9hnprhO7.css +0 -1
- package/dist/public/assets/index-BTpmuKhG.js +0 -108
|
@@ -0,0 +1,911 @@
|
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
import { existsSync, readdirSync, statSync } from "node:fs";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { createInterface } from "node:readline";
|
|
5
|
+
import { buildKimiSessionRawStoreRef, findKimiWorkDirRecordByPath, readKimiWorkDirRecords } from "../kimi-shared.js";
|
|
6
|
+
import { extractTextBlocks, messageIdFromRawRef, nextTimestamp, safeDate } from "../providers/utils.js";
|
|
7
|
+
import { buildKimiMessageRawRef, extractKimiDisplayTextSegments, looksLikeKimiMessagePayload, normalizeKimiMessageRecord, readKimiFirstNonEmptyString, readKimiFirstPresentValue } from "../kimi-message-normalizer.js";
|
|
8
|
+
const INTERRUPT_KILL_TIMEOUT_MS = 1_500;
|
|
9
|
+
const READY_SIGNAL_TIMEOUT_MS = 700;
|
|
10
|
+
const KIMI_START_BINDING_RESOLVE_TIMEOUT_MS = 10_000;
|
|
11
|
+
const KIMI_START_BINDING_RESOLVE_POLL_MS = 100;
|
|
12
|
+
export class KimiRuntimeAdapter {
|
|
13
|
+
options;
|
|
14
|
+
providerId = "kimi";
|
|
15
|
+
commandPath;
|
|
16
|
+
baseArgs;
|
|
17
|
+
spawnFactory;
|
|
18
|
+
cliSyntax;
|
|
19
|
+
cliProbeTimeoutMs;
|
|
20
|
+
cliSyntaxPromise = null;
|
|
21
|
+
constructor(options) {
|
|
22
|
+
this.options = options;
|
|
23
|
+
this.commandPath = options.commandPath?.trim() || "kimi";
|
|
24
|
+
this.baseArgs = options.baseArgs ?? [];
|
|
25
|
+
this.spawnFactory = options.spawnFactory ?? spawn;
|
|
26
|
+
this.cliSyntax = options.cliSyntax ?? "auto";
|
|
27
|
+
this.cliProbeTimeoutMs = options.cliProbeTimeoutMs ?? 1_500;
|
|
28
|
+
}
|
|
29
|
+
async startSession(request, sink) {
|
|
30
|
+
const pendingBinding = buildPendingKimiBinding(request.sessionId);
|
|
31
|
+
const startBindingProbe = this.captureStartBindingProbe(request.workspacePath);
|
|
32
|
+
sink.updateSessionBinding(pendingBinding);
|
|
33
|
+
return this.launchWithFallback({
|
|
34
|
+
request,
|
|
35
|
+
sink,
|
|
36
|
+
mode: "start",
|
|
37
|
+
sessionId: pendingBinding.providerSessionId,
|
|
38
|
+
rawStoreRef: pendingBinding.rawStoreRef,
|
|
39
|
+
startBindingProbe
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
async continueSession(request, sink) {
|
|
43
|
+
const sessionId = request.providerSessionId?.trim();
|
|
44
|
+
if (!sessionId) {
|
|
45
|
+
throw new Error("PROVIDER_SESSION_ID_REQUIRED");
|
|
46
|
+
}
|
|
47
|
+
const rawStoreRef = request.rawStoreRef ?? buildKimiSessionRawStoreRef(sessionId);
|
|
48
|
+
sink.updateSessionBinding({
|
|
49
|
+
providerSessionId: sessionId,
|
|
50
|
+
rawStoreRef
|
|
51
|
+
});
|
|
52
|
+
return this.launchWithFallback({
|
|
53
|
+
request,
|
|
54
|
+
sink,
|
|
55
|
+
mode: "continue",
|
|
56
|
+
sessionId,
|
|
57
|
+
rawStoreRef,
|
|
58
|
+
startBindingProbe: null
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
async launchWithFallback(context) {
|
|
62
|
+
const cliSyntax = await this.resolveCliSyntax();
|
|
63
|
+
const commandAttempt = this.launchTransport(context, "command", cliSyntax);
|
|
64
|
+
try {
|
|
65
|
+
await commandAttempt.ready;
|
|
66
|
+
this.scheduleBindingResolution(context, commandAttempt);
|
|
67
|
+
return commandAttempt.launch;
|
|
68
|
+
}
|
|
69
|
+
catch (commandError) {
|
|
70
|
+
commandAttempt.launch.completed.catch(() => {
|
|
71
|
+
return;
|
|
72
|
+
});
|
|
73
|
+
const commandDetail = extractErrorDetail(await commandAttempt.launch.completed.then(() => null).catch((error) => error));
|
|
74
|
+
throw new Error(`KIMI_RUNTIME_FALLBACK_FAILED: wire=disabled; command=${commandDetail}; cause=${extractErrorDetail(commandError)}`);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
launchTransport(context, transport, cliSyntax) {
|
|
78
|
+
const args = [
|
|
79
|
+
...this.baseArgs,
|
|
80
|
+
...buildKimiRuntimeArgs(transport, context.mode, context.sessionId, context.request, cliSyntax)
|
|
81
|
+
];
|
|
82
|
+
const proc = this.spawnFactory(this.commandPath, args, {
|
|
83
|
+
cwd: context.request.workspacePath,
|
|
84
|
+
env: buildKimiSpawnEnv(),
|
|
85
|
+
shell: shouldSpawnViaShell(this.commandPath),
|
|
86
|
+
windowsHide: true,
|
|
87
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
88
|
+
});
|
|
89
|
+
let sequence = Math.max(0, context.request.sequenceBase ?? 0);
|
|
90
|
+
let lineNumber = 0;
|
|
91
|
+
let interrupted = false;
|
|
92
|
+
let settled = false;
|
|
93
|
+
let activeSessionId = context.sessionId;
|
|
94
|
+
let activeRawStoreRef = context.rawStoreRef;
|
|
95
|
+
let stderrBuffer = "";
|
|
96
|
+
let lineChain = Promise.resolve();
|
|
97
|
+
let stdinClosed = false;
|
|
98
|
+
let writeChain = Promise.resolve();
|
|
99
|
+
let sawStdoutEvent = false;
|
|
100
|
+
let readySettled = false;
|
|
101
|
+
let plainTextBuffer = [];
|
|
102
|
+
let plainTextStartLineNumber = 0;
|
|
103
|
+
const recentMessageSignatures = [];
|
|
104
|
+
let readyTimer = null;
|
|
105
|
+
let resolveReady = null;
|
|
106
|
+
let rejectReady = null;
|
|
107
|
+
const updateActiveBinding = (binding) => {
|
|
108
|
+
if (!binding.providerSessionId.trim()
|
|
109
|
+
|| (binding.providerSessionId === activeSessionId
|
|
110
|
+
&& binding.rawStoreRef === activeRawStoreRef)) {
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
activeSessionId = binding.providerSessionId;
|
|
114
|
+
activeRawStoreRef = binding.rawStoreRef;
|
|
115
|
+
context.sink.updateSessionBinding(binding);
|
|
116
|
+
launch.providerSessionId = binding.providerSessionId;
|
|
117
|
+
launch.rawStoreRef = binding.rawStoreRef;
|
|
118
|
+
};
|
|
119
|
+
const enqueuePromptWrite = (options, closeAfterWrite = false) => {
|
|
120
|
+
writeChain = writeChain.then(() => this.writePromptPayload(proc, options, transport, closeAfterWrite));
|
|
121
|
+
return writeChain;
|
|
122
|
+
};
|
|
123
|
+
const canSubmitInRunInput = () => !interrupted &&
|
|
124
|
+
!settled &&
|
|
125
|
+
!proc.killed &&
|
|
126
|
+
!stdinClosed &&
|
|
127
|
+
!proc.stdin.destroyed &&
|
|
128
|
+
!proc.stdin.writableEnded &&
|
|
129
|
+
proc.stdin.writable;
|
|
130
|
+
const ready = new Promise((resolve, reject) => {
|
|
131
|
+
resolveReady = resolve;
|
|
132
|
+
rejectReady = (error) => reject(error);
|
|
133
|
+
});
|
|
134
|
+
const settleReady = (error) => {
|
|
135
|
+
if (readySettled) {
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
readySettled = true;
|
|
139
|
+
if (readyTimer) {
|
|
140
|
+
clearTimeout(readyTimer);
|
|
141
|
+
}
|
|
142
|
+
if (error) {
|
|
143
|
+
rejectReady?.(error);
|
|
144
|
+
}
|
|
145
|
+
else {
|
|
146
|
+
resolveReady?.();
|
|
147
|
+
}
|
|
148
|
+
};
|
|
149
|
+
readyTimer = setTimeout(() => {
|
|
150
|
+
settleReady();
|
|
151
|
+
}, READY_SIGNAL_TIMEOUT_MS);
|
|
152
|
+
const completed = new Promise((resolve, reject) => {
|
|
153
|
+
const settle = (callback) => {
|
|
154
|
+
if (settled) {
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
settled = true;
|
|
158
|
+
callback();
|
|
159
|
+
};
|
|
160
|
+
const onStructuredEvent = async (event) => {
|
|
161
|
+
if (event.providerSessionId?.trim() && event.providerSessionId !== activeSessionId) {
|
|
162
|
+
updateActiveBinding({
|
|
163
|
+
providerSessionId: event.providerSessionId,
|
|
164
|
+
rawStoreRef: event.rawStoreRef ?? buildKimiSessionRawStoreRef(event.providerSessionId)
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
await context.sink.emit({
|
|
168
|
+
...event,
|
|
169
|
+
providerSessionId: activeSessionId,
|
|
170
|
+
rawStoreRef: activeRawStoreRef
|
|
171
|
+
});
|
|
172
|
+
};
|
|
173
|
+
const emitRuntimeEvent = async (event) => {
|
|
174
|
+
if (event.type === "message" && event.message) {
|
|
175
|
+
if (shouldSkipEquivalentRecentKimiRuntimeMessage(recentMessageSignatures, event.message)) {
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
rememberKimiRuntimeMessage(recentMessageSignatures, event.message);
|
|
179
|
+
}
|
|
180
|
+
await onStructuredEvent(event);
|
|
181
|
+
};
|
|
182
|
+
const handleJsonPayload = async (payload) => {
|
|
183
|
+
const mapped = mapKimiWirePayload(payload, {
|
|
184
|
+
sessionId: activeSessionId,
|
|
185
|
+
rawStoreRef: activeRawStoreRef,
|
|
186
|
+
sequence,
|
|
187
|
+
lineNumber
|
|
188
|
+
});
|
|
189
|
+
if (mapped.providerSessionId && mapped.providerSessionId !== activeSessionId) {
|
|
190
|
+
updateActiveBinding({
|
|
191
|
+
providerSessionId: mapped.providerSessionId,
|
|
192
|
+
rawStoreRef: buildKimiSessionRawStoreRef(mapped.providerSessionId)
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
for (const event of mapped.events) {
|
|
196
|
+
if (event.type === "message" && event.message) {
|
|
197
|
+
sequence = event.message.sequence;
|
|
198
|
+
}
|
|
199
|
+
await emitRuntimeEvent(event);
|
|
200
|
+
}
|
|
201
|
+
};
|
|
202
|
+
const flushBufferedPlainText = async () => {
|
|
203
|
+
if (plainTextBuffer.length === 0) {
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
const startLineNumber = plainTextStartLineNumber || lineNumber;
|
|
207
|
+
const contentBlocks = extractKimiDisplayTextSegments(plainTextBuffer.join("\n"));
|
|
208
|
+
plainTextBuffer = [];
|
|
209
|
+
plainTextStartLineNumber = 0;
|
|
210
|
+
for (const [contentIndex, content] of contentBlocks.entries()) {
|
|
211
|
+
const nextSequence = sequence + 1;
|
|
212
|
+
sequence = nextSequence;
|
|
213
|
+
const message = createTextMessage({
|
|
214
|
+
sessionId: activeSessionId,
|
|
215
|
+
rawStoreRef: activeRawStoreRef,
|
|
216
|
+
sequence: nextSequence,
|
|
217
|
+
lineNumber: startLineNumber,
|
|
218
|
+
role: "assistant",
|
|
219
|
+
kind: "text",
|
|
220
|
+
content,
|
|
221
|
+
timestamp: nextTimestamp(),
|
|
222
|
+
rawEventRef: buildKimiMessageRawRef(activeSessionId, "wire", startLineNumber, contentBlocks.length > 1 ? contentIndex : undefined)
|
|
223
|
+
});
|
|
224
|
+
await emitRuntimeEvent({
|
|
225
|
+
type: "message",
|
|
226
|
+
message,
|
|
227
|
+
status: "running",
|
|
228
|
+
detail: "wire line",
|
|
229
|
+
rawEventRef: message.rawRef
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
};
|
|
233
|
+
const handleStdoutLine = (line) => {
|
|
234
|
+
lineNumber += 1;
|
|
235
|
+
const trimmed = line.trim();
|
|
236
|
+
const payload = trimmed ? parseJsonObject(trimmed) : null;
|
|
237
|
+
if (payload) {
|
|
238
|
+
sawStdoutEvent = true;
|
|
239
|
+
settleReady();
|
|
240
|
+
return flushBufferedPlainText().then(() => handleJsonPayload(payload));
|
|
241
|
+
}
|
|
242
|
+
if (!trimmed) {
|
|
243
|
+
if (plainTextBuffer.length > 0) {
|
|
244
|
+
plainTextBuffer.push("");
|
|
245
|
+
}
|
|
246
|
+
return Promise.resolve();
|
|
247
|
+
}
|
|
248
|
+
sawStdoutEvent = true;
|
|
249
|
+
settleReady();
|
|
250
|
+
if (plainTextBuffer.length === 0) {
|
|
251
|
+
plainTextStartLineNumber = lineNumber;
|
|
252
|
+
}
|
|
253
|
+
plainTextBuffer.push(line);
|
|
254
|
+
if (trimmed.toLowerCase() === "turnend") {
|
|
255
|
+
return flushBufferedPlainText();
|
|
256
|
+
}
|
|
257
|
+
return Promise.resolve();
|
|
258
|
+
};
|
|
259
|
+
const stdoutReader = createInterface({ input: proc.stdout });
|
|
260
|
+
stdoutReader.on("line", (line) => {
|
|
261
|
+
lineChain = lineChain.then(() => handleStdoutLine(line));
|
|
262
|
+
});
|
|
263
|
+
proc.stderr.setEncoding("utf8");
|
|
264
|
+
proc.stderr.on("data", (chunk) => {
|
|
265
|
+
stderrBuffer = `${stderrBuffer}${chunk}`.trim();
|
|
266
|
+
});
|
|
267
|
+
proc.once("error", (error) => {
|
|
268
|
+
if (transport === "wire") {
|
|
269
|
+
settleReady(toWireUnavailableError(error));
|
|
270
|
+
}
|
|
271
|
+
else {
|
|
272
|
+
settleReady(error instanceof Error ? error : new Error("KIMI_RUNTIME_FAILED"));
|
|
273
|
+
}
|
|
274
|
+
settle(() => {
|
|
275
|
+
reject(error);
|
|
276
|
+
});
|
|
277
|
+
});
|
|
278
|
+
proc.once("close", (code, signal) => {
|
|
279
|
+
stdinClosed = true;
|
|
280
|
+
if (!sawStdoutEvent && !interrupted && code !== 0) {
|
|
281
|
+
if (transport === "wire") {
|
|
282
|
+
settleReady(toWireUnavailableError(new Error(stderrBuffer ||
|
|
283
|
+
`Kimi wire exited with code=${String(code ?? "null")} signal=${String(signal ?? "null")}`)));
|
|
284
|
+
}
|
|
285
|
+
else {
|
|
286
|
+
settleReady(new Error(stderrBuffer ||
|
|
287
|
+
`Kimi command exited with code=${String(code ?? "null")} signal=${String(signal ?? "null")}`));
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
else {
|
|
291
|
+
settleReady();
|
|
292
|
+
}
|
|
293
|
+
void lineChain
|
|
294
|
+
.then(async () => {
|
|
295
|
+
await flushBufferedPlainText();
|
|
296
|
+
if (interrupted) {
|
|
297
|
+
settle(() => {
|
|
298
|
+
resolve();
|
|
299
|
+
});
|
|
300
|
+
return;
|
|
301
|
+
}
|
|
302
|
+
if (code === 0) {
|
|
303
|
+
settle(() => {
|
|
304
|
+
resolve();
|
|
305
|
+
});
|
|
306
|
+
return;
|
|
307
|
+
}
|
|
308
|
+
const detail = stderrBuffer ||
|
|
309
|
+
`Kimi ${transport} exited with code=${String(code ?? "null")} signal=${String(signal ?? "null")}`;
|
|
310
|
+
settle(() => {
|
|
311
|
+
reject(new Error(detail));
|
|
312
|
+
});
|
|
313
|
+
})
|
|
314
|
+
.catch((error) => {
|
|
315
|
+
settle(() => {
|
|
316
|
+
reject(error instanceof Error ? error : new Error("KIMI_WIRE_RUNTIME_FAILED"));
|
|
317
|
+
});
|
|
318
|
+
});
|
|
319
|
+
});
|
|
320
|
+
enqueuePromptWrite(context.request.options, transport === "command").catch((error) => {
|
|
321
|
+
settle(() => {
|
|
322
|
+
reject(error);
|
|
323
|
+
});
|
|
324
|
+
});
|
|
325
|
+
});
|
|
326
|
+
const submitDuringRun = async (options) => {
|
|
327
|
+
if (transport === "command" || !canSubmitInRunInput()) {
|
|
328
|
+
throw new Error("IN_RUN_INPUT_NOT_SUPPORTED");
|
|
329
|
+
}
|
|
330
|
+
return enqueuePromptWrite(options).catch((error) => {
|
|
331
|
+
throw mapInRunSubmitError(error);
|
|
332
|
+
});
|
|
333
|
+
};
|
|
334
|
+
const launch = {
|
|
335
|
+
providerSessionId: context.sessionId,
|
|
336
|
+
rawStoreRef: context.rawStoreRef,
|
|
337
|
+
interrupt: async () => {
|
|
338
|
+
interrupted = true;
|
|
339
|
+
if (proc.killed) {
|
|
340
|
+
return;
|
|
341
|
+
}
|
|
342
|
+
proc.kill("SIGINT");
|
|
343
|
+
await new Promise((resolve) => {
|
|
344
|
+
const timeout = setTimeout(() => {
|
|
345
|
+
if (!proc.killed) {
|
|
346
|
+
proc.kill("SIGKILL");
|
|
347
|
+
}
|
|
348
|
+
resolve();
|
|
349
|
+
}, INTERRUPT_KILL_TIMEOUT_MS);
|
|
350
|
+
proc.once("close", () => {
|
|
351
|
+
clearTimeout(timeout);
|
|
352
|
+
resolve();
|
|
353
|
+
});
|
|
354
|
+
});
|
|
355
|
+
},
|
|
356
|
+
isAlive: () => !proc.killed,
|
|
357
|
+
submitDuringRun: transport === "command" ? undefined : submitDuringRun,
|
|
358
|
+
completed
|
|
359
|
+
};
|
|
360
|
+
return {
|
|
361
|
+
transport,
|
|
362
|
+
launch,
|
|
363
|
+
ready,
|
|
364
|
+
updateBinding: updateActiveBinding
|
|
365
|
+
};
|
|
366
|
+
}
|
|
367
|
+
scheduleBindingResolution(context, attempt) {
|
|
368
|
+
if (context.mode !== "start" || !isPendingKimiBinding(context.sessionId)) {
|
|
369
|
+
return;
|
|
370
|
+
}
|
|
371
|
+
void Promise.race([
|
|
372
|
+
this.resolveStartedSessionBinding(context.request.workspacePath, context.startBindingProbe),
|
|
373
|
+
attempt.launch.completed.then(() => null)
|
|
374
|
+
])
|
|
375
|
+
.then(async (binding) => {
|
|
376
|
+
if (!binding) {
|
|
377
|
+
return;
|
|
378
|
+
}
|
|
379
|
+
attempt.updateBinding(binding);
|
|
380
|
+
await context.sink.emit({
|
|
381
|
+
type: "session_created",
|
|
382
|
+
status: "starting",
|
|
383
|
+
providerSessionId: binding.providerSessionId,
|
|
384
|
+
rawStoreRef: binding.rawStoreRef,
|
|
385
|
+
detail: "Kimi session binding resolved"
|
|
386
|
+
});
|
|
387
|
+
})
|
|
388
|
+
.catch(() => {
|
|
389
|
+
return;
|
|
390
|
+
});
|
|
391
|
+
}
|
|
392
|
+
async resolveCliSyntax() {
|
|
393
|
+
if (this.cliSyntax !== "auto") {
|
|
394
|
+
return this.cliSyntax;
|
|
395
|
+
}
|
|
396
|
+
if (!this.cliSyntaxPromise) {
|
|
397
|
+
// 先探测本地 CLI 的参数风格,避免新版/旧版参数互相打架。
|
|
398
|
+
this.cliSyntaxPromise = detectKimiCliSyntax({
|
|
399
|
+
commandPath: this.commandPath,
|
|
400
|
+
baseArgs: this.baseArgs,
|
|
401
|
+
spawnFactory: this.spawnFactory,
|
|
402
|
+
timeoutMs: this.cliProbeTimeoutMs
|
|
403
|
+
}).catch(() => "modern");
|
|
404
|
+
}
|
|
405
|
+
return this.cliSyntaxPromise;
|
|
406
|
+
}
|
|
407
|
+
async resolveStartedSessionBinding(workspacePath, startBindingProbe) {
|
|
408
|
+
const startedAtMs = Date.now();
|
|
409
|
+
const initialLastSessionId = startBindingProbe?.lastSessionId ?? null;
|
|
410
|
+
const workDirHash = startBindingProbe?.workDirHash ?? null;
|
|
411
|
+
while (Date.now() - startedAtMs < KIMI_START_BINDING_RESOLVE_TIMEOUT_MS) {
|
|
412
|
+
const workDirs = readKimiWorkDirRecords(this.options.homeDir);
|
|
413
|
+
const activeWorkDir = findKimiWorkDirRecordByPath(workDirs, workspacePath);
|
|
414
|
+
const candidateSessionId = this.findResolvedSessionIdFromWorkDir(activeWorkDir?.lastSessionId ?? null, initialLastSessionId)
|
|
415
|
+
?? this.findLatestSessionIdForWorkspace(activeWorkDir?.hash ?? workDirHash, startedAtMs, initialLastSessionId);
|
|
416
|
+
if (candidateSessionId) {
|
|
417
|
+
return {
|
|
418
|
+
providerSessionId: candidateSessionId,
|
|
419
|
+
rawStoreRef: buildKimiSessionRawStoreRef(candidateSessionId)
|
|
420
|
+
};
|
|
421
|
+
}
|
|
422
|
+
await waitForKimiBindingResolvePoll();
|
|
423
|
+
}
|
|
424
|
+
return null;
|
|
425
|
+
}
|
|
426
|
+
captureStartBindingProbe(workspacePath) {
|
|
427
|
+
const workDirs = readKimiWorkDirRecords(this.options.homeDir);
|
|
428
|
+
const workDir = findKimiWorkDirRecordByPath(workDirs, workspacePath);
|
|
429
|
+
return {
|
|
430
|
+
workDirHash: workDir?.hash ?? null,
|
|
431
|
+
lastSessionId: workDir?.lastSessionId ?? null
|
|
432
|
+
};
|
|
433
|
+
}
|
|
434
|
+
findResolvedSessionIdFromWorkDir(candidateSessionId, initialLastSessionId) {
|
|
435
|
+
const normalizedCandidate = candidateSessionId?.trim();
|
|
436
|
+
if (!normalizedCandidate) {
|
|
437
|
+
return null;
|
|
438
|
+
}
|
|
439
|
+
if (initialLastSessionId && normalizedCandidate === initialLastSessionId) {
|
|
440
|
+
return null;
|
|
441
|
+
}
|
|
442
|
+
return normalizedCandidate;
|
|
443
|
+
}
|
|
444
|
+
findLatestSessionIdForWorkspace(workDirHash, startedAtMs, initialLastSessionId) {
|
|
445
|
+
if (!workDirHash?.trim()) {
|
|
446
|
+
return null;
|
|
447
|
+
}
|
|
448
|
+
const workspaceSessionsDir = join(this.options.homeDir, "sessions", workDirHash);
|
|
449
|
+
if (!existsSync(workspaceSessionsDir)) {
|
|
450
|
+
return null;
|
|
451
|
+
}
|
|
452
|
+
let bestCandidate = null;
|
|
453
|
+
const entries = readdirSync(workspaceSessionsDir, { withFileTypes: true });
|
|
454
|
+
for (const entry of entries) {
|
|
455
|
+
if (!entry.isDirectory()) {
|
|
456
|
+
continue;
|
|
457
|
+
}
|
|
458
|
+
if (initialLastSessionId && entry.name === initialLastSessionId) {
|
|
459
|
+
continue;
|
|
460
|
+
}
|
|
461
|
+
const sessionDir = join(workspaceSessionsDir, entry.name);
|
|
462
|
+
const mtimeMs = readKimiSessionDirectoryMtime(sessionDir);
|
|
463
|
+
if (mtimeMs < startedAtMs - 1_000) {
|
|
464
|
+
continue;
|
|
465
|
+
}
|
|
466
|
+
if (!bestCandidate || mtimeMs > bestCandidate.mtimeMs) {
|
|
467
|
+
bestCandidate = {
|
|
468
|
+
sessionId: entry.name,
|
|
469
|
+
mtimeMs
|
|
470
|
+
};
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
return bestCandidate?.sessionId ?? null;
|
|
474
|
+
}
|
|
475
|
+
async writePrompt(proc, request) {
|
|
476
|
+
return this.writePromptPayload(proc, request.options, "command");
|
|
477
|
+
}
|
|
478
|
+
async writePromptPayload(proc, options, transport, closeAfterWrite = false) {
|
|
479
|
+
const prompt = options.providerPrompt?.trim() || options.content.trim();
|
|
480
|
+
if (!prompt) {
|
|
481
|
+
if (transport === "command" && closeAfterWrite) {
|
|
482
|
+
await this.closeCommandInput(proc);
|
|
483
|
+
}
|
|
484
|
+
return;
|
|
485
|
+
}
|
|
486
|
+
const payload = transport === "command"
|
|
487
|
+
? buildCommandInputPayloadFromOptions(prompt)
|
|
488
|
+
: buildPromptPayloadFromOptions(options, prompt);
|
|
489
|
+
await this.writeWirePayload(proc, payload);
|
|
490
|
+
if (transport === "command" && closeAfterWrite) {
|
|
491
|
+
await this.closeCommandInput(proc);
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
async writeWirePayload(proc, payload) {
|
|
495
|
+
await new Promise((resolve, reject) => {
|
|
496
|
+
proc.stdin.write(`${JSON.stringify(payload)}\n`, (error) => {
|
|
497
|
+
if (error) {
|
|
498
|
+
reject(error);
|
|
499
|
+
return;
|
|
500
|
+
}
|
|
501
|
+
resolve();
|
|
502
|
+
});
|
|
503
|
+
});
|
|
504
|
+
}
|
|
505
|
+
async closeCommandInput(proc) {
|
|
506
|
+
if (proc.stdin.destroyed || proc.stdin.writableEnded) {
|
|
507
|
+
return;
|
|
508
|
+
}
|
|
509
|
+
await new Promise((resolve, reject) => {
|
|
510
|
+
try {
|
|
511
|
+
proc.stdin.end();
|
|
512
|
+
resolve();
|
|
513
|
+
}
|
|
514
|
+
catch (error) {
|
|
515
|
+
reject(error);
|
|
516
|
+
}
|
|
517
|
+
});
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
function buildPromptPayloadFromOptions(options, prompt) {
|
|
521
|
+
return {
|
|
522
|
+
type: "prompt.submit",
|
|
523
|
+
content: prompt,
|
|
524
|
+
client_request_id: options.clientRequestId,
|
|
525
|
+
permission_mode: options.permissionMode,
|
|
526
|
+
model: options.model,
|
|
527
|
+
reasoning_level: options.reasoningLevel,
|
|
528
|
+
attachments: options.attachments.map((attachment) => ({
|
|
529
|
+
file_path: attachment.filePath,
|
|
530
|
+
file_name: attachment.fileName,
|
|
531
|
+
mime_type: attachment.mimeType,
|
|
532
|
+
file_size: attachment.fileSize
|
|
533
|
+
}))
|
|
534
|
+
};
|
|
535
|
+
}
|
|
536
|
+
function buildKimiRuntimeArgs(transport, mode, sessionId, request, cliSyntax) {
|
|
537
|
+
if (cliSyntax === "modern") {
|
|
538
|
+
return buildModernKimiRuntimeArgs(transport, mode, sessionId, request);
|
|
539
|
+
}
|
|
540
|
+
return buildLegacyKimiRuntimeArgs(transport, mode, sessionId, request);
|
|
541
|
+
}
|
|
542
|
+
function buildModernKimiRuntimeArgs(transport, mode, sessionId, request) {
|
|
543
|
+
if (transport === "wire") {
|
|
544
|
+
const args = ["--wire"];
|
|
545
|
+
if (mode === "continue") {
|
|
546
|
+
args.push("--session", sessionId);
|
|
547
|
+
}
|
|
548
|
+
args.push("--work-dir", request.workspacePath);
|
|
549
|
+
if (request.options.model) {
|
|
550
|
+
args.push("--model", request.options.model);
|
|
551
|
+
}
|
|
552
|
+
return args;
|
|
553
|
+
}
|
|
554
|
+
const args = ["--print", "--output-format", "stream-json", "--input-format", "stream-json"];
|
|
555
|
+
if (mode === "continue") {
|
|
556
|
+
args.push("--session", sessionId);
|
|
557
|
+
}
|
|
558
|
+
args.push("--work-dir", request.workspacePath);
|
|
559
|
+
if (request.options.model) {
|
|
560
|
+
args.push("--model", request.options.model);
|
|
561
|
+
}
|
|
562
|
+
return args;
|
|
563
|
+
}
|
|
564
|
+
function buildLegacyKimiRuntimeArgs(transport, mode, sessionId, request) {
|
|
565
|
+
if (transport === "wire") {
|
|
566
|
+
const args = ["wire", "--output-format", "stream-json"];
|
|
567
|
+
if (mode === "continue") {
|
|
568
|
+
args.push("--resume", sessionId);
|
|
569
|
+
}
|
|
570
|
+
else {
|
|
571
|
+
args.push("--new-session");
|
|
572
|
+
}
|
|
573
|
+
args.push("--cwd", request.workspacePath);
|
|
574
|
+
if (request.options.model) {
|
|
575
|
+
args.push("--model", request.options.model);
|
|
576
|
+
}
|
|
577
|
+
return args;
|
|
578
|
+
}
|
|
579
|
+
const args = ["--print", "--output-format", "stream-json", "--input-format", "stream-json"];
|
|
580
|
+
if (mode === "continue") {
|
|
581
|
+
args.push("--resume", sessionId);
|
|
582
|
+
}
|
|
583
|
+
args.push("--cwd", request.workspacePath);
|
|
584
|
+
if (request.options.model) {
|
|
585
|
+
args.push("--model", request.options.model);
|
|
586
|
+
}
|
|
587
|
+
return args;
|
|
588
|
+
}
|
|
589
|
+
function parseJsonObject(line) {
|
|
590
|
+
try {
|
|
591
|
+
const parsed = JSON.parse(line);
|
|
592
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
593
|
+
return null;
|
|
594
|
+
}
|
|
595
|
+
return parsed;
|
|
596
|
+
}
|
|
597
|
+
catch {
|
|
598
|
+
return null;
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
function mapKimiWirePayload(payload, context) {
|
|
602
|
+
const events = [];
|
|
603
|
+
const wireType = (readKimiFirstNonEmptyString(payload, [
|
|
604
|
+
["type"],
|
|
605
|
+
["event"],
|
|
606
|
+
["kind"],
|
|
607
|
+
["message", "type"],
|
|
608
|
+
["message", "payload", "type"],
|
|
609
|
+
["payload", "type"]
|
|
610
|
+
]) ?? "").trim().toLowerCase();
|
|
611
|
+
const providerSessionId = readKimiFirstNonEmptyString(payload, [
|
|
612
|
+
["sessionId"],
|
|
613
|
+
["session_id"],
|
|
614
|
+
["session", "id"]
|
|
615
|
+
]) ?? null;
|
|
616
|
+
const timestamp = resolveEventTimestamp(payload);
|
|
617
|
+
const resolvedSessionId = providerSessionId ?? context.sessionId;
|
|
618
|
+
const resolvedRawStoreRef = providerSessionId
|
|
619
|
+
? buildKimiSessionRawStoreRef(providerSessionId)
|
|
620
|
+
: context.rawStoreRef;
|
|
621
|
+
const rawEventRef = buildKimiMessageRawRef(resolvedSessionId, "wire", context.lineNumber);
|
|
622
|
+
if (wireType.includes("session") && wireType.includes("created")) {
|
|
623
|
+
events.push({
|
|
624
|
+
type: "session_created",
|
|
625
|
+
status: "starting",
|
|
626
|
+
timestamp,
|
|
627
|
+
detail: "Kimi wire session created",
|
|
628
|
+
rawEventRef,
|
|
629
|
+
providerSessionId: providerSessionId ?? undefined
|
|
630
|
+
});
|
|
631
|
+
}
|
|
632
|
+
if (wireType.includes("running") || wireType.includes("progress")) {
|
|
633
|
+
events.push({
|
|
634
|
+
type: "status",
|
|
635
|
+
status: "running",
|
|
636
|
+
timestamp,
|
|
637
|
+
detail: extractTextBlocks(payload).trim() || "Kimi wire running",
|
|
638
|
+
rawEventRef,
|
|
639
|
+
providerSessionId: providerSessionId ?? undefined
|
|
640
|
+
});
|
|
641
|
+
}
|
|
642
|
+
if (wireType.includes("question") || wireType.includes("prompt") || wireType.includes("request")) {
|
|
643
|
+
events.push({
|
|
644
|
+
type: "status",
|
|
645
|
+
status: "running",
|
|
646
|
+
timestamp,
|
|
647
|
+
detail: extractTextBlocks(payload).trim() || "Kimi wire awaiting runtime guidance",
|
|
648
|
+
rawEventRef,
|
|
649
|
+
providerSessionId: providerSessionId ?? undefined
|
|
650
|
+
});
|
|
651
|
+
}
|
|
652
|
+
const maybeError = readKimiFirstNonEmptyString(payload, [["error"], ["detail"], ["message"]]);
|
|
653
|
+
if (wireType.includes("error") || wireType.includes("failed")) {
|
|
654
|
+
events.push({
|
|
655
|
+
type: "error",
|
|
656
|
+
status: "failed",
|
|
657
|
+
timestamp,
|
|
658
|
+
detail: maybeError || "Kimi wire failed",
|
|
659
|
+
errorCode: normalizeErrorCode(payload),
|
|
660
|
+
rawEventRef,
|
|
661
|
+
providerSessionId: providerSessionId ?? undefined
|
|
662
|
+
});
|
|
663
|
+
return {
|
|
664
|
+
providerSessionId,
|
|
665
|
+
events
|
|
666
|
+
};
|
|
667
|
+
}
|
|
668
|
+
// Kimi 的 wire 完成标记经常早于本地历史真正落盘,这里不直接发 completed,
|
|
669
|
+
// 改由进程 completed Promise 作为终态来源,避免前端过早显示“已结束”。
|
|
670
|
+
const normalizedMessages = normalizeKimiWireMessages(payload, wireType, {
|
|
671
|
+
sessionId: resolvedSessionId,
|
|
672
|
+
rawStoreRef: resolvedRawStoreRef,
|
|
673
|
+
sequence: context.sequence,
|
|
674
|
+
lineNumber: context.lineNumber,
|
|
675
|
+
timestamp
|
|
676
|
+
});
|
|
677
|
+
for (const normalizedMessage of normalizedMessages) {
|
|
678
|
+
events.push({
|
|
679
|
+
type: "message",
|
|
680
|
+
message: normalizedMessage,
|
|
681
|
+
status: "running",
|
|
682
|
+
timestamp,
|
|
683
|
+
detail: null,
|
|
684
|
+
rawEventRef: normalizedMessage.rawRef,
|
|
685
|
+
providerSessionId: providerSessionId ?? undefined
|
|
686
|
+
});
|
|
687
|
+
}
|
|
688
|
+
return {
|
|
689
|
+
providerSessionId,
|
|
690
|
+
events
|
|
691
|
+
};
|
|
692
|
+
}
|
|
693
|
+
function normalizeKimiWireMessages(payload, wireType, input) {
|
|
694
|
+
if (!looksLikeKimiMessagePayload(payload, wireType)) {
|
|
695
|
+
return [];
|
|
696
|
+
}
|
|
697
|
+
const normalizedParts = normalizeKimiMessageRecord(payload);
|
|
698
|
+
return normalizedParts.map((part, index) => createTextMessage({
|
|
699
|
+
sessionId: input.sessionId,
|
|
700
|
+
rawStoreRef: input.rawStoreRef,
|
|
701
|
+
sequence: input.sequence + index + 1,
|
|
702
|
+
lineNumber: input.lineNumber,
|
|
703
|
+
role: part.role,
|
|
704
|
+
kind: part.kind,
|
|
705
|
+
content: part.content,
|
|
706
|
+
timestamp: input.timestamp,
|
|
707
|
+
rawEventRef: buildKimiMessageRawRef(input.sessionId, "wire", input.lineNumber, part.partIndex ?? undefined),
|
|
708
|
+
toolCall: part.toolCall
|
|
709
|
+
}));
|
|
710
|
+
}
|
|
711
|
+
function createTextMessage(input) {
|
|
712
|
+
return {
|
|
713
|
+
messageId: messageIdFromRawRef(input.rawEventRef),
|
|
714
|
+
provider: "kimi",
|
|
715
|
+
providerSessionId: input.sessionId,
|
|
716
|
+
role: input.role,
|
|
717
|
+
kind: input.kind,
|
|
718
|
+
content: input.content,
|
|
719
|
+
toolCall: input.toolCall ?? null,
|
|
720
|
+
timestamp: input.timestamp,
|
|
721
|
+
sequence: input.sequence,
|
|
722
|
+
rawRef: input.rawEventRef
|
|
723
|
+
};
|
|
724
|
+
}
|
|
725
|
+
function resolveEventTimestamp(payload) {
|
|
726
|
+
const raw = readKimiFirstPresentValue(payload, [
|
|
727
|
+
["timestamp"],
|
|
728
|
+
["created_at"],
|
|
729
|
+
["createdAt"],
|
|
730
|
+
["time"],
|
|
731
|
+
["event", "timestamp"]
|
|
732
|
+
]);
|
|
733
|
+
return safeDate(raw, nextTimestamp()) || nextTimestamp();
|
|
734
|
+
}
|
|
735
|
+
function normalizeErrorCode(payload) {
|
|
736
|
+
const code = readKimiFirstNonEmptyString(payload, [["error_code"], ["code"], ["error", "code"]]);
|
|
737
|
+
return code?.trim().toUpperCase().replace(/[^A-Z0-9_]+/g, "_") || "KIMI_WIRE_ERROR";
|
|
738
|
+
}
|
|
739
|
+
function toWireUnavailableError(error) {
|
|
740
|
+
return new Error(`KIMI_WIRE_MODE_UNAVAILABLE: ${extractErrorDetail(error)}`);
|
|
741
|
+
}
|
|
742
|
+
function isWireUnavailableError(error) {
|
|
743
|
+
return error instanceof Error && error.message.startsWith("KIMI_WIRE_MODE_UNAVAILABLE:");
|
|
744
|
+
}
|
|
745
|
+
function extractErrorDetail(error) {
|
|
746
|
+
if (error instanceof Error) {
|
|
747
|
+
return error.message.trim() || "unknown error";
|
|
748
|
+
}
|
|
749
|
+
if (typeof error === "string") {
|
|
750
|
+
return error.trim() || "unknown error";
|
|
751
|
+
}
|
|
752
|
+
return "unknown error";
|
|
753
|
+
}
|
|
754
|
+
function mapInRunSubmitError(error) {
|
|
755
|
+
if (error instanceof Error && error.message === "IN_RUN_INPUT_NOT_SUPPORTED") {
|
|
756
|
+
return error;
|
|
757
|
+
}
|
|
758
|
+
if (isClosedStdinError(error)) {
|
|
759
|
+
return new Error("IN_RUN_INPUT_NOT_SUPPORTED");
|
|
760
|
+
}
|
|
761
|
+
return error instanceof Error ? error : new Error("IN_RUN_INPUT_NOT_SUPPORTED");
|
|
762
|
+
}
|
|
763
|
+
function isClosedStdinError(error) {
|
|
764
|
+
if (!error || typeof error !== "object") {
|
|
765
|
+
return false;
|
|
766
|
+
}
|
|
767
|
+
const code = error.code;
|
|
768
|
+
return (code === "EPIPE" ||
|
|
769
|
+
code === "ECONNRESET" ||
|
|
770
|
+
code === "ERR_STREAM_DESTROYED" ||
|
|
771
|
+
code === "ERR_STREAM_WRITE_AFTER_END");
|
|
772
|
+
}
|
|
773
|
+
function shouldSkipEquivalentRecentKimiRuntimeMessage(recentMessages, message) {
|
|
774
|
+
if (message.kind !== "text" && message.kind !== "thinking") {
|
|
775
|
+
return false;
|
|
776
|
+
}
|
|
777
|
+
const comparableContent = normalizeComparableKimiRuntimeMessageContent(message.content);
|
|
778
|
+
if (!comparableContent) {
|
|
779
|
+
return false;
|
|
780
|
+
}
|
|
781
|
+
return recentMessages.some((item) => item.role === message.role
|
|
782
|
+
&& item.kind === message.kind
|
|
783
|
+
&& item.comparableContent === comparableContent);
|
|
784
|
+
}
|
|
785
|
+
function rememberKimiRuntimeMessage(recentMessages, message) {
|
|
786
|
+
const comparableContent = normalizeComparableKimiRuntimeMessageContent(message.content);
|
|
787
|
+
if (!comparableContent) {
|
|
788
|
+
return;
|
|
789
|
+
}
|
|
790
|
+
recentMessages.push({
|
|
791
|
+
role: message.role,
|
|
792
|
+
kind: message.kind,
|
|
793
|
+
comparableContent
|
|
794
|
+
});
|
|
795
|
+
if (recentMessages.length > 8) {
|
|
796
|
+
recentMessages.splice(0, recentMessages.length - 8);
|
|
797
|
+
}
|
|
798
|
+
}
|
|
799
|
+
function normalizeComparableKimiRuntimeMessageContent(content) {
|
|
800
|
+
const cleaned = extractKimiDisplayTextSegments(content).join("\n\n") || content;
|
|
801
|
+
return cleaned
|
|
802
|
+
.replace(/\r\n/g, "\n")
|
|
803
|
+
.trim()
|
|
804
|
+
.replace(/\s+/g, " ");
|
|
805
|
+
}
|
|
806
|
+
function shouldSpawnViaShell(commandPath) {
|
|
807
|
+
return /\.(cmd|bat|ps1)$/i.test(commandPath);
|
|
808
|
+
}
|
|
809
|
+
function buildKimiSpawnEnv() {
|
|
810
|
+
return {
|
|
811
|
+
...process.env,
|
|
812
|
+
PYTHONIOENCODING: "utf-8",
|
|
813
|
+
PYTHONUTF8: "1"
|
|
814
|
+
};
|
|
815
|
+
}
|
|
816
|
+
function buildPendingKimiBinding(sessionId) {
|
|
817
|
+
const pendingValue = `pending://kimi/${sessionId}`;
|
|
818
|
+
return {
|
|
819
|
+
providerSessionId: pendingValue,
|
|
820
|
+
rawStoreRef: pendingValue
|
|
821
|
+
};
|
|
822
|
+
}
|
|
823
|
+
function buildCommandInputPayloadFromOptions(prompt) {
|
|
824
|
+
return {
|
|
825
|
+
role: "user",
|
|
826
|
+
content: [
|
|
827
|
+
{
|
|
828
|
+
type: "text",
|
|
829
|
+
text: prompt
|
|
830
|
+
}
|
|
831
|
+
]
|
|
832
|
+
};
|
|
833
|
+
}
|
|
834
|
+
function isPendingKimiBinding(value) {
|
|
835
|
+
return value.trim().toLowerCase().startsWith("pending://kimi/");
|
|
836
|
+
}
|
|
837
|
+
function readKimiSessionDirectoryMtime(sessionDir) {
|
|
838
|
+
let mtimeMs = 0;
|
|
839
|
+
for (const fileName of ["state.json", "context.jsonl", "wire.jsonl"]) {
|
|
840
|
+
const filePath = join(sessionDir, fileName);
|
|
841
|
+
if (!existsSync(filePath)) {
|
|
842
|
+
continue;
|
|
843
|
+
}
|
|
844
|
+
mtimeMs = Math.max(mtimeMs, statSync(filePath).mtimeMs);
|
|
845
|
+
}
|
|
846
|
+
return mtimeMs;
|
|
847
|
+
}
|
|
848
|
+
function waitForKimiBindingResolvePoll() {
|
|
849
|
+
return new Promise((resolve) => {
|
|
850
|
+
setTimeout(resolve, KIMI_START_BINDING_RESOLVE_POLL_MS);
|
|
851
|
+
});
|
|
852
|
+
}
|
|
853
|
+
async function detectKimiCliSyntax(input) {
|
|
854
|
+
const helpOutput = await captureKimiCliOutput(input, ["--help"]);
|
|
855
|
+
if (looksLikeModernKimiHelp(helpOutput)) {
|
|
856
|
+
return "modern";
|
|
857
|
+
}
|
|
858
|
+
if (looksLikeLegacyKimiHelp(helpOutput)) {
|
|
859
|
+
return "legacy";
|
|
860
|
+
}
|
|
861
|
+
return "modern";
|
|
862
|
+
}
|
|
863
|
+
async function captureKimiCliOutput(input, probeArgs) {
|
|
864
|
+
return new Promise((resolve) => {
|
|
865
|
+
const proc = input.spawnFactory(input.commandPath, [...input.baseArgs, ...probeArgs], {
|
|
866
|
+
shell: shouldSpawnViaShell(input.commandPath),
|
|
867
|
+
windowsHide: true,
|
|
868
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
869
|
+
});
|
|
870
|
+
let settled = false;
|
|
871
|
+
let stdoutBuffer = "";
|
|
872
|
+
let stderrBuffer = "";
|
|
873
|
+
const finalize = (value) => {
|
|
874
|
+
if (settled) {
|
|
875
|
+
return;
|
|
876
|
+
}
|
|
877
|
+
settled = true;
|
|
878
|
+
clearTimeout(timeout);
|
|
879
|
+
resolve(value);
|
|
880
|
+
};
|
|
881
|
+
const timeout = setTimeout(() => {
|
|
882
|
+
if (!proc.killed) {
|
|
883
|
+
proc.kill("SIGTERM");
|
|
884
|
+
}
|
|
885
|
+
finalize(`${stdoutBuffer}\n${stderrBuffer}`.trim());
|
|
886
|
+
}, Math.max(200, input.timeoutMs));
|
|
887
|
+
proc.stdout.setEncoding("utf8");
|
|
888
|
+
proc.stdout.on("data", (chunk) => {
|
|
889
|
+
stdoutBuffer += chunk;
|
|
890
|
+
});
|
|
891
|
+
proc.stderr.setEncoding("utf8");
|
|
892
|
+
proc.stderr.on("data", (chunk) => {
|
|
893
|
+
stderrBuffer += chunk;
|
|
894
|
+
});
|
|
895
|
+
proc.once("error", () => {
|
|
896
|
+
finalize(`${stdoutBuffer}\n${stderrBuffer}`.trim());
|
|
897
|
+
});
|
|
898
|
+
proc.once("close", () => {
|
|
899
|
+
finalize(`${stdoutBuffer}\n${stderrBuffer}`.trim());
|
|
900
|
+
});
|
|
901
|
+
});
|
|
902
|
+
}
|
|
903
|
+
function looksLikeModernKimiHelp(output) {
|
|
904
|
+
const normalized = output.toLowerCase();
|
|
905
|
+
return normalized.includes("--wire") || normalized.includes("--work-dir");
|
|
906
|
+
}
|
|
907
|
+
function looksLikeLegacyKimiHelp(output) {
|
|
908
|
+
const normalized = output.toLowerCase();
|
|
909
|
+
return normalized.includes("--cwd") || normalized.includes("no such command 'wire'");
|
|
910
|
+
}
|
|
911
|
+
//# sourceMappingURL=kimi-runtime.js.map
|