@skein-code/cli 0.3.8 → 0.3.10
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 +1 -1
- package/dist/cli.js +1164 -445
- package/dist/cli.js.map +1 -1
- package/docs/NEXT_STEPS.md +13 -10
- package/package.json +4 -4
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.10",
|
|
224
224
|
description: "A context-first, model-agnostic coding agent with an auditable terminal workspace.",
|
|
225
225
|
type: "module",
|
|
226
226
|
license: "MIT",
|
|
@@ -236,9 +236,9 @@ var package_default = {
|
|
|
236
236
|
},
|
|
237
237
|
skein: {
|
|
238
238
|
releaseNotes: [
|
|
239
|
-
"
|
|
240
|
-
"
|
|
241
|
-
"
|
|
239
|
+
"Complex executable requests now use a durable Task Contract with evidence-bound acceptance criteria",
|
|
240
|
+
"Completion stays unverified while required acceptance or final verification remains unresolved",
|
|
241
|
+
"Structured tool failure receipts add concise repair hints, retry budgets, cancellation handling, and identical-call circuit breaking"
|
|
242
242
|
]
|
|
243
243
|
},
|
|
244
244
|
bin: {
|
|
@@ -3279,7 +3279,7 @@ function formatContextHits(hits, roots) {
|
|
|
3279
3279
|
}
|
|
3280
3280
|
|
|
3281
3281
|
// src/agent/runner.ts
|
|
3282
|
-
import { randomUUID as
|
|
3282
|
+
import { randomUUID as randomUUID12 } from "node:crypto";
|
|
3283
3283
|
|
|
3284
3284
|
// src/context/manager.ts
|
|
3285
3285
|
var RECENT_TURN_RESERVE = 3;
|
|
@@ -4974,6 +4974,19 @@ var lastRunSchema = z5.object({
|
|
|
4974
4974
|
checks: z5.array(verificationEvidenceSchema),
|
|
4975
4975
|
detail: z5.string(),
|
|
4976
4976
|
mutationTracking: z5.enum(["complete", "unknown"]).optional(),
|
|
4977
|
+
acceptance: z5.object({
|
|
4978
|
+
state: z5.enum(["draft", "active", "satisfied", "blocked"]),
|
|
4979
|
+
total: z5.number().int().nonnegative(),
|
|
4980
|
+
satisfied: z5.number().int().nonnegative(),
|
|
4981
|
+
pending: z5.number().int().nonnegative(),
|
|
4982
|
+
blocked: z5.number().int().nonnegative(),
|
|
4983
|
+
missingVerification: z5.array(z5.string()),
|
|
4984
|
+
unresolved: z5.array(z5.object({
|
|
4985
|
+
id: z5.string(),
|
|
4986
|
+
description: z5.string(),
|
|
4987
|
+
status: z5.enum(["pending", "satisfied", "blocked"])
|
|
4988
|
+
}).strict())
|
|
4989
|
+
}).strict().optional(),
|
|
4977
4990
|
reason: z5.string(),
|
|
4978
4991
|
finishedAt: z5.string()
|
|
4979
4992
|
}).strict();
|
|
@@ -4986,6 +4999,27 @@ var workingMemorySchema = z5.object({
|
|
|
4986
4999
|
relevantFiles: z5.array(z5.string()),
|
|
4987
5000
|
lastUpdatedAt: z5.string()
|
|
4988
5001
|
}).strict();
|
|
5002
|
+
var taskContractCriterionSchema = z5.object({
|
|
5003
|
+
id: z5.string().min(1).max(128),
|
|
5004
|
+
description: z5.string().min(1).max(2e3),
|
|
5005
|
+
required: z5.boolean(),
|
|
5006
|
+
status: z5.enum(["pending", "satisfied", "blocked"]),
|
|
5007
|
+
evidenceRefs: z5.array(z5.string().min(1).max(256)).max(64),
|
|
5008
|
+
note: z5.string().max(2e3).optional()
|
|
5009
|
+
}).strict();
|
|
5010
|
+
var taskContractSchema = z5.object({
|
|
5011
|
+
version: z5.literal(1),
|
|
5012
|
+
state: z5.enum(["draft", "active", "satisfied", "blocked"]),
|
|
5013
|
+
objective: z5.string().min(1).max(2e4),
|
|
5014
|
+
scope: z5.array(z5.string().min(1).max(2e3)).max(64),
|
|
5015
|
+
constraints: z5.array(z5.string().min(1).max(2e3)).max(64),
|
|
5016
|
+
nonGoals: z5.array(z5.string().min(1).max(2e3)).max(64),
|
|
5017
|
+
acceptanceCriteria: z5.array(taskContractCriterionSchema).min(1).max(64),
|
|
5018
|
+
verificationRequirements: z5.array(z5.string().min(1).max(2e3)).max(64),
|
|
5019
|
+
createdAt: z5.string(),
|
|
5020
|
+
updatedAt: z5.string(),
|
|
5021
|
+
auditBoundaryId: z5.string().min(1).max(128).optional()
|
|
5022
|
+
}).strict();
|
|
4989
5023
|
var sessionSchema = z5.object({
|
|
4990
5024
|
id: sessionIdSchema,
|
|
4991
5025
|
title: z5.string(),
|
|
@@ -5003,6 +5037,7 @@ var sessionSchema = z5.object({
|
|
|
5003
5037
|
compactedThroughMessageId: z5.string().optional(),
|
|
5004
5038
|
workingMemory: workingMemorySchema.optional(),
|
|
5005
5039
|
contextSources: z5.array(contextSourceSchema).max(64).optional(),
|
|
5040
|
+
taskContract: taskContractSchema.optional(),
|
|
5006
5041
|
lastRun: lastRunSchema.optional(),
|
|
5007
5042
|
usage: z5.object({
|
|
5008
5043
|
inputTokens: z5.number().nonnegative(),
|
|
@@ -6751,119 +6786,90 @@ var taskTool = {
|
|
|
6751
6786
|
}
|
|
6752
6787
|
};
|
|
6753
6788
|
|
|
6754
|
-
// src/tools/
|
|
6789
|
+
// src/tools/task-contract.ts
|
|
6790
|
+
import { randomUUID as randomUUID11 } from "node:crypto";
|
|
6755
6791
|
import { z as z13 } from "zod";
|
|
6756
|
-
|
|
6757
|
-
|
|
6758
|
-
|
|
6759
|
-
|
|
6760
|
-
|
|
6761
|
-
|
|
6762
|
-
|
|
6763
|
-
|
|
6764
|
-
|
|
6765
|
-
|
|
6766
|
-
|
|
6767
|
-
|
|
6768
|
-
|
|
6769
|
-
|
|
6770
|
-
|
|
6771
|
-
|
|
6772
|
-
|
|
6773
|
-
|
|
6774
|
-
|
|
6775
|
-
|
|
6776
|
-
"set_focus",
|
|
6777
|
-
"add_constraint",
|
|
6778
|
-
"add_decision",
|
|
6779
|
-
"add_question",
|
|
6780
|
-
"resolve_question",
|
|
6781
|
-
"add_file",
|
|
6782
|
-
"clear"
|
|
6783
|
-
] },
|
|
6784
|
-
value: { type: "string", description: "Text for a goal, focus, constraint, decision, or question." },
|
|
6785
|
-
path: { type: "string", description: "Workspace-relative relevant file path." },
|
|
6786
|
-
field: { type: "string", enum: ["constraints", "decisions", "openQuestions", "relevantFiles"] }
|
|
6787
|
-
}, ["action"])
|
|
6788
|
-
},
|
|
6789
|
-
async execute(arguments_, context) {
|
|
6790
|
-
const input2 = inputSchema9.parse(arguments_);
|
|
6791
|
-
const memory = context.session.workingMemory ?? emptyWorkingMemory2();
|
|
6792
|
-
switch (input2.action) {
|
|
6793
|
-
case "show":
|
|
6794
|
-
break;
|
|
6795
|
-
case "set_goal":
|
|
6796
|
-
memory.goal = clean(input2.value);
|
|
6797
|
-
break;
|
|
6798
|
-
case "set_focus":
|
|
6799
|
-
memory.focus = clean(input2.value);
|
|
6800
|
-
break;
|
|
6801
|
-
case "add_constraint":
|
|
6802
|
-
pushBounded2(memory.constraints, input2.value, 12);
|
|
6803
|
-
break;
|
|
6804
|
-
case "add_decision":
|
|
6805
|
-
pushBounded2(memory.decisions, input2.value, 12);
|
|
6806
|
-
break;
|
|
6807
|
-
case "add_question":
|
|
6808
|
-
pushBounded2(memory.openQuestions, input2.value, 12);
|
|
6809
|
-
break;
|
|
6810
|
-
case "resolve_question":
|
|
6811
|
-
removeMatching(memory.openQuestions, input2.value);
|
|
6812
|
-
break;
|
|
6813
|
-
case "add_file": {
|
|
6814
|
-
const safe = await context.workspace.resolvePath(input2.path, { expect: "any" });
|
|
6815
|
-
pushBounded2(memory.relevantFiles, safe, 24);
|
|
6816
|
-
break;
|
|
6817
|
-
}
|
|
6818
|
-
case "clear":
|
|
6819
|
-
memory[input2.field] = [];
|
|
6820
|
-
break;
|
|
6821
|
-
}
|
|
6822
|
-
memory.lastUpdatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
6823
|
-
context.session.workingMemory = memory;
|
|
6824
|
-
return { content: render(memory), metadata: { workingMemory: { ...memory } } };
|
|
6825
|
-
}
|
|
6826
|
-
};
|
|
6827
|
-
function emptyWorkingMemory2() {
|
|
6792
|
+
|
|
6793
|
+
// src/agent/task-contract.ts
|
|
6794
|
+
import { randomUUID as randomUUID10 } from "node:crypto";
|
|
6795
|
+
var EXECUTABLE_INTENTS = /* @__PURE__ */ new Set(["debug", "refactor", "test", "implement"]);
|
|
6796
|
+
function shouldUseTaskContract(request, intent, existing) {
|
|
6797
|
+
if (existing && existing.state !== "satisfied") return true;
|
|
6798
|
+
if (!EXECUTABLE_INTENTS.has(intent)) return false;
|
|
6799
|
+
const value = request.trim();
|
|
6800
|
+
if (value.length < 180) return false;
|
|
6801
|
+
const requirements = value.split(/(?:\n+|[;;。]\s*|\b(?:and|then|also|plus)\b|以及|并且|同时|还要|另外)/iu).filter((item) => item.trim().length >= 12);
|
|
6802
|
+
const complexitySignals = [
|
|
6803
|
+
/\b(?:refactor|migrate|redesign|architecture|end[- ]to[- ]end|across|multiple)\b/iu,
|
|
6804
|
+
/重构|迁移|架构|完整|全链路|多个|跨模块|兼容|同时/iu,
|
|
6805
|
+
/(?:^|\n)\s*(?:[-*]|\d+[.)、])\s+/mu
|
|
6806
|
+
].filter((pattern) => pattern.test(value)).length;
|
|
6807
|
+
return requirements.length >= 3 || complexitySignals >= 2 || value.length >= 500;
|
|
6808
|
+
}
|
|
6809
|
+
function createDraftTaskContract(request, auditBoundaryId) {
|
|
6810
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
6811
|
+
const objective = compact(request, 2e3);
|
|
6828
6812
|
return {
|
|
6829
|
-
|
|
6830
|
-
|
|
6831
|
-
|
|
6832
|
-
|
|
6833
|
-
|
|
6834
|
-
|
|
6835
|
-
|
|
6813
|
+
version: 1,
|
|
6814
|
+
state: "draft",
|
|
6815
|
+
objective,
|
|
6816
|
+
scope: ["Configured workspace roots and the files required by the objective."],
|
|
6817
|
+
constraints: [
|
|
6818
|
+
"Preserve unrelated user changes.",
|
|
6819
|
+
"Use successful tool evidence for acceptance claims."
|
|
6820
|
+
],
|
|
6821
|
+
nonGoals: [],
|
|
6822
|
+
acceptanceCriteria: [
|
|
6823
|
+
criterion("requested-outcome", `Implement the requested outcome: ${compact(request, 500)}`),
|
|
6824
|
+
criterion("verification", "Run the smallest relevant deterministic verification after the final mutation.")
|
|
6825
|
+
],
|
|
6826
|
+
verificationRequirements: [
|
|
6827
|
+
"Record at least one successful test, typecheck, lint, build, check, or diff check after the final mutation."
|
|
6828
|
+
],
|
|
6829
|
+
createdAt: now,
|
|
6830
|
+
updatedAt: now,
|
|
6831
|
+
...auditBoundaryId ? { auditBoundaryId } : {}
|
|
6836
6832
|
};
|
|
6837
6833
|
}
|
|
6838
|
-
function
|
|
6839
|
-
const
|
|
6840
|
-
const
|
|
6841
|
-
if (
|
|
6842
|
-
|
|
6843
|
-
|
|
6834
|
+
function successfulContractEvidence(session) {
|
|
6835
|
+
const refs = /* @__PURE__ */ new Set();
|
|
6836
|
+
const contract = session.taskContract;
|
|
6837
|
+
if (!contract) return refs;
|
|
6838
|
+
for (const event of eventsSinceContract(session.audit ?? [], contract)) {
|
|
6839
|
+
if (event.type !== "tool" || event.outcome !== "success") continue;
|
|
6840
|
+
if (event.tool === "task_contract" || event.tool === "task" || event.tool === "working_memory") continue;
|
|
6841
|
+
refs.add(event.id);
|
|
6842
|
+
refs.add(event.toolCallId);
|
|
6843
|
+
}
|
|
6844
|
+
return refs;
|
|
6844
6845
|
}
|
|
6845
|
-
function
|
|
6846
|
-
|
|
6847
|
-
|
|
6848
|
-
|
|
6849
|
-
if (candidate.toLocaleLowerCase() === query || candidate.toLocaleLowerCase().includes(query)) {
|
|
6850
|
-
values.splice(index, 1);
|
|
6851
|
-
}
|
|
6846
|
+
function eventsSinceContract(audit, contract) {
|
|
6847
|
+
if (contract.auditBoundaryId) {
|
|
6848
|
+
const boundary = audit.findIndex((event) => event.id === contract.auditBoundaryId);
|
|
6849
|
+
if (boundary >= 0) return audit.slice(boundary + 1);
|
|
6852
6850
|
}
|
|
6851
|
+
return audit.filter((event) => event.createdAt >= contract.createdAt);
|
|
6853
6852
|
}
|
|
6854
|
-
function
|
|
6855
|
-
|
|
6853
|
+
function refreshTaskContractState(contract) {
|
|
6854
|
+
const required = contract.acceptanceCriteria.filter((item) => item.required);
|
|
6855
|
+
contract.state = required.some((item) => item.status === "blocked") ? "blocked" : required.length > 0 && required.every((item) => item.status === "satisfied") ? "satisfied" : "active";
|
|
6856
|
+
contract.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
6856
6857
|
}
|
|
6857
|
-
function
|
|
6858
|
-
return
|
|
6859
|
-
|
|
6860
|
-
|
|
6861
|
-
|
|
6862
|
-
|
|
6863
|
-
|
|
6864
|
-
|
|
6865
|
-
].join("\n");
|
|
6858
|
+
function criterion(id, description) {
|
|
6859
|
+
return {
|
|
6860
|
+
id: `${id}-${randomUUID10().slice(0, 8)}`,
|
|
6861
|
+
description,
|
|
6862
|
+
required: true,
|
|
6863
|
+
status: "pending",
|
|
6864
|
+
evidenceRefs: []
|
|
6865
|
+
};
|
|
6866
6866
|
}
|
|
6867
|
+
function compact(value, limit) {
|
|
6868
|
+
return value.trim().replace(/\s+/gu, " ").slice(0, limit);
|
|
6869
|
+
}
|
|
6870
|
+
|
|
6871
|
+
// src/agent/completion-gate.ts
|
|
6872
|
+
import { createHash as createHash9 } from "node:crypto";
|
|
6867
6873
|
|
|
6868
6874
|
// src/tools/permissions.ts
|
|
6869
6875
|
import { createHash as createHash8, createHmac, randomBytes } from "node:crypto";
|
|
@@ -7025,27 +7031,529 @@ function normalizeFullUrl(value) {
|
|
|
7025
7031
|
return normalized.slice(0, 8e3);
|
|
7026
7032
|
}
|
|
7027
7033
|
}
|
|
7028
|
-
function scopeFingerprint(value) {
|
|
7029
|
-
return createHmac("sha256", permissionScopeSecret).update(stableScopeValue(value)).digest("hex").slice(0, 24);
|
|
7034
|
+
function scopeFingerprint(value) {
|
|
7035
|
+
return createHmac("sha256", permissionScopeSecret).update(stableScopeValue(value)).digest("hex").slice(0, 24);
|
|
7036
|
+
}
|
|
7037
|
+
function stableScopeValue(value) {
|
|
7038
|
+
if (value === null) return "null";
|
|
7039
|
+
if (typeof value === "string") return `string:${JSON.stringify(value)}`;
|
|
7040
|
+
if (typeof value === "number") return `number:${String(value)}`;
|
|
7041
|
+
if (typeof value === "boolean") return `boolean:${String(value)}`;
|
|
7042
|
+
if (typeof value === "undefined") return "undefined";
|
|
7043
|
+
if (Array.isArray(value)) return `array:[${value.map(stableScopeValue).join(",")}]`;
|
|
7044
|
+
if (typeof value === "object") {
|
|
7045
|
+
const entries = Object.entries(value).sort(([left], [right]) => left.localeCompare(right)).map(([key, item]) => `${JSON.stringify(key)}:${stableScopeValue(item)}`);
|
|
7046
|
+
return `object:{${entries.join(",")}}`;
|
|
7047
|
+
}
|
|
7048
|
+
return `${typeof value}:${String(value)}`;
|
|
7049
|
+
}
|
|
7050
|
+
function containsShellControl(command2) {
|
|
7051
|
+
return /(?:[;&|<>`\n\r]|\$\(|\$\{)/.test(command2);
|
|
7052
|
+
}
|
|
7053
|
+
function escapeRegExp(value) {
|
|
7054
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
7055
|
+
}
|
|
7056
|
+
|
|
7057
|
+
// src/agent/completion-gate.ts
|
|
7058
|
+
function captureVerification(call, result, changeSequence, configuredCommands) {
|
|
7059
|
+
if (call.name !== "shell" && call.name !== "git") return void 0;
|
|
7060
|
+
const command2 = commandForCall(call);
|
|
7061
|
+
if (!command2) return void 0;
|
|
7062
|
+
const normalized = normalizeCommand2(command2);
|
|
7063
|
+
const configured = new Set(configuredCommands.map(normalizeCommand2));
|
|
7064
|
+
const kind = configured.has(normalized) ? "configured" : classifyVerificationCommand(normalized);
|
|
7065
|
+
if (!kind) return void 0;
|
|
7066
|
+
return {
|
|
7067
|
+
toolCallId: call.id,
|
|
7068
|
+
tool: call.name,
|
|
7069
|
+
command: redactCommand(command2),
|
|
7070
|
+
kind,
|
|
7071
|
+
ok: result.ok,
|
|
7072
|
+
changeSequence,
|
|
7073
|
+
commandKey: createHash9("sha256").update(normalized).digest("hex")
|
|
7074
|
+
};
|
|
7075
|
+
}
|
|
7076
|
+
function buildRunCompletion(changedFiles, evidence, currentChangeSequence, mutationTracking = "complete", taskContract, audit = []) {
|
|
7077
|
+
const files = [...new Set(changedFiles)];
|
|
7078
|
+
const acceptance = taskContract ? buildAcceptance(taskContract, audit, evidence, currentChangeSequence) : void 0;
|
|
7079
|
+
if (mutationTracking === "unknown") {
|
|
7080
|
+
return {
|
|
7081
|
+
status: "unverified",
|
|
7082
|
+
changedFiles: files,
|
|
7083
|
+
checks: [],
|
|
7084
|
+
detail: files.length ? `Workspace changes were observed, but a dynamic shell command prevented complete mutation tracking for ${fileCount(files.length)}.` : "A dynamic shell command may have changed workspace files, but reliable mutation tracking was unavailable.",
|
|
7085
|
+
mutationTracking,
|
|
7086
|
+
...acceptance ? { acceptance: acceptanceForCompletion(acceptance, "unverified") } : {}
|
|
7087
|
+
};
|
|
7088
|
+
}
|
|
7089
|
+
if (!files.length) {
|
|
7090
|
+
if (acceptance && acceptanceUnresolved(acceptance)) {
|
|
7091
|
+
return {
|
|
7092
|
+
status: "unverified",
|
|
7093
|
+
changedFiles: [],
|
|
7094
|
+
checks: [],
|
|
7095
|
+
detail: acceptanceDetail(acceptance),
|
|
7096
|
+
acceptance: acceptanceForCompletion(acceptance, "unverified")
|
|
7097
|
+
};
|
|
7098
|
+
}
|
|
7099
|
+
return {
|
|
7100
|
+
status: "no_changes",
|
|
7101
|
+
changedFiles: [],
|
|
7102
|
+
checks: [],
|
|
7103
|
+
detail: "No workspace files changed in this run.",
|
|
7104
|
+
...acceptance ? { acceptance: acceptanceForCompletion(acceptance, "no_changes") } : {}
|
|
7105
|
+
};
|
|
7106
|
+
}
|
|
7107
|
+
const latestByCommand = /* @__PURE__ */ new Map();
|
|
7108
|
+
for (const item of evidence) {
|
|
7109
|
+
if (item.changeSequence === currentChangeSequence) {
|
|
7110
|
+
latestByCommand.set(item.commandKey, item);
|
|
7111
|
+
}
|
|
7112
|
+
}
|
|
7113
|
+
const checks = [...latestByCommand.values()].map(publicEvidence);
|
|
7114
|
+
if (!checks.length) {
|
|
7115
|
+
return {
|
|
7116
|
+
status: "unverified",
|
|
7117
|
+
changedFiles: files,
|
|
7118
|
+
checks,
|
|
7119
|
+
detail: `No successful verification was recorded after the last change to ${fileCount(files.length)}.`,
|
|
7120
|
+
...acceptance ? { acceptance: acceptanceForCompletion(acceptance, "unverified") } : {}
|
|
7121
|
+
};
|
|
7122
|
+
}
|
|
7123
|
+
const failures = checks.filter((check) => !check.ok);
|
|
7124
|
+
if (failures.length) {
|
|
7125
|
+
return {
|
|
7126
|
+
status: "verification_failed",
|
|
7127
|
+
changedFiles: files,
|
|
7128
|
+
checks,
|
|
7129
|
+
detail: `${failures.length} of ${checks.length} current verification ${checks.length === 1 ? "check" : "checks"} failed.`,
|
|
7130
|
+
...acceptance ? { acceptance: acceptanceForCompletion(acceptance, "verification_failed") } : {}
|
|
7131
|
+
};
|
|
7132
|
+
}
|
|
7133
|
+
if (acceptance && acceptanceUnresolved(acceptance)) {
|
|
7134
|
+
return {
|
|
7135
|
+
status: "unverified",
|
|
7136
|
+
changedFiles: files,
|
|
7137
|
+
checks,
|
|
7138
|
+
detail: acceptanceDetail(acceptance),
|
|
7139
|
+
acceptance: acceptanceForCompletion(acceptance, "unverified")
|
|
7140
|
+
};
|
|
7141
|
+
}
|
|
7142
|
+
return {
|
|
7143
|
+
status: "verified",
|
|
7144
|
+
changedFiles: files,
|
|
7145
|
+
checks,
|
|
7146
|
+
detail: `${checks.length} current verification ${checks.length === 1 ? "check" : "checks"} passed for ${fileCount(files.length)}.`,
|
|
7147
|
+
...acceptance ? { acceptance: acceptanceForCompletion(acceptance, "verified") } : {}
|
|
7148
|
+
};
|
|
7149
|
+
}
|
|
7150
|
+
function completionRecoveryDirective(completion) {
|
|
7151
|
+
if (completion.acceptance && acceptanceUnresolved(completion.acceptance)) {
|
|
7152
|
+
const unresolved = completion.acceptance.unresolved.map((item) => `- [${item.status}] ${item.id}: ${item.description}`).join("\n");
|
|
7153
|
+
const failed = completion.checks.filter((check) => !check.ok).map((check) => `- ${check.command} (tool call ${check.toolCallId})`).join("\n");
|
|
7154
|
+
return `<runtime-completion-gate status="acceptance_unresolved" authorization="none">
|
|
7155
|
+
The run cannot be marked complete while required Task Contract criteria remain unresolved:
|
|
7156
|
+
${unresolved || "- Acceptance criteria are satisfied."}${completion.acceptance.missingVerification.length ? `
|
|
7157
|
+
Missing required verification:
|
|
7158
|
+
${completion.acceptance.missingVerification.map((item) => `- ${item}`).join("\n")}` : ""}${failed ? `
|
|
7159
|
+
Current failed checks:
|
|
7160
|
+
${failed}` : ""}
|
|
7161
|
+
Complete or explicitly block only these criteria. Mark a criterion satisfied through task_contract only with successful tool audit evidence or a successful tool-call id. Run the smallest missing verification after the final mutation. Do not repeat the final summary or claim acceptance from prose alone.
|
|
7162
|
+
</runtime-completion-gate>`;
|
|
7163
|
+
}
|
|
7164
|
+
if (completion.status === "verification_failed") {
|
|
7165
|
+
const failed = completion.checks.filter((check) => !check.ok).map((check) => `- ${check.command} (tool call ${check.toolCallId})`).join("\n");
|
|
7166
|
+
return `<runtime-completion-gate status="verification_failed" authorization="none">
|
|
7167
|
+
The run cannot be marked complete because current verification failed:
|
|
7168
|
+
${failed}
|
|
7169
|
+
Inspect the recorded tool output, correct the underlying problem, and rerun the smallest relevant check. Do not repeat the final summary or claim success without a new successful tool result. If the failure cannot be resolved safely, state the exact blocker and leave the result unverified.
|
|
7170
|
+
</runtime-completion-gate>`;
|
|
7171
|
+
}
|
|
7172
|
+
const changeSummary = completion.mutationTracking === "unknown" ? "A dynamic shell command could not be mapped to a complete set of workspace changes." : `The run changed ${fileCount(completion.changedFiles.length)}, but no successful verification command was recorded after the last change.`;
|
|
7173
|
+
return `<runtime-completion-gate status="unverified" authorization="none">
|
|
7174
|
+
${changeSummary}
|
|
7175
|
+
Run the smallest relevant test, typecheck, lint, build, or git diff --check now. Do not repeat the final summary or claim a check passed without a successful tool result. If verification cannot be run safely, state the exact reason and leave the result unverified.
|
|
7176
|
+
</runtime-completion-gate>`;
|
|
7177
|
+
}
|
|
7178
|
+
function buildAcceptance(contract, audit, evidence, currentChangeSequence) {
|
|
7179
|
+
const contractEvents = eventsSinceContract(audit, contract);
|
|
7180
|
+
const successfulEvents = contractEvents.filter(
|
|
7181
|
+
(event) => event.type === "tool" && event.outcome === "success" && event.tool !== "task_contract" && event.tool !== "task" && event.tool !== "working_memory"
|
|
7182
|
+
);
|
|
7183
|
+
const latestMutationIndex = contractEvents.reduce((latest, event, index) => {
|
|
7184
|
+
const changedFiles = event.metadata?.changedFiles;
|
|
7185
|
+
return Array.isArray(changedFiles) && changedFiles.length > 0 ? index : latest;
|
|
7186
|
+
}, -1);
|
|
7187
|
+
const successfulRefs = /* @__PURE__ */ new Map();
|
|
7188
|
+
for (const event of successfulEvents) {
|
|
7189
|
+
const index = contractEvents.indexOf(event);
|
|
7190
|
+
successfulRefs.set(event.id, { event, index });
|
|
7191
|
+
successfulRefs.set(event.toolCallId, { event, index });
|
|
7192
|
+
}
|
|
7193
|
+
const required = contract.acceptanceCriteria.filter((item) => item.required);
|
|
7194
|
+
const normalized = required.map((item) => {
|
|
7195
|
+
const evidenceValid = item.evidenceRefs.some((ref) => {
|
|
7196
|
+
const event = successfulRefs.get(ref);
|
|
7197
|
+
return event !== void 0 && event.index >= latestMutationIndex;
|
|
7198
|
+
});
|
|
7199
|
+
const status = item.status === "satisfied" && !evidenceValid ? "pending" : item.status;
|
|
7200
|
+
return { id: item.id, description: item.description, status };
|
|
7201
|
+
});
|
|
7202
|
+
const satisfied = normalized.filter((item) => item.status === "satisfied").length;
|
|
7203
|
+
const pending = normalized.filter((item) => item.status === "pending").length;
|
|
7204
|
+
const blocked = normalized.filter((item) => item.status === "blocked").length;
|
|
7205
|
+
const currentChecks = evidence.filter((item) => item.changeSequence === currentChangeSequence && item.ok);
|
|
7206
|
+
const requirements = contract.verificationRequirements.length ? contract.verificationRequirements : ["Record at least one successful test, typecheck, lint, build, check, or diff check after the final mutation."];
|
|
7207
|
+
const missingVerification = requirements.filter(
|
|
7208
|
+
(requirement) => !verificationRequirementMet(requirement, currentChecks)
|
|
7209
|
+
);
|
|
7210
|
+
return {
|
|
7211
|
+
state: contract.state === "draft" ? "draft" : blocked > 0 ? "blocked" : pending > 0 || missingVerification.length > 0 ? "active" : "satisfied",
|
|
7212
|
+
total: normalized.length,
|
|
7213
|
+
satisfied,
|
|
7214
|
+
pending,
|
|
7215
|
+
blocked,
|
|
7216
|
+
missingVerification,
|
|
7217
|
+
unresolved: normalized.filter((item) => item.status !== "satisfied")
|
|
7218
|
+
};
|
|
7219
|
+
}
|
|
7220
|
+
function acceptanceDetail(acceptance) {
|
|
7221
|
+
const parts = [
|
|
7222
|
+
acceptance.pending ? `${acceptance.pending} pending` : "",
|
|
7223
|
+
acceptance.blocked ? `${acceptance.blocked} blocked` : "",
|
|
7224
|
+
acceptance.missingVerification.length ? `${acceptance.missingVerification.length} verification requirements missing` : ""
|
|
7225
|
+
].filter(Boolean).join(" and ");
|
|
7226
|
+
const unresolved = acceptance.pending + acceptance.blocked;
|
|
7227
|
+
return `Task Contract acceptance is unresolved: ${parts} required ${unresolved === 1 ? "criterion" : "criteria"}.`;
|
|
7228
|
+
}
|
|
7229
|
+
function verificationRequirementMet(requirement, checks) {
|
|
7230
|
+
const normalized = normalizeCommand2(requirement);
|
|
7231
|
+
const broad = normalized.match(/^Record at least one successful (.+) after the final mutation\.?$/iu);
|
|
7232
|
+
if (broad) return checks.length > 0;
|
|
7233
|
+
const commandKey = createHash9("sha256").update(normalized).digest("hex");
|
|
7234
|
+
return checks.some((item) => item.commandKey === commandKey);
|
|
7235
|
+
}
|
|
7236
|
+
function acceptanceUnresolved(acceptance) {
|
|
7237
|
+
return acceptance.pending > 0 || acceptance.blocked > 0 || acceptance.missingVerification.length > 0;
|
|
7238
|
+
}
|
|
7239
|
+
function acceptanceForCompletion(acceptance, status) {
|
|
7240
|
+
if (acceptance.state === "draft" || acceptance.state === "blocked" || status === "verified" || status === "no_changes") return acceptance;
|
|
7241
|
+
return acceptance.state === "active" ? acceptance : { ...acceptance, state: "active" };
|
|
7242
|
+
}
|
|
7243
|
+
function classifyVerificationCommand(command2) {
|
|
7244
|
+
const normalized = normalizeCommand2(command2).toLocaleLowerCase();
|
|
7245
|
+
const segments = normalized.split(/\s*(?:&&|\|\||;)\s*/u).filter(Boolean);
|
|
7246
|
+
if (segments.length > 1) {
|
|
7247
|
+
const kinds = segments.map(classifySingleVerificationCommand);
|
|
7248
|
+
if (kinds.every((kind) => kind !== void 0)) {
|
|
7249
|
+
return kinds.every((kind) => kind === kinds[0]) ? kinds[0] : "check";
|
|
7250
|
+
}
|
|
7251
|
+
return void 0;
|
|
7252
|
+
}
|
|
7253
|
+
return classifySingleVerificationCommand(normalized);
|
|
7254
|
+
}
|
|
7255
|
+
function classifySingleVerificationCommand(command2) {
|
|
7256
|
+
const value = command2.replace(/^(?:[A-Za-z_][A-Za-z0-9_]*=(?:"[^"]*"|'[^']*'|[^\s]+)\s+)+/u, "");
|
|
7257
|
+
if (/^git\s+diff\b.*(?:^|\s)--check(?:\s|$)/u.test(value)) return "diff";
|
|
7258
|
+
if (/^(?:npm|pnpm|yarn|bun)\s+(?:run\s+)?(?:test(?::[^\s]+)?|test|vitest|jest)(?:\s|$)/u.test(value) || /^(?:npx|pnpx|bunx)\s+(?:vitest|jest)(?:\s|$)/u.test(value) || /^(?:python(?:\d+(?:\.\d+)*)?\s+-m\s+)?pytest(?:\s|$)/u.test(value) || /^(?:cargo|go|dotnet|mvn|mvnw|gradle|gradlew)\s+(?:test|verify)(?:\s|$)/u.test(value) || /^(?:make|just|task)\s+(?:test|verify)(?:\s|$)/u.test(value) || /^node\s+--test(?:\s|$)/u.test(value)) return "test";
|
|
7259
|
+
if (/^(?:npm|pnpm|yarn|bun)\s+(?:run\s+)?(?:typecheck|type-check|check:types)(?:\s|$)/u.test(value) || /^(?:npx|pnpx|bunx)\s+(?:tsc|pyright|mypy)(?:\s|$)/u.test(value) || /^(?:tsc|pyright|mypy)(?:\s|$)/u.test(value) || /^cargo\s+check(?:\s|$)/u.test(value)) return "typecheck";
|
|
7260
|
+
if (/^(?:npm|pnpm|yarn|bun)\s+(?:run\s+)?lint(?:\s|$)/u.test(value) || /^(?:npx|pnpx|bunx)\s+(?:eslint|biome|ruff)(?:\s|$)/u.test(value) || /^(?:eslint|biome\s+check|ruff\s+check|cargo\s+clippy)(?:\s|$)/u.test(value)) return "lint";
|
|
7261
|
+
if (/^(?:npm|pnpm|yarn|bun)\s+(?:run\s+)?(?:build|compile)(?:\s|$)/u.test(value) || /^(?:cargo|go|dotnet|mvn|mvnw|gradle|gradlew)\s+build(?:\s|$)/u.test(value) || /^(?:make|just|task)\s+(?:build|compile)(?:\s|$)/u.test(value)) return "build";
|
|
7262
|
+
if (/^(?:npm|pnpm|yarn|bun)\s+(?:run\s+)?check(?:\s|$)/u.test(value) || /^(?:make|just|task|gradle|gradlew)\s+check(?:\s|$)/u.test(value)) return "check";
|
|
7263
|
+
return void 0;
|
|
7264
|
+
}
|
|
7265
|
+
function publicEvidence(item) {
|
|
7266
|
+
return {
|
|
7267
|
+
toolCallId: item.toolCallId,
|
|
7268
|
+
tool: item.tool,
|
|
7269
|
+
command: item.command,
|
|
7270
|
+
kind: item.kind,
|
|
7271
|
+
ok: item.ok
|
|
7272
|
+
};
|
|
7273
|
+
}
|
|
7274
|
+
function normalizeCommand2(command2) {
|
|
7275
|
+
return command2.trim().replace(/[\t ]+/gu, " ");
|
|
7276
|
+
}
|
|
7277
|
+
function redactCommand(command2) {
|
|
7278
|
+
return command2.replace(/[\u0000-\u001f\u007f-\u009f]/gu, " ").replace(/\b((?:api[_-]?key|access[_-]?token|authorization|password|secret|token))\s*=\s*([^\s]+)/giu, "$1=[redacted]").replace(/\b(sk-[A-Za-z0-9_-]{12,}|AIza[0-9A-Za-z_-]{20,})\b/gu, "[redacted-secret]").trim().slice(0, 2e3);
|
|
7279
|
+
}
|
|
7280
|
+
function fileCount(count) {
|
|
7281
|
+
return `${count} workspace ${count === 1 ? "file" : "files"}`;
|
|
7282
|
+
}
|
|
7283
|
+
|
|
7284
|
+
// src/tools/task-contract.ts
|
|
7285
|
+
var criterionSchema = z13.object({
|
|
7286
|
+
id: z13.string().min(1).max(128).optional(),
|
|
7287
|
+
description: z13.string().min(1).max(2e3),
|
|
7288
|
+
required: z13.boolean().optional()
|
|
7289
|
+
}).strict();
|
|
7290
|
+
var inputSchema9 = z13.discriminatedUnion("action", [
|
|
7291
|
+
z13.object({ action: z13.literal("show") }).strict(),
|
|
7292
|
+
z13.object({
|
|
7293
|
+
action: z13.literal("replace"),
|
|
7294
|
+
objective: z13.string().min(1).max(2e4),
|
|
7295
|
+
scope: z13.array(z13.string().min(1).max(2e3)).max(64),
|
|
7296
|
+
constraints: z13.array(z13.string().min(1).max(2e3)).max(64),
|
|
7297
|
+
non_goals: z13.array(z13.string().min(1).max(2e3)).max(64),
|
|
7298
|
+
acceptance_criteria: z13.array(criterionSchema).min(1).max(64),
|
|
7299
|
+
verification_requirements: z13.array(z13.string().min(1).max(2e3)).min(1).max(64)
|
|
7300
|
+
}).strict(),
|
|
7301
|
+
z13.object({ action: z13.literal("activate") }).strict(),
|
|
7302
|
+
z13.object({
|
|
7303
|
+
action: z13.literal("update_criterion"),
|
|
7304
|
+
id: z13.string().min(1).max(128),
|
|
7305
|
+
status: z13.enum(["pending", "satisfied", "blocked"]),
|
|
7306
|
+
evidence_refs: z13.array(z13.string().min(1).max(256)).max(64).optional(),
|
|
7307
|
+
note: z13.string().max(2e3).optional()
|
|
7308
|
+
}).strict()
|
|
7309
|
+
]);
|
|
7310
|
+
var taskContractTool = {
|
|
7311
|
+
definition: {
|
|
7312
|
+
name: "task_contract",
|
|
7313
|
+
description: "Define and update the durable acceptance contract for a complex executable request. Satisfied criteria require successful tool audit evidence IDs or tool-call IDs.",
|
|
7314
|
+
category: "read",
|
|
7315
|
+
inputSchema: {
|
|
7316
|
+
type: "object",
|
|
7317
|
+
properties: {
|
|
7318
|
+
action: { type: "string", enum: ["show", "replace", "activate", "update_criterion"] },
|
|
7319
|
+
objective: { type: "string" },
|
|
7320
|
+
scope: { type: "array", items: { type: "string" } },
|
|
7321
|
+
constraints: { type: "array", items: { type: "string" } },
|
|
7322
|
+
non_goals: { type: "array", items: { type: "string" } },
|
|
7323
|
+
acceptance_criteria: { type: "array", items: {
|
|
7324
|
+
type: "object",
|
|
7325
|
+
properties: {
|
|
7326
|
+
id: { type: "string" },
|
|
7327
|
+
description: { type: "string" },
|
|
7328
|
+
required: { type: "boolean" }
|
|
7329
|
+
},
|
|
7330
|
+
required: ["description"],
|
|
7331
|
+
additionalProperties: false
|
|
7332
|
+
} },
|
|
7333
|
+
verification_requirements: {
|
|
7334
|
+
type: "array",
|
|
7335
|
+
minItems: 1,
|
|
7336
|
+
items: { type: "string" },
|
|
7337
|
+
description: "Required verification commands or the standard any-successful-check requirement."
|
|
7338
|
+
},
|
|
7339
|
+
id: { type: "string" },
|
|
7340
|
+
status: { type: "string", enum: ["pending", "satisfied", "blocked"] },
|
|
7341
|
+
evidence_refs: { type: "array", items: { type: "string" } },
|
|
7342
|
+
note: { type: "string" }
|
|
7343
|
+
},
|
|
7344
|
+
required: ["action"],
|
|
7345
|
+
additionalProperties: false
|
|
7346
|
+
}
|
|
7347
|
+
},
|
|
7348
|
+
async execute(arguments_, context) {
|
|
7349
|
+
const input2 = inputSchema9.parse(arguments_);
|
|
7350
|
+
let contract = context.session.taskContract;
|
|
7351
|
+
if (!contract) throw new Error("No Task Contract is active for this session.");
|
|
7352
|
+
if (input2.action === "replace") {
|
|
7353
|
+
if (contract.state !== "draft") {
|
|
7354
|
+
throw new Error("Only a draft Task Contract can be replaced.");
|
|
7355
|
+
}
|
|
7356
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
7357
|
+
const criteria = input2.acceptance_criteria.map((item) => ({
|
|
7358
|
+
id: item.id ?? `criterion-${randomUUID11().slice(0, 8)}`,
|
|
7359
|
+
description: item.description,
|
|
7360
|
+
required: item.required ?? true,
|
|
7361
|
+
status: "pending",
|
|
7362
|
+
evidenceRefs: []
|
|
7363
|
+
}));
|
|
7364
|
+
if (new Set(criteria.map((item) => item.id)).size !== criteria.length) {
|
|
7365
|
+
throw new Error("Task Contract criterion ids must be unique.");
|
|
7366
|
+
}
|
|
7367
|
+
if (!criteria.some((item) => item.required)) {
|
|
7368
|
+
throw new Error("Task Contract requires at least one required acceptance criterion.");
|
|
7369
|
+
}
|
|
7370
|
+
for (const existing of contract.acceptanceCriteria.filter((item) => item.required)) {
|
|
7371
|
+
const retained = criteria.find((item) => item.id === existing.id);
|
|
7372
|
+
if (!retained || !retained.required || retained.description !== existing.description) {
|
|
7373
|
+
throw new Error(`Required criterion cannot be removed or weakened: ${existing.id}`);
|
|
7374
|
+
}
|
|
7375
|
+
}
|
|
7376
|
+
for (const existing of contract.verificationRequirements) {
|
|
7377
|
+
if (!input2.verification_requirements.includes(existing)) {
|
|
7378
|
+
throw new Error(`Verification requirement cannot be removed: ${existing}`);
|
|
7379
|
+
}
|
|
7380
|
+
}
|
|
7381
|
+
for (const requirement of input2.verification_requirements) {
|
|
7382
|
+
validateVerificationRequirement(requirement);
|
|
7383
|
+
}
|
|
7384
|
+
Object.assign(contract, {
|
|
7385
|
+
version: 1,
|
|
7386
|
+
state: "active",
|
|
7387
|
+
objective: input2.objective,
|
|
7388
|
+
scope: input2.scope,
|
|
7389
|
+
constraints: input2.constraints,
|
|
7390
|
+
nonGoals: input2.non_goals,
|
|
7391
|
+
acceptanceCriteria: criteria,
|
|
7392
|
+
verificationRequirements: input2.verification_requirements,
|
|
7393
|
+
createdAt: contract.createdAt,
|
|
7394
|
+
updatedAt: now,
|
|
7395
|
+
...contract.auditBoundaryId ? { auditBoundaryId: contract.auditBoundaryId } : {}
|
|
7396
|
+
});
|
|
7397
|
+
} else if (input2.action === "activate") {
|
|
7398
|
+
refreshTaskContractState(contract);
|
|
7399
|
+
} else if (input2.action === "update_criterion") {
|
|
7400
|
+
if (contract.state === "draft") {
|
|
7401
|
+
throw new Error("Activate the draft Task Contract before updating acceptance criteria.");
|
|
7402
|
+
}
|
|
7403
|
+
const criterion2 = contract.acceptanceCriteria.find((item) => item.id === input2.id);
|
|
7404
|
+
if (!criterion2) throw new Error(`Unknown Task Contract criterion id: ${input2.id}`);
|
|
7405
|
+
const refs = [...new Set(input2.evidence_refs ?? [])];
|
|
7406
|
+
if (input2.status === "satisfied") {
|
|
7407
|
+
if (!refs.length) throw new Error("Satisfied criteria require at least one evidence_refs entry.");
|
|
7408
|
+
const valid = successfulContractEvidence(context.session);
|
|
7409
|
+
const invalid = refs.filter((ref) => !valid.has(ref));
|
|
7410
|
+
if (invalid.length) {
|
|
7411
|
+
throw new Error(`Unknown or unsuccessful evidence refs: ${invalid.join(", ")}`);
|
|
7412
|
+
}
|
|
7413
|
+
}
|
|
7414
|
+
criterion2.status = input2.status;
|
|
7415
|
+
criterion2.evidenceRefs = input2.status === "satisfied" ? refs : [];
|
|
7416
|
+
if (input2.note === void 0) delete criterion2.note;
|
|
7417
|
+
else criterion2.note = input2.note;
|
|
7418
|
+
refreshTaskContractState(contract);
|
|
7419
|
+
}
|
|
7420
|
+
return {
|
|
7421
|
+
content: formatContract(contract),
|
|
7422
|
+
metadata: { taskContract: structuredClone(contract) }
|
|
7423
|
+
};
|
|
7424
|
+
}
|
|
7425
|
+
};
|
|
7426
|
+
function formatContract(contract) {
|
|
7427
|
+
const satisfied = contract.acceptanceCriteria.filter((item) => item.status === "satisfied").length;
|
|
7428
|
+
const criteria = contract.acceptanceCriteria.map(
|
|
7429
|
+
(item) => `- [${item.status}] ${item.id}: ${item.description}`
|
|
7430
|
+
).join("\n");
|
|
7431
|
+
return `Task Contract: ${contract.state} (${satisfied}/${contract.acceptanceCriteria.length} satisfied)
|
|
7432
|
+
Objective: ${contract.objective}
|
|
7433
|
+
${criteria}`;
|
|
7434
|
+
}
|
|
7435
|
+
function validateVerificationRequirement(requirement) {
|
|
7436
|
+
if (/^Record at least one successful (.+) after the final mutation\.?$/iu.test(requirement)) return;
|
|
7437
|
+
if (/\b(?:api[_-]?key|authorization|password|secret|token)\s*=/iu.test(requirement)) {
|
|
7438
|
+
throw new Error("Verification requirements cannot contain credentials.");
|
|
7439
|
+
}
|
|
7440
|
+
if (!classifyVerificationCommand(requirement)) {
|
|
7441
|
+
throw new Error(`Verification requirement is not a recognized deterministic check: ${requirement}`);
|
|
7442
|
+
}
|
|
7443
|
+
}
|
|
7444
|
+
|
|
7445
|
+
// src/tools/working-memory.ts
|
|
7446
|
+
import { z as z14 } from "zod";
|
|
7447
|
+
var inputSchema10 = z14.discriminatedUnion("action", [
|
|
7448
|
+
z14.object({ action: z14.literal("show") }).strict(),
|
|
7449
|
+
z14.object({ action: z14.literal("set_goal"), value: z14.string().min(1).max(1e3) }).strict(),
|
|
7450
|
+
z14.object({ action: z14.literal("set_focus"), value: z14.string().min(1).max(1e3) }).strict(),
|
|
7451
|
+
z14.object({ action: z14.literal("add_constraint"), value: z14.string().min(1).max(1e3) }).strict(),
|
|
7452
|
+
z14.object({ action: z14.literal("add_decision"), value: z14.string().min(1).max(1e3) }).strict(),
|
|
7453
|
+
z14.object({ action: z14.literal("add_question"), value: z14.string().min(1).max(1e3) }).strict(),
|
|
7454
|
+
z14.object({ action: z14.literal("resolve_question"), value: z14.string().min(1).max(1e3) }).strict(),
|
|
7455
|
+
z14.object({ action: z14.literal("add_file"), path: z14.string().min(1).max(4e3) }).strict(),
|
|
7456
|
+
z14.object({ action: z14.literal("clear"), field: z14.enum(["constraints", "decisions", "openQuestions", "relevantFiles"]) }).strict()
|
|
7457
|
+
]);
|
|
7458
|
+
var workingMemoryTool = {
|
|
7459
|
+
definition: {
|
|
7460
|
+
name: "working_memory",
|
|
7461
|
+
description: "Read or update short-term thread state: goal, focus, constraints, decisions, open questions, and relevant files. This state is temporary and is not durable memory.",
|
|
7462
|
+
category: "read",
|
|
7463
|
+
inputSchema: jsonSchema({
|
|
7464
|
+
action: { type: "string", enum: [
|
|
7465
|
+
"show",
|
|
7466
|
+
"set_goal",
|
|
7467
|
+
"set_focus",
|
|
7468
|
+
"add_constraint",
|
|
7469
|
+
"add_decision",
|
|
7470
|
+
"add_question",
|
|
7471
|
+
"resolve_question",
|
|
7472
|
+
"add_file",
|
|
7473
|
+
"clear"
|
|
7474
|
+
] },
|
|
7475
|
+
value: { type: "string", description: "Text for a goal, focus, constraint, decision, or question." },
|
|
7476
|
+
path: { type: "string", description: "Workspace-relative relevant file path." },
|
|
7477
|
+
field: { type: "string", enum: ["constraints", "decisions", "openQuestions", "relevantFiles"] }
|
|
7478
|
+
}, ["action"])
|
|
7479
|
+
},
|
|
7480
|
+
async execute(arguments_, context) {
|
|
7481
|
+
const input2 = inputSchema10.parse(arguments_);
|
|
7482
|
+
const memory = context.session.workingMemory ?? emptyWorkingMemory2();
|
|
7483
|
+
switch (input2.action) {
|
|
7484
|
+
case "show":
|
|
7485
|
+
break;
|
|
7486
|
+
case "set_goal":
|
|
7487
|
+
memory.goal = clean(input2.value);
|
|
7488
|
+
break;
|
|
7489
|
+
case "set_focus":
|
|
7490
|
+
memory.focus = clean(input2.value);
|
|
7491
|
+
break;
|
|
7492
|
+
case "add_constraint":
|
|
7493
|
+
pushBounded2(memory.constraints, input2.value, 12);
|
|
7494
|
+
break;
|
|
7495
|
+
case "add_decision":
|
|
7496
|
+
pushBounded2(memory.decisions, input2.value, 12);
|
|
7497
|
+
break;
|
|
7498
|
+
case "add_question":
|
|
7499
|
+
pushBounded2(memory.openQuestions, input2.value, 12);
|
|
7500
|
+
break;
|
|
7501
|
+
case "resolve_question":
|
|
7502
|
+
removeMatching(memory.openQuestions, input2.value);
|
|
7503
|
+
break;
|
|
7504
|
+
case "add_file": {
|
|
7505
|
+
const safe = await context.workspace.resolvePath(input2.path, { expect: "any" });
|
|
7506
|
+
pushBounded2(memory.relevantFiles, safe, 24);
|
|
7507
|
+
break;
|
|
7508
|
+
}
|
|
7509
|
+
case "clear":
|
|
7510
|
+
memory[input2.field] = [];
|
|
7511
|
+
break;
|
|
7512
|
+
}
|
|
7513
|
+
memory.lastUpdatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
7514
|
+
context.session.workingMemory = memory;
|
|
7515
|
+
return { content: render(memory), metadata: { workingMemory: { ...memory } } };
|
|
7516
|
+
}
|
|
7517
|
+
};
|
|
7518
|
+
function emptyWorkingMemory2() {
|
|
7519
|
+
return {
|
|
7520
|
+
goal: "",
|
|
7521
|
+
focus: "",
|
|
7522
|
+
constraints: [],
|
|
7523
|
+
decisions: [],
|
|
7524
|
+
openQuestions: [],
|
|
7525
|
+
relevantFiles: [],
|
|
7526
|
+
lastUpdatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
7527
|
+
};
|
|
7528
|
+
}
|
|
7529
|
+
function pushBounded2(values, value, limit) {
|
|
7530
|
+
const normalized = clean(value);
|
|
7531
|
+
const existing = values.indexOf(normalized);
|
|
7532
|
+
if (existing >= 0) values.splice(existing, 1);
|
|
7533
|
+
values.push(normalized);
|
|
7534
|
+
if (values.length > limit) values.splice(0, values.length - limit);
|
|
7030
7535
|
}
|
|
7031
|
-
function
|
|
7032
|
-
|
|
7033
|
-
|
|
7034
|
-
|
|
7035
|
-
|
|
7036
|
-
|
|
7037
|
-
|
|
7038
|
-
if (typeof value === "object") {
|
|
7039
|
-
const entries = Object.entries(value).sort(([left], [right]) => left.localeCompare(right)).map(([key, item]) => `${JSON.stringify(key)}:${stableScopeValue(item)}`);
|
|
7040
|
-
return `object:{${entries.join(",")}}`;
|
|
7536
|
+
function removeMatching(values, value) {
|
|
7537
|
+
const query = value.toLocaleLowerCase().trim();
|
|
7538
|
+
for (let index = values.length - 1; index >= 0; index -= 1) {
|
|
7539
|
+
const candidate = values[index];
|
|
7540
|
+
if (candidate.toLocaleLowerCase() === query || candidate.toLocaleLowerCase().includes(query)) {
|
|
7541
|
+
values.splice(index, 1);
|
|
7542
|
+
}
|
|
7041
7543
|
}
|
|
7042
|
-
return `${typeof value}:${String(value)}`;
|
|
7043
7544
|
}
|
|
7044
|
-
function
|
|
7045
|
-
return /(?:[
|
|
7545
|
+
function clean(value) {
|
|
7546
|
+
return value.trim().replace(/\b(sk-[A-Za-z0-9_-]{12,}|AIza[0-9A-Za-z_-]{20,})\b/g, "[redacted-secret]").replace(/\b((?:api[_-]?key|access[_-]?token|auth(?:orization)?|password|secret))\s*[:=]\s*[^\s,;]+/gi, "$1=[redacted]").replace(/\s+/g, " ").slice(0, 1e3);
|
|
7046
7547
|
}
|
|
7047
|
-
function
|
|
7048
|
-
return
|
|
7548
|
+
function render(memory) {
|
|
7549
|
+
return [
|
|
7550
|
+
`Goal: ${memory.goal || "(none)"}`,
|
|
7551
|
+
`Focus: ${memory.focus || "(none)"}`,
|
|
7552
|
+
`Constraints: ${memory.constraints.length ? memory.constraints.join(" \xB7 ") : "(none)"}`,
|
|
7553
|
+
`Decisions: ${memory.decisions.length ? memory.decisions.join(" \xB7 ") : "(none)"}`,
|
|
7554
|
+
`Open questions: ${memory.openQuestions.length ? memory.openQuestions.join(" \xB7 ") : "(none)"}`,
|
|
7555
|
+
`Relevant files: ${memory.relevantFiles.length ? memory.relevantFiles.join(" \xB7 ") : "(none)"}`
|
|
7556
|
+
].join("\n");
|
|
7049
7557
|
}
|
|
7050
7558
|
|
|
7051
7559
|
// src/tools/index.ts
|
|
@@ -7059,6 +7567,7 @@ function createDefaultToolRegistry(_options = {}) {
|
|
|
7059
7567
|
shellTool,
|
|
7060
7568
|
gitTool,
|
|
7061
7569
|
taskTool,
|
|
7570
|
+
taskContractTool,
|
|
7062
7571
|
workingMemoryTool
|
|
7063
7572
|
]);
|
|
7064
7573
|
}
|
|
@@ -7098,11 +7607,19 @@ ${workspaceRules}` : ""}`;
|
|
|
7098
7607
|
}
|
|
7099
7608
|
function buildSessionStatePrompt(session) {
|
|
7100
7609
|
const tasks = session.tasks.length ? session.tasks.map((task) => `- [${task.status}] ${task.title}`).join("\n") : "- No active plan.";
|
|
7610
|
+
const contract = session.taskContract && session.taskContract.state !== "satisfied" ? `
|
|
7611
|
+
|
|
7612
|
+
Task Contract (${session.taskContract.state}):
|
|
7613
|
+
Objective: ${session.taskContract.objective}
|
|
7614
|
+
${session.taskContract.acceptanceCriteria.map(
|
|
7615
|
+
(item) => `- [${item.status}] ${item.id}: ${item.description}`
|
|
7616
|
+
).join("\n")}
|
|
7617
|
+
Use task_contract to activate or update acceptance. A satisfied criterion requires successful tool evidence.` : "";
|
|
7101
7618
|
return `<session-state scope="session" authorization="none">
|
|
7102
7619
|
This is mutable execution state, not a permission grant or higher-priority instruction.
|
|
7103
7620
|
|
|
7104
7621
|
Current saved plan:
|
|
7105
|
-
${tasks}
|
|
7622
|
+
${tasks}${contract}
|
|
7106
7623
|
</session-state>`;
|
|
7107
7624
|
}
|
|
7108
7625
|
function buildRetrievedContext(packed, mentions, primaryRoot, roots = [primaryRoot]) {
|
|
@@ -7170,130 +7687,120 @@ function escapeAttribute3(value) {
|
|
|
7170
7687
|
})[character] ?? character);
|
|
7171
7688
|
}
|
|
7172
7689
|
|
|
7173
|
-
// src/agent/
|
|
7174
|
-
import { createHash as
|
|
7175
|
-
|
|
7176
|
-
|
|
7177
|
-
|
|
7178
|
-
|
|
7179
|
-
|
|
7180
|
-
|
|
7181
|
-
|
|
7182
|
-
|
|
7183
|
-
|
|
7184
|
-
|
|
7185
|
-
|
|
7186
|
-
|
|
7187
|
-
|
|
7188
|
-
|
|
7189
|
-
|
|
7190
|
-
|
|
7191
|
-
|
|
7192
|
-
|
|
7193
|
-
|
|
7194
|
-
|
|
7195
|
-
|
|
7196
|
-
|
|
7197
|
-
|
|
7198
|
-
|
|
7199
|
-
|
|
7200
|
-
|
|
7201
|
-
|
|
7202
|
-
|
|
7690
|
+
// src/agent/tool-recovery.ts
|
|
7691
|
+
import { createHash as createHash10 } from "node:crypto";
|
|
7692
|
+
var RETRY_BUDGET = {
|
|
7693
|
+
schema_input: 3,
|
|
7694
|
+
unknown_tool: 2,
|
|
7695
|
+
permission_denied: 0,
|
|
7696
|
+
command_exit: 3,
|
|
7697
|
+
timeout: 2,
|
|
7698
|
+
cancelled: 0,
|
|
7699
|
+
hook: 1,
|
|
7700
|
+
execution: 3,
|
|
7701
|
+
contract_required: 2
|
|
7702
|
+
};
|
|
7703
|
+
var REPAIR_HINT = {
|
|
7704
|
+
schema_input: "Correct the arguments to match the tool schema.",
|
|
7705
|
+
unknown_tool: "Choose a tool exposed for this turn.",
|
|
7706
|
+
permission_denied: "Do not retry unless the user or configuration changes permission.",
|
|
7707
|
+
command_exit: "Inspect the exit output, change the command or fix the cause, then retry once.",
|
|
7708
|
+
timeout: "Narrow the operation or increase its allowed timeout.",
|
|
7709
|
+
cancelled: "Stop work and preserve the current state.",
|
|
7710
|
+
hook: "Fix the hook failure before relying on the tool result.",
|
|
7711
|
+
execution: "Use the error detail to change the inputs or approach.",
|
|
7712
|
+
contract_required: "Activate the Task Contract before any workspace mutation."
|
|
7713
|
+
};
|
|
7714
|
+
var ToolRecoveryController = class {
|
|
7715
|
+
signatures = /* @__PURE__ */ new Map();
|
|
7716
|
+
classFailures = /* @__PURE__ */ new Map();
|
|
7717
|
+
toolClasses = /* @__PURE__ */ new Map();
|
|
7718
|
+
preflight(call) {
|
|
7719
|
+
const callKey = callSignature(call);
|
|
7720
|
+
const signatureState = this.signatures.get(callKey);
|
|
7721
|
+
if (signatureState && (signatureState.failures >= 2 || !isRetryable(signatureState.failureClass))) {
|
|
7722
|
+
return this.receipt(
|
|
7723
|
+
call,
|
|
7724
|
+
signatureState.failureClass,
|
|
7725
|
+
signatureState.failures + 1,
|
|
7726
|
+
true
|
|
7727
|
+
);
|
|
7728
|
+
}
|
|
7729
|
+
const lastClass = this.toolClasses.get(call.name);
|
|
7730
|
+
if (lastClass && (this.classFailures.get(lastClass) ?? 0) >= RETRY_BUDGET[lastClass] && RETRY_BUDGET[lastClass] > 0) {
|
|
7731
|
+
return this.receipt(call, lastClass, (signatureState?.failures ?? 0) + 1, true);
|
|
7732
|
+
}
|
|
7733
|
+
return void 0;
|
|
7203
7734
|
}
|
|
7204
|
-
|
|
7205
|
-
|
|
7206
|
-
|
|
7207
|
-
|
|
7208
|
-
|
|
7209
|
-
|
|
7210
|
-
|
|
7735
|
+
recordFailure(call, failureClass) {
|
|
7736
|
+
const callKey = callSignature(call);
|
|
7737
|
+
const current = this.signatures.get(callKey);
|
|
7738
|
+
const failures = current?.failureClass === failureClass ? current.failures + 1 : 1;
|
|
7739
|
+
this.signatures.set(callKey, { failureClass, failures });
|
|
7740
|
+
this.toolClasses.set(call.name, failureClass);
|
|
7741
|
+
this.classFailures.set(failureClass, (this.classFailures.get(failureClass) ?? 0) + 1);
|
|
7742
|
+
return this.receipt(
|
|
7743
|
+
call,
|
|
7744
|
+
failureClass,
|
|
7745
|
+
failures,
|
|
7746
|
+
failures >= 2 || !isRetryable(failureClass)
|
|
7747
|
+
);
|
|
7211
7748
|
}
|
|
7212
|
-
|
|
7213
|
-
|
|
7214
|
-
|
|
7215
|
-
latestByCommand.set(item.commandKey, item);
|
|
7216
|
-
}
|
|
7749
|
+
recordSuccess(call) {
|
|
7750
|
+
this.signatures.delete(callSignature(call));
|
|
7751
|
+
this.toolClasses.delete(call.name);
|
|
7217
7752
|
}
|
|
7218
|
-
|
|
7219
|
-
|
|
7753
|
+
receipt(call, failureClass, attempt, circuitOpen) {
|
|
7754
|
+
const budget = RETRY_BUDGET[failureClass];
|
|
7755
|
+
const consumed = this.classFailures.get(failureClass) ?? 0;
|
|
7220
7756
|
return {
|
|
7221
|
-
|
|
7222
|
-
|
|
7223
|
-
|
|
7224
|
-
|
|
7757
|
+
class: failureClass,
|
|
7758
|
+
retryable: isRetryable(failureClass) && consumed < budget && !circuitOpen,
|
|
7759
|
+
repairHint: REPAIR_HINT[failureClass],
|
|
7760
|
+
attempt,
|
|
7761
|
+
remaining: Math.max(0, budget - consumed),
|
|
7762
|
+
circuitOpen,
|
|
7763
|
+
signature: failureSignature(call, failureClass)
|
|
7225
7764
|
};
|
|
7226
7765
|
}
|
|
7227
|
-
|
|
7228
|
-
|
|
7229
|
-
|
|
7230
|
-
|
|
7231
|
-
changedFiles: files,
|
|
7232
|
-
checks,
|
|
7233
|
-
detail: `${failures.length} of ${checks.length} current verification ${checks.length === 1 ? "check" : "checks"} failed.`
|
|
7234
|
-
};
|
|
7766
|
+
};
|
|
7767
|
+
function classifyToolFailure(result, fallback = "execution") {
|
|
7768
|
+
if (result.metadata?.failureClass && isFailureClass(result.metadata.failureClass)) {
|
|
7769
|
+
return result.metadata.failureClass;
|
|
7235
7770
|
}
|
|
7236
|
-
return
|
|
7237
|
-
|
|
7238
|
-
|
|
7239
|
-
|
|
7240
|
-
|
|
7241
|
-
};
|
|
7242
|
-
}
|
|
7243
|
-
function completionRecoveryDirective(completion) {
|
|
7244
|
-
if (completion.status === "verification_failed") {
|
|
7245
|
-
const failed = completion.checks.filter((check) => !check.ok).map((check) => `- ${check.command} (tool call ${check.toolCallId})`).join("\n");
|
|
7246
|
-
return `<runtime-completion-gate status="verification_failed" authorization="none">
|
|
7247
|
-
The run cannot be marked complete because current verification failed:
|
|
7248
|
-
${failed}
|
|
7249
|
-
Inspect the recorded tool output, correct the underlying problem, and rerun the smallest relevant check. Do not repeat the final summary or claim success without a new successful tool result. If the failure cannot be resolved safely, state the exact blocker and leave the result unverified.
|
|
7250
|
-
</runtime-completion-gate>`;
|
|
7771
|
+
if (result.metadata?.aborted === true) return "cancelled";
|
|
7772
|
+
if (result.metadata?.timedOut === true) return "timeout";
|
|
7773
|
+
if (result.metadata?.hookError) return "hook";
|
|
7774
|
+
if (typeof result.metadata?.exitCode === "number" && result.metadata.exitCode !== 0) {
|
|
7775
|
+
return "command_exit";
|
|
7251
7776
|
}
|
|
7252
|
-
|
|
7253
|
-
return `<runtime-completion-gate status="unverified" authorization="none">
|
|
7254
|
-
${changeSummary}
|
|
7255
|
-
Run the smallest relevant test, typecheck, lint, build, or git diff --check now. Do not repeat the final summary or claim a check passed without a successful tool result. If verification cannot be run safely, state the exact reason and leave the result unverified.
|
|
7256
|
-
</runtime-completion-gate>`;
|
|
7777
|
+
return fallback;
|
|
7257
7778
|
}
|
|
7258
|
-
function
|
|
7259
|
-
|
|
7260
|
-
const segments = normalized.split(/\s*(?:&&|\|\||;)\s*/u).filter(Boolean);
|
|
7261
|
-
if (segments.length > 1) {
|
|
7262
|
-
const kinds = segments.map(classifySingleVerificationCommand);
|
|
7263
|
-
if (kinds.every((kind) => kind !== void 0)) {
|
|
7264
|
-
return kinds.every((kind) => kind === kinds[0]) ? kinds[0] : "check";
|
|
7265
|
-
}
|
|
7266
|
-
return void 0;
|
|
7267
|
-
}
|
|
7268
|
-
return classifySingleVerificationCommand(normalized);
|
|
7779
|
+
function formatFailureReceipt(receipt) {
|
|
7780
|
+
return `Failure: ${receipt.class}; attempt ${receipt.attempt}; ${receipt.remaining} retries remain; circuit ${receipt.circuitOpen ? "open" : "closed"}. Repair: ${receipt.repairHint}`;
|
|
7269
7781
|
}
|
|
7270
|
-
function
|
|
7271
|
-
|
|
7272
|
-
if (/^git\s+diff\b.*(?:^|\s)--check(?:\s|$)/u.test(value)) return "diff";
|
|
7273
|
-
if (/^(?:npm|pnpm|yarn|bun)\s+(?:run\s+)?(?:test(?::[^\s]+)?|test|vitest|jest)(?:\s|$)/u.test(value) || /^(?:npx|pnpx|bunx)\s+(?:vitest|jest)(?:\s|$)/u.test(value) || /^(?:python(?:\d+(?:\.\d+)*)?\s+-m\s+)?pytest(?:\s|$)/u.test(value) || /^(?:cargo|go|dotnet|mvn|mvnw|gradle|gradlew)\s+(?:test|verify)(?:\s|$)/u.test(value) || /^(?:make|just|task)\s+(?:test|verify)(?:\s|$)/u.test(value) || /^node\s+--test(?:\s|$)/u.test(value)) return "test";
|
|
7274
|
-
if (/^(?:npm|pnpm|yarn|bun)\s+(?:run\s+)?(?:typecheck|type-check|check:types)(?:\s|$)/u.test(value) || /^(?:npx|pnpx|bunx)\s+(?:tsc|pyright|mypy)(?:\s|$)/u.test(value) || /^(?:tsc|pyright|mypy)(?:\s|$)/u.test(value) || /^cargo\s+check(?:\s|$)/u.test(value)) return "typecheck";
|
|
7275
|
-
if (/^(?:npm|pnpm|yarn|bun)\s+(?:run\s+)?lint(?:\s|$)/u.test(value) || /^(?:npx|pnpx|bunx)\s+(?:eslint|biome|ruff)(?:\s|$)/u.test(value) || /^(?:eslint|biome\s+check|ruff\s+check|cargo\s+clippy)(?:\s|$)/u.test(value)) return "lint";
|
|
7276
|
-
if (/^(?:npm|pnpm|yarn|bun)\s+(?:run\s+)?(?:build|compile)(?:\s|$)/u.test(value) || /^(?:cargo|go|dotnet|mvn|mvnw|gradle|gradlew)\s+build(?:\s|$)/u.test(value) || /^(?:make|just|task)\s+(?:build|compile)(?:\s|$)/u.test(value)) return "build";
|
|
7277
|
-
if (/^(?:npm|pnpm|yarn|bun)\s+(?:run\s+)?check(?:\s|$)/u.test(value) || /^(?:make|just|task|gradle|gradlew)\s+check(?:\s|$)/u.test(value)) return "check";
|
|
7278
|
-
return void 0;
|
|
7782
|
+
function isRetryable(failureClass) {
|
|
7783
|
+
return RETRY_BUDGET[failureClass] > 0;
|
|
7279
7784
|
}
|
|
7280
|
-
function
|
|
7281
|
-
return {
|
|
7282
|
-
toolCallId: item.toolCallId,
|
|
7283
|
-
tool: item.tool,
|
|
7284
|
-
command: item.command,
|
|
7285
|
-
kind: item.kind,
|
|
7286
|
-
ok: item.ok
|
|
7287
|
-
};
|
|
7785
|
+
function callSignature(call) {
|
|
7786
|
+
return createHash10("sha256").update(`${call.name}\0${stableJson(redact(call.arguments))}`).digest("hex");
|
|
7288
7787
|
}
|
|
7289
|
-
function
|
|
7290
|
-
return
|
|
7788
|
+
function failureSignature(call, failureClass) {
|
|
7789
|
+
return createHash10("sha256").update(`${call.name}\0${stableJson(redact(call.arguments))}\0${failureClass}`).digest("hex");
|
|
7291
7790
|
}
|
|
7292
|
-
function
|
|
7293
|
-
|
|
7791
|
+
function redact(value, key = "") {
|
|
7792
|
+
if (/api[_-]?key|authorization|cookie|password|secret|token/i.test(key)) return "[redacted]";
|
|
7793
|
+
if (Array.isArray(value)) return value.map((item) => redact(item));
|
|
7794
|
+
if (value && typeof value === "object") {
|
|
7795
|
+
return Object.fromEntries(Object.entries(value).sort(([left], [right]) => left.localeCompare(right)).map(([name, item]) => [name, redact(item, name)]));
|
|
7796
|
+
}
|
|
7797
|
+
return value;
|
|
7294
7798
|
}
|
|
7295
|
-
function
|
|
7296
|
-
return
|
|
7799
|
+
function stableJson(value) {
|
|
7800
|
+
return JSON.stringify(value) ?? String(value);
|
|
7801
|
+
}
|
|
7802
|
+
function isFailureClass(value) {
|
|
7803
|
+
return typeof value === "string" && Object.hasOwn(RETRY_BUDGET, value);
|
|
7297
7804
|
}
|
|
7298
7805
|
|
|
7299
7806
|
// src/agent/rules.ts
|
|
@@ -7538,6 +8045,8 @@ var AgentRunner = class {
|
|
|
7538
8045
|
const changeSequenceAtStart = this.changeSequence;
|
|
7539
8046
|
const runChangedFiles = /* @__PURE__ */ new Set();
|
|
7540
8047
|
const verificationEvidence = [];
|
|
8048
|
+
const toolRecovery = new ToolRecoveryController();
|
|
8049
|
+
let activeRunContract = this.session.taskContract;
|
|
7541
8050
|
let mutationTracking = "complete";
|
|
7542
8051
|
let completionRecoveryAttempted = false;
|
|
7543
8052
|
const recordExecution = (call, result) => {
|
|
@@ -7556,12 +8065,21 @@ var AgentRunner = class {
|
|
|
7556
8065
|
);
|
|
7557
8066
|
if (evidence) verificationEvidence.push(evidence);
|
|
7558
8067
|
};
|
|
7559
|
-
const completionReport = () =>
|
|
7560
|
-
|
|
7561
|
-
|
|
7562
|
-
|
|
7563
|
-
|
|
7564
|
-
|
|
8068
|
+
const completionReport = () => {
|
|
8069
|
+
const completion = buildRunCompletion(
|
|
8070
|
+
runChangedFiles,
|
|
8071
|
+
verificationEvidence,
|
|
8072
|
+
this.changeSequence,
|
|
8073
|
+
mutationTracking,
|
|
8074
|
+
activeRunContract,
|
|
8075
|
+
this.session.audit ?? []
|
|
8076
|
+
);
|
|
8077
|
+
if (completion.acceptance && activeRunContract && activeRunContract.state !== "draft") {
|
|
8078
|
+
activeRunContract.state = completion.acceptance.state;
|
|
8079
|
+
activeRunContract.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
8080
|
+
}
|
|
8081
|
+
return completion;
|
|
8082
|
+
};
|
|
7565
8083
|
const finishRun = async (reason, completion = completionReport()) => {
|
|
7566
8084
|
this.session.lastRun = {
|
|
7567
8085
|
...completion,
|
|
@@ -7569,6 +8087,10 @@ var AgentRunner = class {
|
|
|
7569
8087
|
finishedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
7570
8088
|
};
|
|
7571
8089
|
await this.persist();
|
|
8090
|
+
const finalContract = activeRunContract && structuredClone(activeRunContract);
|
|
8091
|
+
if (finalContract && finalContract.state !== "satisfied") {
|
|
8092
|
+
await emit({ type: "contract", contract: finalContract });
|
|
8093
|
+
}
|
|
7572
8094
|
await emit({ type: "done", reason, completion });
|
|
7573
8095
|
return this.session;
|
|
7574
8096
|
};
|
|
@@ -7613,10 +8135,22 @@ var AgentRunner = class {
|
|
|
7613
8135
|
const turnDirective = buildTurnDirective(request, {
|
|
7614
8136
|
agents: Boolean(this.config.agents?.enabled)
|
|
7615
8137
|
});
|
|
8138
|
+
const contractEnabled = shouldUseTaskContract(
|
|
8139
|
+
request,
|
|
8140
|
+
turnDirective.intent,
|
|
8141
|
+
this.session.taskContract
|
|
8142
|
+
);
|
|
8143
|
+
if (contractEnabled && (!this.session.taskContract || this.session.taskContract.state === "satisfied")) {
|
|
8144
|
+
this.session.taskContract = createDraftTaskContract(request, this.session.audit?.at(-1)?.id);
|
|
8145
|
+
await this.persist();
|
|
8146
|
+
await emit({ type: "contract", contract: structuredClone(this.session.taskContract) });
|
|
8147
|
+
}
|
|
8148
|
+
activeRunContract = contractEnabled ? this.session.taskContract : void 0;
|
|
7616
8149
|
const promptSections = [
|
|
7617
8150
|
`intent:${turnDirective.intent}`,
|
|
7618
8151
|
...workspaceRules ? ["rules"] : [],
|
|
7619
8152
|
...this.session.workingMemory ? ["working-memory"] : [],
|
|
8153
|
+
...contractEnabled ? ["task-contract"] : [],
|
|
7620
8154
|
...this.session.contextSummary ? ["session-summary"] : [],
|
|
7621
8155
|
...!trivialTurn ? [`context:${packed.engine}`] : [],
|
|
7622
8156
|
...packed.text ? [`code:${packed.engine}`] : [],
|
|
@@ -7669,7 +8203,7 @@ var AgentRunner = class {
|
|
|
7669
8203
|
);
|
|
7670
8204
|
const availableTokens = this.config.agent.maxSessionTokens - (this.session.usage.inputTokens + this.session.usage.outputTokens);
|
|
7671
8205
|
const estimatedInputTokens = estimateMessages2(messages) + estimateToolDefinitions(
|
|
7672
|
-
|
|
8206
|
+
visibleToolDefinitions(this.tools, options.askMode === true, contractEnabled)
|
|
7673
8207
|
);
|
|
7674
8208
|
if (availableTokens <= 0 || estimatedInputTokens >= availableTokens) {
|
|
7675
8209
|
return finishRun("token_budget");
|
|
@@ -7678,8 +8212,8 @@ var AgentRunner = class {
|
|
|
7678
8212
|
this.config.model.maxTokens ?? 8192,
|
|
7679
8213
|
availableTokens - estimatedInputTokens
|
|
7680
8214
|
));
|
|
7681
|
-
const visibleTools =
|
|
7682
|
-
const assistantId =
|
|
8215
|
+
const visibleTools = visibleToolDefinitions(this.tools, options.askMode === true, contractEnabled);
|
|
8216
|
+
const assistantId = randomUUID12();
|
|
7683
8217
|
const response = await this.completeModel(
|
|
7684
8218
|
messages,
|
|
7685
8219
|
visibleTools,
|
|
@@ -7722,9 +8256,17 @@ var AgentRunner = class {
|
|
|
7722
8256
|
return finishRun("token_budget");
|
|
7723
8257
|
}
|
|
7724
8258
|
if (response.toolCalls.length) {
|
|
8259
|
+
const visibleToolNames = new Set(visibleTools.map((tool) => tool.name));
|
|
7725
8260
|
for (const call of response.toolCalls) {
|
|
7726
8261
|
throwIfAborted(options.signal);
|
|
7727
|
-
const result = await this.executeTool(
|
|
8262
|
+
const result = await this.executeTool(
|
|
8263
|
+
call,
|
|
8264
|
+
options,
|
|
8265
|
+
emit,
|
|
8266
|
+
toolRecovery,
|
|
8267
|
+
visibleToolNames
|
|
8268
|
+
);
|
|
8269
|
+
if (call.name === "task_contract") activeRunContract = this.session.taskContract;
|
|
7728
8270
|
recordExecution(call, result);
|
|
7729
8271
|
this.session.messages.push(message("tool", result.content, {
|
|
7730
8272
|
toolCallId: result.toolCallId,
|
|
@@ -7753,8 +8295,11 @@ Review these results, correct any failures if needed, then provide the final ans
|
|
|
7753
8295
|
continue;
|
|
7754
8296
|
}
|
|
7755
8297
|
const completion = completionReport();
|
|
7756
|
-
if (this.config.agent.autoVerify && (completion.status === "unverified" || completion.status === "verification_failed") && !completionRecoveryAttempted && turn < maxTurns) {
|
|
8298
|
+
if ((this.config.agent.autoVerify || Boolean(completion.acceptance)) && (completion.status === "unverified" || completion.status === "verification_failed") && !completionRecoveryAttempted && turn < maxTurns) {
|
|
7757
8299
|
completionRecoveryAttempted = true;
|
|
8300
|
+
if (activeRunContract) {
|
|
8301
|
+
await emit({ type: "contract", contract: structuredClone(activeRunContract) });
|
|
8302
|
+
}
|
|
7758
8303
|
this.session.messages.push(message("user", completionRecoveryDirective(completion)));
|
|
7759
8304
|
await this.persist();
|
|
7760
8305
|
await this.runAfterTurnHook(turn, [], options.signal);
|
|
@@ -7822,10 +8367,29 @@ ${input2}`
|
|
|
7822
8367
|
if (final) return final;
|
|
7823
8368
|
return { content, toolCalls: [] };
|
|
7824
8369
|
}
|
|
7825
|
-
async executeTool(call, options, emit) {
|
|
8370
|
+
async executeTool(call, options, emit, recovery = new ToolRecoveryController(), visibleToolNames) {
|
|
8371
|
+
const preflight = recovery.preflight(call);
|
|
8372
|
+
if (preflight) {
|
|
8373
|
+
const result = failedResult(call, "Tool call rejected by the recovery circuit.", preflight);
|
|
8374
|
+
this.recordToolResult(result);
|
|
8375
|
+
await emit({ type: "tool_result", result });
|
|
8376
|
+
return result;
|
|
8377
|
+
}
|
|
8378
|
+
if (visibleToolNames && !visibleToolNames.has(call.name)) {
|
|
8379
|
+
const receipt = recovery.recordFailure(call, "unknown_tool");
|
|
8380
|
+
const result = failedResult(
|
|
8381
|
+
call,
|
|
8382
|
+
`Tool is not exposed for this turn: ${call.name}`,
|
|
8383
|
+
receipt
|
|
8384
|
+
);
|
|
8385
|
+
this.recordToolResult(result);
|
|
8386
|
+
await emit({ type: "tool_result", result });
|
|
8387
|
+
return result;
|
|
8388
|
+
}
|
|
7826
8389
|
const tool = this.tools.get(call.name);
|
|
7827
8390
|
if (!tool) {
|
|
7828
|
-
const
|
|
8391
|
+
const receipt = recovery.recordFailure(call, "unknown_tool");
|
|
8392
|
+
const result = failedResult(call, `Unknown tool: ${call.name}`, receipt);
|
|
7829
8393
|
this.recordToolResult(result);
|
|
7830
8394
|
await emit({ type: "tool_result", result });
|
|
7831
8395
|
return result;
|
|
@@ -7836,7 +8400,20 @@ ${input2}`
|
|
|
7836
8400
|
tool.permissionCategories?.(call.arguments) ?? [tool.definition.category]
|
|
7837
8401
|
);
|
|
7838
8402
|
} catch (error) {
|
|
7839
|
-
const
|
|
8403
|
+
const failureClass = classifyThrownToolFailure(error, options.signal);
|
|
8404
|
+
const receipt = recovery.recordFailure(call, failureClass);
|
|
8405
|
+
const result = failedResult(call, formatToolError(error), receipt);
|
|
8406
|
+
this.recordToolResult(result, tool.definition.category);
|
|
8407
|
+
await emit({ type: "tool_result", result });
|
|
8408
|
+
return result;
|
|
8409
|
+
}
|
|
8410
|
+
if (categories.some((category) => category !== "read") && this.session.taskContract?.state === "draft") {
|
|
8411
|
+
const receipt = recovery.recordFailure(call, "contract_required");
|
|
8412
|
+
const result = failedResult(
|
|
8413
|
+
call,
|
|
8414
|
+
"Potentially mutating work is paused until the draft Task Contract is activated.",
|
|
8415
|
+
receipt
|
|
8416
|
+
);
|
|
7840
8417
|
this.recordToolResult(result, tool.definition.category);
|
|
7841
8418
|
await emit({ type: "tool_result", result });
|
|
7842
8419
|
return result;
|
|
@@ -7844,7 +8421,8 @@ ${input2}`
|
|
|
7844
8421
|
for (const category of categories) {
|
|
7845
8422
|
const allowed = await this.authorize(call, category, options, emit);
|
|
7846
8423
|
if (!allowed) {
|
|
7847
|
-
const
|
|
8424
|
+
const receipt = recovery.recordFailure(call, "permission_denied");
|
|
8425
|
+
const result = failedResult(call, `Permission denied for ${category} operation.`, receipt);
|
|
7848
8426
|
this.recordToolResult(result, category);
|
|
7849
8427
|
await emit({ type: "tool_result", result });
|
|
7850
8428
|
return result;
|
|
@@ -7906,15 +8484,30 @@ Tool succeeded, but afterTool hook failed: ${afterHookError.message}` : executio
|
|
|
7906
8484
|
...afterHookError ? { toolSucceeded: true, hookError: afterHookError.message } : {}
|
|
7907
8485
|
}
|
|
7908
8486
|
};
|
|
8487
|
+
if (!result.ok) {
|
|
8488
|
+
const failureClass = options.signal?.aborted ? "cancelled" : classifyToolFailure(result);
|
|
8489
|
+
const receipt = recovery.recordFailure(call, failureClass);
|
|
8490
|
+
result.content = truncateToolOutput(`${formatFailureReceipt(receipt)}
|
|
8491
|
+
${result.content}`);
|
|
8492
|
+
result.metadata = { ...result.metadata, failure: receipt };
|
|
8493
|
+
} else {
|
|
8494
|
+
recovery.recordSuccess(call);
|
|
8495
|
+
}
|
|
7909
8496
|
this.contextManager.recordTool(this.session, call, result);
|
|
7910
8497
|
if (JSON.stringify(this.session.tasks) !== tasksBefore || call.name === "task") {
|
|
7911
8498
|
await emit({ type: "tasks", tasks: this.session.tasks.map((task) => ({ ...task })) });
|
|
7912
8499
|
}
|
|
8500
|
+
if (call.name === "task_contract" && this.session.taskContract) {
|
|
8501
|
+
await emit({ type: "contract", contract: structuredClone(this.session.taskContract) });
|
|
8502
|
+
}
|
|
7913
8503
|
this.recordToolResult(result, tool.definition.category);
|
|
7914
8504
|
await emit({ type: "tool_result", result });
|
|
7915
8505
|
return result;
|
|
7916
8506
|
} catch (error) {
|
|
7917
|
-
const
|
|
8507
|
+
const normalized = toError(error);
|
|
8508
|
+
const failureClass = classifyThrownToolFailure(normalized, options.signal);
|
|
8509
|
+
const receipt = recovery.recordFailure(call, failureClass);
|
|
8510
|
+
const result = failedResult(call, formatToolError(error), receipt);
|
|
7918
8511
|
this.recordToolResult(result, tool.definition.category);
|
|
7919
8512
|
await emit({ type: "tool_result", result });
|
|
7920
8513
|
return result;
|
|
@@ -7983,7 +8576,7 @@ Tool succeeded, but afterTool hook failed: ${afterHookError.message}` : executio
|
|
|
7983
8576
|
}
|
|
7984
8577
|
appendAudit(event) {
|
|
7985
8578
|
const audit = this.session.audit ?? (this.session.audit = []);
|
|
7986
|
-
audit.push({ id:
|
|
8579
|
+
audit.push({ id: randomUUID12(), createdAt: (/* @__PURE__ */ new Date()).toISOString(), ...event });
|
|
7987
8580
|
if (audit.length > 5e3) audit.splice(0, audit.length - 5e3);
|
|
7988
8581
|
}
|
|
7989
8582
|
async acceptChangedFiles(paths) {
|
|
@@ -8004,7 +8597,7 @@ Tool succeeded, but afterTool hook failed: ${afterHookError.message}` : executio
|
|
|
8004
8597
|
const results = [];
|
|
8005
8598
|
for (const command2 of this.config.agent.verifyCommands) {
|
|
8006
8599
|
const call = {
|
|
8007
|
-
id: `verify-${
|
|
8600
|
+
id: `verify-${randomUUID12()}`,
|
|
8008
8601
|
name: "shell",
|
|
8009
8602
|
arguments: { command: command2, cwd: this.workspace.primaryRoot }
|
|
8010
8603
|
};
|
|
@@ -8071,7 +8664,7 @@ Tool succeeded, but afterTool hook failed: ${afterHookError.message}` : executio
|
|
|
8071
8664
|
};
|
|
8072
8665
|
function message(role, content, extra = {}) {
|
|
8073
8666
|
return {
|
|
8074
|
-
id:
|
|
8667
|
+
id: randomUUID12(),
|
|
8075
8668
|
role,
|
|
8076
8669
|
content,
|
|
8077
8670
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -8142,14 +8735,21 @@ function estimateResponseTokens(response) {
|
|
|
8142
8735
|
function uniqueCategories(categories) {
|
|
8143
8736
|
return [...new Set(categories)];
|
|
8144
8737
|
}
|
|
8145
|
-
function failedResult(call, content) {
|
|
8738
|
+
function failedResult(call, content, failure) {
|
|
8146
8739
|
return {
|
|
8147
8740
|
toolCallId: call.id,
|
|
8148
8741
|
name: call.name,
|
|
8149
8742
|
ok: false,
|
|
8150
|
-
content: truncateToolOutput(
|
|
8743
|
+
content: truncateToolOutput(failure ? `${formatFailureReceipt(failure)}
|
|
8744
|
+
${content}` : content),
|
|
8745
|
+
...failure ? { metadata: { failure } } : {}
|
|
8151
8746
|
};
|
|
8152
8747
|
}
|
|
8748
|
+
function visibleToolDefinitions(tools, askMode, contractEnabled) {
|
|
8749
|
+
return tools.definitions().filter(
|
|
8750
|
+
(tool) => (!askMode || tool.category === "read") && (contractEnabled || tool.name !== "task_contract")
|
|
8751
|
+
);
|
|
8752
|
+
}
|
|
8153
8753
|
function truncateToolOutput(content) {
|
|
8154
8754
|
const max = 8e4;
|
|
8155
8755
|
return content.length <= max ? content : `${content.slice(0, max)}
|
|
@@ -8160,6 +8760,13 @@ function formatToolError(error) {
|
|
|
8160
8760
|
if (normalized.name === "ZodError") return `Invalid tool arguments: ${normalized.message}`;
|
|
8161
8761
|
return normalized.message;
|
|
8162
8762
|
}
|
|
8763
|
+
function classifyThrownToolFailure(error, signal) {
|
|
8764
|
+
const normalized = toError(error);
|
|
8765
|
+
if (isAbortError(normalized) || signal?.aborted) return "cancelled";
|
|
8766
|
+
if (normalized.name === "HookError") return "hook";
|
|
8767
|
+
if (normalized.name === "ZodError" || normalized.name === "ToolInputError") return "schema_input";
|
|
8768
|
+
return "execution";
|
|
8769
|
+
}
|
|
8163
8770
|
function titleFromInput(input2) {
|
|
8164
8771
|
return input2.trim().replace(/\s+/g, " ").slice(0, 80) || "New session";
|
|
8165
8772
|
}
|
|
@@ -8335,9 +8942,9 @@ function integer(value, fallback, min, max) {
|
|
|
8335
8942
|
}
|
|
8336
8943
|
|
|
8337
8944
|
// src/agent/delegation.ts
|
|
8338
|
-
import { randomUUID as
|
|
8945
|
+
import { randomUUID as randomUUID14 } from "node:crypto";
|
|
8339
8946
|
import { join as join17 } from "node:path";
|
|
8340
|
-
import { z as
|
|
8947
|
+
import { z as z16 } from "zod";
|
|
8341
8948
|
|
|
8342
8949
|
// src/agent/external-runtime.ts
|
|
8343
8950
|
async function runExternalAgent(request) {
|
|
@@ -8464,86 +9071,86 @@ function numeric(...values) {
|
|
|
8464
9071
|
}
|
|
8465
9072
|
|
|
8466
9073
|
// src/agent/team-store.ts
|
|
8467
|
-
import { createHash as
|
|
9074
|
+
import { createHash as createHash11, randomUUID as randomUUID13 } from "node:crypto";
|
|
8468
9075
|
import { lstat as lstat17, readFile as readFile14, readdir as readdir6, rm as rm2 } from "node:fs/promises";
|
|
8469
9076
|
import { join as join15, resolve as resolve15 } from "node:path";
|
|
8470
|
-
import { z as
|
|
8471
|
-
var runIdSchema =
|
|
8472
|
-
var hashSchema =
|
|
8473
|
-
var artifactSchema =
|
|
9077
|
+
import { z as z15 } from "zod";
|
|
9078
|
+
var runIdSchema = z15.string().uuid();
|
|
9079
|
+
var hashSchema = z15.string().regex(/^[a-f0-9]{64}$/u);
|
|
9080
|
+
var artifactSchema = z15.object({
|
|
8474
9081
|
sha256: hashSchema,
|
|
8475
|
-
bytes:
|
|
9082
|
+
bytes: z15.number().int().nonnegative().max(5e5)
|
|
8476
9083
|
}).strict();
|
|
8477
|
-
var phaseSchema =
|
|
8478
|
-
var agentRecordSchema =
|
|
8479
|
-
id:
|
|
8480
|
-
profile:
|
|
8481
|
-
provider:
|
|
8482
|
-
model:
|
|
9084
|
+
var phaseSchema = z15.enum(["work", "review", "revision", "write"]);
|
|
9085
|
+
var agentRecordSchema = z15.object({
|
|
9086
|
+
id: z15.string().uuid(),
|
|
9087
|
+
profile: z15.string(),
|
|
9088
|
+
provider: z15.string(),
|
|
9089
|
+
model: z15.string(),
|
|
8483
9090
|
phase: phaseSchema,
|
|
8484
|
-
ok:
|
|
8485
|
-
createdAt:
|
|
8486
|
-
startedAt:
|
|
8487
|
-
endedAt:
|
|
8488
|
-
durationMs:
|
|
8489
|
-
toolCalls:
|
|
8490
|
-
usage:
|
|
8491
|
-
inputTokens:
|
|
8492
|
-
outputTokens:
|
|
9091
|
+
ok: z15.boolean(),
|
|
9092
|
+
createdAt: z15.string(),
|
|
9093
|
+
startedAt: z15.string().optional(),
|
|
9094
|
+
endedAt: z15.string().optional(),
|
|
9095
|
+
durationMs: z15.number().int().nonnegative().optional(),
|
|
9096
|
+
toolCalls: z15.number().int().nonnegative().optional(),
|
|
9097
|
+
usage: z15.object({
|
|
9098
|
+
inputTokens: z15.number().int().nonnegative(),
|
|
9099
|
+
outputTokens: z15.number().int().nonnegative()
|
|
8493
9100
|
}).strict().optional(),
|
|
8494
9101
|
report: artifactSchema
|
|
8495
9102
|
}).strict();
|
|
8496
|
-
var messageRecordSchema =
|
|
8497
|
-
id:
|
|
8498
|
-
from:
|
|
8499
|
-
to:
|
|
8500
|
-
createdAt:
|
|
9103
|
+
var messageRecordSchema = z15.object({
|
|
9104
|
+
id: z15.string().uuid(),
|
|
9105
|
+
from: z15.string(),
|
|
9106
|
+
to: z15.string(),
|
|
9107
|
+
createdAt: z15.string(),
|
|
8501
9108
|
content: artifactSchema
|
|
8502
9109
|
}).strict();
|
|
8503
|
-
var writerIntegrationSchema =
|
|
8504
|
-
status:
|
|
8505
|
-
checkedAt:
|
|
8506
|
-
detail:
|
|
8507
|
-
checkpoint:
|
|
8508
|
-
sessionId:
|
|
8509
|
-
checkpointId:
|
|
9110
|
+
var writerIntegrationSchema = z15.object({
|
|
9111
|
+
status: z15.enum(["ready", "conflict", "integrated"]),
|
|
9112
|
+
checkedAt: z15.string(),
|
|
9113
|
+
detail: z15.string().max(2e4),
|
|
9114
|
+
checkpoint: z15.object({
|
|
9115
|
+
sessionId: z15.string(),
|
|
9116
|
+
checkpointId: z15.string()
|
|
8510
9117
|
}).strict().optional(),
|
|
8511
|
-
integratedAt:
|
|
9118
|
+
integratedAt: z15.string().optional()
|
|
8512
9119
|
}).strict();
|
|
8513
|
-
var writerLaneSchema =
|
|
8514
|
-
profile:
|
|
8515
|
-
reviewer:
|
|
8516
|
-
baseCommit:
|
|
8517
|
-
outcome:
|
|
9120
|
+
var writerLaneSchema = z15.object({
|
|
9121
|
+
profile: z15.string(),
|
|
9122
|
+
reviewer: z15.string(),
|
|
9123
|
+
baseCommit: z15.string().regex(/^[a-f0-9]{40,64}$/u),
|
|
9124
|
+
outcome: z15.enum(["accepted", "rejected", "failed", "cancelled"]),
|
|
8518
9125
|
patch: artifactSchema,
|
|
8519
|
-
files:
|
|
8520
|
-
worktreeCleaned:
|
|
9126
|
+
files: z15.array(z15.string().min(1).max(4e3)).max(2e3),
|
|
9127
|
+
worktreeCleaned: z15.boolean(),
|
|
8521
9128
|
review: artifactSchema.optional(),
|
|
8522
9129
|
integration: writerIntegrationSchema.optional()
|
|
8523
9130
|
}).strict();
|
|
8524
9131
|
var manifestFields = {
|
|
8525
9132
|
id: runIdSchema,
|
|
8526
|
-
workspace:
|
|
8527
|
-
objective:
|
|
8528
|
-
reviewer:
|
|
8529
|
-
createdAt:
|
|
8530
|
-
updatedAt:
|
|
8531
|
-
status:
|
|
8532
|
-
maxReviewRounds:
|
|
8533
|
-
reviewRounds:
|
|
8534
|
-
agents:
|
|
8535
|
-
messages:
|
|
9133
|
+
workspace: z15.string(),
|
|
9134
|
+
objective: z15.string().max(3e4),
|
|
9135
|
+
reviewer: z15.string(),
|
|
9136
|
+
createdAt: z15.string(),
|
|
9137
|
+
updatedAt: z15.string(),
|
|
9138
|
+
status: z15.enum(["running", "accepted", "rejected", "failed"]),
|
|
9139
|
+
maxReviewRounds: z15.number().int().min(0).max(3),
|
|
9140
|
+
reviewRounds: z15.number().int().min(0).max(3),
|
|
9141
|
+
agents: z15.array(agentRecordSchema).max(256),
|
|
9142
|
+
messages: z15.array(messageRecordSchema).max(512)
|
|
8536
9143
|
};
|
|
8537
|
-
var manifestV1Schema =
|
|
8538
|
-
version:
|
|
9144
|
+
var manifestV1Schema = z15.object({
|
|
9145
|
+
version: z15.literal(1),
|
|
8539
9146
|
...manifestFields
|
|
8540
9147
|
}).strict();
|
|
8541
|
-
var manifestV2Schema =
|
|
8542
|
-
version:
|
|
9148
|
+
var manifestV2Schema = z15.object({
|
|
9149
|
+
version: z15.literal(2),
|
|
8543
9150
|
...manifestFields,
|
|
8544
9151
|
writer: writerLaneSchema.optional()
|
|
8545
9152
|
}).strict();
|
|
8546
|
-
var manifestSchema2 =
|
|
9153
|
+
var manifestSchema2 = z15.discriminatedUnion("version", [manifestV1Schema, manifestV2Schema]);
|
|
8547
9154
|
var TeamRunStore = class {
|
|
8548
9155
|
workspace;
|
|
8549
9156
|
directory;
|
|
@@ -8558,7 +9165,7 @@ var TeamRunStore = class {
|
|
|
8558
9165
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
8559
9166
|
const manifest = manifestSchema2.parse({
|
|
8560
9167
|
version: 2,
|
|
8561
|
-
id:
|
|
9168
|
+
id: randomUUID13(),
|
|
8562
9169
|
workspace: this.workspace,
|
|
8563
9170
|
objective: input2.objective,
|
|
8564
9171
|
reviewer: input2.reviewer,
|
|
@@ -8722,7 +9329,7 @@ var TeamRunStore = class {
|
|
|
8722
9329
|
async writeArtifact(runId, content, truncate = true) {
|
|
8723
9330
|
const data = boundedArtifactText(content, 5e5, truncate);
|
|
8724
9331
|
const bytes = Buffer.byteLength(data);
|
|
8725
|
-
const sha256 =
|
|
9332
|
+
const sha256 = createHash11("sha256").update(data).digest("hex");
|
|
8726
9333
|
const directory = join15(this.runDirectory(runId), "blobs");
|
|
8727
9334
|
await ensureWorkspaceStorageDirectory(this.workspace, directory, {
|
|
8728
9335
|
requireActiveNamespace: this.managedDirectory
|
|
@@ -8731,7 +9338,7 @@ var TeamRunStore = class {
|
|
|
8731
9338
|
try {
|
|
8732
9339
|
await this.assertRegularFile(path);
|
|
8733
9340
|
const existing = await readFile14(path);
|
|
8734
|
-
if (
|
|
9341
|
+
if (createHash11("sha256").update(existing).digest("hex") !== sha256) {
|
|
8735
9342
|
throw new Error(`Team artifact hash collision or corruption: ${sha256}`);
|
|
8736
9343
|
}
|
|
8737
9344
|
} catch (error) {
|
|
@@ -8752,7 +9359,7 @@ var TeamRunStore = class {
|
|
|
8752
9359
|
const path = this.artifactPath(runId, artifact.sha256);
|
|
8753
9360
|
await this.assertRegularFile(path);
|
|
8754
9361
|
const data = await readFile14(path);
|
|
8755
|
-
const hash =
|
|
9362
|
+
const hash = createHash11("sha256").update(data).digest("hex");
|
|
8756
9363
|
if (hash !== artifact.sha256 || data.byteLength !== artifact.bytes) {
|
|
8757
9364
|
throw new Error(`Team artifact integrity check failed: ${artifact.sha256}`);
|
|
8758
9365
|
}
|
|
@@ -8815,7 +9422,7 @@ function resolveAgentModelRoute(team, parent, profile) {
|
|
|
8815
9422
|
}
|
|
8816
9423
|
|
|
8817
9424
|
// src/agent/writer-lane.ts
|
|
8818
|
-
import { createHash as
|
|
9425
|
+
import { createHash as createHash12 } from "node:crypto";
|
|
8819
9426
|
import { lstat as lstat18, mkdtemp, realpath as realpath7, rm as rm3 } from "node:fs/promises";
|
|
8820
9427
|
import { tmpdir as tmpdir2 } from "node:os";
|
|
8821
9428
|
import { isAbsolute as isAbsolute5, join as join16, resolve as resolve16 } from "node:path";
|
|
@@ -8913,7 +9520,7 @@ var WriterLane = class {
|
|
|
8913
9520
|
return {
|
|
8914
9521
|
baseCommit,
|
|
8915
9522
|
patch,
|
|
8916
|
-
patchSha256:
|
|
9523
|
+
patchSha256: createHash12("sha256").update(patch).digest("hex"),
|
|
8917
9524
|
files,
|
|
8918
9525
|
worktreeCleaned,
|
|
8919
9526
|
value
|
|
@@ -9143,14 +9750,14 @@ async function pathExists2(path) {
|
|
|
9143
9750
|
}
|
|
9144
9751
|
|
|
9145
9752
|
// src/agent/delegation.ts
|
|
9146
|
-
var writerRunInputSchema =
|
|
9147
|
-
task:
|
|
9148
|
-
profile:
|
|
9149
|
-
reviewer:
|
|
9753
|
+
var writerRunInputSchema = z16.object({
|
|
9754
|
+
task: z16.string().min(1).max(2e4),
|
|
9755
|
+
profile: z16.string().max(64).optional(),
|
|
9756
|
+
reviewer: z16.string().max(64).optional()
|
|
9150
9757
|
}).strict();
|
|
9151
|
-
var writerIntegrateInputSchema =
|
|
9152
|
-
run_id:
|
|
9153
|
-
patch_sha256:
|
|
9758
|
+
var writerIntegrateInputSchema = z16.object({
|
|
9759
|
+
run_id: z16.string().uuid(),
|
|
9760
|
+
patch_sha256: z16.string().regex(/^[a-f0-9]{64}$/u)
|
|
9154
9761
|
}).strict();
|
|
9155
9762
|
var DelegationManager = class {
|
|
9156
9763
|
constructor(options) {
|
|
@@ -9211,10 +9818,10 @@ var DelegationManager = class {
|
|
|
9211
9818
|
},
|
|
9212
9819
|
async execute(arguments_, context) {
|
|
9213
9820
|
if (!manager.team.enabled) return { ok: false, content: "Multi-agent delegation is disabled." };
|
|
9214
|
-
const input2 =
|
|
9215
|
-
tasks:
|
|
9216
|
-
profile:
|
|
9217
|
-
task:
|
|
9821
|
+
const input2 = z16.object({
|
|
9822
|
+
tasks: z16.array(z16.object({
|
|
9823
|
+
profile: z16.string().max(64).optional(),
|
|
9824
|
+
task: z16.string().min(1).max(2e4)
|
|
9218
9825
|
})).min(1).max(manager.team.maxDelegations)
|
|
9219
9826
|
}).parse(arguments_);
|
|
9220
9827
|
const tasks = input2.tasks.map((task) => ({
|
|
@@ -9260,13 +9867,13 @@ var DelegationManager = class {
|
|
|
9260
9867
|
},
|
|
9261
9868
|
async execute(arguments_, context) {
|
|
9262
9869
|
if (!manager.team.enabled) return { ok: false, content: "Multi-agent teams are disabled." };
|
|
9263
|
-
const input2 =
|
|
9264
|
-
objective:
|
|
9265
|
-
tasks:
|
|
9266
|
-
profile:
|
|
9267
|
-
task:
|
|
9870
|
+
const input2 = z16.object({
|
|
9871
|
+
objective: z16.string().min(1).max(3e4),
|
|
9872
|
+
tasks: z16.array(z16.object({
|
|
9873
|
+
profile: z16.string().max(64).optional(),
|
|
9874
|
+
task: z16.string().min(1).max(2e4)
|
|
9268
9875
|
})).min(1).max(manager.team.maxDelegations),
|
|
9269
|
-
reviewer:
|
|
9876
|
+
reviewer: z16.string().max(64).optional()
|
|
9270
9877
|
}).parse(arguments_);
|
|
9271
9878
|
const tasks = input2.tasks.map((task) => ({
|
|
9272
9879
|
profile: task.profile ?? manager.team.defaultProfile,
|
|
@@ -9364,7 +9971,7 @@ var DelegationManager = class {
|
|
|
9364
9971
|
maxReviewRounds: 0
|
|
9365
9972
|
});
|
|
9366
9973
|
await emit?.({ type: "team_start", id: board.id, objective: task });
|
|
9367
|
-
const writerId =
|
|
9974
|
+
const writerId = randomUUID14();
|
|
9368
9975
|
await emit?.({ type: "agent_queued", id: writerId, profile: profile.name, task, phase: "write" });
|
|
9369
9976
|
const draft = await this.writerLane.createDraft(
|
|
9370
9977
|
Math.min(this.team.maxWriterPatchBytes ?? 6e4, 12e4),
|
|
@@ -9734,7 +10341,7 @@ You are the only writer inside a disposable worktree. Make only the bounded requ
|
|
|
9734
10341
|
const reviewer = reviewerOverride ?? this.team.reviewerProfile ?? "reviewer";
|
|
9735
10342
|
const rounds = Math.max(0, this.team.maxReviewRounds ?? 1);
|
|
9736
10343
|
const board = await this.teamStore?.create({ objective, reviewer, maxReviewRounds: rounds });
|
|
9737
|
-
const runId = board?.id ??
|
|
10344
|
+
const runId = board?.id ?? randomUUID14();
|
|
9738
10345
|
await emit?.({ type: "team_start", id: runId, objective });
|
|
9739
10346
|
try {
|
|
9740
10347
|
let results = await this.runBatch(board?.id, tasks, "work", emit, signal);
|
|
@@ -9792,7 +10399,7 @@ ${review.summary}`,
|
|
|
9792
10399
|
}
|
|
9793
10400
|
}
|
|
9794
10401
|
async runBatch(runId, tasks, phase, emit, signal) {
|
|
9795
|
-
const scheduled = tasks.map((task) => ({ id:
|
|
10402
|
+
const scheduled = tasks.map((task) => ({ id: randomUUID14(), task }));
|
|
9796
10403
|
for (const item of scheduled) {
|
|
9797
10404
|
await emit?.({ type: "agent_queued", id: item.id, profile: item.task.profile, task: item.task.task, phase });
|
|
9798
10405
|
}
|
|
@@ -9901,12 +10508,12 @@ Start the response with exactly VERDICT: ACCEPT when the evidence is sufficient,
|
|
|
9901
10508
|
});
|
|
9902
10509
|
}
|
|
9903
10510
|
async peerMessage(runId, from, to, content, emit) {
|
|
9904
|
-
const id =
|
|
10511
|
+
const id = randomUUID14();
|
|
9905
10512
|
if (runId) await this.teamStore?.recordMessage(runId, { id, from, to, content });
|
|
9906
10513
|
await emit?.({ type: "agent_message", id, from, to, content });
|
|
9907
10514
|
}
|
|
9908
10515
|
async runOne(task, phase, emit, signal, retryOf, scheduledId) {
|
|
9909
|
-
const id = scheduledId ??
|
|
10516
|
+
const id = scheduledId ?? randomUUID14();
|
|
9910
10517
|
const profile = this.options.profiles.get(task.profile);
|
|
9911
10518
|
const configuredRoute = this.team.routes?.[task.profile];
|
|
9912
10519
|
const budgetMode = configuredRoute?.budgetMode ?? this.team.budgetMode ?? "observe";
|
|
@@ -10818,11 +11425,11 @@ ${this.glyphs.meta} ${session.changedFiles.length} changed files ${this.glyphs.s
|
|
|
10818
11425
|
`);
|
|
10819
11426
|
}
|
|
10820
11427
|
printText(event) {
|
|
10821
|
-
const { quiet, compact } = this.options;
|
|
11428
|
+
const { quiet, compact: compact2 } = this.options;
|
|
10822
11429
|
if (quiet) return;
|
|
10823
11430
|
switch (event.type) {
|
|
10824
11431
|
case "thinking":
|
|
10825
|
-
if (!
|
|
11432
|
+
if (!compact2) process.stderr.write(this.paint.dim(`${this.glyphs.meta} reasoning ${this.glyphs.separator} turn ${event.turn}
|
|
10826
11433
|
`));
|
|
10827
11434
|
break;
|
|
10828
11435
|
case "context":
|
|
@@ -10832,7 +11439,7 @@ ${this.glyphs.meta} ${session.changedFiles.length} changed files ${this.glyphs.s
|
|
|
10832
11439
|
));
|
|
10833
11440
|
break;
|
|
10834
11441
|
case "prompt":
|
|
10835
|
-
if (!
|
|
11442
|
+
if (!compact2) {
|
|
10836
11443
|
process.stderr.write(this.paint.dim(
|
|
10837
11444
|
`${this.glyphs.meta} prompt ${this.glyphs.separator} ${event.intent} ${this.glyphs.separator} ${event.sections.join(" + ")} ${this.glyphs.separator} ~${event.estimatedTokens} tokens
|
|
10838
11445
|
`
|
|
@@ -10867,12 +11474,21 @@ ${this.glyphs.meta} ${session.changedFiles.length} changed files ${this.glyphs.s
|
|
|
10867
11474
|
}
|
|
10868
11475
|
break;
|
|
10869
11476
|
case "tasks":
|
|
10870
|
-
if (!
|
|
11477
|
+
if (!compact2) {
|
|
10871
11478
|
const completed = event.tasks.filter((task) => task.status === "completed").length;
|
|
10872
11479
|
process.stderr.write(this.paint.dim(`${this.glyphs.meta} plan ${this.glyphs.separator} ${completed}/${event.tasks.length} complete
|
|
10873
11480
|
`));
|
|
10874
11481
|
}
|
|
10875
11482
|
break;
|
|
11483
|
+
case "contract": {
|
|
11484
|
+
const required = event.contract.acceptanceCriteria.filter((item) => item.required);
|
|
11485
|
+
const satisfied = required.filter((item) => item.status === "satisfied").length;
|
|
11486
|
+
process.stderr.write(this.paint.dim(
|
|
11487
|
+
`${this.glyphs.meta} contract ${this.glyphs.separator} ${event.contract.state} ${this.glyphs.separator} ${satisfied}/${required.length} accepted
|
|
11488
|
+
`
|
|
11489
|
+
));
|
|
11490
|
+
break;
|
|
11491
|
+
}
|
|
10876
11492
|
case "writer_lane":
|
|
10877
11493
|
process.stderr.write(
|
|
10878
11494
|
`${event.status === "ready" || event.status === "integrated" ? this.paint.green(this.glyphs.success) : this.paint.red(this.glyphs.error)} writer ${event.id.slice(0, 8)} ${this.glyphs.separator} ${event.status} ${this.glyphs.separator} ${event.detail}
|
|
@@ -10954,6 +11570,7 @@ function sessionSummary(session) {
|
|
|
10954
11570
|
createdAt: session.createdAt,
|
|
10955
11571
|
updatedAt: session.updatedAt,
|
|
10956
11572
|
tasks: session.tasks,
|
|
11573
|
+
...session.taskContract ? { taskContract: session.taskContract } : {},
|
|
10957
11574
|
changedFiles: session.changedFiles,
|
|
10958
11575
|
...session.lastRun ? { lastRun: session.lastRun } : {},
|
|
10959
11576
|
usage: session.usage
|
|
@@ -11644,7 +12261,7 @@ function ToolGlyph({ state, glyphs }) {
|
|
|
11644
12261
|
if (state === "cancelled") return /* @__PURE__ */ jsx(Text, { color: theme.warning, children: glyphs.warning });
|
|
11645
12262
|
return /* @__PURE__ */ jsx(Text, { color: theme.error, children: glyphs.error });
|
|
11646
12263
|
}
|
|
11647
|
-
function Timeline({ items, width = 80, glyphMode = "auto", showToolOutput = false, expandedToolId, compact = false }) {
|
|
12264
|
+
function Timeline({ items, width = 80, glyphMode = "auto", showToolOutput = false, expandedToolId, compact: compact2 = false }) {
|
|
11648
12265
|
const theme = useTheme();
|
|
11649
12266
|
const glyphs = resolveGlyphs(glyphMode);
|
|
11650
12267
|
if (!items.length) {
|
|
@@ -11652,13 +12269,13 @@ function Timeline({ items, width = 80, glyphMode = "auto", showToolOutput = fals
|
|
|
11652
12269
|
}
|
|
11653
12270
|
return /* @__PURE__ */ jsx(Box, { flexDirection: "column", children: items.map((item, index) => {
|
|
11654
12271
|
if (item.kind === "user") {
|
|
11655
|
-
return /* @__PURE__ */ jsxs(Box, { marginBottom:
|
|
12272
|
+
return /* @__PURE__ */ jsxs(Box, { marginBottom: compact2 || item.clipped ? 0 : 1, children: [
|
|
11656
12273
|
/* @__PURE__ */ jsx(Box, { width: 2, children: /* @__PURE__ */ jsx(Text, { bold: true, color: theme.accent, children: glyphs.prompt }) }),
|
|
11657
12274
|
/* @__PURE__ */ jsx(Text, { bold: true, color: theme.textStrong, wrap: "wrap", children: sanitizeTerminalText(item.text) })
|
|
11658
12275
|
] }, item.id);
|
|
11659
12276
|
}
|
|
11660
12277
|
if (item.kind === "assistant") {
|
|
11661
|
-
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginBottom:
|
|
12278
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginBottom: compact2 || item.clipped ? 0 : 1, children: [
|
|
11662
12279
|
/* @__PURE__ */ jsxs(Text, { bold: true, color: theme.accent, children: [
|
|
11663
12280
|
glyphs.brand,
|
|
11664
12281
|
" ",
|
|
@@ -11674,7 +12291,7 @@ function Timeline({ items, width = 80, glyphMode = "auto", showToolOutput = fals
|
|
|
11674
12291
|
}
|
|
11675
12292
|
if (item.kind === "context") {
|
|
11676
12293
|
const spans = item.spans ?? [];
|
|
11677
|
-
const spanLimit =
|
|
12294
|
+
const spanLimit = compact2 ? 2 : 3;
|
|
11678
12295
|
const innerWidth = Math.max(1, safeWidth(width) - 2);
|
|
11679
12296
|
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
|
|
11680
12297
|
/* @__PURE__ */ jsx(
|
|
@@ -11725,7 +12342,7 @@ function Timeline({ items, width = 80, glyphMode = "auto", showToolOutput = fals
|
|
|
11725
12342
|
const duration = item.durationMs !== void 0 ? formatDuration(item.durationMs) : "";
|
|
11726
12343
|
const detailText = [detail, duration].filter(Boolean).join(" ");
|
|
11727
12344
|
const expanded = Boolean(item.output) && (showToolOutput || expandedToolId === item.id);
|
|
11728
|
-
const verbose = expanded && item.output ? limitTerminalText(item.output,
|
|
12345
|
+
const verbose = expanded && item.output ? limitTerminalText(item.output, compact2 ? 24 : 80) : void 0;
|
|
11729
12346
|
const disclosure = item.output ? expanded ? glyphs.expanded : glyphs.collapsed : "";
|
|
11730
12347
|
const disclosureWidth = disclosure ? displayWidth(disclosure) + 1 : 0;
|
|
11731
12348
|
const nameLimit = Math.max(1, Math.min(rowWidth - 2 - disclosureWidth, rowWidth < 64 ? rowWidth - 2 - disclosureWidth : 28));
|
|
@@ -11859,7 +12476,7 @@ function Timeline({ items, width = 80, glyphMode = "auto", showToolOutput = fals
|
|
|
11859
12476
|
}
|
|
11860
12477
|
if (item.kind === "list") return /* @__PURE__ */ jsx(ListPanel, { title: item.title, entries: item.entries, width, glyphMode }, item.id);
|
|
11861
12478
|
if (item.kind === "context-inspector") {
|
|
11862
|
-
return /* @__PURE__ */ jsx(ContextInspector, { status: item.status, working: item.working, summary: item.summary, width, compact, glyphMode }, item.id);
|
|
12479
|
+
return /* @__PURE__ */ jsx(ContextInspector, { status: item.status, working: item.working, summary: item.summary, width, compact: compact2, glyphMode }, item.id);
|
|
11863
12480
|
}
|
|
11864
12481
|
if (item.kind === "theme") return /* @__PURE__ */ jsx(ThemePreview, { name: item.name, width, glyphs }, item.id);
|
|
11865
12482
|
if (item.kind === "banner") {
|
|
@@ -11917,15 +12534,18 @@ function WorkspacePanel({ status, width = 36, glyphMode = "auto" }) {
|
|
|
11917
12534
|
const inner = Math.max(8, safeWidth(width) - 4);
|
|
11918
12535
|
const contextLabel = status.context === "empty" ? "ready \xB7 empty workspace" : "ready";
|
|
11919
12536
|
const mcpLabel = status.mcpTotal ? `${status.mcpConnected}/${status.mcpTotal} connected` : "off";
|
|
11920
|
-
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", width, borderStyle: glyphs.borderStyle, borderColor: theme.border, paddingX: 1, children: [
|
|
11921
|
-
/* @__PURE__ */ jsx(Text, { bold: true, color: theme.accent, children: truncateDisplay(`${glyphs.
|
|
11922
|
-
/* @__PURE__ */ jsx(Text, { color:
|
|
11923
|
-
|
|
12537
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", width, height: 13, borderStyle: glyphs.borderStyle, borderColor: theme.border, paddingX: 1, children: [
|
|
12538
|
+
/* @__PURE__ */ jsx(Text, { bold: true, color: theme.accent, children: truncateDisplay(`${glyphs.brand} WORKSPACE`, inner) }),
|
|
12539
|
+
/* @__PURE__ */ jsx(Text, { color: theme.dim, children: truncateDisplay("CONTEXT", inner) }),
|
|
12540
|
+
/* @__PURE__ */ jsx(Text, { color: status.context === "empty" ? theme.warning : theme.success, children: truncateDisplay(`${glyphs.success} local index ${contextLabel}`, inner) }),
|
|
12541
|
+
/* @__PURE__ */ jsx(Text, { color: theme.muted, children: truncateDisplay(`${status.files} files ${glyphs.separator} ${status.chunks} chunks`, inner) }),
|
|
12542
|
+
/* @__PURE__ */ jsx(Text, { color: theme.dim, children: truncateDisplay("RUNTIME", inner) }),
|
|
11924
12543
|
/* @__PURE__ */ jsx(Text, { color: theme.text, children: truncateDisplay(status.model, inner) }),
|
|
11925
12544
|
/* @__PURE__ */ jsx(Text, { color: theme.muted, children: truncateDisplay(`mode ${status.mode.toUpperCase()} ${glyphs.separator} ${status.permissions}`, inner) }),
|
|
12545
|
+
/* @__PURE__ */ jsx(Text, { color: theme.dim, children: truncateDisplay("EXTENSIONS", inner) }),
|
|
11926
12546
|
/* @__PURE__ */ jsx(Text, { color: theme.muted, children: truncateDisplay(`${status.tools} tools ${glyphs.separator} ${status.skills} skills`, inner) }),
|
|
11927
12547
|
/* @__PURE__ */ jsx(Text, { color: theme.muted, children: truncateDisplay(`MCP ${mcpLabel} ${glyphs.separator} memory ${status.memory}`, inner) }),
|
|
11928
|
-
/* @__PURE__ */ jsx(Text, { color: theme.dim, children: truncateDisplay(
|
|
12548
|
+
/* @__PURE__ */ jsx(Text, { color: theme.dim, children: truncateDisplay(`@file pin ${glyphs.separator} /status inspect`, inner) })
|
|
11929
12549
|
] });
|
|
11930
12550
|
}
|
|
11931
12551
|
function TeamWorkbench({ items, tasks, width = 80, glyphMode = "auto", view = "agents", selectedIndex = 0, expanded = false, run, notice }) {
|
|
@@ -12066,7 +12686,7 @@ function TaskRail({ tasks, width = 80, glyphMode = "auto", maxItems }) {
|
|
|
12066
12686
|
] }) : null
|
|
12067
12687
|
] });
|
|
12068
12688
|
}
|
|
12069
|
-
function PermissionCard({ call, category, width = 80, glyphMode = "auto", workspace, compact = false }) {
|
|
12689
|
+
function PermissionCard({ call, category, width = 80, glyphMode = "auto", workspace, compact: compact2 = false }) {
|
|
12070
12690
|
const theme = useTheme();
|
|
12071
12691
|
const glyphs = resolveGlyphs(glyphMode);
|
|
12072
12692
|
const summary = permissionSummary(call);
|
|
@@ -12103,7 +12723,7 @@ function PermissionCard({ call, category, width = 80, glyphMode = "auto", worksp
|
|
|
12103
12723
|
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: [
|
|
12104
12724
|
/* @__PURE__ */ jsx(InlineRow, { parts: shortcuts.slice(0, 2), width: innerWidth, separator: " ", separatorColor: theme.border }),
|
|
12105
12725
|
/* @__PURE__ */ jsx(InlineRow, { parts: shortcuts.slice(2), width: innerWidth, separator: " ", separatorColor: theme.border })
|
|
12106
|
-
] }) :
|
|
12726
|
+
] }) : compact2 ? /* @__PURE__ */ jsxs(Box, { paddingLeft: 2, flexDirection: "column", children: [
|
|
12107
12727
|
/* @__PURE__ */ jsx(InlineRow, { parts: compactNarrowShortcuts.slice(0, 2), width: innerWidth, separator: " ", separatorColor: theme.border }),
|
|
12108
12728
|
/* @__PURE__ */ jsx(InlineRow, { parts: compactNarrowShortcuts.slice(2), width: innerWidth, separator: " ", separatorColor: theme.border })
|
|
12109
12729
|
] }) : /* @__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)) })
|
|
@@ -12364,7 +12984,7 @@ function MeterBar({ segments, total, width, glyphs }) {
|
|
|
12364
12984
|
remainder ? /* @__PURE__ */ jsx(Text, { color: theme.border, children: glyphs.meterEmpty.repeat(remainder) }) : null
|
|
12365
12985
|
] });
|
|
12366
12986
|
}
|
|
12367
|
-
function ContextInspector({ status, working, summary, width, memory, connections, sources: sources2, compact = false, minimal = false, glyphMode = "auto" }) {
|
|
12987
|
+
function ContextInspector({ status, working, summary, width, memory, connections, sources: sources2, compact: compact2 = false, minimal = false, glyphMode = "auto" }) {
|
|
12368
12988
|
const theme = useTheme();
|
|
12369
12989
|
const glyphs = resolveGlyphs(glyphMode);
|
|
12370
12990
|
if (minimal) {
|
|
@@ -12384,10 +13004,10 @@ function ContextInspector({ status, working, summary, width, memory, connections
|
|
|
12384
13004
|
{ label: "summary", detail: summary ? `~${formatTokens(status.summaryTokens)} tokens ${glyphs.separator} ${status.compactedMessages} compacted` : "not created" },
|
|
12385
13005
|
{ label: "long-term", detail: memory ?? `retrieved by relevance ${glyphs.separator} untrusted context` }
|
|
12386
13006
|
];
|
|
12387
|
-
if (!
|
|
12388
|
-
if (!
|
|
12389
|
-
if (!
|
|
12390
|
-
if (!
|
|
13007
|
+
if (!compact2 && working?.constraints.length) entries.push({ label: `constraints ${working.constraints.length}`, detail: working.constraints.slice(0, 2).join(` ${glyphs.separator} `) });
|
|
13008
|
+
if (!compact2 && working?.decisions.length) entries.push({ label: `decisions ${working.decisions.length}`, detail: working.decisions.slice(0, 2).join(` ${glyphs.separator} `) });
|
|
13009
|
+
if (!compact2 && working?.openQuestions.length) entries.push({ label: `open ${working.openQuestions.length}`, detail: working.openQuestions.slice(0, 2).join(` ${glyphs.separator} `), tone: "warning" });
|
|
13010
|
+
if (!compact2 && working?.relevantFiles.length) entries.push({ label: "relevant files", detail: working.relevantFiles.map((file) => compactDisplayPath(sanitizeInlineTerminalText(file), 28)).join(` ${glyphs.separator} `) });
|
|
12391
13011
|
if (sources2?.length) {
|
|
12392
13012
|
const pinned = sources2.filter((source) => source.state === "pinned");
|
|
12393
13013
|
const muted = sources2.filter((source) => source.state === "muted");
|
|
@@ -12466,10 +13086,13 @@ function Banner({ model, engine, workspace, version, width, glyphs }) {
|
|
|
12466
13086
|
const padding = rowWidth >= 24 ? 2 : 0;
|
|
12467
13087
|
const innerWidth = Math.max(1, rowWidth - padding);
|
|
12468
13088
|
const safeEngine = sanitizeInlineTerminalText(engine);
|
|
12469
|
-
const
|
|
12470
|
-
const
|
|
13089
|
+
const expanded = rowWidth >= 48;
|
|
13090
|
+
const ascii = glyphs.brand === "*";
|
|
13091
|
+
const weaveTop = ascii ? "/\\/\\" : "\u2572\u2571\u2572\u2571";
|
|
13092
|
+
const weaveBottom = ascii ? "\\/\\/" : "\u2571\u2572\u2571\u2572";
|
|
13093
|
+
const meta = expanded ? "grounded coding workspace" : rowWidth >= 28 ? `New session ${glyphs.separator} v${version}` : `New ${glyphs.separator} v${version}`;
|
|
13094
|
+
const status = expanded ? `${glyphs.success} ${safeEngine} index verified ${glyphs.separator} ${sanitizeInlineTerminalText(model)} ${glyphs.separator} v${version}` : `cwd ${compactDisplayPath(sanitizeInlineTerminalText(workspace), Math.max(1, innerWidth - 4))}`;
|
|
12471
13095
|
const hint = `context runs automatically ${glyphs.separator} @file pins ${glyphs.separator} /help commands`;
|
|
12472
|
-
const statusWidth = displayWidth(glyphs.success) + 1;
|
|
12473
13096
|
return /* @__PURE__ */ jsxs(
|
|
12474
13097
|
Box,
|
|
12475
13098
|
{
|
|
@@ -12477,15 +13100,27 @@ function Banner({ model, engine, workspace, version, width, glyphs }) {
|
|
|
12477
13100
|
flexDirection: "column",
|
|
12478
13101
|
paddingLeft: padding,
|
|
12479
13102
|
children: [
|
|
12480
|
-
/* @__PURE__ */ jsxs(
|
|
13103
|
+
expanded ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
13104
|
+
/* @__PURE__ */ jsxs(Box, { height: 1, overflowY: "hidden", children: [
|
|
13105
|
+
/* @__PURE__ */ jsx(Text, { bold: true, color: theme.accent, children: weaveTop }),
|
|
13106
|
+
/* @__PURE__ */ jsx(Text, { bold: true, color: theme.textStrong, children: " S K E I N" })
|
|
13107
|
+
] }),
|
|
13108
|
+
/* @__PURE__ */ jsxs(Box, { height: 1, overflowY: "hidden", children: [
|
|
13109
|
+
/* @__PURE__ */ jsx(Text, { bold: true, color: theme.accent, children: weaveBottom }),
|
|
13110
|
+
/* @__PURE__ */ jsxs(Text, { color: theme.muted, children: [
|
|
13111
|
+
" ",
|
|
13112
|
+
truncateDisplay(meta, Math.max(1, innerWidth - displayWidth(weaveBottom) - 2))
|
|
13113
|
+
] })
|
|
13114
|
+
] })
|
|
13115
|
+
] }) : /* @__PURE__ */ jsxs(Box, { height: 1, overflowY: "hidden", children: [
|
|
12481
13116
|
/* @__PURE__ */ jsxs(Text, { bold: true, color: theme.accent, children: [
|
|
12482
13117
|
glyphs.brand,
|
|
12483
13118
|
" "
|
|
12484
13119
|
] }),
|
|
12485
|
-
/* @__PURE__ */ jsx(Text, { bold: true, color: theme.textStrong,
|
|
13120
|
+
/* @__PURE__ */ jsx(Text, { bold: true, color: theme.textStrong, children: truncateDisplay(meta, Math.max(1, innerWidth - displayWidth(glyphs.brand) - 1)) })
|
|
12486
13121
|
] }),
|
|
12487
|
-
/* @__PURE__ */ jsx(Text, { color:
|
|
12488
|
-
|
|
13122
|
+
/* @__PURE__ */ jsx(Text, { color: expanded ? theme.success : theme.muted, children: truncateDisplay(status, innerWidth) }),
|
|
13123
|
+
expanded ? /* @__PURE__ */ jsx(Text, { color: theme.dim, children: truncateDisplay(`${hint} ${glyphs.separator} cwd ${compactDisplayPath(sanitizeInlineTerminalText(workspace), 24)}`, innerWidth) }) : null
|
|
12489
13124
|
]
|
|
12490
13125
|
}
|
|
12491
13126
|
);
|
|
@@ -12493,8 +13128,8 @@ function Banner({ model, engine, workspace, version, width, glyphs }) {
|
|
|
12493
13128
|
function UpdateNotice({ current, latest, command: command2, highlights, width, glyphs }) {
|
|
12494
13129
|
const theme = useTheme();
|
|
12495
13130
|
const availableWidth = safeWidth(width);
|
|
12496
|
-
const
|
|
12497
|
-
const parts =
|
|
13131
|
+
const compact2 = availableWidth < 48;
|
|
13132
|
+
const parts = compact2 ? [
|
|
12498
13133
|
{ text: `${glyphs.up} `, color: theme.accent, bold: true },
|
|
12499
13134
|
{ text: `v${current}`, color: theme.dim, bold: false },
|
|
12500
13135
|
{ text: ` ${glyphs.arrow} `, color: theme.muted, bold: false },
|
|
@@ -12515,7 +13150,7 @@ function UpdateNotice({ current, latest, command: command2, highlights, width, g
|
|
|
12515
13150
|
const bullets = bulletWidth > 0 ? (highlights ?? []).map((line) => truncateDisplay(sanitizeInlineTerminalText(line), bulletWidth)) : [];
|
|
12516
13151
|
return /* @__PURE__ */ jsxs(Box, { marginBottom: 1, flexDirection: "column", children: [
|
|
12517
13152
|
/* @__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)) }),
|
|
12518
|
-
|
|
13153
|
+
compact2 ? /* @__PURE__ */ jsx(Text, { color: theme.dim, children: truncateDisplay(` run ${command2}`, availableWidth) }) : null,
|
|
12519
13154
|
bullets.map((line, index) => /* @__PURE__ */ jsx(Text, { color: theme.dim, children: `${bulletPrefix}${line}` }, index))
|
|
12520
13155
|
] });
|
|
12521
13156
|
}
|
|
@@ -13423,9 +14058,9 @@ function tailText(value, width, maxRows) {
|
|
|
13423
14058
|
return `${marker}
|
|
13424
14059
|
${selected.join("\n")}`;
|
|
13425
14060
|
}
|
|
13426
|
-
function estimateTimelineItemRows(item, { width, compact = false, showToolOutput = false, expandedToolId }) {
|
|
14061
|
+
function estimateTimelineItemRows(item, { width, compact: compact2 = false, showToolOutput = false, expandedToolId }) {
|
|
13427
14062
|
const rowWidth = Math.max(1, Math.floor(width));
|
|
13428
|
-
const gap =
|
|
14063
|
+
const gap = compact2 ? 0 : 1;
|
|
13429
14064
|
if (item.kind === "user") return wrappedRows(item.text, Math.max(1, rowWidth - 2)) + (item.clipped ? 0 : gap);
|
|
13430
14065
|
if (item.kind === "assistant") {
|
|
13431
14066
|
return 1 + richTextRows(item.text, Math.max(1, rowWidth - 2)) + (item.clipped ? 0 : gap);
|
|
@@ -13437,7 +14072,7 @@ function estimateTimelineItemRows(item, { width, compact = false, showToolOutput
|
|
|
13437
14072
|
const detail = item.errorDetail || item.detail;
|
|
13438
14073
|
const detailRows = narrow && detail ? 1 : 0;
|
|
13439
14074
|
const metaRows = item.meta ? 1 : 0;
|
|
13440
|
-
const outputRows = (showToolOutput || item.id === expandedToolId) && item.output ? Math.min(
|
|
14075
|
+
const outputRows = (showToolOutput || item.id === expandedToolId) && item.output ? Math.min(compact2 ? 25 : 81, richTextRows(item.output, Math.max(1, rowWidth - 2))) : 0;
|
|
13441
14076
|
return 1 + detailRows + metaRows + outputRows;
|
|
13442
14077
|
}
|
|
13443
14078
|
if (item.kind === "list") {
|
|
@@ -13451,7 +14086,7 @@ function estimateTimelineItemRows(item, { width, compact = false, showToolOutput
|
|
|
13451
14086
|
if (item.kind === "theme") return 3;
|
|
13452
14087
|
if (item.kind === "context") {
|
|
13453
14088
|
const metaRows = rowWidth < 64 ? 2 : 1;
|
|
13454
|
-
const spanLimit =
|
|
14089
|
+
const spanLimit = compact2 ? 2 : 3;
|
|
13455
14090
|
const spanCount = Math.min(item.spans?.length ?? 0, spanLimit);
|
|
13456
14091
|
const moreRow = (item.spans?.length ?? 0) > spanLimit ? 1 : 0;
|
|
13457
14092
|
const degradationRows = item.degradation ? metaRows : 0;
|
|
@@ -13466,7 +14101,7 @@ function estimateTimelineItemRows(item, { width, compact = false, showToolOutput
|
|
|
13466
14101
|
if (item.kind === "agent" || item.kind === "agent-message") return rowWidth < 64 ? 2 : 1;
|
|
13467
14102
|
if (item.kind === "workflow") return rowWidth < 64 ? 2 : 1;
|
|
13468
14103
|
if (item.kind === "banner") {
|
|
13469
|
-
return rowWidth >= 48 ?
|
|
14104
|
+
return rowWidth >= 48 ? 5 : 3;
|
|
13470
14105
|
}
|
|
13471
14106
|
return 1;
|
|
13472
14107
|
}
|
|
@@ -13549,6 +14184,21 @@ function finalizeAssistant(items, id, content) {
|
|
|
13549
14184
|
function endStreamingAssistants(items) {
|
|
13550
14185
|
return items.map((item) => item.kind === "assistant" && item.streaming ? { ...item, streaming: false } : item);
|
|
13551
14186
|
}
|
|
14187
|
+
function updateContractProgress(items, contract, separator = " | ") {
|
|
14188
|
+
const id = "task-contract-progress";
|
|
14189
|
+
if (contract.state === "satisfied") return items.filter((item) => item.id !== id);
|
|
14190
|
+
const required = contract.acceptanceCriteria.filter((item) => item.required);
|
|
14191
|
+
const satisfied = required.filter((item) => item.status === "satisfied").length;
|
|
14192
|
+
const next = {
|
|
14193
|
+
id,
|
|
14194
|
+
kind: "notice",
|
|
14195
|
+
tone: contract.state === "blocked" ? "error" : "info",
|
|
14196
|
+
text: `Contract ${contract.state}${separator}${satisfied}/${required.length} accepted`
|
|
14197
|
+
};
|
|
14198
|
+
const index = items.findIndex((item) => item.id === id);
|
|
14199
|
+
if (index < 0) return [...items, next].slice(-500);
|
|
14200
|
+
return items.map((item, itemIndex) => itemIndex === index ? next : item);
|
|
14201
|
+
}
|
|
13552
14202
|
function updateAgent(items, event) {
|
|
13553
14203
|
const found = items.some((item) => item.kind === "agent" && item.id === event.id);
|
|
13554
14204
|
if (!found) {
|
|
@@ -13641,7 +14291,7 @@ function SkeinApp({ runner, config, extensions, initialPrompt, askMode = false,
|
|
|
13641
14291
|
const colorEnabled = config.ui.color && !process.env.NO_COLOR;
|
|
13642
14292
|
const [theme, setTheme] = useState2(() => resolveThemeWithColor(config.ui.theme, colorEnabled));
|
|
13643
14293
|
const [themeCatalogRevision, setThemeCatalogRevision] = useState2(0);
|
|
13644
|
-
const [
|
|
14294
|
+
const [compact2, setCompact] = useState2(config.ui.compact);
|
|
13645
14295
|
const [interactionMode, setInteractionMode] = useState2(planMode ? "plan" : askMode ? "ask" : "build");
|
|
13646
14296
|
const [input2, setInput] = useState2("");
|
|
13647
14297
|
const [busy, setBusy] = useState2(false);
|
|
@@ -13841,6 +14491,11 @@ function SkeinApp({ runner, config, extensions, initialPrompt, askMode = false,
|
|
|
13841
14491
|
case "tasks":
|
|
13842
14492
|
setTasks(event.tasks.map((task) => ({ ...task })));
|
|
13843
14493
|
break;
|
|
14494
|
+
case "contract": {
|
|
14495
|
+
setTimeline((items) => updateContractProgress(items, event.contract, separator));
|
|
14496
|
+
refreshSession();
|
|
14497
|
+
break;
|
|
14498
|
+
}
|
|
13844
14499
|
case "skill":
|
|
13845
14500
|
append({ id: nextId(), kind: "skill", name: event.name, description: event.description });
|
|
13846
14501
|
break;
|
|
@@ -14333,7 +14988,7 @@ function SkeinApp({ runner, config, extensions, initialPrompt, askMode = false,
|
|
|
14333
14988
|
}
|
|
14334
14989
|
if (command2 === "density") {
|
|
14335
14990
|
const normalized = argument.toLocaleLowerCase();
|
|
14336
|
-
const next = normalized === "compact" ? true : normalized === "comfortable" || normalized === "normal" ? false : normalized === "" || normalized === "toggle" ? !
|
|
14991
|
+
const next = normalized === "compact" ? true : normalized === "comfortable" || normalized === "normal" ? false : normalized === "" || normalized === "toggle" ? !compact2 : void 0;
|
|
14337
14992
|
if (next === void 0) throw new Error("Usage: /density [compact|comfortable]");
|
|
14338
14993
|
setCompact(next);
|
|
14339
14994
|
await saveUiPreference({ compact: next });
|
|
@@ -14426,7 +15081,7 @@ function SkeinApp({ runner, config, extensions, initialPrompt, askMode = false,
|
|
|
14426
15081
|
})));
|
|
14427
15082
|
return true;
|
|
14428
15083
|
}
|
|
14429
|
-
}, [append, appendList,
|
|
15084
|
+
}, [append, appendList, compact2, config, ellipsis, exit, extensions, interactionMode, refreshSession, requestPermission, runner, separator, showToolOutput, tasks, theme, workflows]);
|
|
14430
15085
|
const submit = useCallback(async (raw, mode = "normal") => {
|
|
14431
15086
|
const trimmed = raw.trim();
|
|
14432
15087
|
if (!trimmed) return;
|
|
@@ -14790,7 +15445,7 @@ function SkeinApp({ runner, config, extensions, initialPrompt, askMode = false,
|
|
|
14790
15445
|
const tokenTotal = session.usage.inputTokens + session.usage.outputTokens;
|
|
14791
15446
|
const contextStatus = runner.getContextStatus();
|
|
14792
15447
|
const frame = spinnerFrames()[frameIndex % spinnerFrames().length];
|
|
14793
|
-
const compactUi =
|
|
15448
|
+
const compactUi = compact2 || terminalHeight < 28;
|
|
14794
15449
|
const constrainedHeight = terminalHeight < 18;
|
|
14795
15450
|
const compactComposer = terminalHeight < 18;
|
|
14796
15451
|
const minimalInspector = terminalHeight < 22;
|
|
@@ -14818,7 +15473,7 @@ function SkeinApp({ runner, config, extensions, initialPrompt, askMode = false,
|
|
|
14818
15473
|
const chromeRows = headerRows + composerRows + footerRows + taskRows + paletteRows + inspectorRows + activityRows;
|
|
14819
15474
|
const availableTimelineRows = Math.max(0, terminalHeight - chromeRows);
|
|
14820
15475
|
const teamItems = timeline.filter((item) => item.kind === "agent" || item.kind === "agent-message");
|
|
14821
|
-
const showWorkspacePanel = Boolean(workspaceReadiness) && contentWidth >=
|
|
15476
|
+
const showWorkspacePanel = Boolean(workspaceReadiness) && contentWidth >= 88 && terminalHeight >= 20 && !teamWorkbenchOpen && !teamItems.some((item) => item.kind === "agent");
|
|
14822
15477
|
const workspacePanelWidth = showWorkspacePanel ? Math.min(38, Math.max(32, Math.floor(contentWidth * 0.34))) : 0;
|
|
14823
15478
|
const workspaceTimelineWidth = Math.max(1, contentWidth - workspacePanelWidth - (showWorkspacePanel ? 1 : 0));
|
|
14824
15479
|
const timelineContentRows = timeline.reduce((rows2, item) => rows2 + estimateTimelineItemRows(item, {
|
|
@@ -14828,7 +15483,7 @@ function SkeinApp({ runner, config, extensions, initialPrompt, askMode = false,
|
|
|
14828
15483
|
showToolOutput,
|
|
14829
15484
|
...expandedToolId ? { expandedToolId } : {}
|
|
14830
15485
|
}), 0);
|
|
14831
|
-
const timelineRows = teamWorkbenchOpen ? availableTimelineRows : Math.min(availableTimelineRows, Math.max(timelineContentRows, showWorkspacePanel ?
|
|
15486
|
+
const timelineRows = teamWorkbenchOpen ? availableTimelineRows : Math.min(availableTimelineRows, Math.max(timelineContentRows, showWorkspacePanel ? 13 : 0));
|
|
14832
15487
|
const showTeamCockpit = config.agents?.cockpit !== false && contentWidth >= 100 && timelineRows >= 7 && teamItems.some((item) => item.kind === "agent");
|
|
14833
15488
|
const cockpitWidth = showTeamCockpit ? Math.min(38, Math.max(30, Math.floor(contentWidth * 0.32))) : workspacePanelWidth;
|
|
14834
15489
|
const hasSidePanel = showTeamCockpit || showWorkspacePanel;
|
|
@@ -14996,6 +15651,16 @@ function initialTimeline(session, banner, setupProblem) {
|
|
|
14996
15651
|
if (!items.length) {
|
|
14997
15652
|
items.push({ id: nextId(), kind: "banner", model: banner.model, engine: banner.engine, workspace: banner.workspace, version: banner.version });
|
|
14998
15653
|
}
|
|
15654
|
+
if (session.taskContract && session.taskContract.state !== "satisfied") {
|
|
15655
|
+
const required = session.taskContract.acceptanceCriteria.filter((item) => item.required);
|
|
15656
|
+
const satisfied = required.filter((item) => item.status === "satisfied").length;
|
|
15657
|
+
items.push({
|
|
15658
|
+
id: "task-contract-progress",
|
|
15659
|
+
kind: "notice",
|
|
15660
|
+
tone: session.taskContract.state === "blocked" ? "error" : "info",
|
|
15661
|
+
text: `Contract ${session.taskContract.state} | ${satisfied}/${required.length} accepted`
|
|
15662
|
+
});
|
|
15663
|
+
}
|
|
14999
15664
|
if (setupProblem && items.length <= 1) items.push({ id: nextId(), kind: "notice", tone: "error", text: setupProblem });
|
|
15000
15665
|
return items;
|
|
15001
15666
|
}
|
|
@@ -15087,17 +15752,17 @@ function composerAttachments(value) {
|
|
|
15087
15752
|
const paths = [...value.matchAll(/(?:^|\s)@([^\s]+)/g)].map((match) => match[1]).filter((path) => Boolean(path));
|
|
15088
15753
|
return [...new Set(paths)].slice(-3);
|
|
15089
15754
|
}
|
|
15090
|
-
function permissionRows(width, hasCwd,
|
|
15755
|
+
function permissionRows(width, hasCwd, compact2) {
|
|
15091
15756
|
const content = 3 + (hasCwd ? 1 : 0);
|
|
15092
15757
|
if (width >= 64) return content + 2;
|
|
15093
15758
|
if (width >= 28) return content + 3;
|
|
15094
|
-
if (
|
|
15759
|
+
if (compact2) return content + 3;
|
|
15095
15760
|
return content + 5;
|
|
15096
15761
|
}
|
|
15097
|
-
function contextInspectorRows(session,
|
|
15762
|
+
function contextInspectorRows(session, compact2, width, minimal) {
|
|
15098
15763
|
if (minimal) return 2;
|
|
15099
15764
|
const working = session.workingMemory;
|
|
15100
|
-
const entries = 5 + (
|
|
15765
|
+
const entries = 5 + (compact2 ? 0 : (working?.constraints.length ? 1 : 0) + (working?.decisions.length ? 1 : 0) + (working?.openQuestions.length ? 1 : 0) + (working?.relevantFiles.length ? 1 : 0));
|
|
15101
15766
|
return 2 + entries * (width < 52 ? 2 : 1);
|
|
15102
15767
|
}
|
|
15103
15768
|
function contextInspectorStatus(status) {
|
|
@@ -15143,46 +15808,99 @@ function WorkspacePreparationView({
|
|
|
15143
15808
|
workspace,
|
|
15144
15809
|
model,
|
|
15145
15810
|
width,
|
|
15811
|
+
height = 24,
|
|
15146
15812
|
frame = 0
|
|
15147
15813
|
}) {
|
|
15148
15814
|
const theme = useTheme();
|
|
15149
15815
|
const safeWidth2 = Math.max(1, Math.floor(width));
|
|
15150
15816
|
const innerWidth = Math.max(1, safeWidth2 - (safeWidth2 >= 24 ? 4 : 0));
|
|
15151
|
-
const
|
|
15817
|
+
const compact2 = safeWidth2 < 48;
|
|
15818
|
+
const constrained = height < 14;
|
|
15152
15819
|
const ascii = process.env.SKEIN_GLYPHS === "ascii" || process.env.MOSAIC_GLYPHS === "ascii";
|
|
15153
15820
|
const spinner = (ascii ? [".", "o", "O", "o"] : ["\u25DC", "\u25E0", "\u25DD", "\u25DE", "\u25E1", "\u25DF"])[frame % (ascii ? 4 : 6)];
|
|
15154
15821
|
const separator = ascii ? "|" : "\xB7";
|
|
15155
15822
|
const brand = ascii ? "*" : PRODUCT_MARK;
|
|
15156
15823
|
const phase = readiness ? "ready" : error ? "error" : progress.phase;
|
|
15157
|
-
const
|
|
15158
|
-
const phaseLabel = preparationLabel(phase, progress, readiness, compact);
|
|
15824
|
+
const phaseLabel = preparationLabel(phase, progress, readiness, compact2);
|
|
15159
15825
|
const detail = preparationDetail(phase, progress, readiness, error);
|
|
15160
15826
|
const modelLine = `model ${sanitizeTerminalText(model)}`;
|
|
15161
15827
|
const workspaceLine = `workspace ${compactDisplayPath(sanitizeTerminalText(workspace), Math.max(1, innerWidth - 10))}`;
|
|
15162
|
-
const steps =
|
|
15163
|
-
const currentIndex = readiness ? steps.length : phase === "validate" ? 2 : phase === "scan" || phase === "index" || phase === "write" ? 1 : 0;
|
|
15164
|
-
const tracker = steps.map((step2, index) => {
|
|
15165
|
-
const marker = index < currentIndex ? ascii ? "[x]" : "\u25CF" : index === currentIndex && !error ? ascii ? "[>]" : "\u25C6" : ascii ? "[ ]" : "\u25CB";
|
|
15166
|
-
return `${marker} ${step2}`;
|
|
15167
|
-
}).join(compact ? " " : " ");
|
|
15828
|
+
const steps = preparationSteps(phase, progress, readiness, error, { ascii, spinner });
|
|
15168
15829
|
return /* @__PURE__ */ jsxs4(Box3, { flexDirection: "column", paddingX: safeWidth2 >= 24 ? 2 : 0, children: [
|
|
15169
|
-
/* @__PURE__ */
|
|
15170
|
-
|
|
15830
|
+
/* @__PURE__ */ jsxs4(Box3, { children: [
|
|
15831
|
+
/* @__PURE__ */ jsxs4(Text4, { bold: true, color: theme.accent, children: [
|
|
15832
|
+
brand,
|
|
15833
|
+
" ",
|
|
15834
|
+
PRODUCT_NAME.toUpperCase()
|
|
15835
|
+
] }),
|
|
15836
|
+
!compact2 && !constrained ? /* @__PURE__ */ jsxs4(Text4, { color: theme.dim, children: [
|
|
15837
|
+
" ",
|
|
15838
|
+
separator,
|
|
15839
|
+
" LOCAL CONTEXT"
|
|
15840
|
+
] }) : null
|
|
15841
|
+
] }),
|
|
15842
|
+
!constrained ? /* @__PURE__ */ jsx4(Text4, { color: theme.muted, children: truncateDisplay("Ground the workspace before the first request.", innerWidth) }) : null,
|
|
15843
|
+
!constrained && !compact2 ? /* @__PURE__ */ jsx4(Text4, { color: theme.dim, children: truncateDisplay(`${modelLine} ${separator} ${workspaceLine}`, innerWidth) }) : !constrained ? /* @__PURE__ */ jsxs4(Fragment3, { children: [
|
|
15171
15844
|
/* @__PURE__ */ jsx4(Text4, { color: theme.dim, children: truncateDisplay(modelLine, innerWidth) }),
|
|
15172
15845
|
/* @__PURE__ */ jsx4(Text4, { color: theme.dim, children: truncateDisplay(workspaceLine, innerWidth) })
|
|
15173
|
-
] }),
|
|
15174
|
-
/* @__PURE__ */ jsx4(Box3, { marginTop: 1, children: /* @__PURE__ */
|
|
15846
|
+
] }) : /* @__PURE__ */ jsx4(Text4, { color: theme.dim, children: truncateDisplay(workspaceLine, innerWidth) }),
|
|
15847
|
+
/* @__PURE__ */ jsx4(Box3, { marginTop: 1, flexDirection: constrained ? "row" : "column", children: steps.map((step2) => constrained ? /* @__PURE__ */ jsxs4(Text4, { color: step2.state === "active" ? theme.accent : step2.state === "complete" ? theme.success : step2.state === "error" ? theme.error : theme.dim, children: [
|
|
15848
|
+
step2.glyph,
|
|
15849
|
+
" ",
|
|
15850
|
+
step2.id === "persist" ? "save" : step2.id,
|
|
15851
|
+
step2.id === "verify" ? "" : " "
|
|
15852
|
+
] }, step2.id) : /* @__PURE__ */ jsxs4(Box3, { height: 1, overflowY: "hidden", children: [
|
|
15853
|
+
/* @__PURE__ */ jsxs4(Text4, { bold: true, color: step2.state === "active" ? theme.accent : step2.state === "complete" ? theme.success : step2.state === "error" ? theme.error : theme.border, children: [
|
|
15854
|
+
step2.glyph,
|
|
15855
|
+
" "
|
|
15856
|
+
] }),
|
|
15857
|
+
/* @__PURE__ */ jsx4(Text4, { bold: step2.state === "active", color: step2.state === "pending" ? theme.dim : theme.textStrong, children: truncateDisplay(step2.label, compact2 ? 8 : 10) }),
|
|
15858
|
+
/* @__PURE__ */ jsxs4(Text4, { color: step2.state === "active" ? theme.muted : theme.dim, children: [
|
|
15859
|
+
" ",
|
|
15860
|
+
truncateDisplay(step2.detail, Math.max(1, innerWidth - displayWidth(step2.glyph) - (compact2 ? 12 : 14)))
|
|
15861
|
+
] })
|
|
15862
|
+
] }, step2.id)) }),
|
|
15175
15863
|
/* @__PURE__ */ jsxs4(Box3, { marginTop: 1, children: [
|
|
15176
15864
|
/* @__PURE__ */ jsxs4(Text4, { bold: true, color: error ? theme.error : readiness ? theme.success : theme.accent, children: [
|
|
15177
|
-
|
|
15865
|
+
readiness ? ascii ? "[ok]" : "\u2713" : error ? ascii ? "[x]" : "\xD7" : spinner,
|
|
15178
15866
|
" "
|
|
15179
15867
|
] }),
|
|
15180
|
-
/* @__PURE__ */ jsx4(Text4, { bold: true, color: theme.textStrong, children: truncateDisplay(phaseLabel, Math.max(1, innerWidth -
|
|
15868
|
+
/* @__PURE__ */ jsx4(Text4, { bold: true, color: theme.textStrong, children: truncateDisplay(phaseLabel, Math.max(1, innerWidth - 5)) })
|
|
15181
15869
|
] }),
|
|
15182
15870
|
/* @__PURE__ */ jsx4(Text4, { color: error ? theme.error : theme.muted, wrap: "truncate", children: truncateDisplay(detail, innerWidth) }),
|
|
15183
|
-
error ? /* @__PURE__ */ jsx4(Text4, { color: theme.dim, children: truncateDisplay(`Enter retry ${separator} Esc exit`, innerWidth) }) : null
|
|
15871
|
+
error ? /* @__PURE__ */ jsx4(Text4, { color: theme.dim, children: truncateDisplay(`Enter retry ${separator} Esc exit`, innerWidth) }) : !constrained ? /* @__PURE__ */ jsx4(Text4, { color: theme.dim, children: truncateDisplay(`local only ${separator} no source code uploaded`, innerWidth) }) : null
|
|
15184
15872
|
] });
|
|
15185
15873
|
}
|
|
15874
|
+
function preparationSteps(phase, progress, readiness, error, glyphs) {
|
|
15875
|
+
const runtimePhase = phase === "error" ? progress.phase : phase;
|
|
15876
|
+
const current = runtimePhase === "scan" || runtimePhase === "index" ? "build" : runtimePhase === "write" ? "persist" : runtimePhase === "validate" ? "verify" : "inspect";
|
|
15877
|
+
const order = ["inspect", "build", "persist", "verify"];
|
|
15878
|
+
const currentIndex = phase === "ready" ? order.length : order.indexOf(current);
|
|
15879
|
+
const activeDetail = runtimePhase === "inspect" ? "manifest and workspace boundaries" : runtimePhase === "scan" ? `${progress.total} source files discovered` : runtimePhase === "index" ? `${progress.completed}/${progress.total} source files` : runtimePhase === "write" ? "atomic local index write" : runtimePhase === "validate" ? progress.total ? `${progress.completed}/${progress.total} content hashes` : "generation and content hashes" : "";
|
|
15880
|
+
const readyDetails = {
|
|
15881
|
+
inspect: "workspace boundaries checked",
|
|
15882
|
+
build: readiness?.rebuilt ? `${readiness.files} files \xB7 ${readiness.chunks} chunks` : "existing index is current",
|
|
15883
|
+
persist: readiness?.rebuilt ? "local artifact committed" : "local artifact loaded",
|
|
15884
|
+
verify: "content and generation matched"
|
|
15885
|
+
};
|
|
15886
|
+
const pendingDetails = {
|
|
15887
|
+
inspect: "manifest and workspace boundaries",
|
|
15888
|
+
build: "source files and code chunks",
|
|
15889
|
+
persist: "atomic local index write",
|
|
15890
|
+
verify: "generation and content hashes"
|
|
15891
|
+
};
|
|
15892
|
+
return order.map((id, index) => {
|
|
15893
|
+
const state = error && index === currentIndex ? "error" : index < currentIndex || phase === "ready" ? "complete" : index === currentIndex ? "active" : "pending";
|
|
15894
|
+
const glyph = state === "complete" ? glyphs.ascii ? "[x]" : "\u25CF" : state === "error" ? glyphs.ascii ? "[!]" : "\xD7" : state === "active" ? glyphs.spinner : glyphs.ascii ? "[ ]" : "\u25CB";
|
|
15895
|
+
return {
|
|
15896
|
+
id,
|
|
15897
|
+
label: id === "persist" ? "Persist" : `${id[0]?.toUpperCase()}${id.slice(1)}`,
|
|
15898
|
+
detail: phase === "ready" ? readyDetails[id] : state === "active" || state === "error" ? activeDetail : pendingDetails[id],
|
|
15899
|
+
state,
|
|
15900
|
+
glyph
|
|
15901
|
+
};
|
|
15902
|
+
});
|
|
15903
|
+
}
|
|
15186
15904
|
function WorkspacePreparationApp({
|
|
15187
15905
|
engine,
|
|
15188
15906
|
config,
|
|
@@ -15192,7 +15910,7 @@ function WorkspacePreparationApp({
|
|
|
15192
15910
|
onFinish
|
|
15193
15911
|
}) {
|
|
15194
15912
|
const { exit } = useApp2();
|
|
15195
|
-
const { columns } = useWindowSize2();
|
|
15913
|
+
const { columns, rows } = useWindowSize2();
|
|
15196
15914
|
const [attempt, setAttempt] = useState3(0);
|
|
15197
15915
|
const [frame, setFrame] = useState3(0);
|
|
15198
15916
|
const [progress, setProgress] = useState3({ phase: "inspect", completed: 0, total: 0 });
|
|
@@ -15244,6 +15962,7 @@ function WorkspacePreparationApp({
|
|
|
15244
15962
|
workspace,
|
|
15245
15963
|
model: `${config.model.provider}/${config.model.model}`,
|
|
15246
15964
|
width: Math.max(1, columns || 80),
|
|
15965
|
+
height: Math.max(1, rows || 24),
|
|
15247
15966
|
frame
|
|
15248
15967
|
}
|
|
15249
15968
|
);
|
|
@@ -15279,9 +15998,9 @@ async function runWorkspacePreparation(engine, config, options = {}) {
|
|
|
15279
15998
|
await instance.waitUntilExit();
|
|
15280
15999
|
return result ?? { status: "cancelled" };
|
|
15281
16000
|
}
|
|
15282
|
-
function preparationLabel(phase, progress, readiness,
|
|
16001
|
+
function preparationLabel(phase, progress, readiness, compact2 = false) {
|
|
15283
16002
|
if (phase === "ready") {
|
|
15284
|
-
if (
|
|
16003
|
+
if (compact2) return "Index verified";
|
|
15285
16004
|
return readiness?.rebuilt ? "Workspace index created and verified" : "Workspace index verified";
|
|
15286
16005
|
}
|
|
15287
16006
|
if (phase === "error") return "Workspace preparation failed";
|
|
@@ -15685,7 +16404,7 @@ function OnboardingFlow({ initialConfig, saveConfig, onFinish }) {
|
|
|
15685
16404
|
}, [finish, saveConfig, state]);
|
|
15686
16405
|
return /* @__PURE__ */ jsx5(OnboardingScreen, { state, dispatch, width, compact: compactHeight });
|
|
15687
16406
|
}
|
|
15688
|
-
function OnboardingScreen({ state, dispatch, width, compact = false }) {
|
|
16407
|
+
function OnboardingScreen({ state, dispatch, width, compact: compact2 = false }) {
|
|
15689
16408
|
const theme = useTheme();
|
|
15690
16409
|
const ascii = process.env.SKEIN_GLYPHS === "ascii" || process.env.MOSAIC_GLYPHS === "ascii";
|
|
15691
16410
|
const marker = ascii ? ">" : "\u203A";
|
|
@@ -15702,14 +16421,14 @@ function OnboardingScreen({ state, dispatch, width, compact = false }) {
|
|
|
15702
16421
|
] }),
|
|
15703
16422
|
/* @__PURE__ */ jsx5(Text6, { color: theme.border, children: truncateDisplay(stageDivider(ascii, headerWidth), headerWidth) }),
|
|
15704
16423
|
/* @__PURE__ */ jsx5(Text6, { color: theme.dim, children: truncateDisplay(stage.name, headerWidth) }),
|
|
15705
|
-
!
|
|
16424
|
+
!compact2 ? /* @__PURE__ */ jsx5(Box4, { height: 1 }) : null,
|
|
15706
16425
|
/* @__PURE__ */ jsx5(Text6, { color: theme.textStrong, bold: true, children: truncateDisplay(titleForStep(state.step), headerWidth) }),
|
|
15707
|
-
!
|
|
16426
|
+
!compact2 ? /* @__PURE__ */ jsx5(Text6, { color: theme.muted, wrap: "wrap", children: descriptionForStep(state) }) : null,
|
|
15708
16427
|
summary ? /* @__PURE__ */ jsx5(Text6, { color: theme.dim, children: truncateDisplay(summary, headerWidth) }) : null,
|
|
15709
|
-
!
|
|
15710
|
-
state.step === "method" ? /* @__PURE__ */ jsx5(OptionList, { options: methods, selected: state.selected, marker, width: headerWidth, compact }) : null,
|
|
15711
|
-
state.step === "official-provider" ? /* @__PURE__ */ jsx5(OptionList, { options: officialProviders, selected: state.selected, marker, width: headerWidth, compact }) : null,
|
|
15712
|
-
state.step === "relay-protocol" ? /* @__PURE__ */ jsx5(OptionList, { options: relayProtocols, selected: state.selected, marker, width: headerWidth, compact }) : null,
|
|
16428
|
+
!compact2 ? /* @__PURE__ */ jsx5(Box4, { height: 1 }) : null,
|
|
16429
|
+
state.step === "method" ? /* @__PURE__ */ jsx5(OptionList, { options: methods, selected: state.selected, marker, width: headerWidth, compact: compact2 }) : null,
|
|
16430
|
+
state.step === "official-provider" ? /* @__PURE__ */ jsx5(OptionList, { options: officialProviders, selected: state.selected, marker, width: headerWidth, compact: compact2 }) : null,
|
|
16431
|
+
state.step === "relay-protocol" ? /* @__PURE__ */ jsx5(OptionList, { options: relayProtocols, selected: state.selected, marker, width: headerWidth, compact: compact2 }) : null,
|
|
15713
16432
|
inputField ? /* @__PURE__ */ jsxs5(Box4, { flexDirection: "column", children: [
|
|
15714
16433
|
/* @__PURE__ */ jsxs5(Box4, { children: [
|
|
15715
16434
|
/* @__PURE__ */ jsx5(Text6, { color: theme.textStrong, bold: true, children: inputField.label }),
|
|
@@ -15737,18 +16456,18 @@ function OnboardingScreen({ state, dispatch, width, compact = false }) {
|
|
|
15737
16456
|
"! ",
|
|
15738
16457
|
truncateDisplay(state.error, Math.max(1, headerWidth - 2))
|
|
15739
16458
|
] }) : null,
|
|
15740
|
-
!
|
|
16459
|
+
!compact2 ? /* @__PURE__ */ jsx5(Box4, { height: 1 }) : null,
|
|
15741
16460
|
/* @__PURE__ */ jsx5(Text6, { color: theme.dim, children: footerForStep(state, headerWidth) })
|
|
15742
16461
|
] });
|
|
15743
16462
|
}
|
|
15744
|
-
function OptionList({ options, selected, marker, width, compact }) {
|
|
16463
|
+
function OptionList({ options, selected, marker, width, compact: compact2 }) {
|
|
15745
16464
|
const theme = useTheme();
|
|
15746
16465
|
return /* @__PURE__ */ jsx5(Box4, { flexDirection: "column", children: options.map((option, index) => {
|
|
15747
16466
|
const active = index === selected;
|
|
15748
16467
|
const prefix = active ? `${marker} ` : " ";
|
|
15749
16468
|
const available = Math.max(1, width - displayWidth(prefix) - (active ? 2 : 0));
|
|
15750
16469
|
const label = `${prefix}${truncateDisplay(option.label, available)}`;
|
|
15751
|
-
return /* @__PURE__ */ jsxs5(Box4, { flexDirection: "column", marginBottom:
|
|
16470
|
+
return /* @__PURE__ */ jsxs5(Box4, { flexDirection: "column", marginBottom: compact2 || index === options.length - 1 ? 0 : 1, children: [
|
|
15752
16471
|
/* @__PURE__ */ jsx5(
|
|
15753
16472
|
Text6,
|
|
15754
16473
|
{
|
|
@@ -15758,7 +16477,7 @@ function OptionList({ options, selected, marker, width, compact }) {
|
|
|
15758
16477
|
children: active ? padDisplay(label, width) : label
|
|
15759
16478
|
}
|
|
15760
16479
|
),
|
|
15761
|
-
!
|
|
16480
|
+
!compact2 && 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: option.detail }) }) : null
|
|
15762
16481
|
] }, option.label);
|
|
15763
16482
|
}) });
|
|
15764
16483
|
}
|
|
@@ -15881,7 +16600,7 @@ import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/
|
|
|
15881
16600
|
import stripAnsi4 from "strip-ansi";
|
|
15882
16601
|
|
|
15883
16602
|
// src/mcp/tool.ts
|
|
15884
|
-
import { createHash as
|
|
16603
|
+
import { createHash as createHash13 } from "node:crypto";
|
|
15885
16604
|
import stripAnsi3 from "strip-ansi";
|
|
15886
16605
|
var MAX_ARGUMENT_BYTES = 256e3;
|
|
15887
16606
|
var MAX_DESCRIPTION_LENGTH = 4e3;
|
|
@@ -15889,7 +16608,7 @@ var MAX_RESULT_LENGTH = 8e4;
|
|
|
15889
16608
|
var MAX_SCHEMA_BYTES = 1e5;
|
|
15890
16609
|
function createMcpToolAdapter(options) {
|
|
15891
16610
|
const { remoteTool } = options;
|
|
15892
|
-
const
|
|
16611
|
+
const inputSchema11 = copyInputSchema(remoteTool.inputSchema);
|
|
15893
16612
|
return {
|
|
15894
16613
|
definition: {
|
|
15895
16614
|
name: options.exposedName,
|
|
@@ -15897,7 +16616,7 @@ function createMcpToolAdapter(options) {
|
|
|
15897
16616
|
// MCP servers are an external trust boundary. Read-only annotations are
|
|
15898
16617
|
// hints from that server and must not lower the local permission level.
|
|
15899
16618
|
category: "network",
|
|
15900
|
-
inputSchema:
|
|
16619
|
+
inputSchema: inputSchema11
|
|
15901
16620
|
},
|
|
15902
16621
|
permissionCategories: () => ["network"],
|
|
15903
16622
|
async execute(arguments_, context) {
|
|
@@ -16034,7 +16753,7 @@ function fitToolName(name, identity) {
|
|
|
16034
16753
|
return `${name.slice(0, 64 - suffix.length).replace(/_+$/g, "")}${suffix}`;
|
|
16035
16754
|
}
|
|
16036
16755
|
function shortHash(value) {
|
|
16037
|
-
return
|
|
16756
|
+
return createHash13("sha256").update(value).digest("hex").slice(0, 8);
|
|
16038
16757
|
}
|
|
16039
16758
|
function truncateResult(content) {
|
|
16040
16759
|
if (content.length <= MAX_RESULT_LENGTH) return content;
|
|
@@ -16657,9 +17376,9 @@ async function closeTransportQuietly(transport) {
|
|
|
16657
17376
|
}
|
|
16658
17377
|
|
|
16659
17378
|
// src/memory/tools.ts
|
|
16660
|
-
import { z as
|
|
16661
|
-
var scopeSchema =
|
|
16662
|
-
var kindSchema =
|
|
17379
|
+
import { z as z17 } from "zod";
|
|
17380
|
+
var scopeSchema = z17.enum(["user", "workspace", "session", "agent"]);
|
|
17381
|
+
var kindSchema = z17.enum(["semantic", "episodic", "procedural"]);
|
|
16663
17382
|
function createMemoryTools(store) {
|
|
16664
17383
|
return [
|
|
16665
17384
|
{
|
|
@@ -16674,10 +17393,10 @@ function createMemoryTools(store) {
|
|
|
16674
17393
|
}, ["query"])
|
|
16675
17394
|
},
|
|
16676
17395
|
async execute(arguments_, context) {
|
|
16677
|
-
const input2 =
|
|
16678
|
-
query:
|
|
17396
|
+
const input2 = z17.object({
|
|
17397
|
+
query: z17.string().max(4e3),
|
|
16679
17398
|
scope: scopeSchema.optional(),
|
|
16680
|
-
limit:
|
|
17399
|
+
limit: z17.number().int().min(1).max(20).optional()
|
|
16681
17400
|
}).parse(arguments_);
|
|
16682
17401
|
const scopes = input2.scope ? [{ scope: input2.scope, scopeKey: scopeKey(input2.scope, context) }] : availableScopes(context);
|
|
16683
17402
|
const records = store.search(input2.query, { scopes, limit: input2.limit ?? 8 });
|
|
@@ -16709,17 +17428,17 @@ ${record.content}`
|
|
|
16709
17428
|
}, ["content", "rationale"])
|
|
16710
17429
|
},
|
|
16711
17430
|
async execute(arguments_, context) {
|
|
16712
|
-
const input2 =
|
|
16713
|
-
content:
|
|
16714
|
-
rationale:
|
|
17431
|
+
const input2 = z17.object({
|
|
17432
|
+
content: z17.string().min(1).max(12e3),
|
|
17433
|
+
rationale: z17.string().min(1).max(1e3),
|
|
16715
17434
|
scope: scopeSchema.optional(),
|
|
16716
17435
|
kind: kindSchema.optional(),
|
|
16717
|
-
tags:
|
|
16718
|
-
importance:
|
|
16719
|
-
confidence:
|
|
16720
|
-
agent:
|
|
16721
|
-
revision:
|
|
16722
|
-
conflictKey:
|
|
17436
|
+
tags: z17.array(z17.string()).max(24).optional(),
|
|
17437
|
+
importance: z17.number().min(0).max(1).optional(),
|
|
17438
|
+
confidence: z17.number().min(0).max(1).optional(),
|
|
17439
|
+
agent: z17.string().max(64).optional(),
|
|
17440
|
+
revision: z17.string().max(240).optional(),
|
|
17441
|
+
conflictKey: z17.string().max(240).optional()
|
|
16723
17442
|
}).strict().parse(arguments_);
|
|
16724
17443
|
const scope = input2.scope ?? "workspace";
|
|
16725
17444
|
const candidate = store.propose({
|
|
@@ -16757,9 +17476,9 @@ ${record.content}`
|
|
|
16757
17476
|
}, ["id"])
|
|
16758
17477
|
},
|
|
16759
17478
|
async execute(arguments_) {
|
|
16760
|
-
const input2 =
|
|
16761
|
-
id:
|
|
16762
|
-
permanent:
|
|
17479
|
+
const input2 = z17.object({
|
|
17480
|
+
id: z17.string().uuid(),
|
|
17481
|
+
permanent: z17.boolean().optional()
|
|
16763
17482
|
}).parse(arguments_);
|
|
16764
17483
|
const changed = input2.permanent ? store.remove(input2.id) : store.archive(input2.id);
|
|
16765
17484
|
return {
|
|
@@ -16963,7 +17682,7 @@ function escapeAttribute6(value) {
|
|
|
16963
17682
|
}
|
|
16964
17683
|
|
|
16965
17684
|
// src/workflows/catalog.ts
|
|
16966
|
-
import { z as
|
|
17685
|
+
import { z as z18 } from "zod";
|
|
16967
17686
|
var builtInWorkflows = [
|
|
16968
17687
|
{
|
|
16969
17688
|
name: "implement",
|
|
@@ -17054,7 +17773,7 @@ function createWorkflowTool(catalog) {
|
|
|
17054
17773
|
}, ["name", "task"])
|
|
17055
17774
|
},
|
|
17056
17775
|
async execute(arguments_) {
|
|
17057
|
-
const input2 =
|
|
17776
|
+
const input2 = z18.object({ name: z18.string(), task: z18.string().min(1).max(2e4) }).parse(arguments_);
|
|
17058
17777
|
const workflow = catalog.get(input2.name);
|
|
17059
17778
|
if (!workflow) return { ok: false, content: `Unknown workflow: ${input2.name}` };
|
|
17060
17779
|
return {
|