@skein-code/cli 0.3.24 → 0.3.25
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 +19 -2
- package/dist/cli.js +692 -122
- package/dist/cli.js.map +1 -1
- package/docs/ARCHITECTURE.md +32 -11
- package/docs/NEXT_STEPS.md +27 -3
- package/examples/config.yaml +2 -1
- package/package.json +6 -1
package/dist/cli.js
CHANGED
|
@@ -220,7 +220,7 @@ function isSqliteBusy(error) {
|
|
|
220
220
|
// package.json
|
|
221
221
|
var package_default = {
|
|
222
222
|
name: "@skein-code/cli",
|
|
223
|
-
version: "0.3.
|
|
223
|
+
version: "0.3.25",
|
|
224
224
|
description: "A context-first, model-agnostic coding agent with an auditable terminal workspace.",
|
|
225
225
|
type: "module",
|
|
226
226
|
license: "MIT",
|
|
@@ -236,6 +236,11 @@ var package_default = {
|
|
|
236
236
|
},
|
|
237
237
|
skein: {
|
|
238
238
|
releaseNotes: [
|
|
239
|
+
"Durable sessions now separate a 250k-token context epoch from a 1m-token lifetime ceiling without changing the session id or deleting transcript history",
|
|
240
|
+
"Content-free epoch handoffs preserve Task Contract criteria, unresolved failure circuits, changed files, and verification receipts across long runs",
|
|
241
|
+
"Intent Sufficiency routes clear requests to execution, repository-inferable gaps to inspection, and genuine product choices to one persisted clarification",
|
|
242
|
+
"TUI and headless output expose epoch, lifetime, and needs-input state; queued follow-ups pause and resume after keyboard clarification instead of becoming accidental answers",
|
|
243
|
+
"Successful identical tool calls clear matching historical failure signatures from later epoch handoffs",
|
|
239
244
|
"Context compaction now rebuilds authoritative task, working-state, verification, permission, failure, and artifact facts outside generated narrative",
|
|
240
245
|
"Automatic compaction runs only when three predicted prompt reuses produce positive net token savings while explicit compact commands remain available",
|
|
241
246
|
"Compaction provider usage is included in session totals with separate content-free actual or estimated receipts",
|
|
@@ -1993,6 +1998,7 @@ var partialConfigSchema = z2.object({
|
|
|
1993
1998
|
}).partial().optional(),
|
|
1994
1999
|
agent: z2.object({
|
|
1995
2000
|
maxTurns: z2.number().int().positive().optional(),
|
|
2001
|
+
maxEpochTokens: z2.number().int().positive().optional(),
|
|
1996
2002
|
maxSessionTokens: z2.number().int().positive().optional(),
|
|
1997
2003
|
autoVerify: z2.boolean().optional(),
|
|
1998
2004
|
verifyCommands: z2.array(z2.string()).optional(),
|
|
@@ -2072,7 +2078,8 @@ function defaultConfig(workspace = process.cwd()) {
|
|
|
2072
2078
|
hooks: {},
|
|
2073
2079
|
agent: {
|
|
2074
2080
|
maxTurns: 24,
|
|
2075
|
-
|
|
2081
|
+
maxEpochTokens: 25e4,
|
|
2082
|
+
maxSessionTokens: 1e6,
|
|
2076
2083
|
autoVerify: true,
|
|
2077
2084
|
verifyCommands: [],
|
|
2078
2085
|
checkpointBeforeWrite: true
|
|
@@ -2436,6 +2443,7 @@ function configSummary(config) {
|
|
|
2436
2443
|
workspaceRoots: config.workspaceRoots,
|
|
2437
2444
|
permissions: config.permissions,
|
|
2438
2445
|
maxTurns: config.agent.maxTurns,
|
|
2446
|
+
maxEpochTokens: config.agent.maxEpochTokens,
|
|
2439
2447
|
maxSessionTokens: config.agent.maxSessionTokens,
|
|
2440
2448
|
autoVerify: config.agent.autoVerify,
|
|
2441
2449
|
skills: config.skills ? {
|
|
@@ -4720,10 +4728,127 @@ function formatContextHits(hits, roots) {
|
|
|
4720
4728
|
}
|
|
4721
4729
|
|
|
4722
4730
|
// src/agent/runner.ts
|
|
4723
|
-
import { randomUUID as
|
|
4731
|
+
import { randomUUID as randomUUID15 } from "node:crypto";
|
|
4724
4732
|
|
|
4725
4733
|
// src/context/manager.ts
|
|
4734
|
+
import { randomUUID as randomUUID5 } from "node:crypto";
|
|
4735
|
+
|
|
4736
|
+
// src/context/epochs.ts
|
|
4726
4737
|
import { randomUUID as randomUUID4 } from "node:crypto";
|
|
4738
|
+
var MAX_EPOCHS = 64;
|
|
4739
|
+
var MAX_HANDOFF_FAILURES = 16;
|
|
4740
|
+
function activeContextEpoch(session) {
|
|
4741
|
+
return ensureContextEpoch(session);
|
|
4742
|
+
}
|
|
4743
|
+
function ensureContextEpoch(session) {
|
|
4744
|
+
const epochs = session.contextEpochs ?? (session.contextEpochs = []);
|
|
4745
|
+
const active = epochs.at(-1);
|
|
4746
|
+
if (active && active.finishedAt === void 0) return active;
|
|
4747
|
+
const next = createEpoch((active?.index ?? 0) + 1);
|
|
4748
|
+
epochs.push(next);
|
|
4749
|
+
trimEpochs(epochs);
|
|
4750
|
+
return next;
|
|
4751
|
+
}
|
|
4752
|
+
function recordContextEpochUsage(session, inputTokens, outputTokens) {
|
|
4753
|
+
const epoch = ensureContextEpoch(session);
|
|
4754
|
+
epoch.usage.inputTokens += boundedTokens(inputTokens);
|
|
4755
|
+
epoch.usage.outputTokens += boundedTokens(outputTokens);
|
|
4756
|
+
return epoch;
|
|
4757
|
+
}
|
|
4758
|
+
function contextEpochTokens(session) {
|
|
4759
|
+
const epoch = ensureContextEpoch(session);
|
|
4760
|
+
return epoch.usage.inputTokens + epoch.usage.outputTokens;
|
|
4761
|
+
}
|
|
4762
|
+
function rotateContextEpoch(session, reason, compaction) {
|
|
4763
|
+
const previous = ensureContextEpoch(session);
|
|
4764
|
+
const createdAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
4765
|
+
const handoff = buildEpochHandoff(session, reason, createdAt, compaction);
|
|
4766
|
+
previous.finishedAt = createdAt;
|
|
4767
|
+
previous.handoff = handoff;
|
|
4768
|
+
const current = createEpoch(previous.index + 1, createdAt);
|
|
4769
|
+
const epochs = session.contextEpochs ?? (session.contextEpochs = []);
|
|
4770
|
+
epochs.push(current);
|
|
4771
|
+
trimEpochs(epochs);
|
|
4772
|
+
return { previous, current, handoff };
|
|
4773
|
+
}
|
|
4774
|
+
function buildEpochHandoff(session, reason, createdAt, compaction) {
|
|
4775
|
+
const failures = unresolvedFailureReceipts(session);
|
|
4776
|
+
const contract = session.taskContract;
|
|
4777
|
+
return {
|
|
4778
|
+
reason,
|
|
4779
|
+
createdAt,
|
|
4780
|
+
...compaction ? { compactionReceiptId: compaction.id } : {},
|
|
4781
|
+
...session.compactedThroughMessageId ? { compactedThroughMessageId: session.compactedThroughMessageId } : {},
|
|
4782
|
+
...contract ? {
|
|
4783
|
+
contract: {
|
|
4784
|
+
state: contract.state,
|
|
4785
|
+
required: contract.acceptanceCriteria.filter((criterion2) => criterion2.required).map((criterion2) => ({
|
|
4786
|
+
id: criterion2.id,
|
|
4787
|
+
status: criterion2.status,
|
|
4788
|
+
evidenceRefs: [...criterion2.evidenceRefs]
|
|
4789
|
+
}))
|
|
4790
|
+
}
|
|
4791
|
+
} : {},
|
|
4792
|
+
unresolvedFailures: failures,
|
|
4793
|
+
changedFiles: [...new Set(session.changedFiles)].slice(-256),
|
|
4794
|
+
checks: session.lastRun?.checks.map((check) => ({ ...check })) ?? []
|
|
4795
|
+
};
|
|
4796
|
+
}
|
|
4797
|
+
function unresolvedFailureReceipts(session) {
|
|
4798
|
+
const unresolved2 = /* @__PURE__ */ new Map();
|
|
4799
|
+
for (const event of session.audit ?? []) {
|
|
4800
|
+
if (event.type !== "tool") continue;
|
|
4801
|
+
if (event.outcome === "failure") {
|
|
4802
|
+
const receipt = failureReceipt(event.metadata?.failure);
|
|
4803
|
+
if (receipt) unresolved2.set(receipt.signature, receipt);
|
|
4804
|
+
continue;
|
|
4805
|
+
}
|
|
4806
|
+
const resolved = event.metadata?.resolvedFailureSignatures;
|
|
4807
|
+
if (!Array.isArray(resolved)) continue;
|
|
4808
|
+
for (const signature of resolved) {
|
|
4809
|
+
if (typeof signature === "string") unresolved2.delete(signature);
|
|
4810
|
+
}
|
|
4811
|
+
}
|
|
4812
|
+
return [...unresolved2.values()].slice(-MAX_HANDOFF_FAILURES);
|
|
4813
|
+
}
|
|
4814
|
+
function failureReceipt(value) {
|
|
4815
|
+
if (!value || typeof value !== "object") return;
|
|
4816
|
+
const candidate = value;
|
|
4817
|
+
const classes = /* @__PURE__ */ new Set([
|
|
4818
|
+
"schema_input",
|
|
4819
|
+
"unknown_tool",
|
|
4820
|
+
"permission_denied",
|
|
4821
|
+
"command_exit",
|
|
4822
|
+
"timeout",
|
|
4823
|
+
"cancelled",
|
|
4824
|
+
"hook",
|
|
4825
|
+
"execution",
|
|
4826
|
+
"no_progress",
|
|
4827
|
+
"contract_required"
|
|
4828
|
+
]);
|
|
4829
|
+
if (typeof candidate.signature !== "string" || !candidate.signature || typeof candidate.class !== "string" || !classes.has(candidate.class) || typeof candidate.circuitOpen !== "boolean") return;
|
|
4830
|
+
return {
|
|
4831
|
+
signature: candidate.signature.slice(0, 256),
|
|
4832
|
+
class: candidate.class,
|
|
4833
|
+
circuitOpen: candidate.circuitOpen
|
|
4834
|
+
};
|
|
4835
|
+
}
|
|
4836
|
+
function createEpoch(index, startedAt = (/* @__PURE__ */ new Date()).toISOString()) {
|
|
4837
|
+
return {
|
|
4838
|
+
id: randomUUID4(),
|
|
4839
|
+
index,
|
|
4840
|
+
startedAt,
|
|
4841
|
+
usage: { inputTokens: 0, outputTokens: 0 }
|
|
4842
|
+
};
|
|
4843
|
+
}
|
|
4844
|
+
function trimEpochs(epochs) {
|
|
4845
|
+
if (epochs.length > MAX_EPOCHS) epochs.splice(0, epochs.length - MAX_EPOCHS);
|
|
4846
|
+
}
|
|
4847
|
+
function boundedTokens(value) {
|
|
4848
|
+
return Number.isFinite(value) && value > 0 ? Math.floor(value) : 0;
|
|
4849
|
+
}
|
|
4850
|
+
|
|
4851
|
+
// src/context/manager.ts
|
|
4727
4852
|
var RECENT_TURN_RESERVE = 3;
|
|
4728
4853
|
var COMPACTION_HIGH_WATER = 0.78;
|
|
4729
4854
|
var TOOL_PRESSURE_WATER = 0.28;
|
|
@@ -4776,13 +4901,21 @@ var ContextManager = class {
|
|
|
4776
4901
|
modelContextTokens ?? Math.min(1e5, this.config.context.maxTokens * 3)
|
|
4777
4902
|
);
|
|
4778
4903
|
const compactedMessages = session.compactedThroughMessageId ? Math.max(0, session.messages.findIndex((message2) => message2.id === session.compactedThroughMessageId) + 1) : 0;
|
|
4904
|
+
const epoch = activeContextEpoch(session);
|
|
4905
|
+
const epochBudget = this.config.agent.maxEpochTokens ?? this.config.agent.maxSessionTokens;
|
|
4779
4906
|
return {
|
|
4780
4907
|
activeTokens,
|
|
4781
4908
|
summaryTokens,
|
|
4782
4909
|
toolTokens: toolTokenCount,
|
|
4783
4910
|
messageCount: active.length,
|
|
4784
4911
|
compactedMessages,
|
|
4785
|
-
pressure: Math.min(1, (activeTokens + summaryTokens) / contextLimit)
|
|
4912
|
+
pressure: Math.min(1, (activeTokens + summaryTokens) / contextLimit),
|
|
4913
|
+
epochIndex: epoch.index,
|
|
4914
|
+
epochCount: epoch.index,
|
|
4915
|
+
epochTokens: epoch.usage.inputTokens + epoch.usage.outputTokens,
|
|
4916
|
+
epochBudget,
|
|
4917
|
+
lifetimeTokens: session.usage.inputTokens + session.usage.outputTokens,
|
|
4918
|
+
lifetimeBudget: this.config.agent.maxSessionTokens
|
|
4786
4919
|
};
|
|
4787
4920
|
}
|
|
4788
4921
|
shouldCompact(session, tokenBudget) {
|
|
@@ -4891,7 +5024,7 @@ function compactionEstimate(session, older, facts, request) {
|
|
|
4891
5024
|
}
|
|
4892
5025
|
function skippedCompaction(session, mode, reason, estimate = emptyCompactionEstimate(session)) {
|
|
4893
5026
|
const receipt = {
|
|
4894
|
-
id:
|
|
5027
|
+
id: randomUUID5(),
|
|
4895
5028
|
recordedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
4896
5029
|
mode,
|
|
4897
5030
|
status: "skipped",
|
|
@@ -4928,7 +5061,7 @@ function emptyCompactionEstimate(session) {
|
|
|
4928
5061
|
function completedCompactionReceipt(mode, omittedMessages, compactedThroughMessageId, estimated, response, summary) {
|
|
4929
5062
|
const actual = actualUsage(response.usage);
|
|
4930
5063
|
return {
|
|
4931
|
-
id:
|
|
5064
|
+
id: randomUUID5(),
|
|
4932
5065
|
recordedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
4933
5066
|
mode,
|
|
4934
5067
|
status: "compacted",
|
|
@@ -4967,6 +5100,7 @@ function buildCompactionFactsEnvelope(session, throughMessageId) {
|
|
|
4967
5100
|
const memory = session.workingMemory;
|
|
4968
5101
|
const contract = session.taskContract;
|
|
4969
5102
|
const lastRun = session.lastRun;
|
|
5103
|
+
const epoch = activeContextEpoch(session);
|
|
4970
5104
|
const directives = olderUserDirectives(session, throughMessageId ?? session.compactedThroughMessageId);
|
|
4971
5105
|
const permissions = recentPermissionFacts(session.audit ?? []);
|
|
4972
5106
|
const failures = recentFailureFacts(session.audit ?? []);
|
|
@@ -5019,6 +5153,11 @@ ${factList(memory?.relevantFiles ?? [])}
|
|
|
5019
5153
|
Session changed files:
|
|
5020
5154
|
${factList(session.changedFiles)}
|
|
5021
5155
|
|
|
5156
|
+
Context epoch ledger:
|
|
5157
|
+
- Current epoch: ${epoch.index}
|
|
5158
|
+
- Current epoch usage: input=${epoch.usage.inputTokens}; output=${epoch.usage.outputTokens}
|
|
5159
|
+
- Lifetime usage: input=${session.usage.inputTokens}; output=${session.usage.outputTokens}
|
|
5160
|
+
|
|
5022
5161
|
Last-run verification and residual state:
|
|
5023
5162
|
${lastRunLines}
|
|
5024
5163
|
|
|
@@ -5462,7 +5601,7 @@ function normalizeForMatch(value) {
|
|
|
5462
5601
|
}
|
|
5463
5602
|
|
|
5464
5603
|
// src/providers/anthropic.ts
|
|
5465
|
-
import { randomUUID as
|
|
5604
|
+
import { randomUUID as randomUUID6 } from "node:crypto";
|
|
5466
5605
|
|
|
5467
5606
|
// src/providers/provider.ts
|
|
5468
5607
|
var ProviderError = class extends Error {
|
|
@@ -5587,7 +5726,7 @@ var AnthropicProvider = class {
|
|
|
5587
5726
|
return {
|
|
5588
5727
|
content: blocks.filter((block) => block.type === "text").map((block) => block.text ?? "").join("\n"),
|
|
5589
5728
|
toolCalls: blocks.filter((block) => block.type === "tool_use").map((block) => ({
|
|
5590
|
-
id: block.id ??
|
|
5729
|
+
id: block.id ?? randomUUID6(),
|
|
5591
5730
|
name: block.name ?? "unknown",
|
|
5592
5731
|
arguments: safeJsonArguments(block.input)
|
|
5593
5732
|
})),
|
|
@@ -5661,7 +5800,7 @@ var AnthropicProvider = class {
|
|
|
5661
5800
|
}
|
|
5662
5801
|
if (chunk.type === "content_block_start" && chunk.content_block?.type === "tool_use") {
|
|
5663
5802
|
calls.set(index, {
|
|
5664
|
-
id: chunk.content_block.id ??
|
|
5803
|
+
id: chunk.content_block.id ?? randomUUID6(),
|
|
5665
5804
|
name: chunk.content_block.name ?? "unknown",
|
|
5666
5805
|
input: chunk.content_block.input,
|
|
5667
5806
|
partialJson: ""
|
|
@@ -5672,7 +5811,7 @@ var AnthropicProvider = class {
|
|
|
5672
5811
|
yield { type: "text_delta", content: chunk.delta.text };
|
|
5673
5812
|
}
|
|
5674
5813
|
if (chunk.type === "content_block_delta" && chunk.delta?.type === "input_json_delta") {
|
|
5675
|
-
const call = calls.get(index) ?? { id:
|
|
5814
|
+
const call = calls.get(index) ?? { id: randomUUID6(), name: "unknown", input: void 0, partialJson: "" };
|
|
5676
5815
|
call.partialJson += chunk.delta.partial_json ?? "";
|
|
5677
5816
|
calls.set(index, call);
|
|
5678
5817
|
}
|
|
@@ -5702,7 +5841,7 @@ function normalizeAnthropicResponse(data) {
|
|
|
5702
5841
|
return {
|
|
5703
5842
|
content: blocks.filter((block) => block.type === "text").map((block) => block.text ?? "").join("\n"),
|
|
5704
5843
|
toolCalls: blocks.filter((block) => block.type === "tool_use").map((block) => ({
|
|
5705
|
-
id: block.id ??
|
|
5844
|
+
id: block.id ?? randomUUID6(),
|
|
5706
5845
|
name: block.name ?? "unknown",
|
|
5707
5846
|
arguments: safeJsonArguments(block.input)
|
|
5708
5847
|
})),
|
|
@@ -5747,7 +5886,7 @@ function toAnthropicMessage(message2) {
|
|
|
5747
5886
|
}
|
|
5748
5887
|
|
|
5749
5888
|
// src/providers/gemini.ts
|
|
5750
|
-
import { randomUUID as
|
|
5889
|
+
import { randomUUID as randomUUID7 } from "node:crypto";
|
|
5751
5890
|
var GeminiProvider = class {
|
|
5752
5891
|
constructor(config) {
|
|
5753
5892
|
this.config = config;
|
|
@@ -5787,7 +5926,7 @@ var GeminiProvider = class {
|
|
|
5787
5926
|
return {
|
|
5788
5927
|
content: parts.map((part) => part.text ?? "").filter(Boolean).join("\n"),
|
|
5789
5928
|
toolCalls: parts.filter((part) => part.functionCall).map((part) => ({
|
|
5790
|
-
id:
|
|
5929
|
+
id: randomUUID7(),
|
|
5791
5930
|
name: part.functionCall?.name ?? "unknown",
|
|
5792
5931
|
arguments: safeJsonArguments(part.functionCall?.args)
|
|
5793
5932
|
})),
|
|
@@ -5859,7 +5998,7 @@ var GeminiProvider = class {
|
|
|
5859
5998
|
}
|
|
5860
5999
|
if (part.functionCall) {
|
|
5861
6000
|
toolCalls.push({
|
|
5862
|
-
id:
|
|
6001
|
+
id: randomUUID7(),
|
|
5863
6002
|
name: part.functionCall.name ?? "unknown",
|
|
5864
6003
|
arguments: safeJsonArguments(part.functionCall.args)
|
|
5865
6004
|
});
|
|
@@ -5888,7 +6027,7 @@ function normalizeGeminiResponse(data) {
|
|
|
5888
6027
|
return {
|
|
5889
6028
|
content: parts.map((part) => part.text ?? "").filter(Boolean).join("\n"),
|
|
5890
6029
|
toolCalls: parts.filter((part) => part.functionCall).map((part) => ({
|
|
5891
|
-
id:
|
|
6030
|
+
id: randomUUID7(),
|
|
5892
6031
|
name: part.functionCall?.name ?? "unknown",
|
|
5893
6032
|
arguments: safeJsonArguments(part.functionCall?.args)
|
|
5894
6033
|
})),
|
|
@@ -5932,7 +6071,7 @@ function toGeminiMessage(message2) {
|
|
|
5932
6071
|
}
|
|
5933
6072
|
|
|
5934
6073
|
// src/providers/openai.ts
|
|
5935
|
-
import { randomUUID as
|
|
6074
|
+
import { randomUUID as randomUUID8 } from "node:crypto";
|
|
5936
6075
|
var OpenAIProvider = class {
|
|
5937
6076
|
constructor(config) {
|
|
5938
6077
|
this.config = config;
|
|
@@ -6055,7 +6194,7 @@ var OpenAIProvider = class {
|
|
|
6055
6194
|
}
|
|
6056
6195
|
for (const fragment of delta?.tool_calls ?? []) {
|
|
6057
6196
|
const index = fragment.index ?? 0;
|
|
6058
|
-
const current = calls.get(index) ?? { id:
|
|
6197
|
+
const current = calls.get(index) ?? { id: randomUUID8(), name: "", arguments: "" };
|
|
6059
6198
|
if (fragment.id) current.id = fragment.id;
|
|
6060
6199
|
if (fragment.function?.name) current.name += fragment.function.name;
|
|
6061
6200
|
if (fragment.function?.arguments) current.arguments += fragment.function.arguments;
|
|
@@ -6089,7 +6228,7 @@ function normalizeOpenAIResponse(data) {
|
|
|
6089
6228
|
return {
|
|
6090
6229
|
content: message2.content ?? "",
|
|
6091
6230
|
toolCalls: (message2.tool_calls ?? []).map((call) => ({
|
|
6092
|
-
id: call.id ??
|
|
6231
|
+
id: call.id ?? randomUUID8(),
|
|
6093
6232
|
name: call.function?.name ?? "unknown",
|
|
6094
6233
|
arguments: safeJsonArguments(call.function?.arguments)
|
|
6095
6234
|
})),
|
|
@@ -6145,7 +6284,7 @@ function createProvider(config) {
|
|
|
6145
6284
|
}
|
|
6146
6285
|
|
|
6147
6286
|
// src/checkpoint/store.ts
|
|
6148
|
-
import { createHash as createHash8, randomUUID as
|
|
6287
|
+
import { createHash as createHash8, randomUUID as randomUUID9 } from "node:crypto";
|
|
6149
6288
|
import { lstat as lstat10, mkdir as mkdir7, readFile as readFile5, readdir as readdir2, unlink as unlink2 } from "node:fs/promises";
|
|
6150
6289
|
import { basename as basename6, dirname as dirname8, join as join9, relative as relative6, resolve as resolve12 } from "node:path";
|
|
6151
6290
|
import { z as z4 } from "zod";
|
|
@@ -6181,7 +6320,7 @@ var CheckpointStore = class {
|
|
|
6181
6320
|
return this.withManagedLease(() => this.captureUnlocked(sessionId, unique3, options));
|
|
6182
6321
|
}
|
|
6183
6322
|
async captureUnlocked(sessionId, unique3, options) {
|
|
6184
|
-
const id = `${Date.now().toString(36)}-${
|
|
6323
|
+
const id = `${Date.now().toString(36)}-${randomUUID9()}`;
|
|
6185
6324
|
const target = join9(this.directory, sessionId, id);
|
|
6186
6325
|
const blobDirectory = join9(target, "blobs");
|
|
6187
6326
|
await this.ensureDirectory();
|
|
@@ -6457,7 +6596,7 @@ var HookRunner = class {
|
|
|
6457
6596
|
};
|
|
6458
6597
|
|
|
6459
6598
|
// src/session/store.ts
|
|
6460
|
-
import { randomUUID as
|
|
6599
|
+
import { randomUUID as randomUUID10 } from "node:crypto";
|
|
6461
6600
|
import { constants as constants4 } from "node:fs";
|
|
6462
6601
|
import {
|
|
6463
6602
|
chmod as chmod6,
|
|
@@ -6683,6 +6822,76 @@ var contextCompactionReceiptSchema = z5.object({
|
|
|
6683
6822
|
outputSource: z5.enum(["actual", "estimated", "none"]),
|
|
6684
6823
|
narrative: z5.enum(["present", "empty", "not-requested"])
|
|
6685
6824
|
}).strict();
|
|
6825
|
+
var contextEpochSchema = z5.object({
|
|
6826
|
+
id: z5.string().uuid(),
|
|
6827
|
+
index: z5.number().int().positive(),
|
|
6828
|
+
startedAt: z5.string().datetime(),
|
|
6829
|
+
finishedAt: z5.string().datetime().optional(),
|
|
6830
|
+
usage: z5.object({
|
|
6831
|
+
inputTokens: z5.number().int().nonnegative(),
|
|
6832
|
+
outputTokens: z5.number().int().nonnegative()
|
|
6833
|
+
}).strict(),
|
|
6834
|
+
handoff: z5.object({
|
|
6835
|
+
reason: z5.enum(["token_budget", "context_pressure", "manual"]),
|
|
6836
|
+
createdAt: z5.string().datetime(),
|
|
6837
|
+
compactionReceiptId: z5.string().uuid().optional(),
|
|
6838
|
+
compactedThroughMessageId: z5.string().optional(),
|
|
6839
|
+
contract: z5.object({
|
|
6840
|
+
state: z5.enum(["draft", "active", "satisfied", "blocked"]),
|
|
6841
|
+
required: z5.array(z5.object({
|
|
6842
|
+
id: z5.string().min(1).max(128),
|
|
6843
|
+
status: z5.enum(["pending", "satisfied", "blocked"]),
|
|
6844
|
+
evidenceRefs: z5.array(z5.string().min(1).max(256)).max(64)
|
|
6845
|
+
}).strict()).max(64)
|
|
6846
|
+
}).strict().optional(),
|
|
6847
|
+
unresolvedFailures: z5.array(z5.object({
|
|
6848
|
+
signature: z5.string().min(1).max(256),
|
|
6849
|
+
class: z5.enum([
|
|
6850
|
+
"schema_input",
|
|
6851
|
+
"unknown_tool",
|
|
6852
|
+
"permission_denied",
|
|
6853
|
+
"command_exit",
|
|
6854
|
+
"timeout",
|
|
6855
|
+
"cancelled",
|
|
6856
|
+
"hook",
|
|
6857
|
+
"execution",
|
|
6858
|
+
"no_progress",
|
|
6859
|
+
"contract_required"
|
|
6860
|
+
]),
|
|
6861
|
+
circuitOpen: z5.boolean()
|
|
6862
|
+
}).strict()).max(16),
|
|
6863
|
+
changedFiles: z5.array(z5.string().max(4096)).max(256),
|
|
6864
|
+
checks: z5.array(verificationEvidenceSchema).max(64)
|
|
6865
|
+
}).strict().optional()
|
|
6866
|
+
}).strict();
|
|
6867
|
+
var intentAssessmentSchema = z5.object({
|
|
6868
|
+
version: z5.literal(1),
|
|
6869
|
+
route: z5.enum(["direct_execute", "inspect_then_execute", "needs_input", "permission_required"]),
|
|
6870
|
+
reasons: z5.array(z5.enum([
|
|
6871
|
+
"simple_explicit_request",
|
|
6872
|
+
"workspace_inference_available",
|
|
6873
|
+
"explicit_user_choice_missing",
|
|
6874
|
+
"public_api_compatibility_missing",
|
|
6875
|
+
"runtime_permission_separate",
|
|
6876
|
+
"clarification_resolved"
|
|
6877
|
+
])).min(1).max(8),
|
|
6878
|
+
assessedAt: z5.string().datetime(),
|
|
6879
|
+
retrievalHits: z5.number().int().nonnegative()
|
|
6880
|
+
}).strict();
|
|
6881
|
+
var pendingInputSchema = z5.object({
|
|
6882
|
+
id: z5.string().uuid(),
|
|
6883
|
+
runId: z5.string().uuid(),
|
|
6884
|
+
createdAt: z5.string().datetime(),
|
|
6885
|
+
originalRequest: z5.string().min(1).max(12e4),
|
|
6886
|
+
question: z5.string().min(1).max(2e3),
|
|
6887
|
+
options: z5.array(z5.object({
|
|
6888
|
+
id: z5.string().regex(/^[a-z][a-z0-9_-]{0,63}$/u),
|
|
6889
|
+
label: z5.string().min(1).max(160),
|
|
6890
|
+
impact: z5.string().min(1).max(500),
|
|
6891
|
+
recommended: z5.boolean()
|
|
6892
|
+
}).strict()).min(2).max(3),
|
|
6893
|
+
reason: z5.enum(["explicit_user_choice_missing", "public_api_compatibility_missing"])
|
|
6894
|
+
}).strict();
|
|
6686
6895
|
var sessionSchema = z5.object({
|
|
6687
6896
|
id: sessionIdSchema,
|
|
6688
6897
|
title: z5.string(),
|
|
@@ -6699,6 +6908,9 @@ var sessionSchema = z5.object({
|
|
|
6699
6908
|
contextCompactions: z5.number().int().nonnegative().optional(),
|
|
6700
6909
|
compactedThroughMessageId: z5.string().optional(),
|
|
6701
6910
|
contextCompactionReceipts: z5.array(contextCompactionReceiptSchema).max(64).optional(),
|
|
6911
|
+
contextEpochs: z5.array(contextEpochSchema).max(64).optional(),
|
|
6912
|
+
intentAssessment: intentAssessmentSchema.optional(),
|
|
6913
|
+
pendingInput: pendingInputSchema.optional(),
|
|
6702
6914
|
workingMemory: workingMemorySchema.optional(),
|
|
6703
6915
|
contextSources: z5.array(contextSourceSchema).max(64).optional(),
|
|
6704
6916
|
toolArtifacts: z5.array(toolArtifactSchema).max(200).optional(),
|
|
@@ -6849,7 +7061,7 @@ var SessionStore = class {
|
|
|
6849
7061
|
const backup = this.backupPathFor(session.id);
|
|
6850
7062
|
await this.assertManagedFile(target);
|
|
6851
7063
|
await this.assertManagedFile(backup);
|
|
6852
|
-
const temporary = join10(this.directory, `.${session.id}.${
|
|
7064
|
+
const temporary = join10(this.directory, `.${session.id}.${randomUUID10()}.tmp`);
|
|
6853
7065
|
const data = `${JSON.stringify(session, null, 2)}
|
|
6854
7066
|
`;
|
|
6855
7067
|
const handle = await open2(temporary, "wx", 384);
|
|
@@ -6867,7 +7079,7 @@ var SessionStore = class {
|
|
|
6867
7079
|
}
|
|
6868
7080
|
}
|
|
6869
7081
|
async copyBackup(source, target) {
|
|
6870
|
-
const temporary = join10(this.directory, `.${basename7(target)}.${
|
|
7082
|
+
const temporary = join10(this.directory, `.${basename7(target)}.${randomUUID10()}.tmp`);
|
|
6871
7083
|
try {
|
|
6872
7084
|
await copyFile(source, temporary, constants4.COPYFILE_EXCL);
|
|
6873
7085
|
await chmod6(temporary, 384);
|
|
@@ -6956,7 +7168,7 @@ var SessionStore = class {
|
|
|
6956
7168
|
}
|
|
6957
7169
|
};
|
|
6958
7170
|
function createSession(options) {
|
|
6959
|
-
const id = options.id ??
|
|
7171
|
+
const id = options.id ?? randomUUID10();
|
|
6960
7172
|
validateId(id);
|
|
6961
7173
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
6962
7174
|
return {
|
|
@@ -6971,6 +7183,12 @@ function createSession(options) {
|
|
|
6971
7183
|
tasks: [],
|
|
6972
7184
|
changedFiles: [],
|
|
6973
7185
|
audit: [],
|
|
7186
|
+
contextEpochs: [{
|
|
7187
|
+
id: randomUUID10(),
|
|
7188
|
+
index: 1,
|
|
7189
|
+
startedAt: now,
|
|
7190
|
+
usage: { inputTokens: 0, outputTokens: 0 }
|
|
7191
|
+
}],
|
|
6974
7192
|
usage: { inputTokens: 0, outputTokens: 0 }
|
|
6975
7193
|
};
|
|
6976
7194
|
}
|
|
@@ -8063,7 +8281,7 @@ function isUnsafeGitOption(argument) {
|
|
|
8063
8281
|
"--exclude-from",
|
|
8064
8282
|
"--output",
|
|
8065
8283
|
"--directory"
|
|
8066
|
-
].some((
|
|
8284
|
+
].some((option2) => argument === option2 || argument.startsWith(`${option2}=`));
|
|
8067
8285
|
}
|
|
8068
8286
|
function firstGitCommand(args) {
|
|
8069
8287
|
for (const argument of args) {
|
|
@@ -8811,7 +9029,7 @@ async function discoverSnapshotFiles(root) {
|
|
|
8811
9029
|
}
|
|
8812
9030
|
|
|
8813
9031
|
// src/tools/task.ts
|
|
8814
|
-
import { randomUUID as
|
|
9032
|
+
import { randomUUID as randomUUID11 } from "node:crypto";
|
|
8815
9033
|
import { z as z14 } from "zod";
|
|
8816
9034
|
var taskSchema2 = z14.object({
|
|
8817
9035
|
id: z14.string().min(1).optional(),
|
|
@@ -8860,7 +9078,7 @@ var taskTool = {
|
|
|
8860
9078
|
case "list":
|
|
8861
9079
|
break;
|
|
8862
9080
|
case "add":
|
|
8863
|
-
tasks.push({ id:
|
|
9081
|
+
tasks.push({ id: randomUUID11(), title: input2.title, status: input2.status ?? "pending" });
|
|
8864
9082
|
break;
|
|
8865
9083
|
case "update": {
|
|
8866
9084
|
const task = tasks.find((item) => item.id === input2.id);
|
|
@@ -8877,7 +9095,7 @@ var taskTool = {
|
|
|
8877
9095
|
}
|
|
8878
9096
|
case "replace":
|
|
8879
9097
|
tasks.splice(0, tasks.length, ...input2.tasks.map((task) => ({
|
|
8880
|
-
id: task.id ??
|
|
9098
|
+
id: task.id ?? randomUUID11(),
|
|
8881
9099
|
title: task.title,
|
|
8882
9100
|
status: task.status
|
|
8883
9101
|
})));
|
|
@@ -8891,11 +9109,11 @@ var taskTool = {
|
|
|
8891
9109
|
};
|
|
8892
9110
|
|
|
8893
9111
|
// src/tools/task-contract.ts
|
|
8894
|
-
import { randomUUID as
|
|
9112
|
+
import { randomUUID as randomUUID13 } from "node:crypto";
|
|
8895
9113
|
import { z as z15 } from "zod";
|
|
8896
9114
|
|
|
8897
9115
|
// src/agent/task-contract.ts
|
|
8898
|
-
import { randomUUID as
|
|
9116
|
+
import { randomUUID as randomUUID12 } from "node:crypto";
|
|
8899
9117
|
var EXECUTABLE_INTENTS = /* @__PURE__ */ new Set(["debug", "refactor", "test", "implement"]);
|
|
8900
9118
|
function shouldUseTaskContract(request, intent, existing) {
|
|
8901
9119
|
if (existing && existing.state !== "satisfied") return true;
|
|
@@ -8961,7 +9179,7 @@ function refreshTaskContractState(contract) {
|
|
|
8961
9179
|
}
|
|
8962
9180
|
function criterion(id, description) {
|
|
8963
9181
|
return {
|
|
8964
|
-
id: `${id}-${
|
|
9182
|
+
id: `${id}-${randomUUID12().slice(0, 8)}`,
|
|
8965
9183
|
description,
|
|
8966
9184
|
required: true,
|
|
8967
9185
|
status: "pending",
|
|
@@ -9515,7 +9733,7 @@ var taskContractTool = {
|
|
|
9515
9733
|
}
|
|
9516
9734
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
9517
9735
|
const criteria = input2.acceptance_criteria.map((item) => ({
|
|
9518
|
-
id: item.id ?? `criterion-${
|
|
9736
|
+
id: item.id ?? `criterion-${randomUUID13().slice(0, 8)}`,
|
|
9519
9737
|
description: item.description,
|
|
9520
9738
|
required: item.required ?? true,
|
|
9521
9739
|
status: "pending",
|
|
@@ -9983,6 +10201,118 @@ function escapeAttribute3(value) {
|
|
|
9983
10201
|
})[character] ?? character);
|
|
9984
10202
|
}
|
|
9985
10203
|
|
|
10204
|
+
// src/agent/intent-sufficiency.ts
|
|
10205
|
+
import { randomUUID as randomUUID14 } from "node:crypto";
|
|
10206
|
+
function assessIntentSufficiency(request, intent, context) {
|
|
10207
|
+
const assessedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
10208
|
+
const uiChoice = explicitUiChoice(request);
|
|
10209
|
+
if (uiChoice) {
|
|
10210
|
+
const pending = clarification(
|
|
10211
|
+
request,
|
|
10212
|
+
assessedAt,
|
|
10213
|
+
"explicit_user_choice_missing",
|
|
10214
|
+
isChinese(request) ? "\u8FD9\u4E2A\u754C\u9762\u884C\u4E3A\u9700\u8981\u4F60\u7684\u4EA7\u54C1\u504F\u597D\uFF0C\u5E94\u91C7\u7528\u54EA\u4E00\u79CD\uFF1F" : "This UI behavior depends on your product preference. Which should be used?",
|
|
10215
|
+
uiChoice
|
|
10216
|
+
);
|
|
10217
|
+
return {
|
|
10218
|
+
assessment: assessment("needs_input", "explicit_user_choice_missing", assessedAt, context.retrievalHits),
|
|
10219
|
+
pending,
|
|
10220
|
+
directive: "Pause before mutation and ask the single recorded clarification question."
|
|
10221
|
+
};
|
|
10222
|
+
}
|
|
10223
|
+
if (publicApiCompatibilityMissing(request)) {
|
|
10224
|
+
const chinese = isChinese(request);
|
|
10225
|
+
const pending = clarification(
|
|
10226
|
+
request,
|
|
10227
|
+
assessedAt,
|
|
10228
|
+
"public_api_compatibility_missing",
|
|
10229
|
+
chinese ? "\u516C\u5171 API \u7684\u517C\u5BB9\u7B56\u7565\u5C1A\u672A\u6307\u5B9A\uFF0C\u5E94\u8BE5\u91C7\u7528\u54EA\u4E00\u79CD\uFF1F" : "The public API compatibility policy is unspecified. Which policy should be used?",
|
|
10230
|
+
chinese ? [
|
|
10231
|
+
option("backward_compatible", "\u4FDD\u6301\u5411\u540E\u517C\u5BB9", "\u4FDD\u7559\u65E7\u63A5\u53E3\u5E76\u63D0\u4F9B\u5F03\u7528\u6216\u8FC1\u79FB\u8DEF\u5F84\uFF1B\u6539\u52A8\u66F4\u7A33\u59A5\u4F46\u5B9E\u73B0\u8303\u56F4\u8F83\u5927\u3002", true),
|
|
10232
|
+
option("breaking_change", "\u5141\u8BB8\u7834\u574F\u6027\u53D8\u66F4", "\u76F4\u63A5\u91C7\u7528\u65B0\u63A5\u53E3\uFF1B\u8303\u56F4\u66F4\u5C0F\uFF0C\u4F46\u8C03\u7528\u65B9\u5FC5\u987B\u540C\u6B65\u8FC1\u79FB\u3002", false)
|
|
10233
|
+
] : [
|
|
10234
|
+
option("backward_compatible", "Preserve compatibility", "Keep the old API with a deprecation or migration path; safer but broader.", true),
|
|
10235
|
+
option("breaking_change", "Allow breaking change", "Adopt the new API directly; smaller change but callers must migrate.", false)
|
|
10236
|
+
]
|
|
10237
|
+
);
|
|
10238
|
+
return {
|
|
10239
|
+
assessment: assessment("needs_input", "public_api_compatibility_missing", assessedAt, context.retrievalHits),
|
|
10240
|
+
pending,
|
|
10241
|
+
directive: "Pause before mutation and ask the single recorded clarification question."
|
|
10242
|
+
};
|
|
10243
|
+
}
|
|
10244
|
+
if (requiresRuntimePermission(request)) {
|
|
10245
|
+
return {
|
|
10246
|
+
assessment: assessment("permission_required", "runtime_permission_separate", assessedAt, context.retrievalHits),
|
|
10247
|
+
directive: "The objective is sufficiently clear. Continue, but keep runtime permission approval separate from clarification."
|
|
10248
|
+
};
|
|
10249
|
+
}
|
|
10250
|
+
if (context.complex && shouldInspectWorkspace(request, intent)) {
|
|
10251
|
+
return {
|
|
10252
|
+
assessment: assessment("inspect_then_execute", "workspace_inference_available", assessedAt, context.retrievalHits),
|
|
10253
|
+
directive: "Do not ask the user for repository facts. Inspect the workspace and current evidence before the first mutation."
|
|
10254
|
+
};
|
|
10255
|
+
}
|
|
10256
|
+
return {
|
|
10257
|
+
assessment: assessment("direct_execute", "simple_explicit_request", assessedAt, context.retrievalHits),
|
|
10258
|
+
directive: "The request is sufficiently clear. Execute without an extra clarification turn."
|
|
10259
|
+
};
|
|
10260
|
+
}
|
|
10261
|
+
function resolvePendingInput(pending, answer) {
|
|
10262
|
+
const normalized = answer.trim();
|
|
10263
|
+
const byIndex = /^([1-3])(?:[.)、:]|$)/u.exec(normalized)?.[1];
|
|
10264
|
+
const selected = pending.options.find((candidate) => candidate.id.toLocaleLowerCase() === normalized.toLocaleLowerCase() || candidate.label.toLocaleLowerCase() === normalized.toLocaleLowerCase()) ?? (byIndex ? pending.options[Number(byIndex) - 1] : void 0);
|
|
10265
|
+
const decision = selected ? `${selected.label}: ${selected.impact}` : compact2(normalized, 2e3);
|
|
10266
|
+
return { answer: compact2(normalized, 2e3), decision };
|
|
10267
|
+
}
|
|
10268
|
+
function assessment(route, reason, assessedAt, retrievalHits) {
|
|
10269
|
+
return { version: 1, route, reasons: [reason], assessedAt, retrievalHits };
|
|
10270
|
+
}
|
|
10271
|
+
function clarification(originalRequest, createdAt, reason, question2, options) {
|
|
10272
|
+
return {
|
|
10273
|
+
id: randomUUID14(),
|
|
10274
|
+
runId: randomUUID14(),
|
|
10275
|
+
createdAt,
|
|
10276
|
+
originalRequest: originalRequest.slice(0, 12e4),
|
|
10277
|
+
question: question2,
|
|
10278
|
+
options,
|
|
10279
|
+
reason
|
|
10280
|
+
};
|
|
10281
|
+
}
|
|
10282
|
+
function explicitUiChoice(value) {
|
|
10283
|
+
const terms = "modal|dialog|drawer|popover|inline|new page|side panel|\u5F39\u7A97|\u6A21\u6001\u6846|\u62BD\u5C49|\u6D6E\u5C42|\u5185\u8054|\u9875\u9762\u5185|\u4FA7\u8FB9\u680F|\u65B0\u9875\u9762";
|
|
10284
|
+
const match = value.match(new RegExp(`\\b(${terms})\\b\\s*(?:or|versus|vs\\.?)\\s*\\b(${terms})\\b`, "iu")) ?? value.match(new RegExp(`(${terms})[\uFF0C\u3001\\s]*(?:\u8FD8\u662F|\u6216\u8005|\u6216)[\uFF0C\u3001\\s]*(${terms})`, "iu"));
|
|
10285
|
+
if (!match?.[1] || !match[2] || match[1].toLocaleLowerCase() === match[2].toLocaleLowerCase()) return;
|
|
10286
|
+
const chinese = isChinese(value);
|
|
10287
|
+
return [
|
|
10288
|
+
option("choice_1", compact2(match[1], 80), chinese ? "\u91C7\u7528\u8BF7\u6C42\u4E2D\u5217\u51FA\u7684\u7B2C\u4E00\u79CD\u4EA4\u4E92\u65B9\u5F0F\u3002" : "Use the first interaction named in the request.", true),
|
|
10289
|
+
option("choice_2", compact2(match[2], 80), chinese ? "\u91C7\u7528\u8BF7\u6C42\u4E2D\u5217\u51FA\u7684\u7B2C\u4E8C\u79CD\u4EA4\u4E92\u65B9\u5F0F\u3002" : "Use the second interaction named in the request.", false)
|
|
10290
|
+
];
|
|
10291
|
+
}
|
|
10292
|
+
function publicApiCompatibilityMissing(value) {
|
|
10293
|
+
const api = /\b(?:public|external|exported)\s+(?:api|interface|contract)\b|公共\s*(?:api|接口)|公开\s*(?:api|接口)|对外接口/iu;
|
|
10294
|
+
const change = /\b(?:change|replace|remove|rename|migrate|redesign|refactor)\b|修改|替换|删除|移除|重命名|迁移|重构/iu;
|
|
10295
|
+
const policy = /\b(?:backward compatible|backwards compatible|breaking change|semver major|deprecat|compatibility shim|migration path)\b|向后兼容|保持兼容|允许破坏|破坏性变更|主版本|弃用|迁移路径/iu;
|
|
10296
|
+
return api.test(value) && change.test(value) && !policy.test(value);
|
|
10297
|
+
}
|
|
10298
|
+
function requiresRuntimePermission(value) {
|
|
10299
|
+
return /\b(?:push|publish|deploy|release|delete|drop|reset|force[- ]push|send|upload)\b|推送|发布|部署|删除|清空|重置|发送|上传/iu.test(value);
|
|
10300
|
+
}
|
|
10301
|
+
function shouldInspectWorkspace(value, intent) {
|
|
10302
|
+
if (intent === "debug" || intent === "refactor" || intent === "review") return true;
|
|
10303
|
+
const hasConcreteTarget = /(?:^|\s)(?:[\w.-]+\/)+[\w.-]+|`[^`]+`|\b[A-Za-z_$][\w$]*(?:\(\))?\b/u.test(value);
|
|
10304
|
+
return !hasConcreteTarget || /\b(?:existing|current|relevant|appropriate|best)\b|现有|当前|相关|合适|最适合|这个|那个/iu.test(value);
|
|
10305
|
+
}
|
|
10306
|
+
function option(id, label, impact, recommended) {
|
|
10307
|
+
return { id, label, impact, recommended };
|
|
10308
|
+
}
|
|
10309
|
+
function isChinese(value) {
|
|
10310
|
+
return /[\u3400-\u9fff]/u.test(value);
|
|
10311
|
+
}
|
|
10312
|
+
function compact2(value, limit) {
|
|
10313
|
+
return value.trim().replace(/\s+/gu, " ").slice(0, limit);
|
|
10314
|
+
}
|
|
10315
|
+
|
|
9986
10316
|
// src/agent/tool-recovery.ts
|
|
9987
10317
|
import { createHash as createHash13 } from "node:crypto";
|
|
9988
10318
|
var RETRY_BUDGET = {
|
|
@@ -9997,6 +10327,7 @@ var RETRY_BUDGET = {
|
|
|
9997
10327
|
no_progress: 0,
|
|
9998
10328
|
contract_required: 2
|
|
9999
10329
|
};
|
|
10330
|
+
var FAILURE_CLASSES = Object.keys(RETRY_BUDGET);
|
|
10000
10331
|
var REPAIR_HINT = {
|
|
10001
10332
|
schema_input: "Correct the arguments to match the tool schema.",
|
|
10002
10333
|
unknown_tool: "Choose a tool exposed for this turn.",
|
|
@@ -10098,6 +10429,9 @@ function classifyToolFailure(result, fallback = "execution") {
|
|
|
10098
10429
|
function formatFailureReceipt(receipt) {
|
|
10099
10430
|
return `Failure: ${receipt.class}; attempt ${receipt.attempt}; ${receipt.remaining} retries remain; circuit ${receipt.circuitOpen ? "open" : "closed"}. Repair: ${receipt.repairHint}`;
|
|
10100
10431
|
}
|
|
10432
|
+
function resolvableFailureSignatures(call) {
|
|
10433
|
+
return FAILURE_CLASSES.map((failureClass) => failureSignature(call, failureClass));
|
|
10434
|
+
}
|
|
10101
10435
|
function isRetryable(failureClass) {
|
|
10102
10436
|
return RETRY_BUDGET[failureClass] > 0;
|
|
10103
10437
|
}
|
|
@@ -10915,16 +11249,35 @@ var AgentRunner = class {
|
|
|
10915
11249
|
}
|
|
10916
11250
|
async run(input2, options = {}) {
|
|
10917
11251
|
if (this.running) throw new Error("This AgentRunner is already processing a turn.");
|
|
10918
|
-
const
|
|
10919
|
-
if (!
|
|
10920
|
-
if (
|
|
11252
|
+
const submittedRequest = input2.trim();
|
|
11253
|
+
if (!submittedRequest) throw new Error("User input cannot be empty.");
|
|
11254
|
+
if (submittedRequest.length > 12e4) {
|
|
10921
11255
|
throw new Error("User input is too large; pass a focused request or attach files with @path.");
|
|
10922
11256
|
}
|
|
11257
|
+
let request = submittedRequest;
|
|
10923
11258
|
this.running = true;
|
|
10924
11259
|
this.contextEngine.resetDiagnostics?.();
|
|
10925
11260
|
const emit = async (event) => {
|
|
10926
11261
|
await options.onEvent?.(event);
|
|
10927
11262
|
};
|
|
11263
|
+
const pendingAtStart = this.session.pendingInput;
|
|
11264
|
+
const resolvedInput = pendingAtStart ? resolvePendingInput(pendingAtStart, submittedRequest) : void 0;
|
|
11265
|
+
if (pendingAtStart && resolvedInput) {
|
|
11266
|
+
request = `${pendingAtStart.originalRequest}
|
|
11267
|
+
|
|
11268
|
+
<user-clarification-decision source="explicit-user-input">
|
|
11269
|
+
${resolvedInput.decision}
|
|
11270
|
+
</user-clarification-decision>`;
|
|
11271
|
+
delete this.session.pendingInput;
|
|
11272
|
+
const constraint = `User clarification (${pendingAtStart.id}): ${resolvedInput.decision}`;
|
|
11273
|
+
if (this.session.taskContract && !this.session.taskContract.constraints.includes(constraint)) {
|
|
11274
|
+
this.session.taskContract.constraints.push(constraint);
|
|
11275
|
+
if (this.session.taskContract.constraints.length > 64) {
|
|
11276
|
+
this.session.taskContract.constraints.splice(0, this.session.taskContract.constraints.length - 64);
|
|
11277
|
+
}
|
|
11278
|
+
this.session.taskContract.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
11279
|
+
}
|
|
11280
|
+
}
|
|
10928
11281
|
const changeSequenceAtStart = this.changeSequence;
|
|
10929
11282
|
const runStartedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
10930
11283
|
const loadedProgressiveTools = /* @__PURE__ */ new Set();
|
|
@@ -10992,11 +11345,12 @@ var AgentRunner = class {
|
|
|
10992
11345
|
try {
|
|
10993
11346
|
throwIfAborted(options.signal);
|
|
10994
11347
|
await this.reconcileToolArtifacts();
|
|
11348
|
+
ensureContextEpoch(this.session);
|
|
10995
11349
|
if (this.session.messages.length === 0 && this.session.title === "New session") {
|
|
10996
11350
|
this.session.title = titleFromInput(request);
|
|
10997
11351
|
}
|
|
10998
11352
|
this.contextManager.startTurn(this.session, request);
|
|
10999
|
-
const userMessage = message("user",
|
|
11353
|
+
const userMessage = message("user", submittedRequest);
|
|
11000
11354
|
this.activeReuseGate = { requestId: userMessage.id, request, attempted: false };
|
|
11001
11355
|
this.session.messages.push(userMessage);
|
|
11002
11356
|
await this.persist();
|
|
@@ -11004,11 +11358,48 @@ var AgentRunner = class {
|
|
|
11004
11358
|
const turnDirective = buildTurnDirective(request, {
|
|
11005
11359
|
agents: Boolean(this.config.agents?.enabled)
|
|
11006
11360
|
});
|
|
11361
|
+
const contractEnabled = shouldUseTaskContract(
|
|
11362
|
+
request,
|
|
11363
|
+
turnDirective.intent,
|
|
11364
|
+
this.session.taskContract
|
|
11365
|
+
);
|
|
11007
11366
|
const packed = trivialTurn ? emptyPackedContext(selectContextBudget(request, this.config, {
|
|
11008
11367
|
intent: turnDirective.intent,
|
|
11009
11368
|
trivial: true
|
|
11010
11369
|
})) : await this.packContext(request, { intent: turnDirective.intent });
|
|
11011
11370
|
if (!trivialTurn) await emit({ type: "context", packed });
|
|
11371
|
+
if (contractEnabled && (!this.session.taskContract || this.session.taskContract.state === "satisfied")) {
|
|
11372
|
+
this.session.taskContract = createDraftTaskContract(request, this.session.audit?.at(-1)?.id);
|
|
11373
|
+
await this.persist();
|
|
11374
|
+
await emit({ type: "contract", contract: structuredClone(this.session.taskContract) });
|
|
11375
|
+
}
|
|
11376
|
+
let intentDirective;
|
|
11377
|
+
if (pendingAtStart && resolvedInput) {
|
|
11378
|
+
this.session.intentAssessment = {
|
|
11379
|
+
version: 1,
|
|
11380
|
+
route: "direct_execute",
|
|
11381
|
+
reasons: ["clarification_resolved"],
|
|
11382
|
+
assessedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
11383
|
+
retrievalHits: packed.hits.length
|
|
11384
|
+
};
|
|
11385
|
+
intentDirective = "The user resolved the recorded clarification. Continue the same logical run and apply that decision without asking again.";
|
|
11386
|
+
await emit({ type: "input_resolved", pendingId: pendingAtStart.id, runId: pendingAtStart.runId, answer: resolvedInput.answer });
|
|
11387
|
+
await emit({ type: "intent", assessment: this.session.intentAssessment });
|
|
11388
|
+
} else {
|
|
11389
|
+
const intent = assessIntentSufficiency(request, turnDirective.intent, {
|
|
11390
|
+
retrievalHits: packed.hits.length,
|
|
11391
|
+
complex: contractEnabled
|
|
11392
|
+
});
|
|
11393
|
+
this.session.intentAssessment = intent.assessment;
|
|
11394
|
+
intentDirective = intent.directive;
|
|
11395
|
+
await emit({ type: "intent", assessment: intent.assessment });
|
|
11396
|
+
if (intent.pending) {
|
|
11397
|
+
this.session.pendingInput = intent.pending;
|
|
11398
|
+
await this.persist();
|
|
11399
|
+
await emit({ type: "needs_input", pending: intent.pending });
|
|
11400
|
+
return finishRun("needs_input");
|
|
11401
|
+
}
|
|
11402
|
+
}
|
|
11012
11403
|
const mentions = await this.packMentions(request);
|
|
11013
11404
|
const retrievedContext = trivialTurn && !mentions.length ? "" : buildRetrievedContext(
|
|
11014
11405
|
packed,
|
|
@@ -11036,19 +11427,10 @@ var AgentRunner = class {
|
|
|
11036
11427
|
scope: augmentation.memoryScope ?? "session"
|
|
11037
11428
|
});
|
|
11038
11429
|
}
|
|
11039
|
-
const contractEnabled = shouldUseTaskContract(
|
|
11040
|
-
request,
|
|
11041
|
-
turnDirective.intent,
|
|
11042
|
-
this.session.taskContract
|
|
11043
|
-
);
|
|
11044
|
-
if (contractEnabled && (!this.session.taskContract || this.session.taskContract.state === "satisfied")) {
|
|
11045
|
-
this.session.taskContract = createDraftTaskContract(request, this.session.audit?.at(-1)?.id);
|
|
11046
|
-
await this.persist();
|
|
11047
|
-
await emit({ type: "contract", contract: structuredClone(this.session.taskContract) });
|
|
11048
|
-
}
|
|
11049
11430
|
activeRunContract = contractEnabled ? this.session.taskContract : void 0;
|
|
11050
11431
|
let verificationAttempted = false;
|
|
11051
11432
|
const maxTurns = options.maxTurns ?? this.config.agent.maxTurns;
|
|
11433
|
+
const epochTokenBudget = this.config.agent.maxEpochTokens ?? this.config.agent.maxSessionTokens;
|
|
11052
11434
|
const contextBudget = Math.max(24e3, Math.min(1e5, this.config.context.maxTokens * 3));
|
|
11053
11435
|
if (this.contextManager.shouldCompact(this.session, contextBudget)) {
|
|
11054
11436
|
const compacted = await this.compactContext(void 0, options.signal, "automatic");
|
|
@@ -11074,11 +11456,15 @@ var AgentRunner = class {
|
|
|
11074
11456
|
if (this.session.usage.inputTokens + this.session.usage.outputTokens >= this.config.agent.maxSessionTokens) {
|
|
11075
11457
|
return finishRun("token_budget");
|
|
11076
11458
|
}
|
|
11459
|
+
if (contextEpochTokens(this.session) >= epochTokenBudget) {
|
|
11460
|
+
await this.rollContextEpoch("token_budget", options.signal, emit);
|
|
11461
|
+
}
|
|
11077
11462
|
this.applySteering();
|
|
11078
11463
|
await emit({ type: "thinking", turn });
|
|
11079
11464
|
const dynamicPrompt = [
|
|
11080
11465
|
buildSessionStatePrompt(this.session),
|
|
11081
11466
|
turnDirective.text,
|
|
11467
|
+
`<intent-sufficiency route="${this.session.intentAssessment?.route ?? "direct_execute"}">${intentDirective}</intent-sufficiency>`,
|
|
11082
11468
|
this.contextManager.buildShortTermPrompt(this.session),
|
|
11083
11469
|
pinnedContext,
|
|
11084
11470
|
options.turnInstructions ?? "",
|
|
@@ -11091,7 +11477,9 @@ var AgentRunner = class {
|
|
|
11091
11477
|
activeMessages(this.session),
|
|
11092
11478
|
contextBudget
|
|
11093
11479
|
);
|
|
11094
|
-
const
|
|
11480
|
+
const availableLifetimeTokens = this.config.agent.maxSessionTokens - (this.session.usage.inputTokens + this.session.usage.outputTokens);
|
|
11481
|
+
const availableEpochTokens = epochTokenBudget - contextEpochTokens(this.session);
|
|
11482
|
+
const availableTokens = Math.min(availableLifetimeTokens, availableEpochTokens);
|
|
11095
11483
|
const visibleTools = visibleToolDefinitions(
|
|
11096
11484
|
this.tools,
|
|
11097
11485
|
options.askMode === true,
|
|
@@ -11105,9 +11493,15 @@ var AgentRunner = class {
|
|
|
11105
11493
|
loadedProgressiveTools
|
|
11106
11494
|
);
|
|
11107
11495
|
const estimatedInputTokens = estimateMessages2(messages) + estimateToolDefinitions(visibleTools);
|
|
11108
|
-
if (
|
|
11496
|
+
if (estimatedInputTokens >= availableLifetimeTokens) {
|
|
11109
11497
|
return finishRun("token_budget");
|
|
11110
11498
|
}
|
|
11499
|
+
if (availableTokens <= 0 || estimatedInputTokens >= availableEpochTokens) {
|
|
11500
|
+
if (contextEpochTokens(this.session) === 0) return finishRun("token_budget");
|
|
11501
|
+
await this.rollContextEpoch("token_budget", options.signal, emit);
|
|
11502
|
+
turn -= 1;
|
|
11503
|
+
continue;
|
|
11504
|
+
}
|
|
11111
11505
|
const maxOutputTokens = Math.max(1, Math.min(
|
|
11112
11506
|
this.config.model.maxTokens ?? 8192,
|
|
11113
11507
|
availableTokens - estimatedInputTokens
|
|
@@ -11129,7 +11523,7 @@ var AgentRunner = class {
|
|
|
11129
11523
|
breakdown
|
|
11130
11524
|
});
|
|
11131
11525
|
}
|
|
11132
|
-
const assistantId =
|
|
11526
|
+
const assistantId = randomUUID15();
|
|
11133
11527
|
const response = await this.completeModel(
|
|
11134
11528
|
messages,
|
|
11135
11529
|
visibleTools,
|
|
@@ -11509,6 +11903,9 @@ ${completeContent}`;
|
|
|
11509
11903
|
metadata.failure = receipt;
|
|
11510
11904
|
} else {
|
|
11511
11905
|
recovery.recordSuccess(call);
|
|
11906
|
+
const historicalFailures = new Set((this.session.audit ?? []).filter((event) => event.type === "tool" && event.outcome === "failure").map((event) => failureSignatureFromMetadata(event.metadata?.failure)).filter((signature) => signature !== void 0));
|
|
11907
|
+
const resolvedFailureSignatures = resolvableFailureSignatures(call).filter((signature) => historicalFailures.has(signature));
|
|
11908
|
+
if (resolvedFailureSignatures.length) metadata.resolvedFailureSignatures = resolvedFailureSignatures;
|
|
11512
11909
|
}
|
|
11513
11910
|
const evidenceProgress = recovery.recordEvidence(call, {
|
|
11514
11911
|
toolCallId: call.id,
|
|
@@ -11622,7 +12019,7 @@ ${completeContent}`;
|
|
|
11622
12019
|
}
|
|
11623
12020
|
appendAudit(event) {
|
|
11624
12021
|
const audit = this.session.audit ?? (this.session.audit = []);
|
|
11625
|
-
audit.push({ id:
|
|
12022
|
+
audit.push({ id: randomUUID15(), createdAt: (/* @__PURE__ */ new Date()).toISOString(), ...event });
|
|
11626
12023
|
if (audit.length > 5e3) audit.splice(0, audit.length - 5e3);
|
|
11627
12024
|
}
|
|
11628
12025
|
async acceptChangedFiles(paths) {
|
|
@@ -11643,7 +12040,7 @@ ${completeContent}`;
|
|
|
11643
12040
|
const results = [];
|
|
11644
12041
|
for (const command2 of this.config.agent.verifyCommands) {
|
|
11645
12042
|
const call = {
|
|
11646
|
-
id: `verify-${
|
|
12043
|
+
id: `verify-${randomUUID15()}`,
|
|
11647
12044
|
name: "shell",
|
|
11648
12045
|
arguments: { command: command2, cwd: this.workspace.primaryRoot }
|
|
11649
12046
|
};
|
|
@@ -11691,6 +12088,30 @@ ${completeContent}`;
|
|
|
11691
12088
|
await this.persist();
|
|
11692
12089
|
return result;
|
|
11693
12090
|
}
|
|
12091
|
+
async rollContextEpoch(reason, signal, emit) {
|
|
12092
|
+
let receipt;
|
|
12093
|
+
const contextBudget = Math.max(24e3, Math.min(1e5, this.config.context.maxTokens * 3));
|
|
12094
|
+
if (this.contextManager.shouldCompact(this.session, contextBudget)) {
|
|
12095
|
+
const compacted = await this.compactContext(
|
|
12096
|
+
"Create a boundary handoff for the next bounded context epoch.",
|
|
12097
|
+
signal,
|
|
12098
|
+
"automatic"
|
|
12099
|
+
);
|
|
12100
|
+
receipt = compacted.receipt;
|
|
12101
|
+
if (compacted.status === "compacted") await emit({ type: "context_compacted", ...compacted });
|
|
12102
|
+
}
|
|
12103
|
+
const rotated = rotateContextEpoch(this.session, reason, receipt);
|
|
12104
|
+
await this.persist();
|
|
12105
|
+
await emit({
|
|
12106
|
+
type: "context_epoch",
|
|
12107
|
+
index: rotated.current.index,
|
|
12108
|
+
previousIndex: rotated.previous.index,
|
|
12109
|
+
reason,
|
|
12110
|
+
inputTokens: rotated.previous.usage.inputTokens,
|
|
12111
|
+
outputTokens: rotated.previous.usage.outputTokens,
|
|
12112
|
+
handoff: rotated.handoff
|
|
12113
|
+
});
|
|
12114
|
+
}
|
|
11694
12115
|
getContextStatus() {
|
|
11695
12116
|
return this.contextManager.status(this.session);
|
|
11696
12117
|
}
|
|
@@ -11722,8 +12143,14 @@ ${completeContent}`;
|
|
|
11722
12143
|
toolOutputBudget() {
|
|
11723
12144
|
const contextWindowTokens = Math.max(24e3, Math.min(1e5, this.config.context.maxTokens * 3));
|
|
11724
12145
|
const activeContextTokens = this.contextManager.status(this.session, contextWindowTokens).activeTokens;
|
|
11725
|
-
const
|
|
11726
|
-
|
|
12146
|
+
const remainingLifetimeTokens = this.config.agent.maxSessionTokens - (this.session.usage.inputTokens + this.session.usage.outputTokens);
|
|
12147
|
+
const epochBudget = this.config.agent.maxEpochTokens ?? this.config.agent.maxSessionTokens;
|
|
12148
|
+
const remainingEpochTokens = epochBudget - contextEpochTokens(this.session);
|
|
12149
|
+
return dynamicToolOutputBudget(
|
|
12150
|
+
contextWindowTokens,
|
|
12151
|
+
activeContextTokens,
|
|
12152
|
+
Math.min(remainingLifetimeTokens, remainingEpochTokens)
|
|
12153
|
+
);
|
|
11727
12154
|
}
|
|
11728
12155
|
async protectToolResult(result) {
|
|
11729
12156
|
const metadata = { ...result.metadata ?? {} };
|
|
@@ -11779,7 +12206,7 @@ ${completeContent}`;
|
|
|
11779
12206
|
};
|
|
11780
12207
|
function message(role, content, extra = {}) {
|
|
11781
12208
|
return {
|
|
11782
|
-
id:
|
|
12209
|
+
id: randomUUID15(),
|
|
11783
12210
|
role,
|
|
11784
12211
|
content,
|
|
11785
12212
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -11894,6 +12321,7 @@ function recordTokenUsage(session, providerUsage, estimatedInputTokens, estimate
|
|
|
11894
12321
|
const outputTokens = outputActual ?? estimatedOutputTokens;
|
|
11895
12322
|
session.usage.inputTokens += inputTokens;
|
|
11896
12323
|
session.usage.outputTokens += outputTokens;
|
|
12324
|
+
recordContextEpochUsage(session, inputTokens, outputTokens);
|
|
11897
12325
|
if (inputActual !== void 0) {
|
|
11898
12326
|
session.usage.actualInputTokens = (session.usage.actualInputTokens ?? 0) + inputActual;
|
|
11899
12327
|
} else {
|
|
@@ -11969,6 +12397,11 @@ ${content}` : content,
|
|
|
11969
12397
|
...failure ? { metadata: { failure } } : {}
|
|
11970
12398
|
};
|
|
11971
12399
|
}
|
|
12400
|
+
function failureSignatureFromMetadata(value) {
|
|
12401
|
+
if (!value || typeof value !== "object") return;
|
|
12402
|
+
const signature = value.signature;
|
|
12403
|
+
return typeof signature === "string" && signature ? signature : void 0;
|
|
12404
|
+
}
|
|
11972
12405
|
function visibleToolDefinitions(tools, askMode, contractEnabled, artifactReadAvailable, duplicationAvailable, request, loadedProgressiveTools) {
|
|
11973
12406
|
const eligible = tools.definitions().filter(
|
|
11974
12407
|
(tool) => (!askMode || tool.category === "read") && (contractEnabled || tool.name !== "task_contract") && (artifactReadAvailable || tool.name !== "read_tool_artifact") && (duplicationAvailable || tool.name !== "duplication_audit")
|
|
@@ -12176,7 +12609,7 @@ function integer(value, fallback, min, max) {
|
|
|
12176
12609
|
}
|
|
12177
12610
|
|
|
12178
12611
|
// src/agent/delegation.ts
|
|
12179
|
-
import { randomUUID as
|
|
12612
|
+
import { randomUUID as randomUUID17 } from "node:crypto";
|
|
12180
12613
|
import { join as join18 } from "node:path";
|
|
12181
12614
|
import { z as z19 } from "zod";
|
|
12182
12615
|
|
|
@@ -12305,7 +12738,7 @@ function numeric(...values) {
|
|
|
12305
12738
|
}
|
|
12306
12739
|
|
|
12307
12740
|
// src/agent/team-store.ts
|
|
12308
|
-
import { createHash as createHash16, randomUUID as
|
|
12741
|
+
import { createHash as createHash16, randomUUID as randomUUID16 } from "node:crypto";
|
|
12309
12742
|
import { lstat as lstat18, readFile as readFile17, readdir as readdir7, rm as rm3 } from "node:fs/promises";
|
|
12310
12743
|
import { join as join16, resolve as resolve18 } from "node:path";
|
|
12311
12744
|
import { z as z18 } from "zod";
|
|
@@ -12399,7 +12832,7 @@ var TeamRunStore = class {
|
|
|
12399
12832
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
12400
12833
|
const manifest = manifestSchema2.parse({
|
|
12401
12834
|
version: 2,
|
|
12402
|
-
id:
|
|
12835
|
+
id: randomUUID16(),
|
|
12403
12836
|
workspace: this.workspace,
|
|
12404
12837
|
objective: input2.objective,
|
|
12405
12838
|
reviewer: input2.reviewer,
|
|
@@ -13205,7 +13638,7 @@ var DelegationManager = class {
|
|
|
13205
13638
|
maxReviewRounds: 0
|
|
13206
13639
|
});
|
|
13207
13640
|
await emit?.({ type: "team_start", id: board.id, objective: task });
|
|
13208
|
-
const writerId =
|
|
13641
|
+
const writerId = randomUUID17();
|
|
13209
13642
|
await emit?.({ type: "agent_queued", id: writerId, profile: profile.name, task, phase: "write" });
|
|
13210
13643
|
const draft = await this.writerLane.createDraft(
|
|
13211
13644
|
Math.min(this.team.maxWriterPatchBytes ?? 6e4, 12e4),
|
|
@@ -13575,7 +14008,7 @@ You are the only writer inside a disposable worktree. Make only the bounded requ
|
|
|
13575
14008
|
const reviewer = reviewerOverride ?? this.team.reviewerProfile ?? "reviewer";
|
|
13576
14009
|
const rounds = Math.max(0, this.team.maxReviewRounds ?? 1);
|
|
13577
14010
|
const board = await this.teamStore?.create({ objective, reviewer, maxReviewRounds: rounds });
|
|
13578
|
-
const runId = board?.id ??
|
|
14011
|
+
const runId = board?.id ?? randomUUID17();
|
|
13579
14012
|
await emit?.({ type: "team_start", id: runId, objective });
|
|
13580
14013
|
try {
|
|
13581
14014
|
let results = await this.runBatch(board?.id, tasks, "work", emit, signal);
|
|
@@ -13633,7 +14066,7 @@ ${review.summary}`,
|
|
|
13633
14066
|
}
|
|
13634
14067
|
}
|
|
13635
14068
|
async runBatch(runId, tasks, phase, emit, signal) {
|
|
13636
|
-
const scheduled = tasks.map((task) => ({ id:
|
|
14069
|
+
const scheduled = tasks.map((task) => ({ id: randomUUID17(), task }));
|
|
13637
14070
|
for (const item of scheduled) {
|
|
13638
14071
|
await emit?.({ type: "agent_queued", id: item.id, profile: item.task.profile, task: item.task.task, phase });
|
|
13639
14072
|
}
|
|
@@ -13742,12 +14175,12 @@ Start the response with exactly VERDICT: ACCEPT when the evidence is sufficient,
|
|
|
13742
14175
|
});
|
|
13743
14176
|
}
|
|
13744
14177
|
async peerMessage(runId, from, to, content, emit) {
|
|
13745
|
-
const id =
|
|
14178
|
+
const id = randomUUID17();
|
|
13746
14179
|
if (runId) await this.teamStore?.recordMessage(runId, { id, from, to, content });
|
|
13747
14180
|
await emit?.({ type: "agent_message", id, from, to, content });
|
|
13748
14181
|
}
|
|
13749
14182
|
async runOne(task, phase, emit, signal, retryOf, scheduledId) {
|
|
13750
|
-
const id = scheduledId ??
|
|
14183
|
+
const id = scheduledId ?? randomUUID17();
|
|
13751
14184
|
const profile = this.options.profiles.get(task.profile);
|
|
13752
14185
|
const configuredRoute = this.team.routes?.[task.profile];
|
|
13753
14186
|
const budgetMode = configuredRoute?.budgetMode ?? this.team.budgetMode ?? "observe";
|
|
@@ -14660,11 +15093,11 @@ ${this.glyphs.meta} ${session.changedFiles.length} changed files ${this.glyphs.s
|
|
|
14660
15093
|
`);
|
|
14661
15094
|
}
|
|
14662
15095
|
printText(event) {
|
|
14663
|
-
const { quiet, compact:
|
|
14664
|
-
if (quiet) return;
|
|
15096
|
+
const { quiet, compact: compact3 } = this.options;
|
|
15097
|
+
if (quiet && event.type !== "needs_input") return;
|
|
14665
15098
|
switch (event.type) {
|
|
14666
15099
|
case "thinking":
|
|
14667
|
-
if (!
|
|
15100
|
+
if (!compact3) process.stderr.write(this.paint.dim(`${this.glyphs.meta} reasoning ${this.glyphs.separator} turn ${event.turn}
|
|
14668
15101
|
`));
|
|
14669
15102
|
break;
|
|
14670
15103
|
case "context": {
|
|
@@ -14676,7 +15109,7 @@ ${this.glyphs.meta} ${session.changedFiles.length} changed files ${this.glyphs.s
|
|
|
14676
15109
|
break;
|
|
14677
15110
|
}
|
|
14678
15111
|
case "prompt":
|
|
14679
|
-
if (!
|
|
15112
|
+
if (!compact3) {
|
|
14680
15113
|
const partition = event.breakdown ? ` ${this.glyphs.separator} stable ${event.breakdown.stableTokens} ${this.glyphs.separator} dynamic ${event.breakdown.dynamicTokens} ${this.glyphs.separator} history ${event.breakdown.conversationTokens} ${this.glyphs.separator} tool results ${event.breakdown.toolResultTokens} ${this.glyphs.separator} retrieved ${event.breakdown.retrievedTokens} ${this.glyphs.separator} tools ${event.breakdown.toolSchemaTokens} ${this.glyphs.separator} output cap ${event.breakdown.outputAllowanceTokens}` : "";
|
|
14681
15114
|
process.stderr.write(this.paint.dim(
|
|
14682
15115
|
`${this.glyphs.meta} prompt ${this.glyphs.separator} ${event.intent} ${this.glyphs.separator} ~${event.estimatedTokens} estimated tokens${partition}
|
|
@@ -14712,7 +15145,7 @@ ${this.glyphs.meta} ${session.changedFiles.length} changed files ${this.glyphs.s
|
|
|
14712
15145
|
}
|
|
14713
15146
|
break;
|
|
14714
15147
|
case "tasks":
|
|
14715
|
-
if (!
|
|
15148
|
+
if (!compact3) {
|
|
14716
15149
|
const completed = event.tasks.filter((task) => task.status === "completed").length;
|
|
14717
15150
|
process.stderr.write(this.paint.dim(`${this.glyphs.meta} plan ${this.glyphs.separator} ${completed}/${event.tasks.length} complete
|
|
14718
15151
|
`));
|
|
@@ -14733,6 +15166,22 @@ ${this.glyphs.meta} ${session.changedFiles.length} changed files ${this.glyphs.s
|
|
|
14733
15166
|
`
|
|
14734
15167
|
);
|
|
14735
15168
|
break;
|
|
15169
|
+
case "needs_input":
|
|
15170
|
+
process.stderr.write(this.paint.yellow(`${this.glyphs.meta} ${event.pending.question}
|
|
15171
|
+
`));
|
|
15172
|
+
event.pending.options.forEach((option2, index) => {
|
|
15173
|
+
process.stderr.write(this.paint.dim(
|
|
15174
|
+
` ${index + 1}. ${option2.label}${option2.recommended ? " (recommended)" : ""} ${this.glyphs.separator} ${option2.impact}
|
|
15175
|
+
`
|
|
15176
|
+
));
|
|
15177
|
+
});
|
|
15178
|
+
break;
|
|
15179
|
+
case "input_resolved":
|
|
15180
|
+
process.stderr.write(this.paint.dim(
|
|
15181
|
+
`${this.glyphs.meta} clarification resolved ${this.glyphs.separator} ${event.answer}
|
|
15182
|
+
`
|
|
15183
|
+
));
|
|
15184
|
+
break;
|
|
14736
15185
|
case "usage":
|
|
14737
15186
|
case "permission":
|
|
14738
15187
|
case "skill":
|
|
@@ -14743,6 +15192,8 @@ ${this.glyphs.meta} ${session.changedFiles.length} changed files ${this.glyphs.s
|
|
|
14743
15192
|
case "agent_done":
|
|
14744
15193
|
case "workflow":
|
|
14745
15194
|
case "context_compacted":
|
|
15195
|
+
case "context_epoch":
|
|
15196
|
+
case "intent":
|
|
14746
15197
|
break;
|
|
14747
15198
|
case "done":
|
|
14748
15199
|
this.printCompletion(event.completion);
|
|
@@ -14815,6 +15266,9 @@ function sessionSummary(session) {
|
|
|
14815
15266
|
...session.lastRun ? { lastRun: session.lastRun } : {},
|
|
14816
15267
|
...session.tokenLedger?.length ? { tokenLedger: session.tokenLedger } : {},
|
|
14817
15268
|
...session.contextCompactionReceipts?.length ? { contextCompactionReceipts: session.contextCompactionReceipts } : {},
|
|
15269
|
+
...session.contextEpochs?.length ? { contextEpochs: session.contextEpochs } : {},
|
|
15270
|
+
...session.intentAssessment ? { intentAssessment: session.intentAssessment } : {},
|
|
15271
|
+
...session.pendingInput ? { pendingInput: session.pendingInput } : {},
|
|
14818
15272
|
usage: session.usage
|
|
14819
15273
|
};
|
|
14820
15274
|
}
|
|
@@ -15507,7 +15961,7 @@ function ToolGlyph({ state, glyphs }) {
|
|
|
15507
15961
|
if (state === "cancelled") return /* @__PURE__ */ jsx(Text, { color: theme.warning, children: glyphs.warning });
|
|
15508
15962
|
return /* @__PURE__ */ jsx(Text, { color: theme.error, children: glyphs.error });
|
|
15509
15963
|
}
|
|
15510
|
-
function Timeline({ items, width = 80, glyphMode = "auto", showToolOutput = false, expandedToolId, compact:
|
|
15964
|
+
function Timeline({ items, width = 80, glyphMode = "auto", showToolOutput = false, expandedToolId, compact: compact3 = false }) {
|
|
15511
15965
|
const theme = useTheme();
|
|
15512
15966
|
const glyphs = resolveGlyphs(glyphMode);
|
|
15513
15967
|
if (!items.length) {
|
|
@@ -15515,13 +15969,13 @@ function Timeline({ items, width = 80, glyphMode = "auto", showToolOutput = fals
|
|
|
15515
15969
|
}
|
|
15516
15970
|
return /* @__PURE__ */ jsx(Box, { flexDirection: "column", children: items.map((item, index) => {
|
|
15517
15971
|
if (item.kind === "user") {
|
|
15518
|
-
return /* @__PURE__ */ jsxs(Box, { marginBottom:
|
|
15972
|
+
return /* @__PURE__ */ jsxs(Box, { marginBottom: compact3 || item.clipped ? 0 : 1, children: [
|
|
15519
15973
|
/* @__PURE__ */ jsx(Box, { width: 2, children: /* @__PURE__ */ jsx(Text, { bold: true, color: theme.accent, children: glyphs.prompt }) }),
|
|
15520
15974
|
/* @__PURE__ */ jsx(Text, { bold: true, color: theme.textStrong, wrap: "wrap", children: sanitizeTerminalText(item.text) })
|
|
15521
15975
|
] }, item.id);
|
|
15522
15976
|
}
|
|
15523
15977
|
if (item.kind === "assistant") {
|
|
15524
|
-
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginBottom:
|
|
15978
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginBottom: compact3 || item.clipped ? 0 : 1, children: [
|
|
15525
15979
|
/* @__PURE__ */ jsxs(Text, { bold: true, color: theme.accent, children: [
|
|
15526
15980
|
glyphs.brand,
|
|
15527
15981
|
" ",
|
|
@@ -15537,7 +15991,7 @@ function Timeline({ items, width = 80, glyphMode = "auto", showToolOutput = fals
|
|
|
15537
15991
|
}
|
|
15538
15992
|
if (item.kind === "context") {
|
|
15539
15993
|
const spans = item.spans ?? [];
|
|
15540
|
-
const spanLimit =
|
|
15994
|
+
const spanLimit = compact3 ? 2 : 3;
|
|
15541
15995
|
const innerWidth = Math.max(1, safeWidth(width) - 2);
|
|
15542
15996
|
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
|
|
15543
15997
|
/* @__PURE__ */ jsx(
|
|
@@ -15550,7 +16004,7 @@ function Timeline({ items, width = 80, glyphMode = "auto", showToolOutput = fals
|
|
|
15550
16004
|
labelColor: theme.accent
|
|
15551
16005
|
}
|
|
15552
16006
|
),
|
|
15553
|
-
!
|
|
16007
|
+
!compact3 && item.budgetReason ? /* @__PURE__ */ jsx(Text, { color: theme.dim, children: truncateDisplay(`${glyphs.branchLast} ${sanitizeInlineTerminalText(item.budgetReason)}`, innerWidth) }) : null,
|
|
15554
16008
|
spans.slice(0, spanLimit).map((span, spanIndex) => {
|
|
15555
16009
|
const lines = span.startLine === span.endLine ? `${span.startLine}` : `${span.startLine}-${span.endLine}`;
|
|
15556
16010
|
const location = `${compactDisplayPath(sanitizeInlineTerminalText(span.path), 44)}:${lines}`;
|
|
@@ -15590,7 +16044,7 @@ function Timeline({ items, width = 80, glyphMode = "auto", showToolOutput = fals
|
|
|
15590
16044
|
const duration = item.durationMs !== void 0 ? formatDuration(item.durationMs) : "";
|
|
15591
16045
|
const detailText = [detail, duration].filter(Boolean).join(" ");
|
|
15592
16046
|
const expanded = Boolean(item.output) && (showToolOutput || expandedToolId === item.id);
|
|
15593
|
-
const verbose = expanded && item.output ? limitTerminalText(item.output,
|
|
16047
|
+
const verbose = expanded && item.output ? limitTerminalText(item.output, compact3 ? 24 : 80) : void 0;
|
|
15594
16048
|
const disclosure = item.output ? expanded ? glyphs.expanded : glyphs.collapsed : "";
|
|
15595
16049
|
const disclosureWidth = disclosure ? displayWidth(disclosure) + 1 : 0;
|
|
15596
16050
|
const nameLimit = Math.max(1, Math.min(rowWidth - 2 - disclosureWidth, rowWidth < 64 ? rowWidth - 2 - disclosureWidth : 28));
|
|
@@ -15722,9 +16176,28 @@ function Timeline({ items, width = 80, glyphMode = "auto", showToolOutput = fals
|
|
|
15722
16176
|
item.id
|
|
15723
16177
|
);
|
|
15724
16178
|
}
|
|
16179
|
+
if (item.kind === "clarification") {
|
|
16180
|
+
const rowWidth = safeWidth(width);
|
|
16181
|
+
const chinese = /[\u3400-\u9fff]/u.test(item.pending.question);
|
|
16182
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", paddingLeft: 2, marginBottom: 1, children: [
|
|
16183
|
+
/* @__PURE__ */ jsx(Text, { bold: true, color: theme.warning, children: sanitizeTerminalText(item.pending.question) }),
|
|
16184
|
+
item.pending.options.map((option2, optionIndex) => {
|
|
16185
|
+
const label = `${optionIndex + 1}. ${sanitizeInlineTerminalText(option2.label)}${option2.recommended ? chinese ? "\uFF08\u63A8\u8350\uFF09" : " (recommended)" : ""}`;
|
|
16186
|
+
const impact = sanitizeInlineTerminalText(option2.impact);
|
|
16187
|
+
if (rowWidth < 48) {
|
|
16188
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
|
|
16189
|
+
/* @__PURE__ */ jsx(Text, { color: option2.recommended ? theme.textStrong : theme.muted, children: truncateDisplay(label, Math.max(1, rowWidth - 2)) }),
|
|
16190
|
+
/* @__PURE__ */ jsx(Text, { color: theme.dim, children: truncateDisplay(`${glyphs.branchLast} ${impact}`, Math.max(1, (rowWidth - 2) * 2)) })
|
|
16191
|
+
] }, option2.id);
|
|
16192
|
+
}
|
|
16193
|
+
return /* @__PURE__ */ jsx(Text, { color: option2.recommended ? theme.textStrong : theme.muted, children: truncateDisplay(`${label} ${glyphs.separator} ${impact}`, Math.max(1, rowWidth - 2)) }, option2.id);
|
|
16194
|
+
}),
|
|
16195
|
+
/* @__PURE__ */ jsx(Text, { color: theme.dim, children: chinese ? "\u56DE\u590D\u7F16\u53F7\u3001\u9009\u9879\u540D\u79F0\uFF0C\u6216\u7B80\u77ED\u8BF4\u660E\u4F60\u7684\u51B3\u5B9A\u3002" : "Reply with a number, option label, or a short custom decision." })
|
|
16196
|
+
] }, item.id);
|
|
16197
|
+
}
|
|
15725
16198
|
if (item.kind === "list") return /* @__PURE__ */ jsx(ListPanel, { title: item.title, entries: item.entries, width, glyphMode }, item.id);
|
|
15726
16199
|
if (item.kind === "context-inspector") {
|
|
15727
|
-
return /* @__PURE__ */ jsx(ContextInspector, { status: item.status, working: item.working, summary: item.summary, width, compact:
|
|
16200
|
+
return /* @__PURE__ */ jsx(ContextInspector, { status: item.status, working: item.working, summary: item.summary, width, compact: compact3, glyphMode }, item.id);
|
|
15728
16201
|
}
|
|
15729
16202
|
if (item.kind === "theme") return /* @__PURE__ */ jsx(ThemePreview, { name: item.name, width, glyphs }, item.id);
|
|
15730
16203
|
if (item.kind === "banner") {
|
|
@@ -15934,7 +16407,7 @@ function TaskRail({ tasks, width = 80, glyphMode = "auto", maxItems }) {
|
|
|
15934
16407
|
] }) : null
|
|
15935
16408
|
] });
|
|
15936
16409
|
}
|
|
15937
|
-
function PermissionCard({ call, category, width = 80, glyphMode = "auto", workspace, compact:
|
|
16410
|
+
function PermissionCard({ call, category, width = 80, glyphMode = "auto", workspace, compact: compact3 = false }) {
|
|
15938
16411
|
const theme = useTheme();
|
|
15939
16412
|
const glyphs = resolveGlyphs(glyphMode);
|
|
15940
16413
|
const summary = permissionSummary(call);
|
|
@@ -15971,7 +16444,7 @@ function PermissionCard({ call, category, width = 80, glyphMode = "auto", worksp
|
|
|
15971
16444
|
rowWidth >= 64 ? /* @__PURE__ */ jsx(Box, { paddingLeft: 2, children: /* @__PURE__ */ jsx(InlineRow, { parts: shortcuts, width: innerWidth, separator: ` ${glyphs.separator} `, separatorColor: theme.border }) }) : rowWidth >= 28 ? /* @__PURE__ */ jsxs(Box, { paddingLeft: 2, flexDirection: "column", children: [
|
|
15972
16445
|
/* @__PURE__ */ jsx(InlineRow, { parts: shortcuts.slice(0, 2), width: innerWidth, separator: " ", separatorColor: theme.border }),
|
|
15973
16446
|
/* @__PURE__ */ jsx(InlineRow, { parts: shortcuts.slice(2), width: innerWidth, separator: " ", separatorColor: theme.border })
|
|
15974
|
-
] }) :
|
|
16447
|
+
] }) : compact3 ? /* @__PURE__ */ jsxs(Box, { paddingLeft: 2, flexDirection: "column", children: [
|
|
15975
16448
|
/* @__PURE__ */ jsx(InlineRow, { parts: compactNarrowShortcuts.slice(0, 2), width: innerWidth, separator: " ", separatorColor: theme.border }),
|
|
15976
16449
|
/* @__PURE__ */ jsx(InlineRow, { parts: compactNarrowShortcuts.slice(2), width: innerWidth, separator: " ", separatorColor: theme.border })
|
|
15977
16450
|
] }) : /* @__PURE__ */ jsx(Box, { paddingLeft: 2, flexDirection: "column", children: shortcuts.map((part) => part.color ? /* @__PURE__ */ jsx(Text, { color: part.color, children: truncateDisplay(part.text, innerWidth) }, part.text) : /* @__PURE__ */ jsx(Text, { children: truncateDisplay(part.text, innerWidth) }, part.text)) })
|
|
@@ -16232,7 +16705,7 @@ function MeterBar({ segments, total, width, glyphs }) {
|
|
|
16232
16705
|
remainder ? /* @__PURE__ */ jsx(Text, { color: theme.border, children: glyphs.meterEmpty.repeat(remainder) }) : null
|
|
16233
16706
|
] });
|
|
16234
16707
|
}
|
|
16235
|
-
function ContextInspector({ status, working, summary, width, memory, connections, sources: sources2, compact:
|
|
16708
|
+
function ContextInspector({ status, working, summary, width, memory, connections, sources: sources2, compact: compact3 = false, minimal = false, glyphMode = "auto" }) {
|
|
16236
16709
|
const theme = useTheme();
|
|
16237
16710
|
const glyphs = resolveGlyphs(glyphMode);
|
|
16238
16711
|
const hasCompactedContext = status.compactedMessages > 0 || Boolean(summary);
|
|
@@ -16253,10 +16726,16 @@ function ContextInspector({ status, working, summary, width, memory, connections
|
|
|
16253
16726
|
{ label: "summary", detail: hasCompactedContext ? `~${formatTokens(status.summaryTokens)} tokens ${glyphs.separator} ${status.compactedMessages} compacted${summary ? "" : ` ${glyphs.separator} facts`}` : "not created" },
|
|
16254
16727
|
{ label: "long-term", detail: memory ?? `retrieved by relevance ${glyphs.separator} untrusted context` }
|
|
16255
16728
|
];
|
|
16256
|
-
if (
|
|
16257
|
-
|
|
16258
|
-
|
|
16259
|
-
|
|
16729
|
+
if (status.epochIndex !== void 0 && status.epochCount !== void 0 && status.epochTokens !== void 0 && status.epochBudget !== void 0 && status.lifetimeTokens !== void 0 && status.lifetimeBudget !== void 0) {
|
|
16730
|
+
entries.splice(1, 0, {
|
|
16731
|
+
label: "epoch",
|
|
16732
|
+
detail: `#${status.epochIndex} ${formatTokens(status.epochTokens)}/${formatTokens(status.epochBudget)} ${glyphs.separator} lifetime ${formatTokens(status.lifetimeTokens)}/${formatTokens(status.lifetimeBudget)}`
|
|
16733
|
+
});
|
|
16734
|
+
}
|
|
16735
|
+
if (!compact3 && working?.constraints.length) entries.push({ label: `constraints ${working.constraints.length}`, detail: working.constraints.slice(0, 2).join(` ${glyphs.separator} `) });
|
|
16736
|
+
if (!compact3 && working?.decisions.length) entries.push({ label: `decisions ${working.decisions.length}`, detail: working.decisions.slice(0, 2).join(` ${glyphs.separator} `) });
|
|
16737
|
+
if (!compact3 && working?.openQuestions.length) entries.push({ label: `open ${working.openQuestions.length}`, detail: working.openQuestions.slice(0, 2).join(` ${glyphs.separator} `), tone: "warning" });
|
|
16738
|
+
if (!compact3 && working?.relevantFiles.length) entries.push({ label: "relevant files", detail: working.relevantFiles.map((file) => compactDisplayPath(sanitizeInlineTerminalText(file), 28)).join(` ${glyphs.separator} `) });
|
|
16260
16739
|
if (sources2?.length) {
|
|
16261
16740
|
const pinned = sources2.filter((source) => source.state === "pinned");
|
|
16262
16741
|
const muted = sources2.filter((source) => source.state === "muted");
|
|
@@ -16290,7 +16769,7 @@ function ContextInspector({ status, working, summary, width, memory, connections
|
|
|
16290
16769
|
/* @__PURE__ */ jsx(MeterBar, { segments, total: meterTotal, width: meterWidth, glyphs })
|
|
16291
16770
|
] }) : null
|
|
16292
16771
|
] }),
|
|
16293
|
-
/* @__PURE__ */ jsx(ListPanel, { title: "", hideTitle: true, entries, width, glyphMode })
|
|
16772
|
+
/* @__PURE__ */ jsx(ListPanel, { title: "", hideTitle: true, entries, width: Math.max(1, rowWidth - 2), glyphMode })
|
|
16294
16773
|
] });
|
|
16295
16774
|
}
|
|
16296
16775
|
function ThemePreview({ name, width, glyphs }) {
|
|
@@ -16377,8 +16856,8 @@ function Banner({ model, engine, workspace, version, width, glyphs }) {
|
|
|
16377
16856
|
function UpdateNotice({ current, latest, command: command2, highlights, width, glyphs }) {
|
|
16378
16857
|
const theme = useTheme();
|
|
16379
16858
|
const availableWidth = safeWidth(width);
|
|
16380
|
-
const
|
|
16381
|
-
const parts =
|
|
16859
|
+
const compact3 = availableWidth < 48;
|
|
16860
|
+
const parts = compact3 ? [
|
|
16382
16861
|
{ text: `${glyphs.up} `, color: theme.accent, bold: true },
|
|
16383
16862
|
{ text: `v${current}`, color: theme.dim, bold: false },
|
|
16384
16863
|
{ text: ` ${glyphs.arrow} `, color: theme.muted, bold: false },
|
|
@@ -16399,7 +16878,7 @@ function UpdateNotice({ current, latest, command: command2, highlights, width, g
|
|
|
16399
16878
|
const bullets = bulletWidth > 0 ? (highlights ?? []).map((line) => truncateDisplay(sanitizeInlineTerminalText(line), bulletWidth)) : [];
|
|
16400
16879
|
return /* @__PURE__ */ jsxs(Box, { marginBottom: 1, flexDirection: "column", children: [
|
|
16401
16880
|
/* @__PURE__ */ jsx(Box, { children: truncated ? /* @__PURE__ */ jsx(Text, { color: theme.muted, children: rendered }) : parts.map((part, index) => /* @__PURE__ */ jsx(Text, { color: part.color, bold: part.bold, children: part.text }, index)) }),
|
|
16402
|
-
|
|
16881
|
+
compact3 ? /* @__PURE__ */ jsx(Text, { color: theme.dim, children: truncateDisplay(` run ${command2}`, availableWidth) }) : null,
|
|
16403
16882
|
bullets.map((line, index) => /* @__PURE__ */ jsx(Text, { color: theme.dim, children: `${bulletPrefix}${line}` }, index))
|
|
16404
16883
|
] });
|
|
16405
16884
|
}
|
|
@@ -17307,9 +17786,9 @@ function tailText(value, width, maxRows) {
|
|
|
17307
17786
|
return `${marker}
|
|
17308
17787
|
${selected.join("\n")}`;
|
|
17309
17788
|
}
|
|
17310
|
-
function estimateTimelineItemRows(item, { width, compact:
|
|
17789
|
+
function estimateTimelineItemRows(item, { width, compact: compact3 = false, showToolOutput = false, expandedToolId }) {
|
|
17311
17790
|
const rowWidth = Math.max(1, Math.floor(width));
|
|
17312
|
-
const gap =
|
|
17791
|
+
const gap = compact3 ? 0 : 1;
|
|
17313
17792
|
if (item.kind === "user") return wrappedRows(item.text, Math.max(1, rowWidth - 2)) + (item.clipped ? 0 : gap);
|
|
17314
17793
|
if (item.kind === "assistant") {
|
|
17315
17794
|
return 1 + richTextRows(item.text, Math.max(1, rowWidth - 2)) + (item.clipped ? 0 : gap);
|
|
@@ -17321,7 +17800,7 @@ function estimateTimelineItemRows(item, { width, compact: compact2 = false, show
|
|
|
17321
17800
|
const detail = item.errorDetail || item.detail;
|
|
17322
17801
|
const detailRows = narrow && detail ? 1 : 0;
|
|
17323
17802
|
const metaRows = item.meta ? 1 : 0;
|
|
17324
|
-
const outputRows = (showToolOutput || item.id === expandedToolId) && item.output ? Math.min(
|
|
17803
|
+
const outputRows = (showToolOutput || item.id === expandedToolId) && item.output ? Math.min(compact3 ? 25 : 81, richTextRows(item.output, Math.max(1, rowWidth - 2))) : 0;
|
|
17325
17804
|
return 1 + detailRows + metaRows + outputRows;
|
|
17326
17805
|
}
|
|
17327
17806
|
if (item.kind === "list") {
|
|
@@ -17335,7 +17814,7 @@ function estimateTimelineItemRows(item, { width, compact: compact2 = false, show
|
|
|
17335
17814
|
if (item.kind === "theme") return 3;
|
|
17336
17815
|
if (item.kind === "context") {
|
|
17337
17816
|
const metaRows = rowWidth < 64 ? 2 : 1;
|
|
17338
|
-
const spanLimit =
|
|
17817
|
+
const spanLimit = compact3 ? 2 : 3;
|
|
17339
17818
|
const spanCount = Math.min(item.spans?.length ?? 0, spanLimit);
|
|
17340
17819
|
const moreRow = (item.spans?.length ?? 0) > spanLimit ? 1 : 0;
|
|
17341
17820
|
const degradationRows = item.degradation ? metaRows : 0;
|
|
@@ -17565,7 +18044,7 @@ function SkeinApp({ runner, config, extensions, initialPrompt, askMode = false,
|
|
|
17565
18044
|
const colorEnabled = config.ui.color && !process.env.NO_COLOR;
|
|
17566
18045
|
const [theme, setTheme] = useState2(() => resolveThemeWithColor(config.ui.theme, colorEnabled));
|
|
17567
18046
|
const [themeCatalogRevision, setThemeCatalogRevision] = useState2(0);
|
|
17568
|
-
const [
|
|
18047
|
+
const [compact3, setCompact] = useState2(config.ui.compact);
|
|
17569
18048
|
const [interactionMode, setInteractionMode] = useState2(planMode ? "plan" : askMode ? "ask" : "build");
|
|
17570
18049
|
const [input2, setInput] = useState2("");
|
|
17571
18050
|
const [busy, setBusy] = useState2(false);
|
|
@@ -17602,6 +18081,7 @@ function SkeinApp({ runner, config, extensions, initialPrompt, askMode = false,
|
|
|
17602
18081
|
const controller = useRef2(void 0);
|
|
17603
18082
|
const processing = useRef2(false);
|
|
17604
18083
|
const queued = useRef2([]);
|
|
18084
|
+
const clarificationBacklog = useRef2([]);
|
|
17605
18085
|
const stopRequested = useRef2(false);
|
|
17606
18086
|
const startedInitial = useRef2(false);
|
|
17607
18087
|
const lastSubmitted = useRef2(void 0);
|
|
@@ -17842,6 +18322,26 @@ function SkeinApp({ runner, config, extensions, initialPrompt, askMode = false,
|
|
|
17842
18322
|
append({ id: nextId(), kind: "compaction", messages: event.omittedMessages, tokens: event.summaryTokens });
|
|
17843
18323
|
refreshSession();
|
|
17844
18324
|
break;
|
|
18325
|
+
case "context_epoch":
|
|
18326
|
+
append({
|
|
18327
|
+
id: nextId(),
|
|
18328
|
+
kind: "notice",
|
|
18329
|
+
tone: "info",
|
|
18330
|
+
text: `Context epoch ${event.previousIndex} \u2192 ${event.index}${separator}${event.reason.replace("_", " ")}${separator}${event.inputTokens + event.outputTokens} tokens preserved in the lifetime ledger.`
|
|
18331
|
+
});
|
|
18332
|
+
refreshSession();
|
|
18333
|
+
break;
|
|
18334
|
+
case "needs_input":
|
|
18335
|
+
append({ id: nextId(), kind: "clarification", pending: event.pending });
|
|
18336
|
+
refreshSession();
|
|
18337
|
+
break;
|
|
18338
|
+
case "input_resolved":
|
|
18339
|
+
append({ id: nextId(), kind: "notice", tone: "success", text: `Clarification resolved${separator}${event.answer}` });
|
|
18340
|
+
refreshSession();
|
|
18341
|
+
break;
|
|
18342
|
+
case "intent":
|
|
18343
|
+
refreshSession();
|
|
18344
|
+
break;
|
|
17845
18345
|
case "usage":
|
|
17846
18346
|
refreshSession();
|
|
17847
18347
|
break;
|
|
@@ -18274,7 +18774,7 @@ function SkeinApp({ runner, config, extensions, initialPrompt, askMode = false,
|
|
|
18274
18774
|
}
|
|
18275
18775
|
if (command2 === "density") {
|
|
18276
18776
|
const normalized = argument.toLocaleLowerCase();
|
|
18277
|
-
const next = normalized === "compact" ? true : normalized === "comfortable" || normalized === "normal" ? false : normalized === "" || normalized === "toggle" ? !
|
|
18777
|
+
const next = normalized === "compact" ? true : normalized === "comfortable" || normalized === "normal" ? false : normalized === "" || normalized === "toggle" ? !compact3 : void 0;
|
|
18278
18778
|
if (next === void 0) throw new Error("Usage: /density [compact|comfortable]");
|
|
18279
18779
|
setCompact(next);
|
|
18280
18780
|
await saveUiPreference({ compact: next });
|
|
@@ -18367,7 +18867,7 @@ function SkeinApp({ runner, config, extensions, initialPrompt, askMode = false,
|
|
|
18367
18867
|
})));
|
|
18368
18868
|
return true;
|
|
18369
18869
|
}
|
|
18370
|
-
}, [append, appendList,
|
|
18870
|
+
}, [append, appendList, compact3, config, ellipsis, exit, extensions, interactionMode, refreshSession, requestPermission, runner, separator, showToolOutput, tasks, theme, workflows]);
|
|
18371
18871
|
const submit = useCallback(async (raw, mode = "normal") => {
|
|
18372
18872
|
const trimmed = raw.trim();
|
|
18373
18873
|
if (!trimmed) return;
|
|
@@ -18382,6 +18882,7 @@ function SkeinApp({ runner, config, extensions, initialPrompt, askMode = false,
|
|
|
18382
18882
|
if (processing.current && isExitCommand(trimmed)) {
|
|
18383
18883
|
stopRequested.current = true;
|
|
18384
18884
|
queued.current = [];
|
|
18885
|
+
clarificationBacklog.current = [];
|
|
18385
18886
|
setQueue([]);
|
|
18386
18887
|
controller.current?.abort();
|
|
18387
18888
|
exit();
|
|
@@ -18469,6 +18970,31 @@ function SkeinApp({ runner, config, extensions, initialPrompt, askMode = false,
|
|
|
18469
18970
|
const snapshot = snapshotSession(nextSession);
|
|
18470
18971
|
setSession(snapshot);
|
|
18471
18972
|
setTasks(snapshot.tasks.map((task) => ({ ...task })));
|
|
18973
|
+
if (snapshot.pendingInput) {
|
|
18974
|
+
const deferred = queued.current.length;
|
|
18975
|
+
clarificationBacklog.current.push(...queued.current);
|
|
18976
|
+
queued.current = [];
|
|
18977
|
+
setQueue([]);
|
|
18978
|
+
if (deferred) append({
|
|
18979
|
+
id: nextId(),
|
|
18980
|
+
kind: "notice",
|
|
18981
|
+
tone: "info",
|
|
18982
|
+
text: `Paused ${deferred} queued follow-up${deferred === 1 ? "" : "s"} for clarification; they will resume after the answer.`
|
|
18983
|
+
});
|
|
18984
|
+
break;
|
|
18985
|
+
}
|
|
18986
|
+
if (clarificationBacklog.current.length) {
|
|
18987
|
+
const resumed = clarificationBacklog.current.length;
|
|
18988
|
+
queued.current = [...clarificationBacklog.current, ...queued.current];
|
|
18989
|
+
clarificationBacklog.current = [];
|
|
18990
|
+
setQueue([...queued.current]);
|
|
18991
|
+
append({
|
|
18992
|
+
id: nextId(),
|
|
18993
|
+
kind: "notice",
|
|
18994
|
+
tone: "success",
|
|
18995
|
+
text: `Clarification resolved; resuming ${resumed} queued follow-up${resumed === 1 ? "" : "s"}.`
|
|
18996
|
+
});
|
|
18997
|
+
}
|
|
18472
18998
|
} catch (error) {
|
|
18473
18999
|
const message2 = error instanceof Error ? error.message : String(error);
|
|
18474
19000
|
if (!abortController.signal.aborted && message2 !== lastEventError.current) {
|
|
@@ -18481,8 +19007,9 @@ function SkeinApp({ runner, config, extensions, initialPrompt, askMode = false,
|
|
|
18481
19007
|
}
|
|
18482
19008
|
}
|
|
18483
19009
|
if (abortController.signal.aborted || stopRequested.current) {
|
|
18484
|
-
const discarded = queued.current.length;
|
|
19010
|
+
const discarded = queued.current.length + clarificationBacklog.current.length;
|
|
18485
19011
|
queued.current = [];
|
|
19012
|
+
clarificationBacklog.current = [];
|
|
18486
19013
|
setQueue([]);
|
|
18487
19014
|
if (discarded) append({ id: nextId(), kind: "notice", text: `Discarded ${discarded} queued follow-up${discarded === 1 ? "" : "s"}.` });
|
|
18488
19015
|
break;
|
|
@@ -18731,7 +19258,7 @@ function SkeinApp({ runner, config, extensions, initialPrompt, askMode = false,
|
|
|
18731
19258
|
const tokenTotal = session.usage.inputTokens + session.usage.outputTokens;
|
|
18732
19259
|
const contextStatus = runner.getContextStatus();
|
|
18733
19260
|
const frame = spinnerFrames()[frameIndex % spinnerFrames().length];
|
|
18734
|
-
const compactUi =
|
|
19261
|
+
const compactUi = compact3 || terminalHeight < 28;
|
|
18735
19262
|
const constrainedHeight = terminalHeight < 18;
|
|
18736
19263
|
const compactComposer = terminalHeight < 18;
|
|
18737
19264
|
const minimalInspector = terminalHeight < 22;
|
|
@@ -18947,6 +19474,9 @@ function initialTimeline(session, banner, setupProblem) {
|
|
|
18947
19474
|
text: `Contract ${session.taskContract.state} | ${satisfied}/${required.length} accepted`
|
|
18948
19475
|
});
|
|
18949
19476
|
}
|
|
19477
|
+
if (session.pendingInput) {
|
|
19478
|
+
items.push({ id: `pending-input-${session.pendingInput.id}`, kind: "clarification", pending: session.pendingInput });
|
|
19479
|
+
}
|
|
18950
19480
|
if (setupProblem && items.length <= 1) items.push({ id: nextId(), kind: "notice", tone: "error", text: setupProblem });
|
|
18951
19481
|
return items;
|
|
18952
19482
|
}
|
|
@@ -18992,6 +19522,35 @@ function snapshotSession(source) {
|
|
|
18992
19522
|
relevantFiles: [...source.workingMemory.relevantFiles]
|
|
18993
19523
|
}
|
|
18994
19524
|
} : {},
|
|
19525
|
+
...source.contextEpochs ? {
|
|
19526
|
+
contextEpochs: source.contextEpochs.map((epoch) => ({
|
|
19527
|
+
...epoch,
|
|
19528
|
+
usage: { ...epoch.usage },
|
|
19529
|
+
...epoch.handoff ? {
|
|
19530
|
+
handoff: {
|
|
19531
|
+
...epoch.handoff,
|
|
19532
|
+
...epoch.handoff.contract ? {
|
|
19533
|
+
contract: {
|
|
19534
|
+
...epoch.handoff.contract,
|
|
19535
|
+
required: epoch.handoff.contract.required.map((criterion2) => ({
|
|
19536
|
+
...criterion2,
|
|
19537
|
+
evidenceRefs: [...criterion2.evidenceRefs]
|
|
19538
|
+
}))
|
|
19539
|
+
}
|
|
19540
|
+
} : {},
|
|
19541
|
+
unresolvedFailures: epoch.handoff.unresolvedFailures.map((failure) => ({ ...failure })),
|
|
19542
|
+
changedFiles: [...epoch.handoff.changedFiles],
|
|
19543
|
+
checks: epoch.handoff.checks.map((check) => ({ ...check }))
|
|
19544
|
+
}
|
|
19545
|
+
} : {}
|
|
19546
|
+
}))
|
|
19547
|
+
} : {},
|
|
19548
|
+
...source.intentAssessment ? {
|
|
19549
|
+
intentAssessment: { ...source.intentAssessment, reasons: [...source.intentAssessment.reasons] }
|
|
19550
|
+
} : {},
|
|
19551
|
+
...source.pendingInput ? {
|
|
19552
|
+
pendingInput: { ...source.pendingInput, options: source.pendingInput.options.map((option2) => ({ ...option2 })) }
|
|
19553
|
+
} : {},
|
|
18995
19554
|
usage: { ...source.usage }
|
|
18996
19555
|
};
|
|
18997
19556
|
}
|
|
@@ -19038,17 +19597,17 @@ function composerAttachments(value) {
|
|
|
19038
19597
|
const paths = [...value.matchAll(/(?:^|\s)@([^\s]+)/g)].map((match) => match[1]).filter((path) => Boolean(path));
|
|
19039
19598
|
return [...new Set(paths)].slice(-3);
|
|
19040
19599
|
}
|
|
19041
|
-
function permissionRows(width, hasCwd,
|
|
19600
|
+
function permissionRows(width, hasCwd, compact3) {
|
|
19042
19601
|
const content = 3 + (hasCwd ? 1 : 0);
|
|
19043
19602
|
if (width >= 64) return content + 2;
|
|
19044
19603
|
if (width >= 28) return content + 3;
|
|
19045
|
-
if (
|
|
19604
|
+
if (compact3) return content + 3;
|
|
19046
19605
|
return content + 5;
|
|
19047
19606
|
}
|
|
19048
|
-
function contextInspectorRows(session,
|
|
19607
|
+
function contextInspectorRows(session, compact3, width, minimal) {
|
|
19049
19608
|
if (minimal) return 2;
|
|
19050
19609
|
const working = session.workingMemory;
|
|
19051
|
-
const entries =
|
|
19610
|
+
const entries = 6 + (compact3 ? 0 : (working?.constraints.length ? 1 : 0) + (working?.decisions.length ? 1 : 0) + (working?.openQuestions.length ? 1 : 0) + (working?.relevantFiles.length ? 1 : 0));
|
|
19052
19611
|
return 2 + entries * (width < 52 ? 2 : 1);
|
|
19053
19612
|
}
|
|
19054
19613
|
function contextInspectorStatus(status) {
|
|
@@ -19058,7 +19617,13 @@ function contextInspectorStatus(status) {
|
|
|
19058
19617
|
activeTokens: status.activeTokens,
|
|
19059
19618
|
summaryTokens: status.summaryTokens,
|
|
19060
19619
|
toolTokens: status.toolTokens,
|
|
19061
|
-
compactedMessages: status.compactedMessages
|
|
19620
|
+
compactedMessages: status.compactedMessages,
|
|
19621
|
+
epochIndex: status.epochIndex,
|
|
19622
|
+
epochCount: status.epochCount,
|
|
19623
|
+
epochTokens: status.epochTokens,
|
|
19624
|
+
epochBudget: status.epochBudget,
|
|
19625
|
+
lifetimeTokens: status.lifetimeTokens,
|
|
19626
|
+
lifetimeBudget: status.lifetimeBudget
|
|
19062
19627
|
};
|
|
19063
19628
|
}
|
|
19064
19629
|
function toolDetail2(call) {
|
|
@@ -19100,14 +19665,14 @@ function WorkspacePreparationView({
|
|
|
19100
19665
|
const theme = useTheme();
|
|
19101
19666
|
const safeWidth2 = Math.max(1, Math.floor(width));
|
|
19102
19667
|
const innerWidth = Math.max(1, safeWidth2 - (safeWidth2 >= 24 ? 4 : 0));
|
|
19103
|
-
const
|
|
19668
|
+
const compact3 = safeWidth2 < 48;
|
|
19104
19669
|
const constrained = height < 14;
|
|
19105
19670
|
const ascii = process.env.SKEIN_GLYPHS === "ascii" || process.env.MOSAIC_GLYPHS === "ascii";
|
|
19106
19671
|
const spinner = (ascii ? [".", "o", "O", "o"] : ["\u25DC", "\u25E0", "\u25DD", "\u25DE", "\u25E1", "\u25DF"])[frame % (ascii ? 4 : 6)];
|
|
19107
19672
|
const separator = ascii ? "|" : "\xB7";
|
|
19108
19673
|
const brand = ascii ? "*" : PRODUCT_MARK;
|
|
19109
19674
|
const phase = readiness ? "ready" : error ? "error" : progress.phase;
|
|
19110
|
-
const phaseLabel = preparationLabel(phase, progress, readiness,
|
|
19675
|
+
const phaseLabel = preparationLabel(phase, progress, readiness, compact3);
|
|
19111
19676
|
const detail = preparationDetail(phase, progress, readiness, error);
|
|
19112
19677
|
const modelLine = `model ${sanitizeTerminalText(model)}`;
|
|
19113
19678
|
const workspaceLine = `workspace ${compactDisplayPath(sanitizeTerminalText(workspace), Math.max(1, innerWidth - 10))}`;
|
|
@@ -19119,14 +19684,14 @@ function WorkspacePreparationView({
|
|
|
19119
19684
|
" ",
|
|
19120
19685
|
PRODUCT_NAME.toUpperCase()
|
|
19121
19686
|
] }),
|
|
19122
|
-
!
|
|
19687
|
+
!compact3 && !constrained ? /* @__PURE__ */ jsxs4(Text4, { color: theme.dim, children: [
|
|
19123
19688
|
" ",
|
|
19124
19689
|
separator,
|
|
19125
19690
|
" LOCAL CONTEXT"
|
|
19126
19691
|
] }) : null
|
|
19127
19692
|
] }),
|
|
19128
19693
|
!constrained ? /* @__PURE__ */ jsx4(Text4, { color: theme.muted, children: truncateDisplay("Ground the workspace before the first request.", innerWidth) }) : null,
|
|
19129
|
-
!constrained && !
|
|
19694
|
+
!constrained && !compact3 ? /* @__PURE__ */ jsx4(Text4, { color: theme.dim, children: truncateDisplay(`${modelLine} ${separator} ${workspaceLine}`, innerWidth) }) : !constrained ? /* @__PURE__ */ jsxs4(Fragment3, { children: [
|
|
19130
19695
|
/* @__PURE__ */ jsx4(Text4, { color: theme.dim, children: truncateDisplay(modelLine, innerWidth) }),
|
|
19131
19696
|
/* @__PURE__ */ jsx4(Text4, { color: theme.dim, children: truncateDisplay(workspaceLine, innerWidth) })
|
|
19132
19697
|
] }) : /* @__PURE__ */ jsx4(Text4, { color: theme.dim, children: truncateDisplay(workspaceLine, innerWidth) }),
|
|
@@ -19140,10 +19705,10 @@ function WorkspacePreparationView({
|
|
|
19140
19705
|
step2.glyph,
|
|
19141
19706
|
" "
|
|
19142
19707
|
] }),
|
|
19143
|
-
/* @__PURE__ */ jsx4(Text4, { bold: step2.state === "active", color: step2.state === "pending" ? theme.dim : theme.textStrong, children: truncateDisplay(step2.label,
|
|
19708
|
+
/* @__PURE__ */ jsx4(Text4, { bold: step2.state === "active", color: step2.state === "pending" ? theme.dim : theme.textStrong, children: truncateDisplay(step2.label, compact3 ? 8 : 10) }),
|
|
19144
19709
|
/* @__PURE__ */ jsxs4(Text4, { color: step2.state === "active" ? theme.muted : theme.dim, children: [
|
|
19145
19710
|
" ",
|
|
19146
|
-
truncateDisplay(step2.detail, Math.max(1, innerWidth - displayWidth(step2.glyph) - (
|
|
19711
|
+
truncateDisplay(step2.detail, Math.max(1, innerWidth - displayWidth(step2.glyph) - (compact3 ? 12 : 14)))
|
|
19147
19712
|
] })
|
|
19148
19713
|
] }, step2.id)) }),
|
|
19149
19714
|
/* @__PURE__ */ jsxs4(Box3, { marginTop: 1, children: [
|
|
@@ -19284,9 +19849,9 @@ async function runWorkspacePreparation(engine, config, options = {}) {
|
|
|
19284
19849
|
await instance.waitUntilExit();
|
|
19285
19850
|
return result ?? { status: "cancelled" };
|
|
19286
19851
|
}
|
|
19287
|
-
function preparationLabel(phase, progress, readiness,
|
|
19852
|
+
function preparationLabel(phase, progress, readiness, compact3 = false) {
|
|
19288
19853
|
if (phase === "ready") {
|
|
19289
|
-
if (
|
|
19854
|
+
if (compact3) return "Index verified";
|
|
19290
19855
|
return readiness?.rebuilt ? "Workspace index created and verified" : "Workspace index verified";
|
|
19291
19856
|
}
|
|
19292
19857
|
if (phase === "error") return "Workspace preparation failed";
|
|
@@ -19690,7 +20255,7 @@ function OnboardingFlow({ initialConfig, saveConfig, onFinish }) {
|
|
|
19690
20255
|
}, [finish, saveConfig, state]);
|
|
19691
20256
|
return /* @__PURE__ */ jsx5(OnboardingScreen, { state, dispatch, width, compact: compactHeight });
|
|
19692
20257
|
}
|
|
19693
|
-
function OnboardingScreen({ state, dispatch, width, compact:
|
|
20258
|
+
function OnboardingScreen({ state, dispatch, width, compact: compact3 = false }) {
|
|
19694
20259
|
const theme = useTheme();
|
|
19695
20260
|
const ascii = process.env.SKEIN_GLYPHS === "ascii" || process.env.MOSAIC_GLYPHS === "ascii";
|
|
19696
20261
|
const marker = ascii ? ">" : "\u203A";
|
|
@@ -19707,14 +20272,14 @@ function OnboardingScreen({ state, dispatch, width, compact: compact2 = false })
|
|
|
19707
20272
|
] }),
|
|
19708
20273
|
/* @__PURE__ */ jsx5(Text6, { color: theme.border, children: truncateDisplay(stageDivider(ascii, headerWidth), headerWidth) }),
|
|
19709
20274
|
/* @__PURE__ */ jsx5(Text6, { color: theme.dim, children: truncateDisplay(stage.name, headerWidth) }),
|
|
19710
|
-
!
|
|
20275
|
+
!compact3 ? /* @__PURE__ */ jsx5(Box4, { height: 1 }) : null,
|
|
19711
20276
|
/* @__PURE__ */ jsx5(Text6, { color: theme.textStrong, bold: true, children: truncateDisplay(titleForStep(state.step), headerWidth) }),
|
|
19712
|
-
!
|
|
20277
|
+
!compact3 ? /* @__PURE__ */ jsx5(Text6, { color: theme.muted, wrap: "wrap", children: descriptionForStep(state) }) : null,
|
|
19713
20278
|
summary ? /* @__PURE__ */ jsx5(Text6, { color: theme.dim, children: truncateDisplay(summary, headerWidth) }) : null,
|
|
19714
|
-
!
|
|
19715
|
-
state.step === "method" ? /* @__PURE__ */ jsx5(OptionList, { options: methods, selected: state.selected, marker, width: headerWidth, compact:
|
|
19716
|
-
state.step === "official-provider" ? /* @__PURE__ */ jsx5(OptionList, { options: officialProviders, selected: state.selected, marker, width: headerWidth, compact:
|
|
19717
|
-
state.step === "relay-protocol" ? /* @__PURE__ */ jsx5(OptionList, { options: relayProtocols, selected: state.selected, marker, width: headerWidth, compact:
|
|
20279
|
+
!compact3 ? /* @__PURE__ */ jsx5(Box4, { height: 1 }) : null,
|
|
20280
|
+
state.step === "method" ? /* @__PURE__ */ jsx5(OptionList, { options: methods, selected: state.selected, marker, width: headerWidth, compact: compact3 }) : null,
|
|
20281
|
+
state.step === "official-provider" ? /* @__PURE__ */ jsx5(OptionList, { options: officialProviders, selected: state.selected, marker, width: headerWidth, compact: compact3 }) : null,
|
|
20282
|
+
state.step === "relay-protocol" ? /* @__PURE__ */ jsx5(OptionList, { options: relayProtocols, selected: state.selected, marker, width: headerWidth, compact: compact3 }) : null,
|
|
19718
20283
|
inputField ? /* @__PURE__ */ jsxs5(Box4, { flexDirection: "column", children: [
|
|
19719
20284
|
/* @__PURE__ */ jsxs5(Box4, { children: [
|
|
19720
20285
|
/* @__PURE__ */ jsx5(Text6, { color: theme.textStrong, bold: true, children: inputField.label }),
|
|
@@ -19742,18 +20307,18 @@ function OnboardingScreen({ state, dispatch, width, compact: compact2 = false })
|
|
|
19742
20307
|
"! ",
|
|
19743
20308
|
truncateDisplay(state.error, Math.max(1, headerWidth - 2))
|
|
19744
20309
|
] }) : null,
|
|
19745
|
-
!
|
|
20310
|
+
!compact3 ? /* @__PURE__ */ jsx5(Box4, { height: 1 }) : null,
|
|
19746
20311
|
/* @__PURE__ */ jsx5(Text6, { color: theme.dim, children: footerForStep(state, headerWidth) })
|
|
19747
20312
|
] });
|
|
19748
20313
|
}
|
|
19749
|
-
function OptionList({ options, selected, marker, width, compact:
|
|
20314
|
+
function OptionList({ options, selected, marker, width, compact: compact3 }) {
|
|
19750
20315
|
const theme = useTheme();
|
|
19751
|
-
return /* @__PURE__ */ jsx5(Box4, { flexDirection: "column", children: options.map((
|
|
20316
|
+
return /* @__PURE__ */ jsx5(Box4, { flexDirection: "column", children: options.map((option2, index) => {
|
|
19752
20317
|
const active = index === selected;
|
|
19753
20318
|
const prefix = active ? `${marker} ` : " ";
|
|
19754
20319
|
const available = Math.max(1, width - displayWidth(prefix) - (active ? 2 : 0));
|
|
19755
|
-
const label = `${prefix}${truncateDisplay(
|
|
19756
|
-
return /* @__PURE__ */ jsxs5(Box4, { flexDirection: "column", marginBottom:
|
|
20320
|
+
const label = `${prefix}${truncateDisplay(option2.label, available)}`;
|
|
20321
|
+
return /* @__PURE__ */ jsxs5(Box4, { flexDirection: "column", marginBottom: compact3 || index === options.length - 1 ? 0 : 1, children: [
|
|
19757
20322
|
/* @__PURE__ */ jsx5(
|
|
19758
20323
|
Text6,
|
|
19759
20324
|
{
|
|
@@ -19763,8 +20328,8 @@ function OptionList({ options, selected, marker, width, compact: compact2 }) {
|
|
|
19763
20328
|
children: active ? padDisplay(label, width) : label
|
|
19764
20329
|
}
|
|
19765
20330
|
),
|
|
19766
|
-
!
|
|
19767
|
-
] },
|
|
20331
|
+
!compact3 && width >= 36 || active ? /* @__PURE__ */ jsx5(Box4, { marginLeft: 2, width: Math.max(1, width - 2), children: /* @__PURE__ */ jsx5(Text6, { color: active ? theme.muted : theme.dim, wrap: "wrap", children: option2.detail }) }) : null
|
|
20332
|
+
] }, option2.label);
|
|
19768
20333
|
}) });
|
|
19769
20334
|
}
|
|
19770
20335
|
function Confirmation({ state, width }) {
|
|
@@ -21465,7 +22030,7 @@ process.on("warning", (warning) => {
|
|
|
21465
22030
|
var program = new Command();
|
|
21466
22031
|
program.enablePositionalOptions();
|
|
21467
22032
|
program.name(PRODUCT_COMMAND).description("A context-first, model-agnostic coding agent with an auditable workspace.").version(package_default.version).showSuggestionAfterError();
|
|
21468
|
-
program.argument("[prompt...]", "instruction for the agent").option("-p, --print", "run once and print the result").option("-a, --ask", "retrieval and inspection mode; mutation tools are denied").option("--plan", "read-only planning mode; propose changes without mutating the workspace").option("-q, --quiet", "print only the final response in text mode").addOption(new Option("--output-format <format>", "text, json, or stream-json").choices(["text", "json", "stream-json"]).default("text")).option("--compact", "reduce progress output in print mode").option("--yes", "approve all non-denied tool requests for this run").option("--auto-edit", "approve read/write requests and ask before shell/Git/network").option("--trust-project-config", "allow executable and security-sensitive settings from project config").option("--queue <prompt>", "run an additional prompt after the first one", collect, []).option("-w, --workspace <path>", "primary workspace root", process.cwd()).option("--add-workspace <path>", "additional workspace root", collect, []).option("--config <path>", "explicit config file").option("--provider <provider>", "model provider").option("--model <model>", "model identifier").option("--base-url <url>", "OpenAI-compatible or provider base URL").option("--max-turns <n>", "maximum agent turns").option("--token-budget <n>", "maximum
|
|
22033
|
+
program.argument("[prompt...]", "instruction for the agent").option("-p, --print", "run once and print the result").option("-a, --ask", "retrieval and inspection mode; mutation tools are denied").option("--plan", "read-only planning mode; propose changes without mutating the workspace").option("-q, --quiet", "print only the final response in text mode").addOption(new Option("--output-format <format>", "text, json, or stream-json").choices(["text", "json", "stream-json"]).default("text")).option("--compact", "reduce progress output in print mode").option("--yes", "approve all non-denied tool requests for this run").option("--auto-edit", "approve read/write requests and ask before shell/Git/network").option("--trust-project-config", "allow executable and security-sensitive settings from project config").option("--queue <prompt>", "run an additional prompt after the first one", collect, []).option("-w, --workspace <path>", "primary workspace root", process.cwd()).option("--add-workspace <path>", "additional workspace root", collect, []).option("--config <path>", "explicit config file").option("--provider <provider>", "model provider").option("--model <model>", "model identifier").option("--base-url <url>", "OpenAI-compatible or provider base URL").option("--max-turns <n>", "maximum agent turns").option("--epoch-token-budget <n>", "maximum tokens before an internal context handoff").option("--token-budget <n>", "maximum lifetime tokens across the resumed session").option("--resume [session]", "resume a session by id or prefix").option("-c, --continue", "resume the latest session").option("--no-color", "disable color output").option("--no-checkpoint", "disable pre-mutation checkpoints for this run").action(async (prompts, options) => {
|
|
21469
22034
|
await runChat(prompts, options);
|
|
21470
22035
|
});
|
|
21471
22036
|
program.command("init").description("Create a project-local config (preserving an existing .mosaic namespace)").option("-w, --workspace <path>", "workspace root").option("--provider <provider>", "openai, anthropic, gemini, or compatible", "openai").option("--model <model>", "model identifier").option("--base-url <url>", "provider base URL").option("--api-key <key>", "store a provider key in project config (prefer env vars)").option("--index", "build the index after writing config").option("--yes", "use defaults without prompting").action(async (options) => {
|
|
@@ -22156,6 +22721,7 @@ async function runChat(prompts, options) {
|
|
|
22156
22721
|
requestPermission
|
|
22157
22722
|
});
|
|
22158
22723
|
for (const queued of options.queue) {
|
|
22724
|
+
if (session.pendingInput) break;
|
|
22159
22725
|
session = await runner.run(queued, {
|
|
22160
22726
|
askMode: options.ask === true || options.plan === true,
|
|
22161
22727
|
...options.plan ? { turnInstructions: PLAN_MODE_INSTRUCTIONS } : {},
|
|
@@ -22165,6 +22731,7 @@ async function runChat(prompts, options) {
|
|
|
22165
22731
|
});
|
|
22166
22732
|
}
|
|
22167
22733
|
reporter.finish(session);
|
|
22734
|
+
if (session.pendingInput) process.exitCode = 2;
|
|
22168
22735
|
} catch (error) {
|
|
22169
22736
|
reporter.fail(error);
|
|
22170
22737
|
process.exitCode = 1;
|
|
@@ -22333,6 +22900,7 @@ async function runtimeConfig(workspaceInput, options) {
|
|
|
22333
22900
|
agent: {
|
|
22334
22901
|
...loaded.agent,
|
|
22335
22902
|
...options.checkpoint === false ? { checkpointBeforeWrite: false } : {},
|
|
22903
|
+
...options.epochTokenBudget ? { maxEpochTokens: positiveInt(options.epochTokenBudget, loaded.agent.maxEpochTokens ?? loaded.agent.maxSessionTokens) } : {},
|
|
22336
22904
|
...options.tokenBudget ? { maxSessionTokens: positiveInt(options.tokenBudget, loaded.agent.maxSessionTokens) } : {}
|
|
22337
22905
|
},
|
|
22338
22906
|
ui: { ...loaded.ui, ...options.color === false ? { color: false } : {} }
|
|
@@ -22482,6 +23050,7 @@ function runtimeOptions(options) {
|
|
|
22482
23050
|
const provider = options.provider ?? root.provider;
|
|
22483
23051
|
const model = options.model ?? root.model;
|
|
22484
23052
|
const baseUrl = options.baseUrl ?? root.baseUrl;
|
|
23053
|
+
const epochTokenBudget = options.epochTokenBudget ?? root.epochTokenBudget;
|
|
22485
23054
|
const tokenBudget = options.tokenBudget ?? root.tokenBudget;
|
|
22486
23055
|
return {
|
|
22487
23056
|
addWorkspace: [...root.addWorkspace ?? [], ...options.addWorkspace ?? []],
|
|
@@ -22490,6 +23059,7 @@ function runtimeOptions(options) {
|
|
|
22490
23059
|
...model ? { model } : {},
|
|
22491
23060
|
...baseUrl ? { baseUrl } : {},
|
|
22492
23061
|
...options.maxTokens ? { maxTokens: options.maxTokens } : {},
|
|
23062
|
+
...epochTokenBudget ? { epochTokenBudget } : {},
|
|
22493
23063
|
...tokenBudget ? { tokenBudget } : {},
|
|
22494
23064
|
...root.color !== void 0 ? { color: root.color } : {},
|
|
22495
23065
|
...root.checkpoint !== void 0 ? { checkpoint: root.checkpoint } : {},
|