newmark-agent 0.5.8 → 0.5.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/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 +422 -19
- 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, input2) {
|
|
4472
|
+
const orderedComponents = [...workflow.components];
|
|
4473
|
+
const seq = [];
|
|
4474
|
+
let cur = start;
|
|
4475
|
+
let count = 0;
|
|
4476
|
+
const max2 = workflow.components.length + 10;
|
|
4477
|
+
while (count < max2) {
|
|
4478
|
+
count++;
|
|
4479
|
+
const comp = workflow.components.find((c3) => c3.id === cur);
|
|
4480
|
+
if (!comp) break;
|
|
4481
|
+
if (comp.type === "dialog") {
|
|
4482
|
+
const expanded = _FlowEngine.buildDialogPrompt(comp, input2);
|
|
4483
|
+
seq.push({ id: comp.id, mode: comp.mode, prompt: expanded, isLogic: false });
|
|
4484
|
+
const index = orderedComponents.findIndex((item) => item.id === comp.id);
|
|
4485
|
+
if (index < 0 || index + 1 >= orderedComponents.length) break;
|
|
4486
|
+
cur = orderedComponents[index + 1].id;
|
|
4487
|
+
} else {
|
|
4488
|
+
seq.push({
|
|
4489
|
+
id: comp.id,
|
|
4490
|
+
prompt: comp.prompt.replace(/\{#prompt#\}/g, input2),
|
|
4491
|
+
isLogic: true,
|
|
4492
|
+
gotoTrue: comp.goto_true,
|
|
4493
|
+
gotoFalse: comp.goto_false
|
|
4494
|
+
});
|
|
4495
|
+
break;
|
|
4496
|
+
}
|
|
4497
|
+
}
|
|
4498
|
+
return seq;
|
|
4499
|
+
}
|
|
4500
|
+
static resolveGoto(workflow, cur, cond) {
|
|
4501
|
+
const comp = workflow.components.find((c3) => c3.id === cur);
|
|
4502
|
+
if (comp?.type === "logic") {
|
|
4503
|
+
return cond ? comp.goto_true : comp.goto_false;
|
|
4504
|
+
}
|
|
4505
|
+
const index = workflow.components.findIndex((component) => component.id === cur);
|
|
4506
|
+
return index >= 0 && index + 1 < workflow.components.length ? workflow.components[index + 1].id : -1;
|
|
4507
|
+
}
|
|
4508
|
+
};
|
|
4509
|
+
}
|
|
4510
|
+
});
|
|
4511
|
+
|
|
4284
4512
|
// node_modules/regenerator-runtime/runtime.js
|
|
4285
4513
|
var require_runtime = __commonJS({
|
|
4286
4514
|
"node_modules/regenerator-runtime/runtime.js"(exports2, module2) {
|
|
@@ -326027,234 +326255,6 @@ var require_readability = __commonJS({
|
|
|
326027
326255
|
}
|
|
326028
326256
|
});
|
|
326029
326257
|
|
|
326030
|
-
// src/core/flow.ts
|
|
326031
|
-
var fs16, path18, FlowEngine;
|
|
326032
|
-
var init_flow = __esm({
|
|
326033
|
-
"src/core/flow.ts"() {
|
|
326034
|
-
"use strict";
|
|
326035
|
-
fs16 = __toESM(require("fs"));
|
|
326036
|
-
path18 = __toESM(require("path"));
|
|
326037
|
-
FlowEngine = class _FlowEngine {
|
|
326038
|
-
static load(dir, name50) {
|
|
326039
|
-
const p = path18.join(dir, `${name50}.Flow.json`);
|
|
326040
|
-
try {
|
|
326041
|
-
return JSON.parse(fs16.readFileSync(p, "utf-8").replace(/^\uFEFF/, ""));
|
|
326042
|
-
} catch {
|
|
326043
|
-
return null;
|
|
326044
|
-
}
|
|
326045
|
-
}
|
|
326046
|
-
static save(dir, workflow) {
|
|
326047
|
-
const p = path18.join(dir, `${workflow.name}.Flow.json`);
|
|
326048
|
-
fs16.writeFileSync(p, JSON.stringify(workflow, null, 2), "utf-8");
|
|
326049
|
-
}
|
|
326050
|
-
static delete(dir, name50) {
|
|
326051
|
-
const p = path18.join(dir, `${name50}.Flow.json`);
|
|
326052
|
-
if (fs16.existsSync(p)) fs16.unlinkSync(p);
|
|
326053
|
-
}
|
|
326054
|
-
static listAll(dir) {
|
|
326055
|
-
try {
|
|
326056
|
-
return fs16.readdirSync(dir).filter((f3) => f3.endsWith(".Flow.json")).map((f3) => f3.replace(".Flow.json", "")).sort();
|
|
326057
|
-
} catch {
|
|
326058
|
-
return [];
|
|
326059
|
-
}
|
|
326060
|
-
}
|
|
326061
|
-
static describeWorkflow(wf) {
|
|
326062
|
-
const comps = [...wf.components].sort((a3, b2) => a3.id - b2.id);
|
|
326063
|
-
if (comps.length === 0) return "";
|
|
326064
|
-
const parts = [];
|
|
326065
|
-
for (const c3 of comps) {
|
|
326066
|
-
if (c3.type === "dialog") {
|
|
326067
|
-
parts.push(c3.mode.charAt(0).toUpperCase() + c3.mode.slice(1));
|
|
326068
|
-
} else {
|
|
326069
|
-
const label = c3.prompt.replace(/\{#prompt#\}/g, "<i>").replace(/\n/g, " ").slice(0, 22);
|
|
326070
|
-
parts.push(`?${label}?`);
|
|
326071
|
-
}
|
|
326072
|
-
}
|
|
326073
|
-
return parts.join(" \u2192 ");
|
|
326074
|
-
}
|
|
326075
|
-
static validate(wf) {
|
|
326076
|
-
const errors = [];
|
|
326077
|
-
if (!wf.components || wf.components.length === 0) {
|
|
326078
|
-
errors.push({ message: "No components defined." });
|
|
326079
|
-
return errors;
|
|
326080
|
-
}
|
|
326081
|
-
const ids = /* @__PURE__ */ new Set();
|
|
326082
|
-
for (const c3 of wf.components) {
|
|
326083
|
-
if (typeof c3.id === "number") ids.add(c3.id);
|
|
326084
|
-
}
|
|
326085
|
-
const seenIds = /* @__PURE__ */ new Set();
|
|
326086
|
-
for (const c3 of wf.components) {
|
|
326087
|
-
if (seenIds.has(c3.id)) {
|
|
326088
|
-
errors.push({ componentId: c3.id, message: `Duplicate component ID: ${c3.id}` });
|
|
326089
|
-
}
|
|
326090
|
-
seenIds.add(c3.id);
|
|
326091
|
-
if (c3.type === "dialog") {
|
|
326092
|
-
const mode = c3.mode.toLowerCase();
|
|
326093
|
-
if (!["build", "plan", "goal"].includes(mode)) {
|
|
326094
|
-
errors.push({ componentId: c3.id, message: `Invalid dialog mode '${c3.mode}' (must be build/plan/goal)` });
|
|
326095
|
-
}
|
|
326096
|
-
} else if (c3.type === "logic") {
|
|
326097
|
-
if (!ids.has(c3.goto_true)) {
|
|
326098
|
-
errors.push({ componentId: c3.id, message: `goto_true=${c3.goto_true} not found` });
|
|
326099
|
-
}
|
|
326100
|
-
if (!ids.has(c3.goto_false)) {
|
|
326101
|
-
errors.push({ componentId: c3.id, message: `goto_false=${c3.goto_false} not found` });
|
|
326102
|
-
}
|
|
326103
|
-
} else {
|
|
326104
|
-
errors.push({ componentId: c3.id, message: `Unknown component type '${c3.type}'` });
|
|
326105
|
-
}
|
|
326106
|
-
}
|
|
326107
|
-
return errors;
|
|
326108
|
-
}
|
|
326109
|
-
static detectCycles(wf) {
|
|
326110
|
-
const comps = [...wf.components].sort((a3, b2) => a3.id - b2.id);
|
|
326111
|
-
if (comps.length === 0) return [];
|
|
326112
|
-
const idToIdx = /* @__PURE__ */ new Map();
|
|
326113
|
-
comps.forEach((c3, i4) => idToIdx.set(c3.id, i4));
|
|
326114
|
-
const graph = /* @__PURE__ */ new Map();
|
|
326115
|
-
for (let index = 0; index < comps.length; index++) {
|
|
326116
|
-
const c3 = comps[index];
|
|
326117
|
-
graph.set(c3.id, []);
|
|
326118
|
-
if (c3.type === "dialog") {
|
|
326119
|
-
const next = comps[index + 1];
|
|
326120
|
-
if (next) graph.get(c3.id).push(next.id);
|
|
326121
|
-
} else if (c3.type === "logic") {
|
|
326122
|
-
if (idToIdx.has(c3.goto_true)) graph.get(c3.id).push(c3.goto_true);
|
|
326123
|
-
if (idToIdx.has(c3.goto_false)) graph.get(c3.id).push(c3.goto_false);
|
|
326124
|
-
}
|
|
326125
|
-
}
|
|
326126
|
-
const WHITE = 0, GRAY = 1, BLACK = 2;
|
|
326127
|
-
const color2 = /* @__PURE__ */ new Map();
|
|
326128
|
-
for (const c3 of comps) color2.set(c3.id, WHITE);
|
|
326129
|
-
const cycles = [];
|
|
326130
|
-
const dfsPath = [];
|
|
326131
|
-
function dfs(node) {
|
|
326132
|
-
color2.set(node, GRAY);
|
|
326133
|
-
dfsPath.push(node);
|
|
326134
|
-
for (const nb of graph.get(node) || []) {
|
|
326135
|
-
if (!color2.has(nb)) continue;
|
|
326136
|
-
if (color2.get(nb) === GRAY) {
|
|
326137
|
-
const start = dfsPath.indexOf(nb);
|
|
326138
|
-
cycles.push(dfsPath.slice(start));
|
|
326139
|
-
} else if (color2.get(nb) === WHITE) {
|
|
326140
|
-
dfs(nb);
|
|
326141
|
-
}
|
|
326142
|
-
}
|
|
326143
|
-
dfsPath.pop();
|
|
326144
|
-
color2.set(node, BLACK);
|
|
326145
|
-
}
|
|
326146
|
-
for (const c3 of comps) {
|
|
326147
|
-
if (color2.get(c3.id) === WHITE) dfs(c3.id);
|
|
326148
|
-
}
|
|
326149
|
-
const unique2 = [];
|
|
326150
|
-
const seen = /* @__PURE__ */ new Set();
|
|
326151
|
-
for (const cyc of cycles) {
|
|
326152
|
-
const key3 = [...cyc].sort((a3, b2) => a3 - b2).join(",");
|
|
326153
|
-
if (!seen.has(key3)) {
|
|
326154
|
-
seen.add(key3);
|
|
326155
|
-
unique2.push(cyc);
|
|
326156
|
-
}
|
|
326157
|
-
}
|
|
326158
|
-
return unique2;
|
|
326159
|
-
}
|
|
326160
|
-
static getCycleWarnings(wf) {
|
|
326161
|
-
const cycles = _FlowEngine.detectCycles(wf);
|
|
326162
|
-
return cycles.map(
|
|
326163
|
-
(cyc) => `[!] Potential logic cycle in '${wf.name}': components [${cyc.join(", ")}] can form a loop.`
|
|
326164
|
-
);
|
|
326165
|
-
}
|
|
326166
|
-
static findWorkflow(name50, dir) {
|
|
326167
|
-
const names = _FlowEngine.listAll(dir);
|
|
326168
|
-
if (names.length === 0) return null;
|
|
326169
|
-
if (names.includes(name50)) return name50;
|
|
326170
|
-
const nameLower = name50.toLowerCase();
|
|
326171
|
-
for (const n3 of names) {
|
|
326172
|
-
if (n3.toLowerCase() === nameLower) return n3;
|
|
326173
|
-
}
|
|
326174
|
-
for (const n3 of names) {
|
|
326175
|
-
if (n3.toLowerCase().includes(nameLower)) return n3;
|
|
326176
|
-
}
|
|
326177
|
-
return null;
|
|
326178
|
-
}
|
|
326179
|
-
static autoTrigger(text, dir) {
|
|
326180
|
-
const names = _FlowEngine.listAll(dir);
|
|
326181
|
-
const textLower = text.toLowerCase();
|
|
326182
|
-
const results = [];
|
|
326183
|
-
for (const n3 of names) {
|
|
326184
|
-
const nLower = n3.toLowerCase();
|
|
326185
|
-
if (nLower === textLower) {
|
|
326186
|
-
results.push({ name: n3, score: 1 });
|
|
326187
|
-
} else if (textLower.includes(nLower) || nLower.includes(textLower)) {
|
|
326188
|
-
const longer = nLower.length > textLower.length ? nLower : textLower;
|
|
326189
|
-
const shorter = nLower.length > textLower.length ? textLower : nLower;
|
|
326190
|
-
const ratio = shorter.length / Math.max(longer.length, 1);
|
|
326191
|
-
results.push({ name: n3, score: 0.5 + 0.4 * Math.min(ratio, 1) });
|
|
326192
|
-
} else {
|
|
326193
|
-
const words = nLower.split(/[\s_-]+/).filter((w) => w.length > 0);
|
|
326194
|
-
const matchCount = words.filter((w) => textLower.includes(w)).length;
|
|
326195
|
-
if (matchCount > 0) {
|
|
326196
|
-
results.push({ name: n3, score: 0.2 + 0.6 * (matchCount / Math.max(words.length, 1)) });
|
|
326197
|
-
}
|
|
326198
|
-
}
|
|
326199
|
-
}
|
|
326200
|
-
results.sort((a3, b2) => b2.score - a3.score);
|
|
326201
|
-
return results;
|
|
326202
|
-
}
|
|
326203
|
-
static buildDialogPrompt(component, userInput) {
|
|
326204
|
-
const raw = component.prompt;
|
|
326205
|
-
const ui = userInput || "";
|
|
326206
|
-
const hasPlaceholder = raw.includes("{#prompt#}");
|
|
326207
|
-
if (component.mode === "plan" && ui) {
|
|
326208
|
-
if (hasPlaceholder) {
|
|
326209
|
-
return raw.replace(/\{#prompt#\}/g, ui);
|
|
326210
|
-
} else {
|
|
326211
|
-
return `Plan: ${raw}
|
|
326212
|
-
User context: ${ui}`;
|
|
326213
|
-
}
|
|
326214
|
-
}
|
|
326215
|
-
return hasPlaceholder ? raw.replace(/\{#prompt#\}/g, ui) : raw;
|
|
326216
|
-
}
|
|
326217
|
-
static generateSequence(workflow, start, input2) {
|
|
326218
|
-
const orderedComponents = [...workflow.components];
|
|
326219
|
-
const seq = [];
|
|
326220
|
-
let cur = start;
|
|
326221
|
-
let count = 0;
|
|
326222
|
-
const max2 = workflow.components.length + 10;
|
|
326223
|
-
while (count < max2) {
|
|
326224
|
-
count++;
|
|
326225
|
-
const comp = workflow.components.find((c3) => c3.id === cur);
|
|
326226
|
-
if (!comp) break;
|
|
326227
|
-
if (comp.type === "dialog") {
|
|
326228
|
-
const expanded = _FlowEngine.buildDialogPrompt(comp, input2);
|
|
326229
|
-
seq.push({ id: comp.id, mode: comp.mode, prompt: expanded, isLogic: false });
|
|
326230
|
-
const index = orderedComponents.findIndex((item) => item.id === comp.id);
|
|
326231
|
-
if (index < 0 || index + 1 >= orderedComponents.length) break;
|
|
326232
|
-
cur = orderedComponents[index + 1].id;
|
|
326233
|
-
} else {
|
|
326234
|
-
seq.push({
|
|
326235
|
-
id: comp.id,
|
|
326236
|
-
prompt: comp.prompt.replace(/\{#prompt#\}/g, input2),
|
|
326237
|
-
isLogic: true,
|
|
326238
|
-
gotoTrue: comp.goto_true,
|
|
326239
|
-
gotoFalse: comp.goto_false
|
|
326240
|
-
});
|
|
326241
|
-
break;
|
|
326242
|
-
}
|
|
326243
|
-
}
|
|
326244
|
-
return seq;
|
|
326245
|
-
}
|
|
326246
|
-
static resolveGoto(workflow, cur, cond) {
|
|
326247
|
-
const comp = workflow.components.find((c3) => c3.id === cur);
|
|
326248
|
-
if (comp?.type === "logic") {
|
|
326249
|
-
return cond ? comp.goto_true : comp.goto_false;
|
|
326250
|
-
}
|
|
326251
|
-
const index = workflow.components.findIndex((component) => component.id === cur);
|
|
326252
|
-
return index >= 0 && index + 1 < workflow.components.length ? workflow.components[index + 1].id : -1;
|
|
326253
|
-
}
|
|
326254
|
-
};
|
|
326255
|
-
}
|
|
326256
|
-
});
|
|
326257
|
-
|
|
326258
326258
|
// src/core/agentKernel/agent-loop.ts
|
|
326259
326259
|
async function runAgentLoop(prompts, config, signal) {
|
|
326260
326260
|
throwIfAborted3(signal);
|
|
@@ -331322,8 +331322,8 @@ async function fuzzyDiscoverWithoutGuide(input2, explicit, preferredModels = [])
|
|
|
331322
331322
|
}
|
|
331323
331323
|
|
|
331324
331324
|
// src/tools/index.ts
|
|
331325
|
-
var
|
|
331326
|
-
var
|
|
331325
|
+
var fs15 = __toESM(require("fs"));
|
|
331326
|
+
var path17 = __toESM(require("path"));
|
|
331327
331327
|
var crypto8 = __toESM(require("crypto"));
|
|
331328
331328
|
var import_url2 = require("url");
|
|
331329
331329
|
|
|
@@ -331667,7 +331667,8 @@ var MemoryLabManager = class {
|
|
|
331667
331667
|
"Use memory_lab_read to inspect index.json before deciding what memory is relevant.",
|
|
331668
331668
|
"Use memory_lab_query for bounded task-relevant retrieval; do not inject the complete index when a focused query is sufficient.",
|
|
331669
331669
|
"Use memory_lab_read with component/name/slug to read a component core markdown file.",
|
|
331670
|
-
"Use memory_lab_update only when the user asks to create or update durable memory
|
|
331670
|
+
"Use memory_lab_update only when the user asks to create or update durable memory. Create with name, tags, and content; patch an existing component with component plus only changed fields.",
|
|
331671
|
+
"For small body edits prefer contentAppend or oldText/newText over resending the complete content.",
|
|
331671
331672
|
"For an existing component, pass expectedUpdatedAt from the latest read/query result. A stale update is rejected instead of overwriting newer memory.",
|
|
331672
331673
|
"Use memory_lab_delete only when the user explicitly asks to forget/remove durable memory. Delete moves the prior revision to Memory Lab/archive and records a policy event.",
|
|
331673
331674
|
"Every mutation should include a concise reason and source. ADD, UPDATE, and DELETE decisions are append-only in policy.jsonl and are recoverable from archive.",
|
|
@@ -331775,6 +331776,39 @@ var MemoryLabManager = class {
|
|
|
331775
331776
|
source: String(input2.source || "").trim()
|
|
331776
331777
|
};
|
|
331777
331778
|
}
|
|
331779
|
+
preparePatch(input2) {
|
|
331780
|
+
const selector2 = String(input2.component || "").trim();
|
|
331781
|
+
if (!selector2) throw new Error("Memory component is required for a patch.");
|
|
331782
|
+
const current = this.read(selector2);
|
|
331783
|
+
if (!current.ok || !current.component) throw new Error(current.error || `Memory component not found: ${selector2}`);
|
|
331784
|
+
const existing = current.component.meta;
|
|
331785
|
+
const oldContent = current.component.content;
|
|
331786
|
+
let content = input2.content !== void 0 ? String(input2.content) : oldContent;
|
|
331787
|
+
if (input2.contentAppend !== void 0) content = `${oldContent}${String(input2.contentAppend)}`;
|
|
331788
|
+
if (input2.oldText !== void 0) {
|
|
331789
|
+
const oldText = String(input2.oldText);
|
|
331790
|
+
if (!oldText) throw new Error("oldText must not be empty.");
|
|
331791
|
+
const matches = oldContent.split(oldText).length - 1;
|
|
331792
|
+
if (!matches) throw new Error("oldText was not found in the Memory Lab component.");
|
|
331793
|
+
if (matches > 1 && input2.replaceAll !== true) throw new Error(`oldText matched ${matches} places; pass replaceAll=true or a unique fragment.`);
|
|
331794
|
+
content = input2.replaceAll === true ? oldContent.split(oldText).join(String(input2.newText || "")) : oldContent.replace(oldText, String(input2.newText || ""));
|
|
331795
|
+
}
|
|
331796
|
+
const name50 = input2.name === void 0 ? existing.name : String(input2.name);
|
|
331797
|
+
if (this.slugify(name50) !== current.component.slug) {
|
|
331798
|
+
throw new Error("Renaming a Memory Lab component is not supported by incremental patch; create the new component then delete the old one.");
|
|
331799
|
+
}
|
|
331800
|
+
return this.prepareUpdate({
|
|
331801
|
+
name: name50,
|
|
331802
|
+
description: input2.description === void 0 ? existing.description : String(input2.description),
|
|
331803
|
+
tags: input2.tags === void 0 ? existing.tags : input2.tags,
|
|
331804
|
+
tagPaths: input2.tagPaths === void 0 ? existing.tagPaths : input2.tagPaths,
|
|
331805
|
+
content,
|
|
331806
|
+
kind: input2.kind === void 0 ? existing.kind : input2.kind,
|
|
331807
|
+
expectedUpdatedAt: String(input2.expectedUpdatedAt || existing.updatedAt),
|
|
331808
|
+
reason: input2.reason,
|
|
331809
|
+
source: input2.source
|
|
331810
|
+
});
|
|
331811
|
+
}
|
|
331778
331812
|
update(prepared) {
|
|
331779
331813
|
this.ensure();
|
|
331780
331814
|
const index = this.loadIndex();
|
|
@@ -332321,20 +332355,23 @@ ${JSON.stringify(payload, null, 2)}`;
|
|
|
332321
332355
|
}
|
|
332322
332356
|
};
|
|
332323
332357
|
|
|
332358
|
+
// src/tools/index.ts
|
|
332359
|
+
init_flow();
|
|
332360
|
+
|
|
332324
332361
|
// src/core/compat.ts
|
|
332325
|
-
var
|
|
332326
|
-
var
|
|
332362
|
+
var fs7 = __toESM(require("fs"));
|
|
332363
|
+
var path8 = __toESM(require("path"));
|
|
332327
332364
|
var os2 = __toESM(require("os"));
|
|
332328
332365
|
function readJson(filePath) {
|
|
332329
332366
|
try {
|
|
332330
|
-
return JSON.parse(
|
|
332367
|
+
return JSON.parse(fs7.readFileSync(filePath, "utf-8").replace(/^\uFEFF/, ""));
|
|
332331
332368
|
} catch {
|
|
332332
332369
|
return null;
|
|
332333
332370
|
}
|
|
332334
332371
|
}
|
|
332335
332372
|
function readJsonLoose(filePath) {
|
|
332336
332373
|
try {
|
|
332337
|
-
const withoutBom =
|
|
332374
|
+
const withoutBom = fs7.readFileSync(filePath, "utf-8").replace(/^\uFEFF/, "");
|
|
332338
332375
|
const withoutComments = withoutBom.replace(/\/\*[\s\S]*?\*\//g, "").replace(/(^|\s)\/\/.*$/gm, "$1");
|
|
332339
332376
|
return JSON.parse(withoutComments);
|
|
332340
332377
|
} catch {
|
|
@@ -332415,7 +332452,7 @@ function normalizeToolResult(output, metadata) {
|
|
|
332415
332452
|
return { ok: !error, output, error, metadata };
|
|
332416
332453
|
}
|
|
332417
332454
|
function componentPaths(root2, value) {
|
|
332418
|
-
return asStringArray(value).map((item) =>
|
|
332455
|
+
return asStringArray(value).map((item) => path8.resolve(root2, item));
|
|
332419
332456
|
}
|
|
332420
332457
|
function manifestComponentPaths(root2, manifest, ...keys) {
|
|
332421
332458
|
for (const key3 of keys) {
|
|
@@ -332426,7 +332463,7 @@ function manifestComponentPaths(root2, manifest, ...keys) {
|
|
|
332426
332463
|
function discoverComponentFiles(root2, relativeDirs, extension, maxDepth = 2) {
|
|
332427
332464
|
const files = [];
|
|
332428
332465
|
for (const dir of relativeDirs) {
|
|
332429
|
-
files.push(...listFilesRecursive(
|
|
332466
|
+
files.push(...listFilesRecursive(path8.join(root2, dir), extension, maxDepth));
|
|
332430
332467
|
}
|
|
332431
332468
|
return Array.from(new Set(files)).sort();
|
|
332432
332469
|
}
|
|
@@ -332451,12 +332488,12 @@ function collectMcpServers(...values) {
|
|
|
332451
332488
|
function defaultComponentWarnings(kind, components) {
|
|
332452
332489
|
const warnings = [];
|
|
332453
332490
|
for (const item of components) {
|
|
332454
|
-
if (
|
|
332491
|
+
if (path8.isAbsolute(item) && !fs7.existsSync(item)) warnings.push(`${kind} path does not exist: ${item}`);
|
|
332455
332492
|
}
|
|
332456
332493
|
return warnings;
|
|
332457
332494
|
}
|
|
332458
332495
|
function normalizeCodexPlugin(root2, manifest) {
|
|
332459
|
-
const name50 = asString(manifest.name) ||
|
|
332496
|
+
const name50 = asString(manifest.name) || path8.basename(root2);
|
|
332460
332497
|
const components = {
|
|
332461
332498
|
skills: manifestComponentPaths(root2, manifest, "skills"),
|
|
332462
332499
|
agents: manifestComponentPaths(root2, manifest, "agents"),
|
|
@@ -332487,7 +332524,7 @@ function normalizeCodexPlugin(root2, manifest) {
|
|
|
332487
332524
|
};
|
|
332488
332525
|
}
|
|
332489
332526
|
function normalizeClaudePlugin(root2, manifest) {
|
|
332490
|
-
const name50 = asString(manifest.name) ||
|
|
332527
|
+
const name50 = asString(manifest.name) || path8.basename(root2);
|
|
332491
332528
|
const experimental = nestedRecord(manifest.experimental);
|
|
332492
332529
|
const components = {
|
|
332493
332530
|
skills: manifestComponentPaths(root2, manifest, "skills"),
|
|
@@ -332525,7 +332562,7 @@ function normalizeClaudePlugin(root2, manifest) {
|
|
|
332525
332562
|
};
|
|
332526
332563
|
}
|
|
332527
332564
|
function normalizeNewmarkPlugin(root2, manifest) {
|
|
332528
|
-
const name50 = asString(manifest.name) ||
|
|
332565
|
+
const name50 = asString(manifest.name) || path8.basename(root2);
|
|
332529
332566
|
return {
|
|
332530
332567
|
id: `newmark:${name50}`,
|
|
332531
332568
|
ecosystem: "newmark",
|
|
@@ -332554,7 +332591,7 @@ function findPluginRoots(root2, maxDepth = 5) {
|
|
|
332554
332591
|
if (depth > maxDepth) return;
|
|
332555
332592
|
let entries;
|
|
332556
332593
|
try {
|
|
332557
|
-
entries =
|
|
332594
|
+
entries = fs7.readdirSync(dir, { withFileTypes: true });
|
|
332558
332595
|
} catch {
|
|
332559
332596
|
return;
|
|
332560
332597
|
}
|
|
@@ -332563,7 +332600,7 @@ function findPluginRoots(root2, maxDepth = 5) {
|
|
|
332563
332600
|
}
|
|
332564
332601
|
for (const entry of entries) {
|
|
332565
332602
|
if (!entry.isDirectory() || skip.has(entry.name) || entry.name.startsWith("release.locked-")) continue;
|
|
332566
|
-
walk4(
|
|
332603
|
+
walk4(path8.join(dir, entry.name), depth + 1);
|
|
332567
332604
|
}
|
|
332568
332605
|
};
|
|
332569
332606
|
walk4(root2, 0);
|
|
@@ -332572,20 +332609,20 @@ function findPluginRoots(root2, maxDepth = 5) {
|
|
|
332572
332609
|
function discoverPluginManifests(root2) {
|
|
332573
332610
|
const manifests = [];
|
|
332574
332611
|
for (const pluginRoot of findPluginRoots(root2)) {
|
|
332575
|
-
const codexPath =
|
|
332576
|
-
const claudePath =
|
|
332577
|
-
const newmarkPath =
|
|
332578
|
-
const codex =
|
|
332579
|
-
const claude =
|
|
332580
|
-
const newmark =
|
|
332612
|
+
const codexPath = path8.join(pluginRoot, ".codex-plugin", "plugin.json");
|
|
332613
|
+
const claudePath = path8.join(pluginRoot, ".claude-plugin", "plugin.json");
|
|
332614
|
+
const newmarkPath = path8.join(pluginRoot, ".newmark-plugin", "plugin.json");
|
|
332615
|
+
const codex = fs7.existsSync(codexPath) ? readJson(codexPath) : null;
|
|
332616
|
+
const claude = fs7.existsSync(claudePath) ? readJson(claudePath) : null;
|
|
332617
|
+
const newmark = fs7.existsSync(newmarkPath) ? readJson(newmarkPath) : null;
|
|
332581
332618
|
if (codex && typeof codex === "object") manifests.push(normalizeCodexPlugin(pluginRoot, codex));
|
|
332582
332619
|
if (claude && typeof claude === "object") manifests.push(normalizeClaudePlugin(pluginRoot, claude));
|
|
332583
332620
|
if (newmark && typeof newmark === "object") manifests.push(normalizeNewmarkPlugin(pluginRoot, newmark));
|
|
332584
332621
|
}
|
|
332585
332622
|
const projectOpencode = readOpenCodeManifest(root2, "project");
|
|
332586
332623
|
if (projectOpencode) manifests.push(projectOpencode);
|
|
332587
|
-
const userOpenCodeRoot =
|
|
332588
|
-
if (
|
|
332624
|
+
const userOpenCodeRoot = path8.join(os2.homedir(), ".config", "opencode");
|
|
332625
|
+
if (path8.resolve(userOpenCodeRoot) !== path8.resolve(path8.join(root2, ".opencode"))) {
|
|
332589
332626
|
const userOpenCode = readOpenCodeManifest(userOpenCodeRoot, "user");
|
|
332590
332627
|
if (userOpenCode) manifests.push(userOpenCode);
|
|
332591
332628
|
}
|
|
@@ -332593,20 +332630,20 @@ function discoverPluginManifests(root2) {
|
|
|
332593
332630
|
}
|
|
332594
332631
|
function readOpenCodeConfig(root2) {
|
|
332595
332632
|
const candidates = [
|
|
332596
|
-
|
|
332597
|
-
|
|
332598
|
-
|
|
332599
|
-
|
|
332633
|
+
path8.join(root2, "opencode.json"),
|
|
332634
|
+
path8.join(root2, "opencode.jsonc"),
|
|
332635
|
+
path8.join(root2, ".opencode", "opencode.json"),
|
|
332636
|
+
path8.join(root2, ".opencode", "opencode.jsonc")
|
|
332600
332637
|
];
|
|
332601
332638
|
for (const filePath of candidates) {
|
|
332602
|
-
if (
|
|
332639
|
+
if (fs7.existsSync(filePath)) return { path: filePath, value: readJsonLoose(filePath) };
|
|
332603
332640
|
}
|
|
332604
332641
|
return null;
|
|
332605
332642
|
}
|
|
332606
332643
|
function readOpenCodeManifest(root2, scope) {
|
|
332607
|
-
const localRoot = scope === "project" ?
|
|
332608
|
-
const opencodeToolsDir =
|
|
332609
|
-
const opencodePluginsDir =
|
|
332644
|
+
const localRoot = scope === "project" ? path8.join(root2, ".opencode") : root2;
|
|
332645
|
+
const opencodeToolsDir = path8.join(localRoot, "tools");
|
|
332646
|
+
const opencodePluginsDir = path8.join(localRoot, "plugins");
|
|
332610
332647
|
const tools = listCodeFiles(opencodeToolsDir);
|
|
332611
332648
|
const pluginFiles = listCodeFiles(opencodePluginsDir);
|
|
332612
332649
|
const config = readOpenCodeConfig(root2);
|
|
@@ -332647,18 +332684,18 @@ function readOpenCodeManifest(root2, scope) {
|
|
|
332647
332684
|
}
|
|
332648
332685
|
function discoverOpenCodeInstructionFiles(projectRoot, localRoot) {
|
|
332649
332686
|
const candidates = [
|
|
332650
|
-
|
|
332651
|
-
|
|
332652
|
-
|
|
332653
|
-
|
|
332654
|
-
|
|
332687
|
+
path8.join(projectRoot, "AGENTS.md"),
|
|
332688
|
+
path8.join(projectRoot, ".opencode", "instructions.md"),
|
|
332689
|
+
path8.join(projectRoot, ".opencode", "AGENTS.md"),
|
|
332690
|
+
path8.join(localRoot, "instructions.md"),
|
|
332691
|
+
path8.join(localRoot, "AGENTS.md")
|
|
332655
332692
|
];
|
|
332656
|
-
return Array.from(new Set(candidates.filter((filePath) =>
|
|
332693
|
+
return Array.from(new Set(candidates.filter((filePath) => fs7.existsSync(filePath)))).sort();
|
|
332657
332694
|
}
|
|
332658
332695
|
function dedupeManifests(manifests) {
|
|
332659
332696
|
const seen = /* @__PURE__ */ new Set();
|
|
332660
332697
|
return manifests.filter((item) => {
|
|
332661
|
-
const key3 = `${item.id}:${
|
|
332698
|
+
const key3 = `${item.id}:${path8.resolve(item.root)}`;
|
|
332662
332699
|
if (seen.has(key3)) return false;
|
|
332663
332700
|
seen.add(key3);
|
|
332664
332701
|
return true;
|
|
@@ -332666,14 +332703,14 @@ function dedupeManifests(manifests) {
|
|
|
332666
332703
|
}
|
|
332667
332704
|
function listCodeFiles(dir) {
|
|
332668
332705
|
try {
|
|
332669
|
-
return
|
|
332706
|
+
return fs7.readdirSync(dir, { withFileTypes: true }).filter((e3) => e3.isFile() && /\.(?:c?js|mjs|ts)$/.test(e3.name)).map((e3) => path8.join(dir, e3.name)).sort();
|
|
332670
332707
|
} catch {
|
|
332671
332708
|
return [];
|
|
332672
332709
|
}
|
|
332673
332710
|
}
|
|
332674
332711
|
function parseFrontmatterMarkdown(filePath) {
|
|
332675
332712
|
try {
|
|
332676
|
-
const content =
|
|
332713
|
+
const content = fs7.readFileSync(filePath, "utf-8").replace(/^\uFEFF/, "");
|
|
332677
332714
|
const match = content.match(/^---\s*([\s\S]*?)\s*---\s*/);
|
|
332678
332715
|
if (!match) return { metadata: {}, body: content };
|
|
332679
332716
|
const metadata = {};
|
|
@@ -332702,7 +332739,7 @@ function parseMetadataValue(raw) {
|
|
|
332702
332739
|
function parseSimpleToml(filePath) {
|
|
332703
332740
|
try {
|
|
332704
332741
|
const metadata = {};
|
|
332705
|
-
const content =
|
|
332742
|
+
const content = fs7.readFileSync(filePath, "utf-8").replace(/^\uFEFF/, "");
|
|
332706
332743
|
const multiline = null;
|
|
332707
332744
|
if (multiline) return metadata;
|
|
332708
332745
|
const lines = content.split(/\r?\n/);
|
|
@@ -332736,7 +332773,7 @@ function parseSimpleToml(filePath) {
|
|
|
332736
332773
|
}
|
|
332737
332774
|
}
|
|
332738
332775
|
function agentPresetFromMetadata(filePath, ecosystem, metadata, body = "") {
|
|
332739
|
-
const name50 = asString(metadata.name) ||
|
|
332776
|
+
const name50 = asString(metadata.name) || path8.basename(filePath).replace(/\.(?:toml|md)$/i, "");
|
|
332740
332777
|
const description = asString(metadata.description);
|
|
332741
332778
|
const instructions = asString(metadata.developer_instructions || metadata.instructions || metadata.prompt) || body.trim();
|
|
332742
332779
|
if (!name50 || !description) return null;
|
|
@@ -332764,12 +332801,12 @@ function listFilesRecursive(root2, extension, maxDepth = 4) {
|
|
|
332764
332801
|
if (depth > maxDepth) return;
|
|
332765
332802
|
let entries;
|
|
332766
332803
|
try {
|
|
332767
|
-
entries =
|
|
332804
|
+
entries = fs7.readdirSync(dir, { withFileTypes: true });
|
|
332768
332805
|
} catch {
|
|
332769
332806
|
return;
|
|
332770
332807
|
}
|
|
332771
332808
|
for (const entry of entries) {
|
|
332772
|
-
const full =
|
|
332809
|
+
const full = path8.join(dir, entry.name);
|
|
332773
332810
|
if (entry.isFile() && extension.test(entry.name)) results.push(full);
|
|
332774
332811
|
if (entry.isDirectory() && !entry.name.startsWith(".git") && entry.name !== "node_modules") walk4(full, depth + 1);
|
|
332775
332812
|
}
|
|
@@ -332780,10 +332817,10 @@ function listFilesRecursive(root2, extension, maxDepth = 4) {
|
|
|
332780
332817
|
function discoverAgentPresets(root2) {
|
|
332781
332818
|
const presets = [];
|
|
332782
332819
|
const codexDirs = [
|
|
332783
|
-
|
|
332784
|
-
|
|
332785
|
-
|
|
332786
|
-
|
|
332820
|
+
path8.join(root2, ".codex", "agents"),
|
|
332821
|
+
path8.join(root2, ".agents", "agents"),
|
|
332822
|
+
path8.join(os2.homedir(), ".codex", "agents"),
|
|
332823
|
+
path8.join(os2.homedir(), ".agents", "agents")
|
|
332787
332824
|
];
|
|
332788
332825
|
for (const dir of codexDirs) {
|
|
332789
332826
|
for (const filePath of listFilesRecursive(dir, /\.toml$/i, 1)) {
|
|
@@ -332792,14 +332829,14 @@ function discoverAgentPresets(root2) {
|
|
|
332792
332829
|
}
|
|
332793
332830
|
}
|
|
332794
332831
|
const claudeDirs = [
|
|
332795
|
-
|
|
332796
|
-
|
|
332797
|
-
|
|
332832
|
+
path8.join(root2, ".claude", "agents"),
|
|
332833
|
+
path8.join(os2.homedir(), ".claude", "agents"),
|
|
332834
|
+
path8.join(os2.homedir(), ".config", "opencode", "agents")
|
|
332798
332835
|
];
|
|
332799
332836
|
for (const dir of claudeDirs) {
|
|
332800
332837
|
for (const filePath of listFilesRecursive(dir, /\.md$/i, 1)) {
|
|
332801
332838
|
const parsed = parseFrontmatterMarkdown(filePath);
|
|
332802
|
-
const ecosystem = filePath.includes(`${
|
|
332839
|
+
const ecosystem = filePath.includes(`${path8.sep}.config${path8.sep}opencode${path8.sep}`) ? "opencode" : "claude-code";
|
|
332803
332840
|
const preset = agentPresetFromMetadata(filePath, ecosystem, parsed.metadata, parsed.body);
|
|
332804
332841
|
if (preset) presets.push(preset);
|
|
332805
332842
|
}
|
|
@@ -332836,15 +332873,15 @@ function findAgentPreset(root2, selector2) {
|
|
|
332836
332873
|
preset.id,
|
|
332837
332874
|
preset.name,
|
|
332838
332875
|
`${preset.ecosystem}:${preset.name}`,
|
|
332839
|
-
|
|
332876
|
+
path8.basename(preset.path)
|
|
332840
332877
|
].map((value) => String(value || "").toLowerCase());
|
|
332841
|
-
return keys.includes(normalized) ||
|
|
332878
|
+
return keys.includes(normalized) || path8.resolve(preset.path).toLowerCase() === path8.resolve(wanted).toLowerCase();
|
|
332842
332879
|
}) || null;
|
|
332843
332880
|
}
|
|
332844
332881
|
|
|
332845
332882
|
// src/tools/terminalTakeover.ts
|
|
332846
|
-
var
|
|
332847
|
-
var
|
|
332883
|
+
var fs8 = __toESM(require("fs"));
|
|
332884
|
+
var path9 = __toESM(require("path"));
|
|
332848
332885
|
var import_child_process2 = require("child_process");
|
|
332849
332886
|
var import_crypto5 = require("crypto");
|
|
332850
332887
|
var ROOT_TERMINAL_ACTOR_ID = "00000000-0000-4000-8000-000000000001";
|
|
@@ -332859,7 +332896,7 @@ function isoNow() {
|
|
|
332859
332896
|
return (/* @__PURE__ */ new Date()).toISOString();
|
|
332860
332897
|
}
|
|
332861
332898
|
function canonicalPersistenceRoot(root2) {
|
|
332862
|
-
const resolved =
|
|
332899
|
+
const resolved = path9.resolve(root2 || process.cwd());
|
|
332863
332900
|
return process.platform === "win32" ? resolved.toLowerCase() : resolved;
|
|
332864
332901
|
}
|
|
332865
332902
|
function portableWorkspacePath(input2) {
|
|
@@ -332868,7 +332905,7 @@ function portableWorkspacePath(input2) {
|
|
|
332868
332905
|
if (wsl) return `${wsl[1].toLowerCase()}:/${String(wsl[2] || "").replace(/^\/+|\/+$/g, "")}`.replace(/\/$/, "");
|
|
332869
332906
|
const drive = /^([a-zA-Z]):(?:\/(.*))?$/.exec(raw);
|
|
332870
332907
|
if (drive) return `${drive[1].toLowerCase()}:/${String(drive[2] || "").replace(/^\/+|\/+$/g, "")}`.replace(/\/$/, "");
|
|
332871
|
-
const resolved =
|
|
332908
|
+
const resolved = path9.resolve(raw).replace(/\\/g, "/").replace(/\/+$/g, "");
|
|
332872
332909
|
return process.platform === "win32" ? resolved.toLowerCase() : resolved;
|
|
332873
332910
|
}
|
|
332874
332911
|
function terminalTakeoverWorkspaceId(workspacePath) {
|
|
@@ -332963,12 +333000,12 @@ function nodePtyHasConptyDll() {
|
|
|
332963
333000
|
if (process.platform !== "win32") return false;
|
|
332964
333001
|
try {
|
|
332965
333002
|
const packageJson = require.resolve("node-pty/package.json");
|
|
332966
|
-
const packageRoot =
|
|
333003
|
+
const packageRoot = path9.dirname(packageJson);
|
|
332967
333004
|
return [
|
|
332968
|
-
|
|
332969
|
-
|
|
332970
|
-
|
|
332971
|
-
].some((candidate) =>
|
|
333005
|
+
path9.join(packageRoot, "build", "Release", "conpty", "conpty.dll"),
|
|
333006
|
+
path9.join(packageRoot, "build", "Debug", "conpty", "conpty.dll"),
|
|
333007
|
+
path9.join(packageRoot, "prebuilds", `${process.platform}-${process.arch}`, "conpty", "conpty.dll")
|
|
333008
|
+
].some((candidate) => fs8.existsSync(candidate));
|
|
332972
333009
|
} catch {
|
|
332973
333010
|
return false;
|
|
332974
333011
|
}
|
|
@@ -333201,7 +333238,7 @@ function spawnTakeoverPty(shell, cwd, env, cols, rows) {
|
|
|
333201
333238
|
};
|
|
333202
333239
|
}
|
|
333203
333240
|
function persistencePath(root2) {
|
|
333204
|
-
return
|
|
333241
|
+
return path9.join(root2, "Terminal", "Takeover.json");
|
|
333205
333242
|
}
|
|
333206
333243
|
function validPersistedRecord(input2) {
|
|
333207
333244
|
if (!input2 || typeof input2 !== "object") return null;
|
|
@@ -333242,7 +333279,7 @@ function ensurePersistenceLoaded(rootRaw) {
|
|
|
333242
333279
|
if (loaded) return loaded;
|
|
333243
333280
|
const records = /* @__PURE__ */ new Map();
|
|
333244
333281
|
try {
|
|
333245
|
-
const parsed = JSON.parse(
|
|
333282
|
+
const parsed = JSON.parse(fs8.readFileSync(persistencePath(root2), "utf-8"));
|
|
333246
333283
|
if (Array.isArray(parsed.records)) {
|
|
333247
333284
|
for (const input2 of parsed.records) {
|
|
333248
333285
|
const record = validPersistedRecord(input2);
|
|
@@ -333260,19 +333297,19 @@ function persistEndedRecords(rootRaw) {
|
|
|
333260
333297
|
const output = { version: 1, updatedAt: isoNow(), records };
|
|
333261
333298
|
const filePath = persistencePath(root2);
|
|
333262
333299
|
const tempPath = `${filePath}.tmp-${process.pid}-${(0, import_crypto5.randomUUID)()}`;
|
|
333263
|
-
|
|
333264
|
-
const fd =
|
|
333300
|
+
fs8.mkdirSync(path9.dirname(filePath), { recursive: true });
|
|
333301
|
+
const fd = fs8.openSync(tempPath, "w");
|
|
333265
333302
|
try {
|
|
333266
|
-
|
|
333267
|
-
|
|
333303
|
+
fs8.writeFileSync(fd, JSON.stringify(output, null, 2), "utf-8");
|
|
333304
|
+
fs8.fsyncSync(fd);
|
|
333268
333305
|
} finally {
|
|
333269
|
-
|
|
333306
|
+
fs8.closeSync(fd);
|
|
333270
333307
|
}
|
|
333271
333308
|
try {
|
|
333272
|
-
|
|
333309
|
+
fs8.renameSync(tempPath, filePath);
|
|
333273
333310
|
} catch (error) {
|
|
333274
333311
|
try {
|
|
333275
|
-
|
|
333312
|
+
fs8.rmSync(tempPath, { force: true });
|
|
333276
333313
|
} catch {
|
|
333277
333314
|
}
|
|
333278
333315
|
throw error;
|
|
@@ -333505,8 +333542,8 @@ function runTerminalTakeover(input2) {
|
|
|
333505
333542
|
}
|
|
333506
333543
|
|
|
333507
333544
|
// src/tools/computerUse.ts
|
|
333508
|
-
var
|
|
333509
|
-
var
|
|
333545
|
+
var fs9 = __toESM(require("fs"));
|
|
333546
|
+
var path10 = __toESM(require("path"));
|
|
333510
333547
|
var crypto6 = __toESM(require("crypto"));
|
|
333511
333548
|
var os3 = __toESM(require("os"));
|
|
333512
333549
|
|
|
@@ -333714,8 +333751,8 @@ async function runPowerShell(script, timeout = 3e4, lane = "action") {
|
|
|
333714
333751
|
return await runPersistentPowerShell(script, timeout, lane);
|
|
333715
333752
|
}
|
|
333716
333753
|
function tempScreenshotDir() {
|
|
333717
|
-
const dir =
|
|
333718
|
-
|
|
333754
|
+
const dir = path10.join(os3.tmpdir(), "newmark-computer-use");
|
|
333755
|
+
fs9.mkdirSync(dir, { recursive: true });
|
|
333719
333756
|
const now2 = Date.now();
|
|
333720
333757
|
if (now2 - lastScreenshotCleanupAt >= SCREENSHOT_CLEANUP_INTERVAL_MS) {
|
|
333721
333758
|
lastScreenshotCleanupAt = now2;
|
|
@@ -333737,7 +333774,7 @@ function ephemeralScreenshotPath(kind, directory = tempScreenshotDir(), createdA
|
|
|
333737
333774
|
const pid = Math.max(1, Math.floor(Number(ownerPid) || process.pid));
|
|
333738
333775
|
const timestamp = Math.max(0, Math.floor(Number(createdAt) || Date.now()));
|
|
333739
333776
|
const nonce = /^[a-f0-9]{8}$/i.test(String(suffix)) ? String(suffix).toLowerCase() : crypto6.randomBytes(4).toString("hex");
|
|
333740
|
-
return
|
|
333777
|
+
return path10.join(directory, `${kind}-p${pid}-t${timestamp}-${nonce}.jpg`);
|
|
333741
333778
|
}
|
|
333742
333779
|
function isProcessAlive(pid) {
|
|
333743
333780
|
if (!Number.isSafeInteger(pid) || pid <= 0) return false;
|
|
@@ -333750,14 +333787,14 @@ function isProcessAlive(pid) {
|
|
|
333750
333787
|
}
|
|
333751
333788
|
}
|
|
333752
333789
|
function cleanupStaleScreenshots(options = {}) {
|
|
333753
|
-
const directory = options.directory ||
|
|
333790
|
+
const directory = options.directory || path10.join(os3.tmpdir(), "newmark-computer-use");
|
|
333754
333791
|
const now2 = Number.isFinite(Number(options.now)) ? Number(options.now) : Date.now();
|
|
333755
333792
|
const processAlive = options.isProcessAlive || isProcessAlive;
|
|
333756
333793
|
const ownedPattern = /^(?:observe|app)-p([1-9]\d*)-t(\d{10,16})-[a-f0-9]{8}\.jpg$/i;
|
|
333757
333794
|
const legacyPattern = /^(?:observe|app)-\d{4}-\d{2}-\d{2}T\d{2}-\d{2}-\d{2}-\d{3}Z-[a-f0-9]{8}\.jpg$/i;
|
|
333758
333795
|
let names = [];
|
|
333759
333796
|
try {
|
|
333760
|
-
names =
|
|
333797
|
+
names = fs9.readdirSync(directory);
|
|
333761
333798
|
} catch {
|
|
333762
333799
|
return { removed: 0 };
|
|
333763
333800
|
}
|
|
@@ -333766,10 +333803,10 @@ function cleanupStaleScreenshots(options = {}) {
|
|
|
333766
333803
|
const owned = ownedPattern.exec(name50);
|
|
333767
333804
|
const isLegacy = !owned && legacyPattern.test(name50);
|
|
333768
333805
|
if (!owned && !isLegacy) continue;
|
|
333769
|
-
const filePath =
|
|
333806
|
+
const filePath = path10.join(directory, name50);
|
|
333770
333807
|
let stats;
|
|
333771
333808
|
try {
|
|
333772
|
-
stats =
|
|
333809
|
+
stats = fs9.lstatSync(filePath);
|
|
333773
333810
|
if (!stats.isFile() || stats.isSymbolicLink()) continue;
|
|
333774
333811
|
} catch {
|
|
333775
333812
|
continue;
|
|
@@ -333793,7 +333830,7 @@ function cleanupStaleScreenshots(options = {}) {
|
|
|
333793
333830
|
}
|
|
333794
333831
|
if (!shouldRemove) continue;
|
|
333795
333832
|
try {
|
|
333796
|
-
|
|
333833
|
+
fs9.unlinkSync(filePath);
|
|
333797
333834
|
removed += 1;
|
|
333798
333835
|
} catch {
|
|
333799
333836
|
}
|
|
@@ -333816,7 +333853,7 @@ function captureBounds(maxWidth, maxHeight) {
|
|
|
333816
333853
|
}
|
|
333817
333854
|
function removeEphemeralScreenshot(outPath) {
|
|
333818
333855
|
try {
|
|
333819
|
-
|
|
333856
|
+
fs9.unlinkSync(outPath);
|
|
333820
333857
|
} catch {
|
|
333821
333858
|
}
|
|
333822
333859
|
}
|
|
@@ -333892,7 +333929,7 @@ async function startTakeoverOverlay(durationMs = 0, input2 = {}) {
|
|
|
333892
333929
|
const width = 2;
|
|
333893
333930
|
const speedSeconds = 3;
|
|
333894
333931
|
const ownerPid = Math.max(0, Math.floor(Number(input2.ownerPid ?? process.pid) || 0));
|
|
333895
|
-
const scriptPath =
|
|
333932
|
+
const scriptPath = path10.join(tempScreenshotDir(), `takeover-overlay-${timestampName()}-${crypto6.randomBytes(4).toString("hex")}.ps1`);
|
|
333896
333933
|
const script = [
|
|
333897
333934
|
"Add-Type -AssemblyName System.Windows.Forms",
|
|
333898
333935
|
"Add-Type -AssemblyName System.Drawing",
|
|
@@ -334031,7 +334068,7 @@ async function startTakeoverOverlay(durationMs = 0, input2 = {}) {
|
|
|
334031
334068
|
"[System.Windows.Forms.Application]::Run()",
|
|
334032
334069
|
"try { Remove-Item -LiteralPath $PSCommandPath -Force -ErrorAction SilentlyContinue } catch {}"
|
|
334033
334070
|
].filter(Boolean).join("\r\n");
|
|
334034
|
-
|
|
334071
|
+
fs9.writeFileSync(scriptPath, `\uFEFF${script}`, "utf8");
|
|
334035
334072
|
const createCommand = [
|
|
334036
334073
|
`$cmd = 'powershell.exe -NoProfile -ExecutionPolicy Bypass -File ' + ${psQuote(`"${scriptPath}"`)}`,
|
|
334037
334074
|
`$startup = ([wmiclass]'Win32_ProcessStartup').CreateInstance()`,
|
|
@@ -334044,7 +334081,7 @@ async function startTakeoverOverlay(durationMs = 0, input2 = {}) {
|
|
|
334044
334081
|
const pid = Number(String(result.output || "").trim().split(/\r?\n/).pop() || 0);
|
|
334045
334082
|
if (!Number.isFinite(pid) || pid <= 0 || !result.ok) {
|
|
334046
334083
|
try {
|
|
334047
|
-
|
|
334084
|
+
fs9.unlinkSync(scriptPath);
|
|
334048
334085
|
} catch {
|
|
334049
334086
|
}
|
|
334050
334087
|
return { ok: false, action: "takeover_start", error: result.output || "Overlay failed to start." };
|
|
@@ -334071,7 +334108,7 @@ function parseJsonArray(text) {
|
|
|
334071
334108
|
return [];
|
|
334072
334109
|
}
|
|
334073
334110
|
function observationKey(workspacePath, ownerId) {
|
|
334074
|
-
return `${
|
|
334111
|
+
return `${path10.resolve(workspacePath || process.cwd()).toLowerCase()}::${String(ownerId || "direct")}`;
|
|
334075
334112
|
}
|
|
334076
334113
|
function sceneGeneration(apps, elements) {
|
|
334077
334114
|
const seed = [
|
|
@@ -334287,7 +334324,7 @@ async function cropScreenshot(workspacePath, ownerId, allowEphemeralVisionImage,
|
|
|
334287
334324
|
...parsed
|
|
334288
334325
|
};
|
|
334289
334326
|
if (includeRawUi) payload.perception.elements = elements;
|
|
334290
|
-
const imageAvailable = parsed.image_available === true &&
|
|
334327
|
+
const imageAvailable = parsed.image_available === true && fs9.existsSync(outPath);
|
|
334291
334328
|
if (allowEphemeralVisionImage && imageAvailable) {
|
|
334292
334329
|
payload.vision_image_path = outPath;
|
|
334293
334330
|
retainedForVision = true;
|
|
@@ -334550,7 +334587,7 @@ async function screenshot(workspacePath, ownerId, allowEphemeralVisionImage, inc
|
|
|
334550
334587
|
...parsed
|
|
334551
334588
|
};
|
|
334552
334589
|
if (includeRawUi) payload.perception.elements = ui.elements;
|
|
334553
|
-
const imageAvailable = parsed.image_available === true &&
|
|
334590
|
+
const imageAvailable = parsed.image_available === true && fs9.existsSync(outPath);
|
|
334554
334591
|
if (allowEphemeralVisionImage && imageAvailable) {
|
|
334555
334592
|
payload.vision_image_path = outPath;
|
|
334556
334593
|
retainedForVision = true;
|
|
@@ -334874,13 +334911,13 @@ async function runComputerUse(options) {
|
|
|
334874
334911
|
}
|
|
334875
334912
|
|
|
334876
334913
|
// src/core/ssh.ts
|
|
334877
|
-
var
|
|
334878
|
-
var
|
|
334914
|
+
var fs11 = __toESM(require("fs"));
|
|
334915
|
+
var path12 = __toESM(require("path"));
|
|
334879
334916
|
|
|
334880
334917
|
// src/core/asyncProcess.ts
|
|
334881
334918
|
var import_child_process4 = require("child_process");
|
|
334882
|
-
var
|
|
334883
|
-
var
|
|
334919
|
+
var fs10 = __toESM(require("fs/promises"));
|
|
334920
|
+
var path11 = __toESM(require("path"));
|
|
334884
334921
|
var STOP_SETTLEMENT_WATCHDOG_MS = 500;
|
|
334885
334922
|
function signalMessage(signal) {
|
|
334886
334923
|
const reason = signal?.reason;
|
|
@@ -334890,7 +334927,7 @@ function signalMessage(signal) {
|
|
|
334890
334927
|
}
|
|
334891
334928
|
function trustedWindowsTaskkillPath() {
|
|
334892
334929
|
const windowsRoot = String(process.env.SystemRoot || process.env.WINDIR || "C:\\Windows");
|
|
334893
|
-
return
|
|
334930
|
+
return path11.join(windowsRoot, "System32", "taskkill.exe");
|
|
334894
334931
|
}
|
|
334895
334932
|
function stopProcessTree(child) {
|
|
334896
334933
|
const pid = child.pid;
|
|
@@ -335059,7 +335096,7 @@ async function runAsyncWindowsBatch(command, args, options = {}) {
|
|
|
335059
335096
|
}
|
|
335060
335097
|
async function accessible(filePath) {
|
|
335061
335098
|
try {
|
|
335062
|
-
await
|
|
335099
|
+
await fs10.access(filePath);
|
|
335063
335100
|
return true;
|
|
335064
335101
|
} catch {
|
|
335065
335102
|
return false;
|
|
@@ -335068,14 +335105,14 @@ async function accessible(filePath) {
|
|
|
335068
335105
|
async function resolveWindowsLauncher(command) {
|
|
335069
335106
|
const clean = String(command || "").trim();
|
|
335070
335107
|
if (!clean) return "";
|
|
335071
|
-
if (
|
|
335072
|
-
const absolute =
|
|
335108
|
+
if (path11.isAbsolute(clean) || /[\\/]/.test(clean)) {
|
|
335109
|
+
const absolute = path11.resolve(clean);
|
|
335073
335110
|
return await accessible(absolute) ? absolute : "";
|
|
335074
335111
|
}
|
|
335075
|
-
for (const entry of String(process.env.PATH || "").split(
|
|
335112
|
+
for (const entry of String(process.env.PATH || "").split(path11.delimiter)) {
|
|
335076
335113
|
const directory = entry.trim().replace(/^"|"$/g, "");
|
|
335077
335114
|
if (!directory) continue;
|
|
335078
|
-
const candidate =
|
|
335115
|
+
const candidate = path11.join(directory, clean);
|
|
335079
335116
|
if (await accessible(candidate)) return candidate;
|
|
335080
335117
|
}
|
|
335081
335118
|
return "";
|
|
@@ -335083,11 +335120,11 @@ async function resolveWindowsLauncher(command) {
|
|
|
335083
335120
|
async function resolveNpmBatchTarget(batchPath) {
|
|
335084
335121
|
let source = "";
|
|
335085
335122
|
try {
|
|
335086
|
-
source = await
|
|
335123
|
+
source = await fs10.readFile(batchPath, "utf8");
|
|
335087
335124
|
} catch {
|
|
335088
335125
|
return null;
|
|
335089
335126
|
}
|
|
335090
|
-
const directory =
|
|
335127
|
+
const directory = path11.dirname(batchPath);
|
|
335091
335128
|
let relativeScript = "";
|
|
335092
335129
|
const direct = /(?:%~dp0|%dp0%)\\?([^"\r\n]+)"\s+%\*/i.exec(source);
|
|
335093
335130
|
if (direct) relativeScript = direct[1];
|
|
@@ -335101,10 +335138,10 @@ async function resolveNpmBatchTarget(batchPath) {
|
|
|
335101
335138
|
}
|
|
335102
335139
|
}
|
|
335103
335140
|
if (!relativeScript) return null;
|
|
335104
|
-
const scriptPath =
|
|
335105
|
-
const directoryPrefix = `${
|
|
335141
|
+
const scriptPath = path11.resolve(directory, relativeScript.replace(/\\/g, path11.sep));
|
|
335142
|
+
const directoryPrefix = `${path11.resolve(directory).toLowerCase()}${path11.sep}`;
|
|
335106
335143
|
if (!scriptPath.toLowerCase().startsWith(directoryPrefix) || !await accessible(scriptPath)) return null;
|
|
335107
|
-
const siblingNode =
|
|
335144
|
+
const siblingNode = path11.join(directory, "node.exe");
|
|
335108
335145
|
const nodePath = await accessible(siblingNode) ? siblingNode : await resolveWindowsLauncher("node.exe") || await resolveWindowsLauncher("node");
|
|
335109
335146
|
return nodePath ? { nodePath, scriptPath } : null;
|
|
335110
335147
|
}
|
|
@@ -335147,19 +335184,19 @@ var SshManager = class {
|
|
|
335147
335184
|
rootPath;
|
|
335148
335185
|
runner;
|
|
335149
335186
|
storePath() {
|
|
335150
|
-
return
|
|
335187
|
+
return path12.join(this.rootPath, "Work", "SSH.json");
|
|
335151
335188
|
}
|
|
335152
335189
|
ensureStore() {
|
|
335153
335190
|
try {
|
|
335154
|
-
|
|
335155
|
-
if (!
|
|
335191
|
+
fs11.mkdirSync(path12.join(this.rootPath, "Work"), { recursive: true });
|
|
335192
|
+
if (!fs11.existsSync(this.storePath())) fs11.writeFileSync(this.storePath(), "[]", "utf-8");
|
|
335156
335193
|
} catch {
|
|
335157
335194
|
}
|
|
335158
335195
|
}
|
|
335159
335196
|
readRaw() {
|
|
335160
335197
|
this.ensureStore();
|
|
335161
335198
|
try {
|
|
335162
|
-
const parsed = JSON.parse(
|
|
335199
|
+
const parsed = JSON.parse(fs11.readFileSync(this.storePath(), "utf-8").replace(/^\uFEFF/, ""));
|
|
335163
335200
|
if (!Array.isArray(parsed)) return [];
|
|
335164
335201
|
return parsed.map((item) => this.normalize(item)).filter((item) => !!item);
|
|
335165
335202
|
} catch {
|
|
@@ -335168,7 +335205,7 @@ var SshManager = class {
|
|
|
335168
335205
|
}
|
|
335169
335206
|
writeRaw(items) {
|
|
335170
335207
|
this.ensureStore();
|
|
335171
|
-
|
|
335208
|
+
fs11.writeFileSync(this.storePath(), JSON.stringify(items, null, 2), "utf-8");
|
|
335172
335209
|
}
|
|
335173
335210
|
normalize(raw) {
|
|
335174
335211
|
if (!raw || typeof raw !== "object" || Array.isArray(raw)) return null;
|
|
@@ -335348,8 +335385,8 @@ var SshManager = class {
|
|
|
335348
335385
|
};
|
|
335349
335386
|
|
|
335350
335387
|
// src/core/workspace.ts
|
|
335351
|
-
var
|
|
335352
|
-
var
|
|
335388
|
+
var fs12 = __toESM(require("fs"));
|
|
335389
|
+
var path13 = __toESM(require("path"));
|
|
335353
335390
|
var crypto7 = __toESM(require("crypto"));
|
|
335354
335391
|
function lastEmbeddedWindowsPath(input2) {
|
|
335355
335392
|
const matcher = /[A-Za-z]:[\\/]/g;
|
|
@@ -335368,22 +335405,22 @@ function normalizeHostWorkspacePath(input2, platform = process.platform) {
|
|
|
335368
335405
|
const raw = String(input2 || "").trim();
|
|
335369
335406
|
const embeddedWindowsPath = lastEmbeddedWindowsPath(raw);
|
|
335370
335407
|
if (platform === "win32") {
|
|
335371
|
-
if (embeddedWindowsPath) return
|
|
335408
|
+
if (embeddedWindowsPath) return path13.win32.normalize(embeddedWindowsPath.replace(/\//g, "\\"));
|
|
335372
335409
|
const wsl = /^\/mnt\/([a-zA-Z])(?:\/(.*))?$/.exec(raw.replace(/\\/g, "/"));
|
|
335373
|
-
if (wsl) return
|
|
335374
|
-
return
|
|
335410
|
+
if (wsl) return path13.win32.normalize(`${wsl[1].toUpperCase()}:\\${String(wsl[2] || "").replace(/\//g, "\\")}`);
|
|
335411
|
+
return path13.win32.resolve(raw || ".");
|
|
335375
335412
|
}
|
|
335376
335413
|
if (platform === "linux" && embeddedWindowsPath) {
|
|
335377
335414
|
const drive = embeddedWindowsPath[0].toLowerCase();
|
|
335378
335415
|
const rest = embeddedWindowsPath.slice(3).replace(/\\/g, "/").replace(/^\/+/, "");
|
|
335379
|
-
return
|
|
335416
|
+
return path13.posix.resolve(`/mnt/${drive}/${rest}`);
|
|
335380
335417
|
}
|
|
335381
|
-
return
|
|
335418
|
+
return path13.posix.resolve(raw || ".");
|
|
335382
335419
|
}
|
|
335383
335420
|
function isPathInside(parent, child) {
|
|
335384
335421
|
try {
|
|
335385
|
-
const relative6 =
|
|
335386
|
-
return relative6 === "" || !!relative6 && !relative6.startsWith("..") && !
|
|
335422
|
+
const relative6 = path13.relative(path13.resolve(parent), path13.resolve(child));
|
|
335423
|
+
return relative6 === "" || !!relative6 && !relative6.startsWith("..") && !path13.isAbsolute(relative6);
|
|
335387
335424
|
} catch {
|
|
335388
335425
|
return false;
|
|
335389
335426
|
}
|
|
@@ -335391,7 +335428,7 @@ function isPathInside(parent, child) {
|
|
|
335391
335428
|
function isProtectedInstallWorkspacePath(candidate) {
|
|
335392
335429
|
const value = String(candidate || "").trim();
|
|
335393
335430
|
if (!value) return false;
|
|
335394
|
-
const roots = [
|
|
335431
|
+
const roots = [path13.dirname(process.execPath)];
|
|
335395
335432
|
if (process.platform === "win32") {
|
|
335396
335433
|
roots.push(
|
|
335397
335434
|
process.env.ProgramFiles || "",
|
|
@@ -335399,7 +335436,7 @@ function isProtectedInstallWorkspacePath(candidate) {
|
|
|
335399
335436
|
process.env.ProgramW6432 || ""
|
|
335400
335437
|
);
|
|
335401
335438
|
}
|
|
335402
|
-
const resolved =
|
|
335439
|
+
const resolved = path13.resolve(value);
|
|
335403
335440
|
return roots.filter(Boolean).some((root2) => isPathInside(root2, resolved));
|
|
335404
335441
|
}
|
|
335405
335442
|
var WorkspaceManager = class {
|
|
@@ -335409,16 +335446,16 @@ var WorkspaceManager = class {
|
|
|
335409
335446
|
this.detached = options.detached === true;
|
|
335410
335447
|
this.pcHash = this.loadPcHash();
|
|
335411
335448
|
if (this.detached) return;
|
|
335412
|
-
const workDir =
|
|
335449
|
+
const workDir = path13.join(rootPath, "Work");
|
|
335413
335450
|
try {
|
|
335414
|
-
|
|
335451
|
+
fs12.mkdirSync(workDir, { recursive: true });
|
|
335415
335452
|
} catch {
|
|
335416
335453
|
}
|
|
335417
335454
|
for (const fn of ["Local.json", "External.json"]) {
|
|
335418
|
-
const p =
|
|
335419
|
-
if (!
|
|
335455
|
+
const p = path13.join(workDir, fn);
|
|
335456
|
+
if (!fs12.existsSync(p)) {
|
|
335420
335457
|
try {
|
|
335421
|
-
|
|
335458
|
+
fs12.writeFileSync(p, "[]", "utf-8");
|
|
335422
335459
|
} catch {
|
|
335423
335460
|
}
|
|
335424
335461
|
}
|
|
@@ -335439,7 +335476,7 @@ var WorkspaceManager = class {
|
|
|
335439
335476
|
detached;
|
|
335440
335477
|
loadPcHash() {
|
|
335441
335478
|
try {
|
|
335442
|
-
const h2 =
|
|
335479
|
+
const h2 = fs12.readFileSync(path13.join(this.rootPath, "PC_Hash.config"), "utf-8");
|
|
335443
335480
|
return h2.trim();
|
|
335444
335481
|
} catch {
|
|
335445
335482
|
return "";
|
|
@@ -335454,19 +335491,19 @@ var WorkspaceManager = class {
|
|
|
335454
335491
|
if (this.external.length !== before) this.saveExternal();
|
|
335455
335492
|
}
|
|
335456
335493
|
scan() {
|
|
335457
|
-
const w =
|
|
335458
|
-
if (!
|
|
335494
|
+
const w = path13.join(this.rootPath, "Work");
|
|
335495
|
+
if (!fs12.existsSync(w)) return;
|
|
335459
335496
|
let internalChanged = false;
|
|
335460
335497
|
let externalChanged = false;
|
|
335461
335498
|
try {
|
|
335462
|
-
const local = JSON.parse(
|
|
335499
|
+
const local = JSON.parse(fs12.readFileSync(path13.join(w, "Local.json"), "utf-8"));
|
|
335463
335500
|
this.internal = Array.isArray(local) ? local.map((item) => this.normalizeInternalWorkspace(item, (changed) => {
|
|
335464
335501
|
internalChanged = internalChanged || changed;
|
|
335465
335502
|
})) : [];
|
|
335466
335503
|
} catch {
|
|
335467
335504
|
}
|
|
335468
335505
|
try {
|
|
335469
|
-
const ext = JSON.parse(
|
|
335506
|
+
const ext = JSON.parse(fs12.readFileSync(path13.join(w, "External.json"), "utf-8"));
|
|
335470
335507
|
const normalized = Array.isArray(ext) ? ext.map((item) => this.normalizeExternalWorkspace(item, (changed) => {
|
|
335471
335508
|
externalChanged = externalChanged || changed;
|
|
335472
335509
|
})) : [];
|
|
@@ -335477,13 +335514,13 @@ var WorkspaceManager = class {
|
|
|
335477
335514
|
});
|
|
335478
335515
|
} catch {
|
|
335479
335516
|
}
|
|
335480
|
-
for (const entry of
|
|
335517
|
+
for (const entry of fs12.readdirSync(w, { withFileTypes: true })) {
|
|
335481
335518
|
if (entry.isDirectory() && !["Local.json", "External.json", ".ssh"].includes(entry.name)) {
|
|
335482
335519
|
if (!this.internal.find((wi) => wi.name === entry.name)) {
|
|
335483
335520
|
this.internal.push({
|
|
335484
|
-
id: this.stableWorkspaceId("local",
|
|
335521
|
+
id: this.stableWorkspaceId("local", path13.join(w, entry.name)),
|
|
335485
335522
|
name: entry.name,
|
|
335486
|
-
path:
|
|
335523
|
+
path: path13.join(w, entry.name),
|
|
335487
335524
|
isInternal: true,
|
|
335488
335525
|
hostBinding: "",
|
|
335489
335526
|
icon: entry.name.charAt(0).toUpperCase()
|
|
@@ -335496,9 +335533,9 @@ var WorkspaceManager = class {
|
|
|
335496
335533
|
if (externalChanged) this.saveExternal();
|
|
335497
335534
|
}
|
|
335498
335535
|
normalizeInternalWorkspace(input2, markChanged) {
|
|
335499
|
-
const rawName = String(input2?.name ||
|
|
335536
|
+
const rawName = String(input2?.name || path13.basename(String(input2?.path || "")) || "").trim();
|
|
335500
335537
|
const name50 = rawName || (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "").replace("T", "_").slice(0, 15);
|
|
335501
|
-
const expectedPath =
|
|
335538
|
+
const expectedPath = path13.join(this.rootPath, "Work", name50);
|
|
335502
335539
|
const id = this.stableWorkspaceId("local", expectedPath);
|
|
335503
335540
|
if (normalizeHostWorkspacePath(String(input2?.path || "")) !== normalizeHostWorkspacePath(expectedPath) || input2?.isInternal !== true || input2?.id !== id) markChanged(true);
|
|
335504
335541
|
return {
|
|
@@ -335519,11 +335556,11 @@ var WorkspaceManager = class {
|
|
|
335519
335556
|
return {
|
|
335520
335557
|
...input2,
|
|
335521
335558
|
id,
|
|
335522
|
-
name: String(input2?.name ||
|
|
335559
|
+
name: String(input2?.name || path13.basename(workspacePath) || id),
|
|
335523
335560
|
path: workspacePath,
|
|
335524
335561
|
isInternal: false,
|
|
335525
335562
|
hostBinding: String(input2?.hostBinding || ""),
|
|
335526
|
-
icon: String(input2?.icon ||
|
|
335563
|
+
icon: String(input2?.icon || path13.basename(workspacePath).charAt(0).toUpperCase()),
|
|
335527
335564
|
kind
|
|
335528
335565
|
};
|
|
335529
335566
|
}
|
|
@@ -335544,11 +335581,11 @@ var WorkspaceManager = class {
|
|
|
335544
335581
|
const resolved = normalizeHostWorkspacePath(target);
|
|
335545
335582
|
let real = resolved;
|
|
335546
335583
|
try {
|
|
335547
|
-
real =
|
|
335584
|
+
real = fs12.existsSync(resolved) ? fs12.realpathSync.native(resolved) : resolved;
|
|
335548
335585
|
} catch {
|
|
335549
335586
|
real = resolved;
|
|
335550
335587
|
}
|
|
335551
|
-
const normalized =
|
|
335588
|
+
const normalized = path13.normalize(real).replace(/[\\/]+$/, "");
|
|
335552
335589
|
return process.platform === "win32" ? normalized.toLowerCase() : normalized;
|
|
335553
335590
|
}
|
|
335554
335591
|
stableWorkspaceId(kind, workspacePath) {
|
|
@@ -335574,8 +335611,8 @@ var WorkspaceManager = class {
|
|
|
335574
335611
|
isInsideRoot(target) {
|
|
335575
335612
|
const root2 = this.canonicalWorkspacePath(this.rootPath);
|
|
335576
335613
|
const candidate = this.canonicalWorkspacePath(target);
|
|
335577
|
-
const rel =
|
|
335578
|
-
return rel === "" || !!rel && !rel.startsWith("..") && !
|
|
335614
|
+
const rel = path13.relative(root2, candidate);
|
|
335615
|
+
return rel === "" || !!rel && !rel.startsWith("..") && !path13.isAbsolute(rel);
|
|
335579
335616
|
}
|
|
335580
335617
|
canonicalRemotePath(target) {
|
|
335581
335618
|
let cleaned = String(target || "").trim().replace(/\\/g, "/").replace(/\/+$/g, "");
|
|
@@ -335604,13 +335641,13 @@ var WorkspaceManager = class {
|
|
|
335604
335641
|
return deduped;
|
|
335605
335642
|
}
|
|
335606
335643
|
statePath() {
|
|
335607
|
-
return
|
|
335644
|
+
return path13.join(this.rootPath, "Work", "State.json");
|
|
335608
335645
|
}
|
|
335609
335646
|
readState() {
|
|
335610
335647
|
const p = this.statePath();
|
|
335611
|
-
if (!
|
|
335648
|
+
if (!fs12.existsSync(p)) return {};
|
|
335612
335649
|
try {
|
|
335613
|
-
const raw =
|
|
335650
|
+
const raw = fs12.readFileSync(p, "utf-8").replace(/^\uFEFF/, "");
|
|
335614
335651
|
const parsed = JSON.parse(raw);
|
|
335615
335652
|
if (parsed && typeof parsed === "object") return parsed;
|
|
335616
335653
|
} catch {
|
|
@@ -335631,8 +335668,8 @@ var WorkspaceManager = class {
|
|
|
335631
335668
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
335632
335669
|
};
|
|
335633
335670
|
try {
|
|
335634
|
-
|
|
335635
|
-
|
|
335671
|
+
fs12.mkdirSync(path13.dirname(p), { recursive: true });
|
|
335672
|
+
fs12.writeFileSync(p, JSON.stringify(state, null, 2), "utf-8");
|
|
335636
335673
|
} catch {
|
|
335637
335674
|
}
|
|
335638
335675
|
}
|
|
@@ -335691,17 +335728,17 @@ var WorkspaceManager = class {
|
|
|
335691
335728
|
}
|
|
335692
335729
|
saveInternal() {
|
|
335693
335730
|
if (this.detached) return;
|
|
335694
|
-
const p =
|
|
335731
|
+
const p = path13.join(this.rootPath, "Work", "Local.json");
|
|
335695
335732
|
this.internal = this.dedupeByPath(this.internal);
|
|
335696
335733
|
this.sortWorkspaces();
|
|
335697
|
-
|
|
335734
|
+
fs12.writeFileSync(p, JSON.stringify(this.internal, null, 2), "utf-8");
|
|
335698
335735
|
}
|
|
335699
335736
|
saveExternal() {
|
|
335700
335737
|
if (this.detached) return;
|
|
335701
|
-
const p =
|
|
335738
|
+
const p = path13.join(this.rootPath, "Work", "External.json");
|
|
335702
335739
|
this.external = this.dedupeByPath(this.external);
|
|
335703
335740
|
this.sortWorkspaces();
|
|
335704
|
-
|
|
335741
|
+
fs12.writeFileSync(p, JSON.stringify(this.external, null, 2), "utf-8");
|
|
335705
335742
|
}
|
|
335706
335743
|
sleepSync(ms) {
|
|
335707
335744
|
if (ms <= 0) return;
|
|
@@ -335709,48 +335746,48 @@ var WorkspaceManager = class {
|
|
|
335709
335746
|
Atomics.wait(new Int32Array(buffer), 0, 0, ms);
|
|
335710
335747
|
}
|
|
335711
335748
|
isInternalWorkspacePath(target) {
|
|
335712
|
-
const workRoot =
|
|
335713
|
-
const resolved =
|
|
335714
|
-
const rel =
|
|
335715
|
-
return !!rel && !rel.startsWith("..") && !
|
|
335749
|
+
const workRoot = path13.resolve(this.rootPath, "Work");
|
|
335750
|
+
const resolved = path13.resolve(target);
|
|
335751
|
+
const rel = path13.relative(workRoot, resolved);
|
|
335752
|
+
return !!rel && !rel.startsWith("..") && !path13.isAbsolute(rel);
|
|
335716
335753
|
}
|
|
335717
335754
|
clearReadOnlyRecursive(target) {
|
|
335718
|
-
if (!
|
|
335719
|
-
const stat =
|
|
335755
|
+
if (!fs12.existsSync(target)) return;
|
|
335756
|
+
const stat = fs12.lstatSync(target);
|
|
335720
335757
|
try {
|
|
335721
|
-
|
|
335758
|
+
fs12.chmodSync(target, stat.mode | 448);
|
|
335722
335759
|
} catch {
|
|
335723
335760
|
}
|
|
335724
335761
|
if (!stat.isDirectory()) return;
|
|
335725
|
-
for (const entry of
|
|
335726
|
-
this.clearReadOnlyRecursive(
|
|
335762
|
+
for (const entry of fs12.readdirSync(target)) {
|
|
335763
|
+
this.clearReadOnlyRecursive(path13.join(target, entry));
|
|
335727
335764
|
}
|
|
335728
335765
|
}
|
|
335729
335766
|
removeInternalDirectory(target) {
|
|
335730
|
-
const resolved =
|
|
335767
|
+
const resolved = path13.resolve(target);
|
|
335731
335768
|
if (!this.isInternalWorkspacePath(resolved)) return false;
|
|
335732
|
-
if (!
|
|
335769
|
+
if (!fs12.existsSync(resolved)) return true;
|
|
335733
335770
|
const delays = [0, 50, 100, 200, 400, 800, 1200];
|
|
335734
335771
|
for (const delay of delays) {
|
|
335735
335772
|
this.sleepSync(delay);
|
|
335736
335773
|
try {
|
|
335737
|
-
|
|
335774
|
+
fs12.rmSync(resolved, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 });
|
|
335738
335775
|
} catch {
|
|
335739
335776
|
}
|
|
335740
|
-
if (!
|
|
335777
|
+
if (!fs12.existsSync(resolved)) return true;
|
|
335741
335778
|
try {
|
|
335742
335779
|
this.clearReadOnlyRecursive(resolved);
|
|
335743
|
-
|
|
335780
|
+
fs12.rmSync(resolved, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 });
|
|
335744
335781
|
} catch {
|
|
335745
335782
|
}
|
|
335746
|
-
if (!
|
|
335783
|
+
if (!fs12.existsSync(resolved)) return true;
|
|
335747
335784
|
}
|
|
335748
335785
|
return false;
|
|
335749
335786
|
}
|
|
335750
335787
|
createInternal(name50) {
|
|
335751
335788
|
const n3 = name50 || (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "").replace("T", "_").slice(0, 15);
|
|
335752
|
-
const d3 =
|
|
335753
|
-
|
|
335789
|
+
const d3 = path13.join(this.rootPath, "Work", n3);
|
|
335790
|
+
fs12.mkdirSync(d3, { recursive: true });
|
|
335754
335791
|
const existing = this.findWorkspaceByPath(d3);
|
|
335755
335792
|
if (existing) {
|
|
335756
335793
|
this.current = existing;
|
|
@@ -335772,15 +335809,15 @@ var WorkspaceManager = class {
|
|
|
335772
335809
|
return ws;
|
|
335773
335810
|
}
|
|
335774
335811
|
addExternal(p) {
|
|
335775
|
-
const resolved =
|
|
335776
|
-
if (!
|
|
335812
|
+
const resolved = path13.resolve(p);
|
|
335813
|
+
if (!fs12.existsSync(resolved) || this.isInsideRoot(resolved)) return null;
|
|
335777
335814
|
const existing = this.findWorkspaceByPath(resolved);
|
|
335778
335815
|
if (existing) {
|
|
335779
335816
|
this.current = existing;
|
|
335780
335817
|
this.saveState();
|
|
335781
335818
|
return existing;
|
|
335782
335819
|
}
|
|
335783
|
-
const name50 =
|
|
335820
|
+
const name50 = path13.basename(resolved);
|
|
335784
335821
|
const ws = {
|
|
335785
335822
|
id: this.stableWorkspaceId("local", resolved),
|
|
335786
335823
|
name: name50,
|
|
@@ -335798,10 +335835,10 @@ var WorkspaceManager = class {
|
|
|
335798
335835
|
addSshExternal(input2) {
|
|
335799
335836
|
if (!input2.sshConnectionId || !input2.remotePath || !input2.remotePcHash) return null;
|
|
335800
335837
|
const remotePath = this.canonicalRemotePath(input2.remotePath);
|
|
335801
|
-
const baseName = (input2.name ||
|
|
335838
|
+
const baseName = (input2.name || path13.basename(remotePath.replace(/[\\/]+$/, "")) || input2.sshConnectionId || "ssh-workspace").trim();
|
|
335802
335839
|
const safeName = baseName.replace(/[<>:"/\\|?*\x00-\x1F]/g, "-").replace(/\s+/g, " ").trim() || "ssh-workspace";
|
|
335803
|
-
const shadowRoot = input2.localPath ?
|
|
335804
|
-
|
|
335840
|
+
const shadowRoot = input2.localPath ? path13.resolve(input2.localPath) : path13.join(this.rootPath, "Work", ".ssh", `${input2.sshConnectionId}-${crypto7.createHash("sha256").update(remotePath).digest("hex").slice(0, 16)}`);
|
|
335841
|
+
fs12.mkdirSync(shadowRoot, { recursive: true });
|
|
335805
335842
|
const existing = this.findSshWorkspaceByRemotePath(input2.sshConnectionId, remotePath);
|
|
335806
335843
|
const ws = {
|
|
335807
335844
|
...existing || {},
|
|
@@ -335883,7 +335920,7 @@ var WorkspaceManager = class {
|
|
|
335883
335920
|
currentAgentPrompt() {
|
|
335884
335921
|
if (!this.current) return null;
|
|
335885
335922
|
try {
|
|
335886
|
-
return
|
|
335923
|
+
return fs12.readFileSync(path13.join(this.current.path, "agent.md"), "utf-8");
|
|
335887
335924
|
} catch {
|
|
335888
335925
|
return null;
|
|
335889
335926
|
}
|
|
@@ -335892,8 +335929,8 @@ var WorkspaceManager = class {
|
|
|
335892
335929
|
const perm = this.config.getStr("workspace", "access_permission");
|
|
335893
335930
|
if (perm === "full_access") return true;
|
|
335894
335931
|
if (!this.current) return perm !== "no_outside_access";
|
|
335895
|
-
const rel =
|
|
335896
|
-
const inside2 = rel === "" || !!rel && !rel.startsWith("..") && !
|
|
335932
|
+
const rel = path13.relative(path13.resolve(this.current.path), path13.resolve(target));
|
|
335933
|
+
const inside2 = rel === "" || !!rel && !rel.startsWith("..") && !path13.isAbsolute(rel);
|
|
335897
335934
|
if (inside2) return true;
|
|
335898
335935
|
return perm !== "no_outside_access";
|
|
335899
335936
|
}
|
|
@@ -335976,6 +336013,7 @@ var PLAN_COMPUTER_USE_ACTIONS = ["observe", "app_list", "app_observe"];
|
|
|
335976
336013
|
var PLAN_BROWSER_USE_ACTIONS = ["observe", "navigate", "wait", "extract"];
|
|
335977
336014
|
var PLAN_COMPUTER_USE_ACTION_SET = new Set(PLAN_COMPUTER_USE_ACTIONS);
|
|
335978
336015
|
var PLAN_BROWSER_USE_ACTION_SET = new Set(PLAN_BROWSER_USE_ACTIONS);
|
|
336016
|
+
var CHAT_WEB_TOOLS = /* @__PURE__ */ new Set(["web_search", "web_fetch"]);
|
|
335979
336017
|
var CONCURRENCY_SAFE_TOOLS = /* @__PURE__ */ new Set([
|
|
335980
336018
|
"pwd",
|
|
335981
336019
|
"read",
|
|
@@ -336009,6 +336047,13 @@ function evaluateToolPolicy(request) {
|
|
|
336009
336047
|
const availability = toolAvailability(name50);
|
|
336010
336048
|
const base2 = { availability, settingsVisible: availability === "configurable" };
|
|
336011
336049
|
if (!name50) return { ...base2, allowed: false, reason: "[permission] Tool name is required." };
|
|
336050
|
+
if (request.mode === "chat" && !CHAT_WEB_TOOLS.has(name50)) {
|
|
336051
|
+
return {
|
|
336052
|
+
...base2,
|
|
336053
|
+
allowed: false,
|
|
336054
|
+
reason: `[permission] Chat mode only allows web_search and web_fetch. It has no workspace, host, application, memory, task, or other write access. Blocked: ${name50}`
|
|
336055
|
+
};
|
|
336056
|
+
}
|
|
336012
336057
|
if (request.mode === "plan") {
|
|
336013
336058
|
if (name50 === "computer_use") {
|
|
336014
336059
|
const action = String(request.args?.action || "").trim();
|
|
@@ -336050,6 +336095,13 @@ function planModePolicyPrompt() {
|
|
|
336050
336095
|
"Runtime policy rejects stale or hidden mutating tool calls even if a prompt asks for them."
|
|
336051
336096
|
].join(" ");
|
|
336052
336097
|
}
|
|
336098
|
+
function chatModePolicyPrompt() {
|
|
336099
|
+
return [
|
|
336100
|
+
"Chat mode is a narrow web-evidence mode.",
|
|
336101
|
+
"Only web_search and web_fetch are available; every workspace, host, application, memory, task, browser-control, and write capability is denied at runtime.",
|
|
336102
|
+
"Search the web for relevant evidence, fetch primary or authoritative sources when useful, then summarize and answer promptly instead of expanding into a long-running task."
|
|
336103
|
+
].join(" ");
|
|
336104
|
+
}
|
|
336053
336105
|
var DELETE_VERB_SOURCE = "(?:remove-item|rmdir|unlink|erase|del|rm|rd|ri)";
|
|
336054
336106
|
var DELETE_VERB_BOUNDARY = new RegExp(`(?:^|[\\s;&|()\\n])${DELETE_VERB_SOURCE}(?:\\s|$)`, "i");
|
|
336055
336107
|
function hasDeletionVerb(text) {
|
|
@@ -336327,7 +336379,7 @@ function requestUtilityHostTool(tool, args, context, timeoutMs = 12e4, signal) {
|
|
|
336327
336379
|
}
|
|
336328
336380
|
|
|
336329
336381
|
// src/core/nativeBash.ts
|
|
336330
|
-
var
|
|
336382
|
+
var path14 = __toESM(require("path"));
|
|
336331
336383
|
var import_module = require("module");
|
|
336332
336384
|
var MAX_OUTPUT_BYTES = 1024 * 1024;
|
|
336333
336385
|
var DEFAULT_TIMEOUT_MS = 3e4;
|
|
@@ -336415,11 +336467,11 @@ function normalizedTimeout(timeoutMs) {
|
|
|
336415
336467
|
}
|
|
336416
336468
|
function virtualCwd(workspaceRoot, requestedCwd) {
|
|
336417
336469
|
if (!requestedCwd) return "/";
|
|
336418
|
-
const root2 =
|
|
336419
|
-
const cwd =
|
|
336420
|
-
const relative6 =
|
|
336421
|
-
if (relative6.startsWith("..") ||
|
|
336422
|
-
return relative6 ? `/${relative6.split(
|
|
336470
|
+
const root2 = path14.resolve(workspaceRoot);
|
|
336471
|
+
const cwd = path14.resolve(requestedCwd);
|
|
336472
|
+
const relative6 = path14.relative(root2, cwd);
|
|
336473
|
+
if (relative6.startsWith("..") || path14.isAbsolute(relative6)) return "/";
|
|
336474
|
+
return relative6 ? `/${relative6.split(path14.sep).join("/")}` : "/";
|
|
336423
336475
|
}
|
|
336424
336476
|
function combineAbortSignals(signal, timeoutMs) {
|
|
336425
336477
|
const controller = new AbortController();
|
|
@@ -336445,7 +336497,7 @@ function createBash(workspaceRoot, timeoutMs) {
|
|
|
336445
336497
|
const justBash = loadJustBash();
|
|
336446
336498
|
if (!justBash) throw new Error("Native Bash runtime unavailable");
|
|
336447
336499
|
const fs27 = new justBash.ReadWriteFs({
|
|
336448
|
-
root:
|
|
336500
|
+
root: path14.resolve(workspaceRoot),
|
|
336449
336501
|
maxFileReadSize: MAX_OUTPUT_BYTES * 8,
|
|
336450
336502
|
allowSymlinks: false
|
|
336451
336503
|
});
|
|
@@ -336534,12 +336586,12 @@ async function executeWorkspaceBash(script, workspaceRoot, options = {}) {
|
|
|
336534
336586
|
}
|
|
336535
336587
|
|
|
336536
336588
|
// src/core/toolArgumentValidator.ts
|
|
336537
|
-
var
|
|
336538
|
-
var
|
|
336589
|
+
var fs13 = require("fs");
|
|
336590
|
+
var path15 = require("path");
|
|
336539
336591
|
var typeBoxCompilerPath = [
|
|
336540
|
-
|
|
336541
|
-
|
|
336542
|
-
].find((candidate) =>
|
|
336592
|
+
path15.join(__dirname, "..", "typebox-compile.bundle.cjs"),
|
|
336593
|
+
path15.join(__dirname, "typebox-compile.bundle.cjs")
|
|
336594
|
+
].find((candidate) => fs13.existsSync(candidate));
|
|
336543
336595
|
if (!typeBoxCompilerPath) throw new Error("Bundled TypeBox compiler is missing from the Newmark runtime.");
|
|
336544
336596
|
var { Compile } = require(typeBoxCompilerPath);
|
|
336545
336597
|
function closeToolArgumentSchema(input2) {
|
|
@@ -336629,8 +336681,8 @@ function formatValidationErrors(name50, errors) {
|
|
|
336629
336681
|
}
|
|
336630
336682
|
|
|
336631
336683
|
// src/core/localOcr.ts
|
|
336632
|
-
var
|
|
336633
|
-
var
|
|
336684
|
+
var fs14 = __toESM(require("fs"));
|
|
336685
|
+
var path16 = __toESM(require("path"));
|
|
336634
336686
|
var AGENT_REPAIR_PROMPT = [
|
|
336635
336687
|
"The local OCR output is approximate Chinese/English fallback evidence.",
|
|
336636
336688
|
"Repair likely OCR substitutions, spacing, and line breaks using the visible UI/PDF context and the user task.",
|
|
@@ -336663,12 +336715,12 @@ var LocalOcrEngine = class {
|
|
|
336663
336715
|
return await this.recognize(dataUrlBuffer(dataUrl), signal, profile);
|
|
336664
336716
|
}
|
|
336665
336717
|
async recognizeFile(filePath, signal) {
|
|
336666
|
-
const absolute =
|
|
336667
|
-
const extension =
|
|
336718
|
+
const absolute = path16.resolve(filePath);
|
|
336719
|
+
const extension = path16.extname(absolute).toLowerCase();
|
|
336668
336720
|
if (![".png", ".jpg", ".jpeg", ".bmp"].includes(extension)) {
|
|
336669
336721
|
throw new Error("Local OCR only accepts PNG, JPEG, or BMP images.");
|
|
336670
336722
|
}
|
|
336671
|
-
const stat =
|
|
336723
|
+
const stat = fs14.statSync(absolute);
|
|
336672
336724
|
if (!stat.isFile() || stat.size <= 0 || stat.size > 12 * 1024 * 1024) {
|
|
336673
336725
|
throw new Error("Local OCR image must be a regular file no larger than 12 MB.");
|
|
336674
336726
|
}
|
|
@@ -336722,7 +336774,7 @@ var LocalOcrEngine = class {
|
|
|
336722
336774
|
const tesseract = require_src();
|
|
336723
336775
|
const worker = await tesseract.createWorker("chi_sim+eng", tesseract.OEM.LSTM_ONLY, {
|
|
336724
336776
|
langPath: tessdataPath,
|
|
336725
|
-
cachePath:
|
|
336777
|
+
cachePath: path16.join(this.rootPath, "cache", "ocr-runtime"),
|
|
336726
336778
|
cacheMethod: "none",
|
|
336727
336779
|
gzip: true,
|
|
336728
336780
|
logger: () => void 0
|
|
@@ -336730,14 +336782,14 @@ var LocalOcrEngine = class {
|
|
|
336730
336782
|
return worker;
|
|
336731
336783
|
}
|
|
336732
336784
|
prepareLanguageCache() {
|
|
336733
|
-
const target =
|
|
336734
|
-
|
|
336785
|
+
const target = path16.join(this.rootPath, "cache", "ocr-tessdata");
|
|
336786
|
+
fs14.mkdirSync(target, { recursive: true });
|
|
336735
336787
|
for (const language of ["eng", "chi_sim"]) {
|
|
336736
|
-
const destination =
|
|
336737
|
-
if (
|
|
336738
|
-
const packageRoot =
|
|
336739
|
-
const source =
|
|
336740
|
-
|
|
336788
|
+
const destination = path16.join(target, `${language}.traineddata.gz`);
|
|
336789
|
+
if (fs14.existsSync(destination) && fs14.statSync(destination).size > 0) continue;
|
|
336790
|
+
const packageRoot = path16.dirname(require.resolve(`@tesseract.js-data/${language}/package.json`));
|
|
336791
|
+
const source = path16.join(packageRoot, "4.0.0_best_int", `${language}.traineddata.gz`);
|
|
336792
|
+
fs14.copyFileSync(source, destination);
|
|
336741
336793
|
}
|
|
336742
336794
|
return target;
|
|
336743
336795
|
}
|
|
@@ -336876,8 +336928,8 @@ function normalizeCrossEnvPath(value, wsPath) {
|
|
|
336876
336928
|
const posix3 = windowsDrivePathToPosix(raw);
|
|
336877
336929
|
if (posix3) return posix3;
|
|
336878
336930
|
}
|
|
336879
|
-
if (
|
|
336880
|
-
return
|
|
336931
|
+
if (path17.isAbsolute(raw)) return raw;
|
|
336932
|
+
return path17.join(wsPath, raw);
|
|
336881
336933
|
}
|
|
336882
336934
|
function translateWindowsPathsForWslBash(script) {
|
|
336883
336935
|
if (!process.env.NEWMARK_WSL_DISTRO) return script;
|
|
@@ -336891,7 +336943,7 @@ function translateWindowsPathsForWslBash(script) {
|
|
|
336891
336943
|
function computerUseOwner(context, wsPath) {
|
|
336892
336944
|
const conversationId = String(context.conversationId || "").trim();
|
|
336893
336945
|
if (conversationId) return `conversation:${conversationId}`;
|
|
336894
|
-
const resolved =
|
|
336946
|
+
const resolved = path17.resolve(context.workspacePath || wsPath || process.cwd());
|
|
336895
336947
|
const workspaceHash = crypto8.createHash("sha256").update(resolved).digest("hex").slice(0, 12);
|
|
336896
336948
|
return `direct:${workspaceHash}`;
|
|
336897
336949
|
}
|
|
@@ -336973,7 +337025,7 @@ function computerUseSessionScope(context, wsPath, owner) {
|
|
|
336973
337025
|
return {
|
|
336974
337026
|
runtimeKey: browserUseScope(context, wsPath).runtimeKey,
|
|
336975
337027
|
ownerLabel: owner,
|
|
336976
|
-
workspacePath:
|
|
337028
|
+
workspacePath: path17.resolve(wsPath || process.cwd())
|
|
336977
337029
|
};
|
|
336978
337030
|
}
|
|
336979
337031
|
function acquireComputerUseLock(action, owner, wsPath, context = {}, dryRun = false) {
|
|
@@ -337168,7 +337220,7 @@ var ToolExecutor = class {
|
|
|
337168
337220
|
t3("subagent_send", "Persist a mailbox message to a same-conversation peer agent. Target by exact id (preferred) or name.", { id: { type: "string", description: "Exact peer id from subagent_list." }, name: { type: "string", description: "Convenience peer name." }, message: { type: "string" }, prompt: { type: "string", description: "Legacy alias for message." }, kind: { type: "string", enum: ["directive", "question", "result", "handoff"] }, reply_to: { type: "string" }, correlation_id: { type: "string" } }, []),
|
|
337169
337221
|
t3("subagent_result", "Return the persisted transcript, mailbox summary, status, and latest result for a peer agent. Target by exact id (preferred) or name.", { id: { type: "string", description: "Exact peer id from subagent_list." }, name: { type: "string", description: "Convenience peer name." } }, []),
|
|
337170
337222
|
t3("subagent_close", "Close a same-conversation peer. Root can close any peer; a peer can close only itself. Target by exact id (preferred) or name.", { id: { type: "string", description: "Exact peer id from subagent_list." }, name: { type: "string", description: "Convenience peer name." } }, []),
|
|
337171
|
-
t3("linked_plan", "Read or update the current conversation linked Markdown plan. Update requires the
|
|
337223
|
+
t3("linked_plan", "Read or incrementally update the current conversation linked Markdown plan. Update requires expected_revision. Prefer append or old_text/new_text for local changes; markdown remains the legacy full replacement path.", { action: { type: "string", enum: ["get", "update"] }, markdown: { type: "string" }, append: { type: "string" }, old_text: { type: "string" }, new_text: { type: "string" }, replace_all: { type: "boolean" }, expected_revision: { type: "number" } }, ["action"]),
|
|
337172
337224
|
t3("build_history_query", "Read the concrete public work details (tool calls, results, file changes, guides) of one historical Build Block. Call it proactively when the current task continues, fixes, verifies, or depends on earlier work: reuse the returned activity instead of re-investigating from scratch. Do not call it merely to answer completion status already exposed by the prompt. Select by newest-to-oldest history_index, or by run_id returned from an earlier query. Every activity/guide content is bounded to max_chars (default 2000) to keep the read lean and cache-friendly.", { history_index: { type: "number", minimum: 1, description: "1-based historical Build Block index from the request ledger; 1 is the newest previous task." }, run_id: { type: "string", description: "Exact run id returned by an earlier build_history_query result." }, max_events: { type: "number", minimum: 1, maximum: 200, description: "Maximum trailing public work events; defaults to 80." }, max_chars: { type: "number", minimum: 100, maximum: 4e3, description: "Per-event/per-guide content character bound; defaults to 2000." } }, []),
|
|
337173
337225
|
t3("context_compress", "Actively compress the LLM context history for this conversation. This collapses older history entries into a concise summary while preserving the recent tail, which reduces context tokens and cost. IMPORTANT: it affects only the LLM context (what the model sees); the displayed conversation history shown to the user is never altered. Call this when the conversation is long, token pressure is high, or you judge that older turns are no longer needed in full. Idempotent and safe: repeated calls produce incremental summaries.", { keep_recent: { type: "number", minimum: 2, maximum: 60, description: "Recent message count to keep uncompressed at the tail. Defaults to the configured keep_recent_messages." }, force: { type: "boolean", description: "Compress even if the context is not yet over the automatic threshold. Defaults to false." } }, []),
|
|
337174
337226
|
t3("context_history_manage", "Manage the LLM context history for this conversation without affecting the displayed conversation history. This is the active context-management surface. The hot cache stays bounded; evicted folded segments remain in a conversation-isolated append-only cold archive and are loaded only by explicit search/read/restore calls. Actions: list returns a bounded index of current context entries; remove declares one long-term entry for unload (see below); summarize folds a contiguous current range; restore reinserts a folded segment when its summary marker is still present; search finds matching hot or archived segments; read returns one bounded segment without injecting the whole archive; status reports budgets, hot cache, cold archive, the protected recent zone, and pending removals. The recent context tail and last user message are protected from remove/summarize unless dangerous is true. For cache-optimization, remove ONLY targets long-term history (never the protected recent tail or last user message) and does NOT unload immediately: the declared entry stays in context for the rest of the current Build Block so the provider prefix cache stays stable, then is physically removed when the Block ends \u2014 applying to subsequent Blocks only.", {
|
|
@@ -337198,11 +337250,11 @@ var ToolExecutor = class {
|
|
|
337198
337250
|
t3("skill_download", "Download a skill", { name: { type: "string" }, source: { type: "string" } }, ["name", "source"]),
|
|
337199
337251
|
t3("skill", "Search enabled skill metadata or load one exact skill body on demand. Use query when unsure, then name to load the selected skill.", { query: { type: "string", maxLength: 200 }, name: { type: "string", maxLength: 200 } }, []),
|
|
337200
337252
|
t3("flow_list", "List available Newmark Flow workflows from the Flow folder so the agent can choose one.", {}, []),
|
|
337201
|
-
t3("flow_save", "
|
|
337253
|
+
t3("flow_save", "Create or incrementally update a Newmark Flow workflow. Use action=upsert with one component or action=delete with component_id and confirm=true for local edits. action=replace plus components remains the legacy full replacement path.", { name: { type: "string" }, action: { type: "string", enum: ["replace", "upsert", "delete"] }, components: { type: "array" }, component: { type: "object" }, component_id: { type: "number" }, confirm: { type: "boolean" } }, ["name"]),
|
|
337202
337254
|
t3("flow_run", "Trigger an existing Newmark Flow workflow by name with optional input and start component.", { name: { type: "string" }, input: { type: "string" }, start: { type: "number" } }, ["name"]),
|
|
337203
337255
|
t3("memory_lab_read", "Read Memory Lab index.json, its path, and usage instructions. Optionally pass component/name/slug to read a memory component core markdown.", { component: { type: "string" }, name: { type: "string" }, slug: { type: "string" } }, []),
|
|
337204
337256
|
t3("memory_lab_query", "Retrieve a bounded task-relevant Memory Lab set with deterministic scoring and adaptive early stopping. Prefer this over loading the complete index when a focused query is sufficient.", { query: { type: "string", minLength: 1 }, limit: { type: "number", minimum: 1, maximum: 12 }, max_chars: { type: "number", minimum: 1e3, maximum: 48e3 } }, ["query"]),
|
|
337205
|
-
t3("memory_lab_update", "
|
|
337257
|
+
t3("memory_lab_update", "Create or incrementally patch a Memory Lab component. Create with name/tags/content. For an existing component pass component plus expectedUpdatedAt and only changed fields; prefer contentAppend or oldText/newText for small body edits. Prior revisions are archived and stale writes fail closed.", { component: { type: "string" }, name: { type: "string" }, description: { type: "string" }, tags: { type: "array", items: { type: "string" } }, tagPaths: { type: "array", items: { type: "array", items: { type: "string" } } }, content: { type: "string" }, contentAppend: { type: "string" }, oldText: { type: "string" }, newText: { type: "string" }, replaceAll: { type: "boolean" }, kind: { type: "string", enum: ["file", "folder"] }, expectedUpdatedAt: { type: "string" }, reason: { type: "string" }, source: { type: "string" } }, []),
|
|
337206
337258
|
t3("memory_lab_delete", "DELETE obsolete durable memory only when the user explicitly asks to forget/remove it. The prior revision is moved to Memory Lab/archive and the Policy decision is logged.", { component: { type: "string" }, name: { type: "string" }, slug: { type: "string" }, expectedUpdatedAt: { type: "string" }, reason: { type: "string" }, source: { type: "string" } }, []),
|
|
337207
337259
|
t3("memory_lab_reindex", "Rebuild and organize Memory Lab index links. Routed through Agent runtime when invoked by the model.", {}, []),
|
|
337208
337260
|
t3("automation_list", "List persisted Newmark automations so the agent can inspect scheduled work.", {}, []),
|
|
@@ -337524,13 +337576,13 @@ var ToolExecutor = class {
|
|
|
337524
337576
|
}
|
|
337525
337577
|
case "pdf_read": {
|
|
337526
337578
|
const pdfPath = resolve16(g2("path"));
|
|
337527
|
-
if (
|
|
337528
|
-
const stat =
|
|
337579
|
+
if (path17.extname(pdfPath).toLowerCase() !== ".pdf") return "[pdf_read error] path must end in .pdf.";
|
|
337580
|
+
const stat = fs15.statSync(pdfPath);
|
|
337529
337581
|
if (!stat.isFile() || stat.size <= 0 || stat.size > 250 * 1024 * 1024) {
|
|
337530
337582
|
return "[pdf_read error] PDF must be a regular file no larger than 250 MB.";
|
|
337531
337583
|
}
|
|
337532
337584
|
const maxChars = Math.max(500, Math.min(1e5, Number(args.max_chars || 5e4)));
|
|
337533
|
-
const textLayer = extractPdfTextLayer(
|
|
337585
|
+
const textLayer = extractPdfTextLayer(fs15.readFileSync(pdfPath)).slice(0, maxChars);
|
|
337534
337586
|
const readableCount = (textLayer.match(/[A-Za-z0-9\u3400-\u9fff]/g) || []).length;
|
|
337535
337587
|
if (readableCount >= 20) {
|
|
337536
337588
|
return JSON.stringify({
|
|
@@ -337749,7 +337801,7 @@ var ToolExecutor = class {
|
|
|
337749
337801
|
case "flow_list":
|
|
337750
337802
|
return this.flowList();
|
|
337751
337803
|
case "flow_save":
|
|
337752
|
-
return this.flowSave(g2("name"), args
|
|
337804
|
+
return this.flowSave(g2("name"), args);
|
|
337753
337805
|
case "flow_run":
|
|
337754
337806
|
return `[flow_run] Routed to Agent runtime: ${g2("name")}`;
|
|
337755
337807
|
case "memory_lab_read":
|
|
@@ -337806,8 +337858,8 @@ var ToolExecutor = class {
|
|
|
337806
337858
|
}
|
|
337807
337859
|
}
|
|
337808
337860
|
isInside(parent, child) {
|
|
337809
|
-
const rel =
|
|
337810
|
-
return rel === "" || !!rel && !rel.startsWith("..") && !
|
|
337861
|
+
const rel = path17.relative(path17.resolve(parent), path17.resolve(child));
|
|
337862
|
+
return rel === "" || !!rel && !rel.startsWith("..") && !path17.isAbsolute(rel);
|
|
337811
337863
|
}
|
|
337812
337864
|
hostSupportsTool(name50) {
|
|
337813
337865
|
if (name50.startsWith("browser_") && !this.hostProfile.electronBrowser) return false;
|
|
@@ -337919,7 +337971,7 @@ var ToolExecutor = class {
|
|
|
337919
337971
|
if (!token || /^https?:\/\//i.test(token) || token.startsWith("-")) continue;
|
|
337920
337972
|
if (!this.looksLikePath(token)) continue;
|
|
337921
337973
|
const withoutWildcard = token.replace(/[\\/][*?][^\\/]*$/g, "");
|
|
337922
|
-
refs.push(
|
|
337974
|
+
refs.push(path17.resolve(normalizeCrossEnvPath(withoutWildcard, wsPath)));
|
|
337923
337975
|
}
|
|
337924
337976
|
return Array.from(new Set(refs));
|
|
337925
337977
|
}
|
|
@@ -337970,7 +338022,7 @@ var ToolExecutor = class {
|
|
|
337970
338022
|
}
|
|
337971
338023
|
fread(p) {
|
|
337972
338024
|
try {
|
|
337973
|
-
const c3 =
|
|
338025
|
+
const c3 = fs15.readFileSync(p, "utf-8");
|
|
337974
338026
|
return c3.length > 3e4 ? c3.slice(0, 3e4) + "...\n[truncated]" : c3;
|
|
337975
338027
|
} catch (e3) {
|
|
337976
338028
|
return `[read] ${e3}`;
|
|
@@ -337978,8 +338030,8 @@ var ToolExecutor = class {
|
|
|
337978
338030
|
}
|
|
337979
338031
|
fwrite(p, content) {
|
|
337980
338032
|
try {
|
|
337981
|
-
|
|
337982
|
-
|
|
338033
|
+
fs15.mkdirSync(path17.dirname(p), { recursive: true });
|
|
338034
|
+
fs15.writeFileSync(p, content, "utf-8");
|
|
337983
338035
|
return `[write] OK: ${p}`;
|
|
337984
338036
|
} catch (e3) {
|
|
337985
338037
|
return `[write] ${e3}`;
|
|
@@ -337987,10 +338039,10 @@ var ToolExecutor = class {
|
|
|
337987
338039
|
}
|
|
337988
338040
|
fedit(p, oldStr, newStr) {
|
|
337989
338041
|
try {
|
|
337990
|
-
const c3 =
|
|
338042
|
+
const c3 = fs15.readFileSync(p, "utf-8");
|
|
337991
338043
|
if (!c3.includes(oldStr)) return `[edit] String not found in ${p}.`;
|
|
337992
338044
|
const updated = c3.replace(oldStr, newStr);
|
|
337993
|
-
|
|
338045
|
+
fs15.writeFileSync(p, updated, "utf-8");
|
|
337994
338046
|
return `[edit] OK: ${p}`;
|
|
337995
338047
|
} catch (e3) {
|
|
337996
338048
|
return `[edit] ${e3}`;
|
|
@@ -337999,12 +338051,12 @@ var ToolExecutor = class {
|
|
|
337999
338051
|
fdelete(p) {
|
|
338000
338052
|
try {
|
|
338001
338053
|
if (/[*?]/.test(p)) return "[delete_file] Refused: wildcard paths are not allowed. Delete one file per call.";
|
|
338002
|
-
const resolved =
|
|
338003
|
-
const stat =
|
|
338054
|
+
const resolved = path17.resolve(p);
|
|
338055
|
+
const stat = fs15.lstatSync(resolved);
|
|
338004
338056
|
if (stat.isDirectory()) {
|
|
338005
338057
|
return "[delete_file] Refused: deleting a directory is not allowed. Delete files one by one under Agent supervision.";
|
|
338006
338058
|
}
|
|
338007
|
-
|
|
338059
|
+
fs15.unlinkSync(resolved);
|
|
338008
338060
|
return `[delete_file] OK: ${resolved}`;
|
|
338009
338061
|
} catch (e3) {
|
|
338010
338062
|
return `[delete_file] ${e3 instanceof Error ? e3.message : String(e3)}`;
|
|
@@ -338028,11 +338080,11 @@ var ToolExecutor = class {
|
|
|
338028
338080
|
const results = [];
|
|
338029
338081
|
const walk4 = (d3, depth) => {
|
|
338030
338082
|
if (depth > 5 || results.length >= 80) return;
|
|
338031
|
-
for (const entry of
|
|
338032
|
-
const full =
|
|
338083
|
+
for (const entry of fs15.readdirSync(d3, { withFileTypes: true })) {
|
|
338084
|
+
const full = path17.join(d3, entry.name);
|
|
338033
338085
|
if (entry.isFile()) {
|
|
338034
338086
|
try {
|
|
338035
|
-
const content =
|
|
338087
|
+
const content = fs15.readFileSync(full, "utf-8");
|
|
338036
338088
|
for (const [i4, line] of content.split("\n").entries()) {
|
|
338037
338089
|
if (re.test(line)) {
|
|
338038
338090
|
results.push(`${entry.name}:${i4 + 1}:${line.trim()}`);
|
|
@@ -338248,29 +338300,53 @@ ${String(result.data)}`);
|
|
|
338248
338300
|
try {
|
|
338249
338301
|
const resp = await this.proxyFetch(src, { signal });
|
|
338250
338302
|
const content = await resp.text();
|
|
338251
|
-
const dir =
|
|
338252
|
-
|
|
338253
|
-
|
|
338303
|
+
const dir = path17.join(this.root, "skills", name50);
|
|
338304
|
+
fs15.mkdirSync(dir, { recursive: true });
|
|
338305
|
+
fs15.writeFileSync(path17.join(dir, "SKILL.md"), content, "utf-8");
|
|
338254
338306
|
return `[skill] Downloaded '${name50}'`;
|
|
338255
338307
|
} catch (e3) {
|
|
338256
338308
|
return `[skill] ${e3}`;
|
|
338257
338309
|
}
|
|
338258
338310
|
}
|
|
338259
338311
|
flowList() {
|
|
338260
|
-
const dir =
|
|
338312
|
+
const dir = path17.join(this.root, "Flow");
|
|
338261
338313
|
try {
|
|
338262
|
-
const files =
|
|
338314
|
+
const files = fs15.readdirSync(dir).filter((f3) => f3.endsWith(".Flow.json")).sort();
|
|
338263
338315
|
if (!files.length) return "[flow_list] No workflows found.";
|
|
338264
338316
|
return files.map((f3) => f3.replace(/\.Flow\.json$/, "")).join("\n");
|
|
338265
338317
|
} catch (e3) {
|
|
338266
338318
|
return `[flow_list] ${e3}`;
|
|
338267
338319
|
}
|
|
338268
338320
|
}
|
|
338269
|
-
flowSave(name50,
|
|
338321
|
+
flowSave(name50, input2) {
|
|
338270
338322
|
const cleanName = (name50 || "").replace(/[<>:"/\\|?*]/g, "-").trim();
|
|
338271
338323
|
if (!cleanName) return "[flow_save] Workflow name is required.";
|
|
338272
|
-
|
|
338273
|
-
const
|
|
338324
|
+
const dir = path17.join(this.root, "Flow");
|
|
338325
|
+
const target = path17.join(dir, `${cleanName}.Flow.json`);
|
|
338326
|
+
const action = String(input2.action || (Array.isArray(input2.components) ? "replace" : "upsert")).toLowerCase();
|
|
338327
|
+
let componentsRaw = input2.components;
|
|
338328
|
+
if (action === "upsert") {
|
|
338329
|
+
if (!input2.component || typeof input2.component !== "object") return "[flow_save] component is required for action=upsert.";
|
|
338330
|
+
const existing = FlowEngine.load(dir, cleanName)?.components || [];
|
|
338331
|
+
const component = input2.component;
|
|
338332
|
+
const requestedId = Number(component.id);
|
|
338333
|
+
if (!Number.isFinite(requestedId)) return "[flow_save] component.id is required for action=upsert.";
|
|
338334
|
+
componentsRaw = [...existing.filter((item) => item.id !== requestedId), component].sort((a3, b2) => Number(a3.id) - Number(b2.id));
|
|
338335
|
+
} else if (action === "delete") {
|
|
338336
|
+
if (input2.confirm !== true) return "[flow_save] action=delete requires confirm=true.";
|
|
338337
|
+
const componentId = Number(input2.component_id);
|
|
338338
|
+
if (!Number.isFinite(componentId)) return "[flow_save] component_id is required for action=delete.";
|
|
338339
|
+
const existing = FlowEngine.load(dir, cleanName);
|
|
338340
|
+
if (!existing) return `[flow_save] Workflow not found: ${cleanName}`;
|
|
338341
|
+
const remaining = existing.components.filter((item) => item.id !== componentId);
|
|
338342
|
+
if (remaining.length === existing.components.length) return `[flow_save] Component not found: ${componentId}`;
|
|
338343
|
+
componentsRaw = remaining;
|
|
338344
|
+
} else if (action !== "replace") {
|
|
338345
|
+
return `[flow_save] Unknown action: ${action}`;
|
|
338346
|
+
}
|
|
338347
|
+
if (!Array.isArray(componentsRaw)) return "[flow_save] components must be an array for action=replace.";
|
|
338348
|
+
const componentInputs = componentsRaw;
|
|
338349
|
+
const components = componentInputs.map((raw, idx) => {
|
|
338274
338350
|
const c3 = raw;
|
|
338275
338351
|
const type = c3.type === "logic" ? "logic" : "dialog";
|
|
338276
338352
|
if (type === "logic") {
|
|
@@ -338291,10 +338367,9 @@ ${String(result.data)}`);
|
|
|
338291
338367
|
};
|
|
338292
338368
|
});
|
|
338293
338369
|
const workflow = { name: cleanName, components };
|
|
338294
|
-
|
|
338295
|
-
|
|
338296
|
-
|
|
338297
|
-
return `[flow_save] OK: ${cleanName}.Flow.json`;
|
|
338370
|
+
fs15.mkdirSync(dir, { recursive: true });
|
|
338371
|
+
fs15.writeFileSync(target, JSON.stringify(workflow, null, 2), "utf-8");
|
|
338372
|
+
return `[flow_save] OK (${action}): ${cleanName}.Flow.json`;
|
|
338298
338373
|
}
|
|
338299
338374
|
memoryLabRead(selector2) {
|
|
338300
338375
|
const lab2 = new MemoryLabManager(this.root);
|
|
@@ -338354,10 +338429,10 @@ ${String(result.data)}`);
|
|
|
338354
338429
|
return this.gh(args, ws, signal);
|
|
338355
338430
|
}
|
|
338356
338431
|
async fileAudit(target, ws, includeRemote, baseRef, signal) {
|
|
338357
|
-
const resolvedTarget =
|
|
338358
|
-
const exists =
|
|
338359
|
-
const stat = exists ?
|
|
338360
|
-
const repoRoot = await this.findGitRoot(exists && stat?.isDirectory() ? resolvedTarget :
|
|
338432
|
+
const resolvedTarget = path17.resolve(target || ws);
|
|
338433
|
+
const exists = fs15.existsSync(resolvedTarget);
|
|
338434
|
+
const stat = exists ? fs15.statSync(resolvedTarget) : null;
|
|
338435
|
+
const repoRoot = await this.findGitRoot(exists && stat?.isDirectory() ? resolvedTarget : path17.dirname(resolvedTarget), ws, signal);
|
|
338361
338436
|
const audit = {
|
|
338362
338437
|
ok: true,
|
|
338363
338438
|
target: resolvedTarget,
|
|
@@ -338384,11 +338459,11 @@ ${String(result.data)}`);
|
|
|
338384
338459
|
};
|
|
338385
338460
|
if (stat.isFile()) {
|
|
338386
338461
|
const hash = crypto8.createHash("sha256");
|
|
338387
|
-
hash.update(
|
|
338462
|
+
hash.update(fs15.readFileSync(target));
|
|
338388
338463
|
base2.sha256 = hash.digest("hex").toUpperCase();
|
|
338389
338464
|
}
|
|
338390
338465
|
if (stat.isDirectory()) {
|
|
338391
|
-
base2.entries =
|
|
338466
|
+
base2.entries = fs15.readdirSync(target).slice(0, 200).sort();
|
|
338392
338467
|
}
|
|
338393
338468
|
return base2;
|
|
338394
338469
|
}
|
|
@@ -338397,14 +338472,14 @@ ${String(result.data)}`);
|
|
|
338397
338472
|
const out = await this.gitExecAt(candidate, ["rev-parse", "--show-toplevel"], signal);
|
|
338398
338473
|
if (!out.startsWith("[git]") && !out.includes("not a git repository")) {
|
|
338399
338474
|
const root2 = out.split(/\r?\n/)[0].trim();
|
|
338400
|
-
if (root2 &&
|
|
338475
|
+
if (root2 && fs15.existsSync(root2)) return path17.resolve(root2);
|
|
338401
338476
|
}
|
|
338402
338477
|
}
|
|
338403
338478
|
return null;
|
|
338404
338479
|
}
|
|
338405
338480
|
async gitFileAudit(repoRoot, target, baseRef, signal) {
|
|
338406
|
-
const rel =
|
|
338407
|
-
const inside2 = rel === "" || !!rel && !rel.startsWith("..") && !
|
|
338481
|
+
const rel = path17.relative(repoRoot, target).replace(/\\/g, "/");
|
|
338482
|
+
const inside2 = rel === "" || !!rel && !rel.startsWith("..") && !path17.isAbsolute(rel);
|
|
338408
338483
|
if (!inside2) return { repository: repoRoot, tracked: false, note: "Path is outside the detected repository." };
|
|
338409
338484
|
const branch = await this.gitExecAt(repoRoot, ["branch", "--show-current"], signal);
|
|
338410
338485
|
const status = rel === "" ? await this.gitExecAt(repoRoot, ["status", "--short"], signal) : await this.gitExecAt(repoRoot, ["status", "--short", "--", rel], signal);
|
|
@@ -338462,7 +338537,7 @@ ${String(result.data)}`);
|
|
|
338462
338537
|
}
|
|
338463
338538
|
async githubFileAudit(repoRoot, target, remote, signal) {
|
|
338464
338539
|
const repo = `${remote.owner}/${remote.name}`;
|
|
338465
|
-
const rel =
|
|
338540
|
+
const rel = path17.relative(repoRoot, target).replace(/\\/g, "/");
|
|
338466
338541
|
const branch = (await this.gitExecAt(repoRoot, ["branch", "--show-current"], signal)).trim();
|
|
338467
338542
|
const encodedPath = rel && rel !== "." ? rel.split("/").map((part) => encodeURIComponent(part)).join("/") : "";
|
|
338468
338543
|
const repoInfo = await this.ghJson(["api", `repos/${repo}`, "--jq", "{name: .full_name, private: .private, default_branch: .default_branch, fork: .fork, html_url: .html_url}"], repoRoot, signal);
|
|
@@ -338486,8 +338561,8 @@ ${String(result.data)}`);
|
|
|
338486
338561
|
};
|
|
338487
338562
|
}
|
|
338488
338563
|
async repoSecurityAudit(target, ws, baseRef, signal) {
|
|
338489
|
-
const resolvedTarget =
|
|
338490
|
-
const repoRoot = await this.findGitRoot(
|
|
338564
|
+
const resolvedTarget = path17.resolve(target || ws);
|
|
338565
|
+
const repoRoot = await this.findGitRoot(fs15.existsSync(resolvedTarget) && fs15.statSync(resolvedTarget).isDirectory() ? resolvedTarget : path17.dirname(resolvedTarget), ws, signal);
|
|
338491
338566
|
if (!repoRoot) {
|
|
338492
338567
|
return JSON.stringify({
|
|
338493
338568
|
ok: true,
|
|
@@ -338585,12 +338660,12 @@ ${String(result.data)}`);
|
|
|
338585
338660
|
const findings = [];
|
|
338586
338661
|
for (const rel of Array.from(files).sort()) {
|
|
338587
338662
|
if (findings.length >= 40) break;
|
|
338588
|
-
const full =
|
|
338589
|
-
if (!
|
|
338590
|
-
if (
|
|
338663
|
+
const full = path17.join(repoRoot, rel);
|
|
338664
|
+
if (!fs15.existsSync(full) || !fs15.statSync(full).isFile()) continue;
|
|
338665
|
+
if (fs15.statSync(full).size > 512 * 1024) continue;
|
|
338591
338666
|
let text = "";
|
|
338592
338667
|
try {
|
|
338593
|
-
text =
|
|
338668
|
+
text = fs15.readFileSync(full, "utf-8");
|
|
338594
338669
|
} catch {
|
|
338595
338670
|
continue;
|
|
338596
338671
|
}
|
|
@@ -338620,12 +338695,12 @@ ${String(result.data)}`);
|
|
|
338620
338695
|
const findings = [];
|
|
338621
338696
|
for (const rel of Array.from(files).sort()) {
|
|
338622
338697
|
if (findings.length >= 40) break;
|
|
338623
|
-
const full =
|
|
338624
|
-
if (!
|
|
338625
|
-
if (
|
|
338698
|
+
const full = path17.join(repoRoot, rel);
|
|
338699
|
+
if (!fs15.existsSync(full) || !fs15.statSync(full).isFile()) continue;
|
|
338700
|
+
if (fs15.statSync(full).size > 512 * 1024) continue;
|
|
338626
338701
|
let text = "";
|
|
338627
338702
|
try {
|
|
338628
|
-
text =
|
|
338703
|
+
text = fs15.readFileSync(full, "utf-8");
|
|
338629
338704
|
} catch {
|
|
338630
338705
|
continue;
|
|
338631
338706
|
}
|
|
@@ -338642,7 +338717,7 @@ ${String(result.data)}`);
|
|
|
338642
338717
|
releaseExcludedPathFindings(repoRoot, ignoredFilesRaw) {
|
|
338643
338718
|
const sensitive = /^(config\.json|agent\.md|PC_Hash\.config|Work\/|archive\/|skills\/|Memory Lab\/|Design\.md|release\/|_local\/|_ref\/|vendor\/)/i;
|
|
338644
338719
|
const fromIgnored = String(ignoredFilesRaw || "").split(/\r?\n/).map((line) => line.trim().replace(/\\/g, "/")).filter((line) => line && sensitive.test(line));
|
|
338645
|
-
const direct = ["config.json", "agent.md", "PC_Hash.config", "Work", "archive", "skills", "Memory Lab", "Design.md", "release", "_local", "_ref", "vendor"].filter((rel) =>
|
|
338720
|
+
const direct = ["config.json", "agent.md", "PC_Hash.config", "Work", "archive", "skills", "Memory Lab", "Design.md", "release", "_local", "_ref", "vendor"].filter((rel) => fs15.existsSync(path17.join(repoRoot, rel))).map((rel) => rel.replace(/\\/g, "/"));
|
|
338646
338721
|
return Array.from(/* @__PURE__ */ new Set([...fromIgnored, ...direct])).slice(0, 80);
|
|
338647
338722
|
}
|
|
338648
338723
|
async ghJson(args, ws, signal) {
|
|
@@ -339446,8 +339521,8 @@ function sharedSubagentManager(key3, options) {
|
|
|
339446
339521
|
}
|
|
339447
339522
|
|
|
339448
339523
|
// src/core/skills.ts
|
|
339449
|
-
var
|
|
339450
|
-
var
|
|
339524
|
+
var fs16 = __toESM(require("fs"));
|
|
339525
|
+
var path18 = __toESM(require("path"));
|
|
339451
339526
|
var os4 = __toESM(require("os"));
|
|
339452
339527
|
var import_crypto9 = require("crypto");
|
|
339453
339528
|
var SkillsManager = class {
|
|
@@ -339456,13 +339531,13 @@ var SkillsManager = class {
|
|
|
339456
339531
|
marketSourcesPath;
|
|
339457
339532
|
metadataCache = /* @__PURE__ */ new Map();
|
|
339458
339533
|
constructor(root2) {
|
|
339459
|
-
this.skillsDir =
|
|
339460
|
-
this.metaPath =
|
|
339461
|
-
this.marketSourcesPath =
|
|
339462
|
-
|
|
339534
|
+
this.skillsDir = path18.join(root2, "skills");
|
|
339535
|
+
this.metaPath = path18.join(this.skillsDir, ".skills.json");
|
|
339536
|
+
this.marketSourcesPath = path18.join(this.skillsDir, ".market-sources.json");
|
|
339537
|
+
fs16.mkdirSync(this.skillsDir, { recursive: true });
|
|
339463
339538
|
}
|
|
339464
339539
|
list() {
|
|
339465
|
-
return
|
|
339540
|
+
return fs16.readdirSync(this.skillsDir, { withFileTypes: true }).filter((e3) => e3.isDirectory() && !e3.name.startsWith(".")).map((e3) => e3.name);
|
|
339466
339541
|
}
|
|
339467
339542
|
listDetailed() {
|
|
339468
339543
|
return this.list().map((name50) => this.infoFor(name50, this.getPath(name50), "project", true));
|
|
@@ -339483,48 +339558,48 @@ var SkillsManager = class {
|
|
|
339483
339558
|
}
|
|
339484
339559
|
load(name50) {
|
|
339485
339560
|
const reference = String(name50 || "").trim().toLowerCase();
|
|
339486
|
-
const skill = this.active().find((item) => item.name.toLowerCase() === reference ||
|
|
339561
|
+
const skill = this.active().find((item) => item.name.toLowerCase() === reference || path18.basename(item.path).toLowerCase() === reference);
|
|
339487
339562
|
if (!skill) return null;
|
|
339488
|
-
const skillPath =
|
|
339489
|
-
const content =
|
|
339563
|
+
const skillPath = path18.join(skill.path, "SKILL.md");
|
|
339564
|
+
const content = fs16.readFileSync(skillPath, "utf-8");
|
|
339490
339565
|
const files = this.sampleSkillFiles(skill.path, 10);
|
|
339491
339566
|
return { skill, content, files };
|
|
339492
339567
|
}
|
|
339493
339568
|
has(name50) {
|
|
339494
|
-
return
|
|
339569
|
+
return fs16.existsSync(path18.join(this.skillsDir, name50, "SKILL.md"));
|
|
339495
339570
|
}
|
|
339496
339571
|
getPath(name50) {
|
|
339497
|
-
return
|
|
339572
|
+
return path18.join(this.skillsDir, name50);
|
|
339498
339573
|
}
|
|
339499
339574
|
async download(name50, url) {
|
|
339500
|
-
const dir =
|
|
339501
|
-
|
|
339575
|
+
const dir = path18.join(this.skillsDir, name50);
|
|
339576
|
+
fs16.mkdirSync(dir, { recursive: true });
|
|
339502
339577
|
if (!url.startsWith("http")) return `[skill] Not a URL: ${url}`;
|
|
339503
339578
|
try {
|
|
339504
339579
|
const resp = await fetch(url);
|
|
339505
339580
|
const content = await resp.text();
|
|
339506
|
-
|
|
339581
|
+
fs16.writeFileSync(path18.join(dir, "SKILL.md"), content, "utf-8");
|
|
339507
339582
|
return `[skill] Downloaded '${name50}'`;
|
|
339508
339583
|
} catch (e3) {
|
|
339509
339584
|
return `[skill] ${e3}`;
|
|
339510
339585
|
}
|
|
339511
339586
|
}
|
|
339512
339587
|
installFromLocal(sourceDir, targetName) {
|
|
339513
|
-
const skillPath =
|
|
339514
|
-
if (!
|
|
339588
|
+
const skillPath = path18.join(sourceDir, "SKILL.md");
|
|
339589
|
+
if (!fs16.existsSync(skillPath)) return false;
|
|
339515
339590
|
const info = this.parseSkillInfo(sourceDir);
|
|
339516
|
-
const cleanName = this.cleanName(targetName || info.name ||
|
|
339591
|
+
const cleanName = this.cleanName(targetName || info.name || path18.basename(sourceDir));
|
|
339517
339592
|
if (!cleanName) return false;
|
|
339518
|
-
const dest =
|
|
339519
|
-
|
|
339520
|
-
|
|
339593
|
+
const dest = path18.join(this.skillsDir, cleanName);
|
|
339594
|
+
fs16.rmSync(dest, { recursive: true, force: true });
|
|
339595
|
+
fs16.cpSync(sourceDir, dest, { recursive: true });
|
|
339521
339596
|
this.setEnabled(cleanName, true);
|
|
339522
339597
|
return true;
|
|
339523
339598
|
}
|
|
339524
339599
|
remove(name50) {
|
|
339525
|
-
const dir =
|
|
339526
|
-
if (
|
|
339527
|
-
|
|
339600
|
+
const dir = path18.join(this.skillsDir, name50);
|
|
339601
|
+
if (fs16.existsSync(dir)) {
|
|
339602
|
+
fs16.rmSync(dir, { recursive: true, force: true });
|
|
339528
339603
|
const meta = this.loadMeta();
|
|
339529
339604
|
meta.disabled = meta.disabled.filter((n3) => n3 !== name50);
|
|
339530
339605
|
this.saveMeta(meta);
|
|
@@ -339573,7 +339648,7 @@ var SkillsManager = class {
|
|
|
339573
339648
|
type,
|
|
339574
339649
|
enabled: input2.enabled !== false,
|
|
339575
339650
|
url: url || void 0,
|
|
339576
|
-
path: sourcePath ?
|
|
339651
|
+
path: sourcePath ? path18.resolve(sourcePath) : void 0,
|
|
339577
339652
|
addedAt: existing?.addedAt || now2,
|
|
339578
339653
|
updatedAt: now2
|
|
339579
339654
|
};
|
|
@@ -339611,17 +339686,17 @@ var SkillsManager = class {
|
|
|
339611
339686
|
const items = [];
|
|
339612
339687
|
for (const info of this.listDetailed()) items.push(info);
|
|
339613
339688
|
const roots = [
|
|
339614
|
-
{ root:
|
|
339615
|
-
{ root:
|
|
339616
|
-
{ root:
|
|
339617
|
-
{ root:
|
|
339618
|
-
{ root:
|
|
339619
|
-
{ root:
|
|
339689
|
+
{ root: path18.join(this.skillsDir, "..", ".agents", "skills"), source: "codex" },
|
|
339690
|
+
{ root: path18.join(this.skillsDir, "..", ".claude", "skills"), source: "claude" },
|
|
339691
|
+
{ root: path18.join(os4.homedir(), ".agents", "skills"), source: "user" },
|
|
339692
|
+
{ root: path18.join(os4.homedir(), ".codex", "skills"), source: "codex" },
|
|
339693
|
+
{ root: path18.join(os4.homedir(), ".claude", "skills"), source: "claude" },
|
|
339694
|
+
{ root: path18.join(os4.homedir(), ".config", "opencode", "skills"), source: "opencode" }
|
|
339620
339695
|
];
|
|
339621
339696
|
for (const entry of roots) {
|
|
339622
339697
|
for (const dir of this.findSkillDirs(entry.root, 4, 240)) {
|
|
339623
339698
|
const parsed = this.parseSkillInfo(dir);
|
|
339624
|
-
const name50 = this.cleanName(parsed.name ||
|
|
339699
|
+
const name50 = this.cleanName(parsed.name || path18.basename(dir));
|
|
339625
339700
|
if (!name50 || items.some((i4) => i4.name === name50 && i4.source !== "remote")) continue;
|
|
339626
339701
|
items.push({
|
|
339627
339702
|
name: name50,
|
|
@@ -339638,9 +339713,9 @@ var SkillsManager = class {
|
|
|
339638
339713
|
});
|
|
339639
339714
|
}
|
|
339640
339715
|
}
|
|
339641
|
-
for (const dir of this.findPluginSkillDirs(
|
|
339716
|
+
for (const dir of this.findPluginSkillDirs(path18.join(this.skillsDir, ".."), 5, 240)) {
|
|
339642
339717
|
const parsed = this.parseSkillInfo(dir);
|
|
339643
|
-
const name50 = this.cleanName(parsed.name ||
|
|
339718
|
+
const name50 = this.cleanName(parsed.name || path18.basename(dir));
|
|
339644
339719
|
if (!name50 || items.some((i4) => i4.name === name50 && i4.source !== "remote")) continue;
|
|
339645
339720
|
items.push({
|
|
339646
339721
|
name: name50,
|
|
@@ -339697,8 +339772,8 @@ var SkillsManager = class {
|
|
|
339697
339772
|
}
|
|
339698
339773
|
loadMeta() {
|
|
339699
339774
|
try {
|
|
339700
|
-
if (
|
|
339701
|
-
const raw = JSON.parse(
|
|
339775
|
+
if (fs16.existsSync(this.metaPath)) {
|
|
339776
|
+
const raw = JSON.parse(fs16.readFileSync(this.metaPath, "utf-8"));
|
|
339702
339777
|
return { disabled: Array.isArray(raw.disabled) ? raw.disabled.map(String) : [] };
|
|
339703
339778
|
}
|
|
339704
339779
|
} catch {
|
|
@@ -339706,7 +339781,7 @@ var SkillsManager = class {
|
|
|
339706
339781
|
return { disabled: [] };
|
|
339707
339782
|
}
|
|
339708
339783
|
saveMeta(meta) {
|
|
339709
|
-
|
|
339784
|
+
fs16.writeFileSync(this.metaPath, JSON.stringify({ disabled: meta.disabled }, null, 2), "utf-8");
|
|
339710
339785
|
}
|
|
339711
339786
|
builtinMarketSources() {
|
|
339712
339787
|
return [{
|
|
@@ -339720,8 +339795,8 @@ var SkillsManager = class {
|
|
|
339720
339795
|
}
|
|
339721
339796
|
loadMarketSources() {
|
|
339722
339797
|
try {
|
|
339723
|
-
if (!
|
|
339724
|
-
const raw = JSON.parse(
|
|
339798
|
+
if (!fs16.existsSync(this.marketSourcesPath)) return [];
|
|
339799
|
+
const raw = JSON.parse(fs16.readFileSync(this.marketSourcesPath, "utf-8"));
|
|
339725
339800
|
if (!Array.isArray(raw.sources)) return [];
|
|
339726
339801
|
return raw.sources.map((source) => this.normalizeMarketSource(source)).filter((source) => !!source);
|
|
339727
339802
|
} catch {
|
|
@@ -339730,7 +339805,7 @@ var SkillsManager = class {
|
|
|
339730
339805
|
}
|
|
339731
339806
|
saveMarketSources(sources) {
|
|
339732
339807
|
const normalized = sources.filter((s3) => !s3.builtin).map((s3) => this.normalizeMarketSource(s3)).filter((source) => !!source);
|
|
339733
|
-
|
|
339808
|
+
fs16.writeFileSync(this.marketSourcesPath, JSON.stringify({ sources: normalized }, null, 2), "utf-8");
|
|
339734
339809
|
}
|
|
339735
339810
|
normalizeMarketSource(raw) {
|
|
339736
339811
|
if (!raw || typeof raw !== "object") return null;
|
|
@@ -339750,7 +339825,7 @@ var SkillsManager = class {
|
|
|
339750
339825
|
type,
|
|
339751
339826
|
enabled: source.enabled !== false,
|
|
339752
339827
|
url: url || void 0,
|
|
339753
|
-
path: sourcePath ?
|
|
339828
|
+
path: sourcePath ? path18.resolve(sourcePath) : void 0,
|
|
339754
339829
|
builtin: source.builtin === true,
|
|
339755
339830
|
addedAt: source.addedAt ? String(source.addedAt) : void 0,
|
|
339756
339831
|
updatedAt: source.updatedAt ? String(source.updatedAt) : void 0
|
|
@@ -339801,11 +339876,11 @@ var SkillsManager = class {
|
|
|
339801
339876
|
return rawItems.slice(0, 1e3).map((entry) => this.marketInfoFromCatalogEntry(entry, source, installed)).filter((item) => !!item);
|
|
339802
339877
|
}
|
|
339803
339878
|
readCatalogText(source) {
|
|
339804
|
-
const catalogPath = source.path ?
|
|
339805
|
-
if (catalogPath &&
|
|
339879
|
+
const catalogPath = source.path ? path18.resolve(source.path) : "";
|
|
339880
|
+
if (catalogPath && fs16.existsSync(catalogPath)) return fs16.readFileSync(catalogPath, "utf-8");
|
|
339806
339881
|
const url = source.url || "";
|
|
339807
|
-
if (url.startsWith("file://")) return
|
|
339808
|
-
if (url && !url.startsWith("http")) return
|
|
339882
|
+
if (url.startsWith("file://")) return fs16.readFileSync(new URL(url), "utf-8");
|
|
339883
|
+
if (url && !url.startsWith("http")) return fs16.readFileSync(path18.resolve(url), "utf-8");
|
|
339809
339884
|
return "";
|
|
339810
339885
|
}
|
|
339811
339886
|
async discoverJsonMarketSourceAsync(source, installed) {
|
|
@@ -339865,7 +339940,7 @@ var SkillsManager = class {
|
|
|
339865
339940
|
}
|
|
339866
339941
|
marketInfoFromLocalDir(dir, source, installed) {
|
|
339867
339942
|
const parsed = this.parseSkillInfo(dir);
|
|
339868
|
-
const name50 = this.cleanName(parsed.name ||
|
|
339943
|
+
const name50 = this.cleanName(parsed.name || path18.basename(dir));
|
|
339869
339944
|
if (!name50) return null;
|
|
339870
339945
|
return {
|
|
339871
339946
|
name: name50,
|
|
@@ -339890,9 +339965,9 @@ var SkillsManager = class {
|
|
|
339890
339965
|
}
|
|
339891
339966
|
parseSkillInfo(dir) {
|
|
339892
339967
|
try {
|
|
339893
|
-
const skillPath =
|
|
339894
|
-
const stat =
|
|
339895
|
-
const content =
|
|
339968
|
+
const skillPath = path18.join(dir, "SKILL.md");
|
|
339969
|
+
const stat = fs16.statSync(skillPath);
|
|
339970
|
+
const content = fs16.readFileSync(skillPath, "utf-8");
|
|
339896
339971
|
const digest = (0, import_crypto9.createHash)("sha256").update(content).digest("hex");
|
|
339897
339972
|
const fingerprint2 = `${stat.mtimeMs}:${stat.size}:${digest}`;
|
|
339898
339973
|
const cached = this.metadataCache.get(skillPath);
|
|
@@ -339925,7 +340000,7 @@ var SkillsManager = class {
|
|
|
339925
340000
|
};
|
|
339926
340001
|
this.metadataCache.set(skillPath, {
|
|
339927
340002
|
fingerprint: fingerprint2,
|
|
339928
|
-
info: { ...parsed, path: dir, enabled: this.isEnabled(
|
|
340003
|
+
info: { ...parsed, path: dir, enabled: this.isEnabled(path18.basename(dir)), installed: true, source: "project" }
|
|
339929
340004
|
});
|
|
339930
340005
|
return parsed;
|
|
339931
340006
|
} catch {
|
|
@@ -339942,13 +340017,13 @@ var SkillsManager = class {
|
|
|
339942
340017
|
if (files.length >= limit || depth > 2) return;
|
|
339943
340018
|
let entries = [];
|
|
339944
340019
|
try {
|
|
339945
|
-
entries =
|
|
340020
|
+
entries = fs16.readdirSync(dir, { withFileTypes: true });
|
|
339946
340021
|
} catch {
|
|
339947
340022
|
return;
|
|
339948
340023
|
}
|
|
339949
340024
|
for (const entry of entries) {
|
|
339950
340025
|
if (files.length >= limit || entry.name === "SKILL.md" || entry.name.startsWith(".")) continue;
|
|
339951
|
-
const target =
|
|
340026
|
+
const target = path18.join(dir, entry.name);
|
|
339952
340027
|
if (entry.isDirectory()) walk4(target, depth + 1);
|
|
339953
340028
|
else if (entry.isFile()) files.push(target);
|
|
339954
340029
|
}
|
|
@@ -339962,7 +340037,7 @@ var SkillsManager = class {
|
|
|
339962
340037
|
if (results.length >= maxItems || depth > maxDepth) return;
|
|
339963
340038
|
let entries;
|
|
339964
340039
|
try {
|
|
339965
|
-
entries =
|
|
340040
|
+
entries = fs16.readdirSync(dir, { withFileTypes: true });
|
|
339966
340041
|
} catch {
|
|
339967
340042
|
return;
|
|
339968
340043
|
}
|
|
@@ -339972,7 +340047,7 @@ var SkillsManager = class {
|
|
|
339972
340047
|
}
|
|
339973
340048
|
for (const e3 of entries) {
|
|
339974
340049
|
if (!e3.isDirectory() || e3.name.startsWith(".git") || e3.name === "node_modules") continue;
|
|
339975
|
-
walk4(
|
|
340050
|
+
walk4(path18.join(dir, e3.name), depth + 1);
|
|
339976
340051
|
}
|
|
339977
340052
|
};
|
|
339978
340053
|
walk4(root2, 0);
|
|
@@ -339984,19 +340059,19 @@ var SkillsManager = class {
|
|
|
339984
340059
|
if (results.length >= maxItems || depth > maxDepth) return;
|
|
339985
340060
|
let entries;
|
|
339986
340061
|
try {
|
|
339987
|
-
entries =
|
|
340062
|
+
entries = fs16.readdirSync(dir, { withFileTypes: true });
|
|
339988
340063
|
} catch {
|
|
339989
340064
|
return;
|
|
339990
340065
|
}
|
|
339991
340066
|
const hasPluginManifest = entries.some((e3) => e3.isDirectory() && (e3.name === ".codex-plugin" || e3.name === ".claude-plugin"));
|
|
339992
340067
|
if (hasPluginManifest) {
|
|
339993
340068
|
for (const skillsDir of ["skills", "Skills"]) {
|
|
339994
|
-
results.push(...this.findSkillDirs(
|
|
340069
|
+
results.push(...this.findSkillDirs(path18.join(dir, skillsDir), 3, maxItems - results.length));
|
|
339995
340070
|
}
|
|
339996
340071
|
}
|
|
339997
340072
|
for (const e3 of entries) {
|
|
339998
340073
|
if (!e3.isDirectory() || e3.name.startsWith(".git") || e3.name === "node_modules" || e3.name === "release" || e3.name.startsWith("release.locked-")) continue;
|
|
339999
|
-
walk4(
|
|
340074
|
+
walk4(path18.join(dir, e3.name), depth + 1);
|
|
340000
340075
|
}
|
|
340001
340076
|
};
|
|
340002
340077
|
walk4(root2, 0);
|
|
@@ -340024,25 +340099,25 @@ var SkillsManager = class {
|
|
|
340024
340099
|
if (!description) warnings.push("Missing required frontmatter field: description.");
|
|
340025
340100
|
if (name50 && !/^[A-Za-z0-9][A-Za-z0-9_.:-]{0,119}$/.test(name50)) warnings.push("Skill name contains characters outside the portable Agent Skills subset.");
|
|
340026
340101
|
if (description && description.length > 1e3) warnings.push("Description is longer than recommended for skill discovery.");
|
|
340027
|
-
const folderName =
|
|
340102
|
+
const folderName = path18.basename(dir);
|
|
340028
340103
|
if (name50 && folderName && this.cleanName(name50) !== this.cleanName(folderName)) warnings.push("Skill name does not match containing folder name.");
|
|
340029
340104
|
return warnings;
|
|
340030
340105
|
}
|
|
340031
340106
|
pluginIdForSkill(dir) {
|
|
340032
|
-
let current =
|
|
340107
|
+
let current = path18.resolve(dir);
|
|
340033
340108
|
for (let i4 = 0; i4 < 6; i4++) {
|
|
340034
|
-
const codex =
|
|
340035
|
-
const claude =
|
|
340109
|
+
const codex = path18.join(current, ".codex-plugin", "plugin.json");
|
|
340110
|
+
const claude = path18.join(current, ".claude-plugin", "plugin.json");
|
|
340036
340111
|
for (const filePath of [codex, claude]) {
|
|
340037
340112
|
try {
|
|
340038
|
-
if (
|
|
340039
|
-
const raw = JSON.parse(
|
|
340113
|
+
if (fs16.existsSync(filePath)) {
|
|
340114
|
+
const raw = JSON.parse(fs16.readFileSync(filePath, "utf-8"));
|
|
340040
340115
|
if (raw?.name) return String(raw.name);
|
|
340041
340116
|
}
|
|
340042
340117
|
} catch {
|
|
340043
340118
|
}
|
|
340044
340119
|
}
|
|
340045
|
-
const parent =
|
|
340120
|
+
const parent = path18.dirname(current);
|
|
340046
340121
|
if (parent === current) break;
|
|
340047
340122
|
current = parent;
|
|
340048
340123
|
}
|
|
@@ -345070,7 +345145,7 @@ var Agent4 = class _Agent {
|
|
|
345070
345145
|
this.config.set("skills", "auto_download", "disabled");
|
|
345071
345146
|
}
|
|
345072
345147
|
const modeStr = this.config.getStr("agent", "default_mode");
|
|
345073
|
-
this.mode = ["plan", "goal", "flow"].includes(modeStr) ? modeStr : "build";
|
|
345148
|
+
this.mode = ["plan", "chat", "goal", "flow"].includes(modeStr) ? modeStr : "build";
|
|
345074
345149
|
const inputStr = this.config.getStr("general", "default_input");
|
|
345075
345150
|
this.inputMode = inputStr === "next" ? "next" : "guide";
|
|
345076
345151
|
const configuredModel = this.config.getStr("models", "default_model");
|
|
@@ -345238,6 +345313,7 @@ var Agent4 = class _Agent {
|
|
|
345238
345313
|
return this.toolchainCore;
|
|
345239
345314
|
}
|
|
345240
345315
|
setMode(m2) {
|
|
345316
|
+
if (!["build", "plan", "chat", "goal", "flow"].includes(m2)) m2 = "build";
|
|
345241
345317
|
if (m2 === "goal" && !this.goal) {
|
|
345242
345318
|
this.goal = new GoalStateImpl("Set your objective");
|
|
345243
345319
|
}
|
|
@@ -349605,7 +349681,20 @@ ${summary}`, segment, "local-summarize", true);
|
|
|
349605
349681
|
if (action === "get") return JSON.stringify({ ok: true, linkedPlan: this.getLinkedPlan() }, null, 2);
|
|
349606
349682
|
if (action !== "update") return JSON.stringify({ ok: false, error: `Unknown linked_plan action: ${action}` });
|
|
349607
349683
|
const expectedRevision = Number(input2.expected_revision ?? input2.expectedRevision);
|
|
349608
|
-
|
|
349684
|
+
const current = this.getLinkedPlan();
|
|
349685
|
+
let markdown = input2.markdown === void 0 ? current.markdown : String(input2.markdown);
|
|
349686
|
+
if (input2.append !== void 0) markdown = `${current.markdown}${String(input2.append)}`;
|
|
349687
|
+
if (input2.old_text !== void 0 || input2.oldText !== void 0) {
|
|
349688
|
+
const oldText = String(input2.old_text ?? input2.oldText ?? "");
|
|
349689
|
+
if (!oldText) throw new Error("linked_plan old_text must not be empty.");
|
|
349690
|
+
const matches = current.markdown.split(oldText).length - 1;
|
|
349691
|
+
if (!matches) throw new Error("linked_plan old_text was not found.");
|
|
349692
|
+
const replaceAll = input2.replace_all === true || input2.replaceAll === true;
|
|
349693
|
+
if (matches > 1 && !replaceAll) throw new Error(`linked_plan old_text matched ${matches} places; pass replace_all=true or a unique fragment.`);
|
|
349694
|
+
const newText = String(input2.new_text ?? input2.newText ?? "");
|
|
349695
|
+
markdown = replaceAll ? current.markdown.split(oldText).join(newText) : current.markdown.replace(oldText, newText);
|
|
349696
|
+
}
|
|
349697
|
+
return JSON.stringify({ ok: true, linkedPlan: this.updateLinkedPlan(markdown, expectedRevision) }, null, 2);
|
|
349609
349698
|
} catch (error) {
|
|
349610
349699
|
return JSON.stringify({ ok: false, error: error instanceof Error ? error.message : String(error) });
|
|
349611
349700
|
}
|
|
@@ -351907,7 +351996,24 @@ ${this.formatAutomation(item)}` : `[automation_toggle] Not found: ${id}`;
|
|
|
351907
351996
|
}));
|
|
351908
351997
|
}
|
|
351909
351998
|
case "memory_lab_update": {
|
|
351910
|
-
const
|
|
351999
|
+
const selector2 = String(params.component || params.slug || "").trim();
|
|
352000
|
+
const prepared = selector2 ? this.memoryLab.preparePatch({
|
|
352001
|
+
component: selector2,
|
|
352002
|
+
name: params.name === void 0 ? void 0 : String(params.name),
|
|
352003
|
+
description: params.description === void 0 ? void 0 : String(params.description),
|
|
352004
|
+
tags: params.tags === void 0 ? void 0 : Array.isArray(params.tags) ? params.tags.map(String) : String(params.tags).split(/[,,\n]+/),
|
|
352005
|
+
tagPaths: params.tagPaths === void 0 ? void 0 : Array.isArray(params.tagPaths) ? params.tagPaths.filter(Array.isArray).map((pathValue) => pathValue.map(String)) : [],
|
|
352006
|
+
content: params.content === void 0 ? void 0 : String(params.content),
|
|
352007
|
+
contentAppend: params.contentAppend === void 0 && params.content_append === void 0 ? void 0 : String(params.contentAppend ?? params.content_append),
|
|
352008
|
+
oldText: params.oldText === void 0 && params.old_text === void 0 ? void 0 : String(params.oldText ?? params.old_text),
|
|
352009
|
+
newText: String(params.newText ?? params.new_text ?? ""),
|
|
352010
|
+
replaceAll: params.replaceAll === true || params.replace_all === true,
|
|
352011
|
+
kind: params.kind === void 0 ? void 0 : params.kind === "folder" ? "folder" : "file",
|
|
352012
|
+
expectedUpdatedAt: String(params.expectedUpdatedAt || params.expected_updated_at || ""),
|
|
352013
|
+
reason: String(params.reason || ""),
|
|
352014
|
+
source: String(params.source || "")
|
|
352015
|
+
}) : void 0;
|
|
352016
|
+
const result = await this.updateMemoryLab(prepared || {
|
|
351911
352017
|
name: String(params.name || ""),
|
|
351912
352018
|
description: String(params.description || ""),
|
|
351913
352019
|
tags: Array.isArray(params.tags) ? params.tags.map(String) : String(params.tags || "").split(/[,,\n]+/),
|
|
@@ -352910,6 +353016,8 @@ When using file tools (read, write, edit, glob), use ABSOLUTE paths rooted at th
|
|
|
352910
353016
|
parts.push(this.buildFeatureDisclosurePrompt());
|
|
352911
353017
|
if (this.mode === "plan") parts.push(`[Plan Tool Policy]
|
|
352912
353018
|
${planModePolicyPrompt()}`);
|
|
353019
|
+
if (this.mode === "chat") parts.push(`[Chat Tool Policy]
|
|
353020
|
+
${chatModePolicyPrompt()}`);
|
|
352913
353021
|
const pm = this.config.getStr("workspace", "prompt_mode") || "both";
|
|
352914
353022
|
const injectedPrompts = /* @__PURE__ */ new Set();
|
|
352915
353023
|
if ((pm === "global_only" || pm === "both") && globalPrompt) {
|
|
@@ -353031,7 +353139,7 @@ ${custom}`);
|
|
|
353031
353139
|
`- Language policy: general.language=${language}; the UI can switch this at runtime and each turn must obey the current value. auto follows the user's dominant input language, en replies in English, zh replies in Simplified Chinese. Keep code, commands, file paths, JSON keys, model/provider names, tool names, quoted source text, and user-provided literals exactly as required by their source language.`,
|
|
353032
353140
|
`- Workspace permissions: access_permission=${permission}; file tools are checked before execution and blocked when they exceed the configured workspace boundary.`,
|
|
353033
353141
|
`- Remote repository safety: when the active workspace or any target path is inside a GitHub/remote-backed repository, proactively use repo_security_audit and file_audit before git_push, gh_pr_create, release packaging, public reporting, or cloud-side audit. Treat public remotes as public disclosure surfaces and keep private URLs, secrets, privacy addresses (credential URLs, private network addresses, local user paths), local runtime state, archives, Memory Lab, Work, config, and release outputs out of commits and summaries. git_push/gh_pr_create hard-block on detected high-risk findings until a second review resolves them and the action is retried with security_review_confirmed=true.`,
|
|
353034
|
-
`- Mode engine: current mode=${this.modeName()}; Build works autonomously, Plan is fully read-only
|
|
353142
|
+
`- Mode engine: current mode=${this.modeName()}; Build works autonomously, Plan is fully read-only, Chat only performs web search/fetch evidence gathering and prompt synthesis, Goal continues until completion unless paused, Flow follows saved workflow components.`,
|
|
353035
353143
|
`- Input mode: ${input2}; Guide injects immediately, Next queues user intent for the following build turn.`,
|
|
353036
353144
|
`- Option feedback: ${this.buildQuestionPolicyPrompt(optionFeedback)}`,
|
|
353037
353145
|
`- Model policy: current model=${this.model || "(unset)"}, intelligence=${this.intelligence}, auto-switch=${modelSwitch}.`,
|
|
@@ -353097,6 +353205,14 @@ ${custom}`);
|
|
|
353097
353205
|
'Only after the durable linked plan has actually been updated and the plan is complete, expose the fixed mode handoff asking whether execution should begin. Offer exactly these two choices in the user language: "\u662F\uFF0C\u6267\u884C\u6B64\u8BA1\u5212" / "\u5426\uFF0C\u8BF7\u8865\u5145____" (or "Yes, execute this plan" / "No, please supplement _____"). This fixed handoff remains required when discretionary questions are disabled.',
|
|
353098
353206
|
"A positive choice starts a new Build-mode input. A negative choice remains in Plan mode so the user can supply the missing details."
|
|
353099
353207
|
]).join("\n");
|
|
353208
|
+
case "chat":
|
|
353209
|
+
return withLanguage([
|
|
353210
|
+
"CHAT MODE.",
|
|
353211
|
+
"Use only web_search and web_fetch. You have no workspace, host, application, memory, task, browser-control, or write permissions.",
|
|
353212
|
+
"Perform an online search to gather evidence before answering. Fetch primary or authoritative pages when the search snippets are insufficient.",
|
|
353213
|
+
"After sufficient evidence is collected, summarize and answer the user as soon as possible. Stay concise and do not turn the request into a long-running Build, Plan, Goal, or Flow task.",
|
|
353214
|
+
"Distinguish sourced facts from uncertainty and include useful source links in the final answer."
|
|
353215
|
+
]).join("\n");
|
|
353100
353216
|
case "goal": {
|
|
353101
353217
|
const g2 = this.goal?.history() || "";
|
|
353102
353218
|
const paused = this.goal?.paused ? "\n[GOAL PAUSED by user. Wait for resume.]" : "\n[Continue working until the goal is achieved.]";
|