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.
- package/dist/cli-commands.js +3 -3
- package/dist/cli.js +1 -1
- package/dist/conversation-utility-host.bundle.cjs +671 -555
- package/dist/core/agent.js +50 -4
- package/dist/core/memoryLab.d.ts +17 -0
- package/dist/core/memoryLab.js +43 -1
- package/dist/core/toolPolicy.d.ts +1 -0
- package/dist/core/toolPolicy.js +16 -0
- package/dist/core/types.d.ts +1 -1
- package/dist/tools/index.js +42 -10
- package/dist/ui/index.html +5 -2
- package/dist/wsl-agent-host.bundle.cjs +671 -555
- package/package.json +1 -1
|
@@ -4281,6 +4281,234 @@ var require_jpeg_js = __commonJS({
|
|
|
4281
4281
|
}
|
|
4282
4282
|
});
|
|
4283
4283
|
|
|
4284
|
+
// src/core/flow.ts
|
|
4285
|
+
var fs6, path7, FlowEngine;
|
|
4286
|
+
var init_flow = __esm({
|
|
4287
|
+
"src/core/flow.ts"() {
|
|
4288
|
+
"use strict";
|
|
4289
|
+
fs6 = __toESM(require("fs"));
|
|
4290
|
+
path7 = __toESM(require("path"));
|
|
4291
|
+
FlowEngine = class _FlowEngine {
|
|
4292
|
+
static load(dir, name50) {
|
|
4293
|
+
const p = path7.join(dir, `${name50}.Flow.json`);
|
|
4294
|
+
try {
|
|
4295
|
+
return JSON.parse(fs6.readFileSync(p, "utf-8").replace(/^\uFEFF/, ""));
|
|
4296
|
+
} catch {
|
|
4297
|
+
return null;
|
|
4298
|
+
}
|
|
4299
|
+
}
|
|
4300
|
+
static save(dir, workflow) {
|
|
4301
|
+
const p = path7.join(dir, `${workflow.name}.Flow.json`);
|
|
4302
|
+
fs6.writeFileSync(p, JSON.stringify(workflow, null, 2), "utf-8");
|
|
4303
|
+
}
|
|
4304
|
+
static delete(dir, name50) {
|
|
4305
|
+
const p = path7.join(dir, `${name50}.Flow.json`);
|
|
4306
|
+
if (fs6.existsSync(p)) fs6.unlinkSync(p);
|
|
4307
|
+
}
|
|
4308
|
+
static listAll(dir) {
|
|
4309
|
+
try {
|
|
4310
|
+
return fs6.readdirSync(dir).filter((f3) => f3.endsWith(".Flow.json")).map((f3) => f3.replace(".Flow.json", "")).sort();
|
|
4311
|
+
} catch {
|
|
4312
|
+
return [];
|
|
4313
|
+
}
|
|
4314
|
+
}
|
|
4315
|
+
static describeWorkflow(wf) {
|
|
4316
|
+
const comps = [...wf.components].sort((a3, b2) => a3.id - b2.id);
|
|
4317
|
+
if (comps.length === 0) return "";
|
|
4318
|
+
const parts = [];
|
|
4319
|
+
for (const c3 of comps) {
|
|
4320
|
+
if (c3.type === "dialog") {
|
|
4321
|
+
parts.push(c3.mode.charAt(0).toUpperCase() + c3.mode.slice(1));
|
|
4322
|
+
} else {
|
|
4323
|
+
const label = c3.prompt.replace(/\{#prompt#\}/g, "<i>").replace(/\n/g, " ").slice(0, 22);
|
|
4324
|
+
parts.push(`?${label}?`);
|
|
4325
|
+
}
|
|
4326
|
+
}
|
|
4327
|
+
return parts.join(" \u2192 ");
|
|
4328
|
+
}
|
|
4329
|
+
static validate(wf) {
|
|
4330
|
+
const errors = [];
|
|
4331
|
+
if (!wf.components || wf.components.length === 0) {
|
|
4332
|
+
errors.push({ message: "No components defined." });
|
|
4333
|
+
return errors;
|
|
4334
|
+
}
|
|
4335
|
+
const ids = /* @__PURE__ */ new Set();
|
|
4336
|
+
for (const c3 of wf.components) {
|
|
4337
|
+
if (typeof c3.id === "number") ids.add(c3.id);
|
|
4338
|
+
}
|
|
4339
|
+
const seenIds = /* @__PURE__ */ new Set();
|
|
4340
|
+
for (const c3 of wf.components) {
|
|
4341
|
+
if (seenIds.has(c3.id)) {
|
|
4342
|
+
errors.push({ componentId: c3.id, message: `Duplicate component ID: ${c3.id}` });
|
|
4343
|
+
}
|
|
4344
|
+
seenIds.add(c3.id);
|
|
4345
|
+
if (c3.type === "dialog") {
|
|
4346
|
+
const mode = c3.mode.toLowerCase();
|
|
4347
|
+
if (!["build", "plan", "goal"].includes(mode)) {
|
|
4348
|
+
errors.push({ componentId: c3.id, message: `Invalid dialog mode '${c3.mode}' (must be build/plan/goal)` });
|
|
4349
|
+
}
|
|
4350
|
+
} else if (c3.type === "logic") {
|
|
4351
|
+
if (!ids.has(c3.goto_true)) {
|
|
4352
|
+
errors.push({ componentId: c3.id, message: `goto_true=${c3.goto_true} not found` });
|
|
4353
|
+
}
|
|
4354
|
+
if (!ids.has(c3.goto_false)) {
|
|
4355
|
+
errors.push({ componentId: c3.id, message: `goto_false=${c3.goto_false} not found` });
|
|
4356
|
+
}
|
|
4357
|
+
} else {
|
|
4358
|
+
errors.push({ componentId: c3.id, message: `Unknown component type '${c3.type}'` });
|
|
4359
|
+
}
|
|
4360
|
+
}
|
|
4361
|
+
return errors;
|
|
4362
|
+
}
|
|
4363
|
+
static detectCycles(wf) {
|
|
4364
|
+
const comps = [...wf.components].sort((a3, b2) => a3.id - b2.id);
|
|
4365
|
+
if (comps.length === 0) return [];
|
|
4366
|
+
const idToIdx = /* @__PURE__ */ new Map();
|
|
4367
|
+
comps.forEach((c3, i4) => idToIdx.set(c3.id, i4));
|
|
4368
|
+
const graph = /* @__PURE__ */ new Map();
|
|
4369
|
+
for (let index = 0; index < comps.length; index++) {
|
|
4370
|
+
const c3 = comps[index];
|
|
4371
|
+
graph.set(c3.id, []);
|
|
4372
|
+
if (c3.type === "dialog") {
|
|
4373
|
+
const next = comps[index + 1];
|
|
4374
|
+
if (next) graph.get(c3.id).push(next.id);
|
|
4375
|
+
} else if (c3.type === "logic") {
|
|
4376
|
+
if (idToIdx.has(c3.goto_true)) graph.get(c3.id).push(c3.goto_true);
|
|
4377
|
+
if (idToIdx.has(c3.goto_false)) graph.get(c3.id).push(c3.goto_false);
|
|
4378
|
+
}
|
|
4379
|
+
}
|
|
4380
|
+
const WHITE = 0, GRAY = 1, BLACK = 2;
|
|
4381
|
+
const color2 = /* @__PURE__ */ new Map();
|
|
4382
|
+
for (const c3 of comps) color2.set(c3.id, WHITE);
|
|
4383
|
+
const cycles = [];
|
|
4384
|
+
const dfsPath = [];
|
|
4385
|
+
function dfs(node) {
|
|
4386
|
+
color2.set(node, GRAY);
|
|
4387
|
+
dfsPath.push(node);
|
|
4388
|
+
for (const nb of graph.get(node) || []) {
|
|
4389
|
+
if (!color2.has(nb)) continue;
|
|
4390
|
+
if (color2.get(nb) === GRAY) {
|
|
4391
|
+
const start = dfsPath.indexOf(nb);
|
|
4392
|
+
cycles.push(dfsPath.slice(start));
|
|
4393
|
+
} else if (color2.get(nb) === WHITE) {
|
|
4394
|
+
dfs(nb);
|
|
4395
|
+
}
|
|
4396
|
+
}
|
|
4397
|
+
dfsPath.pop();
|
|
4398
|
+
color2.set(node, BLACK);
|
|
4399
|
+
}
|
|
4400
|
+
for (const c3 of comps) {
|
|
4401
|
+
if (color2.get(c3.id) === WHITE) dfs(c3.id);
|
|
4402
|
+
}
|
|
4403
|
+
const unique2 = [];
|
|
4404
|
+
const seen = /* @__PURE__ */ new Set();
|
|
4405
|
+
for (const cyc of cycles) {
|
|
4406
|
+
const key3 = [...cyc].sort((a3, b2) => a3 - b2).join(",");
|
|
4407
|
+
if (!seen.has(key3)) {
|
|
4408
|
+
seen.add(key3);
|
|
4409
|
+
unique2.push(cyc);
|
|
4410
|
+
}
|
|
4411
|
+
}
|
|
4412
|
+
return unique2;
|
|
4413
|
+
}
|
|
4414
|
+
static getCycleWarnings(wf) {
|
|
4415
|
+
const cycles = _FlowEngine.detectCycles(wf);
|
|
4416
|
+
return cycles.map(
|
|
4417
|
+
(cyc) => `[!] Potential logic cycle in '${wf.name}': components [${cyc.join(", ")}] can form a loop.`
|
|
4418
|
+
);
|
|
4419
|
+
}
|
|
4420
|
+
static findWorkflow(name50, dir) {
|
|
4421
|
+
const names = _FlowEngine.listAll(dir);
|
|
4422
|
+
if (names.length === 0) return null;
|
|
4423
|
+
if (names.includes(name50)) return name50;
|
|
4424
|
+
const nameLower = name50.toLowerCase();
|
|
4425
|
+
for (const n3 of names) {
|
|
4426
|
+
if (n3.toLowerCase() === nameLower) return n3;
|
|
4427
|
+
}
|
|
4428
|
+
for (const n3 of names) {
|
|
4429
|
+
if (n3.toLowerCase().includes(nameLower)) return n3;
|
|
4430
|
+
}
|
|
4431
|
+
return null;
|
|
4432
|
+
}
|
|
4433
|
+
static autoTrigger(text, dir) {
|
|
4434
|
+
const names = _FlowEngine.listAll(dir);
|
|
4435
|
+
const textLower = text.toLowerCase();
|
|
4436
|
+
const results = [];
|
|
4437
|
+
for (const n3 of names) {
|
|
4438
|
+
const nLower = n3.toLowerCase();
|
|
4439
|
+
if (nLower === textLower) {
|
|
4440
|
+
results.push({ name: n3, score: 1 });
|
|
4441
|
+
} else if (textLower.includes(nLower) || nLower.includes(textLower)) {
|
|
4442
|
+
const longer = nLower.length > textLower.length ? nLower : textLower;
|
|
4443
|
+
const shorter = nLower.length > textLower.length ? textLower : nLower;
|
|
4444
|
+
const ratio = shorter.length / Math.max(longer.length, 1);
|
|
4445
|
+
results.push({ name: n3, score: 0.5 + 0.4 * Math.min(ratio, 1) });
|
|
4446
|
+
} else {
|
|
4447
|
+
const words = nLower.split(/[\s_-]+/).filter((w) => w.length > 0);
|
|
4448
|
+
const matchCount = words.filter((w) => textLower.includes(w)).length;
|
|
4449
|
+
if (matchCount > 0) {
|
|
4450
|
+
results.push({ name: n3, score: 0.2 + 0.6 * (matchCount / Math.max(words.length, 1)) });
|
|
4451
|
+
}
|
|
4452
|
+
}
|
|
4453
|
+
}
|
|
4454
|
+
results.sort((a3, b2) => b2.score - a3.score);
|
|
4455
|
+
return results;
|
|
4456
|
+
}
|
|
4457
|
+
static buildDialogPrompt(component, userInput) {
|
|
4458
|
+
const raw = component.prompt;
|
|
4459
|
+
const ui = userInput || "";
|
|
4460
|
+
const hasPlaceholder = raw.includes("{#prompt#}");
|
|
4461
|
+
if (component.mode === "plan" && ui) {
|
|
4462
|
+
if (hasPlaceholder) {
|
|
4463
|
+
return raw.replace(/\{#prompt#\}/g, ui);
|
|
4464
|
+
} else {
|
|
4465
|
+
return `Plan: ${raw}
|
|
4466
|
+
User context: ${ui}`;
|
|
4467
|
+
}
|
|
4468
|
+
}
|
|
4469
|
+
return hasPlaceholder ? raw.replace(/\{#prompt#\}/g, ui) : raw;
|
|
4470
|
+
}
|
|
4471
|
+
static generateSequence(workflow, start, 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
|
|
331322
|
-
var
|
|
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
|
|
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
|
|
332322
|
-
var
|
|
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(
|
|
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 =
|
|
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) =>
|
|
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(
|
|
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 (
|
|
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) ||
|
|
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) ||
|
|
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) ||
|
|
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 =
|
|
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(
|
|
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 =
|
|
332572
|
-
const claudePath =
|
|
332573
|
-
const newmarkPath =
|
|
332574
|
-
const codex =
|
|
332575
|
-
const claude =
|
|
332576
|
-
const newmark =
|
|
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 =
|
|
332584
|
-
if (
|
|
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
|
-
|
|
332593
|
-
|
|
332594
|
-
|
|
332595
|
-
|
|
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 (
|
|
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" ?
|
|
332604
|
-
const opencodeToolsDir =
|
|
332605
|
-
const opencodePluginsDir =
|
|
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
|
-
|
|
332647
|
-
|
|
332648
|
-
|
|
332649
|
-
|
|
332650
|
-
|
|
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) =>
|
|
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}:${
|
|
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
|
|
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 =
|
|
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 =
|
|
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) ||
|
|
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 =
|
|
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 =
|
|
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
|
-
|
|
332780
|
-
|
|
332781
|
-
|
|
332782
|
-
|
|
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
|
-
|
|
332792
|
-
|
|
332793
|
-
|
|
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(`${
|
|
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
|
-
|
|
332872
|
+
path8.basename(preset.path)
|
|
332836
332873
|
].map((value) => String(value || "").toLowerCase());
|
|
332837
|
-
return keys.includes(normalized) ||
|
|
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
|
|
332843
|
-
var
|
|
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 =
|
|
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 =
|
|
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 =
|
|
332999
|
+
const packageRoot = path9.dirname(packageJson);
|
|
332963
333000
|
return [
|
|
332964
|
-
|
|
332965
|
-
|
|
332966
|
-
|
|
332967
|
-
].some((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
|
|
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(
|
|
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
|
-
|
|
333260
|
-
const fd =
|
|
333296
|
+
fs8.mkdirSync(path9.dirname(filePath), { recursive: true });
|
|
333297
|
+
const fd = fs8.openSync(tempPath, "w");
|
|
333261
333298
|
try {
|
|
333262
|
-
|
|
333263
|
-
|
|
333299
|
+
fs8.writeFileSync(fd, JSON.stringify(output, null, 2), "utf-8");
|
|
333300
|
+
fs8.fsyncSync(fd);
|
|
333264
333301
|
} finally {
|
|
333265
|
-
|
|
333302
|
+
fs8.closeSync(fd);
|
|
333266
333303
|
}
|
|
333267
333304
|
try {
|
|
333268
|
-
|
|
333305
|
+
fs8.renameSync(tempPath, filePath);
|
|
333269
333306
|
} catch (error) {
|
|
333270
333307
|
try {
|
|
333271
|
-
|
|
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
|
|
333501
|
-
var
|
|
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 =
|
|
333710
|
-
|
|
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
|
|
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 ||
|
|
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 =
|
|
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 =
|
|
333798
|
+
const filePath = path10.join(directory, name50);
|
|
333762
333799
|
let stats;
|
|
333763
333800
|
try {
|
|
333764
|
-
stats =
|
|
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
|
-
|
|
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
|
-
|
|
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 =
|
|
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
|
-
|
|
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
|
-
|
|
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 `${
|
|
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 &&
|
|
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 &&
|
|
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
|
|
334870
|
-
var
|
|
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
|
|
334875
|
-
var
|
|
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
|
|
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
|
|
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 (
|
|
335064
|
-
const absolute =
|
|
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(
|
|
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 =
|
|
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
|
|
335115
|
+
source = await fs10.readFile(batchPath, "utf8");
|
|
335079
335116
|
} catch {
|
|
335080
335117
|
return null;
|
|
335081
335118
|
}
|
|
335082
|
-
const directory =
|
|
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 =
|
|
335097
|
-
const directoryPrefix = `${
|
|
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 =
|
|
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
|
|
335179
|
+
return path12.join(this.rootPath, "Work", "SSH.json");
|
|
335143
335180
|
}
|
|
335144
335181
|
ensureStore() {
|
|
335145
335182
|
try {
|
|
335146
|
-
|
|
335147
|
-
if (!
|
|
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(
|
|
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
|
-
|
|
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
|
|
335344
|
-
var
|
|
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
|
|
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
|
|
335366
|
-
return
|
|
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
|
|
335408
|
+
return path13.posix.resolve(`/mnt/${drive}/${rest}`);
|
|
335372
335409
|
}
|
|
335373
|
-
return
|
|
335410
|
+
return path13.posix.resolve(raw || ".");
|
|
335374
335411
|
}
|
|
335375
335412
|
function isPathInside(parent, child) {
|
|
335376
335413
|
try {
|
|
335377
|
-
const relative6 =
|
|
335378
|
-
return relative6 === "" || !!relative6 && !relative6.startsWith("..") && !
|
|
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 = [
|
|
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 =
|
|
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 =
|
|
335441
|
+
const workDir = path13.join(rootPath, "Work");
|
|
335405
335442
|
try {
|
|
335406
|
-
|
|
335443
|
+
fs12.mkdirSync(workDir, { recursive: true });
|
|
335407
335444
|
} catch {
|
|
335408
335445
|
}
|
|
335409
335446
|
for (const fn of ["Local.json", "External.json"]) {
|
|
335410
|
-
const p =
|
|
335411
|
-
if (!
|
|
335447
|
+
const p = path13.join(workDir, fn);
|
|
335448
|
+
if (!fs12.existsSync(p)) {
|
|
335412
335449
|
try {
|
|
335413
|
-
|
|
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 =
|
|
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 =
|
|
335450
|
-
if (!
|
|
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(
|
|
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(
|
|
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
|
|
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",
|
|
335513
|
+
id: this.stableWorkspaceId("local", path13.join(w, entry.name)),
|
|
335477
335514
|
name: entry.name,
|
|
335478
|
-
path:
|
|
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 ||
|
|
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 =
|
|
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 ||
|
|
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 ||
|
|
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 =
|
|
335576
|
+
real = fs12.existsSync(resolved) ? fs12.realpathSync.native(resolved) : resolved;
|
|
335540
335577
|
} catch {
|
|
335541
335578
|
real = resolved;
|
|
335542
335579
|
}
|
|
335543
|
-
const normalized =
|
|
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 =
|
|
335570
|
-
return rel === "" || !!rel && !rel.startsWith("..") && !
|
|
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
|
|
335636
|
+
return path13.join(this.rootPath, "Work", "State.json");
|
|
335600
335637
|
}
|
|
335601
335638
|
readState() {
|
|
335602
335639
|
const p = this.statePath();
|
|
335603
|
-
if (!
|
|
335640
|
+
if (!fs12.existsSync(p)) return {};
|
|
335604
335641
|
try {
|
|
335605
|
-
const raw =
|
|
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
|
-
|
|
335627
|
-
|
|
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 =
|
|
335723
|
+
const p = path13.join(this.rootPath, "Work", "Local.json");
|
|
335687
335724
|
this.internal = this.dedupeByPath(this.internal);
|
|
335688
335725
|
this.sortWorkspaces();
|
|
335689
|
-
|
|
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 =
|
|
335730
|
+
const p = path13.join(this.rootPath, "Work", "External.json");
|
|
335694
335731
|
this.external = this.dedupeByPath(this.external);
|
|
335695
335732
|
this.sortWorkspaces();
|
|
335696
|
-
|
|
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 =
|
|
335705
|
-
const resolved =
|
|
335706
|
-
const rel =
|
|
335707
|
-
return !!rel && !rel.startsWith("..") && !
|
|
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 (!
|
|
335711
|
-
const stat =
|
|
335747
|
+
if (!fs12.existsSync(target)) return;
|
|
335748
|
+
const stat = fs12.lstatSync(target);
|
|
335712
335749
|
try {
|
|
335713
|
-
|
|
335750
|
+
fs12.chmodSync(target, stat.mode | 448);
|
|
335714
335751
|
} catch {
|
|
335715
335752
|
}
|
|
335716
335753
|
if (!stat.isDirectory()) return;
|
|
335717
|
-
for (const entry of
|
|
335718
|
-
this.clearReadOnlyRecursive(
|
|
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 =
|
|
335759
|
+
const resolved = path13.resolve(target);
|
|
335723
335760
|
if (!this.isInternalWorkspacePath(resolved)) return false;
|
|
335724
|
-
if (!
|
|
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
|
-
|
|
335766
|
+
fs12.rmSync(resolved, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 });
|
|
335730
335767
|
} catch {
|
|
335731
335768
|
}
|
|
335732
|
-
if (!
|
|
335769
|
+
if (!fs12.existsSync(resolved)) return true;
|
|
335733
335770
|
try {
|
|
335734
335771
|
this.clearReadOnlyRecursive(resolved);
|
|
335735
|
-
|
|
335772
|
+
fs12.rmSync(resolved, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 });
|
|
335736
335773
|
} catch {
|
|
335737
335774
|
}
|
|
335738
|
-
if (!
|
|
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 =
|
|
335745
|
-
|
|
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 =
|
|
335768
|
-
if (!
|
|
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 =
|
|
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 ||
|
|
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 ?
|
|
335796
|
-
|
|
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
|
|
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 =
|
|
335888
|
-
const inside2 = rel === "" || !!rel && !rel.startsWith("..") && !
|
|
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
|
|
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 =
|
|
336415
|
-
const cwd =
|
|
336416
|
-
const relative6 =
|
|
336417
|
-
if (relative6.startsWith("..") ||
|
|
336418
|
-
return relative6 ? `/${relative6.split(
|
|
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:
|
|
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
|
|
336534
|
-
var
|
|
336585
|
+
var fs13 = require("fs");
|
|
336586
|
+
var path15 = require("path");
|
|
336535
336587
|
var typeBoxCompilerPath = [
|
|
336536
|
-
|
|
336537
|
-
|
|
336538
|
-
].find((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
|
|
336629
|
-
var
|
|
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 =
|
|
336663
|
-
const extension =
|
|
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 =
|
|
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:
|
|
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 =
|
|
336730
|
-
|
|
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 =
|
|
336733
|
-
if (
|
|
336734
|
-
const packageRoot =
|
|
336735
|
-
const source =
|
|
336736
|
-
|
|
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 (
|
|
336876
|
-
return
|
|
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 =
|
|
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:
|
|
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
|
|
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", "
|
|
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", "
|
|
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 (
|
|
337524
|
-
const stat =
|
|
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(
|
|
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
|
|
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 =
|
|
337806
|
-
return rel === "" || !!rel && !rel.startsWith("..") && !
|
|
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(
|
|
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 =
|
|
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
|
-
|
|
337978
|
-
|
|
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 =
|
|
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
|
-
|
|
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 =
|
|
337999
|
-
const stat =
|
|
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
|
-
|
|
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
|
|
338028
|
-
const full =
|
|
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 =
|
|
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 =
|
|
338248
|
-
|
|
338249
|
-
|
|
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 =
|
|
338308
|
+
const dir = path17.join(this.root, "Flow");
|
|
338257
338309
|
try {
|
|
338258
|
-
const files =
|
|
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,
|
|
338317
|
+
flowSave(name50, input) {
|
|
338266
338318
|
const cleanName = (name50 || "").replace(/[<>:"/\\|?*]/g, "-").trim();
|
|
338267
338319
|
if (!cleanName) return "[flow_save] Workflow name is required.";
|
|
338268
|
-
|
|
338269
|
-
const
|
|
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
|
-
|
|
338291
|
-
|
|
338292
|
-
|
|
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 =
|
|
338354
|
-
const exists =
|
|
338355
|
-
const stat = exists ?
|
|
338356
|
-
const repoRoot = await this.findGitRoot(exists && stat?.isDirectory() ? resolvedTarget :
|
|
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(
|
|
338458
|
+
hash.update(fs15.readFileSync(target));
|
|
338384
338459
|
base2.sha256 = hash.digest("hex").toUpperCase();
|
|
338385
338460
|
}
|
|
338386
338461
|
if (stat.isDirectory()) {
|
|
338387
|
-
base2.entries =
|
|
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 &&
|
|
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 =
|
|
338403
|
-
const inside2 = rel === "" || !!rel && !rel.startsWith("..") && !
|
|
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 =
|
|
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 =
|
|
338486
|
-
const repoRoot = await this.findGitRoot(
|
|
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 =
|
|
338585
|
-
if (!
|
|
338586
|
-
if (
|
|
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 =
|
|
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 =
|
|
338620
|
-
if (!
|
|
338621
|
-
if (
|
|
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 =
|
|
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) =>
|
|
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
|
|
339446
|
-
var
|
|
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 =
|
|
339456
|
-
this.metaPath =
|
|
339457
|
-
this.marketSourcesPath =
|
|
339458
|
-
|
|
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
|
|
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 ||
|
|
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 =
|
|
339485
|
-
const content =
|
|
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
|
|
339565
|
+
return fs16.existsSync(path18.join(this.skillsDir, name50, "SKILL.md"));
|
|
339491
339566
|
}
|
|
339492
339567
|
getPath(name50) {
|
|
339493
|
-
return
|
|
339568
|
+
return path18.join(this.skillsDir, name50);
|
|
339494
339569
|
}
|
|
339495
339570
|
async download(name50, url) {
|
|
339496
|
-
const dir =
|
|
339497
|
-
|
|
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
|
-
|
|
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 =
|
|
339510
|
-
if (!
|
|
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 ||
|
|
339587
|
+
const cleanName = this.cleanName(targetName || info.name || path18.basename(sourceDir));
|
|
339513
339588
|
if (!cleanName) return false;
|
|
339514
|
-
const dest =
|
|
339515
|
-
|
|
339516
|
-
|
|
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 =
|
|
339522
|
-
if (
|
|
339523
|
-
|
|
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 ?
|
|
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:
|
|
339611
|
-
{ root:
|
|
339612
|
-
{ root:
|
|
339613
|
-
{ root:
|
|
339614
|
-
{ root:
|
|
339615
|
-
{ root:
|
|
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 ||
|
|
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(
|
|
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 ||
|
|
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 (
|
|
339697
|
-
const raw = JSON.parse(
|
|
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
|
-
|
|
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 (!
|
|
339720
|
-
const raw = JSON.parse(
|
|
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
|
-
|
|
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 ?
|
|
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 ?
|
|
339801
|
-
if (catalogPath &&
|
|
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
|
|
339804
|
-
if (url && !url.startsWith("http")) return
|
|
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 ||
|
|
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 =
|
|
339890
|
-
const stat =
|
|
339891
|
-
const content =
|
|
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(
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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(
|
|
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 =
|
|
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(
|
|
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(
|
|
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 =
|
|
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 =
|
|
340103
|
+
let current = path18.resolve(dir);
|
|
340029
340104
|
for (let i4 = 0; i4 < 6; i4++) {
|
|
340030
|
-
const codex =
|
|
340031
|
-
const claude =
|
|
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 (
|
|
340035
|
-
const raw = JSON.parse(
|
|
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 =
|
|
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
|
-
|
|
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
|
|
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
|
|
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.]";
|