kimi-plugin-cc 2.0.7 → 2.2.0
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/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/CHANGELOG.md +50 -0
- package/README.md +22 -6
- package/agents/kimi-ask.md +3 -0
- package/agents/kimi-challenge.md +3 -1
- package/agents/kimi-rescue.md +3 -0
- package/agents/kimi-review.md +3 -1
- package/commands/ask.md +6 -2
- package/commands/challenge.md +6 -2
- package/commands/rescue.md +6 -2
- package/commands/review.md +6 -2
- package/dist/cli-client.js +36 -13
- package/dist/commands/ask.js +16 -7
- package/dist/commands/cli-helpers.js +80 -0
- package/dist/commands/pursue.js +4 -2
- package/dist/commands/repair-sessions.js +2 -1
- package/dist/commands/replay.js +3 -2
- package/dist/commands/rescue.js +19 -9
- package/dist/commands/result.js +7 -1
- package/dist/commands/review-gate.js +2 -1
- package/dist/commands/review.js +8 -5
- package/dist/commands/setup.js +2 -1
- package/dist/commands/status.js +2 -2
- package/dist/commands/swarm.js +7 -3
- package/dist/companion.js +6 -0
- package/dist/help.js +40 -0
- package/dist/hooks/config-safety.js +18 -9
- package/dist/job-store.js +43 -6
- package/dist/jobs.js +7 -3
- package/dist/kimi-engine.js +1 -0
- package/dist/kimi-errors.js +35 -1
- package/dist/kimi-timeouts.js +7 -7
- package/dist/parsing.js +87 -13
- package/dist/render.js +19 -1
- package/dist/session-recovery.js +203 -0
- package/dist/vendor/smol-toml/date.js +50 -21
- package/dist/vendor/smol-toml/error.js +6 -2
- package/dist/vendor/smol-toml/extract.js +259 -66
- package/dist/vendor/smol-toml/parse.js +64 -48
- package/dist/vendor/smol-toml/primitive.js +107 -135
- package/dist/vendor/smol-toml/struct.js +106 -134
- package/dist/vendor/smol-toml/util.js +22 -78
- package/dist/version.js +1 -1
- package/docs/migration.md +3 -3
- package/docs/registry-releases.md +35 -1
- package/docs/safety.md +49 -2
- package/package.json +2 -2
- package/plugins/kimi-codex/.codex-plugin/plugin.json +1 -1
- package/plugins/kimi-codex/dist/cli-client.js +36 -13
- package/plugins/kimi-codex/dist/commands/ask.js +16 -7
- package/plugins/kimi-codex/dist/commands/cli-helpers.js +80 -0
- package/plugins/kimi-codex/dist/commands/pursue.js +4 -2
- package/plugins/kimi-codex/dist/commands/repair-sessions.js +2 -1
- package/plugins/kimi-codex/dist/commands/replay.js +3 -2
- package/plugins/kimi-codex/dist/commands/rescue.js +19 -9
- package/plugins/kimi-codex/dist/commands/result.js +7 -1
- package/plugins/kimi-codex/dist/commands/review-gate.js +2 -1
- package/plugins/kimi-codex/dist/commands/review.js +8 -5
- package/plugins/kimi-codex/dist/commands/setup.js +2 -1
- package/plugins/kimi-codex/dist/commands/status.js +2 -2
- package/plugins/kimi-codex/dist/commands/swarm.js +7 -3
- package/plugins/kimi-codex/dist/companion.js +6 -0
- package/plugins/kimi-codex/dist/help.js +40 -0
- package/plugins/kimi-codex/dist/hooks/config-safety.js +18 -9
- package/plugins/kimi-codex/dist/job-store.js +43 -6
- package/plugins/kimi-codex/dist/jobs.js +7 -3
- package/plugins/kimi-codex/dist/kimi-engine.js +1 -0
- package/plugins/kimi-codex/dist/kimi-errors.js +35 -1
- package/plugins/kimi-codex/dist/kimi-timeouts.js +7 -7
- package/plugins/kimi-codex/dist/parsing.js +87 -13
- package/plugins/kimi-codex/dist/render.js +19 -1
- package/plugins/kimi-codex/dist/session-recovery.js +203 -0
- package/plugins/kimi-codex/dist/vendor/smol-toml/date.js +50 -21
- package/plugins/kimi-codex/dist/vendor/smol-toml/error.js +6 -2
- package/plugins/kimi-codex/dist/vendor/smol-toml/extract.js +259 -66
- package/plugins/kimi-codex/dist/vendor/smol-toml/parse.js +64 -48
- package/plugins/kimi-codex/dist/vendor/smol-toml/primitive.js +107 -135
- package/plugins/kimi-codex/dist/vendor/smol-toml/struct.js +106 -134
- package/plugins/kimi-codex/dist/vendor/smol-toml/util.js +22 -78
- package/plugins/kimi-codex/dist/version.js +1 -1
- package/plugins/kimi-codex/skills/kimi-ask/SKILL.md +3 -1
- package/plugins/kimi-codex/skills/kimi-challenge/SKILL.md +2 -1
- package/plugins/kimi-codex/skills/kimi-rescue/SKILL.md +3 -1
- package/plugins/kimi-codex/skills/kimi-review/SKILL.md +3 -2
|
@@ -84,7 +84,9 @@ export async function runCliPrompt(opts) {
|
|
|
84
84
|
});
|
|
85
85
|
}
|
|
86
86
|
let child;
|
|
87
|
+
let spawnedAt;
|
|
87
88
|
try {
|
|
89
|
+
spawnedAt = Date.now();
|
|
88
90
|
child = spawn(opts.command, args, {
|
|
89
91
|
cwd: opts.cwd,
|
|
90
92
|
env,
|
|
@@ -329,7 +331,7 @@ export async function runCliPrompt(opts) {
|
|
|
329
331
|
return;
|
|
330
332
|
}
|
|
331
333
|
if (kind === "resolve")
|
|
332
|
-
resolve(payload);
|
|
334
|
+
resolve({ ...payload, settledAt: Date.now() });
|
|
333
335
|
else
|
|
334
336
|
reject(payload);
|
|
335
337
|
});
|
|
@@ -580,6 +582,8 @@ export async function runCliPrompt(opts) {
|
|
|
580
582
|
// The result itself is in memory; diagnostics are best-effort.
|
|
581
583
|
await raceWithTimeout(logChain, LOG_DRAIN_TIMEOUT_MS);
|
|
582
584
|
settle("resolve", {
|
|
585
|
+
spawnedAt,
|
|
586
|
+
settledAt: 0, // Filled at settlement, after the teardown barrier.
|
|
583
587
|
sessionId,
|
|
584
588
|
goalSummary: announcedGoalSummary,
|
|
585
589
|
systemVersion: announcedSystemVersion,
|
|
@@ -656,6 +660,27 @@ export function requireSessionId(result, context) {
|
|
|
656
660
|
},
|
|
657
661
|
});
|
|
658
662
|
}
|
|
663
|
+
/** Settled timeout data; stream records are deliberately non-serializable.
|
|
664
|
+
* Without a partial result (teardown rejection), aborted means abort was issued,
|
|
665
|
+
* not that the process was observed aborting. */
|
|
666
|
+
export class ResponseTimeoutError extends RuntimeError {
|
|
667
|
+
constructor(budgetMs, stage, commandLabel, partialResult, cause) {
|
|
668
|
+
super("RESPONSE_TIMEOUT", `${stage} timed out after ${budgetMs}ms.`, stage, {
|
|
669
|
+
...(cause instanceof Error ? { cause } : {}),
|
|
670
|
+
details: {
|
|
671
|
+
budget_ms: budgetMs,
|
|
672
|
+
command_label: commandLabel ?? null,
|
|
673
|
+
record_count: partialResult?.records.length ?? 0,
|
|
674
|
+
partial_output_chars: partialResult?.records.reduce((count, record) => count + (record.role === "assistant" && typeof record.content === "string" ? record.content.length : 0), 0) ?? 0,
|
|
675
|
+
aborted: partialResult?.aborted ?? true,
|
|
676
|
+
...(partialResult ? { settled_post_abort: true } : {}),
|
|
677
|
+
},
|
|
678
|
+
});
|
|
679
|
+
this.name = "ResponseTimeoutError";
|
|
680
|
+
// Never serialize stream records into job error details or error envelopes.
|
|
681
|
+
Object.defineProperty(this, "partialResult", { value: partialResult, enumerable: false });
|
|
682
|
+
}
|
|
683
|
+
}
|
|
659
684
|
/**
|
|
660
685
|
* Run `kimi -p` under a budget that also tells the subprocess to die
|
|
661
686
|
* when the budget expires.
|
|
@@ -682,7 +707,8 @@ export function requireSessionId(result, context) {
|
|
|
682
707
|
* subprocess/tree teardown, then reject with
|
|
683
708
|
* `RuntimeError("RESPONSE_TIMEOUT", …)` matching the legacy
|
|
684
709
|
* `withTimeout` code shape.
|
|
685
|
-
* -
|
|
710
|
+
* - A clean non-aborted exit-0 result wins same-tick budget expiry.
|
|
711
|
+
* Otherwise a settled result on timeout is carried as partial output.
|
|
686
712
|
*/
|
|
687
713
|
export async function runCliPromptWithBudget(opts, budgetMs, stage) {
|
|
688
714
|
const controller = new AbortController();
|
|
@@ -698,12 +724,7 @@ export async function runCliPromptWithBudget(opts, budgetMs, stage) {
|
|
|
698
724
|
controller.abort();
|
|
699
725
|
}, budgetMs);
|
|
700
726
|
timer.unref();
|
|
701
|
-
const timeoutError = (
|
|
702
|
-
details: {
|
|
703
|
-
budget_ms: budgetMs,
|
|
704
|
-
command_label: opts.commandLabel ?? null,
|
|
705
|
-
},
|
|
706
|
-
});
|
|
727
|
+
const timeoutError = (partialResult, cause) => new ResponseTimeoutError(budgetMs, stage, opts.commandLabel, partialResult, cause);
|
|
707
728
|
try {
|
|
708
729
|
let result;
|
|
709
730
|
try {
|
|
@@ -714,13 +735,13 @@ export async function runCliPromptWithBudget(opts, budgetMs, stage) {
|
|
|
714
735
|
}
|
|
715
736
|
catch (error) {
|
|
716
737
|
if (timeoutFired)
|
|
717
|
-
throw timeoutError();
|
|
738
|
+
throw timeoutError(undefined, error);
|
|
718
739
|
throw error;
|
|
719
740
|
}
|
|
720
|
-
if (timeoutFired) {
|
|
721
|
-
//
|
|
722
|
-
//
|
|
723
|
-
throw timeoutError(
|
|
741
|
+
if (timeoutFired && (result.aborted || result.exitCode !== 0)) {
|
|
742
|
+
// A clean, non-aborted result won the settle/timeout boundary and is success.
|
|
743
|
+
// Budget aborts normally resolve with records, after owned teardown settles.
|
|
744
|
+
throw timeoutError(result);
|
|
724
745
|
}
|
|
725
746
|
return result;
|
|
726
747
|
}
|
|
@@ -770,6 +791,8 @@ function buildArgs(opts) {
|
|
|
770
791
|
}
|
|
771
792
|
function buildEnv(opts) {
|
|
772
793
|
const env = { ...opts.env };
|
|
794
|
+
// 2.2.0 audit: ambient trust starts project MCP stdio servers outside PreToolUse.
|
|
795
|
+
delete env.KIMI_CODE_TRUST_WORKSPACE;
|
|
773
796
|
// kimi-code 0.33.0 inverted its CLI engine default: an unflagged `kimi -p`
|
|
774
797
|
// now selects native agent-core-v2, while this upstream-documented flag pins
|
|
775
798
|
// the legacy-v1 path. Native v2 still has a final-allow plan-file path that
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { companionHelp } from "../help.js";
|
|
1
2
|
import { randomUUID } from "node:crypto";
|
|
2
3
|
import path from "node:path";
|
|
3
4
|
import { createCliCancellationHandlers } from "../cli-cancellation.js";
|
|
@@ -16,7 +17,7 @@ import { readArtifact, renderManagedJobOutput, writeArtifact } from "../render.j
|
|
|
16
17
|
import { classifyManagedCommandFailure } from "../kimi-errors.js";
|
|
17
18
|
import { startBackgroundJob } from "../background-spawn.js";
|
|
18
19
|
import { hookRefusalDetails, hookRefusalRetryProtocol, maybeWarnHookMissing, verifyHookInstalled, } from "../hooks/install.js";
|
|
19
|
-
import { assertCliResultSuccess, reassembleProseFromRecords, warnIfSessionIdMissing } from "./cli-helpers.js";
|
|
20
|
+
import { warnInheritedBudget, captureTimeoutPartialOutput, assertCliResultSuccess, reassembleProseFromRecords, warnIfSessionIdMissing } from "./cli-helpers.js";
|
|
20
21
|
import { buildKimiSessionTitle, syncKimiSessionTitle } from "../session-title.js";
|
|
21
22
|
// v1.0 cutover note (PR 2):
|
|
22
23
|
//
|
|
@@ -46,6 +47,8 @@ const ASK_PROMPT_PREFIX = [
|
|
|
46
47
|
].join("\n");
|
|
47
48
|
export async function runAsk(argv, context) {
|
|
48
49
|
const parsed = parseAskArgs(argv);
|
|
50
|
+
if (parsed.help)
|
|
51
|
+
return companionHelp(["ask", ...argv]);
|
|
49
52
|
if (context.env.KIMI_PLUGIN_CC_SKIP_HOOK_CHECK !== "1") {
|
|
50
53
|
await requireAskHookInstalled(context);
|
|
51
54
|
}
|
|
@@ -76,10 +79,14 @@ export async function runAsk(argv, context) {
|
|
|
76
79
|
model: parsed.model ?? null,
|
|
77
80
|
thinking: parsed.thinking ?? null,
|
|
78
81
|
background: parsed.background,
|
|
82
|
+
budget_ms: parsed.budgetMs ?? (sessionResolution.sourceJob?.operation_kind === "ask" ? sessionResolution.sourceJob.budget_ms : null) ?? null,
|
|
83
|
+
budget_source: parsed.budgetMs !== undefined ? "explicit"
|
|
84
|
+
: sessionResolution.sourceJob?.operation_kind === "ask" && sessionResolution.sourceJob.budget_ms !== null ? "inherited" : "default",
|
|
79
85
|
pid: parsed.background ? null : process.pid,
|
|
80
86
|
kimi_pid: null,
|
|
81
87
|
status: "running",
|
|
82
88
|
kimi_session_id: sessionResolution.kimiSessionId,
|
|
89
|
+
kimi_session_id_source: sessionResolution.sourceJob?.kimi_session_id_source ?? null,
|
|
83
90
|
...persistedExecutionPlanFields(executionPlan),
|
|
84
91
|
agent_profile: ASK_AGENT_PROFILE_PLACEHOLDER,
|
|
85
92
|
prompt_digest: digestPrompt(askPrompt),
|
|
@@ -101,6 +108,7 @@ export async function runAsk(argv, context) {
|
|
|
101
108
|
await markJobFailed(store, paths, job, classified, askConfig.cancellation.failedSummary, { phase: "failed" });
|
|
102
109
|
throw classified;
|
|
103
110
|
}
|
|
111
|
+
warnInheritedBudget(job, context.stderr);
|
|
104
112
|
if (parsed.background) {
|
|
105
113
|
return startBackgroundJob(job, askPrompt, context, paths, {
|
|
106
114
|
workerKind: "ask",
|
|
@@ -169,7 +177,7 @@ export async function executeAskJob(jobId, prompt, context, options) {
|
|
|
169
177
|
resumeSessionId: job.kimi_session_id ?? undefined,
|
|
170
178
|
logPath: job.stream_log_path,
|
|
171
179
|
signal: handlers.signal,
|
|
172
|
-
}, KIMI_ASK_PROMPT_TIMEOUT_MS, "ask.prompt");
|
|
180
|
+
}, job.budget_ms ?? KIMI_ASK_PROMPT_TIMEOUT_MS, "ask.prompt");
|
|
173
181
|
store.updateRunningJob(job.job_id, observedExecutionFields(result));
|
|
174
182
|
if (handlers.cancelling) {
|
|
175
183
|
throw new RuntimeError(cancel.errorCodes.cancelled, cancel.cancelMessages.afterPrompt, "ask.runtime");
|
|
@@ -180,12 +188,11 @@ export async function executeAskJob(jobId, prompt, context, options) {
|
|
|
180
188
|
// sessions it should match the input, but capture anyway in case
|
|
181
189
|
// kimi-code mints a new id on each turn.
|
|
182
190
|
if (result.sessionId !== undefined &&
|
|
183
|
-
result.sessionId.length > 0
|
|
184
|
-
result.sessionId !== job.kimi_session_id) {
|
|
191
|
+
result.sessionId.length > 0) {
|
|
185
192
|
// length>0 guard: empty-string capture would poison the row. The
|
|
186
193
|
// warning helper's null-ish check would also fire but only after
|
|
187
194
|
// the bad write. (Kimi alpha.4 challenge finding #3.)
|
|
188
|
-
store.updateRunningJob(job.job_id, { kimi_session_id: result.sessionId });
|
|
195
|
+
store.updateRunningJob(job.job_id, { kimi_session_id_source: "announced", kimi_session_id: result.sessionId });
|
|
189
196
|
}
|
|
190
197
|
await syncKimiSessionTitle({
|
|
191
198
|
promptText: prompt,
|
|
@@ -215,6 +222,9 @@ export async function executeAskJob(jobId, prompt, context, options) {
|
|
|
215
222
|
}) ?? job);
|
|
216
223
|
}
|
|
217
224
|
catch (error) {
|
|
225
|
+
const classified = error instanceof RuntimeError && error.stage === "ask.hook-check" ? error
|
|
226
|
+
: classifyManagedCommandFailure(error, "ask", job.job_id, { background: job.background, budgetMs: job.budget_ms ?? KIMI_ASK_PROMPT_TIMEOUT_MS });
|
|
227
|
+
const partialOutput = await captureTimeoutPartialOutput(classified, store, job, context.env, handlers?.signal);
|
|
218
228
|
if (handlers?.cancelling) {
|
|
219
229
|
const cancelledError = new RuntimeError(cancel.errorCodes.cancelled, cancel.cancelMessages.default, "ask.runtime", error instanceof Error ? { cause: error } : undefined);
|
|
220
230
|
return await markJobCancelled(store, paths, job, cancel.cancelledSummary, cancelledError, { phase: "cancelled" });
|
|
@@ -227,8 +237,7 @@ export async function executeAskJob(jobId, prompt, context, options) {
|
|
|
227
237
|
await markJobFailed(store, paths, job, error, cancel.failedSummary, { phase: "failed" });
|
|
228
238
|
throw error;
|
|
229
239
|
}
|
|
230
|
-
|
|
231
|
-
await markJobFailed(store, paths, job, classified, cancel.failedSummary, { phase: "failed" });
|
|
240
|
+
await markJobFailed(store, paths, job, classified, cancel.failedSummary, { phase: "failed", partialOutput });
|
|
232
241
|
throw classified;
|
|
233
242
|
}
|
|
234
243
|
finally {
|
|
@@ -1,4 +1,9 @@
|
|
|
1
1
|
import { RuntimeError } from "../errors.js";
|
|
2
|
+
import { ResponseTimeoutError } from "../cli-client.js";
|
|
3
|
+
import { observedExecutionFields } from "../kimi-engine.js";
|
|
4
|
+
import { resolveKimiHome } from "../kimi-home.js";
|
|
5
|
+
import { recoverSessionIdFromStore } from "../session-recovery.js";
|
|
6
|
+
import { formatBudgetDuration } from "../render.js";
|
|
2
7
|
/**
|
|
3
8
|
* Reassemble prose final text from cli-client records.
|
|
4
9
|
*
|
|
@@ -110,3 +115,78 @@ export function assertCliResultSuccess(result, stage) {
|
|
|
110
115
|
});
|
|
111
116
|
}
|
|
112
117
|
}
|
|
118
|
+
/** Timeout-only capture. Cancellation takes precedence, including while the
|
|
119
|
+
* asynchronous store scan is in flight. No title sync on failure. */
|
|
120
|
+
export async function captureTimeoutPartialOutput(classified, store, job, env, cancellationSignal) {
|
|
121
|
+
if (cancellationSignal?.aborted)
|
|
122
|
+
return undefined;
|
|
123
|
+
const timeout = classified.cause;
|
|
124
|
+
if (!(timeout instanceof ResponseTimeoutError) || !timeout.partialResult)
|
|
125
|
+
return undefined;
|
|
126
|
+
const result = timeout.partialResult;
|
|
127
|
+
let sessionId = result.sessionId;
|
|
128
|
+
let source = sessionId ? "announced" : null;
|
|
129
|
+
const details = classified instanceof RuntimeError ? classified.details : timeout.details;
|
|
130
|
+
details.kimi_session_id_source = job.kimi_session_id_source;
|
|
131
|
+
// The persisted plan is plugin-owned. Recovery never runs on cancellation,
|
|
132
|
+
// v1, successful turns, teardown rejection, or an already-known resume id.
|
|
133
|
+
if (!sessionId && !job.kimi_session_id && job.intended_engine === "native-v2") {
|
|
134
|
+
// Without the system.version marker the row has no proven engine, and
|
|
135
|
+
// resume would refuse the id as lineage-unknown; do not advertise one.
|
|
136
|
+
if (result.observedEngine === null) {
|
|
137
|
+
details.session_recovery = "engine_unobserved";
|
|
138
|
+
}
|
|
139
|
+
else {
|
|
140
|
+
const recovered = await recoverSessionIdFromStore({
|
|
141
|
+
kimiHome: resolveKimiHome(env, job.cwd), cwd: job.cwd,
|
|
142
|
+
spawnedAt: result.spawnedAt, settledAt: result.settledAt, promptDigest: job.prompt_digest,
|
|
143
|
+
store, jobId: job.job_id,
|
|
144
|
+
});
|
|
145
|
+
sessionId = recovered.sessionId;
|
|
146
|
+
if (sessionId)
|
|
147
|
+
source = "recovered_session_dir";
|
|
148
|
+
else
|
|
149
|
+
details.session_recovery = recovered.reason;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
if (cancellationSignal?.aborted)
|
|
153
|
+
return undefined;
|
|
154
|
+
// Best-effort metadata only. The row is still `running`, and a session id
|
|
155
|
+
// written here can collide with `jobs_running_session_idx` when a resume of
|
|
156
|
+
// the same session was started while this job ran. A store error must never
|
|
157
|
+
// prevent markJobFailed from running — the partial artifact matters more
|
|
158
|
+
// than the metadata, so swallow and fall through.
|
|
159
|
+
try {
|
|
160
|
+
store.updateRunningJob(job.job_id, observedExecutionFields(result));
|
|
161
|
+
if (sessionId) {
|
|
162
|
+
const updated = source === "recovered_session_dir"
|
|
163
|
+
? store.claimRecoveredSessionId(job.job_id, sessionId)
|
|
164
|
+
: store.updateRunningJob(job.job_id, { kimi_session_id: sessionId, kimi_session_id_source: source });
|
|
165
|
+
if (updated?.kimi_session_id === sessionId && updated.kimi_session_id_source === source) {
|
|
166
|
+
details.kimi_session_id = sessionId;
|
|
167
|
+
details.kimi_session_id_source = source;
|
|
168
|
+
}
|
|
169
|
+
else
|
|
170
|
+
details[source === "recovered_session_dir" ? "session_recovery" : "session_id_persistence"] = "persistence_failed";
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
catch {
|
|
174
|
+
// `session_recovery` describes only the recovery branch; an announced id or
|
|
175
|
+
// the provenance update failing is a different fact.
|
|
176
|
+
details[source === "recovered_session_dir" ? "session_recovery" : "session_id_persistence"] = "persistence_failed";
|
|
177
|
+
// Diagnostics stay in the stream log; the failure transition proceeds.
|
|
178
|
+
}
|
|
179
|
+
return {
|
|
180
|
+
text: reassembleProseFromRecords(result.records),
|
|
181
|
+
toolCalls: result.records.some((record) => record.role === "tool" ||
|
|
182
|
+
(record.role === "assistant" && Array.isArray(record.tool_calls) &&
|
|
183
|
+
record.tool_calls.length > 0)),
|
|
184
|
+
recordCount: result.records.length,
|
|
185
|
+
budgetMs: timeout.details.budget_ms,
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
export function warnInheritedBudget(job, stderr) {
|
|
189
|
+
if (job.budget_source === "inherited" && job.budget_ms !== null) {
|
|
190
|
+
stderr.write(`[${job.command_type}] budget ${formatBudgetDuration(job.budget_ms)} inherited from job ${job.resumed_from_job_id}; pass --budget to override\n`);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
@@ -143,6 +143,8 @@ export async function runPursue(argv, context) {
|
|
|
143
143
|
model: parsed.model ?? null,
|
|
144
144
|
thinking: parsed.thinking ?? null,
|
|
145
145
|
background: false,
|
|
146
|
+
budget_ms: parsed.budgetMs ?? KIMI_PURSUE_DEFAULT_BUDGET_MS,
|
|
147
|
+
budget_source: parsed.budgetMs !== undefined ? "explicit" : "default",
|
|
146
148
|
pid: process.pid,
|
|
147
149
|
kimi_pid: null,
|
|
148
150
|
status: "running",
|
|
@@ -168,7 +170,7 @@ export async function runPursue(argv, context) {
|
|
|
168
170
|
await markJobFailed(store, paths, job, classified, "Pursue failed.", { phase: "failed" });
|
|
169
171
|
throw classified;
|
|
170
172
|
}
|
|
171
|
-
const completed = await executePursueJob(job.job_id, prompt, objective,
|
|
173
|
+
const completed = await executePursueJob(job.job_id, prompt, objective, job.budget_ms, context);
|
|
172
174
|
if (!completed.final_output_path) {
|
|
173
175
|
throw new RuntimeError("PURSUE_RESULT_MISSING", "Pursue finished without a rendered result.", "pursue.result");
|
|
174
176
|
}
|
|
@@ -249,7 +251,7 @@ async function executePursueJob(jobId, prompt, objective, budgetMs, context) {
|
|
|
249
251
|
if (result.sessionId !== undefined &&
|
|
250
252
|
result.sessionId.length > 0 &&
|
|
251
253
|
result.sessionId !== job.kimi_session_id) {
|
|
252
|
-
store.updateRunningJob(job.job_id, { kimi_session_id: result.sessionId });
|
|
254
|
+
store.updateRunningJob(job.job_id, { kimi_session_id_source: "announced", kimi_session_id: result.sessionId });
|
|
253
255
|
}
|
|
254
256
|
await syncKimiSessionTitle({
|
|
255
257
|
promptText: objective,
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { REPAIR_SESSIONS_SUPPORTED_FLAGS } from "../parsing.js";
|
|
1
2
|
import { constants } from "node:fs";
|
|
2
3
|
import { lstat, open } from "node:fs/promises";
|
|
3
4
|
import { createRequire } from "node:module";
|
|
@@ -15,7 +16,7 @@ export async function runRepairSessions(argv, context) {
|
|
|
15
16
|
const seen = new Set();
|
|
16
17
|
for (const arg of argv) {
|
|
17
18
|
if ((arg !== "--apply" && arg !== "--all") || seen.has(arg)) {
|
|
18
|
-
throw new RuntimeError("INVALID_ARGS",
|
|
19
|
+
throw new RuntimeError("INVALID_ARGS", `Usage: repair-sessions. Supported flags: ${REPAIR_SESSIONS_SUPPORTED_FLAGS}.`, "repair-sessions.args");
|
|
19
20
|
}
|
|
20
21
|
seen.add(arg);
|
|
21
22
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { REPLAY_SUPPORTED_FLAGS } from "../parsing.js";
|
|
1
2
|
import { access, stat, readFile } from "node:fs/promises";
|
|
2
3
|
import { constants as fsConstants } from "node:fs";
|
|
3
4
|
import { RuntimeError } from "../errors.js";
|
|
@@ -9,8 +10,8 @@ import { sweepStaleJobs } from "../jobs.js";
|
|
|
9
10
|
const MAX_REPLAY_LOG_BYTES = 32 * 1024 * 1024;
|
|
10
11
|
export async function runReplay(argv, context) {
|
|
11
12
|
const [jobId, ...rest] = argv;
|
|
12
|
-
if (!jobId || rest.length > 0) {
|
|
13
|
-
throw new RuntimeError("INVALID_ARGS",
|
|
13
|
+
if (!jobId || jobId.startsWith("-") || rest.length > 0) {
|
|
14
|
+
throw new RuntimeError("INVALID_ARGS", `replay expects exactly one job id: replay <job-id>. Supported flags: ${REPLAY_SUPPORTED_FLAGS}.`, "replay.parse");
|
|
14
15
|
}
|
|
15
16
|
const paths = resolvePluginPaths(context.env);
|
|
16
17
|
await ensurePluginPaths(paths);
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { companionHelp } from "../help.js";
|
|
1
2
|
import { randomUUID } from "node:crypto";
|
|
2
3
|
import path from "node:path";
|
|
3
4
|
import { createCliCancellationHandlers } from "../cli-cancellation.js";
|
|
@@ -16,7 +17,7 @@ import { parseRescueArgs } from "../parsing.js";
|
|
|
16
17
|
import { readArtifact, renderManagedJobOutput, writeArtifact } from "../render.js";
|
|
17
18
|
import { startBackgroundJob } from "../background-spawn.js";
|
|
18
19
|
import { hookRefusalDetails, hookRefusalRetryProtocol, maybeWarnHookMissing, verifyHookInstalled, } from "../hooks/install.js";
|
|
19
|
-
import { assertCliResultSuccess, reassembleProseFromRecords, warnIfSessionIdMissing } from "./cli-helpers.js";
|
|
20
|
+
import { warnInheritedBudget, captureTimeoutPartialOutput, assertCliResultSuccess, reassembleProseFromRecords, warnIfSessionIdMissing } from "./cli-helpers.js";
|
|
20
21
|
import { buildKimiSessionTitle, syncKimiSessionTitle } from "../session-title.js";
|
|
21
22
|
export { describeMissingResult } from "../background-spawn.js";
|
|
22
23
|
// v1.0 cutover note (PR 3):
|
|
@@ -41,6 +42,8 @@ const RESCUE_SUMMARY_MAX = 120;
|
|
|
41
42
|
const RESCUE_AGENT_PROFILE_PLACEHOLDER = "<cli-client>";
|
|
42
43
|
export async function runRescue(argv, context) {
|
|
43
44
|
const parsed = parseRescueArgs(argv);
|
|
45
|
+
if (parsed.help)
|
|
46
|
+
return companionHelp(["task", "rescue", ...argv]);
|
|
44
47
|
const paths = resolvePluginPaths(context.env);
|
|
45
48
|
await ensurePluginPaths(paths);
|
|
46
49
|
const repoIdentity = await resolveRepoIdentity(context.cwd);
|
|
@@ -68,10 +71,14 @@ export async function runRescue(argv, context) {
|
|
|
68
71
|
model: parsed.model ?? null,
|
|
69
72
|
thinking: parsed.thinking ?? null,
|
|
70
73
|
background: parsed.background,
|
|
74
|
+
budget_ms: parsed.budgetMs ?? (sessionResolution.sourceJob?.operation_kind === "rescue" ? sessionResolution.sourceJob.budget_ms : null) ?? null,
|
|
75
|
+
budget_source: parsed.budgetMs !== undefined ? "explicit"
|
|
76
|
+
: sessionResolution.sourceJob?.operation_kind === "rescue" && sessionResolution.sourceJob.budget_ms !== null ? "inherited" : "default",
|
|
71
77
|
pid: parsed.background ? null : process.pid,
|
|
72
78
|
kimi_pid: null,
|
|
73
79
|
status: "running",
|
|
74
80
|
kimi_session_id: sessionResolution.kimiSessionId,
|
|
81
|
+
kimi_session_id_source: sessionResolution.sourceJob?.kimi_session_id_source ?? null,
|
|
75
82
|
...persistedExecutionPlanFields(executionPlan),
|
|
76
83
|
agent_profile: RESCUE_AGENT_PROFILE_PLACEHOLDER,
|
|
77
84
|
prompt_digest: digestPrompt(prompt),
|
|
@@ -93,6 +100,7 @@ export async function runRescue(argv, context) {
|
|
|
93
100
|
await markJobFailed(store, paths, job, classified, rescueConfig.cancellation.failedSummary, { phase: "failed" });
|
|
94
101
|
throw classified;
|
|
95
102
|
}
|
|
103
|
+
warnInheritedBudget(job, context.stderr);
|
|
96
104
|
if (parsed.background) {
|
|
97
105
|
return startBackgroundJob(job, prompt, context, paths, {
|
|
98
106
|
workerKind: "rescue",
|
|
@@ -185,18 +193,17 @@ export async function executeRescueJob(jobId, prompt, context, options) {
|
|
|
185
193
|
signal: handlers.signal,
|
|
186
194
|
// SIGKILL escalation defaults to 1500ms inside cli-client —
|
|
187
195
|
// matches v0.4's cancellation.ts behavior for the wire client.
|
|
188
|
-
}, KIMI_RESCUE_PROMPT_TIMEOUT_MS, "rescue.prompt");
|
|
196
|
+
}, job.budget_ms ?? KIMI_RESCUE_PROMPT_TIMEOUT_MS, "rescue.prompt");
|
|
189
197
|
store.updateRunningJob(job.job_id, observedExecutionFields(result));
|
|
190
198
|
if (handlers.cancelling) {
|
|
191
199
|
throw new RuntimeError(cancel.errorCodes.cancelled, cancel.cancelMessages.afterPrompt, "rescue.runtime");
|
|
192
200
|
}
|
|
193
201
|
assertCliResultSuccess(result, "rescue.runtime");
|
|
194
202
|
if (result.sessionId !== undefined &&
|
|
195
|
-
result.sessionId.length > 0
|
|
196
|
-
result.sessionId !== job.kimi_session_id) {
|
|
203
|
+
result.sessionId.length > 0) {
|
|
197
204
|
// length>0 guard: empty-string capture would poison the row. (Kimi
|
|
198
205
|
// alpha.4 challenge finding #3.)
|
|
199
|
-
store.updateRunningJob(job.job_id, { kimi_session_id: result.sessionId });
|
|
206
|
+
store.updateRunningJob(job.job_id, { kimi_session_id_source: "announced", kimi_session_id: result.sessionId });
|
|
200
207
|
}
|
|
201
208
|
await syncKimiSessionTitle({
|
|
202
209
|
promptText: prompt,
|
|
@@ -242,14 +249,17 @@ export async function executeRescueJob(jobId, prompt, context, options) {
|
|
|
242
249
|
}) ?? job);
|
|
243
250
|
}
|
|
244
251
|
catch (error) {
|
|
252
|
+
const classified = classifyManagedCommandFailure(error, "rescue", job.job_id, {
|
|
253
|
+
preserveStage: true,
|
|
254
|
+
background: job.background,
|
|
255
|
+
budgetMs: job.budget_ms ?? KIMI_RESCUE_PROMPT_TIMEOUT_MS,
|
|
256
|
+
});
|
|
257
|
+
const partialOutput = await captureTimeoutPartialOutput(classified, store, job, context.env, handlers.signal);
|
|
245
258
|
if (handlers.cancelling) {
|
|
246
259
|
const cancelledError = new RuntimeError(cancel.errorCodes.cancelled, cancel.cancelMessages.default, "rescue.runtime", error instanceof Error ? { cause: error } : undefined);
|
|
247
260
|
return await markJobCancelled(store, paths, job, cancel.cancelledSummary, cancelledError, { phase: "cancelled" });
|
|
248
261
|
}
|
|
249
|
-
|
|
250
|
-
preserveStage: true,
|
|
251
|
-
});
|
|
252
|
-
return await markJobFailed(store, paths, job, classified, cancel.failedSummary, { phase: "failed" });
|
|
262
|
+
return await markJobFailed(store, paths, job, classified, cancel.failedSummary, { phase: "failed", partialOutput });
|
|
253
263
|
}
|
|
254
264
|
finally {
|
|
255
265
|
handlers.dispose();
|
|
@@ -2,7 +2,7 @@ import { RuntimeError } from "../errors.js";
|
|
|
2
2
|
import { resolveRepoIdentity } from "../git.js";
|
|
3
3
|
import { sweepStaleJobs } from "../jobs.js";
|
|
4
4
|
import { reconcileHistoricalJobProvenance } from "../kimi-engine.js";
|
|
5
|
-
import { withJobStore } from "../job-store.js";
|
|
5
|
+
import { renderBudgetSource, withJobStore } from "../job-store.js";
|
|
6
6
|
import { ensurePluginPaths, resolvePluginPaths } from "../paths.js";
|
|
7
7
|
import { parseJobLookupArgs } from "../parsing.js";
|
|
8
8
|
import { readArtifact, renderTerminalJobArtifact } from "../render.js";
|
|
@@ -42,6 +42,12 @@ function renderResultEnvelope(job, artifactPath, body) {
|
|
|
42
42
|
job_id: job.job_id,
|
|
43
43
|
kind: job.command_type,
|
|
44
44
|
status: job.status,
|
|
45
|
+
budget_ms: job.budget_ms,
|
|
46
|
+
budget_source: renderBudgetSource(job),
|
|
47
|
+
kimi_session_id_source: job.kimi_session_id_source,
|
|
48
|
+
kimi_session_id: job.kimi_session_id,
|
|
49
|
+
// True when a budget timeout preserved assistant prose in the artifact.
|
|
50
|
+
partial_output: job.status === "failed" && Number(job.error?.details?.partial_output_chars ?? 0) > 0,
|
|
45
51
|
summary: job.summary,
|
|
46
52
|
error: job.error,
|
|
47
53
|
artifact_path: artifactPath,
|
|
@@ -153,6 +153,7 @@ async function executeReviewGate(payload, assistantMessage, context) {
|
|
|
153
153
|
kimi_pid: null,
|
|
154
154
|
status: "running",
|
|
155
155
|
kimi_session_id: null,
|
|
156
|
+
budget_source: "default",
|
|
156
157
|
...persistedExecutionPlanFields(executionPlan),
|
|
157
158
|
agent_profile: REVIEW_GATE_AGENT_PROFILE_PLACEHOLDER,
|
|
158
159
|
prompt_digest: digestPrompt(prompt),
|
|
@@ -195,7 +196,7 @@ async function executeReviewGate(payload, assistantMessage, context) {
|
|
|
195
196
|
// can't synthesize empty strings today, but the guard locks the
|
|
196
197
|
// SQLite contract independent of upstream behavior).
|
|
197
198
|
activeStore.updateRunningJob(job.job_id, {
|
|
198
|
-
kimi_session_id: result.sessionId,
|
|
199
|
+
kimi_session_id_source: "announced", kimi_session_id: result.sessionId,
|
|
199
200
|
});
|
|
200
201
|
}
|
|
201
202
|
const finalText = reassembleProseFromRecords(result.records);
|
|
@@ -17,7 +17,7 @@ import { renderManagedJobOutput, writeArtifact } from "../render.js";
|
|
|
17
17
|
import { RuntimeError } from "../errors.js";
|
|
18
18
|
import { resolveRepoIdentity } from "../git.js";
|
|
19
19
|
import { hookRefusalDetails, hookRefusalRetryProtocol, maybeWarnHookMissing, verifyHookInstalled, } from "../hooks/install.js";
|
|
20
|
-
import { assertCliResultSuccess, reassembleProseFromRecords, warnIfSessionIdMissing } from "./cli-helpers.js";
|
|
20
|
+
import { captureTimeoutPartialOutput, assertCliResultSuccess, reassembleProseFromRecords, warnIfSessionIdMissing } from "./cli-helpers.js";
|
|
21
21
|
import { buildKimiSessionTitle, syncKimiSessionTitle } from "../session-title.js";
|
|
22
22
|
// v1.0 cutover note (PR 2):
|
|
23
23
|
//
|
|
@@ -81,6 +81,8 @@ export async function runReview(argv, context, commandType) {
|
|
|
81
81
|
model: parsed.model ?? null,
|
|
82
82
|
thinking: parsed.thinking ?? null,
|
|
83
83
|
background: false,
|
|
84
|
+
budget_ms: parsed.budgetMs ?? null,
|
|
85
|
+
budget_source: parsed.budgetMs !== undefined ? "explicit" : "default",
|
|
84
86
|
pid: process.pid,
|
|
85
87
|
kimi_pid: null,
|
|
86
88
|
status: "running",
|
|
@@ -113,7 +115,7 @@ export async function runReview(argv, context, commandType) {
|
|
|
113
115
|
model: parsed.model,
|
|
114
116
|
logPath,
|
|
115
117
|
signal: handlers.signal,
|
|
116
|
-
}, KIMI_REVIEW_PROMPT_TIMEOUT_MS, `${commandType}.prompt`);
|
|
118
|
+
}, job.budget_ms ?? KIMI_REVIEW_PROMPT_TIMEOUT_MS, `${commandType}.prompt`);
|
|
117
119
|
store.updateRunningJob(job.job_id, observedExecutionFields(result));
|
|
118
120
|
if (handlers.cancelling) {
|
|
119
121
|
throw new RuntimeError(cancel.errorCodes.cancelled, cancel.cancelMessages.afterPrompt, `${commandType}.runtime`);
|
|
@@ -127,7 +129,7 @@ export async function runReview(argv, context, commandType) {
|
|
|
127
129
|
// poison the row — consumers reading SQLite distinguish "missing"
|
|
128
130
|
// (NULL) from "captured" (non-empty UUID) only via NULL-ness.
|
|
129
131
|
// (Kimi alpha.4 challenge finding #3.)
|
|
130
|
-
store.updateRunningJob(job.job_id, { kimi_session_id: result.sessionId });
|
|
132
|
+
store.updateRunningJob(job.job_id, { kimi_session_id_source: "announced", kimi_session_id: result.sessionId });
|
|
131
133
|
}
|
|
132
134
|
await syncKimiSessionTitle({
|
|
133
135
|
promptText: previewPrompt,
|
|
@@ -158,13 +160,14 @@ export async function runReview(argv, context, commandType) {
|
|
|
158
160
|
return rendered.output;
|
|
159
161
|
}
|
|
160
162
|
catch (error) {
|
|
163
|
+
const classified = classifyManagedCommandFailure(error, commandType, job.job_id, { background: job.background, budgetMs: job.budget_ms ?? KIMI_REVIEW_PROMPT_TIMEOUT_MS });
|
|
164
|
+
const partialOutput = await captureTimeoutPartialOutput(classified, store, job, context.env, handlers.signal);
|
|
161
165
|
if (handlers.cancelling) {
|
|
162
166
|
const cancelledError = new RuntimeError(cancel.errorCodes.cancelled, cancel.cancelMessages.default, `${commandType}.runtime`, error instanceof Error ? { cause: error } : undefined);
|
|
163
167
|
await markJobCancelled(store, paths, job, cancel.cancelledSummary, cancelledError);
|
|
164
168
|
throw cancelledError;
|
|
165
169
|
}
|
|
166
|
-
|
|
167
|
-
await markJobFailed(store, paths, job, classified, cancel.failedSummary);
|
|
170
|
+
await markJobFailed(store, paths, job, classified, cancel.failedSummary, { partialOutput });
|
|
168
171
|
throw classified;
|
|
169
172
|
}
|
|
170
173
|
finally {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { SETUP_SUPPORTED_FLAGS } from "../parsing.js";
|
|
1
2
|
// Managed-block installer for the kimi-code PreToolUse hook.
|
|
2
3
|
//
|
|
3
4
|
// Replaces the v0.4 Wire-based setup probe. In v1.0 the load-bearing
|
|
@@ -127,7 +128,7 @@ function parseArgs(argv) {
|
|
|
127
128
|
disableReviewGate = true;
|
|
128
129
|
break;
|
|
129
130
|
default:
|
|
130
|
-
throw new RuntimeError("INVALID_ARGS", `Unknown setup flag ${token}. Supported flags:
|
|
131
|
+
throw new RuntimeError("INVALID_ARGS", `Unknown setup flag ${token}. Supported flags: ${SETUP_SUPPORTED_FLAGS}.`, "setup.parse");
|
|
131
132
|
}
|
|
132
133
|
}
|
|
133
134
|
if (enableReviewGate && disableReviewGate) {
|
|
@@ -2,7 +2,7 @@ import { RuntimeError } from "../errors.js";
|
|
|
2
2
|
import { resolveRepoIdentity } from "../git.js";
|
|
3
3
|
import { sweepStaleJobs } from "../jobs.js";
|
|
4
4
|
import { reconcileHistoricalJobProvenance } from "../kimi-engine.js";
|
|
5
|
-
import { withJobStore } from "../job-store.js";
|
|
5
|
+
import { renderBudgetSource, withJobStore } from "../job-store.js";
|
|
6
6
|
import { ensurePluginPaths, resolvePluginPaths } from "../paths.js";
|
|
7
7
|
import { parseJobLookupArgs } from "../parsing.js";
|
|
8
8
|
export async function runStatus(argv, context) {
|
|
@@ -22,6 +22,6 @@ export async function runStatus(argv, context) {
|
|
|
22
22
|
throw new RuntimeError("JOB_NOT_FOUND", "No matching job was found for status.", "status.lookup");
|
|
23
23
|
}
|
|
24
24
|
const job = await reconcileHistoricalJobProvenance(store, found);
|
|
25
|
-
return `${JSON.stringify(job, null, 2)}\n`;
|
|
25
|
+
return `${JSON.stringify({ ...job, budget_source: renderBudgetSource(job) }, null, 2)}\n`;
|
|
26
26
|
});
|
|
27
27
|
}
|
|
@@ -210,6 +210,8 @@ async function runReadSwarm(parsed, objective, context) {
|
|
|
210
210
|
model: parsed.model ?? null,
|
|
211
211
|
thinking: parsed.thinking ?? null,
|
|
212
212
|
background: false,
|
|
213
|
+
budget_ms: parsed.budgetMs ?? KIMI_SWARM_DEFAULT_BUDGET_MS,
|
|
214
|
+
budget_source: parsed.budgetMs !== undefined ? "explicit" : "default",
|
|
213
215
|
pid: process.pid,
|
|
214
216
|
kimi_pid: null,
|
|
215
217
|
status: "running",
|
|
@@ -235,7 +237,7 @@ async function runReadSwarm(parsed, objective, context) {
|
|
|
235
237
|
await markJobFailed(store, paths, job, classified, "Swarm failed.", { phase: "failed" });
|
|
236
238
|
throw classified;
|
|
237
239
|
}
|
|
238
|
-
const completed = await executeSwarmJob(job.job_id, prompt, objective,
|
|
240
|
+
const completed = await executeSwarmJob(job.job_id, prompt, objective, job.budget_ms, resolveSwarmMaxConcurrency(parsed.maxConcurrency), context);
|
|
239
241
|
if (!completed.final_output_path) {
|
|
240
242
|
throw new RuntimeError("SWARM_RESULT_MISSING", "Swarm finished without a rendered result.", "swarm.result");
|
|
241
243
|
}
|
|
@@ -308,6 +310,8 @@ async function runWriteSwarm(parsed, objective, context) {
|
|
|
308
310
|
model: parsed.model ?? null,
|
|
309
311
|
thinking: parsed.thinking ?? null,
|
|
310
312
|
background: false,
|
|
313
|
+
budget_ms: parsed.budgetMs ?? KIMI_SWARM_DEFAULT_BUDGET_MS,
|
|
314
|
+
budget_source: parsed.budgetMs !== undefined ? "explicit" : "default",
|
|
311
315
|
pid: process.pid,
|
|
312
316
|
kimi_pid: null,
|
|
313
317
|
status: "running",
|
|
@@ -335,7 +339,7 @@ async function runWriteSwarm(parsed, objective, context) {
|
|
|
335
339
|
});
|
|
336
340
|
throw classified;
|
|
337
341
|
}
|
|
338
|
-
const completed = await executeSwarmJob(job.job_id, prompt, objective,
|
|
342
|
+
const completed = await executeSwarmJob(job.job_id, prompt, objective, job.budget_ms, resolveSwarmWriteMaxConcurrency(parsed.maxConcurrency), context, { spawnCwd: worktreePath, workspaceRoot: worktreePath });
|
|
339
343
|
if (!completed.final_output_path) {
|
|
340
344
|
throw new RuntimeError("SWARM_RESULT_MISSING", "Swarm (write) finished without a rendered result.", "swarm.result");
|
|
341
345
|
}
|
|
@@ -500,7 +504,7 @@ writeMode) {
|
|
|
500
504
|
if (result.sessionId !== undefined &&
|
|
501
505
|
result.sessionId.length > 0 &&
|
|
502
506
|
result.sessionId !== job.kimi_session_id) {
|
|
503
|
-
store.updateRunningJob(job.job_id, { kimi_session_id: result.sessionId });
|
|
507
|
+
store.updateRunningJob(job.job_id, { kimi_session_id_source: "announced", kimi_session_id: result.sessionId });
|
|
504
508
|
}
|
|
505
509
|
await syncKimiSessionTitle({
|
|
506
510
|
promptText: objective,
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { companionHelp } from "./help.js";
|
|
1
2
|
import { runAsk } from "./commands/ask.js";
|
|
2
3
|
import { runModelInventory } from "./commands/models.js";
|
|
3
4
|
import { runCancel } from "./commands/cancel.js";
|
|
@@ -15,6 +16,11 @@ import { runWorker } from "./commands/worker.js";
|
|
|
15
16
|
import { formatError, RuntimeError } from "./errors.js";
|
|
16
17
|
import { resolveKimiHome } from "./kimi-home.js";
|
|
17
18
|
async function main(argv) {
|
|
19
|
+
const help = companionHelp(argv);
|
|
20
|
+
if (help !== undefined) {
|
|
21
|
+
process.stdout.write(`${help}\n`);
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
18
24
|
const [command, ...rest] = argv;
|
|
19
25
|
const cwd = process.env.KIMI_PLUGIN_CC_WORKSPACE_CWD || process.cwd();
|
|
20
26
|
const context = {
|