newmark-agent 0.5.7 → 0.5.9
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/dist/cli-commands.js +3 -3
- package/dist/cli.js +1 -1
- package/dist/conversation-utility-host.bundle.cjs +830 -595
- package/dist/core/agent.d.ts +1 -1
- package/dist/core/agent.js +57 -5
- package/dist/core/agentKernelRunner.js +43 -8
- package/dist/core/emptyResponseRetry.d.ts +16 -0
- package/dist/core/emptyResponseRetry.js +25 -0
- package/dist/core/memoryLab.d.ts +17 -0
- package/dist/core/memoryLab.js +43 -1
- package/dist/core/terminalOutputBuffer.d.ts +24 -0
- package/dist/core/terminalOutputBuffer.js +92 -0
- package/dist/core/toolPolicy.d.ts +1 -0
- package/dist/core/toolPolicy.js +16 -0
- package/dist/core/types.d.ts +1 -1
- package/dist/llm/provider.d.ts +4 -4
- package/dist/llm/provider.js +55 -21
- package/dist/main.js +12 -3
- package/dist/providers/chat-completions.adapter.js +17 -4
- package/dist/providers/provider-events.d.ts +7 -0
- package/dist/providers/provider-events.js +40 -0
- package/dist/providers/responses.adapter.js +23 -9
- package/dist/tools/index.js +42 -10
- package/dist/ui/index.html +73 -19
- package/dist/wsl-agent-host.bundle.cjs +830 -595
- package/package.json +3 -1
|
@@ -4281,6 +4281,234 @@ var require_jpeg_js = __commonJS({
|
|
|
4281
4281
|
}
|
|
4282
4282
|
});
|
|
4283
4283
|
|
|
4284
|
+
// src/core/flow.ts
|
|
4285
|
+
var fs6, path7, FlowEngine;
|
|
4286
|
+
var init_flow = __esm({
|
|
4287
|
+
"src/core/flow.ts"() {
|
|
4288
|
+
"use strict";
|
|
4289
|
+
fs6 = __toESM(require("fs"));
|
|
4290
|
+
path7 = __toESM(require("path"));
|
|
4291
|
+
FlowEngine = class _FlowEngine {
|
|
4292
|
+
static load(dir, name50) {
|
|
4293
|
+
const p = path7.join(dir, `${name50}.Flow.json`);
|
|
4294
|
+
try {
|
|
4295
|
+
return JSON.parse(fs6.readFileSync(p, "utf-8").replace(/^\uFEFF/, ""));
|
|
4296
|
+
} catch {
|
|
4297
|
+
return null;
|
|
4298
|
+
}
|
|
4299
|
+
}
|
|
4300
|
+
static save(dir, workflow) {
|
|
4301
|
+
const p = path7.join(dir, `${workflow.name}.Flow.json`);
|
|
4302
|
+
fs6.writeFileSync(p, JSON.stringify(workflow, null, 2), "utf-8");
|
|
4303
|
+
}
|
|
4304
|
+
static delete(dir, name50) {
|
|
4305
|
+
const p = path7.join(dir, `${name50}.Flow.json`);
|
|
4306
|
+
if (fs6.existsSync(p)) fs6.unlinkSync(p);
|
|
4307
|
+
}
|
|
4308
|
+
static listAll(dir) {
|
|
4309
|
+
try {
|
|
4310
|
+
return fs6.readdirSync(dir).filter((f3) => f3.endsWith(".Flow.json")).map((f3) => f3.replace(".Flow.json", "")).sort();
|
|
4311
|
+
} catch {
|
|
4312
|
+
return [];
|
|
4313
|
+
}
|
|
4314
|
+
}
|
|
4315
|
+
static describeWorkflow(wf) {
|
|
4316
|
+
const comps = [...wf.components].sort((a3, b2) => a3.id - b2.id);
|
|
4317
|
+
if (comps.length === 0) return "";
|
|
4318
|
+
const parts = [];
|
|
4319
|
+
for (const c3 of comps) {
|
|
4320
|
+
if (c3.type === "dialog") {
|
|
4321
|
+
parts.push(c3.mode.charAt(0).toUpperCase() + c3.mode.slice(1));
|
|
4322
|
+
} else {
|
|
4323
|
+
const label = c3.prompt.replace(/\{#prompt#\}/g, "<i>").replace(/\n/g, " ").slice(0, 22);
|
|
4324
|
+
parts.push(`?${label}?`);
|
|
4325
|
+
}
|
|
4326
|
+
}
|
|
4327
|
+
return parts.join(" \u2192 ");
|
|
4328
|
+
}
|
|
4329
|
+
static validate(wf) {
|
|
4330
|
+
const errors = [];
|
|
4331
|
+
if (!wf.components || wf.components.length === 0) {
|
|
4332
|
+
errors.push({ message: "No components defined." });
|
|
4333
|
+
return errors;
|
|
4334
|
+
}
|
|
4335
|
+
const ids = /* @__PURE__ */ new Set();
|
|
4336
|
+
for (const c3 of wf.components) {
|
|
4337
|
+
if (typeof c3.id === "number") ids.add(c3.id);
|
|
4338
|
+
}
|
|
4339
|
+
const seenIds = /* @__PURE__ */ new Set();
|
|
4340
|
+
for (const c3 of wf.components) {
|
|
4341
|
+
if (seenIds.has(c3.id)) {
|
|
4342
|
+
errors.push({ componentId: c3.id, message: `Duplicate component ID: ${c3.id}` });
|
|
4343
|
+
}
|
|
4344
|
+
seenIds.add(c3.id);
|
|
4345
|
+
if (c3.type === "dialog") {
|
|
4346
|
+
const mode = c3.mode.toLowerCase();
|
|
4347
|
+
if (!["build", "plan", "goal"].includes(mode)) {
|
|
4348
|
+
errors.push({ componentId: c3.id, message: `Invalid dialog mode '${c3.mode}' (must be build/plan/goal)` });
|
|
4349
|
+
}
|
|
4350
|
+
} else if (c3.type === "logic") {
|
|
4351
|
+
if (!ids.has(c3.goto_true)) {
|
|
4352
|
+
errors.push({ componentId: c3.id, message: `goto_true=${c3.goto_true} not found` });
|
|
4353
|
+
}
|
|
4354
|
+
if (!ids.has(c3.goto_false)) {
|
|
4355
|
+
errors.push({ componentId: c3.id, message: `goto_false=${c3.goto_false} not found` });
|
|
4356
|
+
}
|
|
4357
|
+
} else {
|
|
4358
|
+
errors.push({ componentId: c3.id, message: `Unknown component type '${c3.type}'` });
|
|
4359
|
+
}
|
|
4360
|
+
}
|
|
4361
|
+
return errors;
|
|
4362
|
+
}
|
|
4363
|
+
static detectCycles(wf) {
|
|
4364
|
+
const comps = [...wf.components].sort((a3, b2) => a3.id - b2.id);
|
|
4365
|
+
if (comps.length === 0) return [];
|
|
4366
|
+
const idToIdx = /* @__PURE__ */ new Map();
|
|
4367
|
+
comps.forEach((c3, i4) => idToIdx.set(c3.id, i4));
|
|
4368
|
+
const graph = /* @__PURE__ */ new Map();
|
|
4369
|
+
for (let index = 0; index < comps.length; index++) {
|
|
4370
|
+
const c3 = comps[index];
|
|
4371
|
+
graph.set(c3.id, []);
|
|
4372
|
+
if (c3.type === "dialog") {
|
|
4373
|
+
const next = comps[index + 1];
|
|
4374
|
+
if (next) graph.get(c3.id).push(next.id);
|
|
4375
|
+
} else if (c3.type === "logic") {
|
|
4376
|
+
if (idToIdx.has(c3.goto_true)) graph.get(c3.id).push(c3.goto_true);
|
|
4377
|
+
if (idToIdx.has(c3.goto_false)) graph.get(c3.id).push(c3.goto_false);
|
|
4378
|
+
}
|
|
4379
|
+
}
|
|
4380
|
+
const WHITE = 0, GRAY = 1, BLACK = 2;
|
|
4381
|
+
const color2 = /* @__PURE__ */ new Map();
|
|
4382
|
+
for (const c3 of comps) color2.set(c3.id, WHITE);
|
|
4383
|
+
const cycles = [];
|
|
4384
|
+
const dfsPath = [];
|
|
4385
|
+
function dfs(node) {
|
|
4386
|
+
color2.set(node, GRAY);
|
|
4387
|
+
dfsPath.push(node);
|
|
4388
|
+
for (const nb of graph.get(node) || []) {
|
|
4389
|
+
if (!color2.has(nb)) continue;
|
|
4390
|
+
if (color2.get(nb) === GRAY) {
|
|
4391
|
+
const start = dfsPath.indexOf(nb);
|
|
4392
|
+
cycles.push(dfsPath.slice(start));
|
|
4393
|
+
} else if (color2.get(nb) === WHITE) {
|
|
4394
|
+
dfs(nb);
|
|
4395
|
+
}
|
|
4396
|
+
}
|
|
4397
|
+
dfsPath.pop();
|
|
4398
|
+
color2.set(node, BLACK);
|
|
4399
|
+
}
|
|
4400
|
+
for (const c3 of comps) {
|
|
4401
|
+
if (color2.get(c3.id) === WHITE) dfs(c3.id);
|
|
4402
|
+
}
|
|
4403
|
+
const unique2 = [];
|
|
4404
|
+
const seen = /* @__PURE__ */ new Set();
|
|
4405
|
+
for (const cyc of cycles) {
|
|
4406
|
+
const key3 = [...cyc].sort((a3, b2) => a3 - b2).join(",");
|
|
4407
|
+
if (!seen.has(key3)) {
|
|
4408
|
+
seen.add(key3);
|
|
4409
|
+
unique2.push(cyc);
|
|
4410
|
+
}
|
|
4411
|
+
}
|
|
4412
|
+
return unique2;
|
|
4413
|
+
}
|
|
4414
|
+
static getCycleWarnings(wf) {
|
|
4415
|
+
const cycles = _FlowEngine.detectCycles(wf);
|
|
4416
|
+
return cycles.map(
|
|
4417
|
+
(cyc) => `[!] Potential logic cycle in '${wf.name}': components [${cyc.join(", ")}] can form a loop.`
|
|
4418
|
+
);
|
|
4419
|
+
}
|
|
4420
|
+
static findWorkflow(name50, dir) {
|
|
4421
|
+
const names = _FlowEngine.listAll(dir);
|
|
4422
|
+
if (names.length === 0) return null;
|
|
4423
|
+
if (names.includes(name50)) return name50;
|
|
4424
|
+
const nameLower = name50.toLowerCase();
|
|
4425
|
+
for (const n3 of names) {
|
|
4426
|
+
if (n3.toLowerCase() === nameLower) return n3;
|
|
4427
|
+
}
|
|
4428
|
+
for (const n3 of names) {
|
|
4429
|
+
if (n3.toLowerCase().includes(nameLower)) return n3;
|
|
4430
|
+
}
|
|
4431
|
+
return null;
|
|
4432
|
+
}
|
|
4433
|
+
static autoTrigger(text, dir) {
|
|
4434
|
+
const names = _FlowEngine.listAll(dir);
|
|
4435
|
+
const textLower = text.toLowerCase();
|
|
4436
|
+
const results = [];
|
|
4437
|
+
for (const n3 of names) {
|
|
4438
|
+
const nLower = n3.toLowerCase();
|
|
4439
|
+
if (nLower === textLower) {
|
|
4440
|
+
results.push({ name: n3, score: 1 });
|
|
4441
|
+
} else if (textLower.includes(nLower) || nLower.includes(textLower)) {
|
|
4442
|
+
const longer = nLower.length > textLower.length ? nLower : textLower;
|
|
4443
|
+
const shorter = nLower.length > textLower.length ? textLower : nLower;
|
|
4444
|
+
const ratio = shorter.length / Math.max(longer.length, 1);
|
|
4445
|
+
results.push({ name: n3, score: 0.5 + 0.4 * Math.min(ratio, 1) });
|
|
4446
|
+
} else {
|
|
4447
|
+
const words = nLower.split(/[\s_-]+/).filter((w) => w.length > 0);
|
|
4448
|
+
const matchCount = words.filter((w) => textLower.includes(w)).length;
|
|
4449
|
+
if (matchCount > 0) {
|
|
4450
|
+
results.push({ name: n3, score: 0.2 + 0.6 * (matchCount / Math.max(words.length, 1)) });
|
|
4451
|
+
}
|
|
4452
|
+
}
|
|
4453
|
+
}
|
|
4454
|
+
results.sort((a3, b2) => b2.score - a3.score);
|
|
4455
|
+
return results;
|
|
4456
|
+
}
|
|
4457
|
+
static buildDialogPrompt(component, userInput) {
|
|
4458
|
+
const raw = component.prompt;
|
|
4459
|
+
const ui = userInput || "";
|
|
4460
|
+
const hasPlaceholder = raw.includes("{#prompt#}");
|
|
4461
|
+
if (component.mode === "plan" && ui) {
|
|
4462
|
+
if (hasPlaceholder) {
|
|
4463
|
+
return raw.replace(/\{#prompt#\}/g, ui);
|
|
4464
|
+
} else {
|
|
4465
|
+
return `Plan: ${raw}
|
|
4466
|
+
User context: ${ui}`;
|
|
4467
|
+
}
|
|
4468
|
+
}
|
|
4469
|
+
return hasPlaceholder ? raw.replace(/\{#prompt#\}/g, ui) : raw;
|
|
4470
|
+
}
|
|
4471
|
+
static generateSequence(workflow, start, input2) {
|
|
4472
|
+
const orderedComponents = [...workflow.components];
|
|
4473
|
+
const seq = [];
|
|
4474
|
+
let cur = start;
|
|
4475
|
+
let count = 0;
|
|
4476
|
+
const max2 = workflow.components.length + 10;
|
|
4477
|
+
while (count < max2) {
|
|
4478
|
+
count++;
|
|
4479
|
+
const comp = workflow.components.find((c3) => c3.id === cur);
|
|
4480
|
+
if (!comp) break;
|
|
4481
|
+
if (comp.type === "dialog") {
|
|
4482
|
+
const expanded = _FlowEngine.buildDialogPrompt(comp, input2);
|
|
4483
|
+
seq.push({ id: comp.id, mode: comp.mode, prompt: expanded, isLogic: false });
|
|
4484
|
+
const index = orderedComponents.findIndex((item) => item.id === comp.id);
|
|
4485
|
+
if (index < 0 || index + 1 >= orderedComponents.length) break;
|
|
4486
|
+
cur = orderedComponents[index + 1].id;
|
|
4487
|
+
} else {
|
|
4488
|
+
seq.push({
|
|
4489
|
+
id: comp.id,
|
|
4490
|
+
prompt: comp.prompt.replace(/\{#prompt#\}/g, input2),
|
|
4491
|
+
isLogic: true,
|
|
4492
|
+
gotoTrue: comp.goto_true,
|
|
4493
|
+
gotoFalse: comp.goto_false
|
|
4494
|
+
});
|
|
4495
|
+
break;
|
|
4496
|
+
}
|
|
4497
|
+
}
|
|
4498
|
+
return seq;
|
|
4499
|
+
}
|
|
4500
|
+
static resolveGoto(workflow, cur, cond) {
|
|
4501
|
+
const comp = workflow.components.find((c3) => c3.id === cur);
|
|
4502
|
+
if (comp?.type === "logic") {
|
|
4503
|
+
return cond ? comp.goto_true : comp.goto_false;
|
|
4504
|
+
}
|
|
4505
|
+
const index = workflow.components.findIndex((component) => component.id === cur);
|
|
4506
|
+
return index >= 0 && index + 1 < workflow.components.length ? workflow.components[index + 1].id : -1;
|
|
4507
|
+
}
|
|
4508
|
+
};
|
|
4509
|
+
}
|
|
4510
|
+
});
|
|
4511
|
+
|
|
4284
4512
|
// node_modules/regenerator-runtime/runtime.js
|
|
4285
4513
|
var require_runtime = __commonJS({
|
|
4286
4514
|
"node_modules/regenerator-runtime/runtime.js"(exports2, module2) {
|
|
@@ -326027,234 +326255,6 @@ var require_readability = __commonJS({
|
|
|
326027
326255
|
}
|
|
326028
326256
|
});
|
|
326029
326257
|
|
|
326030
|
-
// src/core/flow.ts
|
|
326031
|
-
var fs16, path18, FlowEngine;
|
|
326032
|
-
var init_flow = __esm({
|
|
326033
|
-
"src/core/flow.ts"() {
|
|
326034
|
-
"use strict";
|
|
326035
|
-
fs16 = __toESM(require("fs"));
|
|
326036
|
-
path18 = __toESM(require("path"));
|
|
326037
|
-
FlowEngine = class _FlowEngine {
|
|
326038
|
-
static load(dir, name50) {
|
|
326039
|
-
const p = path18.join(dir, `${name50}.Flow.json`);
|
|
326040
|
-
try {
|
|
326041
|
-
return JSON.parse(fs16.readFileSync(p, "utf-8").replace(/^\uFEFF/, ""));
|
|
326042
|
-
} catch {
|
|
326043
|
-
return null;
|
|
326044
|
-
}
|
|
326045
|
-
}
|
|
326046
|
-
static save(dir, workflow) {
|
|
326047
|
-
const p = path18.join(dir, `${workflow.name}.Flow.json`);
|
|
326048
|
-
fs16.writeFileSync(p, JSON.stringify(workflow, null, 2), "utf-8");
|
|
326049
|
-
}
|
|
326050
|
-
static delete(dir, name50) {
|
|
326051
|
-
const p = path18.join(dir, `${name50}.Flow.json`);
|
|
326052
|
-
if (fs16.existsSync(p)) fs16.unlinkSync(p);
|
|
326053
|
-
}
|
|
326054
|
-
static listAll(dir) {
|
|
326055
|
-
try {
|
|
326056
|
-
return fs16.readdirSync(dir).filter((f3) => f3.endsWith(".Flow.json")).map((f3) => f3.replace(".Flow.json", "")).sort();
|
|
326057
|
-
} catch {
|
|
326058
|
-
return [];
|
|
326059
|
-
}
|
|
326060
|
-
}
|
|
326061
|
-
static describeWorkflow(wf) {
|
|
326062
|
-
const comps = [...wf.components].sort((a3, b2) => a3.id - b2.id);
|
|
326063
|
-
if (comps.length === 0) return "";
|
|
326064
|
-
const parts = [];
|
|
326065
|
-
for (const c3 of comps) {
|
|
326066
|
-
if (c3.type === "dialog") {
|
|
326067
|
-
parts.push(c3.mode.charAt(0).toUpperCase() + c3.mode.slice(1));
|
|
326068
|
-
} else {
|
|
326069
|
-
const label = c3.prompt.replace(/\{#prompt#\}/g, "<i>").replace(/\n/g, " ").slice(0, 22);
|
|
326070
|
-
parts.push(`?${label}?`);
|
|
326071
|
-
}
|
|
326072
|
-
}
|
|
326073
|
-
return parts.join(" \u2192 ");
|
|
326074
|
-
}
|
|
326075
|
-
static validate(wf) {
|
|
326076
|
-
const errors = [];
|
|
326077
|
-
if (!wf.components || wf.components.length === 0) {
|
|
326078
|
-
errors.push({ message: "No components defined." });
|
|
326079
|
-
return errors;
|
|
326080
|
-
}
|
|
326081
|
-
const ids = /* @__PURE__ */ new Set();
|
|
326082
|
-
for (const c3 of wf.components) {
|
|
326083
|
-
if (typeof c3.id === "number") ids.add(c3.id);
|
|
326084
|
-
}
|
|
326085
|
-
const seenIds = /* @__PURE__ */ new Set();
|
|
326086
|
-
for (const c3 of wf.components) {
|
|
326087
|
-
if (seenIds.has(c3.id)) {
|
|
326088
|
-
errors.push({ componentId: c3.id, message: `Duplicate component ID: ${c3.id}` });
|
|
326089
|
-
}
|
|
326090
|
-
seenIds.add(c3.id);
|
|
326091
|
-
if (c3.type === "dialog") {
|
|
326092
|
-
const mode = c3.mode.toLowerCase();
|
|
326093
|
-
if (!["build", "plan", "goal"].includes(mode)) {
|
|
326094
|
-
errors.push({ componentId: c3.id, message: `Invalid dialog mode '${c3.mode}' (must be build/plan/goal)` });
|
|
326095
|
-
}
|
|
326096
|
-
} else if (c3.type === "logic") {
|
|
326097
|
-
if (!ids.has(c3.goto_true)) {
|
|
326098
|
-
errors.push({ componentId: c3.id, message: `goto_true=${c3.goto_true} not found` });
|
|
326099
|
-
}
|
|
326100
|
-
if (!ids.has(c3.goto_false)) {
|
|
326101
|
-
errors.push({ componentId: c3.id, message: `goto_false=${c3.goto_false} not found` });
|
|
326102
|
-
}
|
|
326103
|
-
} else {
|
|
326104
|
-
errors.push({ componentId: c3.id, message: `Unknown component type '${c3.type}'` });
|
|
326105
|
-
}
|
|
326106
|
-
}
|
|
326107
|
-
return errors;
|
|
326108
|
-
}
|
|
326109
|
-
static detectCycles(wf) {
|
|
326110
|
-
const comps = [...wf.components].sort((a3, b2) => a3.id - b2.id);
|
|
326111
|
-
if (comps.length === 0) return [];
|
|
326112
|
-
const idToIdx = /* @__PURE__ */ new Map();
|
|
326113
|
-
comps.forEach((c3, i4) => idToIdx.set(c3.id, i4));
|
|
326114
|
-
const graph = /* @__PURE__ */ new Map();
|
|
326115
|
-
for (let index = 0; index < comps.length; index++) {
|
|
326116
|
-
const c3 = comps[index];
|
|
326117
|
-
graph.set(c3.id, []);
|
|
326118
|
-
if (c3.type === "dialog") {
|
|
326119
|
-
const next = comps[index + 1];
|
|
326120
|
-
if (next) graph.get(c3.id).push(next.id);
|
|
326121
|
-
} else if (c3.type === "logic") {
|
|
326122
|
-
if (idToIdx.has(c3.goto_true)) graph.get(c3.id).push(c3.goto_true);
|
|
326123
|
-
if (idToIdx.has(c3.goto_false)) graph.get(c3.id).push(c3.goto_false);
|
|
326124
|
-
}
|
|
326125
|
-
}
|
|
326126
|
-
const WHITE = 0, GRAY = 1, BLACK = 2;
|
|
326127
|
-
const color2 = /* @__PURE__ */ new Map();
|
|
326128
|
-
for (const c3 of comps) color2.set(c3.id, WHITE);
|
|
326129
|
-
const cycles = [];
|
|
326130
|
-
const dfsPath = [];
|
|
326131
|
-
function dfs(node) {
|
|
326132
|
-
color2.set(node, GRAY);
|
|
326133
|
-
dfsPath.push(node);
|
|
326134
|
-
for (const nb of graph.get(node) || []) {
|
|
326135
|
-
if (!color2.has(nb)) continue;
|
|
326136
|
-
if (color2.get(nb) === GRAY) {
|
|
326137
|
-
const start = dfsPath.indexOf(nb);
|
|
326138
|
-
cycles.push(dfsPath.slice(start));
|
|
326139
|
-
} else if (color2.get(nb) === WHITE) {
|
|
326140
|
-
dfs(nb);
|
|
326141
|
-
}
|
|
326142
|
-
}
|
|
326143
|
-
dfsPath.pop();
|
|
326144
|
-
color2.set(node, BLACK);
|
|
326145
|
-
}
|
|
326146
|
-
for (const c3 of comps) {
|
|
326147
|
-
if (color2.get(c3.id) === WHITE) dfs(c3.id);
|
|
326148
|
-
}
|
|
326149
|
-
const unique2 = [];
|
|
326150
|
-
const seen = /* @__PURE__ */ new Set();
|
|
326151
|
-
for (const cyc of cycles) {
|
|
326152
|
-
const key3 = [...cyc].sort((a3, b2) => a3 - b2).join(",");
|
|
326153
|
-
if (!seen.has(key3)) {
|
|
326154
|
-
seen.add(key3);
|
|
326155
|
-
unique2.push(cyc);
|
|
326156
|
-
}
|
|
326157
|
-
}
|
|
326158
|
-
return unique2;
|
|
326159
|
-
}
|
|
326160
|
-
static getCycleWarnings(wf) {
|
|
326161
|
-
const cycles = _FlowEngine.detectCycles(wf);
|
|
326162
|
-
return cycles.map(
|
|
326163
|
-
(cyc) => `[!] Potential logic cycle in '${wf.name}': components [${cyc.join(", ")}] can form a loop.`
|
|
326164
|
-
);
|
|
326165
|
-
}
|
|
326166
|
-
static findWorkflow(name50, dir) {
|
|
326167
|
-
const names = _FlowEngine.listAll(dir);
|
|
326168
|
-
if (names.length === 0) return null;
|
|
326169
|
-
if (names.includes(name50)) return name50;
|
|
326170
|
-
const nameLower = name50.toLowerCase();
|
|
326171
|
-
for (const n3 of names) {
|
|
326172
|
-
if (n3.toLowerCase() === nameLower) return n3;
|
|
326173
|
-
}
|
|
326174
|
-
for (const n3 of names) {
|
|
326175
|
-
if (n3.toLowerCase().includes(nameLower)) return n3;
|
|
326176
|
-
}
|
|
326177
|
-
return null;
|
|
326178
|
-
}
|
|
326179
|
-
static autoTrigger(text, dir) {
|
|
326180
|
-
const names = _FlowEngine.listAll(dir);
|
|
326181
|
-
const textLower = text.toLowerCase();
|
|
326182
|
-
const results = [];
|
|
326183
|
-
for (const n3 of names) {
|
|
326184
|
-
const nLower = n3.toLowerCase();
|
|
326185
|
-
if (nLower === textLower) {
|
|
326186
|
-
results.push({ name: n3, score: 1 });
|
|
326187
|
-
} else if (textLower.includes(nLower) || nLower.includes(textLower)) {
|
|
326188
|
-
const longer = nLower.length > textLower.length ? nLower : textLower;
|
|
326189
|
-
const shorter = nLower.length > textLower.length ? textLower : nLower;
|
|
326190
|
-
const ratio = shorter.length / Math.max(longer.length, 1);
|
|
326191
|
-
results.push({ name: n3, score: 0.5 + 0.4 * Math.min(ratio, 1) });
|
|
326192
|
-
} else {
|
|
326193
|
-
const words = nLower.split(/[\s_-]+/).filter((w) => w.length > 0);
|
|
326194
|
-
const matchCount = words.filter((w) => textLower.includes(w)).length;
|
|
326195
|
-
if (matchCount > 0) {
|
|
326196
|
-
results.push({ name: n3, score: 0.2 + 0.6 * (matchCount / Math.max(words.length, 1)) });
|
|
326197
|
-
}
|
|
326198
|
-
}
|
|
326199
|
-
}
|
|
326200
|
-
results.sort((a3, b2) => b2.score - a3.score);
|
|
326201
|
-
return results;
|
|
326202
|
-
}
|
|
326203
|
-
static buildDialogPrompt(component, userInput) {
|
|
326204
|
-
const raw = component.prompt;
|
|
326205
|
-
const ui = userInput || "";
|
|
326206
|
-
const hasPlaceholder = raw.includes("{#prompt#}");
|
|
326207
|
-
if (component.mode === "plan" && ui) {
|
|
326208
|
-
if (hasPlaceholder) {
|
|
326209
|
-
return raw.replace(/\{#prompt#\}/g, ui);
|
|
326210
|
-
} else {
|
|
326211
|
-
return `Plan: ${raw}
|
|
326212
|
-
User context: ${ui}`;
|
|
326213
|
-
}
|
|
326214
|
-
}
|
|
326215
|
-
return hasPlaceholder ? raw.replace(/\{#prompt#\}/g, ui) : raw;
|
|
326216
|
-
}
|
|
326217
|
-
static generateSequence(workflow, start, input2) {
|
|
326218
|
-
const orderedComponents = [...workflow.components];
|
|
326219
|
-
const seq = [];
|
|
326220
|
-
let cur = start;
|
|
326221
|
-
let count = 0;
|
|
326222
|
-
const max2 = workflow.components.length + 10;
|
|
326223
|
-
while (count < max2) {
|
|
326224
|
-
count++;
|
|
326225
|
-
const comp = workflow.components.find((c3) => c3.id === cur);
|
|
326226
|
-
if (!comp) break;
|
|
326227
|
-
if (comp.type === "dialog") {
|
|
326228
|
-
const expanded = _FlowEngine.buildDialogPrompt(comp, input2);
|
|
326229
|
-
seq.push({ id: comp.id, mode: comp.mode, prompt: expanded, isLogic: false });
|
|
326230
|
-
const index = orderedComponents.findIndex((item) => item.id === comp.id);
|
|
326231
|
-
if (index < 0 || index + 1 >= orderedComponents.length) break;
|
|
326232
|
-
cur = orderedComponents[index + 1].id;
|
|
326233
|
-
} else {
|
|
326234
|
-
seq.push({
|
|
326235
|
-
id: comp.id,
|
|
326236
|
-
prompt: comp.prompt.replace(/\{#prompt#\}/g, input2),
|
|
326237
|
-
isLogic: true,
|
|
326238
|
-
gotoTrue: comp.goto_true,
|
|
326239
|
-
gotoFalse: comp.goto_false
|
|
326240
|
-
});
|
|
326241
|
-
break;
|
|
326242
|
-
}
|
|
326243
|
-
}
|
|
326244
|
-
return seq;
|
|
326245
|
-
}
|
|
326246
|
-
static resolveGoto(workflow, cur, cond) {
|
|
326247
|
-
const comp = workflow.components.find((c3) => c3.id === cur);
|
|
326248
|
-
if (comp?.type === "logic") {
|
|
326249
|
-
return cond ? comp.goto_true : comp.goto_false;
|
|
326250
|
-
}
|
|
326251
|
-
const index = workflow.components.findIndex((component) => component.id === cur);
|
|
326252
|
-
return index >= 0 && index + 1 < workflow.components.length ? workflow.components[index + 1].id : -1;
|
|
326253
|
-
}
|
|
326254
|
-
};
|
|
326255
|
-
}
|
|
326256
|
-
});
|
|
326257
|
-
|
|
326258
326258
|
// src/core/agentKernel/agent-loop.ts
|
|
326259
326259
|
async function runAgentLoop(prompts, config, signal) {
|
|
326260
326260
|
throwIfAborted3(signal);
|
|
@@ -328713,6 +328713,30 @@ function parseProviderSse(raw) {
|
|
|
328713
328713
|
}
|
|
328714
328714
|
return events;
|
|
328715
328715
|
}
|
|
328716
|
+
function assembleCompatibleToolArguments(parts) {
|
|
328717
|
+
const nonEmpty = (parts || []).map(String).filter((part) => part && part !== "null");
|
|
328718
|
+
if (!nonEmpty.length) return "{}";
|
|
328719
|
+
const isJsonObject = (value) => {
|
|
328720
|
+
try {
|
|
328721
|
+
const parsed = JSON.parse(value);
|
|
328722
|
+
return !!parsed && typeof parsed === "object" && !Array.isArray(parsed);
|
|
328723
|
+
} catch {
|
|
328724
|
+
return false;
|
|
328725
|
+
}
|
|
328726
|
+
};
|
|
328727
|
+
const incremental = nonEmpty.join("");
|
|
328728
|
+
if (isJsonObject(incremental)) return incremental;
|
|
328729
|
+
let compatible = "";
|
|
328730
|
+
for (const incoming of nonEmpty) {
|
|
328731
|
+
if (!compatible) compatible = incoming;
|
|
328732
|
+
else if (incoming === compatible) continue;
|
|
328733
|
+
else if (incoming.startsWith(compatible)) compatible = incoming;
|
|
328734
|
+
else if (compatible.startsWith(incoming)) continue;
|
|
328735
|
+
else compatible += incoming;
|
|
328736
|
+
}
|
|
328737
|
+
if (isJsonObject(compatible)) return compatible;
|
|
328738
|
+
return [...nonEmpty].reverse().find(isJsonObject) || compatible;
|
|
328739
|
+
}
|
|
328716
328740
|
function isContentPolicyBlocked(json) {
|
|
328717
328741
|
const choices = Array.isArray(json.choices) ? json.choices : [];
|
|
328718
328742
|
const choice = choices[0] || {};
|
|
@@ -328941,6 +328965,8 @@ var ChatCompletionsAdapter = class {
|
|
|
328941
328965
|
let contentPolicyBlocked = false;
|
|
328942
328966
|
let emittedContent = false;
|
|
328943
328967
|
let emittedTool = false;
|
|
328968
|
+
let emittedReasoning = false;
|
|
328969
|
+
let explicitCompletion = false;
|
|
328944
328970
|
try {
|
|
328945
328971
|
while (true) {
|
|
328946
328972
|
const { done, value } = await readProviderStreamChunk(reader, signal);
|
|
@@ -328952,7 +328978,10 @@ var ChatCompletionsAdapter = class {
|
|
|
328952
328978
|
const trimmed = line.trim();
|
|
328953
328979
|
if (!trimmed.startsWith("data: ")) continue;
|
|
328954
328980
|
const data = trimmed.slice(6);
|
|
328955
|
-
if (data === "[DONE]")
|
|
328981
|
+
if (data === "[DONE]") {
|
|
328982
|
+
explicitCompletion = true;
|
|
328983
|
+
continue;
|
|
328984
|
+
}
|
|
328956
328985
|
let json;
|
|
328957
328986
|
try {
|
|
328958
328987
|
json = JSON.parse(data);
|
|
@@ -328965,11 +328994,16 @@ var ChatCompletionsAdapter = class {
|
|
|
328965
328994
|
}
|
|
328966
328995
|
if (isContentPolicyBlocked(json)) contentPolicyBlocked = true;
|
|
328967
328996
|
const choices = Array.isArray(json.choices) ? json.choices : [];
|
|
328968
|
-
const
|
|
328997
|
+
const choice = choices[0];
|
|
328998
|
+
if (choice?.finish_reason !== void 0 && choice.finish_reason !== null) explicitCompletion = true;
|
|
328999
|
+
const delta = choice?.delta;
|
|
328969
329000
|
if (!delta) continue;
|
|
328970
329001
|
if (delta.reasoning_content) {
|
|
328971
329002
|
const reasoning = this.extractText(delta.reasoning_content);
|
|
328972
|
-
if (reasoning)
|
|
329003
|
+
if (reasoning) {
|
|
329004
|
+
emittedReasoning = true;
|
|
329005
|
+
yield { type: "reasoning.summary.delta", delta: reasoning };
|
|
329006
|
+
}
|
|
328973
329007
|
}
|
|
328974
329008
|
const textDelta = this.extractText(delta.content);
|
|
328975
329009
|
if (textDelta) {
|
|
@@ -329014,13 +329048,17 @@ var ChatCompletionsAdapter = class {
|
|
|
329014
329048
|
type: "tool_call.completed",
|
|
329015
329049
|
id: currentToolCall.id,
|
|
329016
329050
|
name: currentToolCall.name,
|
|
329017
|
-
arguments: currentToolCall.argumentParts
|
|
329051
|
+
arguments: assembleCompatibleToolArguments(currentToolCall.argumentParts)
|
|
329018
329052
|
};
|
|
329019
329053
|
}
|
|
329020
329054
|
} else if (!emittedContent && !emittedTool && contentPolicyBlocked) {
|
|
329021
329055
|
yield { type: "response.failed", error: "[Error] Content policy refusal (content_filter)." };
|
|
329022
329056
|
return;
|
|
329023
329057
|
}
|
|
329058
|
+
if (!explicitCompletion && !emittedContent && !emittedTool && !emittedReasoning) {
|
|
329059
|
+
yield { type: "response.failed", error: "[LLM Error] Chat stream ended before an explicit completion." };
|
|
329060
|
+
return;
|
|
329061
|
+
}
|
|
329024
329062
|
yield { type: "response.completed" };
|
|
329025
329063
|
} finally {
|
|
329026
329064
|
reader.releaseLock();
|
|
@@ -329217,6 +329255,7 @@ var ResponsesAdapter = class {
|
|
|
329217
329255
|
const key3 = `${String(payload.item_id || "")}:${String(payload.summary_index || 0)}`;
|
|
329218
329256
|
const delta = this.extractText(payload.delta);
|
|
329219
329257
|
if (delta) {
|
|
329258
|
+
emittedContent = true;
|
|
329220
329259
|
reasoningSummaries.set(key3, (reasoningSummaries.get(key3) || "") + delta);
|
|
329221
329260
|
yield { type: "reasoning.summary.delta", delta };
|
|
329222
329261
|
}
|
|
@@ -329247,7 +329286,7 @@ var ResponsesAdapter = class {
|
|
|
329247
329286
|
calls.set(key3, {
|
|
329248
329287
|
id: String(item.call_id || item.id || key3),
|
|
329249
329288
|
name: String(item.name || ""),
|
|
329250
|
-
|
|
329289
|
+
argumentParts: item.arguments ? [String(item.arguments)] : [],
|
|
329251
329290
|
emitted: false
|
|
329252
329291
|
});
|
|
329253
329292
|
}
|
|
@@ -329255,9 +329294,9 @@ var ResponsesAdapter = class {
|
|
|
329255
329294
|
}
|
|
329256
329295
|
if (eventType === "response.function_call_arguments.delta") {
|
|
329257
329296
|
const key3 = String(payload.item_id || payload.call_id || payload.output_index || "");
|
|
329258
|
-
const call = calls.get(key3) || { id: String(payload.call_id || key3), name: String(payload.name || ""),
|
|
329297
|
+
const call = calls.get(key3) || { id: String(payload.call_id || key3), name: String(payload.name || ""), argumentParts: [], emitted: false };
|
|
329259
329298
|
const delta = String(payload.delta || "");
|
|
329260
|
-
call.
|
|
329299
|
+
if (delta) call.argumentParts.push(delta);
|
|
329261
329300
|
calls.set(key3, call);
|
|
329262
329301
|
yield { type: "tool_call.arguments.delta", id: call.id, delta };
|
|
329263
329302
|
continue;
|
|
@@ -329269,19 +329308,20 @@ var ResponsesAdapter = class {
|
|
|
329269
329308
|
const call = calls.get(key3) || {
|
|
329270
329309
|
id: String(item.call_id || item.id || key3),
|
|
329271
329310
|
name: String(item.name || ""),
|
|
329272
|
-
|
|
329311
|
+
argumentParts: item.arguments ? [String(item.arguments)] : [],
|
|
329273
329312
|
emitted: false
|
|
329274
329313
|
};
|
|
329275
329314
|
call.id = String(item.call_id || call.id);
|
|
329276
329315
|
call.name = String(item.name || call.name);
|
|
329277
|
-
|
|
329316
|
+
if (typeof item.arguments === "string" && item.arguments) call.argumentParts.push(item.arguments);
|
|
329278
329317
|
if (!call.emitted) {
|
|
329279
329318
|
call.emitted = true;
|
|
329319
|
+
const argumentsJson = assembleCompatibleToolArguments(call.argumentParts);
|
|
329280
329320
|
yield { type: "tool_call.started", id: call.id, name: call.name };
|
|
329281
|
-
if (
|
|
329282
|
-
yield { type: "tool_call.arguments.delta", id: call.id, delta:
|
|
329321
|
+
if (argumentsJson !== "{}") {
|
|
329322
|
+
yield { type: "tool_call.arguments.delta", id: call.id, delta: argumentsJson };
|
|
329283
329323
|
}
|
|
329284
|
-
yield { type: "tool_call.completed", id: call.id, name: call.name, arguments:
|
|
329324
|
+
yield { type: "tool_call.completed", id: call.id, name: call.name, arguments: argumentsJson };
|
|
329285
329325
|
}
|
|
329286
329326
|
calls.set(key3, call);
|
|
329287
329327
|
}
|
|
@@ -329306,8 +329346,14 @@ var ResponsesAdapter = class {
|
|
|
329306
329346
|
} else if (!completed) {
|
|
329307
329347
|
yield { type: "response.failed", error: "[LLM Error] Responses stream ended before response.completed." };
|
|
329308
329348
|
} else if (!emittedContent && calls.size === 0) {
|
|
329309
|
-
yield { type: "response.failed", error: "[Error]
|
|
329349
|
+
yield { type: "response.failed", error: "[Error] Provider returned an empty response." };
|
|
329310
329350
|
} else {
|
|
329351
|
+
for (const call of calls.values()) {
|
|
329352
|
+
if (call.emitted) continue;
|
|
329353
|
+
const argumentsJson = assembleCompatibleToolArguments(call.argumentParts);
|
|
329354
|
+
yield { type: "tool_call.started", id: call.id, name: call.name };
|
|
329355
|
+
yield { type: "tool_call.completed", id: call.id, name: call.name, arguments: argumentsJson };
|
|
329356
|
+
}
|
|
329311
329357
|
yield { type: "response.completed" };
|
|
329312
329358
|
}
|
|
329313
329359
|
} finally {
|
|
@@ -330186,7 +330232,7 @@ ${responsePath}
|
|
|
330186
330232
|
* `provider_adapters_v2` context flag. Request serialization and SSE
|
|
330187
330233
|
* normalization are delegated to the shared provider adapters while the
|
|
330188
330234
|
* transport orchestration (loopback node-http, fetch -> node-http fallback,
|
|
330189
|
-
*
|
|
330235
|
+
* cancellation-only streaming and the 4xx Chat -> Responses downgrade) stay here.
|
|
330190
330236
|
* The emitted request body and StreamToken stream are byte-equivalent to
|
|
330191
330237
|
* the legacy inlined path.
|
|
330192
330238
|
*/
|
|
@@ -330323,9 +330369,9 @@ ${responsePath}
|
|
|
330323
330369
|
}
|
|
330324
330370
|
/**
|
|
330325
330371
|
* Loopback-aware transport injected into adapter `execute`. Streaming
|
|
330326
|
-
* requests retain the fetch-to-node fallback for transport failures
|
|
330327
|
-
*
|
|
330328
|
-
*
|
|
330372
|
+
* requests retain the fetch-to-node fallback for transport failures. They
|
|
330373
|
+
* have no response deadline; only caller cancellation or a concrete
|
|
330374
|
+
* transport/provider failure may end the request.
|
|
330329
330375
|
*/
|
|
330330
330376
|
buildProviderAdapterTransport() {
|
|
330331
330377
|
return async (request, signal) => {
|
|
@@ -330335,7 +330381,7 @@ ${responsePath}
|
|
|
330335
330381
|
const forwardAbort = () => abort.abort(signal?.reason);
|
|
330336
330382
|
if (signal?.aborted) forwardAbort();
|
|
330337
330383
|
else signal?.addEventListener("abort", forwardAbort, { once: true });
|
|
330338
|
-
const effectiveTimeout =
|
|
330384
|
+
const effectiveTimeout = 0;
|
|
330339
330385
|
const timer = effectiveTimeout > 0 ? setTimeout(() => abort.abort(providerTimeoutError(effectiveTimeout)), effectiveTimeout) : void 0;
|
|
330340
330386
|
try {
|
|
330341
330387
|
try {
|
|
@@ -330480,7 +330526,7 @@ ${responsePath}
|
|
|
330480
330526
|
const forwardAbort = () => abort.abort(signal?.reason);
|
|
330481
330527
|
if (signal?.aborted) forwardAbort();
|
|
330482
330528
|
else signal?.addEventListener("abort", forwardAbort, { once: true });
|
|
330483
|
-
const effectiveTimeout =
|
|
330529
|
+
const effectiveTimeout = 0;
|
|
330484
330530
|
const timeout = effectiveTimeout > 0 ? setTimeout(() => abort.abort(providerTimeoutError(effectiveTimeout)), effectiveTimeout) : void 0;
|
|
330485
330531
|
let reader = null;
|
|
330486
330532
|
try {
|
|
@@ -330512,10 +330558,14 @@ ${responsePath}
|
|
|
330512
330558
|
}
|
|
330513
330559
|
const decoder = new TextDecoder();
|
|
330514
330560
|
let buffer = "";
|
|
330515
|
-
|
|
330561
|
+
const toolCalls = /* @__PURE__ */ new Map();
|
|
330562
|
+
const toolCallOrder = [];
|
|
330563
|
+
let syntheticToolIndex = 0;
|
|
330564
|
+
let lastToolIndex = 0;
|
|
330516
330565
|
let currentReasoningContent = "";
|
|
330517
330566
|
let contentPolicyBlocked = false;
|
|
330518
330567
|
let emittedContent = false;
|
|
330568
|
+
let explicitCompletion = false;
|
|
330519
330569
|
const streamSignal = signal || new AbortController().signal;
|
|
330520
330570
|
while (true) {
|
|
330521
330571
|
const { done, value } = await readProviderStreamChunk(reader, streamSignal);
|
|
@@ -330527,7 +330577,10 @@ ${responsePath}
|
|
|
330527
330577
|
const trimmed = line.trim();
|
|
330528
330578
|
if (!trimmed.startsWith("data: ")) continue;
|
|
330529
330579
|
const data = trimmed.slice(6);
|
|
330530
|
-
if (data === "[DONE]")
|
|
330580
|
+
if (data === "[DONE]") {
|
|
330581
|
+
explicitCompletion = true;
|
|
330582
|
+
continue;
|
|
330583
|
+
}
|
|
330531
330584
|
try {
|
|
330532
330585
|
const json = JSON.parse(data);
|
|
330533
330586
|
if (json.usage) yield { type: "usage", text: "", usage: extractProviderUsage(json) };
|
|
@@ -330545,24 +330598,44 @@ ${responsePath}
|
|
|
330545
330598
|
}
|
|
330546
330599
|
if (delta.tool_calls) {
|
|
330547
330600
|
for (const tc of delta.tool_calls) {
|
|
330548
|
-
|
|
330549
|
-
|
|
330550
|
-
|
|
330551
|
-
|
|
330552
|
-
|
|
330553
|
-
|
|
330554
|
-
|
|
330601
|
+
const rawIndex = Number(tc.index);
|
|
330602
|
+
const index = Number.isInteger(rawIndex) && rawIndex >= 0 ? rawIndex : tc.id ? syntheticToolIndex++ : lastToolIndex;
|
|
330603
|
+
lastToolIndex = index;
|
|
330604
|
+
let call = toolCalls.get(index);
|
|
330605
|
+
if (!call && (tc.id || tc.function?.name)) {
|
|
330606
|
+
call = { id: tc.id || "", name: tc.function?.name || "", argumentParts: [] };
|
|
330607
|
+
toolCalls.set(index, call);
|
|
330608
|
+
toolCallOrder.push(index);
|
|
330555
330609
|
}
|
|
330610
|
+
if (!call) continue;
|
|
330611
|
+
if (tc.id && !call.id) call.id = tc.id;
|
|
330612
|
+
if (tc.function?.name && !call.name) call.name = tc.function.name;
|
|
330613
|
+
if (tc.function?.arguments) call.argumentParts.push(tc.function.arguments);
|
|
330556
330614
|
}
|
|
330557
330615
|
}
|
|
330558
330616
|
} catch {
|
|
330559
330617
|
}
|
|
330560
330618
|
}
|
|
330561
330619
|
}
|
|
330562
|
-
if (
|
|
330563
|
-
|
|
330620
|
+
if (toolCallOrder.length) {
|
|
330621
|
+
for (const index of toolCallOrder) {
|
|
330622
|
+
const call = toolCalls.get(index);
|
|
330623
|
+
if (!call) continue;
|
|
330624
|
+
yield {
|
|
330625
|
+
type: "tool_call",
|
|
330626
|
+
text: "",
|
|
330627
|
+
toolCall: {
|
|
330628
|
+
id: call.id,
|
|
330629
|
+
name: call.name,
|
|
330630
|
+
arguments: assembleCompatibleToolArguments(call.argumentParts)
|
|
330631
|
+
},
|
|
330632
|
+
reasoningContent: currentReasoningContent || void 0
|
|
330633
|
+
};
|
|
330634
|
+
}
|
|
330564
330635
|
} else if (!emittedContent && contentPolicyBlocked) {
|
|
330565
330636
|
yield { type: "text", text: "[Error] Content policy refusal (content_filter)." };
|
|
330637
|
+
} else if (!explicitCompletion && !emittedContent && !currentReasoningContent) {
|
|
330638
|
+
yield { type: "text", text: "[LLM Error] GitHub Models stream ended before an explicit completion." };
|
|
330566
330639
|
}
|
|
330567
330640
|
} finally {
|
|
330568
330641
|
reader?.releaseLock();
|
|
@@ -331249,8 +331322,8 @@ async function fuzzyDiscoverWithoutGuide(input2, explicit, preferredModels = [])
|
|
|
331249
331322
|
}
|
|
331250
331323
|
|
|
331251
331324
|
// src/tools/index.ts
|
|
331252
|
-
var
|
|
331253
|
-
var
|
|
331325
|
+
var fs15 = __toESM(require("fs"));
|
|
331326
|
+
var path17 = __toESM(require("path"));
|
|
331254
331327
|
var crypto8 = __toESM(require("crypto"));
|
|
331255
331328
|
var import_url2 = require("url");
|
|
331256
331329
|
|
|
@@ -331594,7 +331667,8 @@ var MemoryLabManager = class {
|
|
|
331594
331667
|
"Use memory_lab_read to inspect index.json before deciding what memory is relevant.",
|
|
331595
331668
|
"Use memory_lab_query for bounded task-relevant retrieval; do not inject the complete index when a focused query is sufficient.",
|
|
331596
331669
|
"Use memory_lab_read with component/name/slug to read a component core markdown file.",
|
|
331597
|
-
"Use memory_lab_update only when the user asks to create or update durable memory
|
|
331670
|
+
"Use memory_lab_update only when the user asks to create or update durable memory. Create with name, tags, and content; patch an existing component with component plus only changed fields.",
|
|
331671
|
+
"For small body edits prefer contentAppend or oldText/newText over resending the complete content.",
|
|
331598
331672
|
"For an existing component, pass expectedUpdatedAt from the latest read/query result. A stale update is rejected instead of overwriting newer memory.",
|
|
331599
331673
|
"Use memory_lab_delete only when the user explicitly asks to forget/remove durable memory. Delete moves the prior revision to Memory Lab/archive and records a policy event.",
|
|
331600
331674
|
"Every mutation should include a concise reason and source. ADD, UPDATE, and DELETE decisions are append-only in policy.jsonl and are recoverable from archive.",
|
|
@@ -331702,6 +331776,39 @@ var MemoryLabManager = class {
|
|
|
331702
331776
|
source: String(input2.source || "").trim()
|
|
331703
331777
|
};
|
|
331704
331778
|
}
|
|
331779
|
+
preparePatch(input2) {
|
|
331780
|
+
const selector2 = String(input2.component || "").trim();
|
|
331781
|
+
if (!selector2) throw new Error("Memory component is required for a patch.");
|
|
331782
|
+
const current = this.read(selector2);
|
|
331783
|
+
if (!current.ok || !current.component) throw new Error(current.error || `Memory component not found: ${selector2}`);
|
|
331784
|
+
const existing = current.component.meta;
|
|
331785
|
+
const oldContent = current.component.content;
|
|
331786
|
+
let content = input2.content !== void 0 ? String(input2.content) : oldContent;
|
|
331787
|
+
if (input2.contentAppend !== void 0) content = `${oldContent}${String(input2.contentAppend)}`;
|
|
331788
|
+
if (input2.oldText !== void 0) {
|
|
331789
|
+
const oldText = String(input2.oldText);
|
|
331790
|
+
if (!oldText) throw new Error("oldText must not be empty.");
|
|
331791
|
+
const matches = oldContent.split(oldText).length - 1;
|
|
331792
|
+
if (!matches) throw new Error("oldText was not found in the Memory Lab component.");
|
|
331793
|
+
if (matches > 1 && input2.replaceAll !== true) throw new Error(`oldText matched ${matches} places; pass replaceAll=true or a unique fragment.`);
|
|
331794
|
+
content = input2.replaceAll === true ? oldContent.split(oldText).join(String(input2.newText || "")) : oldContent.replace(oldText, String(input2.newText || ""));
|
|
331795
|
+
}
|
|
331796
|
+
const name50 = input2.name === void 0 ? existing.name : String(input2.name);
|
|
331797
|
+
if (this.slugify(name50) !== current.component.slug) {
|
|
331798
|
+
throw new Error("Renaming a Memory Lab component is not supported by incremental patch; create the new component then delete the old one.");
|
|
331799
|
+
}
|
|
331800
|
+
return this.prepareUpdate({
|
|
331801
|
+
name: name50,
|
|
331802
|
+
description: input2.description === void 0 ? existing.description : String(input2.description),
|
|
331803
|
+
tags: input2.tags === void 0 ? existing.tags : input2.tags,
|
|
331804
|
+
tagPaths: input2.tagPaths === void 0 ? existing.tagPaths : input2.tagPaths,
|
|
331805
|
+
content,
|
|
331806
|
+
kind: input2.kind === void 0 ? existing.kind : input2.kind,
|
|
331807
|
+
expectedUpdatedAt: String(input2.expectedUpdatedAt || existing.updatedAt),
|
|
331808
|
+
reason: input2.reason,
|
|
331809
|
+
source: input2.source
|
|
331810
|
+
});
|
|
331811
|
+
}
|
|
331705
331812
|
update(prepared) {
|
|
331706
331813
|
this.ensure();
|
|
331707
331814
|
const index = this.loadIndex();
|
|
@@ -332248,20 +332355,23 @@ ${JSON.stringify(payload, null, 2)}`;
|
|
|
332248
332355
|
}
|
|
332249
332356
|
};
|
|
332250
332357
|
|
|
332358
|
+
// src/tools/index.ts
|
|
332359
|
+
init_flow();
|
|
332360
|
+
|
|
332251
332361
|
// src/core/compat.ts
|
|
332252
|
-
var
|
|
332253
|
-
var
|
|
332362
|
+
var fs7 = __toESM(require("fs"));
|
|
332363
|
+
var path8 = __toESM(require("path"));
|
|
332254
332364
|
var os2 = __toESM(require("os"));
|
|
332255
332365
|
function readJson(filePath) {
|
|
332256
332366
|
try {
|
|
332257
|
-
return JSON.parse(
|
|
332367
|
+
return JSON.parse(fs7.readFileSync(filePath, "utf-8").replace(/^\uFEFF/, ""));
|
|
332258
332368
|
} catch {
|
|
332259
332369
|
return null;
|
|
332260
332370
|
}
|
|
332261
332371
|
}
|
|
332262
332372
|
function readJsonLoose(filePath) {
|
|
332263
332373
|
try {
|
|
332264
|
-
const withoutBom =
|
|
332374
|
+
const withoutBom = fs7.readFileSync(filePath, "utf-8").replace(/^\uFEFF/, "");
|
|
332265
332375
|
const withoutComments = withoutBom.replace(/\/\*[\s\S]*?\*\//g, "").replace(/(^|\s)\/\/.*$/gm, "$1");
|
|
332266
332376
|
return JSON.parse(withoutComments);
|
|
332267
332377
|
} catch {
|
|
@@ -332342,7 +332452,7 @@ function normalizeToolResult(output, metadata) {
|
|
|
332342
332452
|
return { ok: !error, output, error, metadata };
|
|
332343
332453
|
}
|
|
332344
332454
|
function componentPaths(root2, value) {
|
|
332345
|
-
return asStringArray(value).map((item) =>
|
|
332455
|
+
return asStringArray(value).map((item) => path8.resolve(root2, item));
|
|
332346
332456
|
}
|
|
332347
332457
|
function manifestComponentPaths(root2, manifest, ...keys) {
|
|
332348
332458
|
for (const key3 of keys) {
|
|
@@ -332353,7 +332463,7 @@ function manifestComponentPaths(root2, manifest, ...keys) {
|
|
|
332353
332463
|
function discoverComponentFiles(root2, relativeDirs, extension, maxDepth = 2) {
|
|
332354
332464
|
const files = [];
|
|
332355
332465
|
for (const dir of relativeDirs) {
|
|
332356
|
-
files.push(...listFilesRecursive(
|
|
332466
|
+
files.push(...listFilesRecursive(path8.join(root2, dir), extension, maxDepth));
|
|
332357
332467
|
}
|
|
332358
332468
|
return Array.from(new Set(files)).sort();
|
|
332359
332469
|
}
|
|
@@ -332378,12 +332488,12 @@ function collectMcpServers(...values) {
|
|
|
332378
332488
|
function defaultComponentWarnings(kind, components) {
|
|
332379
332489
|
const warnings = [];
|
|
332380
332490
|
for (const item of components) {
|
|
332381
|
-
if (
|
|
332491
|
+
if (path8.isAbsolute(item) && !fs7.existsSync(item)) warnings.push(`${kind} path does not exist: ${item}`);
|
|
332382
332492
|
}
|
|
332383
332493
|
return warnings;
|
|
332384
332494
|
}
|
|
332385
332495
|
function normalizeCodexPlugin(root2, manifest) {
|
|
332386
|
-
const name50 = asString(manifest.name) ||
|
|
332496
|
+
const name50 = asString(manifest.name) || path8.basename(root2);
|
|
332387
332497
|
const components = {
|
|
332388
332498
|
skills: manifestComponentPaths(root2, manifest, "skills"),
|
|
332389
332499
|
agents: manifestComponentPaths(root2, manifest, "agents"),
|
|
@@ -332414,7 +332524,7 @@ function normalizeCodexPlugin(root2, manifest) {
|
|
|
332414
332524
|
};
|
|
332415
332525
|
}
|
|
332416
332526
|
function normalizeClaudePlugin(root2, manifest) {
|
|
332417
|
-
const name50 = asString(manifest.name) ||
|
|
332527
|
+
const name50 = asString(manifest.name) || path8.basename(root2);
|
|
332418
332528
|
const experimental = nestedRecord(manifest.experimental);
|
|
332419
332529
|
const components = {
|
|
332420
332530
|
skills: manifestComponentPaths(root2, manifest, "skills"),
|
|
@@ -332452,7 +332562,7 @@ function normalizeClaudePlugin(root2, manifest) {
|
|
|
332452
332562
|
};
|
|
332453
332563
|
}
|
|
332454
332564
|
function normalizeNewmarkPlugin(root2, manifest) {
|
|
332455
|
-
const name50 = asString(manifest.name) ||
|
|
332565
|
+
const name50 = asString(manifest.name) || path8.basename(root2);
|
|
332456
332566
|
return {
|
|
332457
332567
|
id: `newmark:${name50}`,
|
|
332458
332568
|
ecosystem: "newmark",
|
|
@@ -332481,7 +332591,7 @@ function findPluginRoots(root2, maxDepth = 5) {
|
|
|
332481
332591
|
if (depth > maxDepth) return;
|
|
332482
332592
|
let entries;
|
|
332483
332593
|
try {
|
|
332484
|
-
entries =
|
|
332594
|
+
entries = fs7.readdirSync(dir, { withFileTypes: true });
|
|
332485
332595
|
} catch {
|
|
332486
332596
|
return;
|
|
332487
332597
|
}
|
|
@@ -332490,7 +332600,7 @@ function findPluginRoots(root2, maxDepth = 5) {
|
|
|
332490
332600
|
}
|
|
332491
332601
|
for (const entry of entries) {
|
|
332492
332602
|
if (!entry.isDirectory() || skip.has(entry.name) || entry.name.startsWith("release.locked-")) continue;
|
|
332493
|
-
walk4(
|
|
332603
|
+
walk4(path8.join(dir, entry.name), depth + 1);
|
|
332494
332604
|
}
|
|
332495
332605
|
};
|
|
332496
332606
|
walk4(root2, 0);
|
|
@@ -332499,20 +332609,20 @@ function findPluginRoots(root2, maxDepth = 5) {
|
|
|
332499
332609
|
function discoverPluginManifests(root2) {
|
|
332500
332610
|
const manifests = [];
|
|
332501
332611
|
for (const pluginRoot of findPluginRoots(root2)) {
|
|
332502
|
-
const codexPath =
|
|
332503
|
-
const claudePath =
|
|
332504
|
-
const newmarkPath =
|
|
332505
|
-
const codex =
|
|
332506
|
-
const claude =
|
|
332507
|
-
const newmark =
|
|
332612
|
+
const codexPath = path8.join(pluginRoot, ".codex-plugin", "plugin.json");
|
|
332613
|
+
const claudePath = path8.join(pluginRoot, ".claude-plugin", "plugin.json");
|
|
332614
|
+
const newmarkPath = path8.join(pluginRoot, ".newmark-plugin", "plugin.json");
|
|
332615
|
+
const codex = fs7.existsSync(codexPath) ? readJson(codexPath) : null;
|
|
332616
|
+
const claude = fs7.existsSync(claudePath) ? readJson(claudePath) : null;
|
|
332617
|
+
const newmark = fs7.existsSync(newmarkPath) ? readJson(newmarkPath) : null;
|
|
332508
332618
|
if (codex && typeof codex === "object") manifests.push(normalizeCodexPlugin(pluginRoot, codex));
|
|
332509
332619
|
if (claude && typeof claude === "object") manifests.push(normalizeClaudePlugin(pluginRoot, claude));
|
|
332510
332620
|
if (newmark && typeof newmark === "object") manifests.push(normalizeNewmarkPlugin(pluginRoot, newmark));
|
|
332511
332621
|
}
|
|
332512
332622
|
const projectOpencode = readOpenCodeManifest(root2, "project");
|
|
332513
332623
|
if (projectOpencode) manifests.push(projectOpencode);
|
|
332514
|
-
const userOpenCodeRoot =
|
|
332515
|
-
if (
|
|
332624
|
+
const userOpenCodeRoot = path8.join(os2.homedir(), ".config", "opencode");
|
|
332625
|
+
if (path8.resolve(userOpenCodeRoot) !== path8.resolve(path8.join(root2, ".opencode"))) {
|
|
332516
332626
|
const userOpenCode = readOpenCodeManifest(userOpenCodeRoot, "user");
|
|
332517
332627
|
if (userOpenCode) manifests.push(userOpenCode);
|
|
332518
332628
|
}
|
|
@@ -332520,20 +332630,20 @@ function discoverPluginManifests(root2) {
|
|
|
332520
332630
|
}
|
|
332521
332631
|
function readOpenCodeConfig(root2) {
|
|
332522
332632
|
const candidates = [
|
|
332523
|
-
|
|
332524
|
-
|
|
332525
|
-
|
|
332526
|
-
|
|
332633
|
+
path8.join(root2, "opencode.json"),
|
|
332634
|
+
path8.join(root2, "opencode.jsonc"),
|
|
332635
|
+
path8.join(root2, ".opencode", "opencode.json"),
|
|
332636
|
+
path8.join(root2, ".opencode", "opencode.jsonc")
|
|
332527
332637
|
];
|
|
332528
332638
|
for (const filePath of candidates) {
|
|
332529
|
-
if (
|
|
332639
|
+
if (fs7.existsSync(filePath)) return { path: filePath, value: readJsonLoose(filePath) };
|
|
332530
332640
|
}
|
|
332531
332641
|
return null;
|
|
332532
332642
|
}
|
|
332533
332643
|
function readOpenCodeManifest(root2, scope) {
|
|
332534
|
-
const localRoot = scope === "project" ?
|
|
332535
|
-
const opencodeToolsDir =
|
|
332536
|
-
const opencodePluginsDir =
|
|
332644
|
+
const localRoot = scope === "project" ? path8.join(root2, ".opencode") : root2;
|
|
332645
|
+
const opencodeToolsDir = path8.join(localRoot, "tools");
|
|
332646
|
+
const opencodePluginsDir = path8.join(localRoot, "plugins");
|
|
332537
332647
|
const tools = listCodeFiles(opencodeToolsDir);
|
|
332538
332648
|
const pluginFiles = listCodeFiles(opencodePluginsDir);
|
|
332539
332649
|
const config = readOpenCodeConfig(root2);
|
|
@@ -332574,18 +332684,18 @@ function readOpenCodeManifest(root2, scope) {
|
|
|
332574
332684
|
}
|
|
332575
332685
|
function discoverOpenCodeInstructionFiles(projectRoot, localRoot) {
|
|
332576
332686
|
const candidates = [
|
|
332577
|
-
|
|
332578
|
-
|
|
332579
|
-
|
|
332580
|
-
|
|
332581
|
-
|
|
332687
|
+
path8.join(projectRoot, "AGENTS.md"),
|
|
332688
|
+
path8.join(projectRoot, ".opencode", "instructions.md"),
|
|
332689
|
+
path8.join(projectRoot, ".opencode", "AGENTS.md"),
|
|
332690
|
+
path8.join(localRoot, "instructions.md"),
|
|
332691
|
+
path8.join(localRoot, "AGENTS.md")
|
|
332582
332692
|
];
|
|
332583
|
-
return Array.from(new Set(candidates.filter((filePath) =>
|
|
332693
|
+
return Array.from(new Set(candidates.filter((filePath) => fs7.existsSync(filePath)))).sort();
|
|
332584
332694
|
}
|
|
332585
332695
|
function dedupeManifests(manifests) {
|
|
332586
332696
|
const seen = /* @__PURE__ */ new Set();
|
|
332587
332697
|
return manifests.filter((item) => {
|
|
332588
|
-
const key3 = `${item.id}:${
|
|
332698
|
+
const key3 = `${item.id}:${path8.resolve(item.root)}`;
|
|
332589
332699
|
if (seen.has(key3)) return false;
|
|
332590
332700
|
seen.add(key3);
|
|
332591
332701
|
return true;
|
|
@@ -332593,14 +332703,14 @@ function dedupeManifests(manifests) {
|
|
|
332593
332703
|
}
|
|
332594
332704
|
function listCodeFiles(dir) {
|
|
332595
332705
|
try {
|
|
332596
|
-
return
|
|
332706
|
+
return fs7.readdirSync(dir, { withFileTypes: true }).filter((e3) => e3.isFile() && /\.(?:c?js|mjs|ts)$/.test(e3.name)).map((e3) => path8.join(dir, e3.name)).sort();
|
|
332597
332707
|
} catch {
|
|
332598
332708
|
return [];
|
|
332599
332709
|
}
|
|
332600
332710
|
}
|
|
332601
332711
|
function parseFrontmatterMarkdown(filePath) {
|
|
332602
332712
|
try {
|
|
332603
|
-
const content =
|
|
332713
|
+
const content = fs7.readFileSync(filePath, "utf-8").replace(/^\uFEFF/, "");
|
|
332604
332714
|
const match = content.match(/^---\s*([\s\S]*?)\s*---\s*/);
|
|
332605
332715
|
if (!match) return { metadata: {}, body: content };
|
|
332606
332716
|
const metadata = {};
|
|
@@ -332629,7 +332739,7 @@ function parseMetadataValue(raw) {
|
|
|
332629
332739
|
function parseSimpleToml(filePath) {
|
|
332630
332740
|
try {
|
|
332631
332741
|
const metadata = {};
|
|
332632
|
-
const content =
|
|
332742
|
+
const content = fs7.readFileSync(filePath, "utf-8").replace(/^\uFEFF/, "");
|
|
332633
332743
|
const multiline = null;
|
|
332634
332744
|
if (multiline) return metadata;
|
|
332635
332745
|
const lines = content.split(/\r?\n/);
|
|
@@ -332663,7 +332773,7 @@ function parseSimpleToml(filePath) {
|
|
|
332663
332773
|
}
|
|
332664
332774
|
}
|
|
332665
332775
|
function agentPresetFromMetadata(filePath, ecosystem, metadata, body = "") {
|
|
332666
|
-
const name50 = asString(metadata.name) ||
|
|
332776
|
+
const name50 = asString(metadata.name) || path8.basename(filePath).replace(/\.(?:toml|md)$/i, "");
|
|
332667
332777
|
const description = asString(metadata.description);
|
|
332668
332778
|
const instructions = asString(metadata.developer_instructions || metadata.instructions || metadata.prompt) || body.trim();
|
|
332669
332779
|
if (!name50 || !description) return null;
|
|
@@ -332691,12 +332801,12 @@ function listFilesRecursive(root2, extension, maxDepth = 4) {
|
|
|
332691
332801
|
if (depth > maxDepth) return;
|
|
332692
332802
|
let entries;
|
|
332693
332803
|
try {
|
|
332694
|
-
entries =
|
|
332804
|
+
entries = fs7.readdirSync(dir, { withFileTypes: true });
|
|
332695
332805
|
} catch {
|
|
332696
332806
|
return;
|
|
332697
332807
|
}
|
|
332698
332808
|
for (const entry of entries) {
|
|
332699
|
-
const full =
|
|
332809
|
+
const full = path8.join(dir, entry.name);
|
|
332700
332810
|
if (entry.isFile() && extension.test(entry.name)) results.push(full);
|
|
332701
332811
|
if (entry.isDirectory() && !entry.name.startsWith(".git") && entry.name !== "node_modules") walk4(full, depth + 1);
|
|
332702
332812
|
}
|
|
@@ -332707,10 +332817,10 @@ function listFilesRecursive(root2, extension, maxDepth = 4) {
|
|
|
332707
332817
|
function discoverAgentPresets(root2) {
|
|
332708
332818
|
const presets = [];
|
|
332709
332819
|
const codexDirs = [
|
|
332710
|
-
|
|
332711
|
-
|
|
332712
|
-
|
|
332713
|
-
|
|
332820
|
+
path8.join(root2, ".codex", "agents"),
|
|
332821
|
+
path8.join(root2, ".agents", "agents"),
|
|
332822
|
+
path8.join(os2.homedir(), ".codex", "agents"),
|
|
332823
|
+
path8.join(os2.homedir(), ".agents", "agents")
|
|
332714
332824
|
];
|
|
332715
332825
|
for (const dir of codexDirs) {
|
|
332716
332826
|
for (const filePath of listFilesRecursive(dir, /\.toml$/i, 1)) {
|
|
@@ -332719,14 +332829,14 @@ function discoverAgentPresets(root2) {
|
|
|
332719
332829
|
}
|
|
332720
332830
|
}
|
|
332721
332831
|
const claudeDirs = [
|
|
332722
|
-
|
|
332723
|
-
|
|
332724
|
-
|
|
332832
|
+
path8.join(root2, ".claude", "agents"),
|
|
332833
|
+
path8.join(os2.homedir(), ".claude", "agents"),
|
|
332834
|
+
path8.join(os2.homedir(), ".config", "opencode", "agents")
|
|
332725
332835
|
];
|
|
332726
332836
|
for (const dir of claudeDirs) {
|
|
332727
332837
|
for (const filePath of listFilesRecursive(dir, /\.md$/i, 1)) {
|
|
332728
332838
|
const parsed = parseFrontmatterMarkdown(filePath);
|
|
332729
|
-
const ecosystem = filePath.includes(`${
|
|
332839
|
+
const ecosystem = filePath.includes(`${path8.sep}.config${path8.sep}opencode${path8.sep}`) ? "opencode" : "claude-code";
|
|
332730
332840
|
const preset = agentPresetFromMetadata(filePath, ecosystem, parsed.metadata, parsed.body);
|
|
332731
332841
|
if (preset) presets.push(preset);
|
|
332732
332842
|
}
|
|
@@ -332763,15 +332873,15 @@ function findAgentPreset(root2, selector2) {
|
|
|
332763
332873
|
preset.id,
|
|
332764
332874
|
preset.name,
|
|
332765
332875
|
`${preset.ecosystem}:${preset.name}`,
|
|
332766
|
-
|
|
332876
|
+
path8.basename(preset.path)
|
|
332767
332877
|
].map((value) => String(value || "").toLowerCase());
|
|
332768
|
-
return keys.includes(normalized) ||
|
|
332878
|
+
return keys.includes(normalized) || path8.resolve(preset.path).toLowerCase() === path8.resolve(wanted).toLowerCase();
|
|
332769
332879
|
}) || null;
|
|
332770
332880
|
}
|
|
332771
332881
|
|
|
332772
332882
|
// src/tools/terminalTakeover.ts
|
|
332773
|
-
var
|
|
332774
|
-
var
|
|
332883
|
+
var fs8 = __toESM(require("fs"));
|
|
332884
|
+
var path9 = __toESM(require("path"));
|
|
332775
332885
|
var import_child_process2 = require("child_process");
|
|
332776
332886
|
var import_crypto5 = require("crypto");
|
|
332777
332887
|
var ROOT_TERMINAL_ACTOR_ID = "00000000-0000-4000-8000-000000000001";
|
|
@@ -332786,7 +332896,7 @@ function isoNow() {
|
|
|
332786
332896
|
return (/* @__PURE__ */ new Date()).toISOString();
|
|
332787
332897
|
}
|
|
332788
332898
|
function canonicalPersistenceRoot(root2) {
|
|
332789
|
-
const resolved =
|
|
332899
|
+
const resolved = path9.resolve(root2 || process.cwd());
|
|
332790
332900
|
return process.platform === "win32" ? resolved.toLowerCase() : resolved;
|
|
332791
332901
|
}
|
|
332792
332902
|
function portableWorkspacePath(input2) {
|
|
@@ -332795,7 +332905,7 @@ function portableWorkspacePath(input2) {
|
|
|
332795
332905
|
if (wsl) return `${wsl[1].toLowerCase()}:/${String(wsl[2] || "").replace(/^\/+|\/+$/g, "")}`.replace(/\/$/, "");
|
|
332796
332906
|
const drive = /^([a-zA-Z]):(?:\/(.*))?$/.exec(raw);
|
|
332797
332907
|
if (drive) return `${drive[1].toLowerCase()}:/${String(drive[2] || "").replace(/^\/+|\/+$/g, "")}`.replace(/\/$/, "");
|
|
332798
|
-
const resolved =
|
|
332908
|
+
const resolved = path9.resolve(raw).replace(/\\/g, "/").replace(/\/+$/g, "");
|
|
332799
332909
|
return process.platform === "win32" ? resolved.toLowerCase() : resolved;
|
|
332800
332910
|
}
|
|
332801
332911
|
function terminalTakeoverWorkspaceId(workspacePath) {
|
|
@@ -332890,12 +333000,12 @@ function nodePtyHasConptyDll() {
|
|
|
332890
333000
|
if (process.platform !== "win32") return false;
|
|
332891
333001
|
try {
|
|
332892
333002
|
const packageJson = require.resolve("node-pty/package.json");
|
|
332893
|
-
const packageRoot =
|
|
333003
|
+
const packageRoot = path9.dirname(packageJson);
|
|
332894
333004
|
return [
|
|
332895
|
-
|
|
332896
|
-
|
|
332897
|
-
|
|
332898
|
-
].some((candidate) =>
|
|
333005
|
+
path9.join(packageRoot, "build", "Release", "conpty", "conpty.dll"),
|
|
333006
|
+
path9.join(packageRoot, "build", "Debug", "conpty", "conpty.dll"),
|
|
333007
|
+
path9.join(packageRoot, "prebuilds", `${process.platform}-${process.arch}`, "conpty", "conpty.dll")
|
|
333008
|
+
].some((candidate) => fs8.existsSync(candidate));
|
|
332899
333009
|
} catch {
|
|
332900
333010
|
return false;
|
|
332901
333011
|
}
|
|
@@ -333128,7 +333238,7 @@ function spawnTakeoverPty(shell, cwd, env, cols, rows) {
|
|
|
333128
333238
|
};
|
|
333129
333239
|
}
|
|
333130
333240
|
function persistencePath(root2) {
|
|
333131
|
-
return
|
|
333241
|
+
return path9.join(root2, "Terminal", "Takeover.json");
|
|
333132
333242
|
}
|
|
333133
333243
|
function validPersistedRecord(input2) {
|
|
333134
333244
|
if (!input2 || typeof input2 !== "object") return null;
|
|
@@ -333169,7 +333279,7 @@ function ensurePersistenceLoaded(rootRaw) {
|
|
|
333169
333279
|
if (loaded) return loaded;
|
|
333170
333280
|
const records = /* @__PURE__ */ new Map();
|
|
333171
333281
|
try {
|
|
333172
|
-
const parsed = JSON.parse(
|
|
333282
|
+
const parsed = JSON.parse(fs8.readFileSync(persistencePath(root2), "utf-8"));
|
|
333173
333283
|
if (Array.isArray(parsed.records)) {
|
|
333174
333284
|
for (const input2 of parsed.records) {
|
|
333175
333285
|
const record = validPersistedRecord(input2);
|
|
@@ -333187,19 +333297,19 @@ function persistEndedRecords(rootRaw) {
|
|
|
333187
333297
|
const output = { version: 1, updatedAt: isoNow(), records };
|
|
333188
333298
|
const filePath = persistencePath(root2);
|
|
333189
333299
|
const tempPath = `${filePath}.tmp-${process.pid}-${(0, import_crypto5.randomUUID)()}`;
|
|
333190
|
-
|
|
333191
|
-
const fd =
|
|
333300
|
+
fs8.mkdirSync(path9.dirname(filePath), { recursive: true });
|
|
333301
|
+
const fd = fs8.openSync(tempPath, "w");
|
|
333192
333302
|
try {
|
|
333193
|
-
|
|
333194
|
-
|
|
333303
|
+
fs8.writeFileSync(fd, JSON.stringify(output, null, 2), "utf-8");
|
|
333304
|
+
fs8.fsyncSync(fd);
|
|
333195
333305
|
} finally {
|
|
333196
|
-
|
|
333306
|
+
fs8.closeSync(fd);
|
|
333197
333307
|
}
|
|
333198
333308
|
try {
|
|
333199
|
-
|
|
333309
|
+
fs8.renameSync(tempPath, filePath);
|
|
333200
333310
|
} catch (error) {
|
|
333201
333311
|
try {
|
|
333202
|
-
|
|
333312
|
+
fs8.rmSync(tempPath, { force: true });
|
|
333203
333313
|
} catch {
|
|
333204
333314
|
}
|
|
333205
333315
|
throw error;
|
|
@@ -333432,8 +333542,8 @@ function runTerminalTakeover(input2) {
|
|
|
333432
333542
|
}
|
|
333433
333543
|
|
|
333434
333544
|
// src/tools/computerUse.ts
|
|
333435
|
-
var
|
|
333436
|
-
var
|
|
333545
|
+
var fs9 = __toESM(require("fs"));
|
|
333546
|
+
var path10 = __toESM(require("path"));
|
|
333437
333547
|
var crypto6 = __toESM(require("crypto"));
|
|
333438
333548
|
var os3 = __toESM(require("os"));
|
|
333439
333549
|
|
|
@@ -333641,8 +333751,8 @@ async function runPowerShell(script, timeout = 3e4, lane = "action") {
|
|
|
333641
333751
|
return await runPersistentPowerShell(script, timeout, lane);
|
|
333642
333752
|
}
|
|
333643
333753
|
function tempScreenshotDir() {
|
|
333644
|
-
const dir =
|
|
333645
|
-
|
|
333754
|
+
const dir = path10.join(os3.tmpdir(), "newmark-computer-use");
|
|
333755
|
+
fs9.mkdirSync(dir, { recursive: true });
|
|
333646
333756
|
const now2 = Date.now();
|
|
333647
333757
|
if (now2 - lastScreenshotCleanupAt >= SCREENSHOT_CLEANUP_INTERVAL_MS) {
|
|
333648
333758
|
lastScreenshotCleanupAt = now2;
|
|
@@ -333664,7 +333774,7 @@ function ephemeralScreenshotPath(kind, directory = tempScreenshotDir(), createdA
|
|
|
333664
333774
|
const pid = Math.max(1, Math.floor(Number(ownerPid) || process.pid));
|
|
333665
333775
|
const timestamp = Math.max(0, Math.floor(Number(createdAt) || Date.now()));
|
|
333666
333776
|
const nonce = /^[a-f0-9]{8}$/i.test(String(suffix)) ? String(suffix).toLowerCase() : crypto6.randomBytes(4).toString("hex");
|
|
333667
|
-
return
|
|
333777
|
+
return path10.join(directory, `${kind}-p${pid}-t${timestamp}-${nonce}.jpg`);
|
|
333668
333778
|
}
|
|
333669
333779
|
function isProcessAlive(pid) {
|
|
333670
333780
|
if (!Number.isSafeInteger(pid) || pid <= 0) return false;
|
|
@@ -333677,14 +333787,14 @@ function isProcessAlive(pid) {
|
|
|
333677
333787
|
}
|
|
333678
333788
|
}
|
|
333679
333789
|
function cleanupStaleScreenshots(options = {}) {
|
|
333680
|
-
const directory = options.directory ||
|
|
333790
|
+
const directory = options.directory || path10.join(os3.tmpdir(), "newmark-computer-use");
|
|
333681
333791
|
const now2 = Number.isFinite(Number(options.now)) ? Number(options.now) : Date.now();
|
|
333682
333792
|
const processAlive = options.isProcessAlive || isProcessAlive;
|
|
333683
333793
|
const ownedPattern = /^(?:observe|app)-p([1-9]\d*)-t(\d{10,16})-[a-f0-9]{8}\.jpg$/i;
|
|
333684
333794
|
const legacyPattern = /^(?:observe|app)-\d{4}-\d{2}-\d{2}T\d{2}-\d{2}-\d{2}-\d{3}Z-[a-f0-9]{8}\.jpg$/i;
|
|
333685
333795
|
let names = [];
|
|
333686
333796
|
try {
|
|
333687
|
-
names =
|
|
333797
|
+
names = fs9.readdirSync(directory);
|
|
333688
333798
|
} catch {
|
|
333689
333799
|
return { removed: 0 };
|
|
333690
333800
|
}
|
|
@@ -333693,10 +333803,10 @@ function cleanupStaleScreenshots(options = {}) {
|
|
|
333693
333803
|
const owned = ownedPattern.exec(name50);
|
|
333694
333804
|
const isLegacy = !owned && legacyPattern.test(name50);
|
|
333695
333805
|
if (!owned && !isLegacy) continue;
|
|
333696
|
-
const filePath =
|
|
333806
|
+
const filePath = path10.join(directory, name50);
|
|
333697
333807
|
let stats;
|
|
333698
333808
|
try {
|
|
333699
|
-
stats =
|
|
333809
|
+
stats = fs9.lstatSync(filePath);
|
|
333700
333810
|
if (!stats.isFile() || stats.isSymbolicLink()) continue;
|
|
333701
333811
|
} catch {
|
|
333702
333812
|
continue;
|
|
@@ -333720,7 +333830,7 @@ function cleanupStaleScreenshots(options = {}) {
|
|
|
333720
333830
|
}
|
|
333721
333831
|
if (!shouldRemove) continue;
|
|
333722
333832
|
try {
|
|
333723
|
-
|
|
333833
|
+
fs9.unlinkSync(filePath);
|
|
333724
333834
|
removed += 1;
|
|
333725
333835
|
} catch {
|
|
333726
333836
|
}
|
|
@@ -333743,7 +333853,7 @@ function captureBounds(maxWidth, maxHeight) {
|
|
|
333743
333853
|
}
|
|
333744
333854
|
function removeEphemeralScreenshot(outPath) {
|
|
333745
333855
|
try {
|
|
333746
|
-
|
|
333856
|
+
fs9.unlinkSync(outPath);
|
|
333747
333857
|
} catch {
|
|
333748
333858
|
}
|
|
333749
333859
|
}
|
|
@@ -333819,7 +333929,7 @@ async function startTakeoverOverlay(durationMs = 0, input2 = {}) {
|
|
|
333819
333929
|
const width = 2;
|
|
333820
333930
|
const speedSeconds = 3;
|
|
333821
333931
|
const ownerPid = Math.max(0, Math.floor(Number(input2.ownerPid ?? process.pid) || 0));
|
|
333822
|
-
const scriptPath =
|
|
333932
|
+
const scriptPath = path10.join(tempScreenshotDir(), `takeover-overlay-${timestampName()}-${crypto6.randomBytes(4).toString("hex")}.ps1`);
|
|
333823
333933
|
const script = [
|
|
333824
333934
|
"Add-Type -AssemblyName System.Windows.Forms",
|
|
333825
333935
|
"Add-Type -AssemblyName System.Drawing",
|
|
@@ -333958,7 +334068,7 @@ async function startTakeoverOverlay(durationMs = 0, input2 = {}) {
|
|
|
333958
334068
|
"[System.Windows.Forms.Application]::Run()",
|
|
333959
334069
|
"try { Remove-Item -LiteralPath $PSCommandPath -Force -ErrorAction SilentlyContinue } catch {}"
|
|
333960
334070
|
].filter(Boolean).join("\r\n");
|
|
333961
|
-
|
|
334071
|
+
fs9.writeFileSync(scriptPath, `\uFEFF${script}`, "utf8");
|
|
333962
334072
|
const createCommand = [
|
|
333963
334073
|
`$cmd = 'powershell.exe -NoProfile -ExecutionPolicy Bypass -File ' + ${psQuote(`"${scriptPath}"`)}`,
|
|
333964
334074
|
`$startup = ([wmiclass]'Win32_ProcessStartup').CreateInstance()`,
|
|
@@ -333971,7 +334081,7 @@ async function startTakeoverOverlay(durationMs = 0, input2 = {}) {
|
|
|
333971
334081
|
const pid = Number(String(result.output || "").trim().split(/\r?\n/).pop() || 0);
|
|
333972
334082
|
if (!Number.isFinite(pid) || pid <= 0 || !result.ok) {
|
|
333973
334083
|
try {
|
|
333974
|
-
|
|
334084
|
+
fs9.unlinkSync(scriptPath);
|
|
333975
334085
|
} catch {
|
|
333976
334086
|
}
|
|
333977
334087
|
return { ok: false, action: "takeover_start", error: result.output || "Overlay failed to start." };
|
|
@@ -333998,7 +334108,7 @@ function parseJsonArray(text) {
|
|
|
333998
334108
|
return [];
|
|
333999
334109
|
}
|
|
334000
334110
|
function observationKey(workspacePath, ownerId) {
|
|
334001
|
-
return `${
|
|
334111
|
+
return `${path10.resolve(workspacePath || process.cwd()).toLowerCase()}::${String(ownerId || "direct")}`;
|
|
334002
334112
|
}
|
|
334003
334113
|
function sceneGeneration(apps, elements) {
|
|
334004
334114
|
const seed = [
|
|
@@ -334214,7 +334324,7 @@ async function cropScreenshot(workspacePath, ownerId, allowEphemeralVisionImage,
|
|
|
334214
334324
|
...parsed
|
|
334215
334325
|
};
|
|
334216
334326
|
if (includeRawUi) payload.perception.elements = elements;
|
|
334217
|
-
const imageAvailable = parsed.image_available === true &&
|
|
334327
|
+
const imageAvailable = parsed.image_available === true && fs9.existsSync(outPath);
|
|
334218
334328
|
if (allowEphemeralVisionImage && imageAvailable) {
|
|
334219
334329
|
payload.vision_image_path = outPath;
|
|
334220
334330
|
retainedForVision = true;
|
|
@@ -334477,7 +334587,7 @@ async function screenshot(workspacePath, ownerId, allowEphemeralVisionImage, inc
|
|
|
334477
334587
|
...parsed
|
|
334478
334588
|
};
|
|
334479
334589
|
if (includeRawUi) payload.perception.elements = ui.elements;
|
|
334480
|
-
const imageAvailable = parsed.image_available === true &&
|
|
334590
|
+
const imageAvailable = parsed.image_available === true && fs9.existsSync(outPath);
|
|
334481
334591
|
if (allowEphemeralVisionImage && imageAvailable) {
|
|
334482
334592
|
payload.vision_image_path = outPath;
|
|
334483
334593
|
retainedForVision = true;
|
|
@@ -334801,13 +334911,13 @@ async function runComputerUse(options) {
|
|
|
334801
334911
|
}
|
|
334802
334912
|
|
|
334803
334913
|
// src/core/ssh.ts
|
|
334804
|
-
var
|
|
334805
|
-
var
|
|
334914
|
+
var fs11 = __toESM(require("fs"));
|
|
334915
|
+
var path12 = __toESM(require("path"));
|
|
334806
334916
|
|
|
334807
334917
|
// src/core/asyncProcess.ts
|
|
334808
334918
|
var import_child_process4 = require("child_process");
|
|
334809
|
-
var
|
|
334810
|
-
var
|
|
334919
|
+
var fs10 = __toESM(require("fs/promises"));
|
|
334920
|
+
var path11 = __toESM(require("path"));
|
|
334811
334921
|
var STOP_SETTLEMENT_WATCHDOG_MS = 500;
|
|
334812
334922
|
function signalMessage(signal) {
|
|
334813
334923
|
const reason = signal?.reason;
|
|
@@ -334817,7 +334927,7 @@ function signalMessage(signal) {
|
|
|
334817
334927
|
}
|
|
334818
334928
|
function trustedWindowsTaskkillPath() {
|
|
334819
334929
|
const windowsRoot = String(process.env.SystemRoot || process.env.WINDIR || "C:\\Windows");
|
|
334820
|
-
return
|
|
334930
|
+
return path11.join(windowsRoot, "System32", "taskkill.exe");
|
|
334821
334931
|
}
|
|
334822
334932
|
function stopProcessTree(child) {
|
|
334823
334933
|
const pid = child.pid;
|
|
@@ -334986,7 +335096,7 @@ async function runAsyncWindowsBatch(command, args, options = {}) {
|
|
|
334986
335096
|
}
|
|
334987
335097
|
async function accessible(filePath) {
|
|
334988
335098
|
try {
|
|
334989
|
-
await
|
|
335099
|
+
await fs10.access(filePath);
|
|
334990
335100
|
return true;
|
|
334991
335101
|
} catch {
|
|
334992
335102
|
return false;
|
|
@@ -334995,14 +335105,14 @@ async function accessible(filePath) {
|
|
|
334995
335105
|
async function resolveWindowsLauncher(command) {
|
|
334996
335106
|
const clean = String(command || "").trim();
|
|
334997
335107
|
if (!clean) return "";
|
|
334998
|
-
if (
|
|
334999
|
-
const absolute =
|
|
335108
|
+
if (path11.isAbsolute(clean) || /[\\/]/.test(clean)) {
|
|
335109
|
+
const absolute = path11.resolve(clean);
|
|
335000
335110
|
return await accessible(absolute) ? absolute : "";
|
|
335001
335111
|
}
|
|
335002
|
-
for (const entry of String(process.env.PATH || "").split(
|
|
335112
|
+
for (const entry of String(process.env.PATH || "").split(path11.delimiter)) {
|
|
335003
335113
|
const directory = entry.trim().replace(/^"|"$/g, "");
|
|
335004
335114
|
if (!directory) continue;
|
|
335005
|
-
const candidate =
|
|
335115
|
+
const candidate = path11.join(directory, clean);
|
|
335006
335116
|
if (await accessible(candidate)) return candidate;
|
|
335007
335117
|
}
|
|
335008
335118
|
return "";
|
|
@@ -335010,11 +335120,11 @@ async function resolveWindowsLauncher(command) {
|
|
|
335010
335120
|
async function resolveNpmBatchTarget(batchPath) {
|
|
335011
335121
|
let source = "";
|
|
335012
335122
|
try {
|
|
335013
|
-
source = await
|
|
335123
|
+
source = await fs10.readFile(batchPath, "utf8");
|
|
335014
335124
|
} catch {
|
|
335015
335125
|
return null;
|
|
335016
335126
|
}
|
|
335017
|
-
const directory =
|
|
335127
|
+
const directory = path11.dirname(batchPath);
|
|
335018
335128
|
let relativeScript = "";
|
|
335019
335129
|
const direct = /(?:%~dp0|%dp0%)\\?([^"\r\n]+)"\s+%\*/i.exec(source);
|
|
335020
335130
|
if (direct) relativeScript = direct[1];
|
|
@@ -335028,10 +335138,10 @@ async function resolveNpmBatchTarget(batchPath) {
|
|
|
335028
335138
|
}
|
|
335029
335139
|
}
|
|
335030
335140
|
if (!relativeScript) return null;
|
|
335031
|
-
const scriptPath =
|
|
335032
|
-
const directoryPrefix = `${
|
|
335141
|
+
const scriptPath = path11.resolve(directory, relativeScript.replace(/\\/g, path11.sep));
|
|
335142
|
+
const directoryPrefix = `${path11.resolve(directory).toLowerCase()}${path11.sep}`;
|
|
335033
335143
|
if (!scriptPath.toLowerCase().startsWith(directoryPrefix) || !await accessible(scriptPath)) return null;
|
|
335034
|
-
const siblingNode =
|
|
335144
|
+
const siblingNode = path11.join(directory, "node.exe");
|
|
335035
335145
|
const nodePath = await accessible(siblingNode) ? siblingNode : await resolveWindowsLauncher("node.exe") || await resolveWindowsLauncher("node");
|
|
335036
335146
|
return nodePath ? { nodePath, scriptPath } : null;
|
|
335037
335147
|
}
|
|
@@ -335074,19 +335184,19 @@ var SshManager = class {
|
|
|
335074
335184
|
rootPath;
|
|
335075
335185
|
runner;
|
|
335076
335186
|
storePath() {
|
|
335077
|
-
return
|
|
335187
|
+
return path12.join(this.rootPath, "Work", "SSH.json");
|
|
335078
335188
|
}
|
|
335079
335189
|
ensureStore() {
|
|
335080
335190
|
try {
|
|
335081
|
-
|
|
335082
|
-
if (!
|
|
335191
|
+
fs11.mkdirSync(path12.join(this.rootPath, "Work"), { recursive: true });
|
|
335192
|
+
if (!fs11.existsSync(this.storePath())) fs11.writeFileSync(this.storePath(), "[]", "utf-8");
|
|
335083
335193
|
} catch {
|
|
335084
335194
|
}
|
|
335085
335195
|
}
|
|
335086
335196
|
readRaw() {
|
|
335087
335197
|
this.ensureStore();
|
|
335088
335198
|
try {
|
|
335089
|
-
const parsed = JSON.parse(
|
|
335199
|
+
const parsed = JSON.parse(fs11.readFileSync(this.storePath(), "utf-8").replace(/^\uFEFF/, ""));
|
|
335090
335200
|
if (!Array.isArray(parsed)) return [];
|
|
335091
335201
|
return parsed.map((item) => this.normalize(item)).filter((item) => !!item);
|
|
335092
335202
|
} catch {
|
|
@@ -335095,7 +335205,7 @@ var SshManager = class {
|
|
|
335095
335205
|
}
|
|
335096
335206
|
writeRaw(items) {
|
|
335097
335207
|
this.ensureStore();
|
|
335098
|
-
|
|
335208
|
+
fs11.writeFileSync(this.storePath(), JSON.stringify(items, null, 2), "utf-8");
|
|
335099
335209
|
}
|
|
335100
335210
|
normalize(raw) {
|
|
335101
335211
|
if (!raw || typeof raw !== "object" || Array.isArray(raw)) return null;
|
|
@@ -335275,8 +335385,8 @@ var SshManager = class {
|
|
|
335275
335385
|
};
|
|
335276
335386
|
|
|
335277
335387
|
// src/core/workspace.ts
|
|
335278
|
-
var
|
|
335279
|
-
var
|
|
335388
|
+
var fs12 = __toESM(require("fs"));
|
|
335389
|
+
var path13 = __toESM(require("path"));
|
|
335280
335390
|
var crypto7 = __toESM(require("crypto"));
|
|
335281
335391
|
function lastEmbeddedWindowsPath(input2) {
|
|
335282
335392
|
const matcher = /[A-Za-z]:[\\/]/g;
|
|
@@ -335295,22 +335405,22 @@ function normalizeHostWorkspacePath(input2, platform = process.platform) {
|
|
|
335295
335405
|
const raw = String(input2 || "").trim();
|
|
335296
335406
|
const embeddedWindowsPath = lastEmbeddedWindowsPath(raw);
|
|
335297
335407
|
if (platform === "win32") {
|
|
335298
|
-
if (embeddedWindowsPath) return
|
|
335408
|
+
if (embeddedWindowsPath) return path13.win32.normalize(embeddedWindowsPath.replace(/\//g, "\\"));
|
|
335299
335409
|
const wsl = /^\/mnt\/([a-zA-Z])(?:\/(.*))?$/.exec(raw.replace(/\\/g, "/"));
|
|
335300
|
-
if (wsl) return
|
|
335301
|
-
return
|
|
335410
|
+
if (wsl) return path13.win32.normalize(`${wsl[1].toUpperCase()}:\\${String(wsl[2] || "").replace(/\//g, "\\")}`);
|
|
335411
|
+
return path13.win32.resolve(raw || ".");
|
|
335302
335412
|
}
|
|
335303
335413
|
if (platform === "linux" && embeddedWindowsPath) {
|
|
335304
335414
|
const drive = embeddedWindowsPath[0].toLowerCase();
|
|
335305
335415
|
const rest = embeddedWindowsPath.slice(3).replace(/\\/g, "/").replace(/^\/+/, "");
|
|
335306
|
-
return
|
|
335416
|
+
return path13.posix.resolve(`/mnt/${drive}/${rest}`);
|
|
335307
335417
|
}
|
|
335308
|
-
return
|
|
335418
|
+
return path13.posix.resolve(raw || ".");
|
|
335309
335419
|
}
|
|
335310
335420
|
function isPathInside(parent, child) {
|
|
335311
335421
|
try {
|
|
335312
|
-
const relative6 =
|
|
335313
|
-
return relative6 === "" || !!relative6 && !relative6.startsWith("..") && !
|
|
335422
|
+
const relative6 = path13.relative(path13.resolve(parent), path13.resolve(child));
|
|
335423
|
+
return relative6 === "" || !!relative6 && !relative6.startsWith("..") && !path13.isAbsolute(relative6);
|
|
335314
335424
|
} catch {
|
|
335315
335425
|
return false;
|
|
335316
335426
|
}
|
|
@@ -335318,7 +335428,7 @@ function isPathInside(parent, child) {
|
|
|
335318
335428
|
function isProtectedInstallWorkspacePath(candidate) {
|
|
335319
335429
|
const value = String(candidate || "").trim();
|
|
335320
335430
|
if (!value) return false;
|
|
335321
|
-
const roots = [
|
|
335431
|
+
const roots = [path13.dirname(process.execPath)];
|
|
335322
335432
|
if (process.platform === "win32") {
|
|
335323
335433
|
roots.push(
|
|
335324
335434
|
process.env.ProgramFiles || "",
|
|
@@ -335326,7 +335436,7 @@ function isProtectedInstallWorkspacePath(candidate) {
|
|
|
335326
335436
|
process.env.ProgramW6432 || ""
|
|
335327
335437
|
);
|
|
335328
335438
|
}
|
|
335329
|
-
const resolved =
|
|
335439
|
+
const resolved = path13.resolve(value);
|
|
335330
335440
|
return roots.filter(Boolean).some((root2) => isPathInside(root2, resolved));
|
|
335331
335441
|
}
|
|
335332
335442
|
var WorkspaceManager = class {
|
|
@@ -335336,16 +335446,16 @@ var WorkspaceManager = class {
|
|
|
335336
335446
|
this.detached = options.detached === true;
|
|
335337
335447
|
this.pcHash = this.loadPcHash();
|
|
335338
335448
|
if (this.detached) return;
|
|
335339
|
-
const workDir =
|
|
335449
|
+
const workDir = path13.join(rootPath, "Work");
|
|
335340
335450
|
try {
|
|
335341
|
-
|
|
335451
|
+
fs12.mkdirSync(workDir, { recursive: true });
|
|
335342
335452
|
} catch {
|
|
335343
335453
|
}
|
|
335344
335454
|
for (const fn of ["Local.json", "External.json"]) {
|
|
335345
|
-
const p =
|
|
335346
|
-
if (!
|
|
335455
|
+
const p = path13.join(workDir, fn);
|
|
335456
|
+
if (!fs12.existsSync(p)) {
|
|
335347
335457
|
try {
|
|
335348
|
-
|
|
335458
|
+
fs12.writeFileSync(p, "[]", "utf-8");
|
|
335349
335459
|
} catch {
|
|
335350
335460
|
}
|
|
335351
335461
|
}
|
|
@@ -335366,7 +335476,7 @@ var WorkspaceManager = class {
|
|
|
335366
335476
|
detached;
|
|
335367
335477
|
loadPcHash() {
|
|
335368
335478
|
try {
|
|
335369
|
-
const h2 =
|
|
335479
|
+
const h2 = fs12.readFileSync(path13.join(this.rootPath, "PC_Hash.config"), "utf-8");
|
|
335370
335480
|
return h2.trim();
|
|
335371
335481
|
} catch {
|
|
335372
335482
|
return "";
|
|
@@ -335381,19 +335491,19 @@ var WorkspaceManager = class {
|
|
|
335381
335491
|
if (this.external.length !== before) this.saveExternal();
|
|
335382
335492
|
}
|
|
335383
335493
|
scan() {
|
|
335384
|
-
const w =
|
|
335385
|
-
if (!
|
|
335494
|
+
const w = path13.join(this.rootPath, "Work");
|
|
335495
|
+
if (!fs12.existsSync(w)) return;
|
|
335386
335496
|
let internalChanged = false;
|
|
335387
335497
|
let externalChanged = false;
|
|
335388
335498
|
try {
|
|
335389
|
-
const local = JSON.parse(
|
|
335499
|
+
const local = JSON.parse(fs12.readFileSync(path13.join(w, "Local.json"), "utf-8"));
|
|
335390
335500
|
this.internal = Array.isArray(local) ? local.map((item) => this.normalizeInternalWorkspace(item, (changed) => {
|
|
335391
335501
|
internalChanged = internalChanged || changed;
|
|
335392
335502
|
})) : [];
|
|
335393
335503
|
} catch {
|
|
335394
335504
|
}
|
|
335395
335505
|
try {
|
|
335396
|
-
const ext = JSON.parse(
|
|
335506
|
+
const ext = JSON.parse(fs12.readFileSync(path13.join(w, "External.json"), "utf-8"));
|
|
335397
335507
|
const normalized = Array.isArray(ext) ? ext.map((item) => this.normalizeExternalWorkspace(item, (changed) => {
|
|
335398
335508
|
externalChanged = externalChanged || changed;
|
|
335399
335509
|
})) : [];
|
|
@@ -335404,13 +335514,13 @@ var WorkspaceManager = class {
|
|
|
335404
335514
|
});
|
|
335405
335515
|
} catch {
|
|
335406
335516
|
}
|
|
335407
|
-
for (const entry of
|
|
335517
|
+
for (const entry of fs12.readdirSync(w, { withFileTypes: true })) {
|
|
335408
335518
|
if (entry.isDirectory() && !["Local.json", "External.json", ".ssh"].includes(entry.name)) {
|
|
335409
335519
|
if (!this.internal.find((wi) => wi.name === entry.name)) {
|
|
335410
335520
|
this.internal.push({
|
|
335411
|
-
id: this.stableWorkspaceId("local",
|
|
335521
|
+
id: this.stableWorkspaceId("local", path13.join(w, entry.name)),
|
|
335412
335522
|
name: entry.name,
|
|
335413
|
-
path:
|
|
335523
|
+
path: path13.join(w, entry.name),
|
|
335414
335524
|
isInternal: true,
|
|
335415
335525
|
hostBinding: "",
|
|
335416
335526
|
icon: entry.name.charAt(0).toUpperCase()
|
|
@@ -335423,9 +335533,9 @@ var WorkspaceManager = class {
|
|
|
335423
335533
|
if (externalChanged) this.saveExternal();
|
|
335424
335534
|
}
|
|
335425
335535
|
normalizeInternalWorkspace(input2, markChanged) {
|
|
335426
|
-
const rawName = String(input2?.name ||
|
|
335536
|
+
const rawName = String(input2?.name || path13.basename(String(input2?.path || "")) || "").trim();
|
|
335427
335537
|
const name50 = rawName || (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "").replace("T", "_").slice(0, 15);
|
|
335428
|
-
const expectedPath =
|
|
335538
|
+
const expectedPath = path13.join(this.rootPath, "Work", name50);
|
|
335429
335539
|
const id = this.stableWorkspaceId("local", expectedPath);
|
|
335430
335540
|
if (normalizeHostWorkspacePath(String(input2?.path || "")) !== normalizeHostWorkspacePath(expectedPath) || input2?.isInternal !== true || input2?.id !== id) markChanged(true);
|
|
335431
335541
|
return {
|
|
@@ -335446,11 +335556,11 @@ var WorkspaceManager = class {
|
|
|
335446
335556
|
return {
|
|
335447
335557
|
...input2,
|
|
335448
335558
|
id,
|
|
335449
|
-
name: String(input2?.name ||
|
|
335559
|
+
name: String(input2?.name || path13.basename(workspacePath) || id),
|
|
335450
335560
|
path: workspacePath,
|
|
335451
335561
|
isInternal: false,
|
|
335452
335562
|
hostBinding: String(input2?.hostBinding || ""),
|
|
335453
|
-
icon: String(input2?.icon ||
|
|
335563
|
+
icon: String(input2?.icon || path13.basename(workspacePath).charAt(0).toUpperCase()),
|
|
335454
335564
|
kind
|
|
335455
335565
|
};
|
|
335456
335566
|
}
|
|
@@ -335471,11 +335581,11 @@ var WorkspaceManager = class {
|
|
|
335471
335581
|
const resolved = normalizeHostWorkspacePath(target);
|
|
335472
335582
|
let real = resolved;
|
|
335473
335583
|
try {
|
|
335474
|
-
real =
|
|
335584
|
+
real = fs12.existsSync(resolved) ? fs12.realpathSync.native(resolved) : resolved;
|
|
335475
335585
|
} catch {
|
|
335476
335586
|
real = resolved;
|
|
335477
335587
|
}
|
|
335478
|
-
const normalized =
|
|
335588
|
+
const normalized = path13.normalize(real).replace(/[\\/]+$/, "");
|
|
335479
335589
|
return process.platform === "win32" ? normalized.toLowerCase() : normalized;
|
|
335480
335590
|
}
|
|
335481
335591
|
stableWorkspaceId(kind, workspacePath) {
|
|
@@ -335501,8 +335611,8 @@ var WorkspaceManager = class {
|
|
|
335501
335611
|
isInsideRoot(target) {
|
|
335502
335612
|
const root2 = this.canonicalWorkspacePath(this.rootPath);
|
|
335503
335613
|
const candidate = this.canonicalWorkspacePath(target);
|
|
335504
|
-
const rel =
|
|
335505
|
-
return rel === "" || !!rel && !rel.startsWith("..") && !
|
|
335614
|
+
const rel = path13.relative(root2, candidate);
|
|
335615
|
+
return rel === "" || !!rel && !rel.startsWith("..") && !path13.isAbsolute(rel);
|
|
335506
335616
|
}
|
|
335507
335617
|
canonicalRemotePath(target) {
|
|
335508
335618
|
let cleaned = String(target || "").trim().replace(/\\/g, "/").replace(/\/+$/g, "");
|
|
@@ -335531,13 +335641,13 @@ var WorkspaceManager = class {
|
|
|
335531
335641
|
return deduped;
|
|
335532
335642
|
}
|
|
335533
335643
|
statePath() {
|
|
335534
|
-
return
|
|
335644
|
+
return path13.join(this.rootPath, "Work", "State.json");
|
|
335535
335645
|
}
|
|
335536
335646
|
readState() {
|
|
335537
335647
|
const p = this.statePath();
|
|
335538
|
-
if (!
|
|
335648
|
+
if (!fs12.existsSync(p)) return {};
|
|
335539
335649
|
try {
|
|
335540
|
-
const raw =
|
|
335650
|
+
const raw = fs12.readFileSync(p, "utf-8").replace(/^\uFEFF/, "");
|
|
335541
335651
|
const parsed = JSON.parse(raw);
|
|
335542
335652
|
if (parsed && typeof parsed === "object") return parsed;
|
|
335543
335653
|
} catch {
|
|
@@ -335558,8 +335668,8 @@ var WorkspaceManager = class {
|
|
|
335558
335668
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
335559
335669
|
};
|
|
335560
335670
|
try {
|
|
335561
|
-
|
|
335562
|
-
|
|
335671
|
+
fs12.mkdirSync(path13.dirname(p), { recursive: true });
|
|
335672
|
+
fs12.writeFileSync(p, JSON.stringify(state, null, 2), "utf-8");
|
|
335563
335673
|
} catch {
|
|
335564
335674
|
}
|
|
335565
335675
|
}
|
|
@@ -335618,17 +335728,17 @@ var WorkspaceManager = class {
|
|
|
335618
335728
|
}
|
|
335619
335729
|
saveInternal() {
|
|
335620
335730
|
if (this.detached) return;
|
|
335621
|
-
const p =
|
|
335731
|
+
const p = path13.join(this.rootPath, "Work", "Local.json");
|
|
335622
335732
|
this.internal = this.dedupeByPath(this.internal);
|
|
335623
335733
|
this.sortWorkspaces();
|
|
335624
|
-
|
|
335734
|
+
fs12.writeFileSync(p, JSON.stringify(this.internal, null, 2), "utf-8");
|
|
335625
335735
|
}
|
|
335626
335736
|
saveExternal() {
|
|
335627
335737
|
if (this.detached) return;
|
|
335628
|
-
const p =
|
|
335738
|
+
const p = path13.join(this.rootPath, "Work", "External.json");
|
|
335629
335739
|
this.external = this.dedupeByPath(this.external);
|
|
335630
335740
|
this.sortWorkspaces();
|
|
335631
|
-
|
|
335741
|
+
fs12.writeFileSync(p, JSON.stringify(this.external, null, 2), "utf-8");
|
|
335632
335742
|
}
|
|
335633
335743
|
sleepSync(ms) {
|
|
335634
335744
|
if (ms <= 0) return;
|
|
@@ -335636,48 +335746,48 @@ var WorkspaceManager = class {
|
|
|
335636
335746
|
Atomics.wait(new Int32Array(buffer), 0, 0, ms);
|
|
335637
335747
|
}
|
|
335638
335748
|
isInternalWorkspacePath(target) {
|
|
335639
|
-
const workRoot =
|
|
335640
|
-
const resolved =
|
|
335641
|
-
const rel =
|
|
335642
|
-
return !!rel && !rel.startsWith("..") && !
|
|
335749
|
+
const workRoot = path13.resolve(this.rootPath, "Work");
|
|
335750
|
+
const resolved = path13.resolve(target);
|
|
335751
|
+
const rel = path13.relative(workRoot, resolved);
|
|
335752
|
+
return !!rel && !rel.startsWith("..") && !path13.isAbsolute(rel);
|
|
335643
335753
|
}
|
|
335644
335754
|
clearReadOnlyRecursive(target) {
|
|
335645
|
-
if (!
|
|
335646
|
-
const stat =
|
|
335755
|
+
if (!fs12.existsSync(target)) return;
|
|
335756
|
+
const stat = fs12.lstatSync(target);
|
|
335647
335757
|
try {
|
|
335648
|
-
|
|
335758
|
+
fs12.chmodSync(target, stat.mode | 448);
|
|
335649
335759
|
} catch {
|
|
335650
335760
|
}
|
|
335651
335761
|
if (!stat.isDirectory()) return;
|
|
335652
|
-
for (const entry of
|
|
335653
|
-
this.clearReadOnlyRecursive(
|
|
335762
|
+
for (const entry of fs12.readdirSync(target)) {
|
|
335763
|
+
this.clearReadOnlyRecursive(path13.join(target, entry));
|
|
335654
335764
|
}
|
|
335655
335765
|
}
|
|
335656
335766
|
removeInternalDirectory(target) {
|
|
335657
|
-
const resolved =
|
|
335767
|
+
const resolved = path13.resolve(target);
|
|
335658
335768
|
if (!this.isInternalWorkspacePath(resolved)) return false;
|
|
335659
|
-
if (!
|
|
335769
|
+
if (!fs12.existsSync(resolved)) return true;
|
|
335660
335770
|
const delays = [0, 50, 100, 200, 400, 800, 1200];
|
|
335661
335771
|
for (const delay of delays) {
|
|
335662
335772
|
this.sleepSync(delay);
|
|
335663
335773
|
try {
|
|
335664
|
-
|
|
335774
|
+
fs12.rmSync(resolved, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 });
|
|
335665
335775
|
} catch {
|
|
335666
335776
|
}
|
|
335667
|
-
if (!
|
|
335777
|
+
if (!fs12.existsSync(resolved)) return true;
|
|
335668
335778
|
try {
|
|
335669
335779
|
this.clearReadOnlyRecursive(resolved);
|
|
335670
|
-
|
|
335780
|
+
fs12.rmSync(resolved, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 });
|
|
335671
335781
|
} catch {
|
|
335672
335782
|
}
|
|
335673
|
-
if (!
|
|
335783
|
+
if (!fs12.existsSync(resolved)) return true;
|
|
335674
335784
|
}
|
|
335675
335785
|
return false;
|
|
335676
335786
|
}
|
|
335677
335787
|
createInternal(name50) {
|
|
335678
335788
|
const n3 = name50 || (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "").replace("T", "_").slice(0, 15);
|
|
335679
|
-
const d3 =
|
|
335680
|
-
|
|
335789
|
+
const d3 = path13.join(this.rootPath, "Work", n3);
|
|
335790
|
+
fs12.mkdirSync(d3, { recursive: true });
|
|
335681
335791
|
const existing = this.findWorkspaceByPath(d3);
|
|
335682
335792
|
if (existing) {
|
|
335683
335793
|
this.current = existing;
|
|
@@ -335699,15 +335809,15 @@ var WorkspaceManager = class {
|
|
|
335699
335809
|
return ws;
|
|
335700
335810
|
}
|
|
335701
335811
|
addExternal(p) {
|
|
335702
|
-
const resolved =
|
|
335703
|
-
if (!
|
|
335812
|
+
const resolved = path13.resolve(p);
|
|
335813
|
+
if (!fs12.existsSync(resolved) || this.isInsideRoot(resolved)) return null;
|
|
335704
335814
|
const existing = this.findWorkspaceByPath(resolved);
|
|
335705
335815
|
if (existing) {
|
|
335706
335816
|
this.current = existing;
|
|
335707
335817
|
this.saveState();
|
|
335708
335818
|
return existing;
|
|
335709
335819
|
}
|
|
335710
|
-
const name50 =
|
|
335820
|
+
const name50 = path13.basename(resolved);
|
|
335711
335821
|
const ws = {
|
|
335712
335822
|
id: this.stableWorkspaceId("local", resolved),
|
|
335713
335823
|
name: name50,
|
|
@@ -335725,10 +335835,10 @@ var WorkspaceManager = class {
|
|
|
335725
335835
|
addSshExternal(input2) {
|
|
335726
335836
|
if (!input2.sshConnectionId || !input2.remotePath || !input2.remotePcHash) return null;
|
|
335727
335837
|
const remotePath = this.canonicalRemotePath(input2.remotePath);
|
|
335728
|
-
const baseName = (input2.name ||
|
|
335838
|
+
const baseName = (input2.name || path13.basename(remotePath.replace(/[\\/]+$/, "")) || input2.sshConnectionId || "ssh-workspace").trim();
|
|
335729
335839
|
const safeName = baseName.replace(/[<>:"/\\|?*\x00-\x1F]/g, "-").replace(/\s+/g, " ").trim() || "ssh-workspace";
|
|
335730
|
-
const shadowRoot = input2.localPath ?
|
|
335731
|
-
|
|
335840
|
+
const shadowRoot = input2.localPath ? path13.resolve(input2.localPath) : path13.join(this.rootPath, "Work", ".ssh", `${input2.sshConnectionId}-${crypto7.createHash("sha256").update(remotePath).digest("hex").slice(0, 16)}`);
|
|
335841
|
+
fs12.mkdirSync(shadowRoot, { recursive: true });
|
|
335732
335842
|
const existing = this.findSshWorkspaceByRemotePath(input2.sshConnectionId, remotePath);
|
|
335733
335843
|
const ws = {
|
|
335734
335844
|
...existing || {},
|
|
@@ -335810,7 +335920,7 @@ var WorkspaceManager = class {
|
|
|
335810
335920
|
currentAgentPrompt() {
|
|
335811
335921
|
if (!this.current) return null;
|
|
335812
335922
|
try {
|
|
335813
|
-
return
|
|
335923
|
+
return fs12.readFileSync(path13.join(this.current.path, "agent.md"), "utf-8");
|
|
335814
335924
|
} catch {
|
|
335815
335925
|
return null;
|
|
335816
335926
|
}
|
|
@@ -335819,8 +335929,8 @@ var WorkspaceManager = class {
|
|
|
335819
335929
|
const perm = this.config.getStr("workspace", "access_permission");
|
|
335820
335930
|
if (perm === "full_access") return true;
|
|
335821
335931
|
if (!this.current) return perm !== "no_outside_access";
|
|
335822
|
-
const rel =
|
|
335823
|
-
const inside2 = rel === "" || !!rel && !rel.startsWith("..") && !
|
|
335932
|
+
const rel = path13.relative(path13.resolve(this.current.path), path13.resolve(target));
|
|
335933
|
+
const inside2 = rel === "" || !!rel && !rel.startsWith("..") && !path13.isAbsolute(rel);
|
|
335824
335934
|
if (inside2) return true;
|
|
335825
335935
|
return perm !== "no_outside_access";
|
|
335826
335936
|
}
|
|
@@ -335903,6 +336013,7 @@ var PLAN_COMPUTER_USE_ACTIONS = ["observe", "app_list", "app_observe"];
|
|
|
335903
336013
|
var PLAN_BROWSER_USE_ACTIONS = ["observe", "navigate", "wait", "extract"];
|
|
335904
336014
|
var PLAN_COMPUTER_USE_ACTION_SET = new Set(PLAN_COMPUTER_USE_ACTIONS);
|
|
335905
336015
|
var PLAN_BROWSER_USE_ACTION_SET = new Set(PLAN_BROWSER_USE_ACTIONS);
|
|
336016
|
+
var CHAT_WEB_TOOLS = /* @__PURE__ */ new Set(["web_search", "web_fetch"]);
|
|
335906
336017
|
var CONCURRENCY_SAFE_TOOLS = /* @__PURE__ */ new Set([
|
|
335907
336018
|
"pwd",
|
|
335908
336019
|
"read",
|
|
@@ -335936,6 +336047,13 @@ function evaluateToolPolicy(request) {
|
|
|
335936
336047
|
const availability = toolAvailability(name50);
|
|
335937
336048
|
const base2 = { availability, settingsVisible: availability === "configurable" };
|
|
335938
336049
|
if (!name50) return { ...base2, allowed: false, reason: "[permission] Tool name is required." };
|
|
336050
|
+
if (request.mode === "chat" && !CHAT_WEB_TOOLS.has(name50)) {
|
|
336051
|
+
return {
|
|
336052
|
+
...base2,
|
|
336053
|
+
allowed: false,
|
|
336054
|
+
reason: `[permission] Chat mode only allows web_search and web_fetch. It has no workspace, host, application, memory, task, or other write access. Blocked: ${name50}`
|
|
336055
|
+
};
|
|
336056
|
+
}
|
|
335939
336057
|
if (request.mode === "plan") {
|
|
335940
336058
|
if (name50 === "computer_use") {
|
|
335941
336059
|
const action = String(request.args?.action || "").trim();
|
|
@@ -335977,6 +336095,13 @@ function planModePolicyPrompt() {
|
|
|
335977
336095
|
"Runtime policy rejects stale or hidden mutating tool calls even if a prompt asks for them."
|
|
335978
336096
|
].join(" ");
|
|
335979
336097
|
}
|
|
336098
|
+
function chatModePolicyPrompt() {
|
|
336099
|
+
return [
|
|
336100
|
+
"Chat mode is a narrow web-evidence mode.",
|
|
336101
|
+
"Only web_search and web_fetch are available; every workspace, host, application, memory, task, browser-control, and write capability is denied at runtime.",
|
|
336102
|
+
"Search the web for relevant evidence, fetch primary or authoritative sources when useful, then summarize and answer promptly instead of expanding into a long-running task."
|
|
336103
|
+
].join(" ");
|
|
336104
|
+
}
|
|
335980
336105
|
var DELETE_VERB_SOURCE = "(?:remove-item|rmdir|unlink|erase|del|rm|rd|ri)";
|
|
335981
336106
|
var DELETE_VERB_BOUNDARY = new RegExp(`(?:^|[\\s;&|()\\n])${DELETE_VERB_SOURCE}(?:\\s|$)`, "i");
|
|
335982
336107
|
function hasDeletionVerb(text) {
|
|
@@ -336254,7 +336379,7 @@ function requestUtilityHostTool(tool, args, context, timeoutMs = 12e4, signal) {
|
|
|
336254
336379
|
}
|
|
336255
336380
|
|
|
336256
336381
|
// src/core/nativeBash.ts
|
|
336257
|
-
var
|
|
336382
|
+
var path14 = __toESM(require("path"));
|
|
336258
336383
|
var import_module = require("module");
|
|
336259
336384
|
var MAX_OUTPUT_BYTES = 1024 * 1024;
|
|
336260
336385
|
var DEFAULT_TIMEOUT_MS = 3e4;
|
|
@@ -336342,11 +336467,11 @@ function normalizedTimeout(timeoutMs) {
|
|
|
336342
336467
|
}
|
|
336343
336468
|
function virtualCwd(workspaceRoot, requestedCwd) {
|
|
336344
336469
|
if (!requestedCwd) return "/";
|
|
336345
|
-
const root2 =
|
|
336346
|
-
const cwd =
|
|
336347
|
-
const relative6 =
|
|
336348
|
-
if (relative6.startsWith("..") ||
|
|
336349
|
-
return relative6 ? `/${relative6.split(
|
|
336470
|
+
const root2 = path14.resolve(workspaceRoot);
|
|
336471
|
+
const cwd = path14.resolve(requestedCwd);
|
|
336472
|
+
const relative6 = path14.relative(root2, cwd);
|
|
336473
|
+
if (relative6.startsWith("..") || path14.isAbsolute(relative6)) return "/";
|
|
336474
|
+
return relative6 ? `/${relative6.split(path14.sep).join("/")}` : "/";
|
|
336350
336475
|
}
|
|
336351
336476
|
function combineAbortSignals(signal, timeoutMs) {
|
|
336352
336477
|
const controller = new AbortController();
|
|
@@ -336372,7 +336497,7 @@ function createBash(workspaceRoot, timeoutMs) {
|
|
|
336372
336497
|
const justBash = loadJustBash();
|
|
336373
336498
|
if (!justBash) throw new Error("Native Bash runtime unavailable");
|
|
336374
336499
|
const fs27 = new justBash.ReadWriteFs({
|
|
336375
|
-
root:
|
|
336500
|
+
root: path14.resolve(workspaceRoot),
|
|
336376
336501
|
maxFileReadSize: MAX_OUTPUT_BYTES * 8,
|
|
336377
336502
|
allowSymlinks: false
|
|
336378
336503
|
});
|
|
@@ -336461,12 +336586,12 @@ async function executeWorkspaceBash(script, workspaceRoot, options = {}) {
|
|
|
336461
336586
|
}
|
|
336462
336587
|
|
|
336463
336588
|
// src/core/toolArgumentValidator.ts
|
|
336464
|
-
var
|
|
336465
|
-
var
|
|
336589
|
+
var fs13 = require("fs");
|
|
336590
|
+
var path15 = require("path");
|
|
336466
336591
|
var typeBoxCompilerPath = [
|
|
336467
|
-
|
|
336468
|
-
|
|
336469
|
-
].find((candidate) =>
|
|
336592
|
+
path15.join(__dirname, "..", "typebox-compile.bundle.cjs"),
|
|
336593
|
+
path15.join(__dirname, "typebox-compile.bundle.cjs")
|
|
336594
|
+
].find((candidate) => fs13.existsSync(candidate));
|
|
336470
336595
|
if (!typeBoxCompilerPath) throw new Error("Bundled TypeBox compiler is missing from the Newmark runtime.");
|
|
336471
336596
|
var { Compile } = require(typeBoxCompilerPath);
|
|
336472
336597
|
function closeToolArgumentSchema(input2) {
|
|
@@ -336556,8 +336681,8 @@ function formatValidationErrors(name50, errors) {
|
|
|
336556
336681
|
}
|
|
336557
336682
|
|
|
336558
336683
|
// src/core/localOcr.ts
|
|
336559
|
-
var
|
|
336560
|
-
var
|
|
336684
|
+
var fs14 = __toESM(require("fs"));
|
|
336685
|
+
var path16 = __toESM(require("path"));
|
|
336561
336686
|
var AGENT_REPAIR_PROMPT = [
|
|
336562
336687
|
"The local OCR output is approximate Chinese/English fallback evidence.",
|
|
336563
336688
|
"Repair likely OCR substitutions, spacing, and line breaks using the visible UI/PDF context and the user task.",
|
|
@@ -336590,12 +336715,12 @@ var LocalOcrEngine = class {
|
|
|
336590
336715
|
return await this.recognize(dataUrlBuffer(dataUrl), signal, profile);
|
|
336591
336716
|
}
|
|
336592
336717
|
async recognizeFile(filePath, signal) {
|
|
336593
|
-
const absolute =
|
|
336594
|
-
const extension =
|
|
336718
|
+
const absolute = path16.resolve(filePath);
|
|
336719
|
+
const extension = path16.extname(absolute).toLowerCase();
|
|
336595
336720
|
if (![".png", ".jpg", ".jpeg", ".bmp"].includes(extension)) {
|
|
336596
336721
|
throw new Error("Local OCR only accepts PNG, JPEG, or BMP images.");
|
|
336597
336722
|
}
|
|
336598
|
-
const stat =
|
|
336723
|
+
const stat = fs14.statSync(absolute);
|
|
336599
336724
|
if (!stat.isFile() || stat.size <= 0 || stat.size > 12 * 1024 * 1024) {
|
|
336600
336725
|
throw new Error("Local OCR image must be a regular file no larger than 12 MB.");
|
|
336601
336726
|
}
|
|
@@ -336649,7 +336774,7 @@ var LocalOcrEngine = class {
|
|
|
336649
336774
|
const tesseract = require_src();
|
|
336650
336775
|
const worker = await tesseract.createWorker("chi_sim+eng", tesseract.OEM.LSTM_ONLY, {
|
|
336651
336776
|
langPath: tessdataPath,
|
|
336652
|
-
cachePath:
|
|
336777
|
+
cachePath: path16.join(this.rootPath, "cache", "ocr-runtime"),
|
|
336653
336778
|
cacheMethod: "none",
|
|
336654
336779
|
gzip: true,
|
|
336655
336780
|
logger: () => void 0
|
|
@@ -336657,14 +336782,14 @@ var LocalOcrEngine = class {
|
|
|
336657
336782
|
return worker;
|
|
336658
336783
|
}
|
|
336659
336784
|
prepareLanguageCache() {
|
|
336660
|
-
const target =
|
|
336661
|
-
|
|
336785
|
+
const target = path16.join(this.rootPath, "cache", "ocr-tessdata");
|
|
336786
|
+
fs14.mkdirSync(target, { recursive: true });
|
|
336662
336787
|
for (const language of ["eng", "chi_sim"]) {
|
|
336663
|
-
const destination =
|
|
336664
|
-
if (
|
|
336665
|
-
const packageRoot =
|
|
336666
|
-
const source =
|
|
336667
|
-
|
|
336788
|
+
const destination = path16.join(target, `${language}.traineddata.gz`);
|
|
336789
|
+
if (fs14.existsSync(destination) && fs14.statSync(destination).size > 0) continue;
|
|
336790
|
+
const packageRoot = path16.dirname(require.resolve(`@tesseract.js-data/${language}/package.json`));
|
|
336791
|
+
const source = path16.join(packageRoot, "4.0.0_best_int", `${language}.traineddata.gz`);
|
|
336792
|
+
fs14.copyFileSync(source, destination);
|
|
336668
336793
|
}
|
|
336669
336794
|
return target;
|
|
336670
336795
|
}
|
|
@@ -336803,8 +336928,8 @@ function normalizeCrossEnvPath(value, wsPath) {
|
|
|
336803
336928
|
const posix3 = windowsDrivePathToPosix(raw);
|
|
336804
336929
|
if (posix3) return posix3;
|
|
336805
336930
|
}
|
|
336806
|
-
if (
|
|
336807
|
-
return
|
|
336931
|
+
if (path17.isAbsolute(raw)) return raw;
|
|
336932
|
+
return path17.join(wsPath, raw);
|
|
336808
336933
|
}
|
|
336809
336934
|
function translateWindowsPathsForWslBash(script) {
|
|
336810
336935
|
if (!process.env.NEWMARK_WSL_DISTRO) return script;
|
|
@@ -336818,7 +336943,7 @@ function translateWindowsPathsForWslBash(script) {
|
|
|
336818
336943
|
function computerUseOwner(context, wsPath) {
|
|
336819
336944
|
const conversationId = String(context.conversationId || "").trim();
|
|
336820
336945
|
if (conversationId) return `conversation:${conversationId}`;
|
|
336821
|
-
const resolved =
|
|
336946
|
+
const resolved = path17.resolve(context.workspacePath || wsPath || process.cwd());
|
|
336822
336947
|
const workspaceHash = crypto8.createHash("sha256").update(resolved).digest("hex").slice(0, 12);
|
|
336823
336948
|
return `direct:${workspaceHash}`;
|
|
336824
336949
|
}
|
|
@@ -336900,7 +337025,7 @@ function computerUseSessionScope(context, wsPath, owner) {
|
|
|
336900
337025
|
return {
|
|
336901
337026
|
runtimeKey: browserUseScope(context, wsPath).runtimeKey,
|
|
336902
337027
|
ownerLabel: owner,
|
|
336903
|
-
workspacePath:
|
|
337028
|
+
workspacePath: path17.resolve(wsPath || process.cwd())
|
|
336904
337029
|
};
|
|
336905
337030
|
}
|
|
336906
337031
|
function acquireComputerUseLock(action, owner, wsPath, context = {}, dryRun = false) {
|
|
@@ -337095,7 +337220,7 @@ var ToolExecutor = class {
|
|
|
337095
337220
|
t3("subagent_send", "Persist a mailbox message to a same-conversation peer agent. Target by exact id (preferred) or name.", { id: { type: "string", description: "Exact peer id from subagent_list." }, name: { type: "string", description: "Convenience peer name." }, message: { type: "string" }, prompt: { type: "string", description: "Legacy alias for message." }, kind: { type: "string", enum: ["directive", "question", "result", "handoff"] }, reply_to: { type: "string" }, correlation_id: { type: "string" } }, []),
|
|
337096
337221
|
t3("subagent_result", "Return the persisted transcript, mailbox summary, status, and latest result for a peer agent. Target by exact id (preferred) or name.", { id: { type: "string", description: "Exact peer id from subagent_list." }, name: { type: "string", description: "Convenience peer name." } }, []),
|
|
337097
337222
|
t3("subagent_close", "Close a same-conversation peer. Root can close any peer; a peer can close only itself. Target by exact id (preferred) or name.", { id: { type: "string", description: "Exact peer id from subagent_list." }, name: { type: "string", description: "Convenience peer name." } }, []),
|
|
337098
|
-
t3("linked_plan", "Read or update the current conversation linked Markdown plan. Update requires the
|
|
337223
|
+
t3("linked_plan", "Read or incrementally update the current conversation linked Markdown plan. Update requires expected_revision. Prefer append or old_text/new_text for local changes; markdown remains the legacy full replacement path.", { action: { type: "string", enum: ["get", "update"] }, markdown: { type: "string" }, append: { type: "string" }, old_text: { type: "string" }, new_text: { type: "string" }, replace_all: { type: "boolean" }, expected_revision: { type: "number" } }, ["action"]),
|
|
337099
337224
|
t3("build_history_query", "Read the concrete public work details (tool calls, results, file changes, guides) of one historical Build Block. Call it proactively when the current task continues, fixes, verifies, or depends on earlier work: reuse the returned activity instead of re-investigating from scratch. Do not call it merely to answer completion status already exposed by the prompt. Select by newest-to-oldest history_index, or by run_id returned from an earlier query. Every activity/guide content is bounded to max_chars (default 2000) to keep the read lean and cache-friendly.", { history_index: { type: "number", minimum: 1, description: "1-based historical Build Block index from the request ledger; 1 is the newest previous task." }, run_id: { type: "string", description: "Exact run id returned by an earlier build_history_query result." }, max_events: { type: "number", minimum: 1, maximum: 200, description: "Maximum trailing public work events; defaults to 80." }, max_chars: { type: "number", minimum: 100, maximum: 4e3, description: "Per-event/per-guide content character bound; defaults to 2000." } }, []),
|
|
337100
337225
|
t3("context_compress", "Actively compress the LLM context history for this conversation. This collapses older history entries into a concise summary while preserving the recent tail, which reduces context tokens and cost. IMPORTANT: it affects only the LLM context (what the model sees); the displayed conversation history shown to the user is never altered. Call this when the conversation is long, token pressure is high, or you judge that older turns are no longer needed in full. Idempotent and safe: repeated calls produce incremental summaries.", { keep_recent: { type: "number", minimum: 2, maximum: 60, description: "Recent message count to keep uncompressed at the tail. Defaults to the configured keep_recent_messages." }, force: { type: "boolean", description: "Compress even if the context is not yet over the automatic threshold. Defaults to false." } }, []),
|
|
337101
337226
|
t3("context_history_manage", "Manage the LLM context history for this conversation without affecting the displayed conversation history. This is the active context-management surface. The hot cache stays bounded; evicted folded segments remain in a conversation-isolated append-only cold archive and are loaded only by explicit search/read/restore calls. Actions: list returns a bounded index of current context entries; remove declares one long-term entry for unload (see below); summarize folds a contiguous current range; restore reinserts a folded segment when its summary marker is still present; search finds matching hot or archived segments; read returns one bounded segment without injecting the whole archive; status reports budgets, hot cache, cold archive, the protected recent zone, and pending removals. The recent context tail and last user message are protected from remove/summarize unless dangerous is true. For cache-optimization, remove ONLY targets long-term history (never the protected recent tail or last user message) and does NOT unload immediately: the declared entry stays in context for the rest of the current Build Block so the provider prefix cache stays stable, then is physically removed when the Block ends \u2014 applying to subsequent Blocks only.", {
|
|
@@ -337125,11 +337250,11 @@ var ToolExecutor = class {
|
|
|
337125
337250
|
t3("skill_download", "Download a skill", { name: { type: "string" }, source: { type: "string" } }, ["name", "source"]),
|
|
337126
337251
|
t3("skill", "Search enabled skill metadata or load one exact skill body on demand. Use query when unsure, then name to load the selected skill.", { query: { type: "string", maxLength: 200 }, name: { type: "string", maxLength: 200 } }, []),
|
|
337127
337252
|
t3("flow_list", "List available Newmark Flow workflows from the Flow folder so the agent can choose one.", {}, []),
|
|
337128
|
-
t3("flow_save", "
|
|
337253
|
+
t3("flow_save", "Create or incrementally update a Newmark Flow workflow. Use action=upsert with one component or action=delete with component_id and confirm=true for local edits. action=replace plus components remains the legacy full replacement path.", { name: { type: "string" }, action: { type: "string", enum: ["replace", "upsert", "delete"] }, components: { type: "array" }, component: { type: "object" }, component_id: { type: "number" }, confirm: { type: "boolean" } }, ["name"]),
|
|
337129
337254
|
t3("flow_run", "Trigger an existing Newmark Flow workflow by name with optional input and start component.", { name: { type: "string" }, input: { type: "string" }, start: { type: "number" } }, ["name"]),
|
|
337130
337255
|
t3("memory_lab_read", "Read Memory Lab index.json, its path, and usage instructions. Optionally pass component/name/slug to read a memory component core markdown.", { component: { type: "string" }, name: { type: "string" }, slug: { type: "string" } }, []),
|
|
337131
337256
|
t3("memory_lab_query", "Retrieve a bounded task-relevant Memory Lab set with deterministic scoring and adaptive early stopping. Prefer this over loading the complete index when a focused query is sufficient.", { query: { type: "string", minLength: 1 }, limit: { type: "number", minimum: 1, maximum: 12 }, max_chars: { type: "number", minimum: 1e3, maximum: 48e3 } }, ["query"]),
|
|
337132
|
-
t3("memory_lab_update", "
|
|
337257
|
+
t3("memory_lab_update", "Create or incrementally patch a Memory Lab component. Create with name/tags/content. For an existing component pass component plus expectedUpdatedAt and only changed fields; prefer contentAppend or oldText/newText for small body edits. Prior revisions are archived and stale writes fail closed.", { component: { type: "string" }, name: { type: "string" }, description: { type: "string" }, tags: { type: "array", items: { type: "string" } }, tagPaths: { type: "array", items: { type: "array", items: { type: "string" } } }, content: { type: "string" }, contentAppend: { type: "string" }, oldText: { type: "string" }, newText: { type: "string" }, replaceAll: { type: "boolean" }, kind: { type: "string", enum: ["file", "folder"] }, expectedUpdatedAt: { type: "string" }, reason: { type: "string" }, source: { type: "string" } }, []),
|
|
337133
337258
|
t3("memory_lab_delete", "DELETE obsolete durable memory only when the user explicitly asks to forget/remove it. The prior revision is moved to Memory Lab/archive and the Policy decision is logged.", { component: { type: "string" }, name: { type: "string" }, slug: { type: "string" }, expectedUpdatedAt: { type: "string" }, reason: { type: "string" }, source: { type: "string" } }, []),
|
|
337134
337259
|
t3("memory_lab_reindex", "Rebuild and organize Memory Lab index links. Routed through Agent runtime when invoked by the model.", {}, []),
|
|
337135
337260
|
t3("automation_list", "List persisted Newmark automations so the agent can inspect scheduled work.", {}, []),
|
|
@@ -337451,13 +337576,13 @@ var ToolExecutor = class {
|
|
|
337451
337576
|
}
|
|
337452
337577
|
case "pdf_read": {
|
|
337453
337578
|
const pdfPath = resolve16(g2("path"));
|
|
337454
|
-
if (
|
|
337455
|
-
const stat =
|
|
337579
|
+
if (path17.extname(pdfPath).toLowerCase() !== ".pdf") return "[pdf_read error] path must end in .pdf.";
|
|
337580
|
+
const stat = fs15.statSync(pdfPath);
|
|
337456
337581
|
if (!stat.isFile() || stat.size <= 0 || stat.size > 250 * 1024 * 1024) {
|
|
337457
337582
|
return "[pdf_read error] PDF must be a regular file no larger than 250 MB.";
|
|
337458
337583
|
}
|
|
337459
337584
|
const maxChars = Math.max(500, Math.min(1e5, Number(args.max_chars || 5e4)));
|
|
337460
|
-
const textLayer = extractPdfTextLayer(
|
|
337585
|
+
const textLayer = extractPdfTextLayer(fs15.readFileSync(pdfPath)).slice(0, maxChars);
|
|
337461
337586
|
const readableCount = (textLayer.match(/[A-Za-z0-9\u3400-\u9fff]/g) || []).length;
|
|
337462
337587
|
if (readableCount >= 20) {
|
|
337463
337588
|
return JSON.stringify({
|
|
@@ -337676,7 +337801,7 @@ var ToolExecutor = class {
|
|
|
337676
337801
|
case "flow_list":
|
|
337677
337802
|
return this.flowList();
|
|
337678
337803
|
case "flow_save":
|
|
337679
|
-
return this.flowSave(g2("name"), args
|
|
337804
|
+
return this.flowSave(g2("name"), args);
|
|
337680
337805
|
case "flow_run":
|
|
337681
337806
|
return `[flow_run] Routed to Agent runtime: ${g2("name")}`;
|
|
337682
337807
|
case "memory_lab_read":
|
|
@@ -337733,8 +337858,8 @@ var ToolExecutor = class {
|
|
|
337733
337858
|
}
|
|
337734
337859
|
}
|
|
337735
337860
|
isInside(parent, child) {
|
|
337736
|
-
const rel =
|
|
337737
|
-
return rel === "" || !!rel && !rel.startsWith("..") && !
|
|
337861
|
+
const rel = path17.relative(path17.resolve(parent), path17.resolve(child));
|
|
337862
|
+
return rel === "" || !!rel && !rel.startsWith("..") && !path17.isAbsolute(rel);
|
|
337738
337863
|
}
|
|
337739
337864
|
hostSupportsTool(name50) {
|
|
337740
337865
|
if (name50.startsWith("browser_") && !this.hostProfile.electronBrowser) return false;
|
|
@@ -337846,7 +337971,7 @@ var ToolExecutor = class {
|
|
|
337846
337971
|
if (!token || /^https?:\/\//i.test(token) || token.startsWith("-")) continue;
|
|
337847
337972
|
if (!this.looksLikePath(token)) continue;
|
|
337848
337973
|
const withoutWildcard = token.replace(/[\\/][*?][^\\/]*$/g, "");
|
|
337849
|
-
refs.push(
|
|
337974
|
+
refs.push(path17.resolve(normalizeCrossEnvPath(withoutWildcard, wsPath)));
|
|
337850
337975
|
}
|
|
337851
337976
|
return Array.from(new Set(refs));
|
|
337852
337977
|
}
|
|
@@ -337897,7 +338022,7 @@ var ToolExecutor = class {
|
|
|
337897
338022
|
}
|
|
337898
338023
|
fread(p) {
|
|
337899
338024
|
try {
|
|
337900
|
-
const c3 =
|
|
338025
|
+
const c3 = fs15.readFileSync(p, "utf-8");
|
|
337901
338026
|
return c3.length > 3e4 ? c3.slice(0, 3e4) + "...\n[truncated]" : c3;
|
|
337902
338027
|
} catch (e3) {
|
|
337903
338028
|
return `[read] ${e3}`;
|
|
@@ -337905,8 +338030,8 @@ var ToolExecutor = class {
|
|
|
337905
338030
|
}
|
|
337906
338031
|
fwrite(p, content) {
|
|
337907
338032
|
try {
|
|
337908
|
-
|
|
337909
|
-
|
|
338033
|
+
fs15.mkdirSync(path17.dirname(p), { recursive: true });
|
|
338034
|
+
fs15.writeFileSync(p, content, "utf-8");
|
|
337910
338035
|
return `[write] OK: ${p}`;
|
|
337911
338036
|
} catch (e3) {
|
|
337912
338037
|
return `[write] ${e3}`;
|
|
@@ -337914,10 +338039,10 @@ var ToolExecutor = class {
|
|
|
337914
338039
|
}
|
|
337915
338040
|
fedit(p, oldStr, newStr) {
|
|
337916
338041
|
try {
|
|
337917
|
-
const c3 =
|
|
338042
|
+
const c3 = fs15.readFileSync(p, "utf-8");
|
|
337918
338043
|
if (!c3.includes(oldStr)) return `[edit] String not found in ${p}.`;
|
|
337919
338044
|
const updated = c3.replace(oldStr, newStr);
|
|
337920
|
-
|
|
338045
|
+
fs15.writeFileSync(p, updated, "utf-8");
|
|
337921
338046
|
return `[edit] OK: ${p}`;
|
|
337922
338047
|
} catch (e3) {
|
|
337923
338048
|
return `[edit] ${e3}`;
|
|
@@ -337926,12 +338051,12 @@ var ToolExecutor = class {
|
|
|
337926
338051
|
fdelete(p) {
|
|
337927
338052
|
try {
|
|
337928
338053
|
if (/[*?]/.test(p)) return "[delete_file] Refused: wildcard paths are not allowed. Delete one file per call.";
|
|
337929
|
-
const resolved =
|
|
337930
|
-
const stat =
|
|
338054
|
+
const resolved = path17.resolve(p);
|
|
338055
|
+
const stat = fs15.lstatSync(resolved);
|
|
337931
338056
|
if (stat.isDirectory()) {
|
|
337932
338057
|
return "[delete_file] Refused: deleting a directory is not allowed. Delete files one by one under Agent supervision.";
|
|
337933
338058
|
}
|
|
337934
|
-
|
|
338059
|
+
fs15.unlinkSync(resolved);
|
|
337935
338060
|
return `[delete_file] OK: ${resolved}`;
|
|
337936
338061
|
} catch (e3) {
|
|
337937
338062
|
return `[delete_file] ${e3 instanceof Error ? e3.message : String(e3)}`;
|
|
@@ -337955,11 +338080,11 @@ var ToolExecutor = class {
|
|
|
337955
338080
|
const results = [];
|
|
337956
338081
|
const walk4 = (d3, depth) => {
|
|
337957
338082
|
if (depth > 5 || results.length >= 80) return;
|
|
337958
|
-
for (const entry of
|
|
337959
|
-
const full =
|
|
338083
|
+
for (const entry of fs15.readdirSync(d3, { withFileTypes: true })) {
|
|
338084
|
+
const full = path17.join(d3, entry.name);
|
|
337960
338085
|
if (entry.isFile()) {
|
|
337961
338086
|
try {
|
|
337962
|
-
const content =
|
|
338087
|
+
const content = fs15.readFileSync(full, "utf-8");
|
|
337963
338088
|
for (const [i4, line] of content.split("\n").entries()) {
|
|
337964
338089
|
if (re.test(line)) {
|
|
337965
338090
|
results.push(`${entry.name}:${i4 + 1}:${line.trim()}`);
|
|
@@ -338175,29 +338300,53 @@ ${String(result.data)}`);
|
|
|
338175
338300
|
try {
|
|
338176
338301
|
const resp = await this.proxyFetch(src, { signal });
|
|
338177
338302
|
const content = await resp.text();
|
|
338178
|
-
const dir =
|
|
338179
|
-
|
|
338180
|
-
|
|
338303
|
+
const dir = path17.join(this.root, "skills", name50);
|
|
338304
|
+
fs15.mkdirSync(dir, { recursive: true });
|
|
338305
|
+
fs15.writeFileSync(path17.join(dir, "SKILL.md"), content, "utf-8");
|
|
338181
338306
|
return `[skill] Downloaded '${name50}'`;
|
|
338182
338307
|
} catch (e3) {
|
|
338183
338308
|
return `[skill] ${e3}`;
|
|
338184
338309
|
}
|
|
338185
338310
|
}
|
|
338186
338311
|
flowList() {
|
|
338187
|
-
const dir =
|
|
338312
|
+
const dir = path17.join(this.root, "Flow");
|
|
338188
338313
|
try {
|
|
338189
|
-
const files =
|
|
338314
|
+
const files = fs15.readdirSync(dir).filter((f3) => f3.endsWith(".Flow.json")).sort();
|
|
338190
338315
|
if (!files.length) return "[flow_list] No workflows found.";
|
|
338191
338316
|
return files.map((f3) => f3.replace(/\.Flow\.json$/, "")).join("\n");
|
|
338192
338317
|
} catch (e3) {
|
|
338193
338318
|
return `[flow_list] ${e3}`;
|
|
338194
338319
|
}
|
|
338195
338320
|
}
|
|
338196
|
-
flowSave(name50,
|
|
338321
|
+
flowSave(name50, input2) {
|
|
338197
338322
|
const cleanName = (name50 || "").replace(/[<>:"/\\|?*]/g, "-").trim();
|
|
338198
338323
|
if (!cleanName) return "[flow_save] Workflow name is required.";
|
|
338199
|
-
|
|
338200
|
-
const
|
|
338324
|
+
const dir = path17.join(this.root, "Flow");
|
|
338325
|
+
const target = path17.join(dir, `${cleanName}.Flow.json`);
|
|
338326
|
+
const action = String(input2.action || (Array.isArray(input2.components) ? "replace" : "upsert")).toLowerCase();
|
|
338327
|
+
let componentsRaw = input2.components;
|
|
338328
|
+
if (action === "upsert") {
|
|
338329
|
+
if (!input2.component || typeof input2.component !== "object") return "[flow_save] component is required for action=upsert.";
|
|
338330
|
+
const existing = FlowEngine.load(dir, cleanName)?.components || [];
|
|
338331
|
+
const component = input2.component;
|
|
338332
|
+
const requestedId = Number(component.id);
|
|
338333
|
+
if (!Number.isFinite(requestedId)) return "[flow_save] component.id is required for action=upsert.";
|
|
338334
|
+
componentsRaw = [...existing.filter((item) => item.id !== requestedId), component].sort((a3, b2) => Number(a3.id) - Number(b2.id));
|
|
338335
|
+
} else if (action === "delete") {
|
|
338336
|
+
if (input2.confirm !== true) return "[flow_save] action=delete requires confirm=true.";
|
|
338337
|
+
const componentId = Number(input2.component_id);
|
|
338338
|
+
if (!Number.isFinite(componentId)) return "[flow_save] component_id is required for action=delete.";
|
|
338339
|
+
const existing = FlowEngine.load(dir, cleanName);
|
|
338340
|
+
if (!existing) return `[flow_save] Workflow not found: ${cleanName}`;
|
|
338341
|
+
const remaining = existing.components.filter((item) => item.id !== componentId);
|
|
338342
|
+
if (remaining.length === existing.components.length) return `[flow_save] Component not found: ${componentId}`;
|
|
338343
|
+
componentsRaw = remaining;
|
|
338344
|
+
} else if (action !== "replace") {
|
|
338345
|
+
return `[flow_save] Unknown action: ${action}`;
|
|
338346
|
+
}
|
|
338347
|
+
if (!Array.isArray(componentsRaw)) return "[flow_save] components must be an array for action=replace.";
|
|
338348
|
+
const componentInputs = componentsRaw;
|
|
338349
|
+
const components = componentInputs.map((raw, idx) => {
|
|
338201
338350
|
const c3 = raw;
|
|
338202
338351
|
const type = c3.type === "logic" ? "logic" : "dialog";
|
|
338203
338352
|
if (type === "logic") {
|
|
@@ -338218,10 +338367,9 @@ ${String(result.data)}`);
|
|
|
338218
338367
|
};
|
|
338219
338368
|
});
|
|
338220
338369
|
const workflow = { name: cleanName, components };
|
|
338221
|
-
|
|
338222
|
-
|
|
338223
|
-
|
|
338224
|
-
return `[flow_save] OK: ${cleanName}.Flow.json`;
|
|
338370
|
+
fs15.mkdirSync(dir, { recursive: true });
|
|
338371
|
+
fs15.writeFileSync(target, JSON.stringify(workflow, null, 2), "utf-8");
|
|
338372
|
+
return `[flow_save] OK (${action}): ${cleanName}.Flow.json`;
|
|
338225
338373
|
}
|
|
338226
338374
|
memoryLabRead(selector2) {
|
|
338227
338375
|
const lab2 = new MemoryLabManager(this.root);
|
|
@@ -338281,10 +338429,10 @@ ${String(result.data)}`);
|
|
|
338281
338429
|
return this.gh(args, ws, signal);
|
|
338282
338430
|
}
|
|
338283
338431
|
async fileAudit(target, ws, includeRemote, baseRef, signal) {
|
|
338284
|
-
const resolvedTarget =
|
|
338285
|
-
const exists =
|
|
338286
|
-
const stat = exists ?
|
|
338287
|
-
const repoRoot = await this.findGitRoot(exists && stat?.isDirectory() ? resolvedTarget :
|
|
338432
|
+
const resolvedTarget = path17.resolve(target || ws);
|
|
338433
|
+
const exists = fs15.existsSync(resolvedTarget);
|
|
338434
|
+
const stat = exists ? fs15.statSync(resolvedTarget) : null;
|
|
338435
|
+
const repoRoot = await this.findGitRoot(exists && stat?.isDirectory() ? resolvedTarget : path17.dirname(resolvedTarget), ws, signal);
|
|
338288
338436
|
const audit = {
|
|
338289
338437
|
ok: true,
|
|
338290
338438
|
target: resolvedTarget,
|
|
@@ -338311,11 +338459,11 @@ ${String(result.data)}`);
|
|
|
338311
338459
|
};
|
|
338312
338460
|
if (stat.isFile()) {
|
|
338313
338461
|
const hash = crypto8.createHash("sha256");
|
|
338314
|
-
hash.update(
|
|
338462
|
+
hash.update(fs15.readFileSync(target));
|
|
338315
338463
|
base2.sha256 = hash.digest("hex").toUpperCase();
|
|
338316
338464
|
}
|
|
338317
338465
|
if (stat.isDirectory()) {
|
|
338318
|
-
base2.entries =
|
|
338466
|
+
base2.entries = fs15.readdirSync(target).slice(0, 200).sort();
|
|
338319
338467
|
}
|
|
338320
338468
|
return base2;
|
|
338321
338469
|
}
|
|
@@ -338324,14 +338472,14 @@ ${String(result.data)}`);
|
|
|
338324
338472
|
const out = await this.gitExecAt(candidate, ["rev-parse", "--show-toplevel"], signal);
|
|
338325
338473
|
if (!out.startsWith("[git]") && !out.includes("not a git repository")) {
|
|
338326
338474
|
const root2 = out.split(/\r?\n/)[0].trim();
|
|
338327
|
-
if (root2 &&
|
|
338475
|
+
if (root2 && fs15.existsSync(root2)) return path17.resolve(root2);
|
|
338328
338476
|
}
|
|
338329
338477
|
}
|
|
338330
338478
|
return null;
|
|
338331
338479
|
}
|
|
338332
338480
|
async gitFileAudit(repoRoot, target, baseRef, signal) {
|
|
338333
|
-
const rel =
|
|
338334
|
-
const inside2 = rel === "" || !!rel && !rel.startsWith("..") && !
|
|
338481
|
+
const rel = path17.relative(repoRoot, target).replace(/\\/g, "/");
|
|
338482
|
+
const inside2 = rel === "" || !!rel && !rel.startsWith("..") && !path17.isAbsolute(rel);
|
|
338335
338483
|
if (!inside2) return { repository: repoRoot, tracked: false, note: "Path is outside the detected repository." };
|
|
338336
338484
|
const branch = await this.gitExecAt(repoRoot, ["branch", "--show-current"], signal);
|
|
338337
338485
|
const status = rel === "" ? await this.gitExecAt(repoRoot, ["status", "--short"], signal) : await this.gitExecAt(repoRoot, ["status", "--short", "--", rel], signal);
|
|
@@ -338389,7 +338537,7 @@ ${String(result.data)}`);
|
|
|
338389
338537
|
}
|
|
338390
338538
|
async githubFileAudit(repoRoot, target, remote, signal) {
|
|
338391
338539
|
const repo = `${remote.owner}/${remote.name}`;
|
|
338392
|
-
const rel =
|
|
338540
|
+
const rel = path17.relative(repoRoot, target).replace(/\\/g, "/");
|
|
338393
338541
|
const branch = (await this.gitExecAt(repoRoot, ["branch", "--show-current"], signal)).trim();
|
|
338394
338542
|
const encodedPath = rel && rel !== "." ? rel.split("/").map((part) => encodeURIComponent(part)).join("/") : "";
|
|
338395
338543
|
const repoInfo = await this.ghJson(["api", `repos/${repo}`, "--jq", "{name: .full_name, private: .private, default_branch: .default_branch, fork: .fork, html_url: .html_url}"], repoRoot, signal);
|
|
@@ -338413,8 +338561,8 @@ ${String(result.data)}`);
|
|
|
338413
338561
|
};
|
|
338414
338562
|
}
|
|
338415
338563
|
async repoSecurityAudit(target, ws, baseRef, signal) {
|
|
338416
|
-
const resolvedTarget =
|
|
338417
|
-
const repoRoot = await this.findGitRoot(
|
|
338564
|
+
const resolvedTarget = path17.resolve(target || ws);
|
|
338565
|
+
const repoRoot = await this.findGitRoot(fs15.existsSync(resolvedTarget) && fs15.statSync(resolvedTarget).isDirectory() ? resolvedTarget : path17.dirname(resolvedTarget), ws, signal);
|
|
338418
338566
|
if (!repoRoot) {
|
|
338419
338567
|
return JSON.stringify({
|
|
338420
338568
|
ok: true,
|
|
@@ -338512,12 +338660,12 @@ ${String(result.data)}`);
|
|
|
338512
338660
|
const findings = [];
|
|
338513
338661
|
for (const rel of Array.from(files).sort()) {
|
|
338514
338662
|
if (findings.length >= 40) break;
|
|
338515
|
-
const full =
|
|
338516
|
-
if (!
|
|
338517
|
-
if (
|
|
338663
|
+
const full = path17.join(repoRoot, rel);
|
|
338664
|
+
if (!fs15.existsSync(full) || !fs15.statSync(full).isFile()) continue;
|
|
338665
|
+
if (fs15.statSync(full).size > 512 * 1024) continue;
|
|
338518
338666
|
let text = "";
|
|
338519
338667
|
try {
|
|
338520
|
-
text =
|
|
338668
|
+
text = fs15.readFileSync(full, "utf-8");
|
|
338521
338669
|
} catch {
|
|
338522
338670
|
continue;
|
|
338523
338671
|
}
|
|
@@ -338547,12 +338695,12 @@ ${String(result.data)}`);
|
|
|
338547
338695
|
const findings = [];
|
|
338548
338696
|
for (const rel of Array.from(files).sort()) {
|
|
338549
338697
|
if (findings.length >= 40) break;
|
|
338550
|
-
const full =
|
|
338551
|
-
if (!
|
|
338552
|
-
if (
|
|
338698
|
+
const full = path17.join(repoRoot, rel);
|
|
338699
|
+
if (!fs15.existsSync(full) || !fs15.statSync(full).isFile()) continue;
|
|
338700
|
+
if (fs15.statSync(full).size > 512 * 1024) continue;
|
|
338553
338701
|
let text = "";
|
|
338554
338702
|
try {
|
|
338555
|
-
text =
|
|
338703
|
+
text = fs15.readFileSync(full, "utf-8");
|
|
338556
338704
|
} catch {
|
|
338557
338705
|
continue;
|
|
338558
338706
|
}
|
|
@@ -338569,7 +338717,7 @@ ${String(result.data)}`);
|
|
|
338569
338717
|
releaseExcludedPathFindings(repoRoot, ignoredFilesRaw) {
|
|
338570
338718
|
const sensitive = /^(config\.json|agent\.md|PC_Hash\.config|Work\/|archive\/|skills\/|Memory Lab\/|Design\.md|release\/|_local\/|_ref\/|vendor\/)/i;
|
|
338571
338719
|
const fromIgnored = String(ignoredFilesRaw || "").split(/\r?\n/).map((line) => line.trim().replace(/\\/g, "/")).filter((line) => line && sensitive.test(line));
|
|
338572
|
-
const direct = ["config.json", "agent.md", "PC_Hash.config", "Work", "archive", "skills", "Memory Lab", "Design.md", "release", "_local", "_ref", "vendor"].filter((rel) =>
|
|
338720
|
+
const direct = ["config.json", "agent.md", "PC_Hash.config", "Work", "archive", "skills", "Memory Lab", "Design.md", "release", "_local", "_ref", "vendor"].filter((rel) => fs15.existsSync(path17.join(repoRoot, rel))).map((rel) => rel.replace(/\\/g, "/"));
|
|
338573
338721
|
return Array.from(/* @__PURE__ */ new Set([...fromIgnored, ...direct])).slice(0, 80);
|
|
338574
338722
|
}
|
|
338575
338723
|
async ghJson(args, ws, signal) {
|
|
@@ -339373,8 +339521,8 @@ function sharedSubagentManager(key3, options) {
|
|
|
339373
339521
|
}
|
|
339374
339522
|
|
|
339375
339523
|
// src/core/skills.ts
|
|
339376
|
-
var
|
|
339377
|
-
var
|
|
339524
|
+
var fs16 = __toESM(require("fs"));
|
|
339525
|
+
var path18 = __toESM(require("path"));
|
|
339378
339526
|
var os4 = __toESM(require("os"));
|
|
339379
339527
|
var import_crypto9 = require("crypto");
|
|
339380
339528
|
var SkillsManager = class {
|
|
@@ -339383,13 +339531,13 @@ var SkillsManager = class {
|
|
|
339383
339531
|
marketSourcesPath;
|
|
339384
339532
|
metadataCache = /* @__PURE__ */ new Map();
|
|
339385
339533
|
constructor(root2) {
|
|
339386
|
-
this.skillsDir =
|
|
339387
|
-
this.metaPath =
|
|
339388
|
-
this.marketSourcesPath =
|
|
339389
|
-
|
|
339534
|
+
this.skillsDir = path18.join(root2, "skills");
|
|
339535
|
+
this.metaPath = path18.join(this.skillsDir, ".skills.json");
|
|
339536
|
+
this.marketSourcesPath = path18.join(this.skillsDir, ".market-sources.json");
|
|
339537
|
+
fs16.mkdirSync(this.skillsDir, { recursive: true });
|
|
339390
339538
|
}
|
|
339391
339539
|
list() {
|
|
339392
|
-
return
|
|
339540
|
+
return fs16.readdirSync(this.skillsDir, { withFileTypes: true }).filter((e3) => e3.isDirectory() && !e3.name.startsWith(".")).map((e3) => e3.name);
|
|
339393
339541
|
}
|
|
339394
339542
|
listDetailed() {
|
|
339395
339543
|
return this.list().map((name50) => this.infoFor(name50, this.getPath(name50), "project", true));
|
|
@@ -339410,48 +339558,48 @@ var SkillsManager = class {
|
|
|
339410
339558
|
}
|
|
339411
339559
|
load(name50) {
|
|
339412
339560
|
const reference = String(name50 || "").trim().toLowerCase();
|
|
339413
|
-
const skill = this.active().find((item) => item.name.toLowerCase() === reference ||
|
|
339561
|
+
const skill = this.active().find((item) => item.name.toLowerCase() === reference || path18.basename(item.path).toLowerCase() === reference);
|
|
339414
339562
|
if (!skill) return null;
|
|
339415
|
-
const skillPath =
|
|
339416
|
-
const content =
|
|
339563
|
+
const skillPath = path18.join(skill.path, "SKILL.md");
|
|
339564
|
+
const content = fs16.readFileSync(skillPath, "utf-8");
|
|
339417
339565
|
const files = this.sampleSkillFiles(skill.path, 10);
|
|
339418
339566
|
return { skill, content, files };
|
|
339419
339567
|
}
|
|
339420
339568
|
has(name50) {
|
|
339421
|
-
return
|
|
339569
|
+
return fs16.existsSync(path18.join(this.skillsDir, name50, "SKILL.md"));
|
|
339422
339570
|
}
|
|
339423
339571
|
getPath(name50) {
|
|
339424
|
-
return
|
|
339572
|
+
return path18.join(this.skillsDir, name50);
|
|
339425
339573
|
}
|
|
339426
339574
|
async download(name50, url) {
|
|
339427
|
-
const dir =
|
|
339428
|
-
|
|
339575
|
+
const dir = path18.join(this.skillsDir, name50);
|
|
339576
|
+
fs16.mkdirSync(dir, { recursive: true });
|
|
339429
339577
|
if (!url.startsWith("http")) return `[skill] Not a URL: ${url}`;
|
|
339430
339578
|
try {
|
|
339431
339579
|
const resp = await fetch(url);
|
|
339432
339580
|
const content = await resp.text();
|
|
339433
|
-
|
|
339581
|
+
fs16.writeFileSync(path18.join(dir, "SKILL.md"), content, "utf-8");
|
|
339434
339582
|
return `[skill] Downloaded '${name50}'`;
|
|
339435
339583
|
} catch (e3) {
|
|
339436
339584
|
return `[skill] ${e3}`;
|
|
339437
339585
|
}
|
|
339438
339586
|
}
|
|
339439
339587
|
installFromLocal(sourceDir, targetName) {
|
|
339440
|
-
const skillPath =
|
|
339441
|
-
if (!
|
|
339588
|
+
const skillPath = path18.join(sourceDir, "SKILL.md");
|
|
339589
|
+
if (!fs16.existsSync(skillPath)) return false;
|
|
339442
339590
|
const info = this.parseSkillInfo(sourceDir);
|
|
339443
|
-
const cleanName = this.cleanName(targetName || info.name ||
|
|
339591
|
+
const cleanName = this.cleanName(targetName || info.name || path18.basename(sourceDir));
|
|
339444
339592
|
if (!cleanName) return false;
|
|
339445
|
-
const dest =
|
|
339446
|
-
|
|
339447
|
-
|
|
339593
|
+
const dest = path18.join(this.skillsDir, cleanName);
|
|
339594
|
+
fs16.rmSync(dest, { recursive: true, force: true });
|
|
339595
|
+
fs16.cpSync(sourceDir, dest, { recursive: true });
|
|
339448
339596
|
this.setEnabled(cleanName, true);
|
|
339449
339597
|
return true;
|
|
339450
339598
|
}
|
|
339451
339599
|
remove(name50) {
|
|
339452
|
-
const dir =
|
|
339453
|
-
if (
|
|
339454
|
-
|
|
339600
|
+
const dir = path18.join(this.skillsDir, name50);
|
|
339601
|
+
if (fs16.existsSync(dir)) {
|
|
339602
|
+
fs16.rmSync(dir, { recursive: true, force: true });
|
|
339455
339603
|
const meta = this.loadMeta();
|
|
339456
339604
|
meta.disabled = meta.disabled.filter((n3) => n3 !== name50);
|
|
339457
339605
|
this.saveMeta(meta);
|
|
@@ -339500,7 +339648,7 @@ var SkillsManager = class {
|
|
|
339500
339648
|
type,
|
|
339501
339649
|
enabled: input2.enabled !== false,
|
|
339502
339650
|
url: url || void 0,
|
|
339503
|
-
path: sourcePath ?
|
|
339651
|
+
path: sourcePath ? path18.resolve(sourcePath) : void 0,
|
|
339504
339652
|
addedAt: existing?.addedAt || now2,
|
|
339505
339653
|
updatedAt: now2
|
|
339506
339654
|
};
|
|
@@ -339538,17 +339686,17 @@ var SkillsManager = class {
|
|
|
339538
339686
|
const items = [];
|
|
339539
339687
|
for (const info of this.listDetailed()) items.push(info);
|
|
339540
339688
|
const roots = [
|
|
339541
|
-
{ root:
|
|
339542
|
-
{ root:
|
|
339543
|
-
{ root:
|
|
339544
|
-
{ root:
|
|
339545
|
-
{ root:
|
|
339546
|
-
{ root:
|
|
339689
|
+
{ root: path18.join(this.skillsDir, "..", ".agents", "skills"), source: "codex" },
|
|
339690
|
+
{ root: path18.join(this.skillsDir, "..", ".claude", "skills"), source: "claude" },
|
|
339691
|
+
{ root: path18.join(os4.homedir(), ".agents", "skills"), source: "user" },
|
|
339692
|
+
{ root: path18.join(os4.homedir(), ".codex", "skills"), source: "codex" },
|
|
339693
|
+
{ root: path18.join(os4.homedir(), ".claude", "skills"), source: "claude" },
|
|
339694
|
+
{ root: path18.join(os4.homedir(), ".config", "opencode", "skills"), source: "opencode" }
|
|
339547
339695
|
];
|
|
339548
339696
|
for (const entry of roots) {
|
|
339549
339697
|
for (const dir of this.findSkillDirs(entry.root, 4, 240)) {
|
|
339550
339698
|
const parsed = this.parseSkillInfo(dir);
|
|
339551
|
-
const name50 = this.cleanName(parsed.name ||
|
|
339699
|
+
const name50 = this.cleanName(parsed.name || path18.basename(dir));
|
|
339552
339700
|
if (!name50 || items.some((i4) => i4.name === name50 && i4.source !== "remote")) continue;
|
|
339553
339701
|
items.push({
|
|
339554
339702
|
name: name50,
|
|
@@ -339565,9 +339713,9 @@ var SkillsManager = class {
|
|
|
339565
339713
|
});
|
|
339566
339714
|
}
|
|
339567
339715
|
}
|
|
339568
|
-
for (const dir of this.findPluginSkillDirs(
|
|
339716
|
+
for (const dir of this.findPluginSkillDirs(path18.join(this.skillsDir, ".."), 5, 240)) {
|
|
339569
339717
|
const parsed = this.parseSkillInfo(dir);
|
|
339570
|
-
const name50 = this.cleanName(parsed.name ||
|
|
339718
|
+
const name50 = this.cleanName(parsed.name || path18.basename(dir));
|
|
339571
339719
|
if (!name50 || items.some((i4) => i4.name === name50 && i4.source !== "remote")) continue;
|
|
339572
339720
|
items.push({
|
|
339573
339721
|
name: name50,
|
|
@@ -339624,8 +339772,8 @@ var SkillsManager = class {
|
|
|
339624
339772
|
}
|
|
339625
339773
|
loadMeta() {
|
|
339626
339774
|
try {
|
|
339627
|
-
if (
|
|
339628
|
-
const raw = JSON.parse(
|
|
339775
|
+
if (fs16.existsSync(this.metaPath)) {
|
|
339776
|
+
const raw = JSON.parse(fs16.readFileSync(this.metaPath, "utf-8"));
|
|
339629
339777
|
return { disabled: Array.isArray(raw.disabled) ? raw.disabled.map(String) : [] };
|
|
339630
339778
|
}
|
|
339631
339779
|
} catch {
|
|
@@ -339633,7 +339781,7 @@ var SkillsManager = class {
|
|
|
339633
339781
|
return { disabled: [] };
|
|
339634
339782
|
}
|
|
339635
339783
|
saveMeta(meta) {
|
|
339636
|
-
|
|
339784
|
+
fs16.writeFileSync(this.metaPath, JSON.stringify({ disabled: meta.disabled }, null, 2), "utf-8");
|
|
339637
339785
|
}
|
|
339638
339786
|
builtinMarketSources() {
|
|
339639
339787
|
return [{
|
|
@@ -339647,8 +339795,8 @@ var SkillsManager = class {
|
|
|
339647
339795
|
}
|
|
339648
339796
|
loadMarketSources() {
|
|
339649
339797
|
try {
|
|
339650
|
-
if (!
|
|
339651
|
-
const raw = JSON.parse(
|
|
339798
|
+
if (!fs16.existsSync(this.marketSourcesPath)) return [];
|
|
339799
|
+
const raw = JSON.parse(fs16.readFileSync(this.marketSourcesPath, "utf-8"));
|
|
339652
339800
|
if (!Array.isArray(raw.sources)) return [];
|
|
339653
339801
|
return raw.sources.map((source) => this.normalizeMarketSource(source)).filter((source) => !!source);
|
|
339654
339802
|
} catch {
|
|
@@ -339657,7 +339805,7 @@ var SkillsManager = class {
|
|
|
339657
339805
|
}
|
|
339658
339806
|
saveMarketSources(sources) {
|
|
339659
339807
|
const normalized = sources.filter((s3) => !s3.builtin).map((s3) => this.normalizeMarketSource(s3)).filter((source) => !!source);
|
|
339660
|
-
|
|
339808
|
+
fs16.writeFileSync(this.marketSourcesPath, JSON.stringify({ sources: normalized }, null, 2), "utf-8");
|
|
339661
339809
|
}
|
|
339662
339810
|
normalizeMarketSource(raw) {
|
|
339663
339811
|
if (!raw || typeof raw !== "object") return null;
|
|
@@ -339677,7 +339825,7 @@ var SkillsManager = class {
|
|
|
339677
339825
|
type,
|
|
339678
339826
|
enabled: source.enabled !== false,
|
|
339679
339827
|
url: url || void 0,
|
|
339680
|
-
path: sourcePath ?
|
|
339828
|
+
path: sourcePath ? path18.resolve(sourcePath) : void 0,
|
|
339681
339829
|
builtin: source.builtin === true,
|
|
339682
339830
|
addedAt: source.addedAt ? String(source.addedAt) : void 0,
|
|
339683
339831
|
updatedAt: source.updatedAt ? String(source.updatedAt) : void 0
|
|
@@ -339728,11 +339876,11 @@ var SkillsManager = class {
|
|
|
339728
339876
|
return rawItems.slice(0, 1e3).map((entry) => this.marketInfoFromCatalogEntry(entry, source, installed)).filter((item) => !!item);
|
|
339729
339877
|
}
|
|
339730
339878
|
readCatalogText(source) {
|
|
339731
|
-
const catalogPath = source.path ?
|
|
339732
|
-
if (catalogPath &&
|
|
339879
|
+
const catalogPath = source.path ? path18.resolve(source.path) : "";
|
|
339880
|
+
if (catalogPath && fs16.existsSync(catalogPath)) return fs16.readFileSync(catalogPath, "utf-8");
|
|
339733
339881
|
const url = source.url || "";
|
|
339734
|
-
if (url.startsWith("file://")) return
|
|
339735
|
-
if (url && !url.startsWith("http")) return
|
|
339882
|
+
if (url.startsWith("file://")) return fs16.readFileSync(new URL(url), "utf-8");
|
|
339883
|
+
if (url && !url.startsWith("http")) return fs16.readFileSync(path18.resolve(url), "utf-8");
|
|
339736
339884
|
return "";
|
|
339737
339885
|
}
|
|
339738
339886
|
async discoverJsonMarketSourceAsync(source, installed) {
|
|
@@ -339792,7 +339940,7 @@ var SkillsManager = class {
|
|
|
339792
339940
|
}
|
|
339793
339941
|
marketInfoFromLocalDir(dir, source, installed) {
|
|
339794
339942
|
const parsed = this.parseSkillInfo(dir);
|
|
339795
|
-
const name50 = this.cleanName(parsed.name ||
|
|
339943
|
+
const name50 = this.cleanName(parsed.name || path18.basename(dir));
|
|
339796
339944
|
if (!name50) return null;
|
|
339797
339945
|
return {
|
|
339798
339946
|
name: name50,
|
|
@@ -339817,9 +339965,9 @@ var SkillsManager = class {
|
|
|
339817
339965
|
}
|
|
339818
339966
|
parseSkillInfo(dir) {
|
|
339819
339967
|
try {
|
|
339820
|
-
const skillPath =
|
|
339821
|
-
const stat =
|
|
339822
|
-
const content =
|
|
339968
|
+
const skillPath = path18.join(dir, "SKILL.md");
|
|
339969
|
+
const stat = fs16.statSync(skillPath);
|
|
339970
|
+
const content = fs16.readFileSync(skillPath, "utf-8");
|
|
339823
339971
|
const digest = (0, import_crypto9.createHash)("sha256").update(content).digest("hex");
|
|
339824
339972
|
const fingerprint2 = `${stat.mtimeMs}:${stat.size}:${digest}`;
|
|
339825
339973
|
const cached = this.metadataCache.get(skillPath);
|
|
@@ -339852,7 +340000,7 @@ var SkillsManager = class {
|
|
|
339852
340000
|
};
|
|
339853
340001
|
this.metadataCache.set(skillPath, {
|
|
339854
340002
|
fingerprint: fingerprint2,
|
|
339855
|
-
info: { ...parsed, path: dir, enabled: this.isEnabled(
|
|
340003
|
+
info: { ...parsed, path: dir, enabled: this.isEnabled(path18.basename(dir)), installed: true, source: "project" }
|
|
339856
340004
|
});
|
|
339857
340005
|
return parsed;
|
|
339858
340006
|
} catch {
|
|
@@ -339869,13 +340017,13 @@ var SkillsManager = class {
|
|
|
339869
340017
|
if (files.length >= limit || depth > 2) return;
|
|
339870
340018
|
let entries = [];
|
|
339871
340019
|
try {
|
|
339872
|
-
entries =
|
|
340020
|
+
entries = fs16.readdirSync(dir, { withFileTypes: true });
|
|
339873
340021
|
} catch {
|
|
339874
340022
|
return;
|
|
339875
340023
|
}
|
|
339876
340024
|
for (const entry of entries) {
|
|
339877
340025
|
if (files.length >= limit || entry.name === "SKILL.md" || entry.name.startsWith(".")) continue;
|
|
339878
|
-
const target =
|
|
340026
|
+
const target = path18.join(dir, entry.name);
|
|
339879
340027
|
if (entry.isDirectory()) walk4(target, depth + 1);
|
|
339880
340028
|
else if (entry.isFile()) files.push(target);
|
|
339881
340029
|
}
|
|
@@ -339889,7 +340037,7 @@ var SkillsManager = class {
|
|
|
339889
340037
|
if (results.length >= maxItems || depth > maxDepth) return;
|
|
339890
340038
|
let entries;
|
|
339891
340039
|
try {
|
|
339892
|
-
entries =
|
|
340040
|
+
entries = fs16.readdirSync(dir, { withFileTypes: true });
|
|
339893
340041
|
} catch {
|
|
339894
340042
|
return;
|
|
339895
340043
|
}
|
|
@@ -339899,7 +340047,7 @@ var SkillsManager = class {
|
|
|
339899
340047
|
}
|
|
339900
340048
|
for (const e3 of entries) {
|
|
339901
340049
|
if (!e3.isDirectory() || e3.name.startsWith(".git") || e3.name === "node_modules") continue;
|
|
339902
|
-
walk4(
|
|
340050
|
+
walk4(path18.join(dir, e3.name), depth + 1);
|
|
339903
340051
|
}
|
|
339904
340052
|
};
|
|
339905
340053
|
walk4(root2, 0);
|
|
@@ -339911,19 +340059,19 @@ var SkillsManager = class {
|
|
|
339911
340059
|
if (results.length >= maxItems || depth > maxDepth) return;
|
|
339912
340060
|
let entries;
|
|
339913
340061
|
try {
|
|
339914
|
-
entries =
|
|
340062
|
+
entries = fs16.readdirSync(dir, { withFileTypes: true });
|
|
339915
340063
|
} catch {
|
|
339916
340064
|
return;
|
|
339917
340065
|
}
|
|
339918
340066
|
const hasPluginManifest = entries.some((e3) => e3.isDirectory() && (e3.name === ".codex-plugin" || e3.name === ".claude-plugin"));
|
|
339919
340067
|
if (hasPluginManifest) {
|
|
339920
340068
|
for (const skillsDir of ["skills", "Skills"]) {
|
|
339921
|
-
results.push(...this.findSkillDirs(
|
|
340069
|
+
results.push(...this.findSkillDirs(path18.join(dir, skillsDir), 3, maxItems - results.length));
|
|
339922
340070
|
}
|
|
339923
340071
|
}
|
|
339924
340072
|
for (const e3 of entries) {
|
|
339925
340073
|
if (!e3.isDirectory() || e3.name.startsWith(".git") || e3.name === "node_modules" || e3.name === "release" || e3.name.startsWith("release.locked-")) continue;
|
|
339926
|
-
walk4(
|
|
340074
|
+
walk4(path18.join(dir, e3.name), depth + 1);
|
|
339927
340075
|
}
|
|
339928
340076
|
};
|
|
339929
340077
|
walk4(root2, 0);
|
|
@@ -339951,25 +340099,25 @@ var SkillsManager = class {
|
|
|
339951
340099
|
if (!description) warnings.push("Missing required frontmatter field: description.");
|
|
339952
340100
|
if (name50 && !/^[A-Za-z0-9][A-Za-z0-9_.:-]{0,119}$/.test(name50)) warnings.push("Skill name contains characters outside the portable Agent Skills subset.");
|
|
339953
340101
|
if (description && description.length > 1e3) warnings.push("Description is longer than recommended for skill discovery.");
|
|
339954
|
-
const folderName =
|
|
340102
|
+
const folderName = path18.basename(dir);
|
|
339955
340103
|
if (name50 && folderName && this.cleanName(name50) !== this.cleanName(folderName)) warnings.push("Skill name does not match containing folder name.");
|
|
339956
340104
|
return warnings;
|
|
339957
340105
|
}
|
|
339958
340106
|
pluginIdForSkill(dir) {
|
|
339959
|
-
let current =
|
|
340107
|
+
let current = path18.resolve(dir);
|
|
339960
340108
|
for (let i4 = 0; i4 < 6; i4++) {
|
|
339961
|
-
const codex =
|
|
339962
|
-
const claude =
|
|
340109
|
+
const codex = path18.join(current, ".codex-plugin", "plugin.json");
|
|
340110
|
+
const claude = path18.join(current, ".claude-plugin", "plugin.json");
|
|
339963
340111
|
for (const filePath of [codex, claude]) {
|
|
339964
340112
|
try {
|
|
339965
|
-
if (
|
|
339966
|
-
const raw = JSON.parse(
|
|
340113
|
+
if (fs16.existsSync(filePath)) {
|
|
340114
|
+
const raw = JSON.parse(fs16.readFileSync(filePath, "utf-8"));
|
|
339967
340115
|
if (raw?.name) return String(raw.name);
|
|
339968
340116
|
}
|
|
339969
340117
|
} catch {
|
|
339970
340118
|
}
|
|
339971
340119
|
}
|
|
339972
|
-
const parent =
|
|
340120
|
+
const parent = path18.dirname(current);
|
|
339973
340121
|
if (parent === current) break;
|
|
339974
340122
|
current = parent;
|
|
339975
340123
|
}
|
|
@@ -340515,6 +340663,22 @@ function createToolchainCore() {
|
|
|
340515
340663
|
return { registry: new ToolRegistry(), catalog: new CapabilityCatalog() };
|
|
340516
340664
|
}
|
|
340517
340665
|
|
|
340666
|
+
// src/core/emptyResponseRetry.ts
|
|
340667
|
+
var EMPTY_RESPONSE_RETRY_DELAYS_MS = [200, 800, 2e3, 1e4, 6e4];
|
|
340668
|
+
var MAX_EMPTY_RESPONSE_RETRIES = EMPTY_RESPONSE_RETRY_DELAYS_MS.length;
|
|
340669
|
+
var MAX_CONSECUTIVE_EMPTY_RESPONSES = MAX_EMPTY_RESPONSE_RETRIES + 1;
|
|
340670
|
+
function emptyResponseRetryDelayMs(consecutiveEmptyResponses) {
|
|
340671
|
+
return EMPTY_RESPONSE_RETRY_DELAYS_MS[Math.max(0, consecutiveEmptyResponses - 1)] ?? 0;
|
|
340672
|
+
}
|
|
340673
|
+
function observeEmptyResponseOutcome(consecutiveEmptyResponses, emptyResponse) {
|
|
340674
|
+
const nextCount = emptyResponse ? consecutiveEmptyResponses + 1 : 0;
|
|
340675
|
+
return {
|
|
340676
|
+
consecutiveEmptyResponses: nextCount,
|
|
340677
|
+
retry: emptyResponse && nextCount <= MAX_EMPTY_RESPONSE_RETRIES,
|
|
340678
|
+
terminate: emptyResponse && nextCount > MAX_EMPTY_RESPONSE_RETRIES
|
|
340679
|
+
};
|
|
340680
|
+
}
|
|
340681
|
+
|
|
340518
340682
|
// src/core/agentKernelRunner.ts
|
|
340519
340683
|
var publicStreamFilters = /* @__PURE__ */ new WeakMap();
|
|
340520
340684
|
var brokerOnlyAssistantBuffers = /* @__PURE__ */ new WeakMap();
|
|
@@ -340666,7 +340830,7 @@ function kernelTurnFailed(agent, turn) {
|
|
|
340666
340830
|
return turn.stopReason === "error" || agent.isLlmErrorText(turn.text);
|
|
340667
340831
|
}
|
|
340668
340832
|
function providerTurnIsEmpty(turn) {
|
|
340669
|
-
return /provider returned an empty response/i.test(`${turn.errorMessage}
|
|
340833
|
+
return !turn.activity && /provider returned an empty response/i.test(`${turn.errorMessage}
|
|
340670
340834
|
${turn.text}`);
|
|
340671
340835
|
}
|
|
340672
340836
|
function removeTrailingFailedAssistant(agent, messages) {
|
|
@@ -340675,6 +340839,12 @@ function removeTrailingFailedAssistant(agent, messages) {
|
|
|
340675
340839
|
const text = KernelMessageText(last);
|
|
340676
340840
|
if (last.stopReason === "error" || agent.isLlmErrorText(text)) messages.pop();
|
|
340677
340841
|
}
|
|
340842
|
+
function removeTrailingThoughtOnlyAssistant(messages) {
|
|
340843
|
+
const last = messages[messages.length - 1];
|
|
340844
|
+
if (last?.role !== "assistant") return;
|
|
340845
|
+
const hasToolCall = last.content.some((content) => content.type === "toolCall");
|
|
340846
|
+
if (!KernelMessageText(last).trim() && !hasToolCall) messages.pop();
|
|
340847
|
+
}
|
|
340678
340848
|
function normalizePublicProviderError(error, secrets = []) {
|
|
340679
340849
|
let raw = "";
|
|
340680
340850
|
if (error instanceof Error) {
|
|
@@ -340800,8 +340970,17 @@ async function runAgentKernel(agent) {
|
|
|
340800
340970
|
const tokens = [];
|
|
340801
340971
|
const runOnce = async (promptMessages, appendPromptToAgentHistory) => {
|
|
340802
340972
|
let lastAssistant = null;
|
|
340973
|
+
let observedActivity = false;
|
|
340974
|
+
let observedThought = false;
|
|
340803
340975
|
const unsubscribe = kernel2.subscribe(async (event) => {
|
|
340804
340976
|
await handleKernelEvent(agent, event, tokens);
|
|
340977
|
+
if (event.type === "message_update") {
|
|
340978
|
+
const delta = event.assistantMessageEvent;
|
|
340979
|
+
const deltaText = typeof delta.delta === "string" ? delta.delta : "";
|
|
340980
|
+
const thoughtDelta = delta.type === "thinking_delta" && !!deltaText.trim();
|
|
340981
|
+
observedThought = observedThought || thoughtDelta;
|
|
340982
|
+
observedActivity = observedActivity || thoughtDelta || delta.type === "text_delta" && !!deltaText.trim() || delta.type === "toolcall_end";
|
|
340983
|
+
}
|
|
340805
340984
|
if (event.type === "message_end" && event.message.role === "assistant") {
|
|
340806
340985
|
lastAssistant = event.message;
|
|
340807
340986
|
}
|
|
@@ -340819,11 +340998,13 @@ async function runAgentKernel(agent) {
|
|
|
340819
340998
|
const assistant = lastAssistant;
|
|
340820
340999
|
const text = assistant ? KernelMessageText(assistant) : "";
|
|
340821
341000
|
const hasToolCall = !!assistant?.content?.some((content) => content.type === "toolCall");
|
|
340822
|
-
const emptyResponse = !assistant || !text.trim() && !hasToolCall && String(assistant?.stopReason || "") !== "aborted";
|
|
341001
|
+
const emptyResponse = !assistant || !text.trim() && !hasToolCall && !observedActivity && String(assistant?.stopReason || "") !== "aborted";
|
|
340823
341002
|
return {
|
|
340824
341003
|
text: emptyResponse ? "[Error] Provider returned an empty response." : text,
|
|
340825
341004
|
stopReason: String(assistant?.stopReason || ""),
|
|
340826
|
-
errorMessage: String(assistant?.errorMessage || (emptyResponse ? "Provider returned an empty response." : ""))
|
|
341005
|
+
errorMessage: String(assistant?.errorMessage || (emptyResponse ? "Provider returned an empty response." : "")),
|
|
341006
|
+
activity: observedActivity || !!text.trim() || hasToolCall,
|
|
341007
|
+
thoughtOnly: observedThought && !text.trim() && !hasToolCall && !["error", "aborted"].includes(String(assistant?.stopReason || ""))
|
|
340827
341008
|
};
|
|
340828
341009
|
} finally {
|
|
340829
341010
|
unsubscribe();
|
|
@@ -340869,14 +341050,22 @@ async function runAgentKernel(agent) {
|
|
|
340869
341050
|
fallback: { from: modelBeforeKernelRun, to: agent.model, providerId: agent.activeDeployment()?.providerId }
|
|
340870
341051
|
});
|
|
340871
341052
|
}
|
|
340872
|
-
let
|
|
340873
|
-
|
|
341053
|
+
let consecutiveEmptyResponses = 0;
|
|
341054
|
+
for (; ; ) {
|
|
341055
|
+
const emptyResponseState = observeEmptyResponseOutcome(consecutiveEmptyResponses, providerTurnIsEmpty(lastTurn));
|
|
341056
|
+
consecutiveEmptyResponses = emptyResponseState.consecutiveEmptyResponses;
|
|
341057
|
+
if (lastTurn.thoughtOnly) {
|
|
341058
|
+
removeTrailingThoughtOnlyAssistant(kernel2.state.messages);
|
|
341059
|
+
lastTurn = await runWithCompressionResume([], false);
|
|
341060
|
+
continue;
|
|
341061
|
+
}
|
|
341062
|
+
if (!emptyResponseState.retry) break;
|
|
340874
341063
|
removeTrailingFailedAssistant(agent, kernel2.state.messages);
|
|
340875
|
-
|
|
340876
|
-
const notice = `[Model retry] Provider returned an empty response; retrying the same deployment (${
|
|
341064
|
+
const retryNumber = consecutiveEmptyResponses;
|
|
341065
|
+
const notice = `[Model retry] Provider returned an empty response; retrying the same deployment (${retryNumber}/${MAX_EMPTY_RESPONSE_RETRIES}) after ${emptyResponseRetryDelayMs(consecutiveEmptyResponses)}ms.`;
|
|
340877
341066
|
tokens.push({ type: "text", text: notice });
|
|
340878
341067
|
agent.recordWorkStatus(notice);
|
|
340879
|
-
await agent.waitForPlannedRouteRetry();
|
|
341068
|
+
await agent.waitForPlannedRouteRetry(emptyResponseRetryDelayMs(consecutiveEmptyResponses));
|
|
340880
341069
|
lastTurn = await runWithCompressionResume([], false);
|
|
340881
341070
|
}
|
|
340882
341071
|
let routeRetries = 0;
|
|
@@ -341072,7 +341261,7 @@ async function runAgentKernel(agent) {
|
|
|
341072
341261
|
return;
|
|
341073
341262
|
}
|
|
341074
341263
|
if (textStarted) finalContent.push({ type: "text", text });
|
|
341075
|
-
if (!finalContent.length) {
|
|
341264
|
+
if (!finalContent.length && !thinking.trim()) {
|
|
341076
341265
|
text = "[Error] Provider returned an empty response.";
|
|
341077
341266
|
finalContent.push({ type: "text", text });
|
|
341078
341267
|
}
|
|
@@ -344956,7 +345145,7 @@ var Agent4 = class _Agent {
|
|
|
344956
345145
|
this.config.set("skills", "auto_download", "disabled");
|
|
344957
345146
|
}
|
|
344958
345147
|
const modeStr = this.config.getStr("agent", "default_mode");
|
|
344959
|
-
this.mode = ["plan", "goal", "flow"].includes(modeStr) ? modeStr : "build";
|
|
345148
|
+
this.mode = ["plan", "chat", "goal", "flow"].includes(modeStr) ? modeStr : "build";
|
|
344960
345149
|
const inputStr = this.config.getStr("general", "default_input");
|
|
344961
345150
|
this.inputMode = inputStr === "next" ? "next" : "guide";
|
|
344962
345151
|
const configuredModel = this.config.getStr("models", "default_model");
|
|
@@ -345124,6 +345313,7 @@ var Agent4 = class _Agent {
|
|
|
345124
345313
|
return this.toolchainCore;
|
|
345125
345314
|
}
|
|
345126
345315
|
setMode(m2) {
|
|
345316
|
+
if (!["build", "plan", "chat", "goal", "flow"].includes(m2)) m2 = "build";
|
|
345127
345317
|
if (m2 === "goal" && !this.goal) {
|
|
345128
345318
|
this.goal = new GoalStateImpl("Set your objective");
|
|
345129
345319
|
}
|
|
@@ -345656,7 +345846,12 @@ var Agent4 = class _Agent {
|
|
|
345656
345846
|
beginRouteAttempt() {
|
|
345657
345847
|
this.routeAttemptStartedAt = Date.now();
|
|
345658
345848
|
}
|
|
345659
|
-
async waitForPlannedRouteRetry() {
|
|
345849
|
+
async waitForPlannedRouteRetry(explicitDelayMs) {
|
|
345850
|
+
if (explicitDelayMs !== void 0) {
|
|
345851
|
+
if (explicitDelayMs <= 0) return;
|
|
345852
|
+
await new Promise((resolve16) => setTimeout(resolve16, explicitDelayMs));
|
|
345853
|
+
return;
|
|
345854
|
+
}
|
|
345660
345855
|
const waitBudgetMs = Math.max(0, Math.min(15e3, this.lastRouteDecision?.retryBudgetMs ?? 5e3));
|
|
345661
345856
|
const delay = Math.max(0, Math.min(waitBudgetMs, this.lastRouteRetryDelayMs));
|
|
345662
345857
|
this.lastRouteRetryDelayMs = 0;
|
|
@@ -349486,7 +349681,20 @@ ${summary}`, segment, "local-summarize", true);
|
|
|
349486
349681
|
if (action === "get") return JSON.stringify({ ok: true, linkedPlan: this.getLinkedPlan() }, null, 2);
|
|
349487
349682
|
if (action !== "update") return JSON.stringify({ ok: false, error: `Unknown linked_plan action: ${action}` });
|
|
349488
349683
|
const expectedRevision = Number(input2.expected_revision ?? input2.expectedRevision);
|
|
349489
|
-
|
|
349684
|
+
const current = this.getLinkedPlan();
|
|
349685
|
+
let markdown = input2.markdown === void 0 ? current.markdown : String(input2.markdown);
|
|
349686
|
+
if (input2.append !== void 0) markdown = `${current.markdown}${String(input2.append)}`;
|
|
349687
|
+
if (input2.old_text !== void 0 || input2.oldText !== void 0) {
|
|
349688
|
+
const oldText = String(input2.old_text ?? input2.oldText ?? "");
|
|
349689
|
+
if (!oldText) throw new Error("linked_plan old_text must not be empty.");
|
|
349690
|
+
const matches = current.markdown.split(oldText).length - 1;
|
|
349691
|
+
if (!matches) throw new Error("linked_plan old_text was not found.");
|
|
349692
|
+
const replaceAll = input2.replace_all === true || input2.replaceAll === true;
|
|
349693
|
+
if (matches > 1 && !replaceAll) throw new Error(`linked_plan old_text matched ${matches} places; pass replace_all=true or a unique fragment.`);
|
|
349694
|
+
const newText = String(input2.new_text ?? input2.newText ?? "");
|
|
349695
|
+
markdown = replaceAll ? current.markdown.split(oldText).join(newText) : current.markdown.replace(oldText, newText);
|
|
349696
|
+
}
|
|
349697
|
+
return JSON.stringify({ ok: true, linkedPlan: this.updateLinkedPlan(markdown, expectedRevision) }, null, 2);
|
|
349490
349698
|
} catch (error) {
|
|
349491
349699
|
return JSON.stringify({ ok: false, error: error instanceof Error ? error.message : String(error) });
|
|
349492
349700
|
}
|
|
@@ -351788,7 +351996,24 @@ ${this.formatAutomation(item)}` : `[automation_toggle] Not found: ${id}`;
|
|
|
351788
351996
|
}));
|
|
351789
351997
|
}
|
|
351790
351998
|
case "memory_lab_update": {
|
|
351791
|
-
const
|
|
351999
|
+
const selector2 = String(params.component || params.slug || "").trim();
|
|
352000
|
+
const prepared = selector2 ? this.memoryLab.preparePatch({
|
|
352001
|
+
component: selector2,
|
|
352002
|
+
name: params.name === void 0 ? void 0 : String(params.name),
|
|
352003
|
+
description: params.description === void 0 ? void 0 : String(params.description),
|
|
352004
|
+
tags: params.tags === void 0 ? void 0 : Array.isArray(params.tags) ? params.tags.map(String) : String(params.tags).split(/[,,\n]+/),
|
|
352005
|
+
tagPaths: params.tagPaths === void 0 ? void 0 : Array.isArray(params.tagPaths) ? params.tagPaths.filter(Array.isArray).map((pathValue) => pathValue.map(String)) : [],
|
|
352006
|
+
content: params.content === void 0 ? void 0 : String(params.content),
|
|
352007
|
+
contentAppend: params.contentAppend === void 0 && params.content_append === void 0 ? void 0 : String(params.contentAppend ?? params.content_append),
|
|
352008
|
+
oldText: params.oldText === void 0 && params.old_text === void 0 ? void 0 : String(params.oldText ?? params.old_text),
|
|
352009
|
+
newText: String(params.newText ?? params.new_text ?? ""),
|
|
352010
|
+
replaceAll: params.replaceAll === true || params.replace_all === true,
|
|
352011
|
+
kind: params.kind === void 0 ? void 0 : params.kind === "folder" ? "folder" : "file",
|
|
352012
|
+
expectedUpdatedAt: String(params.expectedUpdatedAt || params.expected_updated_at || ""),
|
|
352013
|
+
reason: String(params.reason || ""),
|
|
352014
|
+
source: String(params.source || "")
|
|
352015
|
+
}) : void 0;
|
|
352016
|
+
const result = await this.updateMemoryLab(prepared || {
|
|
351792
352017
|
name: String(params.name || ""),
|
|
351793
352018
|
description: String(params.description || ""),
|
|
351794
352019
|
tags: Array.isArray(params.tags) ? params.tags.map(String) : String(params.tags || "").split(/[,,\n]+/),
|
|
@@ -352791,6 +353016,8 @@ When using file tools (read, write, edit, glob), use ABSOLUTE paths rooted at th
|
|
|
352791
353016
|
parts.push(this.buildFeatureDisclosurePrompt());
|
|
352792
353017
|
if (this.mode === "plan") parts.push(`[Plan Tool Policy]
|
|
352793
353018
|
${planModePolicyPrompt()}`);
|
|
353019
|
+
if (this.mode === "chat") parts.push(`[Chat Tool Policy]
|
|
353020
|
+
${chatModePolicyPrompt()}`);
|
|
352794
353021
|
const pm = this.config.getStr("workspace", "prompt_mode") || "both";
|
|
352795
353022
|
const injectedPrompts = /* @__PURE__ */ new Set();
|
|
352796
353023
|
if ((pm === "global_only" || pm === "both") && globalPrompt) {
|
|
@@ -352912,7 +353139,7 @@ ${custom}`);
|
|
|
352912
353139
|
`- Language policy: general.language=${language}; the UI can switch this at runtime and each turn must obey the current value. auto follows the user's dominant input language, en replies in English, zh replies in Simplified Chinese. Keep code, commands, file paths, JSON keys, model/provider names, tool names, quoted source text, and user-provided literals exactly as required by their source language.`,
|
|
352913
353140
|
`- Workspace permissions: access_permission=${permission}; file tools are checked before execution and blocked when they exceed the configured workspace boundary.`,
|
|
352914
353141
|
`- Remote repository safety: when the active workspace or any target path is inside a GitHub/remote-backed repository, proactively use repo_security_audit and file_audit before git_push, gh_pr_create, release packaging, public reporting, or cloud-side audit. Treat public remotes as public disclosure surfaces and keep private URLs, secrets, privacy addresses (credential URLs, private network addresses, local user paths), local runtime state, archives, Memory Lab, Work, config, and release outputs out of commits and summaries. git_push/gh_pr_create hard-block on detected high-risk findings until a second review resolves them and the action is retried with security_review_confirmed=true.`,
|
|
352915
|
-
`- Mode engine: current mode=${this.modeName()}; Build works autonomously, Plan is fully read-only
|
|
353142
|
+
`- Mode engine: current mode=${this.modeName()}; Build works autonomously, Plan is fully read-only, Chat only performs web search/fetch evidence gathering and prompt synthesis, Goal continues until completion unless paused, Flow follows saved workflow components.`,
|
|
352916
353143
|
`- Input mode: ${input2}; Guide injects immediately, Next queues user intent for the following build turn.`,
|
|
352917
353144
|
`- Option feedback: ${this.buildQuestionPolicyPrompt(optionFeedback)}`,
|
|
352918
353145
|
`- Model policy: current model=${this.model || "(unset)"}, intelligence=${this.intelligence}, auto-switch=${modelSwitch}.`,
|
|
@@ -352978,6 +353205,14 @@ ${custom}`);
|
|
|
352978
353205
|
'Only after the durable linked plan has actually been updated and the plan is complete, expose the fixed mode handoff asking whether execution should begin. Offer exactly these two choices in the user language: "\u662F\uFF0C\u6267\u884C\u6B64\u8BA1\u5212" / "\u5426\uFF0C\u8BF7\u8865\u5145____" (or "Yes, execute this plan" / "No, please supplement _____"). This fixed handoff remains required when discretionary questions are disabled.',
|
|
352979
353206
|
"A positive choice starts a new Build-mode input. A negative choice remains in Plan mode so the user can supply the missing details."
|
|
352980
353207
|
]).join("\n");
|
|
353208
|
+
case "chat":
|
|
353209
|
+
return withLanguage([
|
|
353210
|
+
"CHAT MODE.",
|
|
353211
|
+
"Use only web_search and web_fetch. You have no workspace, host, application, memory, task, browser-control, or write permissions.",
|
|
353212
|
+
"Perform an online search to gather evidence before answering. Fetch primary or authoritative pages when the search snippets are insufficient.",
|
|
353213
|
+
"After sufficient evidence is collected, summarize and answer the user as soon as possible. Stay concise and do not turn the request into a long-running Build, Plan, Goal, or Flow task.",
|
|
353214
|
+
"Distinguish sourced facts from uncertainty and include useful source links in the final answer."
|
|
353215
|
+
]).join("\n");
|
|
352981
353216
|
case "goal": {
|
|
352982
353217
|
const g2 = this.goal?.history() || "";
|
|
352983
353218
|
const paused = this.goal?.paused ? "\n[GOAL PAUSED by user. Wait for resume.]" : "\n[Continue working until the goal is achieved.]";
|