@odla-ai/cli 0.43.0 → 0.43.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -4
- package/dist/bin.cjs +275 -148
- package/dist/bin.cjs.map +1 -1
- package/dist/bin.js +1 -1
- package/dist/{chunk-WDWJ7HC7.js → chunk-T4OPSRME.js} +272 -145
- package/dist/chunk-T4OPSRME.js.map +1 -0
- package/dist/{cli-OITEPXW4.js → cli-3JOB4OUV.js} +2 -2
- package/dist/index.cjs +271 -144
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/skills/odla/SKILL.md +10 -3
- package/skills/odla/references/pm-work-intake.md +33 -11
- package/skills/odla/references/pm.md +23 -12
- package/dist/chunk-WDWJ7HC7.js.map +0 -1
- /package/dist/{cli-OITEPXW4.js.map → cli-3JOB4OUV.js.map} +0 -0
package/dist/index.cjs
CHANGED
|
@@ -452,10 +452,10 @@ function isManagedDevVar(line2) {
|
|
|
452
452
|
const match = line2.match(/^\s*(?:export\s+)?([A-Z][A-Z0-9_]*)\s*=/);
|
|
453
453
|
return !!match?.[1] && MANAGED_DEV_VARS.has(match[1]);
|
|
454
454
|
}
|
|
455
|
-
function writePrivateText(path,
|
|
455
|
+
function writePrivateText(path, text4) {
|
|
456
456
|
(0, import_node_fs4.mkdirSync)((0, import_node_path4.dirname)(path), { recursive: true });
|
|
457
457
|
const temporary = `${path}.tmp-${process.pid}-${Date.now()}`;
|
|
458
|
-
(0, import_node_fs4.writeFileSync)(temporary,
|
|
458
|
+
(0, import_node_fs4.writeFileSync)(temporary, text4, { mode: 384 });
|
|
459
459
|
(0, import_node_fs4.chmodSync)(temporary, 384);
|
|
460
460
|
(0, import_node_fs4.renameSync)(temporary, path);
|
|
461
461
|
}
|
|
@@ -895,12 +895,12 @@ async function readAdminAiAudit(request3) {
|
|
|
895
895
|
}
|
|
896
896
|
}
|
|
897
897
|
async function responseBody(response2) {
|
|
898
|
-
const
|
|
899
|
-
if (!
|
|
898
|
+
const text4 = await response2.text();
|
|
899
|
+
if (!text4) return {};
|
|
900
900
|
try {
|
|
901
|
-
return JSON.parse(
|
|
901
|
+
return JSON.parse(text4);
|
|
902
902
|
} catch {
|
|
903
|
-
return { message:
|
|
903
|
+
return { message: text4.slice(0, 300) };
|
|
904
904
|
}
|
|
905
905
|
}
|
|
906
906
|
function apiError(status, body) {
|
|
@@ -1002,12 +1002,12 @@ function timestamp2(value2) {
|
|
|
1002
1002
|
return Number.isFinite(date.valueOf()) ? date.toISOString() : "";
|
|
1003
1003
|
}
|
|
1004
1004
|
async function responseBody2(res) {
|
|
1005
|
-
const
|
|
1006
|
-
if (!
|
|
1005
|
+
const text4 = await res.text();
|
|
1006
|
+
if (!text4) return {};
|
|
1007
1007
|
try {
|
|
1008
|
-
return JSON.parse(
|
|
1008
|
+
return JSON.parse(text4);
|
|
1009
1009
|
} catch {
|
|
1010
|
-
return { message:
|
|
1010
|
+
return { message: text4.slice(0, 300) };
|
|
1011
1011
|
}
|
|
1012
1012
|
}
|
|
1013
1013
|
function apiError2(action2, status, body) {
|
|
@@ -1183,12 +1183,12 @@ function catalogModels(body) {
|
|
|
1183
1183
|
return body.catalog.models.filter((value2) => isRecord3(value2) && typeof value2.id === "string" && typeof value2.provider === "string");
|
|
1184
1184
|
}
|
|
1185
1185
|
async function responseBody3(res) {
|
|
1186
|
-
const
|
|
1187
|
-
if (!
|
|
1186
|
+
const text4 = await res.text();
|
|
1187
|
+
if (!text4) return {};
|
|
1188
1188
|
try {
|
|
1189
|
-
return JSON.parse(
|
|
1189
|
+
return JSON.parse(text4);
|
|
1190
1190
|
} catch {
|
|
1191
|
-
return { message:
|
|
1191
|
+
return { message: text4.slice(0, 300) };
|
|
1192
1192
|
}
|
|
1193
1193
|
}
|
|
1194
1194
|
function apiError3(action2, status, body) {
|
|
@@ -2557,8 +2557,8 @@ async function appImport(options) {
|
|
|
2557
2557
|
const out = options.stdout ?? console;
|
|
2558
2558
|
const say = options.json ? (line2) => out.error(line2) : (line2) => out.log(line2);
|
|
2559
2559
|
const { tenant } = resolveTenant(cfg, options.env);
|
|
2560
|
-
const
|
|
2561
|
-
const { format, sources } = (0, import_import.parseImport)(
|
|
2560
|
+
const text4 = options.file === "-" ? (options.readStdin ?? (() => (0, import_node_fs9.readFileSync)(0, "utf8")))() : (0, import_node_fs9.readFileSync)(options.file, "utf8");
|
|
2561
|
+
const { format, sources } = (0, import_import.parseImport)(text4, options.ns);
|
|
2562
2562
|
if (format === "namespace-map" && options.ns) {
|
|
2563
2563
|
throw new Error("--ns cannot be combined with a {namespace: rows} file \u2014 the file already names each namespace");
|
|
2564
2564
|
}
|
|
@@ -2769,7 +2769,7 @@ var EXTENSIONS = {
|
|
|
2769
2769
|
"text/html": "html",
|
|
2770
2770
|
"application/json": "json"
|
|
2771
2771
|
};
|
|
2772
|
-
var encode = (
|
|
2772
|
+
var encode = (text4) => new TextEncoder().encode(text4);
|
|
2773
2773
|
function assetFileName(uuid, mime) {
|
|
2774
2774
|
const ext = EXTENSIONS[mime.split(";")[0].trim().toLowerCase()] ?? "bin";
|
|
2775
2775
|
return `${uuid.replace(/[^a-zA-Z0-9._-]/g, "_")}.${ext}`;
|
|
@@ -3679,9 +3679,9 @@ async function assertTenantAdminAccess(doFetch, cfg, env, token) {
|
|
|
3679
3679
|
}
|
|
3680
3680
|
throw new Error(`${env}: tenant access preflight (${tenantId}) failed: ${res.status} ${await safeText5(res)}`);
|
|
3681
3681
|
}
|
|
3682
|
-
function errorCode(
|
|
3682
|
+
function errorCode(text4) {
|
|
3683
3683
|
try {
|
|
3684
|
-
const body = JSON.parse(
|
|
3684
|
+
const body = JSON.parse(text4);
|
|
3685
3685
|
return typeof body.error?.code === "string" ? body.error.code : null;
|
|
3686
3686
|
} catch {
|
|
3687
3687
|
return null;
|
|
@@ -4416,15 +4416,15 @@ function readWranglerConfig(path) {
|
|
|
4416
4416
|
return null;
|
|
4417
4417
|
}
|
|
4418
4418
|
}
|
|
4419
|
-
function stripJsonComments(
|
|
4419
|
+
function stripJsonComments(text4) {
|
|
4420
4420
|
let result = "";
|
|
4421
4421
|
let inString = false;
|
|
4422
|
-
for (let i = 0; i <
|
|
4423
|
-
const ch =
|
|
4422
|
+
for (let i = 0; i < text4.length; i++) {
|
|
4423
|
+
const ch = text4[i];
|
|
4424
4424
|
if (inString) {
|
|
4425
4425
|
result += ch;
|
|
4426
4426
|
if (ch === "\\") {
|
|
4427
|
-
result +=
|
|
4427
|
+
result += text4[i + 1] ?? "";
|
|
4428
4428
|
i++;
|
|
4429
4429
|
} else if (ch === '"') {
|
|
4430
4430
|
inString = false;
|
|
@@ -4436,14 +4436,14 @@ function stripJsonComments(text3) {
|
|
|
4436
4436
|
result += ch;
|
|
4437
4437
|
continue;
|
|
4438
4438
|
}
|
|
4439
|
-
if (ch === "/" &&
|
|
4440
|
-
while (i <
|
|
4439
|
+
if (ch === "/" && text4[i + 1] === "/") {
|
|
4440
|
+
while (i < text4.length && text4[i] !== "\n") i++;
|
|
4441
4441
|
result += "\n";
|
|
4442
4442
|
continue;
|
|
4443
4443
|
}
|
|
4444
|
-
if (ch === "/" &&
|
|
4444
|
+
if (ch === "/" && text4[i + 1] === "*") {
|
|
4445
4445
|
i += 2;
|
|
4446
|
-
while (i <
|
|
4446
|
+
while (i < text4.length && !(text4[i] === "*" && text4[i + 1] === "/")) i++;
|
|
4447
4447
|
i++;
|
|
4448
4448
|
continue;
|
|
4449
4449
|
}
|
|
@@ -4957,9 +4957,9 @@ function initProject(options) {
|
|
|
4957
4957
|
out.log("created src/odla/schema.mjs and src/odla/rules.mjs");
|
|
4958
4958
|
out.log("updated .gitignore for local odla credentials");
|
|
4959
4959
|
}
|
|
4960
|
-
function writeIfMissing(path,
|
|
4960
|
+
function writeIfMissing(path, text4) {
|
|
4961
4961
|
if ((0, import_node_fs14.existsSync)(path)) return;
|
|
4962
|
-
(0, import_node_fs14.writeFileSync)(path,
|
|
4962
|
+
(0, import_node_fs14.writeFileSync)(path, text4);
|
|
4963
4963
|
}
|
|
4964
4964
|
function configTemplate(input) {
|
|
4965
4965
|
const calendar = input.services.includes("calendar") ? ` calendar: {
|
|
@@ -5171,13 +5171,13 @@ async function secretsSetClerkKey(options) {
|
|
|
5171
5171
|
body: JSON.stringify({ value: value2 })
|
|
5172
5172
|
});
|
|
5173
5173
|
if (!res.ok) {
|
|
5174
|
-
const
|
|
5175
|
-
throw new Error(`store Clerk secret key failed (${res.status}): ${
|
|
5174
|
+
const text4 = scrubValue((await res.text().catch(() => "")).slice(0, 300), value2);
|
|
5175
|
+
throw new Error(`store Clerk secret key failed (${res.status}): ${text4 || "request failed"}`);
|
|
5176
5176
|
}
|
|
5177
5177
|
out.log(`Clerk secret key stored for ${tenantId} ($clerk_secret, reserved + write-only; the value was never echoed)`);
|
|
5178
5178
|
}
|
|
5179
|
-
function scrubValue(
|
|
5180
|
-
return redactSecrets(
|
|
5179
|
+
function scrubValue(text4, value2) {
|
|
5180
|
+
return redactSecrets(text4).split(value2).join("[value redacted]");
|
|
5181
5181
|
}
|
|
5182
5182
|
async function resolveVaultWrite(options) {
|
|
5183
5183
|
const out = options.stdout ?? console;
|
|
@@ -5469,8 +5469,8 @@ ${conflicts.map((f) => ` - ${f}`).join("\n")}`
|
|
|
5469
5469
|
harnesses: installations
|
|
5470
5470
|
};
|
|
5471
5471
|
}
|
|
5472
|
-
function pathsUnder(root,
|
|
5473
|
-
return [...
|
|
5472
|
+
function pathsUnder(root, paths2) {
|
|
5473
|
+
return [...paths2].map((path) => (0, import_node_path15.relative)(root, path)).filter((path) => path !== ".." && !path.startsWith(`..${import_node_path15.sep}`) && !(0, import_node_path15.isAbsolute)(path)).sort();
|
|
5474
5474
|
}
|
|
5475
5475
|
function normalizeHarnesses(values, global) {
|
|
5476
5476
|
const requested = values?.length ? values : ["claude"];
|
|
@@ -5899,10 +5899,10 @@ var import_node_fs16 = require("fs");
|
|
|
5899
5899
|
var import_node_os5 = require("os");
|
|
5900
5900
|
var import_node_path16 = require("path");
|
|
5901
5901
|
|
|
5902
|
-
// ../harness/dist/chunk-
|
|
5902
|
+
// ../harness/dist/chunk-RXNHCGWE.js
|
|
5903
5903
|
var HARNESS_PROTOCOL_VERSION = 1;
|
|
5904
5904
|
|
|
5905
|
-
// ../harness/dist/chunk-
|
|
5905
|
+
// ../harness/dist/chunk-CR6RE3A2.js
|
|
5906
5906
|
var import_child_process = require("child_process");
|
|
5907
5907
|
var import_fs = require("fs");
|
|
5908
5908
|
var import_promises2 = require("fs/promises");
|
|
@@ -6154,12 +6154,12 @@ async function gitSourceFiles(sourceDir, maxFiles, maxBytes) {
|
|
|
6154
6154
|
});
|
|
6155
6155
|
if (outputBytes > 8 * 1024 * 1024) throw new Error("git file inventory exceeds 8 MiB");
|
|
6156
6156
|
if (code !== 0) throw new Error(`git file inventory failed: ${Buffer.concat(stderr2).toString("utf8").slice(0, 1e3)}`);
|
|
6157
|
-
const
|
|
6158
|
-
if (
|
|
6157
|
+
const paths2 = Buffer.concat(stdout).toString("utf8").split("\0").filter(Boolean).sort();
|
|
6158
|
+
if (paths2.length > maxFiles) throw new Error(`workspace exceeds ${maxFiles} files`);
|
|
6159
6159
|
const root = (0, import_path4.resolve)(sourceDir);
|
|
6160
6160
|
const files = [];
|
|
6161
6161
|
let bytes = 0;
|
|
6162
|
-
for (const relativePath of
|
|
6162
|
+
for (const relativePath of paths2) {
|
|
6163
6163
|
if (!allowedWorkspacePath(relativePath)) continue;
|
|
6164
6164
|
const source = (0, import_path4.resolve)(root, relativePath);
|
|
6165
6165
|
if (!source.startsWith(`${root}${import_path4.sep}`)) throw new TypeError("git file path escapes workspace");
|
|
@@ -6275,7 +6275,7 @@ async function stageWorkspacePair(baselineSource, workspaceSource, options = {})
|
|
|
6275
6275
|
}
|
|
6276
6276
|
}
|
|
6277
6277
|
|
|
6278
|
-
// ../harness/dist/chunk-
|
|
6278
|
+
// ../harness/dist/chunk-ISR434K7.js
|
|
6279
6279
|
var import_crypto = require("crypto");
|
|
6280
6280
|
var import_promises5 = require("fs/promises");
|
|
6281
6281
|
var import_path5 = require("path");
|
|
@@ -6598,13 +6598,13 @@ function validateSnapshot(snapshot, limits) {
|
|
|
6598
6598
|
if (!Number.isSafeInteger(limits.maximumFiles) || limits.maximumFiles < 1 || !Number.isSafeInteger(limits.maximumBytes) || limits.maximumBytes < 1 || snapshot.files.length > limits.maximumFiles) {
|
|
6599
6599
|
throw new CamelError("limit_exceeded", "Code snapshot exceeds its registered limits.");
|
|
6600
6600
|
}
|
|
6601
|
-
const
|
|
6601
|
+
const paths2 = /* @__PURE__ */ new Set();
|
|
6602
6602
|
let bytes = 0;
|
|
6603
6603
|
for (const file of snapshot.files) {
|
|
6604
|
-
if (!file.path || file.path.startsWith("/") || file.path.includes("\\") || file.path.split("/").some((part) => !part || part === "." || part === "..") ||
|
|
6604
|
+
if (!file.path || file.path.startsWith("/") || file.path.includes("\\") || file.path.split("/").some((part) => !part || part === "." || part === "..") || paths2.has(file.path) || typeof file.content !== "string") {
|
|
6605
6605
|
throw new CamelError("state_conflict", "Code snapshot contains an invalid or duplicate path.");
|
|
6606
6606
|
}
|
|
6607
|
-
|
|
6607
|
+
paths2.add(file.path);
|
|
6608
6608
|
bytes += utf8Length(file.path) + utf8Length(file.content);
|
|
6609
6609
|
}
|
|
6610
6610
|
if (bytes > limits.maximumBytes) {
|
|
@@ -6612,7 +6612,7 @@ function validateSnapshot(snapshot, limits) {
|
|
|
6612
6612
|
}
|
|
6613
6613
|
}
|
|
6614
6614
|
|
|
6615
|
-
// ../harness/dist/chunk-
|
|
6615
|
+
// ../harness/dist/chunk-ISR434K7.js
|
|
6616
6616
|
var import_child_process4 = require("child_process");
|
|
6617
6617
|
var import_promises6 = require("fs/promises");
|
|
6618
6618
|
var import_path6 = require("path");
|
|
@@ -6755,8 +6755,8 @@ function boundedInteger(value2, spec) {
|
|
|
6755
6755
|
}
|
|
6756
6756
|
function boundedNumber(value2, spec) {
|
|
6757
6757
|
if (spec.kind !== "finite_number" || typeof value2 !== "number" || !Number.isFinite(value2) || value2 < spec.minimum || value2 > spec.maximum) throw new CamelError("conversion_rejected", "Finite-number conversion rejected the structured value.");
|
|
6758
|
-
const
|
|
6759
|
-
if (/e/i.test(
|
|
6758
|
+
const text4 = String(value2);
|
|
6759
|
+
if (/e/i.test(text4) || (text4.split(".")[1]?.length ?? 0) > spec.maximumDecimalPlaces) throw new CamelError("conversion_rejected", "Finite-number conversion rejected a non-canonical decimal.");
|
|
6760
6760
|
return value2;
|
|
6761
6761
|
}
|
|
6762
6762
|
function enumMember(value2, spec) {
|
|
@@ -6912,11 +6912,11 @@ function validateUnsafeSelector(path, value2, tool) {
|
|
|
6912
6912
|
return void 0;
|
|
6913
6913
|
}
|
|
6914
6914
|
function looksLikeDestination(value2) {
|
|
6915
|
-
const
|
|
6916
|
-
return /^(?:[a-z][a-z0-9+.-]*:\/\/|\/|\\\\)/i.test(
|
|
6915
|
+
const text4 = value2.trim();
|
|
6916
|
+
return /^(?:[a-z][a-z0-9+.-]*:\/\/|\/|\\\\)/i.test(text4) || /^[\w.-]+\.[a-z]{2,}(?:[/:]|$)/i.test(text4);
|
|
6917
6917
|
}
|
|
6918
6918
|
|
|
6919
|
-
// ../harness/dist/chunk-
|
|
6919
|
+
// ../harness/dist/chunk-ISR434K7.js
|
|
6920
6920
|
var import_promises10 = require("fs/promises");
|
|
6921
6921
|
var import_promises11 = require("fs/promises");
|
|
6922
6922
|
var import_path10 = require("path");
|
|
@@ -7081,9 +7081,9 @@ async function extractImports(builder, input) {
|
|
|
7081
7081
|
const sources = input.paths.filter(isSourcePath);
|
|
7082
7082
|
const known = new Set(sources);
|
|
7083
7083
|
for (const path of sources) {
|
|
7084
|
-
let
|
|
7084
|
+
let text4;
|
|
7085
7085
|
try {
|
|
7086
|
-
|
|
7086
|
+
text4 = await input.read(path);
|
|
7087
7087
|
} catch {
|
|
7088
7088
|
continue;
|
|
7089
7089
|
}
|
|
@@ -7091,13 +7091,13 @@ async function extractImports(builder, input) {
|
|
|
7091
7091
|
const file = builder.node(FILE, path, pkg ? { pkg } : void 0);
|
|
7092
7092
|
if (pkg) builder.edge(builder.node(PACKAGE, pkg), CONTAINS, file);
|
|
7093
7093
|
const specifiers = /* @__PURE__ */ new Set();
|
|
7094
|
-
for (const match of
|
|
7095
|
-
for (const match of
|
|
7094
|
+
for (const match of text4.matchAll(IMPORT_FROM)) specifiers.add(match[1]);
|
|
7095
|
+
for (const match of text4.matchAll(BARE_IMPORT)) specifiers.add(match[1]);
|
|
7096
7096
|
for (const specifier of specifiers) {
|
|
7097
7097
|
const resolved = resolveImport(path, specifier, known);
|
|
7098
7098
|
if (resolved) builder.edge(file, IMPORTS, nodeId(FILE, resolved));
|
|
7099
7099
|
}
|
|
7100
|
-
for (const name of exportedNames(
|
|
7100
|
+
for (const name of exportedNames(text4)) {
|
|
7101
7101
|
builder.edge(file, EXPORTS, builder.node(SYMBOL, name));
|
|
7102
7102
|
}
|
|
7103
7103
|
}
|
|
@@ -7138,16 +7138,16 @@ async function extractData(builder, input) {
|
|
|
7138
7138
|
};
|
|
7139
7139
|
for (const path of input.paths) {
|
|
7140
7140
|
if (!SOURCE_FILE.test(path) || input.ignore?.(path)) continue;
|
|
7141
|
-
let
|
|
7141
|
+
let text4;
|
|
7142
7142
|
try {
|
|
7143
|
-
|
|
7143
|
+
text4 = await input.read(path);
|
|
7144
7144
|
} catch {
|
|
7145
7145
|
continue;
|
|
7146
7146
|
}
|
|
7147
|
-
for (const statement of
|
|
7147
|
+
for (const statement of text4.matchAll(STATEMENT)) {
|
|
7148
7148
|
const verb = statement[1].toUpperCase().replace(/\s+/g, " ");
|
|
7149
7149
|
const start = statement.index ?? 0;
|
|
7150
|
-
const rest =
|
|
7150
|
+
const rest = text4.slice(start + statement[0].length, start + STATEMENT_WINDOW);
|
|
7151
7151
|
if (verb === "SELECT") {
|
|
7152
7152
|
for (const read3 of rest.matchAll(READ_TABLES)) touch(path, read3[1].toLowerCase(), TABLE, READS);
|
|
7153
7153
|
continue;
|
|
@@ -7163,16 +7163,16 @@ async function extractData(builder, input) {
|
|
|
7163
7163
|
for (const read3 of rest.matchAll(READ_TABLES)) touch(path, read3[1].toLowerCase(), TABLE, READS);
|
|
7164
7164
|
}
|
|
7165
7165
|
}
|
|
7166
|
-
for (const match of
|
|
7167
|
-
touch(path, `${match[1]}.${match[2]}`, NAMESPACE, accessFor(
|
|
7166
|
+
for (const match of text4.matchAll(NS_CONST)) {
|
|
7167
|
+
touch(path, `${match[1]}.${match[2]}`, NAMESPACE, accessFor(text4, match.index ?? 0));
|
|
7168
7168
|
}
|
|
7169
|
-
for (const match of
|
|
7170
|
-
touch(path, match[1], NAMESPACE, accessFor(
|
|
7169
|
+
for (const match of text4.matchAll(NS_LITERAL)) {
|
|
7170
|
+
touch(path, match[1], NAMESPACE, accessFor(text4, match.index ?? 0));
|
|
7171
7171
|
}
|
|
7172
7172
|
}
|
|
7173
7173
|
}
|
|
7174
|
-
function accessFor(
|
|
7175
|
-
const window =
|
|
7174
|
+
function accessFor(text4, index) {
|
|
7175
|
+
const window = text4.slice(Math.max(0, index - 160), index + 40);
|
|
7176
7176
|
return /\b(?:transact|update|delete|create|insert|Ops)\b/.test(window) ? WRITES : READS;
|
|
7177
7177
|
}
|
|
7178
7178
|
async function buildCodeGraph(input) {
|
|
@@ -7184,7 +7184,7 @@ async function buildCodeGraph(input) {
|
|
|
7184
7184
|
return builder.build();
|
|
7185
7185
|
}
|
|
7186
7186
|
|
|
7187
|
-
// ../harness/dist/chunk-
|
|
7187
|
+
// ../harness/dist/chunk-ISR434K7.js
|
|
7188
7188
|
var import_crypto4 = require("crypto");
|
|
7189
7189
|
async function digestStagedWorkspace(root, limits) {
|
|
7190
7190
|
const files = [];
|
|
@@ -7512,7 +7512,7 @@ function validateCodePatch(rawPatch, maxBytes) {
|
|
|
7512
7512
|
if (FORBIDDEN.test(patch2) || /(?:old|new)(?: file)? mode 120000/.test(patch2)) {
|
|
7513
7513
|
throw new TypeError("patch uses a forbidden binary, link, mode, rename, or copy operation");
|
|
7514
7514
|
}
|
|
7515
|
-
const
|
|
7515
|
+
const paths2 = [];
|
|
7516
7516
|
const lines = patch2.split("\n");
|
|
7517
7517
|
for (let index = 0; index < lines.length; index += 1) {
|
|
7518
7518
|
const line2 = lines[index];
|
|
@@ -7528,10 +7528,10 @@ function validateCodePatch(rawPatch, maxBytes) {
|
|
|
7528
7528
|
if (!validHeaderPath(oldPath, path, "a") || !validHeaderPath(newPath, path, "b")) {
|
|
7529
7529
|
throw new TypeError("patch file headers do not match the declared path");
|
|
7530
7530
|
}
|
|
7531
|
-
|
|
7531
|
+
paths2.push(path);
|
|
7532
7532
|
}
|
|
7533
|
-
if (!
|
|
7534
|
-
return
|
|
7533
|
+
if (!paths2.length || new Set(paths2).size !== paths2.length) throw new TypeError("patch has no diffs or repeats a path");
|
|
7534
|
+
return paths2;
|
|
7535
7535
|
}
|
|
7536
7536
|
function validHeaderPath(value2, path, prefix) {
|
|
7537
7537
|
return value2 === "/dev/null" || value2 === `${prefix}/${path}`;
|
|
@@ -7556,11 +7556,11 @@ function describePatchFailure(patch2, detail) {
|
|
|
7556
7556
|
const hint = hunks.length > 0 && contextless ? " A hunk has no context lines; include at least one unchanged line above or below each change." : "";
|
|
7557
7557
|
return `patch did not apply: ${detail}${hint}`;
|
|
7558
7558
|
}
|
|
7559
|
-
async function applyCodePatch(workspaceDir, rawPatch,
|
|
7559
|
+
async function applyCodePatch(workspaceDir, rawPatch, paths2) {
|
|
7560
7560
|
const patch2 = stripPatchEnvelope(rawPatch);
|
|
7561
7561
|
await gitApply(workspaceDir, patch2, true);
|
|
7562
7562
|
await gitApply(workspaceDir, patch2, false);
|
|
7563
|
-
for (const path of
|
|
7563
|
+
for (const path of paths2) {
|
|
7564
7564
|
try {
|
|
7565
7565
|
const info = await (0, import_promises6.lstat)(resolveCodePath(workspaceDir, path));
|
|
7566
7566
|
if (info.isSymbolicLink() || !info.isFile() && !info.isDirectory()) {
|
|
@@ -7582,8 +7582,8 @@ function gitApply(cwd, patch2, check) {
|
|
|
7582
7582
|
});
|
|
7583
7583
|
let stderr2 = "";
|
|
7584
7584
|
child.stderr.setEncoding("utf8");
|
|
7585
|
-
child.stderr.on("data", (
|
|
7586
|
-
if (stderr2.length < 4e3) stderr2 +=
|
|
7585
|
+
child.stderr.on("data", (text22) => {
|
|
7586
|
+
if (stderr2.length < 4e3) stderr2 += text22.slice(0, 4e3);
|
|
7587
7587
|
});
|
|
7588
7588
|
child.once("error", reject);
|
|
7589
7589
|
child.once("exit", (code) => code === 0 ? accept() : reject(new TypeError(describePatchFailure(patch2, stderr2.trim().slice(0, 500)))));
|
|
@@ -7607,8 +7607,8 @@ async function restoreCodeWorkspaceCheckpoint(input) {
|
|
|
7607
7607
|
const workspace = await stageWorkspace(input.trustedBaseDir, input.stage);
|
|
7608
7608
|
try {
|
|
7609
7609
|
if (checkpoint.patch) {
|
|
7610
|
-
const
|
|
7611
|
-
await applyCodePatch(workspace.workspaceDir, checkpoint.patch,
|
|
7610
|
+
const paths2 = validateCodePatch(checkpoint.patch, 256 * 1024);
|
|
7611
|
+
await applyCodePatch(workspace.workspaceDir, checkpoint.patch, paths2);
|
|
7612
7612
|
}
|
|
7613
7613
|
return { workspace, checkpoint };
|
|
7614
7614
|
} catch (error) {
|
|
@@ -7757,8 +7757,8 @@ async function verifyCodeCandidate(input) {
|
|
|
7757
7757
|
try {
|
|
7758
7758
|
const baseDigest = await digestStagedWorkspace(staged.workspaceDir, limits);
|
|
7759
7759
|
if (baseDigest !== input.trustedBaseDigest) throw new TypeError("trusted base does not match its registered digest");
|
|
7760
|
-
const
|
|
7761
|
-
await applyCodePatch(staged.workspaceDir, input.candidatePatch,
|
|
7760
|
+
const paths2 = validateCodePatch(input.candidatePatch, policy.maximumPatchBytes);
|
|
7761
|
+
await applyCodePatch(staged.workspaceDir, input.candidatePatch, paths2);
|
|
7762
7762
|
const sourceDigest = await digestStagedWorkspace(staged.workspaceDir, limits);
|
|
7763
7763
|
const policyDigest = digestPolicy(policy);
|
|
7764
7764
|
const patchDigest = digestBytes(input.candidatePatch);
|
|
@@ -7767,7 +7767,7 @@ async function verifyCodeCandidate(input) {
|
|
|
7767
7767
|
trustedBaseDigest: input.trustedBaseDigest,
|
|
7768
7768
|
patchDigest
|
|
7769
7769
|
});
|
|
7770
|
-
const changedTests = changedTestPaths(
|
|
7770
|
+
const changedTests = changedTestPaths(paths2, policy);
|
|
7771
7771
|
if (changedTests.length > policy.maximumChangedTests) throw new TypeError("candidate changes too many test files");
|
|
7772
7772
|
const recipes = [];
|
|
7773
7773
|
const logs = [];
|
|
@@ -7834,8 +7834,8 @@ function validate2(input) {
|
|
|
7834
7834
|
}
|
|
7835
7835
|
return result;
|
|
7836
7836
|
}
|
|
7837
|
-
function changedTestPaths(
|
|
7838
|
-
return
|
|
7837
|
+
function changedTestPaths(paths2, policy) {
|
|
7838
|
+
return paths2.filter((path) => policy.testPathSuffixes.some((suffix) => path.endsWith(suffix)) || policy.testPathPrefixes.some((prefix) => path.startsWith(prefix) || path.includes(`/${prefix}`))).sort();
|
|
7839
7839
|
}
|
|
7840
7840
|
function recipeReceipt(recipe2, result, artifacts) {
|
|
7841
7841
|
const status = result.timedOut ? "timed_out" : result.outputLimitExceeded ? "output_limited" : result.exitCode === 0 && artifacts.every((item) => item.status === "verified") ? "passed" : "failed";
|
|
@@ -8566,7 +8566,7 @@ function createWorkspaceFileRegistry(limit = DEFAULT_MAX_FILES, enumerate = regi
|
|
|
8566
8566
|
files(root) {
|
|
8567
8567
|
const existing = cache2.get(root);
|
|
8568
8568
|
if (existing) return existing;
|
|
8569
|
-
const pending = enumerate(root, limit).then((
|
|
8569
|
+
const pending = enumerate(root, limit).then((paths2) => Object.freeze(paths2));
|
|
8570
8570
|
cache2.set(root, pending);
|
|
8571
8571
|
void pending.catch(() => {
|
|
8572
8572
|
if (cache2.get(root) === pending) cache2.delete(root);
|
|
@@ -8579,7 +8579,7 @@ function createWorkspaceFileRegistry(limit = DEFAULT_MAX_FILES, enumerate = regi
|
|
|
8579
8579
|
};
|
|
8580
8580
|
}
|
|
8581
8581
|
async function registeredFiles(root, limit = DEFAULT_MAX_FILES) {
|
|
8582
|
-
const
|
|
8582
|
+
const paths2 = [];
|
|
8583
8583
|
const walk = async (directory) => {
|
|
8584
8584
|
for (const entry of await (0, import_promises9.readdir)(directory, { withFileTypes: true })) {
|
|
8585
8585
|
if (SKIP_WORKSPACE_DIRS.has(entry.name)) continue;
|
|
@@ -8593,26 +8593,26 @@ async function registeredFiles(root, limit = DEFAULT_MAX_FILES) {
|
|
|
8593
8593
|
} catch {
|
|
8594
8594
|
continue;
|
|
8595
8595
|
}
|
|
8596
|
-
|
|
8597
|
-
if (
|
|
8596
|
+
paths2.push(path);
|
|
8597
|
+
if (paths2.length > limit) throw new TypeError("workspace file registry exceeds its bound");
|
|
8598
8598
|
}
|
|
8599
8599
|
}
|
|
8600
8600
|
};
|
|
8601
8601
|
await walk((0, import_path9.resolve)(root));
|
|
8602
|
-
return
|
|
8602
|
+
return paths2.sort();
|
|
8603
8603
|
}
|
|
8604
|
-
function listWorkspace(
|
|
8604
|
+
function listWorkspace(paths2, options = {}) {
|
|
8605
8605
|
const max = options.maxEntries ?? 1e3;
|
|
8606
8606
|
const prefix = options.prefix?.replace(/\/+$/, "");
|
|
8607
|
-
const scoped = prefix ?
|
|
8607
|
+
const scoped = prefix ? paths2.filter((path) => path === prefix || path.startsWith(`${prefix}/`)) : [...paths2];
|
|
8608
8608
|
return scoped.slice(0, max);
|
|
8609
8609
|
}
|
|
8610
|
-
async function searchWorkspace(root,
|
|
8610
|
+
async function searchWorkspace(root, paths2, options) {
|
|
8611
8611
|
options.signal?.throwIfAborted();
|
|
8612
8612
|
if (!options.query) throw new TypeError("search query must be a non-empty string");
|
|
8613
8613
|
const maxResults = options.maxResults ?? DEFAULT_MAX_RESULTS;
|
|
8614
8614
|
const maxFileBytes = options.maxFileBytes ?? DEFAULT_MAX_FILE_BYTES;
|
|
8615
|
-
const scoped = listWorkspace(
|
|
8615
|
+
const scoped = listWorkspace(paths2, { ...options.prefix ? { prefix: options.prefix } : {}, maxEntries: paths2.length });
|
|
8616
8616
|
if (scoped.length === 0) return [];
|
|
8617
8617
|
try {
|
|
8618
8618
|
return await nativeSearch(root, scoped, { ...options, maxResults, maxFileBytes });
|
|
@@ -8622,11 +8622,11 @@ async function searchWorkspace(root, paths, options) {
|
|
|
8622
8622
|
}
|
|
8623
8623
|
}
|
|
8624
8624
|
var MAX_NATIVE_ARG_BYTES = 96 * 1024;
|
|
8625
|
-
async function nativeSearch(root,
|
|
8625
|
+
async function nativeSearch(root, paths2, options) {
|
|
8626
8626
|
const batches = [];
|
|
8627
8627
|
let batch = [];
|
|
8628
8628
|
let bytes = 0;
|
|
8629
|
-
for (const path of
|
|
8629
|
+
for (const path of paths2) {
|
|
8630
8630
|
const size = Buffer.byteLength(path) + 1;
|
|
8631
8631
|
if (batch.length > 0 && bytes + size > MAX_NATIVE_ARG_BYTES) {
|
|
8632
8632
|
batches.push(batch);
|
|
@@ -8645,7 +8645,7 @@ async function nativeSearch(root, paths, options) {
|
|
|
8645
8645
|
}
|
|
8646
8646
|
return matches;
|
|
8647
8647
|
}
|
|
8648
|
-
function nativeSearchBatch(root,
|
|
8648
|
+
function nativeSearchBatch(root, paths2, options, remaining) {
|
|
8649
8649
|
return new Promise((resolveMatches, reject) => {
|
|
8650
8650
|
const args = [
|
|
8651
8651
|
"--fixed-strings",
|
|
@@ -8658,7 +8658,7 @@ function nativeSearchBatch(root, paths, options, remaining) {
|
|
|
8658
8658
|
options.caseSensitive === false ? "--ignore-case" : "--case-sensitive",
|
|
8659
8659
|
"--",
|
|
8660
8660
|
options.query,
|
|
8661
|
-
...
|
|
8661
|
+
...paths2
|
|
8662
8662
|
];
|
|
8663
8663
|
const child = (0, import_child_process6.spawn)("rg", args, {
|
|
8664
8664
|
cwd: root,
|
|
@@ -8844,16 +8844,16 @@ function createCodePolicyGate(options) {
|
|
|
8844
8844
|
}
|
|
8845
8845
|
};
|
|
8846
8846
|
}
|
|
8847
|
-
function directoryPrefixes(
|
|
8847
|
+
function directoryPrefixes(paths2) {
|
|
8848
8848
|
const prefixes = /* @__PURE__ */ new Set(["."]);
|
|
8849
|
-
for (const path of
|
|
8849
|
+
for (const path of paths2) {
|
|
8850
8850
|
const parts = path.split("/");
|
|
8851
8851
|
for (let index = 1; index < parts.length; index += 1) prefixes.add(parts.slice(0, index).join("/"));
|
|
8852
8852
|
}
|
|
8853
8853
|
return [...prefixes].sort();
|
|
8854
8854
|
}
|
|
8855
|
-
async function safePrefix(base,
|
|
8856
|
-
const prefixes = directoryPrefixes(
|
|
8855
|
+
async function safePrefix(base, paths2, prefix) {
|
|
8856
|
+
const prefixes = directoryPrefixes(paths2);
|
|
8857
8857
|
const conversions = await conversionRegistry(
|
|
8858
8858
|
[await registeredPolicy("code.prefix.v1", "code.prefixes.v1", prefixes)],
|
|
8859
8859
|
{ "code.prefixes.v1": prefixes }
|
|
@@ -8965,7 +8965,7 @@ function response(request3, ok, content2, details) {
|
|
|
8965
8965
|
return { requestId: request3.requestId, ok, content: content2, ...details ? { details } : {} };
|
|
8966
8966
|
}
|
|
8967
8967
|
var cache = /* @__PURE__ */ new Map();
|
|
8968
|
-
function workspaceGraphs(workspaceDir,
|
|
8968
|
+
function workspaceGraphs(workspaceDir, paths2) {
|
|
8969
8969
|
const existing = cache.get(workspaceDir);
|
|
8970
8970
|
if (existing) return existing;
|
|
8971
8971
|
const read22 = (path) => (0, import_promises11.readFile)((0, import_path10.join)(workspaceDir, path), "utf8");
|
|
@@ -8973,7 +8973,7 @@ function workspaceGraphs(workspaceDir, paths) {
|
|
|
8973
8973
|
// No knownTables: a staged workspace may not carry migrations, and a filter
|
|
8974
8974
|
// that silently drops every table is worse than an unfiltered one. Callers
|
|
8975
8975
|
// with ground truth should build the graph themselves.
|
|
8976
|
-
graph: await buildCodeGraph({ paths, read: read22, data: { ignore: (path) => path.includes(".generated.") } })
|
|
8976
|
+
graph: await buildCodeGraph({ paths: paths2, read: read22, data: { ignore: (path) => path.includes(".generated.") } })
|
|
8977
8977
|
}))();
|
|
8978
8978
|
cache.set(workspaceDir, built);
|
|
8979
8979
|
return built;
|
|
@@ -9033,11 +9033,11 @@ async function read(context, request3, options, policy, registry) {
|
|
|
9033
9033
|
if (endLine < startLine || endLine - startLine + 1 > (options.maxReadLines ?? 2e3)) {
|
|
9034
9034
|
throw new TypeError("requested line range exceeds its bound");
|
|
9035
9035
|
}
|
|
9036
|
-
const
|
|
9037
|
-
if (!
|
|
9036
|
+
const paths2 = await registry.files(context.workspaceDir);
|
|
9037
|
+
if (!paths2.includes(path)) {
|
|
9038
9038
|
throw new TypeError(`no such file in the staged workspace: "${path}". Use sandbox.overview, sandbox.where_is or sandbox.search to find the correct path.`);
|
|
9039
9039
|
}
|
|
9040
|
-
const allowed = await policy.read(policyContext(context, request3, options, { paths, path, startLine, endLine }));
|
|
9040
|
+
const allowed = await policy.read(policyContext(context, request3, options, { paths: paths2, path, startLine, endLine }));
|
|
9041
9041
|
if (!allowed) return response(request3, false, "tool denied by CaMeL policy");
|
|
9042
9042
|
const target = resolveCodePath(context.workspaceDir, path);
|
|
9043
9043
|
const info = await (0, import_promises10.stat)(target);
|
|
@@ -9059,16 +9059,16 @@ async function list(context, request3, options, policy, registry) {
|
|
|
9059
9059
|
const prefix = typeof raw === "string" && raw.length > 0 ? raw : void 0;
|
|
9060
9060
|
const maxEntries = optionalInteger(request3.input.maxEntries) ?? 1e3;
|
|
9061
9061
|
if (maxEntries > 5e3) throw new TypeError("maxEntries exceeds its bound");
|
|
9062
|
-
const
|
|
9063
|
-
const allowed = await policy.list(policyContext(context, request3, options, { paths, ...prefix ? { prefix } : {} }));
|
|
9062
|
+
const paths2 = await registry.files(context.workspaceDir);
|
|
9063
|
+
const allowed = await policy.list(policyContext(context, request3, options, { paths: paths2, ...prefix ? { prefix } : {} }));
|
|
9064
9064
|
if (!allowed) return response(request3, false, "tool denied by CaMeL policy");
|
|
9065
|
-
const entries = listWorkspace(
|
|
9065
|
+
const entries = listWorkspace(paths2, { ...prefix ? { prefix } : {}, maxEntries });
|
|
9066
9066
|
if (!entries.length) {
|
|
9067
9067
|
return response(request3, true, prefix ? `No files under "${prefix}".` : "Workspace is empty.", { count: 0 });
|
|
9068
9068
|
}
|
|
9069
|
-
const truncated = entries.length <
|
|
9070
|
-
const hint = !prefix &&
|
|
9071
|
-
\u2026 ${
|
|
9069
|
+
const truncated = entries.length < paths2.length && entries.length === maxEntries;
|
|
9070
|
+
const hint = !prefix && paths2.length > 500 ? `
|
|
9071
|
+
\u2026 ${paths2.length} files total. sandbox.overview is far cheaper for orientation; use a prefix here once you know the area.` : "";
|
|
9072
9072
|
return response(
|
|
9073
9073
|
request3,
|
|
9074
9074
|
true,
|
|
@@ -9086,10 +9086,10 @@ async function search(context, request3, options, policy, registry) {
|
|
|
9086
9086
|
const maxResults = optionalInteger(request3.input.maxResults) ?? 100;
|
|
9087
9087
|
if (maxResults > 500) throw new TypeError("maxResults exceeds its bound");
|
|
9088
9088
|
const caseSensitive = request3.input.caseSensitive === void 0 ? true : request3.input.caseSensitive === true;
|
|
9089
|
-
const
|
|
9090
|
-
const allowed = await policy.search(policyContext(context, request3, options, { paths, query, ...prefix ? { prefix } : {} }));
|
|
9089
|
+
const paths2 = await registry.files(context.workspaceDir);
|
|
9090
|
+
const allowed = await policy.search(policyContext(context, request3, options, { paths: paths2, query, ...prefix ? { prefix } : {} }));
|
|
9091
9091
|
if (!allowed) return response(request3, false, "tool denied by CaMeL policy");
|
|
9092
|
-
const matches = await searchWorkspace(context.workspaceDir,
|
|
9092
|
+
const matches = await searchWorkspace(context.workspaceDir, paths2, {
|
|
9093
9093
|
query,
|
|
9094
9094
|
maxResults,
|
|
9095
9095
|
caseSensitive,
|
|
@@ -9111,8 +9111,8 @@ async function graphQuery(context, request3, options, policy, registry) {
|
|
|
9111
9111
|
selector: query
|
|
9112
9112
|
}));
|
|
9113
9113
|
if (!allowed) return response(request3, false, "tool denied by CaMeL policy");
|
|
9114
|
-
const
|
|
9115
|
-
const graphs = await workspaceGraphs(context.workspaceDir,
|
|
9114
|
+
const paths2 = await registry.files(context.workspaceDir);
|
|
9115
|
+
const graphs = await workspaceGraphs(context.workspaceDir, paths2);
|
|
9116
9116
|
if (request3.tool === "sandbox.overview") {
|
|
9117
9117
|
return response(request3, true, renderOverview(graphs, query || void 0));
|
|
9118
9118
|
}
|
|
@@ -9174,16 +9174,16 @@ function toolFailureMessage(reason) {
|
|
|
9174
9174
|
async function patch(context, request3, options, policy, registry) {
|
|
9175
9175
|
exactKeys(request3.input, ["patch"]);
|
|
9176
9176
|
const value2 = stringField(request3.input, "patch");
|
|
9177
|
-
const
|
|
9178
|
-
if (
|
|
9177
|
+
const paths2 = validateCodePatch(value2, options.maxPatchBytes ?? 256 * 1024);
|
|
9178
|
+
if (paths2.some((path) => options.readOnlyPrefixes?.some((prefix) => path === prefix || path.startsWith(`${prefix}/`)))) {
|
|
9179
9179
|
throw new TypeError("patch targets a read-only reference source");
|
|
9180
9180
|
}
|
|
9181
9181
|
const allowed = await policy.patch(policyContext(context, request3, options, { patch: value2 }));
|
|
9182
9182
|
if (!allowed) return response(request3, false, "tool denied by CaMeL policy");
|
|
9183
|
-
await applyCodePatch(context.workspaceDir, value2,
|
|
9183
|
+
await applyCodePatch(context.workspaceDir, value2, paths2);
|
|
9184
9184
|
registry.invalidate(context.workspaceDir);
|
|
9185
9185
|
forgetWorkspaceGraphs(context.workspaceDir);
|
|
9186
|
-
return response(request3, true, `Applied patch to ${
|
|
9186
|
+
return response(request3, true, `Applied patch to ${paths2.length} file(s).`, { paths: paths2 });
|
|
9187
9187
|
}
|
|
9188
9188
|
async function recipe(context, request3, options, recipes, policy) {
|
|
9189
9189
|
exactKeys(request3.input, ["recipeId"]);
|
|
@@ -9532,11 +9532,126 @@ async function startGoalPursuit(input) {
|
|
|
9532
9532
|
async function appendCodeRuntimeEvent(control, command, event, refs) {
|
|
9533
9533
|
const eventId = `${command.commandId.slice(0, 45)}:${refs.length + 1}`;
|
|
9534
9534
|
refs.push(eventId);
|
|
9535
|
-
const
|
|
9535
|
+
const attributed = { ...event, interactionId: command.commandId };
|
|
9536
|
+
const bounded = attributed.type === "message" ? { ...attributed, body: attributed.body.trim().slice(0, 2e4) || `${attributed.actor} event` } : attributed;
|
|
9536
9537
|
await control.appendSessionEvent(command.sessionId, eventId, bounded);
|
|
9537
9538
|
}
|
|
9538
9539
|
var digestRuntimeValue = (value2) => `sha256:${(0, import_crypto4.createHash)("sha256").update(value2).digest("hex")}`;
|
|
9539
9540
|
var runtimeErrorMessage = (value2) => value2 instanceof Error ? value2.message : String(value2);
|
|
9541
|
+
var text3 = (value2, maximum) => {
|
|
9542
|
+
if (typeof value2 !== "string") return void 0;
|
|
9543
|
+
const bounded = value2.replace(/[\u0000-\u0008\u000b\u000c\u000e-\u001f\u007f]/g, " ").trim();
|
|
9544
|
+
return bounded ? bounded.slice(0, maximum) : void 0;
|
|
9545
|
+
};
|
|
9546
|
+
var integer2 = (value2) => Number.isSafeInteger(value2) && Number(value2) >= 0 ? Number(value2) : void 0;
|
|
9547
|
+
var record32 = (value2) => value2 && typeof value2 === "object" && !Array.isArray(value2) ? value2 : void 0;
|
|
9548
|
+
var excerpt = (value2, tail = false) => {
|
|
9549
|
+
if (typeof value2 !== "string") return void 0;
|
|
9550
|
+
const safe = value2.replace(/[\u0000-\u0008\u000b\u000c\u000e-\u001f\u007f]/g, " ");
|
|
9551
|
+
const source = (tail ? safe.slice(-1e4) : safe.slice(0, 1e4)).trim();
|
|
9552
|
+
if (!source) return void 0;
|
|
9553
|
+
const lines = source.split("\n").filter((line2) => line2.trim()).map((line2) => line2.slice(0, 240));
|
|
9554
|
+
const selected = tail ? lines.slice(-10) : lines.slice(0, 10);
|
|
9555
|
+
return text3(selected.join("\n"), 2400);
|
|
9556
|
+
};
|
|
9557
|
+
var paths = (value2) => {
|
|
9558
|
+
if (!Array.isArray(value2)) return void 0;
|
|
9559
|
+
const items = value2.flatMap((item) => {
|
|
9560
|
+
const path = text3(item, 1024);
|
|
9561
|
+
return path ? [path] : [];
|
|
9562
|
+
}).slice(0, 12);
|
|
9563
|
+
return items.length ? items : void 0;
|
|
9564
|
+
};
|
|
9565
|
+
function patchStats(value2) {
|
|
9566
|
+
if (typeof value2 !== "string") return {};
|
|
9567
|
+
let additions = 0;
|
|
9568
|
+
let deletions = 0;
|
|
9569
|
+
for (const line2 of value2.slice(0, 262144).split("\n")) {
|
|
9570
|
+
if (line2.startsWith("+++") || line2.startsWith("---")) continue;
|
|
9571
|
+
if (line2.startsWith("+")) additions += 1;
|
|
9572
|
+
else if (line2.startsWith("-")) deletions += 1;
|
|
9573
|
+
}
|
|
9574
|
+
return { ...additions ? { additions } : {}, ...deletions ? { deletions } : {} };
|
|
9575
|
+
}
|
|
9576
|
+
function searchResults(value2) {
|
|
9577
|
+
if (typeof value2 !== "string") return void 0;
|
|
9578
|
+
const results = value2.split("\n").flatMap((line2) => {
|
|
9579
|
+
const match = /^([^:\n]{1,1024}):(\d+):\s?(.*)$/.exec(line2);
|
|
9580
|
+
if (!match) return [];
|
|
9581
|
+
const lineNumber = Number(match[2]);
|
|
9582
|
+
const itemText = text3(match[3], 240);
|
|
9583
|
+
if (!Number.isSafeInteger(lineNumber) || lineNumber < 1) return [];
|
|
9584
|
+
return [{ path: match[1], line: lineNumber, ...itemText ? { text: itemText } : {} }];
|
|
9585
|
+
}).slice(0, 5);
|
|
9586
|
+
return results.length ? results : void 0;
|
|
9587
|
+
}
|
|
9588
|
+
function codeToolRequestPresentation(request3) {
|
|
9589
|
+
const input = request3.input;
|
|
9590
|
+
if (request3.tool === "sandbox.read") {
|
|
9591
|
+
const path = text3(input.path, 1024);
|
|
9592
|
+
if (!path) return void 0;
|
|
9593
|
+
const startLine = integer2(input.startLine);
|
|
9594
|
+
const endLine = integer2(input.endLine);
|
|
9595
|
+
return { kind: "read", path, ...startLine ? { startLine } : {}, ...endLine ? { endLine } : {} };
|
|
9596
|
+
}
|
|
9597
|
+
if (request3.tool === "sandbox.list") {
|
|
9598
|
+
const scope = text3(input.prefix, 1024);
|
|
9599
|
+
return { kind: "list", ...scope ? { scope } : {} };
|
|
9600
|
+
}
|
|
9601
|
+
if (request3.tool === "sandbox.search" || request3.tool === "sandbox.overview" || request3.tool === "sandbox.where_is" || request3.tool === "sandbox.who_imports" || request3.tool === "sandbox.who_touches") {
|
|
9602
|
+
const query = text3(input.query, 512);
|
|
9603
|
+
const scope = request3.tool === "sandbox.search" ? text3(input.prefix, 1024) : void 0;
|
|
9604
|
+
if (request3.tool === "sandbox.search" && !query) return void 0;
|
|
9605
|
+
return { kind: "query", ...query ? { query } : {}, ...scope ? { scope } : {} };
|
|
9606
|
+
}
|
|
9607
|
+
if (request3.tool === "sandbox.apply_patch") {
|
|
9608
|
+
return { kind: "patch", ...patchStats(input.patch) };
|
|
9609
|
+
}
|
|
9610
|
+
const recipeId = text3(input.recipeId, 120);
|
|
9611
|
+
return recipeId ? { kind: "recipe", recipeId } : void 0;
|
|
9612
|
+
}
|
|
9613
|
+
function codeToolResultPresentation(request3, response2) {
|
|
9614
|
+
const started = codeToolRequestPresentation(request3);
|
|
9615
|
+
if (!started || !response2.ok) return started;
|
|
9616
|
+
const details = record32(response2.details);
|
|
9617
|
+
if (started.kind === "read") {
|
|
9618
|
+
return {
|
|
9619
|
+
...started,
|
|
9620
|
+
...integer2(details?.startLine) ? { startLine: integer2(details?.startLine) } : {},
|
|
9621
|
+
...integer2(details?.endLine) ? { endLine: integer2(details?.endLine) } : {},
|
|
9622
|
+
...excerpt(response2.content) ? { excerpt: excerpt(response2.content) } : {}
|
|
9623
|
+
};
|
|
9624
|
+
}
|
|
9625
|
+
if (started.kind === "list") {
|
|
9626
|
+
const listed = response2.content.split("\n").filter((line2) => line2 && !line2.startsWith("\u2026") && !line2.startsWith("Workspace ")).map((line2) => text3(line2, 1024)).filter((line2) => Boolean(line2)).slice(0, 8);
|
|
9627
|
+
return {
|
|
9628
|
+
...started,
|
|
9629
|
+
...integer2(details?.count) !== void 0 ? { count: integer2(details?.count) } : {},
|
|
9630
|
+
...listed.length ? { paths: listed } : {}
|
|
9631
|
+
};
|
|
9632
|
+
}
|
|
9633
|
+
if (started.kind === "query") {
|
|
9634
|
+
const results = request3.tool === "sandbox.search" ? searchResults(response2.content) : void 0;
|
|
9635
|
+
const resultExcerpt = request3.tool === "sandbox.search" ? void 0 : excerpt(response2.content);
|
|
9636
|
+
return {
|
|
9637
|
+
...started,
|
|
9638
|
+
...integer2(details?.count) !== void 0 ? { count: integer2(details?.count) } : {},
|
|
9639
|
+
...results ? { results } : {},
|
|
9640
|
+
...resultExcerpt ? { excerpt: resultExcerpt } : {}
|
|
9641
|
+
};
|
|
9642
|
+
}
|
|
9643
|
+
if (started.kind === "patch") {
|
|
9644
|
+
return { ...started, ...paths(details?.paths) ? { paths: paths(details?.paths) } : {} };
|
|
9645
|
+
}
|
|
9646
|
+
const output = response2.content.replace(/^Recipe [^\n]*\.?\s*/u, "");
|
|
9647
|
+
return {
|
|
9648
|
+
...started,
|
|
9649
|
+
...integer2(details?.exitCode) !== void 0 ? { exitCode: integer2(details?.exitCode) } : {},
|
|
9650
|
+
...typeof details?.timedOut === "boolean" ? { timedOut: details.timedOut } : {},
|
|
9651
|
+
...typeof details?.outputLimitExceeded === "boolean" ? { outputLimitExceeded: details.outputLimitExceeded } : {},
|
|
9652
|
+
...excerpt(output, true) ? { excerpt: excerpt(output, true) } : {}
|
|
9653
|
+
};
|
|
9654
|
+
}
|
|
9540
9655
|
var TheseusRuntimeEngine = class {
|
|
9541
9656
|
constructor(options) {
|
|
9542
9657
|
this.options = options;
|
|
@@ -9770,18 +9885,29 @@ var TheseusRuntimeEngine = class {
|
|
|
9770
9885
|
return {
|
|
9771
9886
|
execute: async (context, request3) => {
|
|
9772
9887
|
const startedAt = Date.now();
|
|
9888
|
+
const operationId = digestRuntimeValue(`${command.commandId}:${request3.requestId}`);
|
|
9889
|
+
const startedPresentation = codeToolRequestPresentation(request3);
|
|
9773
9890
|
await this.#event(
|
|
9774
9891
|
command,
|
|
9775
|
-
{
|
|
9892
|
+
{
|
|
9893
|
+
type: "tool",
|
|
9894
|
+
phase: "started",
|
|
9895
|
+
tool: request3.tool,
|
|
9896
|
+
operationId,
|
|
9897
|
+
...startedPresentation ? { presentation: startedPresentation } : {}
|
|
9898
|
+
},
|
|
9776
9899
|
active.conversationRefs
|
|
9777
9900
|
).catch(() => void 0);
|
|
9778
9901
|
const response2 = await broker.execute(context, request3);
|
|
9902
|
+
const completedPresentation = codeToolResultPresentation(request3, response2);
|
|
9779
9903
|
await this.#event(command, {
|
|
9780
9904
|
type: "tool",
|
|
9781
9905
|
phase: "completed",
|
|
9782
9906
|
tool: request3.tool,
|
|
9783
9907
|
ok: response2.ok,
|
|
9784
|
-
durationMs: Date.now() - startedAt
|
|
9908
|
+
durationMs: Date.now() - startedAt,
|
|
9909
|
+
operationId,
|
|
9910
|
+
...completedPresentation ? { presentation: completedPresentation } : {}
|
|
9785
9911
|
}, active.conversationRefs).catch(() => void 0);
|
|
9786
9912
|
return response2;
|
|
9787
9913
|
}
|
|
@@ -11815,8 +11941,8 @@ function collectFields(parsed, allowClear) {
|
|
|
11815
11941
|
if (allowClear) out[spec.key] = null;
|
|
11816
11942
|
continue;
|
|
11817
11943
|
}
|
|
11818
|
-
const
|
|
11819
|
-
out[spec.key] = spec.num ? Number(
|
|
11944
|
+
const text4 = stringOpt(value2);
|
|
11945
|
+
out[spec.key] = spec.num ? Number(text4) : text4;
|
|
11820
11946
|
}
|
|
11821
11947
|
return out;
|
|
11822
11948
|
}
|
|
@@ -13228,14 +13354,14 @@ function statusMinutes(value2) {
|
|
|
13228
13354
|
}
|
|
13229
13355
|
async function read2(url, headers, doFetch) {
|
|
13230
13356
|
const response2 = await doFetch(url, { headers });
|
|
13231
|
-
const
|
|
13357
|
+
const text4 = await response2.text();
|
|
13232
13358
|
let body = {};
|
|
13233
|
-
if (
|
|
13359
|
+
if (text4) {
|
|
13234
13360
|
try {
|
|
13235
|
-
const value2 = JSON.parse(
|
|
13361
|
+
const value2 = JSON.parse(text4);
|
|
13236
13362
|
body = value2 && typeof value2 === "object" && !Array.isArray(value2) ? value2 : { value: value2 };
|
|
13237
13363
|
} catch {
|
|
13238
|
-
body = { message:
|
|
13364
|
+
body = { message: text4.slice(0, 300) };
|
|
13239
13365
|
}
|
|
13240
13366
|
}
|
|
13241
13367
|
return { httpStatus: response2.status, body };
|
|
@@ -13465,13 +13591,13 @@ async function monitorCommand(parsed, deps = {}) {
|
|
|
13465
13591
|
}
|
|
13466
13592
|
async function request2(url, init, doFetch) {
|
|
13467
13593
|
const response2 = await doFetch(url, init);
|
|
13468
|
-
const
|
|
13594
|
+
const text4 = await response2.text();
|
|
13469
13595
|
let body = {};
|
|
13470
13596
|
try {
|
|
13471
|
-
const parsed =
|
|
13597
|
+
const parsed = text4 ? JSON.parse(text4) : {};
|
|
13472
13598
|
body = record10(parsed) ? parsed : { value: parsed };
|
|
13473
13599
|
} catch {
|
|
13474
|
-
body = { message:
|
|
13600
|
+
body = { message: text4.slice(0, 500) };
|
|
13475
13601
|
}
|
|
13476
13602
|
if (!response2.ok) {
|
|
13477
13603
|
const error = record10(body.error) ? body.error : body;
|
|
@@ -13674,8 +13800,8 @@ function runtimeUrl(cfg, suffix = "") {
|
|
|
13674
13800
|
return `${cfg.platformUrl}/registry/apps/${encodeURIComponent(cfg.app.id)}/runtime-credentials${suffix}`;
|
|
13675
13801
|
}
|
|
13676
13802
|
async function safeError(response2) {
|
|
13677
|
-
const
|
|
13678
|
-
return redactSecrets(
|
|
13803
|
+
const text4 = await response2.text();
|
|
13804
|
+
return redactSecrets(text4.slice(0, 1e3));
|
|
13679
13805
|
}
|
|
13680
13806
|
async function finish(doFetch, cfg, token, sessionId, method) {
|
|
13681
13807
|
return doFetch(runtimeUrl(cfg, `/${encodeURIComponent(sessionId)}`), {
|
|
@@ -14094,6 +14220,7 @@ var COMMAND_SURFACE = {
|
|
|
14094
14220
|
project: { list: {}, add: {}, create: {}, use: {} },
|
|
14095
14221
|
handoff: {},
|
|
14096
14222
|
next: {},
|
|
14223
|
+
start: {},
|
|
14097
14224
|
watch: {}
|
|
14098
14225
|
},
|
|
14099
14226
|
provision: {},
|
|
@@ -14168,13 +14295,13 @@ function invocationPath(words2) {
|
|
|
14168
14295
|
return path;
|
|
14169
14296
|
}
|
|
14170
14297
|
function surfacePaths(node = COMMAND_SURFACE, prefix = []) {
|
|
14171
|
-
const
|
|
14298
|
+
const paths2 = [];
|
|
14172
14299
|
for (const [word, child] of Object.entries(node)) {
|
|
14173
14300
|
const path = [...prefix, word];
|
|
14174
|
-
|
|
14175
|
-
|
|
14301
|
+
paths2.push(path);
|
|
14302
|
+
paths2.push(...surfacePaths(child, path));
|
|
14176
14303
|
}
|
|
14177
|
-
return
|
|
14304
|
+
return paths2;
|
|
14178
14305
|
}
|
|
14179
14306
|
|
|
14180
14307
|
// src/record.ts
|
|
@@ -14232,10 +14359,10 @@ var DAY_MS = 24 * 60 * 60 * 1e3;
|
|
|
14232
14359
|
var UNITS = { d: DAY_MS, w: 7 * DAY_MS, y: 365 * DAY_MS };
|
|
14233
14360
|
function parseDeviceTtl(raw) {
|
|
14234
14361
|
if (raw === void 0 || raw === true) return void 0;
|
|
14235
|
-
const
|
|
14236
|
-
if (!
|
|
14237
|
-
if (
|
|
14238
|
-
const match = /^(\d+)\s*([dwy])$/.exec(
|
|
14362
|
+
const text4 = String(raw).trim().toLowerCase();
|
|
14363
|
+
if (!text4) return void 0;
|
|
14364
|
+
if (text4 === "forever" || text4 === "never") return 100 * 365 * DAY_MS;
|
|
14365
|
+
const match = /^(\d+)\s*([dwy])$/.exec(text4);
|
|
14239
14366
|
if (!match) {
|
|
14240
14367
|
throw new Error(
|
|
14241
14368
|
`--device-ttl expects a duration like 30d, 6w, 2y, or "forever" (got "${raw}")`
|
|
@@ -14617,12 +14744,12 @@ async function runbookRemove(ctx, slug) {
|
|
|
14617
14744
|
// src/runbook-import.ts
|
|
14618
14745
|
var import_node_fs21 = require("fs");
|
|
14619
14746
|
var import_node_path19 = require("path");
|
|
14620
|
-
function parseRunbook(
|
|
14621
|
-
let rest =
|
|
14747
|
+
function parseRunbook(text4, slug) {
|
|
14748
|
+
let rest = text4;
|
|
14622
14749
|
const meta = {};
|
|
14623
|
-
const fm = /^---\r?\n([\s\S]*?)\r?\n---\r?\n?/.exec(
|
|
14750
|
+
const fm = /^---\r?\n([\s\S]*?)\r?\n---\r?\n?/.exec(text4);
|
|
14624
14751
|
if (fm) {
|
|
14625
|
-
rest =
|
|
14752
|
+
rest = text4.slice(fm[0].length);
|
|
14626
14753
|
for (const line2 of fm[1].split(/\r?\n/)) {
|
|
14627
14754
|
const pair = /^(\w+)\s*:\s*(.+)$/.exec(line2.trim());
|
|
14628
14755
|
if (!pair) continue;
|