newmark-agent 0.5.8 → 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.
@@ -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, input) {
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, input);
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, input),
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, input) {
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, input);
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, input),
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);
@@ -331318,8 +331318,8 @@ async function fuzzyDiscoverWithoutGuide(input, explicit, preferredModels = [])
331318
331318
  }
331319
331319
 
331320
331320
  // src/tools/index.ts
331321
- var fs14 = __toESM(require("fs"));
331322
- var path16 = __toESM(require("path"));
331321
+ var fs15 = __toESM(require("fs"));
331322
+ var path17 = __toESM(require("path"));
331323
331323
  var crypto8 = __toESM(require("crypto"));
331324
331324
  var import_url2 = require("url");
331325
331325
 
@@ -331663,7 +331663,8 @@ var MemoryLabManager = class {
331663
331663
  "Use memory_lab_read to inspect index.json before deciding what memory is relevant.",
331664
331664
  "Use memory_lab_query for bounded task-relevant retrieval; do not inject the complete index when a focused query is sufficient.",
331665
331665
  "Use memory_lab_read with component/name/slug to read a component core markdown file.",
331666
- "Use memory_lab_update only when the user asks to create or update durable memory, passing name, description, tags, optional tagPaths, content, and optional kind=file|folder.",
331666
+ "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.",
331667
+ "For small body edits prefer contentAppend or oldText/newText over resending the complete content.",
331667
331668
  "For an existing component, pass expectedUpdatedAt from the latest read/query result. A stale update is rejected instead of overwriting newer memory.",
331668
331669
  "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.",
331669
331670
  "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.",
@@ -331771,6 +331772,39 @@ var MemoryLabManager = class {
331771
331772
  source: String(input.source || "").trim()
331772
331773
  };
331773
331774
  }
331775
+ preparePatch(input) {
331776
+ const selector2 = String(input.component || "").trim();
331777
+ if (!selector2) throw new Error("Memory component is required for a patch.");
331778
+ const current = this.read(selector2);
331779
+ if (!current.ok || !current.component) throw new Error(current.error || `Memory component not found: ${selector2}`);
331780
+ const existing = current.component.meta;
331781
+ const oldContent = current.component.content;
331782
+ let content = input.content !== void 0 ? String(input.content) : oldContent;
331783
+ if (input.contentAppend !== void 0) content = `${oldContent}${String(input.contentAppend)}`;
331784
+ if (input.oldText !== void 0) {
331785
+ const oldText = String(input.oldText);
331786
+ if (!oldText) throw new Error("oldText must not be empty.");
331787
+ const matches = oldContent.split(oldText).length - 1;
331788
+ if (!matches) throw new Error("oldText was not found in the Memory Lab component.");
331789
+ if (matches > 1 && input.replaceAll !== true) throw new Error(`oldText matched ${matches} places; pass replaceAll=true or a unique fragment.`);
331790
+ content = input.replaceAll === true ? oldContent.split(oldText).join(String(input.newText || "")) : oldContent.replace(oldText, String(input.newText || ""));
331791
+ }
331792
+ const name50 = input.name === void 0 ? existing.name : String(input.name);
331793
+ if (this.slugify(name50) !== current.component.slug) {
331794
+ throw new Error("Renaming a Memory Lab component is not supported by incremental patch; create the new component then delete the old one.");
331795
+ }
331796
+ return this.prepareUpdate({
331797
+ name: name50,
331798
+ description: input.description === void 0 ? existing.description : String(input.description),
331799
+ tags: input.tags === void 0 ? existing.tags : input.tags,
331800
+ tagPaths: input.tagPaths === void 0 ? existing.tagPaths : input.tagPaths,
331801
+ content,
331802
+ kind: input.kind === void 0 ? existing.kind : input.kind,
331803
+ expectedUpdatedAt: String(input.expectedUpdatedAt || existing.updatedAt),
331804
+ reason: input.reason,
331805
+ source: input.source
331806
+ });
331807
+ }
331774
331808
  update(prepared) {
331775
331809
  this.ensure();
331776
331810
  const index = this.loadIndex();
@@ -332317,20 +332351,23 @@ ${JSON.stringify(payload, null, 2)}`;
332317
332351
  }
332318
332352
  };
332319
332353
 
332354
+ // src/tools/index.ts
332355
+ init_flow();
332356
+
332320
332357
  // src/core/compat.ts
332321
- var fs6 = __toESM(require("fs"));
332322
- var path7 = __toESM(require("path"));
332358
+ var fs7 = __toESM(require("fs"));
332359
+ var path8 = __toESM(require("path"));
332323
332360
  var os2 = __toESM(require("os"));
332324
332361
  function readJson(filePath) {
332325
332362
  try {
332326
- return JSON.parse(fs6.readFileSync(filePath, "utf-8").replace(/^\uFEFF/, ""));
332363
+ return JSON.parse(fs7.readFileSync(filePath, "utf-8").replace(/^\uFEFF/, ""));
332327
332364
  } catch {
332328
332365
  return null;
332329
332366
  }
332330
332367
  }
332331
332368
  function readJsonLoose(filePath) {
332332
332369
  try {
332333
- const withoutBom = fs6.readFileSync(filePath, "utf-8").replace(/^\uFEFF/, "");
332370
+ const withoutBom = fs7.readFileSync(filePath, "utf-8").replace(/^\uFEFF/, "");
332334
332371
  const withoutComments = withoutBom.replace(/\/\*[\s\S]*?\*\//g, "").replace(/(^|\s)\/\/.*$/gm, "$1");
332335
332372
  return JSON.parse(withoutComments);
332336
332373
  } catch {
@@ -332411,7 +332448,7 @@ function normalizeToolResult(output, metadata) {
332411
332448
  return { ok: !error, output, error, metadata };
332412
332449
  }
332413
332450
  function componentPaths(root2, value) {
332414
- return asStringArray(value).map((item) => path7.resolve(root2, item));
332451
+ return asStringArray(value).map((item) => path8.resolve(root2, item));
332415
332452
  }
332416
332453
  function manifestComponentPaths(root2, manifest, ...keys) {
332417
332454
  for (const key3 of keys) {
@@ -332422,7 +332459,7 @@ function manifestComponentPaths(root2, manifest, ...keys) {
332422
332459
  function discoverComponentFiles(root2, relativeDirs, extension, maxDepth = 2) {
332423
332460
  const files = [];
332424
332461
  for (const dir of relativeDirs) {
332425
- files.push(...listFilesRecursive(path7.join(root2, dir), extension, maxDepth));
332462
+ files.push(...listFilesRecursive(path8.join(root2, dir), extension, maxDepth));
332426
332463
  }
332427
332464
  return Array.from(new Set(files)).sort();
332428
332465
  }
@@ -332447,12 +332484,12 @@ function collectMcpServers(...values) {
332447
332484
  function defaultComponentWarnings(kind, components) {
332448
332485
  const warnings = [];
332449
332486
  for (const item of components) {
332450
- if (path7.isAbsolute(item) && !fs6.existsSync(item)) warnings.push(`${kind} path does not exist: ${item}`);
332487
+ if (path8.isAbsolute(item) && !fs7.existsSync(item)) warnings.push(`${kind} path does not exist: ${item}`);
332451
332488
  }
332452
332489
  return warnings;
332453
332490
  }
332454
332491
  function normalizeCodexPlugin(root2, manifest) {
332455
- const name50 = asString(manifest.name) || path7.basename(root2);
332492
+ const name50 = asString(manifest.name) || path8.basename(root2);
332456
332493
  const components = {
332457
332494
  skills: manifestComponentPaths(root2, manifest, "skills"),
332458
332495
  agents: manifestComponentPaths(root2, manifest, "agents"),
@@ -332483,7 +332520,7 @@ function normalizeCodexPlugin(root2, manifest) {
332483
332520
  };
332484
332521
  }
332485
332522
  function normalizeClaudePlugin(root2, manifest) {
332486
- const name50 = asString(manifest.name) || path7.basename(root2);
332523
+ const name50 = asString(manifest.name) || path8.basename(root2);
332487
332524
  const experimental = nestedRecord(manifest.experimental);
332488
332525
  const components = {
332489
332526
  skills: manifestComponentPaths(root2, manifest, "skills"),
@@ -332521,7 +332558,7 @@ function normalizeClaudePlugin(root2, manifest) {
332521
332558
  };
332522
332559
  }
332523
332560
  function normalizeNewmarkPlugin(root2, manifest) {
332524
- const name50 = asString(manifest.name) || path7.basename(root2);
332561
+ const name50 = asString(manifest.name) || path8.basename(root2);
332525
332562
  return {
332526
332563
  id: `newmark:${name50}`,
332527
332564
  ecosystem: "newmark",
@@ -332550,7 +332587,7 @@ function findPluginRoots(root2, maxDepth = 5) {
332550
332587
  if (depth > maxDepth) return;
332551
332588
  let entries;
332552
332589
  try {
332553
- entries = fs6.readdirSync(dir, { withFileTypes: true });
332590
+ entries = fs7.readdirSync(dir, { withFileTypes: true });
332554
332591
  } catch {
332555
332592
  return;
332556
332593
  }
@@ -332559,7 +332596,7 @@ function findPluginRoots(root2, maxDepth = 5) {
332559
332596
  }
332560
332597
  for (const entry of entries) {
332561
332598
  if (!entry.isDirectory() || skip.has(entry.name) || entry.name.startsWith("release.locked-")) continue;
332562
- walk4(path7.join(dir, entry.name), depth + 1);
332599
+ walk4(path8.join(dir, entry.name), depth + 1);
332563
332600
  }
332564
332601
  };
332565
332602
  walk4(root2, 0);
@@ -332568,20 +332605,20 @@ function findPluginRoots(root2, maxDepth = 5) {
332568
332605
  function discoverPluginManifests(root2) {
332569
332606
  const manifests = [];
332570
332607
  for (const pluginRoot of findPluginRoots(root2)) {
332571
- const codexPath = path7.join(pluginRoot, ".codex-plugin", "plugin.json");
332572
- const claudePath = path7.join(pluginRoot, ".claude-plugin", "plugin.json");
332573
- const newmarkPath = path7.join(pluginRoot, ".newmark-plugin", "plugin.json");
332574
- const codex = fs6.existsSync(codexPath) ? readJson(codexPath) : null;
332575
- const claude = fs6.existsSync(claudePath) ? readJson(claudePath) : null;
332576
- const newmark = fs6.existsSync(newmarkPath) ? readJson(newmarkPath) : null;
332608
+ const codexPath = path8.join(pluginRoot, ".codex-plugin", "plugin.json");
332609
+ const claudePath = path8.join(pluginRoot, ".claude-plugin", "plugin.json");
332610
+ const newmarkPath = path8.join(pluginRoot, ".newmark-plugin", "plugin.json");
332611
+ const codex = fs7.existsSync(codexPath) ? readJson(codexPath) : null;
332612
+ const claude = fs7.existsSync(claudePath) ? readJson(claudePath) : null;
332613
+ const newmark = fs7.existsSync(newmarkPath) ? readJson(newmarkPath) : null;
332577
332614
  if (codex && typeof codex === "object") manifests.push(normalizeCodexPlugin(pluginRoot, codex));
332578
332615
  if (claude && typeof claude === "object") manifests.push(normalizeClaudePlugin(pluginRoot, claude));
332579
332616
  if (newmark && typeof newmark === "object") manifests.push(normalizeNewmarkPlugin(pluginRoot, newmark));
332580
332617
  }
332581
332618
  const projectOpencode = readOpenCodeManifest(root2, "project");
332582
332619
  if (projectOpencode) manifests.push(projectOpencode);
332583
- const userOpenCodeRoot = path7.join(os2.homedir(), ".config", "opencode");
332584
- if (path7.resolve(userOpenCodeRoot) !== path7.resolve(path7.join(root2, ".opencode"))) {
332620
+ const userOpenCodeRoot = path8.join(os2.homedir(), ".config", "opencode");
332621
+ if (path8.resolve(userOpenCodeRoot) !== path8.resolve(path8.join(root2, ".opencode"))) {
332585
332622
  const userOpenCode = readOpenCodeManifest(userOpenCodeRoot, "user");
332586
332623
  if (userOpenCode) manifests.push(userOpenCode);
332587
332624
  }
@@ -332589,20 +332626,20 @@ function discoverPluginManifests(root2) {
332589
332626
  }
332590
332627
  function readOpenCodeConfig(root2) {
332591
332628
  const candidates = [
332592
- path7.join(root2, "opencode.json"),
332593
- path7.join(root2, "opencode.jsonc"),
332594
- path7.join(root2, ".opencode", "opencode.json"),
332595
- path7.join(root2, ".opencode", "opencode.jsonc")
332629
+ path8.join(root2, "opencode.json"),
332630
+ path8.join(root2, "opencode.jsonc"),
332631
+ path8.join(root2, ".opencode", "opencode.json"),
332632
+ path8.join(root2, ".opencode", "opencode.jsonc")
332596
332633
  ];
332597
332634
  for (const filePath of candidates) {
332598
- if (fs6.existsSync(filePath)) return { path: filePath, value: readJsonLoose(filePath) };
332635
+ if (fs7.existsSync(filePath)) return { path: filePath, value: readJsonLoose(filePath) };
332599
332636
  }
332600
332637
  return null;
332601
332638
  }
332602
332639
  function readOpenCodeManifest(root2, scope) {
332603
- const localRoot = scope === "project" ? path7.join(root2, ".opencode") : root2;
332604
- const opencodeToolsDir = path7.join(localRoot, "tools");
332605
- const opencodePluginsDir = path7.join(localRoot, "plugins");
332640
+ const localRoot = scope === "project" ? path8.join(root2, ".opencode") : root2;
332641
+ const opencodeToolsDir = path8.join(localRoot, "tools");
332642
+ const opencodePluginsDir = path8.join(localRoot, "plugins");
332606
332643
  const tools = listCodeFiles(opencodeToolsDir);
332607
332644
  const pluginFiles = listCodeFiles(opencodePluginsDir);
332608
332645
  const config = readOpenCodeConfig(root2);
@@ -332643,18 +332680,18 @@ function readOpenCodeManifest(root2, scope) {
332643
332680
  }
332644
332681
  function discoverOpenCodeInstructionFiles(projectRoot, localRoot) {
332645
332682
  const candidates = [
332646
- path7.join(projectRoot, "AGENTS.md"),
332647
- path7.join(projectRoot, ".opencode", "instructions.md"),
332648
- path7.join(projectRoot, ".opencode", "AGENTS.md"),
332649
- path7.join(localRoot, "instructions.md"),
332650
- path7.join(localRoot, "AGENTS.md")
332683
+ path8.join(projectRoot, "AGENTS.md"),
332684
+ path8.join(projectRoot, ".opencode", "instructions.md"),
332685
+ path8.join(projectRoot, ".opencode", "AGENTS.md"),
332686
+ path8.join(localRoot, "instructions.md"),
332687
+ path8.join(localRoot, "AGENTS.md")
332651
332688
  ];
332652
- return Array.from(new Set(candidates.filter((filePath) => fs6.existsSync(filePath)))).sort();
332689
+ return Array.from(new Set(candidates.filter((filePath) => fs7.existsSync(filePath)))).sort();
332653
332690
  }
332654
332691
  function dedupeManifests(manifests) {
332655
332692
  const seen = /* @__PURE__ */ new Set();
332656
332693
  return manifests.filter((item) => {
332657
- const key3 = `${item.id}:${path7.resolve(item.root)}`;
332694
+ const key3 = `${item.id}:${path8.resolve(item.root)}`;
332658
332695
  if (seen.has(key3)) return false;
332659
332696
  seen.add(key3);
332660
332697
  return true;
@@ -332662,14 +332699,14 @@ function dedupeManifests(manifests) {
332662
332699
  }
332663
332700
  function listCodeFiles(dir) {
332664
332701
  try {
332665
- return fs6.readdirSync(dir, { withFileTypes: true }).filter((e3) => e3.isFile() && /\.(?:c?js|mjs|ts)$/.test(e3.name)).map((e3) => path7.join(dir, e3.name)).sort();
332702
+ 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();
332666
332703
  } catch {
332667
332704
  return [];
332668
332705
  }
332669
332706
  }
332670
332707
  function parseFrontmatterMarkdown(filePath) {
332671
332708
  try {
332672
- const content = fs6.readFileSync(filePath, "utf-8").replace(/^\uFEFF/, "");
332709
+ const content = fs7.readFileSync(filePath, "utf-8").replace(/^\uFEFF/, "");
332673
332710
  const match = content.match(/^---\s*([\s\S]*?)\s*---\s*/);
332674
332711
  if (!match) return { metadata: {}, body: content };
332675
332712
  const metadata = {};
@@ -332698,7 +332735,7 @@ function parseMetadataValue(raw) {
332698
332735
  function parseSimpleToml(filePath) {
332699
332736
  try {
332700
332737
  const metadata = {};
332701
- const content = fs6.readFileSync(filePath, "utf-8").replace(/^\uFEFF/, "");
332738
+ const content = fs7.readFileSync(filePath, "utf-8").replace(/^\uFEFF/, "");
332702
332739
  const multiline = null;
332703
332740
  if (multiline) return metadata;
332704
332741
  const lines = content.split(/\r?\n/);
@@ -332732,7 +332769,7 @@ function parseSimpleToml(filePath) {
332732
332769
  }
332733
332770
  }
332734
332771
  function agentPresetFromMetadata(filePath, ecosystem, metadata, body = "") {
332735
- const name50 = asString(metadata.name) || path7.basename(filePath).replace(/\.(?:toml|md)$/i, "");
332772
+ const name50 = asString(metadata.name) || path8.basename(filePath).replace(/\.(?:toml|md)$/i, "");
332736
332773
  const description = asString(metadata.description);
332737
332774
  const instructions = asString(metadata.developer_instructions || metadata.instructions || metadata.prompt) || body.trim();
332738
332775
  if (!name50 || !description) return null;
@@ -332760,12 +332797,12 @@ function listFilesRecursive(root2, extension, maxDepth = 4) {
332760
332797
  if (depth > maxDepth) return;
332761
332798
  let entries;
332762
332799
  try {
332763
- entries = fs6.readdirSync(dir, { withFileTypes: true });
332800
+ entries = fs7.readdirSync(dir, { withFileTypes: true });
332764
332801
  } catch {
332765
332802
  return;
332766
332803
  }
332767
332804
  for (const entry of entries) {
332768
- const full = path7.join(dir, entry.name);
332805
+ const full = path8.join(dir, entry.name);
332769
332806
  if (entry.isFile() && extension.test(entry.name)) results.push(full);
332770
332807
  if (entry.isDirectory() && !entry.name.startsWith(".git") && entry.name !== "node_modules") walk4(full, depth + 1);
332771
332808
  }
@@ -332776,10 +332813,10 @@ function listFilesRecursive(root2, extension, maxDepth = 4) {
332776
332813
  function discoverAgentPresets(root2) {
332777
332814
  const presets = [];
332778
332815
  const codexDirs = [
332779
- path7.join(root2, ".codex", "agents"),
332780
- path7.join(root2, ".agents", "agents"),
332781
- path7.join(os2.homedir(), ".codex", "agents"),
332782
- path7.join(os2.homedir(), ".agents", "agents")
332816
+ path8.join(root2, ".codex", "agents"),
332817
+ path8.join(root2, ".agents", "agents"),
332818
+ path8.join(os2.homedir(), ".codex", "agents"),
332819
+ path8.join(os2.homedir(), ".agents", "agents")
332783
332820
  ];
332784
332821
  for (const dir of codexDirs) {
332785
332822
  for (const filePath of listFilesRecursive(dir, /\.toml$/i, 1)) {
@@ -332788,14 +332825,14 @@ function discoverAgentPresets(root2) {
332788
332825
  }
332789
332826
  }
332790
332827
  const claudeDirs = [
332791
- path7.join(root2, ".claude", "agents"),
332792
- path7.join(os2.homedir(), ".claude", "agents"),
332793
- path7.join(os2.homedir(), ".config", "opencode", "agents")
332828
+ path8.join(root2, ".claude", "agents"),
332829
+ path8.join(os2.homedir(), ".claude", "agents"),
332830
+ path8.join(os2.homedir(), ".config", "opencode", "agents")
332794
332831
  ];
332795
332832
  for (const dir of claudeDirs) {
332796
332833
  for (const filePath of listFilesRecursive(dir, /\.md$/i, 1)) {
332797
332834
  const parsed = parseFrontmatterMarkdown(filePath);
332798
- const ecosystem = filePath.includes(`${path7.sep}.config${path7.sep}opencode${path7.sep}`) ? "opencode" : "claude-code";
332835
+ const ecosystem = filePath.includes(`${path8.sep}.config${path8.sep}opencode${path8.sep}`) ? "opencode" : "claude-code";
332799
332836
  const preset = agentPresetFromMetadata(filePath, ecosystem, parsed.metadata, parsed.body);
332800
332837
  if (preset) presets.push(preset);
332801
332838
  }
@@ -332832,15 +332869,15 @@ function findAgentPreset(root2, selector2) {
332832
332869
  preset.id,
332833
332870
  preset.name,
332834
332871
  `${preset.ecosystem}:${preset.name}`,
332835
- path7.basename(preset.path)
332872
+ path8.basename(preset.path)
332836
332873
  ].map((value) => String(value || "").toLowerCase());
332837
- return keys.includes(normalized) || path7.resolve(preset.path).toLowerCase() === path7.resolve(wanted).toLowerCase();
332874
+ return keys.includes(normalized) || path8.resolve(preset.path).toLowerCase() === path8.resolve(wanted).toLowerCase();
332838
332875
  }) || null;
332839
332876
  }
332840
332877
 
332841
332878
  // src/tools/terminalTakeover.ts
332842
- var fs7 = __toESM(require("fs"));
332843
- var path8 = __toESM(require("path"));
332879
+ var fs8 = __toESM(require("fs"));
332880
+ var path9 = __toESM(require("path"));
332844
332881
  var import_child_process2 = require("child_process");
332845
332882
  var import_crypto5 = require("crypto");
332846
332883
  var ROOT_TERMINAL_ACTOR_ID = "00000000-0000-4000-8000-000000000001";
@@ -332855,7 +332892,7 @@ function isoNow() {
332855
332892
  return (/* @__PURE__ */ new Date()).toISOString();
332856
332893
  }
332857
332894
  function canonicalPersistenceRoot(root2) {
332858
- const resolved = path8.resolve(root2 || process.cwd());
332895
+ const resolved = path9.resolve(root2 || process.cwd());
332859
332896
  return process.platform === "win32" ? resolved.toLowerCase() : resolved;
332860
332897
  }
332861
332898
  function portableWorkspacePath(input) {
@@ -332864,7 +332901,7 @@ function portableWorkspacePath(input) {
332864
332901
  if (wsl) return `${wsl[1].toLowerCase()}:/${String(wsl[2] || "").replace(/^\/+|\/+$/g, "")}`.replace(/\/$/, "");
332865
332902
  const drive = /^([a-zA-Z]):(?:\/(.*))?$/.exec(raw);
332866
332903
  if (drive) return `${drive[1].toLowerCase()}:/${String(drive[2] || "").replace(/^\/+|\/+$/g, "")}`.replace(/\/$/, "");
332867
- const resolved = path8.resolve(raw).replace(/\\/g, "/").replace(/\/+$/g, "");
332904
+ const resolved = path9.resolve(raw).replace(/\\/g, "/").replace(/\/+$/g, "");
332868
332905
  return process.platform === "win32" ? resolved.toLowerCase() : resolved;
332869
332906
  }
332870
332907
  function terminalTakeoverWorkspaceId(workspacePath) {
@@ -332959,12 +332996,12 @@ function nodePtyHasConptyDll() {
332959
332996
  if (process.platform !== "win32") return false;
332960
332997
  try {
332961
332998
  const packageJson = require.resolve("node-pty/package.json");
332962
- const packageRoot = path8.dirname(packageJson);
332999
+ const packageRoot = path9.dirname(packageJson);
332963
333000
  return [
332964
- path8.join(packageRoot, "build", "Release", "conpty", "conpty.dll"),
332965
- path8.join(packageRoot, "build", "Debug", "conpty", "conpty.dll"),
332966
- path8.join(packageRoot, "prebuilds", `${process.platform}-${process.arch}`, "conpty", "conpty.dll")
332967
- ].some((candidate) => fs7.existsSync(candidate));
333001
+ path9.join(packageRoot, "build", "Release", "conpty", "conpty.dll"),
333002
+ path9.join(packageRoot, "build", "Debug", "conpty", "conpty.dll"),
333003
+ path9.join(packageRoot, "prebuilds", `${process.platform}-${process.arch}`, "conpty", "conpty.dll")
333004
+ ].some((candidate) => fs8.existsSync(candidate));
332968
333005
  } catch {
332969
333006
  return false;
332970
333007
  }
@@ -333197,7 +333234,7 @@ function spawnTakeoverPty(shell, cwd, env, cols, rows) {
333197
333234
  };
333198
333235
  }
333199
333236
  function persistencePath(root2) {
333200
- return path8.join(root2, "Terminal", "Takeover.json");
333237
+ return path9.join(root2, "Terminal", "Takeover.json");
333201
333238
  }
333202
333239
  function validPersistedRecord(input) {
333203
333240
  if (!input || typeof input !== "object") return null;
@@ -333238,7 +333275,7 @@ function ensurePersistenceLoaded(rootRaw) {
333238
333275
  if (loaded) return loaded;
333239
333276
  const records = /* @__PURE__ */ new Map();
333240
333277
  try {
333241
- const parsed = JSON.parse(fs7.readFileSync(persistencePath(root2), "utf-8"));
333278
+ const parsed = JSON.parse(fs8.readFileSync(persistencePath(root2), "utf-8"));
333242
333279
  if (Array.isArray(parsed.records)) {
333243
333280
  for (const input of parsed.records) {
333244
333281
  const record = validPersistedRecord(input);
@@ -333256,19 +333293,19 @@ function persistEndedRecords(rootRaw) {
333256
333293
  const output = { version: 1, updatedAt: isoNow(), records };
333257
333294
  const filePath = persistencePath(root2);
333258
333295
  const tempPath = `${filePath}.tmp-${process.pid}-${(0, import_crypto5.randomUUID)()}`;
333259
- fs7.mkdirSync(path8.dirname(filePath), { recursive: true });
333260
- const fd = fs7.openSync(tempPath, "w");
333296
+ fs8.mkdirSync(path9.dirname(filePath), { recursive: true });
333297
+ const fd = fs8.openSync(tempPath, "w");
333261
333298
  try {
333262
- fs7.writeFileSync(fd, JSON.stringify(output, null, 2), "utf-8");
333263
- fs7.fsyncSync(fd);
333299
+ fs8.writeFileSync(fd, JSON.stringify(output, null, 2), "utf-8");
333300
+ fs8.fsyncSync(fd);
333264
333301
  } finally {
333265
- fs7.closeSync(fd);
333302
+ fs8.closeSync(fd);
333266
333303
  }
333267
333304
  try {
333268
- fs7.renameSync(tempPath, filePath);
333305
+ fs8.renameSync(tempPath, filePath);
333269
333306
  } catch (error) {
333270
333307
  try {
333271
- fs7.rmSync(tempPath, { force: true });
333308
+ fs8.rmSync(tempPath, { force: true });
333272
333309
  } catch {
333273
333310
  }
333274
333311
  throw error;
@@ -333497,8 +333534,8 @@ function runTerminalTakeover(input) {
333497
333534
  }
333498
333535
 
333499
333536
  // src/tools/computerUse.ts
333500
- var fs8 = __toESM(require("fs"));
333501
- var path9 = __toESM(require("path"));
333537
+ var fs9 = __toESM(require("fs"));
333538
+ var path10 = __toESM(require("path"));
333502
333539
  var crypto6 = __toESM(require("crypto"));
333503
333540
  var os3 = __toESM(require("os"));
333504
333541
 
@@ -333706,8 +333743,8 @@ async function runPowerShell(script, timeout = 3e4, lane = "action") {
333706
333743
  return await runPersistentPowerShell(script, timeout, lane);
333707
333744
  }
333708
333745
  function tempScreenshotDir() {
333709
- const dir = path9.join(os3.tmpdir(), "newmark-computer-use");
333710
- fs8.mkdirSync(dir, { recursive: true });
333746
+ const dir = path10.join(os3.tmpdir(), "newmark-computer-use");
333747
+ fs9.mkdirSync(dir, { recursive: true });
333711
333748
  const now2 = Date.now();
333712
333749
  if (now2 - lastScreenshotCleanupAt >= SCREENSHOT_CLEANUP_INTERVAL_MS) {
333713
333750
  lastScreenshotCleanupAt = now2;
@@ -333729,7 +333766,7 @@ function ephemeralScreenshotPath(kind, directory = tempScreenshotDir(), createdA
333729
333766
  const pid = Math.max(1, Math.floor(Number(ownerPid) || process.pid));
333730
333767
  const timestamp = Math.max(0, Math.floor(Number(createdAt) || Date.now()));
333731
333768
  const nonce = /^[a-f0-9]{8}$/i.test(String(suffix)) ? String(suffix).toLowerCase() : crypto6.randomBytes(4).toString("hex");
333732
- return path9.join(directory, `${kind}-p${pid}-t${timestamp}-${nonce}.jpg`);
333769
+ return path10.join(directory, `${kind}-p${pid}-t${timestamp}-${nonce}.jpg`);
333733
333770
  }
333734
333771
  function isProcessAlive(pid) {
333735
333772
  if (!Number.isSafeInteger(pid) || pid <= 0) return false;
@@ -333742,14 +333779,14 @@ function isProcessAlive(pid) {
333742
333779
  }
333743
333780
  }
333744
333781
  function cleanupStaleScreenshots(options = {}) {
333745
- const directory = options.directory || path9.join(os3.tmpdir(), "newmark-computer-use");
333782
+ const directory = options.directory || path10.join(os3.tmpdir(), "newmark-computer-use");
333746
333783
  const now2 = Number.isFinite(Number(options.now)) ? Number(options.now) : Date.now();
333747
333784
  const processAlive = options.isProcessAlive || isProcessAlive;
333748
333785
  const ownedPattern = /^(?:observe|app)-p([1-9]\d*)-t(\d{10,16})-[a-f0-9]{8}\.jpg$/i;
333749
333786
  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;
333750
333787
  let names = [];
333751
333788
  try {
333752
- names = fs8.readdirSync(directory);
333789
+ names = fs9.readdirSync(directory);
333753
333790
  } catch {
333754
333791
  return { removed: 0 };
333755
333792
  }
@@ -333758,10 +333795,10 @@ function cleanupStaleScreenshots(options = {}) {
333758
333795
  const owned = ownedPattern.exec(name50);
333759
333796
  const isLegacy = !owned && legacyPattern.test(name50);
333760
333797
  if (!owned && !isLegacy) continue;
333761
- const filePath = path9.join(directory, name50);
333798
+ const filePath = path10.join(directory, name50);
333762
333799
  let stats;
333763
333800
  try {
333764
- stats = fs8.lstatSync(filePath);
333801
+ stats = fs9.lstatSync(filePath);
333765
333802
  if (!stats.isFile() || stats.isSymbolicLink()) continue;
333766
333803
  } catch {
333767
333804
  continue;
@@ -333785,7 +333822,7 @@ function cleanupStaleScreenshots(options = {}) {
333785
333822
  }
333786
333823
  if (!shouldRemove) continue;
333787
333824
  try {
333788
- fs8.unlinkSync(filePath);
333825
+ fs9.unlinkSync(filePath);
333789
333826
  removed += 1;
333790
333827
  } catch {
333791
333828
  }
@@ -333808,7 +333845,7 @@ function captureBounds(maxWidth, maxHeight) {
333808
333845
  }
333809
333846
  function removeEphemeralScreenshot(outPath) {
333810
333847
  try {
333811
- fs8.unlinkSync(outPath);
333848
+ fs9.unlinkSync(outPath);
333812
333849
  } catch {
333813
333850
  }
333814
333851
  }
@@ -333884,7 +333921,7 @@ async function startTakeoverOverlay(durationMs = 0, input = {}) {
333884
333921
  const width = 2;
333885
333922
  const speedSeconds = 3;
333886
333923
  const ownerPid = Math.max(0, Math.floor(Number(input.ownerPid ?? process.pid) || 0));
333887
- const scriptPath = path9.join(tempScreenshotDir(), `takeover-overlay-${timestampName()}-${crypto6.randomBytes(4).toString("hex")}.ps1`);
333924
+ const scriptPath = path10.join(tempScreenshotDir(), `takeover-overlay-${timestampName()}-${crypto6.randomBytes(4).toString("hex")}.ps1`);
333888
333925
  const script = [
333889
333926
  "Add-Type -AssemblyName System.Windows.Forms",
333890
333927
  "Add-Type -AssemblyName System.Drawing",
@@ -334023,7 +334060,7 @@ async function startTakeoverOverlay(durationMs = 0, input = {}) {
334023
334060
  "[System.Windows.Forms.Application]::Run()",
334024
334061
  "try { Remove-Item -LiteralPath $PSCommandPath -Force -ErrorAction SilentlyContinue } catch {}"
334025
334062
  ].filter(Boolean).join("\r\n");
334026
- fs8.writeFileSync(scriptPath, `\uFEFF${script}`, "utf8");
334063
+ fs9.writeFileSync(scriptPath, `\uFEFF${script}`, "utf8");
334027
334064
  const createCommand = [
334028
334065
  `$cmd = 'powershell.exe -NoProfile -ExecutionPolicy Bypass -File ' + ${psQuote(`"${scriptPath}"`)}`,
334029
334066
  `$startup = ([wmiclass]'Win32_ProcessStartup').CreateInstance()`,
@@ -334036,7 +334073,7 @@ async function startTakeoverOverlay(durationMs = 0, input = {}) {
334036
334073
  const pid = Number(String(result.output || "").trim().split(/\r?\n/).pop() || 0);
334037
334074
  if (!Number.isFinite(pid) || pid <= 0 || !result.ok) {
334038
334075
  try {
334039
- fs8.unlinkSync(scriptPath);
334076
+ fs9.unlinkSync(scriptPath);
334040
334077
  } catch {
334041
334078
  }
334042
334079
  return { ok: false, action: "takeover_start", error: result.output || "Overlay failed to start." };
@@ -334063,7 +334100,7 @@ function parseJsonArray(text) {
334063
334100
  return [];
334064
334101
  }
334065
334102
  function observationKey(workspacePath, ownerId) {
334066
- return `${path9.resolve(workspacePath || process.cwd()).toLowerCase()}::${String(ownerId || "direct")}`;
334103
+ return `${path10.resolve(workspacePath || process.cwd()).toLowerCase()}::${String(ownerId || "direct")}`;
334067
334104
  }
334068
334105
  function sceneGeneration(apps, elements) {
334069
334106
  const seed = [
@@ -334279,7 +334316,7 @@ async function cropScreenshot(workspacePath, ownerId, allowEphemeralVisionImage,
334279
334316
  ...parsed
334280
334317
  };
334281
334318
  if (includeRawUi) payload.perception.elements = elements;
334282
- const imageAvailable = parsed.image_available === true && fs8.existsSync(outPath);
334319
+ const imageAvailable = parsed.image_available === true && fs9.existsSync(outPath);
334283
334320
  if (allowEphemeralVisionImage && imageAvailable) {
334284
334321
  payload.vision_image_path = outPath;
334285
334322
  retainedForVision = true;
@@ -334542,7 +334579,7 @@ async function screenshot(workspacePath, ownerId, allowEphemeralVisionImage, inc
334542
334579
  ...parsed
334543
334580
  };
334544
334581
  if (includeRawUi) payload.perception.elements = ui.elements;
334545
- const imageAvailable = parsed.image_available === true && fs8.existsSync(outPath);
334582
+ const imageAvailable = parsed.image_available === true && fs9.existsSync(outPath);
334546
334583
  if (allowEphemeralVisionImage && imageAvailable) {
334547
334584
  payload.vision_image_path = outPath;
334548
334585
  retainedForVision = true;
@@ -334866,13 +334903,13 @@ async function runComputerUse(options) {
334866
334903
  }
334867
334904
 
334868
334905
  // src/core/ssh.ts
334869
- var fs10 = __toESM(require("fs"));
334870
- var path11 = __toESM(require("path"));
334906
+ var fs11 = __toESM(require("fs"));
334907
+ var path12 = __toESM(require("path"));
334871
334908
 
334872
334909
  // src/core/asyncProcess.ts
334873
334910
  var import_child_process4 = require("child_process");
334874
- var fs9 = __toESM(require("fs/promises"));
334875
- var path10 = __toESM(require("path"));
334911
+ var fs10 = __toESM(require("fs/promises"));
334912
+ var path11 = __toESM(require("path"));
334876
334913
  var STOP_SETTLEMENT_WATCHDOG_MS = 500;
334877
334914
  function signalMessage(signal) {
334878
334915
  const reason = signal?.reason;
@@ -334882,7 +334919,7 @@ function signalMessage(signal) {
334882
334919
  }
334883
334920
  function trustedWindowsTaskkillPath() {
334884
334921
  const windowsRoot = String(process.env.SystemRoot || process.env.WINDIR || "C:\\Windows");
334885
- return path10.join(windowsRoot, "System32", "taskkill.exe");
334922
+ return path11.join(windowsRoot, "System32", "taskkill.exe");
334886
334923
  }
334887
334924
  function stopProcessTree(child) {
334888
334925
  const pid = child.pid;
@@ -335051,7 +335088,7 @@ async function runAsyncWindowsBatch(command, args, options = {}) {
335051
335088
  }
335052
335089
  async function accessible(filePath) {
335053
335090
  try {
335054
- await fs9.access(filePath);
335091
+ await fs10.access(filePath);
335055
335092
  return true;
335056
335093
  } catch {
335057
335094
  return false;
@@ -335060,14 +335097,14 @@ async function accessible(filePath) {
335060
335097
  async function resolveWindowsLauncher(command) {
335061
335098
  const clean = String(command || "").trim();
335062
335099
  if (!clean) return "";
335063
- if (path10.isAbsolute(clean) || /[\\/]/.test(clean)) {
335064
- const absolute = path10.resolve(clean);
335100
+ if (path11.isAbsolute(clean) || /[\\/]/.test(clean)) {
335101
+ const absolute = path11.resolve(clean);
335065
335102
  return await accessible(absolute) ? absolute : "";
335066
335103
  }
335067
- for (const entry of String(process.env.PATH || "").split(path10.delimiter)) {
335104
+ for (const entry of String(process.env.PATH || "").split(path11.delimiter)) {
335068
335105
  const directory = entry.trim().replace(/^"|"$/g, "");
335069
335106
  if (!directory) continue;
335070
- const candidate = path10.join(directory, clean);
335107
+ const candidate = path11.join(directory, clean);
335071
335108
  if (await accessible(candidate)) return candidate;
335072
335109
  }
335073
335110
  return "";
@@ -335075,11 +335112,11 @@ async function resolveWindowsLauncher(command) {
335075
335112
  async function resolveNpmBatchTarget(batchPath) {
335076
335113
  let source = "";
335077
335114
  try {
335078
- source = await fs9.readFile(batchPath, "utf8");
335115
+ source = await fs10.readFile(batchPath, "utf8");
335079
335116
  } catch {
335080
335117
  return null;
335081
335118
  }
335082
- const directory = path10.dirname(batchPath);
335119
+ const directory = path11.dirname(batchPath);
335083
335120
  let relativeScript = "";
335084
335121
  const direct = /(?:%~dp0|%dp0%)\\?([^"\r\n]+)"\s+%\*/i.exec(source);
335085
335122
  if (direct) relativeScript = direct[1];
@@ -335093,10 +335130,10 @@ async function resolveNpmBatchTarget(batchPath) {
335093
335130
  }
335094
335131
  }
335095
335132
  if (!relativeScript) return null;
335096
- const scriptPath = path10.resolve(directory, relativeScript.replace(/\\/g, path10.sep));
335097
- const directoryPrefix = `${path10.resolve(directory).toLowerCase()}${path10.sep}`;
335133
+ const scriptPath = path11.resolve(directory, relativeScript.replace(/\\/g, path11.sep));
335134
+ const directoryPrefix = `${path11.resolve(directory).toLowerCase()}${path11.sep}`;
335098
335135
  if (!scriptPath.toLowerCase().startsWith(directoryPrefix) || !await accessible(scriptPath)) return null;
335099
- const siblingNode = path10.join(directory, "node.exe");
335136
+ const siblingNode = path11.join(directory, "node.exe");
335100
335137
  const nodePath = await accessible(siblingNode) ? siblingNode : await resolveWindowsLauncher("node.exe") || await resolveWindowsLauncher("node");
335101
335138
  return nodePath ? { nodePath, scriptPath } : null;
335102
335139
  }
@@ -335139,19 +335176,19 @@ var SshManager = class {
335139
335176
  rootPath;
335140
335177
  runner;
335141
335178
  storePath() {
335142
- return path11.join(this.rootPath, "Work", "SSH.json");
335179
+ return path12.join(this.rootPath, "Work", "SSH.json");
335143
335180
  }
335144
335181
  ensureStore() {
335145
335182
  try {
335146
- fs10.mkdirSync(path11.join(this.rootPath, "Work"), { recursive: true });
335147
- if (!fs10.existsSync(this.storePath())) fs10.writeFileSync(this.storePath(), "[]", "utf-8");
335183
+ fs11.mkdirSync(path12.join(this.rootPath, "Work"), { recursive: true });
335184
+ if (!fs11.existsSync(this.storePath())) fs11.writeFileSync(this.storePath(), "[]", "utf-8");
335148
335185
  } catch {
335149
335186
  }
335150
335187
  }
335151
335188
  readRaw() {
335152
335189
  this.ensureStore();
335153
335190
  try {
335154
- const parsed = JSON.parse(fs10.readFileSync(this.storePath(), "utf-8").replace(/^\uFEFF/, ""));
335191
+ const parsed = JSON.parse(fs11.readFileSync(this.storePath(), "utf-8").replace(/^\uFEFF/, ""));
335155
335192
  if (!Array.isArray(parsed)) return [];
335156
335193
  return parsed.map((item) => this.normalize(item)).filter((item) => !!item);
335157
335194
  } catch {
@@ -335160,7 +335197,7 @@ var SshManager = class {
335160
335197
  }
335161
335198
  writeRaw(items) {
335162
335199
  this.ensureStore();
335163
- fs10.writeFileSync(this.storePath(), JSON.stringify(items, null, 2), "utf-8");
335200
+ fs11.writeFileSync(this.storePath(), JSON.stringify(items, null, 2), "utf-8");
335164
335201
  }
335165
335202
  normalize(raw) {
335166
335203
  if (!raw || typeof raw !== "object" || Array.isArray(raw)) return null;
@@ -335340,8 +335377,8 @@ var SshManager = class {
335340
335377
  };
335341
335378
 
335342
335379
  // src/core/workspace.ts
335343
- var fs11 = __toESM(require("fs"));
335344
- var path12 = __toESM(require("path"));
335380
+ var fs12 = __toESM(require("fs"));
335381
+ var path13 = __toESM(require("path"));
335345
335382
  var crypto7 = __toESM(require("crypto"));
335346
335383
  function lastEmbeddedWindowsPath(input) {
335347
335384
  const matcher = /[A-Za-z]:[\\/]/g;
@@ -335360,22 +335397,22 @@ function normalizeHostWorkspacePath(input, platform = process.platform) {
335360
335397
  const raw = String(input || "").trim();
335361
335398
  const embeddedWindowsPath = lastEmbeddedWindowsPath(raw);
335362
335399
  if (platform === "win32") {
335363
- if (embeddedWindowsPath) return path12.win32.normalize(embeddedWindowsPath.replace(/\//g, "\\"));
335400
+ if (embeddedWindowsPath) return path13.win32.normalize(embeddedWindowsPath.replace(/\//g, "\\"));
335364
335401
  const wsl = /^\/mnt\/([a-zA-Z])(?:\/(.*))?$/.exec(raw.replace(/\\/g, "/"));
335365
- if (wsl) return path12.win32.normalize(`${wsl[1].toUpperCase()}:\\${String(wsl[2] || "").replace(/\//g, "\\")}`);
335366
- return path12.win32.resolve(raw || ".");
335402
+ if (wsl) return path13.win32.normalize(`${wsl[1].toUpperCase()}:\\${String(wsl[2] || "").replace(/\//g, "\\")}`);
335403
+ return path13.win32.resolve(raw || ".");
335367
335404
  }
335368
335405
  if (platform === "linux" && embeddedWindowsPath) {
335369
335406
  const drive = embeddedWindowsPath[0].toLowerCase();
335370
335407
  const rest = embeddedWindowsPath.slice(3).replace(/\\/g, "/").replace(/^\/+/, "");
335371
- return path12.posix.resolve(`/mnt/${drive}/${rest}`);
335408
+ return path13.posix.resolve(`/mnt/${drive}/${rest}`);
335372
335409
  }
335373
- return path12.posix.resolve(raw || ".");
335410
+ return path13.posix.resolve(raw || ".");
335374
335411
  }
335375
335412
  function isPathInside(parent, child) {
335376
335413
  try {
335377
- const relative6 = path12.relative(path12.resolve(parent), path12.resolve(child));
335378
- return relative6 === "" || !!relative6 && !relative6.startsWith("..") && !path12.isAbsolute(relative6);
335414
+ const relative6 = path13.relative(path13.resolve(parent), path13.resolve(child));
335415
+ return relative6 === "" || !!relative6 && !relative6.startsWith("..") && !path13.isAbsolute(relative6);
335379
335416
  } catch {
335380
335417
  return false;
335381
335418
  }
@@ -335383,7 +335420,7 @@ function isPathInside(parent, child) {
335383
335420
  function isProtectedInstallWorkspacePath(candidate) {
335384
335421
  const value = String(candidate || "").trim();
335385
335422
  if (!value) return false;
335386
- const roots = [path12.dirname(process.execPath)];
335423
+ const roots = [path13.dirname(process.execPath)];
335387
335424
  if (process.platform === "win32") {
335388
335425
  roots.push(
335389
335426
  process.env.ProgramFiles || "",
@@ -335391,7 +335428,7 @@ function isProtectedInstallWorkspacePath(candidate) {
335391
335428
  process.env.ProgramW6432 || ""
335392
335429
  );
335393
335430
  }
335394
- const resolved = path12.resolve(value);
335431
+ const resolved = path13.resolve(value);
335395
335432
  return roots.filter(Boolean).some((root2) => isPathInside(root2, resolved));
335396
335433
  }
335397
335434
  var WorkspaceManager = class {
@@ -335401,16 +335438,16 @@ var WorkspaceManager = class {
335401
335438
  this.detached = options.detached === true;
335402
335439
  this.pcHash = this.loadPcHash();
335403
335440
  if (this.detached) return;
335404
- const workDir = path12.join(rootPath, "Work");
335441
+ const workDir = path13.join(rootPath, "Work");
335405
335442
  try {
335406
- fs11.mkdirSync(workDir, { recursive: true });
335443
+ fs12.mkdirSync(workDir, { recursive: true });
335407
335444
  } catch {
335408
335445
  }
335409
335446
  for (const fn of ["Local.json", "External.json"]) {
335410
- const p = path12.join(workDir, fn);
335411
- if (!fs11.existsSync(p)) {
335447
+ const p = path13.join(workDir, fn);
335448
+ if (!fs12.existsSync(p)) {
335412
335449
  try {
335413
- fs11.writeFileSync(p, "[]", "utf-8");
335450
+ fs12.writeFileSync(p, "[]", "utf-8");
335414
335451
  } catch {
335415
335452
  }
335416
335453
  }
@@ -335431,7 +335468,7 @@ var WorkspaceManager = class {
335431
335468
  detached;
335432
335469
  loadPcHash() {
335433
335470
  try {
335434
- const h2 = fs11.readFileSync(path12.join(this.rootPath, "PC_Hash.config"), "utf-8");
335471
+ const h2 = fs12.readFileSync(path13.join(this.rootPath, "PC_Hash.config"), "utf-8");
335435
335472
  return h2.trim();
335436
335473
  } catch {
335437
335474
  return "";
@@ -335446,19 +335483,19 @@ var WorkspaceManager = class {
335446
335483
  if (this.external.length !== before) this.saveExternal();
335447
335484
  }
335448
335485
  scan() {
335449
- const w = path12.join(this.rootPath, "Work");
335450
- if (!fs11.existsSync(w)) return;
335486
+ const w = path13.join(this.rootPath, "Work");
335487
+ if (!fs12.existsSync(w)) return;
335451
335488
  let internalChanged = false;
335452
335489
  let externalChanged = false;
335453
335490
  try {
335454
- const local = JSON.parse(fs11.readFileSync(path12.join(w, "Local.json"), "utf-8"));
335491
+ const local = JSON.parse(fs12.readFileSync(path13.join(w, "Local.json"), "utf-8"));
335455
335492
  this.internal = Array.isArray(local) ? local.map((item) => this.normalizeInternalWorkspace(item, (changed) => {
335456
335493
  internalChanged = internalChanged || changed;
335457
335494
  })) : [];
335458
335495
  } catch {
335459
335496
  }
335460
335497
  try {
335461
- const ext = JSON.parse(fs11.readFileSync(path12.join(w, "External.json"), "utf-8"));
335498
+ const ext = JSON.parse(fs12.readFileSync(path13.join(w, "External.json"), "utf-8"));
335462
335499
  const normalized = Array.isArray(ext) ? ext.map((item) => this.normalizeExternalWorkspace(item, (changed) => {
335463
335500
  externalChanged = externalChanged || changed;
335464
335501
  })) : [];
@@ -335469,13 +335506,13 @@ var WorkspaceManager = class {
335469
335506
  });
335470
335507
  } catch {
335471
335508
  }
335472
- for (const entry of fs11.readdirSync(w, { withFileTypes: true })) {
335509
+ for (const entry of fs12.readdirSync(w, { withFileTypes: true })) {
335473
335510
  if (entry.isDirectory() && !["Local.json", "External.json", ".ssh"].includes(entry.name)) {
335474
335511
  if (!this.internal.find((wi) => wi.name === entry.name)) {
335475
335512
  this.internal.push({
335476
- id: this.stableWorkspaceId("local", path12.join(w, entry.name)),
335513
+ id: this.stableWorkspaceId("local", path13.join(w, entry.name)),
335477
335514
  name: entry.name,
335478
- path: path12.join(w, entry.name),
335515
+ path: path13.join(w, entry.name),
335479
335516
  isInternal: true,
335480
335517
  hostBinding: "",
335481
335518
  icon: entry.name.charAt(0).toUpperCase()
@@ -335488,9 +335525,9 @@ var WorkspaceManager = class {
335488
335525
  if (externalChanged) this.saveExternal();
335489
335526
  }
335490
335527
  normalizeInternalWorkspace(input, markChanged) {
335491
- const rawName = String(input?.name || path12.basename(String(input?.path || "")) || "").trim();
335528
+ const rawName = String(input?.name || path13.basename(String(input?.path || "")) || "").trim();
335492
335529
  const name50 = rawName || (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "").replace("T", "_").slice(0, 15);
335493
- const expectedPath = path12.join(this.rootPath, "Work", name50);
335530
+ const expectedPath = path13.join(this.rootPath, "Work", name50);
335494
335531
  const id = this.stableWorkspaceId("local", expectedPath);
335495
335532
  if (normalizeHostWorkspacePath(String(input?.path || "")) !== normalizeHostWorkspacePath(expectedPath) || input?.isInternal !== true || input?.id !== id) markChanged(true);
335496
335533
  return {
@@ -335511,11 +335548,11 @@ var WorkspaceManager = class {
335511
335548
  return {
335512
335549
  ...input,
335513
335550
  id,
335514
- name: String(input?.name || path12.basename(workspacePath) || id),
335551
+ name: String(input?.name || path13.basename(workspacePath) || id),
335515
335552
  path: workspacePath,
335516
335553
  isInternal: false,
335517
335554
  hostBinding: String(input?.hostBinding || ""),
335518
- icon: String(input?.icon || path12.basename(workspacePath).charAt(0).toUpperCase()),
335555
+ icon: String(input?.icon || path13.basename(workspacePath).charAt(0).toUpperCase()),
335519
335556
  kind
335520
335557
  };
335521
335558
  }
@@ -335536,11 +335573,11 @@ var WorkspaceManager = class {
335536
335573
  const resolved = normalizeHostWorkspacePath(target);
335537
335574
  let real = resolved;
335538
335575
  try {
335539
- real = fs11.existsSync(resolved) ? fs11.realpathSync.native(resolved) : resolved;
335576
+ real = fs12.existsSync(resolved) ? fs12.realpathSync.native(resolved) : resolved;
335540
335577
  } catch {
335541
335578
  real = resolved;
335542
335579
  }
335543
- const normalized = path12.normalize(real).replace(/[\\/]+$/, "");
335580
+ const normalized = path13.normalize(real).replace(/[\\/]+$/, "");
335544
335581
  return process.platform === "win32" ? normalized.toLowerCase() : normalized;
335545
335582
  }
335546
335583
  stableWorkspaceId(kind, workspacePath) {
@@ -335566,8 +335603,8 @@ var WorkspaceManager = class {
335566
335603
  isInsideRoot(target) {
335567
335604
  const root2 = this.canonicalWorkspacePath(this.rootPath);
335568
335605
  const candidate = this.canonicalWorkspacePath(target);
335569
- const rel = path12.relative(root2, candidate);
335570
- return rel === "" || !!rel && !rel.startsWith("..") && !path12.isAbsolute(rel);
335606
+ const rel = path13.relative(root2, candidate);
335607
+ return rel === "" || !!rel && !rel.startsWith("..") && !path13.isAbsolute(rel);
335571
335608
  }
335572
335609
  canonicalRemotePath(target) {
335573
335610
  let cleaned = String(target || "").trim().replace(/\\/g, "/").replace(/\/+$/g, "");
@@ -335596,13 +335633,13 @@ var WorkspaceManager = class {
335596
335633
  return deduped;
335597
335634
  }
335598
335635
  statePath() {
335599
- return path12.join(this.rootPath, "Work", "State.json");
335636
+ return path13.join(this.rootPath, "Work", "State.json");
335600
335637
  }
335601
335638
  readState() {
335602
335639
  const p = this.statePath();
335603
- if (!fs11.existsSync(p)) return {};
335640
+ if (!fs12.existsSync(p)) return {};
335604
335641
  try {
335605
- const raw = fs11.readFileSync(p, "utf-8").replace(/^\uFEFF/, "");
335642
+ const raw = fs12.readFileSync(p, "utf-8").replace(/^\uFEFF/, "");
335606
335643
  const parsed = JSON.parse(raw);
335607
335644
  if (parsed && typeof parsed === "object") return parsed;
335608
335645
  } catch {
@@ -335623,8 +335660,8 @@ var WorkspaceManager = class {
335623
335660
  updatedAt: (/* @__PURE__ */ new Date()).toISOString()
335624
335661
  };
335625
335662
  try {
335626
- fs11.mkdirSync(path12.dirname(p), { recursive: true });
335627
- fs11.writeFileSync(p, JSON.stringify(state, null, 2), "utf-8");
335663
+ fs12.mkdirSync(path13.dirname(p), { recursive: true });
335664
+ fs12.writeFileSync(p, JSON.stringify(state, null, 2), "utf-8");
335628
335665
  } catch {
335629
335666
  }
335630
335667
  }
@@ -335683,17 +335720,17 @@ var WorkspaceManager = class {
335683
335720
  }
335684
335721
  saveInternal() {
335685
335722
  if (this.detached) return;
335686
- const p = path12.join(this.rootPath, "Work", "Local.json");
335723
+ const p = path13.join(this.rootPath, "Work", "Local.json");
335687
335724
  this.internal = this.dedupeByPath(this.internal);
335688
335725
  this.sortWorkspaces();
335689
- fs11.writeFileSync(p, JSON.stringify(this.internal, null, 2), "utf-8");
335726
+ fs12.writeFileSync(p, JSON.stringify(this.internal, null, 2), "utf-8");
335690
335727
  }
335691
335728
  saveExternal() {
335692
335729
  if (this.detached) return;
335693
- const p = path12.join(this.rootPath, "Work", "External.json");
335730
+ const p = path13.join(this.rootPath, "Work", "External.json");
335694
335731
  this.external = this.dedupeByPath(this.external);
335695
335732
  this.sortWorkspaces();
335696
- fs11.writeFileSync(p, JSON.stringify(this.external, null, 2), "utf-8");
335733
+ fs12.writeFileSync(p, JSON.stringify(this.external, null, 2), "utf-8");
335697
335734
  }
335698
335735
  sleepSync(ms) {
335699
335736
  if (ms <= 0) return;
@@ -335701,48 +335738,48 @@ var WorkspaceManager = class {
335701
335738
  Atomics.wait(new Int32Array(buffer), 0, 0, ms);
335702
335739
  }
335703
335740
  isInternalWorkspacePath(target) {
335704
- const workRoot = path12.resolve(this.rootPath, "Work");
335705
- const resolved = path12.resolve(target);
335706
- const rel = path12.relative(workRoot, resolved);
335707
- return !!rel && !rel.startsWith("..") && !path12.isAbsolute(rel);
335741
+ const workRoot = path13.resolve(this.rootPath, "Work");
335742
+ const resolved = path13.resolve(target);
335743
+ const rel = path13.relative(workRoot, resolved);
335744
+ return !!rel && !rel.startsWith("..") && !path13.isAbsolute(rel);
335708
335745
  }
335709
335746
  clearReadOnlyRecursive(target) {
335710
- if (!fs11.existsSync(target)) return;
335711
- const stat = fs11.lstatSync(target);
335747
+ if (!fs12.existsSync(target)) return;
335748
+ const stat = fs12.lstatSync(target);
335712
335749
  try {
335713
- fs11.chmodSync(target, stat.mode | 448);
335750
+ fs12.chmodSync(target, stat.mode | 448);
335714
335751
  } catch {
335715
335752
  }
335716
335753
  if (!stat.isDirectory()) return;
335717
- for (const entry of fs11.readdirSync(target)) {
335718
- this.clearReadOnlyRecursive(path12.join(target, entry));
335754
+ for (const entry of fs12.readdirSync(target)) {
335755
+ this.clearReadOnlyRecursive(path13.join(target, entry));
335719
335756
  }
335720
335757
  }
335721
335758
  removeInternalDirectory(target) {
335722
- const resolved = path12.resolve(target);
335759
+ const resolved = path13.resolve(target);
335723
335760
  if (!this.isInternalWorkspacePath(resolved)) return false;
335724
- if (!fs11.existsSync(resolved)) return true;
335761
+ if (!fs12.existsSync(resolved)) return true;
335725
335762
  const delays = [0, 50, 100, 200, 400, 800, 1200];
335726
335763
  for (const delay of delays) {
335727
335764
  this.sleepSync(delay);
335728
335765
  try {
335729
- fs11.rmSync(resolved, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 });
335766
+ fs12.rmSync(resolved, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 });
335730
335767
  } catch {
335731
335768
  }
335732
- if (!fs11.existsSync(resolved)) return true;
335769
+ if (!fs12.existsSync(resolved)) return true;
335733
335770
  try {
335734
335771
  this.clearReadOnlyRecursive(resolved);
335735
- fs11.rmSync(resolved, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 });
335772
+ fs12.rmSync(resolved, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 });
335736
335773
  } catch {
335737
335774
  }
335738
- if (!fs11.existsSync(resolved)) return true;
335775
+ if (!fs12.existsSync(resolved)) return true;
335739
335776
  }
335740
335777
  return false;
335741
335778
  }
335742
335779
  createInternal(name50) {
335743
335780
  const n3 = name50 || (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "").replace("T", "_").slice(0, 15);
335744
- const d3 = path12.join(this.rootPath, "Work", n3);
335745
- fs11.mkdirSync(d3, { recursive: true });
335781
+ const d3 = path13.join(this.rootPath, "Work", n3);
335782
+ fs12.mkdirSync(d3, { recursive: true });
335746
335783
  const existing = this.findWorkspaceByPath(d3);
335747
335784
  if (existing) {
335748
335785
  this.current = existing;
@@ -335764,15 +335801,15 @@ var WorkspaceManager = class {
335764
335801
  return ws;
335765
335802
  }
335766
335803
  addExternal(p) {
335767
- const resolved = path12.resolve(p);
335768
- if (!fs11.existsSync(resolved) || this.isInsideRoot(resolved)) return null;
335804
+ const resolved = path13.resolve(p);
335805
+ if (!fs12.existsSync(resolved) || this.isInsideRoot(resolved)) return null;
335769
335806
  const existing = this.findWorkspaceByPath(resolved);
335770
335807
  if (existing) {
335771
335808
  this.current = existing;
335772
335809
  this.saveState();
335773
335810
  return existing;
335774
335811
  }
335775
- const name50 = path12.basename(resolved);
335812
+ const name50 = path13.basename(resolved);
335776
335813
  const ws = {
335777
335814
  id: this.stableWorkspaceId("local", resolved),
335778
335815
  name: name50,
@@ -335790,10 +335827,10 @@ var WorkspaceManager = class {
335790
335827
  addSshExternal(input) {
335791
335828
  if (!input.sshConnectionId || !input.remotePath || !input.remotePcHash) return null;
335792
335829
  const remotePath = this.canonicalRemotePath(input.remotePath);
335793
- const baseName = (input.name || path12.basename(remotePath.replace(/[\\/]+$/, "")) || input.sshConnectionId || "ssh-workspace").trim();
335830
+ const baseName = (input.name || path13.basename(remotePath.replace(/[\\/]+$/, "")) || input.sshConnectionId || "ssh-workspace").trim();
335794
335831
  const safeName = baseName.replace(/[<>:"/\\|?*\x00-\x1F]/g, "-").replace(/\s+/g, " ").trim() || "ssh-workspace";
335795
- const shadowRoot = input.localPath ? path12.resolve(input.localPath) : path12.join(this.rootPath, "Work", ".ssh", `${input.sshConnectionId}-${crypto7.createHash("sha256").update(remotePath).digest("hex").slice(0, 16)}`);
335796
- fs11.mkdirSync(shadowRoot, { recursive: true });
335832
+ const shadowRoot = input.localPath ? path13.resolve(input.localPath) : path13.join(this.rootPath, "Work", ".ssh", `${input.sshConnectionId}-${crypto7.createHash("sha256").update(remotePath).digest("hex").slice(0, 16)}`);
335833
+ fs12.mkdirSync(shadowRoot, { recursive: true });
335797
335834
  const existing = this.findSshWorkspaceByRemotePath(input.sshConnectionId, remotePath);
335798
335835
  const ws = {
335799
335836
  ...existing || {},
@@ -335875,7 +335912,7 @@ var WorkspaceManager = class {
335875
335912
  currentAgentPrompt() {
335876
335913
  if (!this.current) return null;
335877
335914
  try {
335878
- return fs11.readFileSync(path12.join(this.current.path, "agent.md"), "utf-8");
335915
+ return fs12.readFileSync(path13.join(this.current.path, "agent.md"), "utf-8");
335879
335916
  } catch {
335880
335917
  return null;
335881
335918
  }
@@ -335884,8 +335921,8 @@ var WorkspaceManager = class {
335884
335921
  const perm = this.config.getStr("workspace", "access_permission");
335885
335922
  if (perm === "full_access") return true;
335886
335923
  if (!this.current) return perm !== "no_outside_access";
335887
- const rel = path12.relative(path12.resolve(this.current.path), path12.resolve(target));
335888
- const inside2 = rel === "" || !!rel && !rel.startsWith("..") && !path12.isAbsolute(rel);
335924
+ const rel = path13.relative(path13.resolve(this.current.path), path13.resolve(target));
335925
+ const inside2 = rel === "" || !!rel && !rel.startsWith("..") && !path13.isAbsolute(rel);
335889
335926
  if (inside2) return true;
335890
335927
  return perm !== "no_outside_access";
335891
335928
  }
@@ -335968,6 +336005,7 @@ var PLAN_COMPUTER_USE_ACTIONS = ["observe", "app_list", "app_observe"];
335968
336005
  var PLAN_BROWSER_USE_ACTIONS = ["observe", "navigate", "wait", "extract"];
335969
336006
  var PLAN_COMPUTER_USE_ACTION_SET = new Set(PLAN_COMPUTER_USE_ACTIONS);
335970
336007
  var PLAN_BROWSER_USE_ACTION_SET = new Set(PLAN_BROWSER_USE_ACTIONS);
336008
+ var CHAT_WEB_TOOLS = /* @__PURE__ */ new Set(["web_search", "web_fetch"]);
335971
336009
  var CONCURRENCY_SAFE_TOOLS = /* @__PURE__ */ new Set([
335972
336010
  "pwd",
335973
336011
  "read",
@@ -336001,6 +336039,13 @@ function evaluateToolPolicy(request) {
336001
336039
  const availability = toolAvailability(name50);
336002
336040
  const base2 = { availability, settingsVisible: availability === "configurable" };
336003
336041
  if (!name50) return { ...base2, allowed: false, reason: "[permission] Tool name is required." };
336042
+ if (request.mode === "chat" && !CHAT_WEB_TOOLS.has(name50)) {
336043
+ return {
336044
+ ...base2,
336045
+ allowed: false,
336046
+ 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}`
336047
+ };
336048
+ }
336004
336049
  if (request.mode === "plan") {
336005
336050
  if (name50 === "computer_use") {
336006
336051
  const action = String(request.args?.action || "").trim();
@@ -336042,6 +336087,13 @@ function planModePolicyPrompt() {
336042
336087
  "Runtime policy rejects stale or hidden mutating tool calls even if a prompt asks for them."
336043
336088
  ].join(" ");
336044
336089
  }
336090
+ function chatModePolicyPrompt() {
336091
+ return [
336092
+ "Chat mode is a narrow web-evidence mode.",
336093
+ "Only web_search and web_fetch are available; every workspace, host, application, memory, task, browser-control, and write capability is denied at runtime.",
336094
+ "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."
336095
+ ].join(" ");
336096
+ }
336045
336097
  var DELETE_VERB_SOURCE = "(?:remove-item|rmdir|unlink|erase|del|rm|rd|ri)";
336046
336098
  var DELETE_VERB_BOUNDARY = new RegExp(`(?:^|[\\s;&|()\\n])${DELETE_VERB_SOURCE}(?:\\s|$)`, "i");
336047
336099
  function hasDeletionVerb(text) {
@@ -336323,7 +336375,7 @@ function rejectPendingUtilityHostTools(reason) {
336323
336375
  }
336324
336376
 
336325
336377
  // src/core/nativeBash.ts
336326
- var path13 = __toESM(require("path"));
336378
+ var path14 = __toESM(require("path"));
336327
336379
  var import_module = require("module");
336328
336380
  var MAX_OUTPUT_BYTES = 1024 * 1024;
336329
336381
  var DEFAULT_TIMEOUT_MS = 3e4;
@@ -336411,11 +336463,11 @@ function normalizedTimeout(timeoutMs) {
336411
336463
  }
336412
336464
  function virtualCwd(workspaceRoot, requestedCwd) {
336413
336465
  if (!requestedCwd) return "/";
336414
- const root2 = path13.resolve(workspaceRoot);
336415
- const cwd = path13.resolve(requestedCwd);
336416
- const relative6 = path13.relative(root2, cwd);
336417
- if (relative6.startsWith("..") || path13.isAbsolute(relative6)) return "/";
336418
- return relative6 ? `/${relative6.split(path13.sep).join("/")}` : "/";
336466
+ const root2 = path14.resolve(workspaceRoot);
336467
+ const cwd = path14.resolve(requestedCwd);
336468
+ const relative6 = path14.relative(root2, cwd);
336469
+ if (relative6.startsWith("..") || path14.isAbsolute(relative6)) return "/";
336470
+ return relative6 ? `/${relative6.split(path14.sep).join("/")}` : "/";
336419
336471
  }
336420
336472
  function combineAbortSignals(signal, timeoutMs) {
336421
336473
  const controller = new AbortController();
@@ -336441,7 +336493,7 @@ function createBash(workspaceRoot, timeoutMs) {
336441
336493
  const justBash = loadJustBash();
336442
336494
  if (!justBash) throw new Error("Native Bash runtime unavailable");
336443
336495
  const fs26 = new justBash.ReadWriteFs({
336444
- root: path13.resolve(workspaceRoot),
336496
+ root: path14.resolve(workspaceRoot),
336445
336497
  maxFileReadSize: MAX_OUTPUT_BYTES * 8,
336446
336498
  allowSymlinks: false
336447
336499
  });
@@ -336530,12 +336582,12 @@ async function executeWorkspaceBash(script, workspaceRoot, options = {}) {
336530
336582
  }
336531
336583
 
336532
336584
  // src/core/toolArgumentValidator.ts
336533
- var fs12 = require("fs");
336534
- var path14 = require("path");
336585
+ var fs13 = require("fs");
336586
+ var path15 = require("path");
336535
336587
  var typeBoxCompilerPath = [
336536
- path14.join(__dirname, "..", "typebox-compile.bundle.cjs"),
336537
- path14.join(__dirname, "typebox-compile.bundle.cjs")
336538
- ].find((candidate) => fs12.existsSync(candidate));
336588
+ path15.join(__dirname, "..", "typebox-compile.bundle.cjs"),
336589
+ path15.join(__dirname, "typebox-compile.bundle.cjs")
336590
+ ].find((candidate) => fs13.existsSync(candidate));
336539
336591
  if (!typeBoxCompilerPath) throw new Error("Bundled TypeBox compiler is missing from the Newmark runtime.");
336540
336592
  var { Compile } = require(typeBoxCompilerPath);
336541
336593
  function closeToolArgumentSchema(input) {
@@ -336625,8 +336677,8 @@ function formatValidationErrors(name50, errors) {
336625
336677
  }
336626
336678
 
336627
336679
  // src/core/localOcr.ts
336628
- var fs13 = __toESM(require("fs"));
336629
- var path15 = __toESM(require("path"));
336680
+ var fs14 = __toESM(require("fs"));
336681
+ var path16 = __toESM(require("path"));
336630
336682
  var AGENT_REPAIR_PROMPT = [
336631
336683
  "The local OCR output is approximate Chinese/English fallback evidence.",
336632
336684
  "Repair likely OCR substitutions, spacing, and line breaks using the visible UI/PDF context and the user task.",
@@ -336659,12 +336711,12 @@ var LocalOcrEngine = class {
336659
336711
  return await this.recognize(dataUrlBuffer(dataUrl), signal, profile);
336660
336712
  }
336661
336713
  async recognizeFile(filePath, signal) {
336662
- const absolute = path15.resolve(filePath);
336663
- const extension = path15.extname(absolute).toLowerCase();
336714
+ const absolute = path16.resolve(filePath);
336715
+ const extension = path16.extname(absolute).toLowerCase();
336664
336716
  if (![".png", ".jpg", ".jpeg", ".bmp"].includes(extension)) {
336665
336717
  throw new Error("Local OCR only accepts PNG, JPEG, or BMP images.");
336666
336718
  }
336667
- const stat = fs13.statSync(absolute);
336719
+ const stat = fs14.statSync(absolute);
336668
336720
  if (!stat.isFile() || stat.size <= 0 || stat.size > 12 * 1024 * 1024) {
336669
336721
  throw new Error("Local OCR image must be a regular file no larger than 12 MB.");
336670
336722
  }
@@ -336718,7 +336770,7 @@ var LocalOcrEngine = class {
336718
336770
  const tesseract = require_src();
336719
336771
  const worker = await tesseract.createWorker("chi_sim+eng", tesseract.OEM.LSTM_ONLY, {
336720
336772
  langPath: tessdataPath,
336721
- cachePath: path15.join(this.rootPath, "cache", "ocr-runtime"),
336773
+ cachePath: path16.join(this.rootPath, "cache", "ocr-runtime"),
336722
336774
  cacheMethod: "none",
336723
336775
  gzip: true,
336724
336776
  logger: () => void 0
@@ -336726,14 +336778,14 @@ var LocalOcrEngine = class {
336726
336778
  return worker;
336727
336779
  }
336728
336780
  prepareLanguageCache() {
336729
- const target = path15.join(this.rootPath, "cache", "ocr-tessdata");
336730
- fs13.mkdirSync(target, { recursive: true });
336781
+ const target = path16.join(this.rootPath, "cache", "ocr-tessdata");
336782
+ fs14.mkdirSync(target, { recursive: true });
336731
336783
  for (const language of ["eng", "chi_sim"]) {
336732
- const destination = path15.join(target, `${language}.traineddata.gz`);
336733
- if (fs13.existsSync(destination) && fs13.statSync(destination).size > 0) continue;
336734
- const packageRoot = path15.dirname(require.resolve(`@tesseract.js-data/${language}/package.json`));
336735
- const source = path15.join(packageRoot, "4.0.0_best_int", `${language}.traineddata.gz`);
336736
- fs13.copyFileSync(source, destination);
336784
+ const destination = path16.join(target, `${language}.traineddata.gz`);
336785
+ if (fs14.existsSync(destination) && fs14.statSync(destination).size > 0) continue;
336786
+ const packageRoot = path16.dirname(require.resolve(`@tesseract.js-data/${language}/package.json`));
336787
+ const source = path16.join(packageRoot, "4.0.0_best_int", `${language}.traineddata.gz`);
336788
+ fs14.copyFileSync(source, destination);
336737
336789
  }
336738
336790
  return target;
336739
336791
  }
@@ -336872,8 +336924,8 @@ function normalizeCrossEnvPath(value, wsPath) {
336872
336924
  const posix3 = windowsDrivePathToPosix(raw);
336873
336925
  if (posix3) return posix3;
336874
336926
  }
336875
- if (path16.isAbsolute(raw)) return raw;
336876
- return path16.join(wsPath, raw);
336927
+ if (path17.isAbsolute(raw)) return raw;
336928
+ return path17.join(wsPath, raw);
336877
336929
  }
336878
336930
  function translateWindowsPathsForWslBash(script) {
336879
336931
  if (!process.env.NEWMARK_WSL_DISTRO) return script;
@@ -336887,7 +336939,7 @@ function translateWindowsPathsForWslBash(script) {
336887
336939
  function computerUseOwner(context, wsPath) {
336888
336940
  const conversationId = String(context.conversationId || "").trim();
336889
336941
  if (conversationId) return `conversation:${conversationId}`;
336890
- const resolved = path16.resolve(context.workspacePath || wsPath || process.cwd());
336942
+ const resolved = path17.resolve(context.workspacePath || wsPath || process.cwd());
336891
336943
  const workspaceHash = crypto8.createHash("sha256").update(resolved).digest("hex").slice(0, 12);
336892
336944
  return `direct:${workspaceHash}`;
336893
336945
  }
@@ -336969,7 +337021,7 @@ function computerUseSessionScope(context, wsPath, owner) {
336969
337021
  return {
336970
337022
  runtimeKey: browserUseScope(context, wsPath).runtimeKey,
336971
337023
  ownerLabel: owner,
336972
- workspacePath: path16.resolve(wsPath || process.cwd())
337024
+ workspacePath: path17.resolve(wsPath || process.cwd())
336973
337025
  };
336974
337026
  }
336975
337027
  function acquireComputerUseLock(action, owner, wsPath, context = {}, dryRun = false) {
@@ -337164,7 +337216,7 @@ var ToolExecutor = class {
337164
337216
  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" } }, []),
337165
337217
  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." } }, []),
337166
337218
  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." } }, []),
337167
- t3("linked_plan", "Read or update the current conversation linked Markdown plan. Update requires the current expected_revision.", { action: { type: "string", enum: ["get", "update"] }, markdown: { type: "string" }, expected_revision: { type: "number" } }, ["action"]),
337219
+ 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"]),
337168
337220
  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." } }, []),
337169
337221
  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." } }, []),
337170
337222
  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.", {
@@ -337194,11 +337246,11 @@ var ToolExecutor = class {
337194
337246
  t3("skill_download", "Download a skill", { name: { type: "string" }, source: { type: "string" } }, ["name", "source"]),
337195
337247
  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 } }, []),
337196
337248
  t3("flow_list", "List available Newmark Flow workflows from the Flow folder so the agent can choose one.", {}, []),
337197
- t3("flow_save", "Design or update a Newmark Flow workflow. Components must be an array of dialog/logic objects compatible with *.Flow.json.", { name: { type: "string" }, components: { type: "array" } }, ["name", "components"]),
337249
+ 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"]),
337198
337250
  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"]),
337199
337251
  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" } }, []),
337200
337252
  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"]),
337201
- t3("memory_lab_update", "ADD or UPDATE a Memory Lab component. Existing memory should include expectedUpdatedAt from the latest read/query so stale writes fail closed. Prior revisions are archived and the Policy decision is logged.", { name: { type: "string" }, description: { type: "string" }, tags: { type: "array", items: { type: "string" } }, tagPaths: { type: "array", items: { type: "array", items: { type: "string" } } }, content: { type: "string" }, kind: { type: "string", enum: ["file", "folder"] }, expectedUpdatedAt: { type: "string" }, reason: { type: "string" }, source: { type: "string" } }, ["name", "tags", "content"]),
337253
+ 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" } }, []),
337202
337254
  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" } }, []),
337203
337255
  t3("memory_lab_reindex", "Rebuild and organize Memory Lab index links. Routed through Agent runtime when invoked by the model.", {}, []),
337204
337256
  t3("automation_list", "List persisted Newmark automations so the agent can inspect scheduled work.", {}, []),
@@ -337520,13 +337572,13 @@ var ToolExecutor = class {
337520
337572
  }
337521
337573
  case "pdf_read": {
337522
337574
  const pdfPath = resolve16(g2("path"));
337523
- if (path16.extname(pdfPath).toLowerCase() !== ".pdf") return "[pdf_read error] path must end in .pdf.";
337524
- const stat = fs14.statSync(pdfPath);
337575
+ if (path17.extname(pdfPath).toLowerCase() !== ".pdf") return "[pdf_read error] path must end in .pdf.";
337576
+ const stat = fs15.statSync(pdfPath);
337525
337577
  if (!stat.isFile() || stat.size <= 0 || stat.size > 250 * 1024 * 1024) {
337526
337578
  return "[pdf_read error] PDF must be a regular file no larger than 250 MB.";
337527
337579
  }
337528
337580
  const maxChars = Math.max(500, Math.min(1e5, Number(args.max_chars || 5e4)));
337529
- const textLayer = extractPdfTextLayer(fs14.readFileSync(pdfPath)).slice(0, maxChars);
337581
+ const textLayer = extractPdfTextLayer(fs15.readFileSync(pdfPath)).slice(0, maxChars);
337530
337582
  const readableCount = (textLayer.match(/[A-Za-z0-9\u3400-\u9fff]/g) || []).length;
337531
337583
  if (readableCount >= 20) {
337532
337584
  return JSON.stringify({
@@ -337745,7 +337797,7 @@ var ToolExecutor = class {
337745
337797
  case "flow_list":
337746
337798
  return this.flowList();
337747
337799
  case "flow_save":
337748
- return this.flowSave(g2("name"), args.components);
337800
+ return this.flowSave(g2("name"), args);
337749
337801
  case "flow_run":
337750
337802
  return `[flow_run] Routed to Agent runtime: ${g2("name")}`;
337751
337803
  case "memory_lab_read":
@@ -337802,8 +337854,8 @@ var ToolExecutor = class {
337802
337854
  }
337803
337855
  }
337804
337856
  isInside(parent, child) {
337805
- const rel = path16.relative(path16.resolve(parent), path16.resolve(child));
337806
- return rel === "" || !!rel && !rel.startsWith("..") && !path16.isAbsolute(rel);
337857
+ const rel = path17.relative(path17.resolve(parent), path17.resolve(child));
337858
+ return rel === "" || !!rel && !rel.startsWith("..") && !path17.isAbsolute(rel);
337807
337859
  }
337808
337860
  hostSupportsTool(name50) {
337809
337861
  if (name50.startsWith("browser_") && !this.hostProfile.electronBrowser) return false;
@@ -337915,7 +337967,7 @@ var ToolExecutor = class {
337915
337967
  if (!token || /^https?:\/\//i.test(token) || token.startsWith("-")) continue;
337916
337968
  if (!this.looksLikePath(token)) continue;
337917
337969
  const withoutWildcard = token.replace(/[\\/][*?][^\\/]*$/g, "");
337918
- refs.push(path16.resolve(normalizeCrossEnvPath(withoutWildcard, wsPath)));
337970
+ refs.push(path17.resolve(normalizeCrossEnvPath(withoutWildcard, wsPath)));
337919
337971
  }
337920
337972
  return Array.from(new Set(refs));
337921
337973
  }
@@ -337966,7 +338018,7 @@ var ToolExecutor = class {
337966
338018
  }
337967
338019
  fread(p) {
337968
338020
  try {
337969
- const c3 = fs14.readFileSync(p, "utf-8");
338021
+ const c3 = fs15.readFileSync(p, "utf-8");
337970
338022
  return c3.length > 3e4 ? c3.slice(0, 3e4) + "...\n[truncated]" : c3;
337971
338023
  } catch (e3) {
337972
338024
  return `[read] ${e3}`;
@@ -337974,8 +338026,8 @@ var ToolExecutor = class {
337974
338026
  }
337975
338027
  fwrite(p, content) {
337976
338028
  try {
337977
- fs14.mkdirSync(path16.dirname(p), { recursive: true });
337978
- fs14.writeFileSync(p, content, "utf-8");
338029
+ fs15.mkdirSync(path17.dirname(p), { recursive: true });
338030
+ fs15.writeFileSync(p, content, "utf-8");
337979
338031
  return `[write] OK: ${p}`;
337980
338032
  } catch (e3) {
337981
338033
  return `[write] ${e3}`;
@@ -337983,10 +338035,10 @@ var ToolExecutor = class {
337983
338035
  }
337984
338036
  fedit(p, oldStr, newStr) {
337985
338037
  try {
337986
- const c3 = fs14.readFileSync(p, "utf-8");
338038
+ const c3 = fs15.readFileSync(p, "utf-8");
337987
338039
  if (!c3.includes(oldStr)) return `[edit] String not found in ${p}.`;
337988
338040
  const updated = c3.replace(oldStr, newStr);
337989
- fs14.writeFileSync(p, updated, "utf-8");
338041
+ fs15.writeFileSync(p, updated, "utf-8");
337990
338042
  return `[edit] OK: ${p}`;
337991
338043
  } catch (e3) {
337992
338044
  return `[edit] ${e3}`;
@@ -337995,12 +338047,12 @@ var ToolExecutor = class {
337995
338047
  fdelete(p) {
337996
338048
  try {
337997
338049
  if (/[*?]/.test(p)) return "[delete_file] Refused: wildcard paths are not allowed. Delete one file per call.";
337998
- const resolved = path16.resolve(p);
337999
- const stat = fs14.lstatSync(resolved);
338050
+ const resolved = path17.resolve(p);
338051
+ const stat = fs15.lstatSync(resolved);
338000
338052
  if (stat.isDirectory()) {
338001
338053
  return "[delete_file] Refused: deleting a directory is not allowed. Delete files one by one under Agent supervision.";
338002
338054
  }
338003
- fs14.unlinkSync(resolved);
338055
+ fs15.unlinkSync(resolved);
338004
338056
  return `[delete_file] OK: ${resolved}`;
338005
338057
  } catch (e3) {
338006
338058
  return `[delete_file] ${e3 instanceof Error ? e3.message : String(e3)}`;
@@ -338024,11 +338076,11 @@ var ToolExecutor = class {
338024
338076
  const results = [];
338025
338077
  const walk4 = (d3, depth) => {
338026
338078
  if (depth > 5 || results.length >= 80) return;
338027
- for (const entry of fs14.readdirSync(d3, { withFileTypes: true })) {
338028
- const full = path16.join(d3, entry.name);
338079
+ for (const entry of fs15.readdirSync(d3, { withFileTypes: true })) {
338080
+ const full = path17.join(d3, entry.name);
338029
338081
  if (entry.isFile()) {
338030
338082
  try {
338031
- const content = fs14.readFileSync(full, "utf-8");
338083
+ const content = fs15.readFileSync(full, "utf-8");
338032
338084
  for (const [i4, line] of content.split("\n").entries()) {
338033
338085
  if (re.test(line)) {
338034
338086
  results.push(`${entry.name}:${i4 + 1}:${line.trim()}`);
@@ -338244,29 +338296,53 @@ ${String(result.data)}`);
338244
338296
  try {
338245
338297
  const resp = await this.proxyFetch(src, { signal });
338246
338298
  const content = await resp.text();
338247
- const dir = path16.join(this.root, "skills", name50);
338248
- fs14.mkdirSync(dir, { recursive: true });
338249
- fs14.writeFileSync(path16.join(dir, "SKILL.md"), content, "utf-8");
338299
+ const dir = path17.join(this.root, "skills", name50);
338300
+ fs15.mkdirSync(dir, { recursive: true });
338301
+ fs15.writeFileSync(path17.join(dir, "SKILL.md"), content, "utf-8");
338250
338302
  return `[skill] Downloaded '${name50}'`;
338251
338303
  } catch (e3) {
338252
338304
  return `[skill] ${e3}`;
338253
338305
  }
338254
338306
  }
338255
338307
  flowList() {
338256
- const dir = path16.join(this.root, "Flow");
338308
+ const dir = path17.join(this.root, "Flow");
338257
338309
  try {
338258
- const files = fs14.readdirSync(dir).filter((f3) => f3.endsWith(".Flow.json")).sort();
338310
+ const files = fs15.readdirSync(dir).filter((f3) => f3.endsWith(".Flow.json")).sort();
338259
338311
  if (!files.length) return "[flow_list] No workflows found.";
338260
338312
  return files.map((f3) => f3.replace(/\.Flow\.json$/, "")).join("\n");
338261
338313
  } catch (e3) {
338262
338314
  return `[flow_list] ${e3}`;
338263
338315
  }
338264
338316
  }
338265
- flowSave(name50, componentsRaw) {
338317
+ flowSave(name50, input) {
338266
338318
  const cleanName = (name50 || "").replace(/[<>:"/\\|?*]/g, "-").trim();
338267
338319
  if (!cleanName) return "[flow_save] Workflow name is required.";
338268
- if (!Array.isArray(componentsRaw)) return "[flow_save] components must be an array.";
338269
- const components = componentsRaw.map((raw, idx) => {
338320
+ const dir = path17.join(this.root, "Flow");
338321
+ const target = path17.join(dir, `${cleanName}.Flow.json`);
338322
+ const action = String(input.action || (Array.isArray(input.components) ? "replace" : "upsert")).toLowerCase();
338323
+ let componentsRaw = input.components;
338324
+ if (action === "upsert") {
338325
+ if (!input.component || typeof input.component !== "object") return "[flow_save] component is required for action=upsert.";
338326
+ const existing = FlowEngine.load(dir, cleanName)?.components || [];
338327
+ const component = input.component;
338328
+ const requestedId = Number(component.id);
338329
+ if (!Number.isFinite(requestedId)) return "[flow_save] component.id is required for action=upsert.";
338330
+ componentsRaw = [...existing.filter((item) => item.id !== requestedId), component].sort((a3, b2) => Number(a3.id) - Number(b2.id));
338331
+ } else if (action === "delete") {
338332
+ if (input.confirm !== true) return "[flow_save] action=delete requires confirm=true.";
338333
+ const componentId = Number(input.component_id);
338334
+ if (!Number.isFinite(componentId)) return "[flow_save] component_id is required for action=delete.";
338335
+ const existing = FlowEngine.load(dir, cleanName);
338336
+ if (!existing) return `[flow_save] Workflow not found: ${cleanName}`;
338337
+ const remaining = existing.components.filter((item) => item.id !== componentId);
338338
+ if (remaining.length === existing.components.length) return `[flow_save] Component not found: ${componentId}`;
338339
+ componentsRaw = remaining;
338340
+ } else if (action !== "replace") {
338341
+ return `[flow_save] Unknown action: ${action}`;
338342
+ }
338343
+ if (!Array.isArray(componentsRaw)) return "[flow_save] components must be an array for action=replace.";
338344
+ const componentInputs = componentsRaw;
338345
+ const components = componentInputs.map((raw, idx) => {
338270
338346
  const c3 = raw;
338271
338347
  const type = c3.type === "logic" ? "logic" : "dialog";
338272
338348
  if (type === "logic") {
@@ -338287,10 +338363,9 @@ ${String(result.data)}`);
338287
338363
  };
338288
338364
  });
338289
338365
  const workflow = { name: cleanName, components };
338290
- const dir = path16.join(this.root, "Flow");
338291
- fs14.mkdirSync(dir, { recursive: true });
338292
- fs14.writeFileSync(path16.join(dir, `${cleanName}.Flow.json`), JSON.stringify(workflow, null, 2), "utf-8");
338293
- return `[flow_save] OK: ${cleanName}.Flow.json`;
338366
+ fs15.mkdirSync(dir, { recursive: true });
338367
+ fs15.writeFileSync(target, JSON.stringify(workflow, null, 2), "utf-8");
338368
+ return `[flow_save] OK (${action}): ${cleanName}.Flow.json`;
338294
338369
  }
338295
338370
  memoryLabRead(selector2) {
338296
338371
  const lab2 = new MemoryLabManager(this.root);
@@ -338350,10 +338425,10 @@ ${String(result.data)}`);
338350
338425
  return this.gh(args, ws, signal);
338351
338426
  }
338352
338427
  async fileAudit(target, ws, includeRemote, baseRef, signal) {
338353
- const resolvedTarget = path16.resolve(target || ws);
338354
- const exists = fs14.existsSync(resolvedTarget);
338355
- const stat = exists ? fs14.statSync(resolvedTarget) : null;
338356
- const repoRoot = await this.findGitRoot(exists && stat?.isDirectory() ? resolvedTarget : path16.dirname(resolvedTarget), ws, signal);
338428
+ const resolvedTarget = path17.resolve(target || ws);
338429
+ const exists = fs15.existsSync(resolvedTarget);
338430
+ const stat = exists ? fs15.statSync(resolvedTarget) : null;
338431
+ const repoRoot = await this.findGitRoot(exists && stat?.isDirectory() ? resolvedTarget : path17.dirname(resolvedTarget), ws, signal);
338357
338432
  const audit = {
338358
338433
  ok: true,
338359
338434
  target: resolvedTarget,
@@ -338380,11 +338455,11 @@ ${String(result.data)}`);
338380
338455
  };
338381
338456
  if (stat.isFile()) {
338382
338457
  const hash = crypto8.createHash("sha256");
338383
- hash.update(fs14.readFileSync(target));
338458
+ hash.update(fs15.readFileSync(target));
338384
338459
  base2.sha256 = hash.digest("hex").toUpperCase();
338385
338460
  }
338386
338461
  if (stat.isDirectory()) {
338387
- base2.entries = fs14.readdirSync(target).slice(0, 200).sort();
338462
+ base2.entries = fs15.readdirSync(target).slice(0, 200).sort();
338388
338463
  }
338389
338464
  return base2;
338390
338465
  }
@@ -338393,14 +338468,14 @@ ${String(result.data)}`);
338393
338468
  const out = await this.gitExecAt(candidate, ["rev-parse", "--show-toplevel"], signal);
338394
338469
  if (!out.startsWith("[git]") && !out.includes("not a git repository")) {
338395
338470
  const root2 = out.split(/\r?\n/)[0].trim();
338396
- if (root2 && fs14.existsSync(root2)) return path16.resolve(root2);
338471
+ if (root2 && fs15.existsSync(root2)) return path17.resolve(root2);
338397
338472
  }
338398
338473
  }
338399
338474
  return null;
338400
338475
  }
338401
338476
  async gitFileAudit(repoRoot, target, baseRef, signal) {
338402
- const rel = path16.relative(repoRoot, target).replace(/\\/g, "/");
338403
- const inside2 = rel === "" || !!rel && !rel.startsWith("..") && !path16.isAbsolute(rel);
338477
+ const rel = path17.relative(repoRoot, target).replace(/\\/g, "/");
338478
+ const inside2 = rel === "" || !!rel && !rel.startsWith("..") && !path17.isAbsolute(rel);
338404
338479
  if (!inside2) return { repository: repoRoot, tracked: false, note: "Path is outside the detected repository." };
338405
338480
  const branch = await this.gitExecAt(repoRoot, ["branch", "--show-current"], signal);
338406
338481
  const status = rel === "" ? await this.gitExecAt(repoRoot, ["status", "--short"], signal) : await this.gitExecAt(repoRoot, ["status", "--short", "--", rel], signal);
@@ -338458,7 +338533,7 @@ ${String(result.data)}`);
338458
338533
  }
338459
338534
  async githubFileAudit(repoRoot, target, remote, signal) {
338460
338535
  const repo = `${remote.owner}/${remote.name}`;
338461
- const rel = path16.relative(repoRoot, target).replace(/\\/g, "/");
338536
+ const rel = path17.relative(repoRoot, target).replace(/\\/g, "/");
338462
338537
  const branch = (await this.gitExecAt(repoRoot, ["branch", "--show-current"], signal)).trim();
338463
338538
  const encodedPath = rel && rel !== "." ? rel.split("/").map((part) => encodeURIComponent(part)).join("/") : "";
338464
338539
  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);
@@ -338482,8 +338557,8 @@ ${String(result.data)}`);
338482
338557
  };
338483
338558
  }
338484
338559
  async repoSecurityAudit(target, ws, baseRef, signal) {
338485
- const resolvedTarget = path16.resolve(target || ws);
338486
- const repoRoot = await this.findGitRoot(fs14.existsSync(resolvedTarget) && fs14.statSync(resolvedTarget).isDirectory() ? resolvedTarget : path16.dirname(resolvedTarget), ws, signal);
338560
+ const resolvedTarget = path17.resolve(target || ws);
338561
+ const repoRoot = await this.findGitRoot(fs15.existsSync(resolvedTarget) && fs15.statSync(resolvedTarget).isDirectory() ? resolvedTarget : path17.dirname(resolvedTarget), ws, signal);
338487
338562
  if (!repoRoot) {
338488
338563
  return JSON.stringify({
338489
338564
  ok: true,
@@ -338581,12 +338656,12 @@ ${String(result.data)}`);
338581
338656
  const findings = [];
338582
338657
  for (const rel of Array.from(files).sort()) {
338583
338658
  if (findings.length >= 40) break;
338584
- const full = path16.join(repoRoot, rel);
338585
- if (!fs14.existsSync(full) || !fs14.statSync(full).isFile()) continue;
338586
- if (fs14.statSync(full).size > 512 * 1024) continue;
338659
+ const full = path17.join(repoRoot, rel);
338660
+ if (!fs15.existsSync(full) || !fs15.statSync(full).isFile()) continue;
338661
+ if (fs15.statSync(full).size > 512 * 1024) continue;
338587
338662
  let text = "";
338588
338663
  try {
338589
- text = fs14.readFileSync(full, "utf-8");
338664
+ text = fs15.readFileSync(full, "utf-8");
338590
338665
  } catch {
338591
338666
  continue;
338592
338667
  }
@@ -338616,12 +338691,12 @@ ${String(result.data)}`);
338616
338691
  const findings = [];
338617
338692
  for (const rel of Array.from(files).sort()) {
338618
338693
  if (findings.length >= 40) break;
338619
- const full = path16.join(repoRoot, rel);
338620
- if (!fs14.existsSync(full) || !fs14.statSync(full).isFile()) continue;
338621
- if (fs14.statSync(full).size > 512 * 1024) continue;
338694
+ const full = path17.join(repoRoot, rel);
338695
+ if (!fs15.existsSync(full) || !fs15.statSync(full).isFile()) continue;
338696
+ if (fs15.statSync(full).size > 512 * 1024) continue;
338622
338697
  let text = "";
338623
338698
  try {
338624
- text = fs14.readFileSync(full, "utf-8");
338699
+ text = fs15.readFileSync(full, "utf-8");
338625
338700
  } catch {
338626
338701
  continue;
338627
338702
  }
@@ -338638,7 +338713,7 @@ ${String(result.data)}`);
338638
338713
  releaseExcludedPathFindings(repoRoot, ignoredFilesRaw) {
338639
338714
  const sensitive = /^(config\.json|agent\.md|PC_Hash\.config|Work\/|archive\/|skills\/|Memory Lab\/|Design\.md|release\/|_local\/|_ref\/|vendor\/)/i;
338640
338715
  const fromIgnored = String(ignoredFilesRaw || "").split(/\r?\n/).map((line) => line.trim().replace(/\\/g, "/")).filter((line) => line && sensitive.test(line));
338641
- const direct = ["config.json", "agent.md", "PC_Hash.config", "Work", "archive", "skills", "Memory Lab", "Design.md", "release", "_local", "_ref", "vendor"].filter((rel) => fs14.existsSync(path16.join(repoRoot, rel))).map((rel) => rel.replace(/\\/g, "/"));
338716
+ 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, "/"));
338642
338717
  return Array.from(/* @__PURE__ */ new Set([...fromIgnored, ...direct])).slice(0, 80);
338643
338718
  }
338644
338719
  async ghJson(args, ws, signal) {
@@ -339442,8 +339517,8 @@ function sharedSubagentManager(key3, options) {
339442
339517
  }
339443
339518
 
339444
339519
  // src/core/skills.ts
339445
- var fs15 = __toESM(require("fs"));
339446
- var path17 = __toESM(require("path"));
339520
+ var fs16 = __toESM(require("fs"));
339521
+ var path18 = __toESM(require("path"));
339447
339522
  var os4 = __toESM(require("os"));
339448
339523
  var import_crypto9 = require("crypto");
339449
339524
  var SkillsManager = class {
@@ -339452,13 +339527,13 @@ var SkillsManager = class {
339452
339527
  marketSourcesPath;
339453
339528
  metadataCache = /* @__PURE__ */ new Map();
339454
339529
  constructor(root2) {
339455
- this.skillsDir = path17.join(root2, "skills");
339456
- this.metaPath = path17.join(this.skillsDir, ".skills.json");
339457
- this.marketSourcesPath = path17.join(this.skillsDir, ".market-sources.json");
339458
- fs15.mkdirSync(this.skillsDir, { recursive: true });
339530
+ this.skillsDir = path18.join(root2, "skills");
339531
+ this.metaPath = path18.join(this.skillsDir, ".skills.json");
339532
+ this.marketSourcesPath = path18.join(this.skillsDir, ".market-sources.json");
339533
+ fs16.mkdirSync(this.skillsDir, { recursive: true });
339459
339534
  }
339460
339535
  list() {
339461
- return fs15.readdirSync(this.skillsDir, { withFileTypes: true }).filter((e3) => e3.isDirectory() && !e3.name.startsWith(".")).map((e3) => e3.name);
339536
+ return fs16.readdirSync(this.skillsDir, { withFileTypes: true }).filter((e3) => e3.isDirectory() && !e3.name.startsWith(".")).map((e3) => e3.name);
339462
339537
  }
339463
339538
  listDetailed() {
339464
339539
  return this.list().map((name50) => this.infoFor(name50, this.getPath(name50), "project", true));
@@ -339479,48 +339554,48 @@ var SkillsManager = class {
339479
339554
  }
339480
339555
  load(name50) {
339481
339556
  const reference = String(name50 || "").trim().toLowerCase();
339482
- const skill = this.active().find((item) => item.name.toLowerCase() === reference || path17.basename(item.path).toLowerCase() === reference);
339557
+ const skill = this.active().find((item) => item.name.toLowerCase() === reference || path18.basename(item.path).toLowerCase() === reference);
339483
339558
  if (!skill) return null;
339484
- const skillPath = path17.join(skill.path, "SKILL.md");
339485
- const content = fs15.readFileSync(skillPath, "utf-8");
339559
+ const skillPath = path18.join(skill.path, "SKILL.md");
339560
+ const content = fs16.readFileSync(skillPath, "utf-8");
339486
339561
  const files = this.sampleSkillFiles(skill.path, 10);
339487
339562
  return { skill, content, files };
339488
339563
  }
339489
339564
  has(name50) {
339490
- return fs15.existsSync(path17.join(this.skillsDir, name50, "SKILL.md"));
339565
+ return fs16.existsSync(path18.join(this.skillsDir, name50, "SKILL.md"));
339491
339566
  }
339492
339567
  getPath(name50) {
339493
- return path17.join(this.skillsDir, name50);
339568
+ return path18.join(this.skillsDir, name50);
339494
339569
  }
339495
339570
  async download(name50, url) {
339496
- const dir = path17.join(this.skillsDir, name50);
339497
- fs15.mkdirSync(dir, { recursive: true });
339571
+ const dir = path18.join(this.skillsDir, name50);
339572
+ fs16.mkdirSync(dir, { recursive: true });
339498
339573
  if (!url.startsWith("http")) return `[skill] Not a URL: ${url}`;
339499
339574
  try {
339500
339575
  const resp = await fetch(url);
339501
339576
  const content = await resp.text();
339502
- fs15.writeFileSync(path17.join(dir, "SKILL.md"), content, "utf-8");
339577
+ fs16.writeFileSync(path18.join(dir, "SKILL.md"), content, "utf-8");
339503
339578
  return `[skill] Downloaded '${name50}'`;
339504
339579
  } catch (e3) {
339505
339580
  return `[skill] ${e3}`;
339506
339581
  }
339507
339582
  }
339508
339583
  installFromLocal(sourceDir, targetName) {
339509
- const skillPath = path17.join(sourceDir, "SKILL.md");
339510
- if (!fs15.existsSync(skillPath)) return false;
339584
+ const skillPath = path18.join(sourceDir, "SKILL.md");
339585
+ if (!fs16.existsSync(skillPath)) return false;
339511
339586
  const info = this.parseSkillInfo(sourceDir);
339512
- const cleanName = this.cleanName(targetName || info.name || path17.basename(sourceDir));
339587
+ const cleanName = this.cleanName(targetName || info.name || path18.basename(sourceDir));
339513
339588
  if (!cleanName) return false;
339514
- const dest = path17.join(this.skillsDir, cleanName);
339515
- fs15.rmSync(dest, { recursive: true, force: true });
339516
- fs15.cpSync(sourceDir, dest, { recursive: true });
339589
+ const dest = path18.join(this.skillsDir, cleanName);
339590
+ fs16.rmSync(dest, { recursive: true, force: true });
339591
+ fs16.cpSync(sourceDir, dest, { recursive: true });
339517
339592
  this.setEnabled(cleanName, true);
339518
339593
  return true;
339519
339594
  }
339520
339595
  remove(name50) {
339521
- const dir = path17.join(this.skillsDir, name50);
339522
- if (fs15.existsSync(dir)) {
339523
- fs15.rmSync(dir, { recursive: true, force: true });
339596
+ const dir = path18.join(this.skillsDir, name50);
339597
+ if (fs16.existsSync(dir)) {
339598
+ fs16.rmSync(dir, { recursive: true, force: true });
339524
339599
  const meta = this.loadMeta();
339525
339600
  meta.disabled = meta.disabled.filter((n3) => n3 !== name50);
339526
339601
  this.saveMeta(meta);
@@ -339569,7 +339644,7 @@ var SkillsManager = class {
339569
339644
  type,
339570
339645
  enabled: input.enabled !== false,
339571
339646
  url: url || void 0,
339572
- path: sourcePath ? path17.resolve(sourcePath) : void 0,
339647
+ path: sourcePath ? path18.resolve(sourcePath) : void 0,
339573
339648
  addedAt: existing?.addedAt || now2,
339574
339649
  updatedAt: now2
339575
339650
  };
@@ -339607,17 +339682,17 @@ var SkillsManager = class {
339607
339682
  const items = [];
339608
339683
  for (const info of this.listDetailed()) items.push(info);
339609
339684
  const roots = [
339610
- { root: path17.join(this.skillsDir, "..", ".agents", "skills"), source: "codex" },
339611
- { root: path17.join(this.skillsDir, "..", ".claude", "skills"), source: "claude" },
339612
- { root: path17.join(os4.homedir(), ".agents", "skills"), source: "user" },
339613
- { root: path17.join(os4.homedir(), ".codex", "skills"), source: "codex" },
339614
- { root: path17.join(os4.homedir(), ".claude", "skills"), source: "claude" },
339615
- { root: path17.join(os4.homedir(), ".config", "opencode", "skills"), source: "opencode" }
339685
+ { root: path18.join(this.skillsDir, "..", ".agents", "skills"), source: "codex" },
339686
+ { root: path18.join(this.skillsDir, "..", ".claude", "skills"), source: "claude" },
339687
+ { root: path18.join(os4.homedir(), ".agents", "skills"), source: "user" },
339688
+ { root: path18.join(os4.homedir(), ".codex", "skills"), source: "codex" },
339689
+ { root: path18.join(os4.homedir(), ".claude", "skills"), source: "claude" },
339690
+ { root: path18.join(os4.homedir(), ".config", "opencode", "skills"), source: "opencode" }
339616
339691
  ];
339617
339692
  for (const entry of roots) {
339618
339693
  for (const dir of this.findSkillDirs(entry.root, 4, 240)) {
339619
339694
  const parsed = this.parseSkillInfo(dir);
339620
- const name50 = this.cleanName(parsed.name || path17.basename(dir));
339695
+ const name50 = this.cleanName(parsed.name || path18.basename(dir));
339621
339696
  if (!name50 || items.some((i4) => i4.name === name50 && i4.source !== "remote")) continue;
339622
339697
  items.push({
339623
339698
  name: name50,
@@ -339634,9 +339709,9 @@ var SkillsManager = class {
339634
339709
  });
339635
339710
  }
339636
339711
  }
339637
- for (const dir of this.findPluginSkillDirs(path17.join(this.skillsDir, ".."), 5, 240)) {
339712
+ for (const dir of this.findPluginSkillDirs(path18.join(this.skillsDir, ".."), 5, 240)) {
339638
339713
  const parsed = this.parseSkillInfo(dir);
339639
- const name50 = this.cleanName(parsed.name || path17.basename(dir));
339714
+ const name50 = this.cleanName(parsed.name || path18.basename(dir));
339640
339715
  if (!name50 || items.some((i4) => i4.name === name50 && i4.source !== "remote")) continue;
339641
339716
  items.push({
339642
339717
  name: name50,
@@ -339693,8 +339768,8 @@ var SkillsManager = class {
339693
339768
  }
339694
339769
  loadMeta() {
339695
339770
  try {
339696
- if (fs15.existsSync(this.metaPath)) {
339697
- const raw = JSON.parse(fs15.readFileSync(this.metaPath, "utf-8"));
339771
+ if (fs16.existsSync(this.metaPath)) {
339772
+ const raw = JSON.parse(fs16.readFileSync(this.metaPath, "utf-8"));
339698
339773
  return { disabled: Array.isArray(raw.disabled) ? raw.disabled.map(String) : [] };
339699
339774
  }
339700
339775
  } catch {
@@ -339702,7 +339777,7 @@ var SkillsManager = class {
339702
339777
  return { disabled: [] };
339703
339778
  }
339704
339779
  saveMeta(meta) {
339705
- fs15.writeFileSync(this.metaPath, JSON.stringify({ disabled: meta.disabled }, null, 2), "utf-8");
339780
+ fs16.writeFileSync(this.metaPath, JSON.stringify({ disabled: meta.disabled }, null, 2), "utf-8");
339706
339781
  }
339707
339782
  builtinMarketSources() {
339708
339783
  return [{
@@ -339716,8 +339791,8 @@ var SkillsManager = class {
339716
339791
  }
339717
339792
  loadMarketSources() {
339718
339793
  try {
339719
- if (!fs15.existsSync(this.marketSourcesPath)) return [];
339720
- const raw = JSON.parse(fs15.readFileSync(this.marketSourcesPath, "utf-8"));
339794
+ if (!fs16.existsSync(this.marketSourcesPath)) return [];
339795
+ const raw = JSON.parse(fs16.readFileSync(this.marketSourcesPath, "utf-8"));
339721
339796
  if (!Array.isArray(raw.sources)) return [];
339722
339797
  return raw.sources.map((source) => this.normalizeMarketSource(source)).filter((source) => !!source);
339723
339798
  } catch {
@@ -339726,7 +339801,7 @@ var SkillsManager = class {
339726
339801
  }
339727
339802
  saveMarketSources(sources) {
339728
339803
  const normalized = sources.filter((s3) => !s3.builtin).map((s3) => this.normalizeMarketSource(s3)).filter((source) => !!source);
339729
- fs15.writeFileSync(this.marketSourcesPath, JSON.stringify({ sources: normalized }, null, 2), "utf-8");
339804
+ fs16.writeFileSync(this.marketSourcesPath, JSON.stringify({ sources: normalized }, null, 2), "utf-8");
339730
339805
  }
339731
339806
  normalizeMarketSource(raw) {
339732
339807
  if (!raw || typeof raw !== "object") return null;
@@ -339746,7 +339821,7 @@ var SkillsManager = class {
339746
339821
  type,
339747
339822
  enabled: source.enabled !== false,
339748
339823
  url: url || void 0,
339749
- path: sourcePath ? path17.resolve(sourcePath) : void 0,
339824
+ path: sourcePath ? path18.resolve(sourcePath) : void 0,
339750
339825
  builtin: source.builtin === true,
339751
339826
  addedAt: source.addedAt ? String(source.addedAt) : void 0,
339752
339827
  updatedAt: source.updatedAt ? String(source.updatedAt) : void 0
@@ -339797,11 +339872,11 @@ var SkillsManager = class {
339797
339872
  return rawItems.slice(0, 1e3).map((entry) => this.marketInfoFromCatalogEntry(entry, source, installed)).filter((item) => !!item);
339798
339873
  }
339799
339874
  readCatalogText(source) {
339800
- const catalogPath = source.path ? path17.resolve(source.path) : "";
339801
- if (catalogPath && fs15.existsSync(catalogPath)) return fs15.readFileSync(catalogPath, "utf-8");
339875
+ const catalogPath = source.path ? path18.resolve(source.path) : "";
339876
+ if (catalogPath && fs16.existsSync(catalogPath)) return fs16.readFileSync(catalogPath, "utf-8");
339802
339877
  const url = source.url || "";
339803
- if (url.startsWith("file://")) return fs15.readFileSync(new URL(url), "utf-8");
339804
- if (url && !url.startsWith("http")) return fs15.readFileSync(path17.resolve(url), "utf-8");
339878
+ if (url.startsWith("file://")) return fs16.readFileSync(new URL(url), "utf-8");
339879
+ if (url && !url.startsWith("http")) return fs16.readFileSync(path18.resolve(url), "utf-8");
339805
339880
  return "";
339806
339881
  }
339807
339882
  async discoverJsonMarketSourceAsync(source, installed) {
@@ -339861,7 +339936,7 @@ var SkillsManager = class {
339861
339936
  }
339862
339937
  marketInfoFromLocalDir(dir, source, installed) {
339863
339938
  const parsed = this.parseSkillInfo(dir);
339864
- const name50 = this.cleanName(parsed.name || path17.basename(dir));
339939
+ const name50 = this.cleanName(parsed.name || path18.basename(dir));
339865
339940
  if (!name50) return null;
339866
339941
  return {
339867
339942
  name: name50,
@@ -339886,9 +339961,9 @@ var SkillsManager = class {
339886
339961
  }
339887
339962
  parseSkillInfo(dir) {
339888
339963
  try {
339889
- const skillPath = path17.join(dir, "SKILL.md");
339890
- const stat = fs15.statSync(skillPath);
339891
- const content = fs15.readFileSync(skillPath, "utf-8");
339964
+ const skillPath = path18.join(dir, "SKILL.md");
339965
+ const stat = fs16.statSync(skillPath);
339966
+ const content = fs16.readFileSync(skillPath, "utf-8");
339892
339967
  const digest = (0, import_crypto9.createHash)("sha256").update(content).digest("hex");
339893
339968
  const fingerprint2 = `${stat.mtimeMs}:${stat.size}:${digest}`;
339894
339969
  const cached = this.metadataCache.get(skillPath);
@@ -339921,7 +339996,7 @@ var SkillsManager = class {
339921
339996
  };
339922
339997
  this.metadataCache.set(skillPath, {
339923
339998
  fingerprint: fingerprint2,
339924
- info: { ...parsed, path: dir, enabled: this.isEnabled(path17.basename(dir)), installed: true, source: "project" }
339999
+ info: { ...parsed, path: dir, enabled: this.isEnabled(path18.basename(dir)), installed: true, source: "project" }
339925
340000
  });
339926
340001
  return parsed;
339927
340002
  } catch {
@@ -339938,13 +340013,13 @@ var SkillsManager = class {
339938
340013
  if (files.length >= limit || depth > 2) return;
339939
340014
  let entries = [];
339940
340015
  try {
339941
- entries = fs15.readdirSync(dir, { withFileTypes: true });
340016
+ entries = fs16.readdirSync(dir, { withFileTypes: true });
339942
340017
  } catch {
339943
340018
  return;
339944
340019
  }
339945
340020
  for (const entry of entries) {
339946
340021
  if (files.length >= limit || entry.name === "SKILL.md" || entry.name.startsWith(".")) continue;
339947
- const target = path17.join(dir, entry.name);
340022
+ const target = path18.join(dir, entry.name);
339948
340023
  if (entry.isDirectory()) walk4(target, depth + 1);
339949
340024
  else if (entry.isFile()) files.push(target);
339950
340025
  }
@@ -339958,7 +340033,7 @@ var SkillsManager = class {
339958
340033
  if (results.length >= maxItems || depth > maxDepth) return;
339959
340034
  let entries;
339960
340035
  try {
339961
- entries = fs15.readdirSync(dir, { withFileTypes: true });
340036
+ entries = fs16.readdirSync(dir, { withFileTypes: true });
339962
340037
  } catch {
339963
340038
  return;
339964
340039
  }
@@ -339968,7 +340043,7 @@ var SkillsManager = class {
339968
340043
  }
339969
340044
  for (const e3 of entries) {
339970
340045
  if (!e3.isDirectory() || e3.name.startsWith(".git") || e3.name === "node_modules") continue;
339971
- walk4(path17.join(dir, e3.name), depth + 1);
340046
+ walk4(path18.join(dir, e3.name), depth + 1);
339972
340047
  }
339973
340048
  };
339974
340049
  walk4(root2, 0);
@@ -339980,19 +340055,19 @@ var SkillsManager = class {
339980
340055
  if (results.length >= maxItems || depth > maxDepth) return;
339981
340056
  let entries;
339982
340057
  try {
339983
- entries = fs15.readdirSync(dir, { withFileTypes: true });
340058
+ entries = fs16.readdirSync(dir, { withFileTypes: true });
339984
340059
  } catch {
339985
340060
  return;
339986
340061
  }
339987
340062
  const hasPluginManifest = entries.some((e3) => e3.isDirectory() && (e3.name === ".codex-plugin" || e3.name === ".claude-plugin"));
339988
340063
  if (hasPluginManifest) {
339989
340064
  for (const skillsDir of ["skills", "Skills"]) {
339990
- results.push(...this.findSkillDirs(path17.join(dir, skillsDir), 3, maxItems - results.length));
340065
+ results.push(...this.findSkillDirs(path18.join(dir, skillsDir), 3, maxItems - results.length));
339991
340066
  }
339992
340067
  }
339993
340068
  for (const e3 of entries) {
339994
340069
  if (!e3.isDirectory() || e3.name.startsWith(".git") || e3.name === "node_modules" || e3.name === "release" || e3.name.startsWith("release.locked-")) continue;
339995
- walk4(path17.join(dir, e3.name), depth + 1);
340070
+ walk4(path18.join(dir, e3.name), depth + 1);
339996
340071
  }
339997
340072
  };
339998
340073
  walk4(root2, 0);
@@ -340020,25 +340095,25 @@ var SkillsManager = class {
340020
340095
  if (!description) warnings.push("Missing required frontmatter field: description.");
340021
340096
  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.");
340022
340097
  if (description && description.length > 1e3) warnings.push("Description is longer than recommended for skill discovery.");
340023
- const folderName = path17.basename(dir);
340098
+ const folderName = path18.basename(dir);
340024
340099
  if (name50 && folderName && this.cleanName(name50) !== this.cleanName(folderName)) warnings.push("Skill name does not match containing folder name.");
340025
340100
  return warnings;
340026
340101
  }
340027
340102
  pluginIdForSkill(dir) {
340028
- let current = path17.resolve(dir);
340103
+ let current = path18.resolve(dir);
340029
340104
  for (let i4 = 0; i4 < 6; i4++) {
340030
- const codex = path17.join(current, ".codex-plugin", "plugin.json");
340031
- const claude = path17.join(current, ".claude-plugin", "plugin.json");
340105
+ const codex = path18.join(current, ".codex-plugin", "plugin.json");
340106
+ const claude = path18.join(current, ".claude-plugin", "plugin.json");
340032
340107
  for (const filePath of [codex, claude]) {
340033
340108
  try {
340034
- if (fs15.existsSync(filePath)) {
340035
- const raw = JSON.parse(fs15.readFileSync(filePath, "utf-8"));
340109
+ if (fs16.existsSync(filePath)) {
340110
+ const raw = JSON.parse(fs16.readFileSync(filePath, "utf-8"));
340036
340111
  if (raw?.name) return String(raw.name);
340037
340112
  }
340038
340113
  } catch {
340039
340114
  }
340040
340115
  }
340041
- const parent = path17.dirname(current);
340116
+ const parent = path18.dirname(current);
340042
340117
  if (parent === current) break;
340043
340118
  current = parent;
340044
340119
  }
@@ -345066,7 +345141,7 @@ var Agent4 = class _Agent {
345066
345141
  this.config.set("skills", "auto_download", "disabled");
345067
345142
  }
345068
345143
  const modeStr = this.config.getStr("agent", "default_mode");
345069
- this.mode = ["plan", "goal", "flow"].includes(modeStr) ? modeStr : "build";
345144
+ this.mode = ["plan", "chat", "goal", "flow"].includes(modeStr) ? modeStr : "build";
345070
345145
  const inputStr = this.config.getStr("general", "default_input");
345071
345146
  this.inputMode = inputStr === "next" ? "next" : "guide";
345072
345147
  const configuredModel = this.config.getStr("models", "default_model");
@@ -345234,6 +345309,7 @@ var Agent4 = class _Agent {
345234
345309
  return this.toolchainCore;
345235
345310
  }
345236
345311
  setMode(m2) {
345312
+ if (!["build", "plan", "chat", "goal", "flow"].includes(m2)) m2 = "build";
345237
345313
  if (m2 === "goal" && !this.goal) {
345238
345314
  this.goal = new GoalStateImpl("Set your objective");
345239
345315
  }
@@ -349601,7 +349677,20 @@ ${summary}`, segment, "local-summarize", true);
349601
349677
  if (action === "get") return JSON.stringify({ ok: true, linkedPlan: this.getLinkedPlan() }, null, 2);
349602
349678
  if (action !== "update") return JSON.stringify({ ok: false, error: `Unknown linked_plan action: ${action}` });
349603
349679
  const expectedRevision = Number(input.expected_revision ?? input.expectedRevision);
349604
- return JSON.stringify({ ok: true, linkedPlan: this.updateLinkedPlan(String(input.markdown || ""), expectedRevision) }, null, 2);
349680
+ const current = this.getLinkedPlan();
349681
+ let markdown = input.markdown === void 0 ? current.markdown : String(input.markdown);
349682
+ if (input.append !== void 0) markdown = `${current.markdown}${String(input.append)}`;
349683
+ if (input.old_text !== void 0 || input.oldText !== void 0) {
349684
+ const oldText = String(input.old_text ?? input.oldText ?? "");
349685
+ if (!oldText) throw new Error("linked_plan old_text must not be empty.");
349686
+ const matches = current.markdown.split(oldText).length - 1;
349687
+ if (!matches) throw new Error("linked_plan old_text was not found.");
349688
+ const replaceAll = input.replace_all === true || input.replaceAll === true;
349689
+ if (matches > 1 && !replaceAll) throw new Error(`linked_plan old_text matched ${matches} places; pass replace_all=true or a unique fragment.`);
349690
+ const newText = String(input.new_text ?? input.newText ?? "");
349691
+ markdown = replaceAll ? current.markdown.split(oldText).join(newText) : current.markdown.replace(oldText, newText);
349692
+ }
349693
+ return JSON.stringify({ ok: true, linkedPlan: this.updateLinkedPlan(markdown, expectedRevision) }, null, 2);
349605
349694
  } catch (error) {
349606
349695
  return JSON.stringify({ ok: false, error: error instanceof Error ? error.message : String(error) });
349607
349696
  }
@@ -351903,7 +351992,24 @@ ${this.formatAutomation(item)}` : `[automation_toggle] Not found: ${id}`;
351903
351992
  }));
351904
351993
  }
351905
351994
  case "memory_lab_update": {
351906
- const result = await this.updateMemoryLab({
351995
+ const selector2 = String(params.component || params.slug || "").trim();
351996
+ const prepared = selector2 ? this.memoryLab.preparePatch({
351997
+ component: selector2,
351998
+ name: params.name === void 0 ? void 0 : String(params.name),
351999
+ description: params.description === void 0 ? void 0 : String(params.description),
352000
+ tags: params.tags === void 0 ? void 0 : Array.isArray(params.tags) ? params.tags.map(String) : String(params.tags).split(/[,,\n]+/),
352001
+ tagPaths: params.tagPaths === void 0 ? void 0 : Array.isArray(params.tagPaths) ? params.tagPaths.filter(Array.isArray).map((pathValue) => pathValue.map(String)) : [],
352002
+ content: params.content === void 0 ? void 0 : String(params.content),
352003
+ contentAppend: params.contentAppend === void 0 && params.content_append === void 0 ? void 0 : String(params.contentAppend ?? params.content_append),
352004
+ oldText: params.oldText === void 0 && params.old_text === void 0 ? void 0 : String(params.oldText ?? params.old_text),
352005
+ newText: String(params.newText ?? params.new_text ?? ""),
352006
+ replaceAll: params.replaceAll === true || params.replace_all === true,
352007
+ kind: params.kind === void 0 ? void 0 : params.kind === "folder" ? "folder" : "file",
352008
+ expectedUpdatedAt: String(params.expectedUpdatedAt || params.expected_updated_at || ""),
352009
+ reason: String(params.reason || ""),
352010
+ source: String(params.source || "")
352011
+ }) : void 0;
352012
+ const result = await this.updateMemoryLab(prepared || {
351907
352013
  name: String(params.name || ""),
351908
352014
  description: String(params.description || ""),
351909
352015
  tags: Array.isArray(params.tags) ? params.tags.map(String) : String(params.tags || "").split(/[,,\n]+/),
@@ -352906,6 +353012,8 @@ When using file tools (read, write, edit, glob), use ABSOLUTE paths rooted at th
352906
353012
  parts.push(this.buildFeatureDisclosurePrompt());
352907
353013
  if (this.mode === "plan") parts.push(`[Plan Tool Policy]
352908
353014
  ${planModePolicyPrompt()}`);
353015
+ if (this.mode === "chat") parts.push(`[Chat Tool Policy]
353016
+ ${chatModePolicyPrompt()}`);
352909
353017
  const pm = this.config.getStr("workspace", "prompt_mode") || "both";
352910
353018
  const injectedPrompts = /* @__PURE__ */ new Set();
352911
353019
  if ((pm === "global_only" || pm === "both") && globalPrompt) {
@@ -353027,7 +353135,7 @@ ${custom}`);
353027
353135
  `- 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.`,
353028
353136
  `- Workspace permissions: access_permission=${permission}; file tools are checked before execution and blocked when they exceed the configured workspace boundary.`,
353029
353137
  `- 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.`,
353030
- `- Mode engine: current mode=${this.modeName()}; Build works autonomously, Plan is fully read-only with no file modifications, Goal continues until completion unless paused, Flow follows saved workflow components.`,
353138
+ `- 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.`,
353031
353139
  `- Input mode: ${input}; Guide injects immediately, Next queues user intent for the following build turn.`,
353032
353140
  `- Option feedback: ${this.buildQuestionPolicyPrompt(optionFeedback)}`,
353033
353141
  `- Model policy: current model=${this.model || "(unset)"}, intelligence=${this.intelligence}, auto-switch=${modelSwitch}.`,
@@ -353093,6 +353201,14 @@ ${custom}`);
353093
353201
  '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.',
353094
353202
  "A positive choice starts a new Build-mode input. A negative choice remains in Plan mode so the user can supply the missing details."
353095
353203
  ]).join("\n");
353204
+ case "chat":
353205
+ return withLanguage([
353206
+ "CHAT MODE.",
353207
+ "Use only web_search and web_fetch. You have no workspace, host, application, memory, task, browser-control, or write permissions.",
353208
+ "Perform an online search to gather evidence before answering. Fetch primary or authoritative pages when the search snippets are insufficient.",
353209
+ "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.",
353210
+ "Distinguish sourced facts from uncertainty and include useful source links in the final answer."
353211
+ ]).join("\n");
353096
353212
  case "goal": {
353097
353213
  const g2 = this.goal?.history() || "";
353098
353214
  const paused = this.goal?.paused ? "\n[GOAL PAUSED by user. Wait for resume.]" : "\n[Continue working until the goal is achieved.]";