@vincemakes/kiso-code 0.49.0 → 0.50.1
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/README.md +5 -1
- package/dist/builtin.js +3 -2
- package/dist/chat.js +5 -2
- package/dist/coding-prompt.d.ts +1 -1
- package/dist/coding-prompt.js +15 -31
- package/dist/dispatch.js +7 -3
- package/dist/index.js +3 -2
- package/dist/replay.d.ts +1 -0
- package/dist/replay.js +7 -2
- package/dist/state.d.ts +5 -1
- package/dist/state.js +102 -2
- package/dist/task-notice.d.ts +7 -0
- package/dist/task-notice.js +13 -0
- package/package.json +14 -14
package/README.md
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
|
|
1
|
+
<h1 align="center"><picture><source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/vincemakes/kiso/main/assets/readme/lockup-dark.png"><img src="https://raw.githubusercontent.com/vincemakes/kiso/main/assets/readme/lockup-light.png" height="46" alt="kiso"></picture></h1>
|
|
2
|
+
|
|
3
|
+
<p align="center"><picture><source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/vincemakes/kiso/main/assets/readme/features-dark.png"><img src="https://raw.githubusercontent.com/vincemakes/kiso/main/assets/readme/features-light.png" width="830" alt="Built in, not bolted on: it asks before it guesses; subagents in parallel; background tasks; approval modes; it resumes after a crash; yours to extend."></picture></p>
|
|
4
|
+
|
|
5
|
+
<p align="center"><img src="https://raw.githubusercontent.com/vincemakes/kiso/main/assets/readme/screenshot.png" width="830" alt="kiso in a dark terminal window: a green diff of new tests, then the test suite started as a background task, with 1 task running in the status row"></p>
|
|
2
6
|
|
|
3
7
|
The coding agent that survives kill -9: durable sessions (append-only
|
|
4
8
|
JSONL), pre-effect approvals, and honest recovery — an interrupted side
|
package/dist/builtin.js
CHANGED
|
@@ -59,8 +59,9 @@ ask,
|
|
|
59
59
|
* too late. Only the config knows them; nothing else can. */
|
|
60
60
|
secretEnvNames = []) {
|
|
61
61
|
// ADR-0058 3d: the session's task manager makes `delegate` offer
|
|
62
|
-
// background children (
|
|
63
|
-
//
|
|
62
|
+
// background children (any role; a writer works in its own snapshot and
|
|
63
|
+
// is collected; the caps and the turn budgets are the extension's
|
|
64
|
+
// defaults). 0.49.0 C1: the session's live binding
|
|
64
65
|
// is the model a child runs on when its task names none.
|
|
65
66
|
const all = await Promise.all([createMcp({ secretEnvNames }), createSkills(), createSubagent({ tasks: tasksFor, currentBinding: bindingFor, ...joinOption() }), ...(ask === undefined ? [] : [createAsk(ask).then(offInDontAsk)])]);
|
|
66
67
|
const shadowed = all.filter((b) => user.some((u) => u.name === b.name));
|
package/dist/chat.js
CHANGED
|
@@ -9,7 +9,7 @@ import { escapeTerminal, cacheHitPct, decodeRate, palette, renderEvent, renderRe
|
|
|
9
9
|
import { askView, coldResumeLine, coldResumeView, deletionRiskHint, editFileHunksDiff, hunksOf, writeFileDiff } from "@vincemakes/kiso-tui";
|
|
10
10
|
import { canonicalTargetPath, isProtectedPath, protectedIdentity, shellProgressPath } from "@vincemakes/kiso-tools-node";
|
|
11
11
|
import { deliveryLines, liveTasks, lostToldOf, mergedConfig, queuedSwitchLines, setExitTasks, tasksFor, taskWhatOf } from "./state.js";
|
|
12
|
-
import { budgetSpentLine, taskCounts, taskNoticeLines, taskNoticeRows, tasksForDisplay } from "./task-notice.js";
|
|
12
|
+
import { budgetSpentLine, cappedWaitLine, taskCounts, taskNoticeLines, taskNoticeRows, tasksForDisplay } from "./task-notice.js";
|
|
13
13
|
import { current as inRunCompaction, takeKept as takeKeptCompaction } from "./in-run-compaction.js";
|
|
14
14
|
import { echoText } from "@vincemakes/kiso-tui-cells/render";
|
|
15
15
|
import { canonicalizeUsage, RunClosedError } from "@vincemakes/kiso-runtime";
|
|
@@ -1062,7 +1062,10 @@ onInputLanded) {
|
|
|
1062
1062
|
if (m !== null)
|
|
1063
1063
|
reason = m[1];
|
|
1064
1064
|
}
|
|
1065
|
-
body.toolResult(ev.callId, { content: text, isError: ev.isError, reason });
|
|
1065
|
+
body.toolResult(ev.callId, { content: text, isError: ev.isError, reason, ...((ev.tags ?? []).includes("created") ? { created: true } : {}) });
|
|
1066
|
+
const capped = ev.isError ? null : cappedWaitLine(text);
|
|
1067
|
+
if (capped !== null)
|
|
1068
|
+
body.notice(capped);
|
|
1066
1069
|
break;
|
|
1067
1070
|
}
|
|
1068
1071
|
case "text_delta":
|
package/dist/coding-prompt.d.ts
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
*/
|
|
10
10
|
/** The built-in prompt. Exported for scripts/request-surface.mjs — the
|
|
11
11
|
* model-side token-rent counter measures the REAL bytes, never a copy. */
|
|
12
|
-
export declare const SYSTEM_PROMPT = "You are
|
|
12
|
+
export declare const SYSTEM_PROMPT = "You are an expert coding assistant running on Kiso, an agent runtime. Help the user complete software engineering tasks in the current workspace using the available tools.\n\nShell can access this machine and the network, including git, package managers, and HTTP. For factual questions the user asks, use existing valid tool evidence or an available tool rather than guessing or claiming the information is unavailable.\n\nWork directly toward the user's request. Make the smallest complete change that solves it, follow existing conventions, and do not expand the task into unrelated fixes, refactors, or features.\n\nInspect enough current context to act correctly. Reuse valid observations and tool results instead of repeating work. A confirmed tool result is evidence; do not re-read or re-check solely for reassurance. If a tool reports a failure or conflict, use that new evidence to decide the next action.\n\nAfter a successful edit or write, treat the change you made and the returned revision as the file's current observed state. Do not re-read it before a follow-up edit unless you need context you have not already observed or a tool reports a conflict or failure. When a conflict or refusal already provides the current relevant text and revision, use that result directly instead of reading the file again.\n\nFor behavior-changing work, use the narrowest relevant existing verification when needed. Broaden verification only when a failure, meaningful risk, or concrete unresolved concern gives a reason to do so. Do not create ad-hoc verification scripts when existing evidence is sufficient.\n\nWhen the requested work is complete and there is no concrete unresolved issue, stop. Continue investigating or checking only when new evidence gives a reason to continue.\n\nNecessary workspace changes are within the scope of the requested task. Ask the user only for decisions that require the user. Do not commit, push, publish, send, or perform other remote or irreversible actions unless explicitly requested.\n\nRequests to share, deliver, hand over, or get work ready do not by themselves authorize a commit, push, publish, or send. Perform those actions only when the user explicitly names the action; otherwise leave the changes in the workspace.\n\nBe concise.";
|
|
13
13
|
/** Hard cap for injected instructions — truncate and say so. */
|
|
14
14
|
/**
|
|
15
15
|
* A area: read the FIRST present instruction file (AGENTS.md preferred) and
|
package/dist/coding-prompt.js
CHANGED
|
@@ -13,41 +13,25 @@ import { readFileSync } from "node:fs";
|
|
|
13
13
|
*/
|
|
14
14
|
/** The built-in prompt. Exported for scripts/request-surface.mjs — the
|
|
15
15
|
* model-side token-rent counter measures the REAL bytes, never a copy. */
|
|
16
|
-
export const SYSTEM_PROMPT = `You are
|
|
17
|
-
directory and change code with tools. Be concise: answer in a few lines
|
|
18
|
-
unless the task genuinely needs more. Never claim a file was changed
|
|
19
|
-
unless a tool confirmed it.
|
|
16
|
+
export const SYSTEM_PROMPT = `You are an expert coding assistant running on Kiso, an agent runtime. Help the user complete software engineering tasks in the current workspace using the available tools.
|
|
20
17
|
|
|
21
|
-
|
|
22
|
-
- The workspace: read_file, list_dir, search_text, write_file, edit_file.
|
|
23
|
-
- This machine and the network: shell — builds, tests, git, package
|
|
24
|
-
managers, curl for HTTP, system queries. A request one command can
|
|
25
|
-
answer is answered by running it.
|
|
26
|
-
- The human: ask_user, for a decision that is theirs.
|
|
18
|
+
Shell can access this machine and the network, including git, package managers, and HTTP. For factual questions the user asks, use existing valid tool evidence or an available tool rather than guessing or claiming the information is unavailable.
|
|
27
19
|
|
|
28
|
-
|
|
29
|
-
- READ BEFORE YOU EDIT. For any file you are about to change, read it
|
|
30
|
-
first — never guess its content.
|
|
31
|
-
- Use edit_file for targeted changes and write_file for new files or
|
|
32
|
-
full rewrites.
|
|
33
|
-
- Be careful — shell has side effects and may take time.
|
|
34
|
-
- search_text and list_dir are cheap — locate first, then read ranges
|
|
35
|
-
with read_file offset/limit; never read a whole large file in one call.
|
|
36
|
-
- Do not re-read a file you already read unchanged, or one you changed
|
|
37
|
-
yourself through a confirmed edit — rely on the earlier result and
|
|
38
|
-
on the change you just made.
|
|
39
|
-
- When a tool fails, read the error and adjust; do not repeat the same
|
|
40
|
-
call blindly.
|
|
20
|
+
Work directly toward the user's request. Make the smallest complete change that solves it, follow existing conventions, and do not expand the task into unrelated fixes, refactors, or features.
|
|
41
21
|
|
|
42
|
-
|
|
43
|
-
which files, which branches, whether to push — ask before acting.
|
|
44
|
-
Delivering, sharing or handing over changes means committing locally and
|
|
45
|
-
stopping; pushing, publishing or sending happens only when the human
|
|
46
|
-
names it.
|
|
22
|
+
Inspect enough current context to act correctly. Reuse valid observations and tool results instead of repeating work. A confirmed tool result is evidence; do not re-read or re-check solely for reassurance. If a tool reports a failure or conflict, use that new evidence to decide the next action.
|
|
47
23
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
24
|
+
After a successful edit or write, treat the change you made and the returned revision as the file's current observed state. Do not re-read it before a follow-up edit unless you need context you have not already observed or a tool reports a conflict or failure. When a conflict or refusal already provides the current relevant text and revision, use that result directly instead of reading the file again.
|
|
25
|
+
|
|
26
|
+
For behavior-changing work, use the narrowest relevant existing verification when needed. Broaden verification only when a failure, meaningful risk, or concrete unresolved concern gives a reason to do so. Do not create ad-hoc verification scripts when existing evidence is sufficient.
|
|
27
|
+
|
|
28
|
+
When the requested work is complete and there is no concrete unresolved issue, stop. Continue investigating or checking only when new evidence gives a reason to continue.
|
|
29
|
+
|
|
30
|
+
Necessary workspace changes are within the scope of the requested task. Ask the user only for decisions that require the user. Do not commit, push, publish, send, or perform other remote or irreversible actions unless explicitly requested.
|
|
31
|
+
|
|
32
|
+
Requests to share, deliver, hand over, or get work ready do not by themselves authorize a commit, push, publish, or send. Perform those actions only when the user explicitly names the action; otherwise leave the changes in the workspace.
|
|
33
|
+
|
|
34
|
+
Be concise.`;
|
|
51
35
|
/** The project-instructions file names, in priority order (A area). */
|
|
52
36
|
const INSTRUCTION_FILES = ["AGENTS.md", "CLAUDE.md"];
|
|
53
37
|
/** Hard cap for injected instructions — truncate and say so. */
|
package/dist/dispatch.js
CHANGED
|
@@ -880,7 +880,7 @@ export function dispatch(line, ctx) {
|
|
|
880
880
|
if (want !== wasOn)
|
|
881
881
|
body.dontAskNotice(`don't ask → ${want ? "on" : "off"}`, want);
|
|
882
882
|
else
|
|
883
|
-
body.
|
|
883
|
+
body.dontAskNotice(`don't ask → ${want ? "on" : "off"}`, want, true);
|
|
884
884
|
ctx.paintIdle();
|
|
885
885
|
}
|
|
886
886
|
ctx.input.prompt();
|
|
@@ -1087,6 +1087,9 @@ export function dispatch(line, ctx) {
|
|
|
1087
1087
|
// session still names the outgoing profile
|
|
1088
1088
|
const prevProfile = currentProfileName !== null ? configModels[currentProfileName] : undefined;
|
|
1089
1089
|
const payeeBefore = prevProfile !== undefined ? payeeOf(prevProfile) : null;
|
|
1090
|
+
// the notices round (owner, 2026-10-14): the MODEL row says what it
|
|
1091
|
+
// switched FROM, read before the outgoing binding is replaced
|
|
1092
|
+
const fromName = currentProfileName ?? agentModel;
|
|
1090
1093
|
ctx.session.setModelBinding(binding);
|
|
1091
1094
|
setLastBinding(binding);
|
|
1092
1095
|
setAgentModel(profile.model, profile.baseUrl);
|
|
@@ -1117,14 +1120,15 @@ export function dispatch(line, ctx) {
|
|
|
1117
1120
|
// (and the owner's) read `gpt-6-astra · CH 92%`, the new
|
|
1118
1121
|
// model beside the previous model's figure.
|
|
1119
1122
|
ctx.modelSwitched();
|
|
1120
|
-
|
|
1123
|
+
const hostLabel = providerLabel(profile.baseUrl, profile.upstream);
|
|
1124
|
+
body.modelNotice(`model → ${profName} (${profile.model}${hostLabel === "" ? "" : ` ${hostLabel}`}${effortTok !== undefined ? ` · ${effortTok}` : ""}) — takes effect on the next turn`, fromName, profName, `${profile.model}${hostLabel === "" ? "" : ` ${hostLabel}`}${effortTok !== undefined ? ` \u00b7 ${effortTok}` : ""} \u00b7 takes effect on the next turn`);
|
|
1121
1125
|
// MP-1 (0.40.7): when the switch changes WHO PAYS — another
|
|
1122
1126
|
// endpoint, or another credential for it — say so, once,
|
|
1123
1127
|
// under the switch line. A switch between two models on the
|
|
1124
1128
|
// same account says nothing more.
|
|
1125
1129
|
const payeeAfter = payeeOf(profile);
|
|
1126
1130
|
if (payeeBefore !== null && payeeBefore !== payeeAfter)
|
|
1127
|
-
body.
|
|
1131
|
+
body.metaNotice(`paid by ${payeeAfter} from the next turn — was ${payeeBefore}`, [{ label: "PAYER", sentence: `${payeeAfter} from the next turn \u00b7 was ${payeeBefore}` }]);
|
|
1128
1132
|
}
|
|
1129
1133
|
}
|
|
1130
1134
|
}
|
package/dist/index.js
CHANGED
|
@@ -45,7 +45,7 @@ import { activeStoreDir, setActiveStoreDir, agentModel, atFiles, body, bodyLog,
|
|
|
45
45
|
import { fauxSkip, readFauxScript } from "./faux-glue.js";
|
|
46
46
|
import { barFor, chat, contextWindowTokens, displayCtxRatio, microcompactThresholdFor, statusModelLabel } from "./chat.js";
|
|
47
47
|
import { preferences, usePreferences } from "./preferences.js";
|
|
48
|
-
import { settingsLayers, setChildTurnBudget, stopAllTasks, tasksFor } from "./state.js";
|
|
48
|
+
import { settingsLayers, setChildTurnBudget, setPrintRun, stopAllTasks, tasksFor } from "./state.js";
|
|
49
49
|
import { tasksForDisplay } from "./task-notice.js";
|
|
50
50
|
import { finishChild } from "./child-result.js";
|
|
51
51
|
import { loadUserConfig, resolveAutoCompact } from "./config.js";
|
|
@@ -1114,7 +1114,7 @@ async function chatLoop(first, firstId, input, autoCompact) {
|
|
|
1114
1114
|
return r.status === 0 ? r.stdout.trim() : null;
|
|
1115
1115
|
});
|
|
1116
1116
|
if (tmuxHint !== null)
|
|
1117
|
-
body.
|
|
1117
|
+
body.metaNotice(tmuxHint, [{ label: "HINT", sentence: tmuxHint }]);
|
|
1118
1118
|
void announceUpdate();
|
|
1119
1119
|
}
|
|
1120
1120
|
else {
|
|
@@ -1305,6 +1305,7 @@ async function main() {
|
|
|
1305
1305
|
process.exit(2);
|
|
1306
1306
|
}
|
|
1307
1307
|
args.splice(printIdx, 2);
|
|
1308
|
+
setPrintRun();
|
|
1308
1309
|
}
|
|
1309
1310
|
// merge round B: --model <profile|provider/model> — the top of the model
|
|
1310
1311
|
// precedence chain; the value flows into createCodingAgent's config resolution.
|
package/dist/replay.d.ts
CHANGED
package/dist/replay.js
CHANGED
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
*/
|
|
22
22
|
import { echoText } from "@vincemakes/kiso-tui-cells/render";
|
|
23
23
|
import { bandHeader } from "@vincemakes/kiso-tui-cells/strings";
|
|
24
|
-
import { taskNoticeLines, taskNoticeRows, taskWhat } from "./task-notice.js";
|
|
24
|
+
import { cappedWaitLine, taskNoticeLines, taskNoticeRows, taskWhat } from "./task-notice.js";
|
|
25
25
|
/** How many turns stay on screen in full. */
|
|
26
26
|
const FULL_TURNS = 2;
|
|
27
27
|
/** A user turn's opening line, or null when this input does not open one
|
|
@@ -98,8 +98,13 @@ function replayTurn(body, turn, tasks) {
|
|
|
98
98
|
if (m !== null)
|
|
99
99
|
reason = m[1];
|
|
100
100
|
}
|
|
101
|
-
|
|
101
|
+
const created = (e.tags ?? []).includes("created");
|
|
102
|
+
body.toolResult(String(e.callId), { content: text, isError: e.isError === true, reason, untimed: true, ...(created ? { created: true } : {}) });
|
|
102
103
|
results.add(String(e.callId));
|
|
104
|
+
// 0.50.1: the capped wait's TASK row, as the live run drew it
|
|
105
|
+
const capped = e.isError === true ? null : cappedWaitLine(text);
|
|
106
|
+
if (capped !== null)
|
|
107
|
+
body.notice(capped);
|
|
103
108
|
break;
|
|
104
109
|
}
|
|
105
110
|
case "text_delta":
|
package/dist/state.d.ts
CHANGED
|
@@ -29,14 +29,17 @@ export declare function kisoHome(): string;
|
|
|
29
29
|
* these state setters have run.
|
|
30
30
|
*/
|
|
31
31
|
export declare function secretEnvNamesOf(models: Readonly<Record<string, unknown>>): readonly string[];
|
|
32
|
+
export declare function setPrintRun(): void;
|
|
32
33
|
export declare function codingToolOptions(): {
|
|
33
34
|
readonly workspaceRoot: string;
|
|
34
35
|
readonly excludeRoots: readonly string[];
|
|
35
36
|
readonly secretEnvNames: readonly string[];
|
|
36
37
|
readonly protectedFiles: readonly string[];
|
|
37
38
|
readonly tasks: (sessionId: string | undefined) => ShellTasks | undefined;
|
|
39
|
+
readonly observedRevision: (sessionId: string | undefined, full: string, kind?: "edit" | "write") => string | undefined;
|
|
38
40
|
readonly limits?: {
|
|
39
|
-
readonly minForegroundMs
|
|
41
|
+
readonly minForegroundMs?: number;
|
|
42
|
+
readonly maxForegroundMs?: number;
|
|
40
43
|
};
|
|
41
44
|
};
|
|
42
45
|
/** Amendment 8: what a session's task ran — a lost task's transcript row
|
|
@@ -441,4 +444,5 @@ export declare function setLastBinding(b: LastBinding): void;
|
|
|
441
444
|
export declare function lastBinding(): LastBinding | null;
|
|
442
445
|
export declare function setAcceptDrift(v: boolean): void;
|
|
443
446
|
export declare function acceptDrift(): boolean;
|
|
447
|
+
export declare function observedRevisionFromLog(sessionId: string | undefined, full: string, kind?: "edit" | "write"): string | undefined;
|
|
444
448
|
export {};
|
package/dist/state.js
CHANGED
|
@@ -8,9 +8,10 @@
|
|
|
8
8
|
import { execFileSync } from "node:child_process";
|
|
9
9
|
import { readdirSync, readFileSync, realpathSync } from "node:fs";
|
|
10
10
|
import { homedir } from "node:os";
|
|
11
|
-
import { dirname, join } from "node:path";
|
|
11
|
+
import { dirname, join, resolve } from "node:path";
|
|
12
12
|
import { fileURLToPath } from "node:url";
|
|
13
13
|
import { AT_CAP, AT_SKIP, Dock } from "@vincemakes/kiso-tui";
|
|
14
|
+
import { projectMessages } from "@vincemakes/kiso-core";
|
|
14
15
|
import { TaskManager } from "@vincemakes/kiso-runtime/internal";
|
|
15
16
|
import { processTaskBackend } from "@vincemakes/kiso-tools-node";
|
|
16
17
|
import { collectWriter } from "@vincemakes/kiso-subagent-ext";
|
|
@@ -42,18 +43,33 @@ export function secretEnvNamesOf(models) {
|
|
|
42
43
|
.filter((n) => typeof n === "string" && n.length > 0)),
|
|
43
44
|
];
|
|
44
45
|
}
|
|
46
|
+
/** 0.50.1 (ADR-0058 Amendment 16): `kiso -p` runs with nobody watching and
|
|
47
|
+
* stops its tasks when the one turn ends, so the foreground wait keeps the
|
|
48
|
+
* model's value — no ceiling. Set once, where `-p` is parsed. */
|
|
49
|
+
let printRun = false;
|
|
50
|
+
export function setPrintRun() {
|
|
51
|
+
printRun = true;
|
|
52
|
+
}
|
|
45
53
|
export function codingToolOptions() {
|
|
46
54
|
// KISO_MIN_FOREGROUND_MS — the test rigs' knob (like KISO_AUTO_DETACH_MS):
|
|
47
55
|
// the least foreground wait (ADR-0058 Amendment 10, default 60 s). The
|
|
48
56
|
// rigs that promote a command by a short wait lower it; nothing else does.
|
|
49
57
|
const minForeground = Number.parseInt(process.env.KISO_MIN_FOREGROUND_MS ?? "", 10);
|
|
58
|
+
// KISO_MAX_FOREGROUND_MS — the rigs' knob for the ceiling (Amendment 15,
|
|
59
|
+
// default 5 min). `-p` has none whatever the knob says (Amendment 16).
|
|
60
|
+
const maxForeground = Number.parseInt(process.env.KISO_MAX_FOREGROUND_MS ?? "", 10);
|
|
61
|
+
const limits = {
|
|
62
|
+
...(Number.isFinite(minForeground) && minForeground >= 0 ? { minForegroundMs: minForeground } : {}),
|
|
63
|
+
...(printRun ? { maxForegroundMs: 0 } : Number.isFinite(maxForeground) && maxForeground >= 0 ? { maxForegroundMs: maxForeground } : {}),
|
|
64
|
+
};
|
|
50
65
|
return {
|
|
51
66
|
workspaceRoot: process.cwd(),
|
|
52
67
|
excludeRoots: [kisoHome()],
|
|
53
68
|
secretEnvNames: secretEnvNamesOf(configModels),
|
|
54
69
|
protectedFiles: protectedFiles(),
|
|
55
70
|
tasks: tasksFor,
|
|
56
|
-
|
|
71
|
+
observedRevision: observedRevisionFromLog,
|
|
72
|
+
...(Object.keys(limits).length > 0 ? { limits } : {}),
|
|
57
73
|
};
|
|
58
74
|
}
|
|
59
75
|
/** ADR-0058 (3b): one TaskManager per session, its directory beside the
|
|
@@ -638,3 +654,87 @@ export function setAcceptDrift(v) {
|
|
|
638
654
|
export function acceptDrift() {
|
|
639
655
|
return acceptDriftValue;
|
|
640
656
|
}
|
|
657
|
+
/** O1 — the hidden observed revision. The revision the model last
|
|
658
|
+
* OBSERVED for a file, rebuilt from the session's MODEL-VISIBLE history
|
|
659
|
+
* (`projectMessages` over the durable log, so a receipt cleared by
|
|
660
|
+
* microcompaction or covered by a summary no longer counts): the last
|
|
661
|
+
* [rev:…] of a successful read_file / edit_file / write_file on that
|
|
662
|
+
* file, or of an edit_file stale refusal (it carries the current text).
|
|
663
|
+
* Never the disk's current revision — a stale write stays refused.
|
|
664
|
+
* `kind: "write"` (a whole-file replace) also needs visible whole-file
|
|
665
|
+
* knowledge: an unranged, uncapped read or an own write, followed only
|
|
666
|
+
* by own mutations. The log is per session, so a child session (a
|
|
667
|
+
* subagent) inherits no observation. */
|
|
668
|
+
function realOrResolved(p) {
|
|
669
|
+
try {
|
|
670
|
+
return realpathSync(p);
|
|
671
|
+
}
|
|
672
|
+
catch {
|
|
673
|
+
return p;
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
export function observedRevisionFromLog(sessionId, full, kind = "edit") {
|
|
677
|
+
if (sessionId === undefined || activeStoreDir === "")
|
|
678
|
+
return undefined;
|
|
679
|
+
let text;
|
|
680
|
+
try {
|
|
681
|
+
text = readFileSync(join(activeStoreDir, `${sessionId}.jsonl`), "utf8");
|
|
682
|
+
}
|
|
683
|
+
catch {
|
|
684
|
+
return undefined;
|
|
685
|
+
}
|
|
686
|
+
const events = [];
|
|
687
|
+
for (const line of text.split("\n")) {
|
|
688
|
+
if (line === "")
|
|
689
|
+
continue;
|
|
690
|
+
try {
|
|
691
|
+
const e = JSON.parse(line).event;
|
|
692
|
+
if (e !== undefined)
|
|
693
|
+
events.push(e);
|
|
694
|
+
}
|
|
695
|
+
catch { /* a torn tail line */ }
|
|
696
|
+
}
|
|
697
|
+
let messages;
|
|
698
|
+
try {
|
|
699
|
+
messages = projectMessages(events);
|
|
700
|
+
}
|
|
701
|
+
catch {
|
|
702
|
+
return undefined;
|
|
703
|
+
}
|
|
704
|
+
const target = realOrResolved(full);
|
|
705
|
+
const calls = new Map();
|
|
706
|
+
let rev;
|
|
707
|
+
let wholeKnown = false;
|
|
708
|
+
for (const m of messages) {
|
|
709
|
+
if (m.role === "assistant") {
|
|
710
|
+
for (const b of m.blocks) {
|
|
711
|
+
if (b.type === "tool_use" && typeof b.input.path === "string") {
|
|
712
|
+
calls.set(b.callId, { name: b.name, full: realOrResolved(resolve(process.cwd(), b.input.path)), ranged: b.input.offset !== undefined || b.input.limit !== undefined });
|
|
713
|
+
}
|
|
714
|
+
}
|
|
715
|
+
}
|
|
716
|
+
else if (m.role === "tool") {
|
|
717
|
+
const c = calls.get(m.callId);
|
|
718
|
+
if (c === undefined || c.full !== target)
|
|
719
|
+
continue;
|
|
720
|
+
const body = typeof m.content === "string" ? m.content : m.content.map((x) => (x.type === "text" ? x.text : "")).join("");
|
|
721
|
+
const hit = [...body.matchAll(/\[(rev:[0-9a-f]{16})\]/g)].pop();
|
|
722
|
+
if (hit === undefined)
|
|
723
|
+
continue;
|
|
724
|
+
if (!m.isError && (c.name === "read_file" || c.name === "edit_file" || c.name === "write_file")) {
|
|
725
|
+
rev = hit[1];
|
|
726
|
+
if (c.name === "read_file")
|
|
727
|
+
wholeKnown = !c.ranged && !body.includes("(call again with offset=") && !body.includes("[output capped at");
|
|
728
|
+
else if (c.name === "write_file")
|
|
729
|
+
wholeKnown = true;
|
|
730
|
+
}
|
|
731
|
+
else if (m.isError && c.name === "edit_file" && body.includes(" changed since ")) {
|
|
732
|
+
rev = hit[1];
|
|
733
|
+
wholeKnown = false;
|
|
734
|
+
}
|
|
735
|
+
}
|
|
736
|
+
}
|
|
737
|
+
if (kind === "write" && !wholeKnown)
|
|
738
|
+
return undefined;
|
|
739
|
+
return rev;
|
|
740
|
+
}
|
package/dist/task-notice.d.ts
CHANGED
|
@@ -7,6 +7,13 @@ import type { NoticeMark } from "@vincemakes/kiso-tui";
|
|
|
7
7
|
* (<what>) — ` — the parenthesis only when the command is known — and the
|
|
8
8
|
* LAST ` — ` part opening with "it may still be running". One line each. */
|
|
9
9
|
export declare function taskNoticeLines(items: readonly TaskDeliveryItem[], what?: (taskId: string) => string | undefined): string[];
|
|
10
|
+
/** 0.50.1: a command promoted at the foreground ceiling — its shell result
|
|
11
|
+
* opens `still running after <wait> ms (the limit; you asked <asked> ms);
|
|
12
|
+
* continued as background task <id>` — is said to the person as one TASK
|
|
13
|
+
* row: `t3 · moved to the background at the 5m limit · asked 6m 40s`. Only
|
|
14
|
+
* this case: every other promotion stays rowless (the task-start row is
|
|
15
|
+
* deferred, owner 2026-10-14). */
|
|
16
|
+
export declare function cappedWaitLine(result: string): string | null;
|
|
10
17
|
/** Finding 0480-F9: the chain budget is spent — said to the person once,
|
|
11
18
|
* so a chain that went quiet on its budget does not look idle. */
|
|
12
19
|
export declare function budgetSpentLine(info: {
|
package/dist/task-notice.js
CHANGED
|
@@ -36,6 +36,19 @@ export function taskNoticeLines(items, what) {
|
|
|
36
36
|
}
|
|
37
37
|
return rows;
|
|
38
38
|
}
|
|
39
|
+
/** 0.50.1: a command promoted at the foreground ceiling — its shell result
|
|
40
|
+
* opens `still running after <wait> ms (the limit; you asked <asked> ms);
|
|
41
|
+
* continued as background task <id>` — is said to the person as one TASK
|
|
42
|
+
* row: `t3 · moved to the background at the 5m limit · asked 6m 40s`. Only
|
|
43
|
+
* this case: every other promotion stays rowless (the task-start row is
|
|
44
|
+
* deferred, owner 2026-10-14). */
|
|
45
|
+
export function cappedWaitLine(result) {
|
|
46
|
+
const m = /^still running after (\d+) ms \(the limit; you asked (\d+) ms\); continued as background task (\S+) /.exec(result);
|
|
47
|
+
if (m === null)
|
|
48
|
+
return null;
|
|
49
|
+
const limit = elapsedLabel(Number(m[1]) / 1000).replace(/(?<=m) 0s$/, "");
|
|
50
|
+
return `✦ task ${m[3]} · moved to the background at the ${limit} limit · asked ${elapsedLabel(Number(m[2]) / 1000)}`;
|
|
51
|
+
}
|
|
39
52
|
/** Finding 0480-F9: the chain budget is spent — said to the person once,
|
|
40
53
|
* so a chain that went quiet on its budget does not look idle. */
|
|
41
54
|
export function budgetSpentLine(info) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vincemakes/kiso-code",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.50.1",
|
|
4
4
|
"description": "kiso-code \u2014 the coding agent on kiso, the durable runtime for AI agents: kiso chat / kiso resume / kiso sessions.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -18,19 +18,19 @@
|
|
|
18
18
|
"test": "vitest run"
|
|
19
19
|
},
|
|
20
20
|
"dependencies": {
|
|
21
|
-
"@vincemakes/kiso-ask-ext": "0.
|
|
22
|
-
"@vincemakes/kiso-core": "0.
|
|
23
|
-
"@vincemakes/kiso-evals": "0.
|
|
24
|
-
"@vincemakes/kiso-mcp-ext": "0.
|
|
25
|
-
"@vincemakes/kiso-provider-anthropic": "0.
|
|
26
|
-
"@vincemakes/kiso-provider-openai": "0.
|
|
27
|
-
"@vincemakes/kiso-provider-openai-responses": "0.
|
|
28
|
-
"@vincemakes/kiso-runtime": "0.
|
|
29
|
-
"@vincemakes/kiso-skills-ext": "0.
|
|
30
|
-
"@vincemakes/kiso-subagent-ext": "0.
|
|
31
|
-
"@vincemakes/kiso-tools-node": "0.
|
|
32
|
-
"@vincemakes/kiso-tui": "0.
|
|
33
|
-
"@vincemakes/kiso-tui-cells": "0.
|
|
21
|
+
"@vincemakes/kiso-ask-ext": "0.50.1",
|
|
22
|
+
"@vincemakes/kiso-core": "0.50.1",
|
|
23
|
+
"@vincemakes/kiso-evals": "0.50.1",
|
|
24
|
+
"@vincemakes/kiso-mcp-ext": "0.50.1",
|
|
25
|
+
"@vincemakes/kiso-provider-anthropic": "0.50.1",
|
|
26
|
+
"@vincemakes/kiso-provider-openai": "0.50.1",
|
|
27
|
+
"@vincemakes/kiso-provider-openai-responses": "0.50.1",
|
|
28
|
+
"@vincemakes/kiso-runtime": "0.50.1",
|
|
29
|
+
"@vincemakes/kiso-skills-ext": "0.50.1",
|
|
30
|
+
"@vincemakes/kiso-subagent-ext": "0.50.1",
|
|
31
|
+
"@vincemakes/kiso-tools-node": "0.50.1",
|
|
32
|
+
"@vincemakes/kiso-tui": "0.50.1",
|
|
33
|
+
"@vincemakes/kiso-tui-cells": "0.50.1"
|
|
34
34
|
},
|
|
35
35
|
"devDependencies": {
|
|
36
36
|
"@types/node": "^26.1.2",
|