@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/bin.cjs
CHANGED
|
@@ -556,10 +556,10 @@ function isManagedDevVar(line2) {
|
|
|
556
556
|
const match = line2.match(/^\s*(?:export\s+)?([A-Z][A-Z0-9_]*)\s*=/);
|
|
557
557
|
return !!match?.[1] && MANAGED_DEV_VARS.has(match[1]);
|
|
558
558
|
}
|
|
559
|
-
function writePrivateText(path,
|
|
559
|
+
function writePrivateText(path, text4) {
|
|
560
560
|
(0, import_node_fs7.mkdirSync)((0, import_node_path5.dirname)(path), { recursive: true });
|
|
561
561
|
const temporary = `${path}.tmp-${process.pid}-${Date.now()}`;
|
|
562
|
-
(0, import_node_fs7.writeFileSync)(temporary,
|
|
562
|
+
(0, import_node_fs7.writeFileSync)(temporary, text4, { mode: 384 });
|
|
563
563
|
(0, import_node_fs7.chmodSync)(temporary, 384);
|
|
564
564
|
(0, import_node_fs7.renameSync)(temporary, path);
|
|
565
565
|
}
|
|
@@ -1105,12 +1105,12 @@ async function readAdminAiAudit(request3) {
|
|
|
1105
1105
|
}
|
|
1106
1106
|
}
|
|
1107
1107
|
async function responseBody(response2) {
|
|
1108
|
-
const
|
|
1109
|
-
if (!
|
|
1108
|
+
const text4 = await response2.text();
|
|
1109
|
+
if (!text4) return {};
|
|
1110
1110
|
try {
|
|
1111
|
-
return JSON.parse(
|
|
1111
|
+
return JSON.parse(text4);
|
|
1112
1112
|
} catch {
|
|
1113
|
-
return { message:
|
|
1113
|
+
return { message: text4.slice(0, 300) };
|
|
1114
1114
|
}
|
|
1115
1115
|
}
|
|
1116
1116
|
function apiError(status, body) {
|
|
@@ -1226,12 +1226,12 @@ function timestamp2(value2) {
|
|
|
1226
1226
|
return Number.isFinite(date.valueOf()) ? date.toISOString() : "";
|
|
1227
1227
|
}
|
|
1228
1228
|
async function responseBody2(res) {
|
|
1229
|
-
const
|
|
1230
|
-
if (!
|
|
1229
|
+
const text4 = await res.text();
|
|
1230
|
+
if (!text4) return {};
|
|
1231
1231
|
try {
|
|
1232
|
-
return JSON.parse(
|
|
1232
|
+
return JSON.parse(text4);
|
|
1233
1233
|
} catch {
|
|
1234
|
-
return { message:
|
|
1234
|
+
return { message: text4.slice(0, 300) };
|
|
1235
1235
|
}
|
|
1236
1236
|
}
|
|
1237
1237
|
function apiError2(action2, status, body) {
|
|
@@ -1414,12 +1414,12 @@ function catalogModels(body) {
|
|
|
1414
1414
|
return body.catalog.models.filter((value2) => isRecord3(value2) && typeof value2.id === "string" && typeof value2.provider === "string");
|
|
1415
1415
|
}
|
|
1416
1416
|
async function responseBody3(res) {
|
|
1417
|
-
const
|
|
1418
|
-
if (!
|
|
1417
|
+
const text4 = await res.text();
|
|
1418
|
+
if (!text4) return {};
|
|
1419
1419
|
try {
|
|
1420
|
-
return JSON.parse(
|
|
1420
|
+
return JSON.parse(text4);
|
|
1421
1421
|
} catch {
|
|
1422
|
-
return { message:
|
|
1422
|
+
return { message: text4.slice(0, 300) };
|
|
1423
1423
|
}
|
|
1424
1424
|
}
|
|
1425
1425
|
function apiError3(action2, status, body) {
|
|
@@ -2936,8 +2936,8 @@ async function appImport(options) {
|
|
|
2936
2936
|
const out = options.stdout ?? console;
|
|
2937
2937
|
const say = options.json ? (line2) => out.error(line2) : (line2) => out.log(line2);
|
|
2938
2938
|
const { tenant } = resolveTenant(cfg, options.env);
|
|
2939
|
-
const
|
|
2940
|
-
const { format, sources } = (0, import_import.parseImport)(
|
|
2939
|
+
const text4 = options.file === "-" ? (options.readStdin ?? (() => (0, import_node_fs12.readFileSync)(0, "utf8")))() : (0, import_node_fs12.readFileSync)(options.file, "utf8");
|
|
2940
|
+
const { format, sources } = (0, import_import.parseImport)(text4, options.ns);
|
|
2941
2941
|
if (format === "namespace-map" && options.ns) {
|
|
2942
2942
|
throw new Error("--ns cannot be combined with a {namespace: rows} file \u2014 the file already names each namespace");
|
|
2943
2943
|
}
|
|
@@ -3274,7 +3274,7 @@ var init_brand_design_unpack = __esm({
|
|
|
3274
3274
|
"text/html": "html",
|
|
3275
3275
|
"application/json": "json"
|
|
3276
3276
|
};
|
|
3277
|
-
encode = (
|
|
3277
|
+
encode = (text4) => new TextEncoder().encode(text4);
|
|
3278
3278
|
}
|
|
3279
3279
|
});
|
|
3280
3280
|
|
|
@@ -4130,9 +4130,9 @@ async function assertTenantAdminAccess(doFetch, cfg, env, token) {
|
|
|
4130
4130
|
}
|
|
4131
4131
|
throw new Error(`${env}: tenant access preflight (${tenantId}) failed: ${res.status} ${await safeText5(res)}`);
|
|
4132
4132
|
}
|
|
4133
|
-
function errorCode(
|
|
4133
|
+
function errorCode(text4) {
|
|
4134
4134
|
try {
|
|
4135
|
-
const body = JSON.parse(
|
|
4135
|
+
const body = JSON.parse(text4);
|
|
4136
4136
|
return typeof body.error?.code === "string" ? body.error.code : null;
|
|
4137
4137
|
} catch {
|
|
4138
4138
|
return null;
|
|
@@ -4918,15 +4918,15 @@ function readWranglerConfig(path) {
|
|
|
4918
4918
|
return null;
|
|
4919
4919
|
}
|
|
4920
4920
|
}
|
|
4921
|
-
function stripJsonComments(
|
|
4921
|
+
function stripJsonComments(text4) {
|
|
4922
4922
|
let result = "";
|
|
4923
4923
|
let inString = false;
|
|
4924
|
-
for (let i = 0; i <
|
|
4925
|
-
const ch =
|
|
4924
|
+
for (let i = 0; i < text4.length; i++) {
|
|
4925
|
+
const ch = text4[i];
|
|
4926
4926
|
if (inString) {
|
|
4927
4927
|
result += ch;
|
|
4928
4928
|
if (ch === "\\") {
|
|
4929
|
-
result +=
|
|
4929
|
+
result += text4[i + 1] ?? "";
|
|
4930
4930
|
i++;
|
|
4931
4931
|
} else if (ch === '"') {
|
|
4932
4932
|
inString = false;
|
|
@@ -4938,14 +4938,14 @@ function stripJsonComments(text3) {
|
|
|
4938
4938
|
result += ch;
|
|
4939
4939
|
continue;
|
|
4940
4940
|
}
|
|
4941
|
-
if (ch === "/" &&
|
|
4942
|
-
while (i <
|
|
4941
|
+
if (ch === "/" && text4[i + 1] === "/") {
|
|
4942
|
+
while (i < text4.length && text4[i] !== "\n") i++;
|
|
4943
4943
|
result += "\n";
|
|
4944
4944
|
continue;
|
|
4945
4945
|
}
|
|
4946
|
-
if (ch === "/" &&
|
|
4946
|
+
if (ch === "/" && text4[i + 1] === "*") {
|
|
4947
4947
|
i += 2;
|
|
4948
|
-
while (i <
|
|
4948
|
+
while (i < text4.length && !(text4[i] === "*" && text4[i + 1] === "/")) i++;
|
|
4949
4949
|
i++;
|
|
4950
4950
|
continue;
|
|
4951
4951
|
}
|
|
@@ -5529,9 +5529,9 @@ function initProject(options) {
|
|
|
5529
5529
|
out.log("created src/odla/schema.mjs and src/odla/rules.mjs");
|
|
5530
5530
|
out.log("updated .gitignore for local odla credentials");
|
|
5531
5531
|
}
|
|
5532
|
-
function writeIfMissing(path,
|
|
5532
|
+
function writeIfMissing(path, text4) {
|
|
5533
5533
|
if ((0, import_node_fs16.existsSync)(path)) return;
|
|
5534
|
-
(0, import_node_fs16.writeFileSync)(path,
|
|
5534
|
+
(0, import_node_fs16.writeFileSync)(path, text4);
|
|
5535
5535
|
}
|
|
5536
5536
|
function configTemplate(input) {
|
|
5537
5537
|
const calendar = input.services.includes("calendar") ? ` calendar: {
|
|
@@ -5763,13 +5763,13 @@ async function secretsSetClerkKey(options) {
|
|
|
5763
5763
|
body: JSON.stringify({ value: value2 })
|
|
5764
5764
|
});
|
|
5765
5765
|
if (!res.ok) {
|
|
5766
|
-
const
|
|
5767
|
-
throw new Error(`store Clerk secret key failed (${res.status}): ${
|
|
5766
|
+
const text4 = scrubValue((await res.text().catch(() => "")).slice(0, 300), value2);
|
|
5767
|
+
throw new Error(`store Clerk secret key failed (${res.status}): ${text4 || "request failed"}`);
|
|
5768
5768
|
}
|
|
5769
5769
|
out.log(`Clerk secret key stored for ${tenantId} ($clerk_secret, reserved + write-only; the value was never echoed)`);
|
|
5770
5770
|
}
|
|
5771
|
-
function scrubValue(
|
|
5772
|
-
return redactSecrets(
|
|
5771
|
+
function scrubValue(text4, value2) {
|
|
5772
|
+
return redactSecrets(text4).split(value2).join("[value redacted]");
|
|
5773
5773
|
}
|
|
5774
5774
|
async function resolveVaultWrite(options) {
|
|
5775
5775
|
const out = options.stdout ?? console;
|
|
@@ -6086,8 +6086,8 @@ ${conflicts.map((f) => ` - ${f}`).join("\n")}`
|
|
|
6086
6086
|
harnesses: installations
|
|
6087
6087
|
};
|
|
6088
6088
|
}
|
|
6089
|
-
function pathsUnder(root,
|
|
6090
|
-
return [...
|
|
6089
|
+
function pathsUnder(root, paths2) {
|
|
6090
|
+
return [...paths2].map((path) => (0, import_node_path16.relative)(root, path)).filter((path) => path !== ".." && !path.startsWith(`..${import_node_path16.sep}`) && !(0, import_node_path16.isAbsolute)(path)).sort();
|
|
6091
6091
|
}
|
|
6092
6092
|
function normalizeHarnesses(values, global) {
|
|
6093
6093
|
const requested = values?.length ? values : ["claude"];
|
|
@@ -6557,17 +6557,17 @@ var init_cli_project = __esm({
|
|
|
6557
6557
|
}
|
|
6558
6558
|
});
|
|
6559
6559
|
|
|
6560
|
-
// ../harness/dist/chunk-
|
|
6560
|
+
// ../harness/dist/chunk-RXNHCGWE.js
|
|
6561
6561
|
var HARNESS_PROTOCOL_VERSION;
|
|
6562
|
-
var
|
|
6563
|
-
"../harness/dist/chunk-
|
|
6562
|
+
var init_chunk_RXNHCGWE = __esm({
|
|
6563
|
+
"../harness/dist/chunk-RXNHCGWE.js"() {
|
|
6564
6564
|
"use strict";
|
|
6565
6565
|
init_cjs_shims();
|
|
6566
6566
|
HARNESS_PROTOCOL_VERSION = 1;
|
|
6567
6567
|
}
|
|
6568
6568
|
});
|
|
6569
6569
|
|
|
6570
|
-
// ../harness/dist/chunk-
|
|
6570
|
+
// ../harness/dist/chunk-CR6RE3A2.js
|
|
6571
6571
|
function assertPinnedImage(image) {
|
|
6572
6572
|
if (!DIGEST_IMAGE.test(image)) throw new TypeError("container image must be pinned by sha256 digest");
|
|
6573
6573
|
}
|
|
@@ -6795,12 +6795,12 @@ async function gitSourceFiles(sourceDir, maxFiles, maxBytes) {
|
|
|
6795
6795
|
});
|
|
6796
6796
|
if (outputBytes > 8 * 1024 * 1024) throw new Error("git file inventory exceeds 8 MiB");
|
|
6797
6797
|
if (code !== 0) throw new Error(`git file inventory failed: ${Buffer.concat(stderr2).toString("utf8").slice(0, 1e3)}`);
|
|
6798
|
-
const
|
|
6799
|
-
if (
|
|
6798
|
+
const paths2 = Buffer.concat(stdout).toString("utf8").split("\0").filter(Boolean).sort();
|
|
6799
|
+
if (paths2.length > maxFiles) throw new Error(`workspace exceeds ${maxFiles} files`);
|
|
6800
6800
|
const root = (0, import_path4.resolve)(sourceDir);
|
|
6801
6801
|
const files = [];
|
|
6802
6802
|
let bytes = 0;
|
|
6803
|
-
for (const relativePath of
|
|
6803
|
+
for (const relativePath of paths2) {
|
|
6804
6804
|
if (!allowedWorkspacePath(relativePath)) continue;
|
|
6805
6805
|
const source = (0, import_path4.resolve)(root, relativePath);
|
|
6806
6806
|
if (!source.startsWith(`${root}${import_path4.sep}`)) throw new TypeError("git file path escapes workspace");
|
|
@@ -6916,8 +6916,8 @@ async function stageWorkspacePair(baselineSource, workspaceSource, options = {})
|
|
|
6916
6916
|
}
|
|
6917
6917
|
}
|
|
6918
6918
|
var import_child_process, import_fs, import_promises2, import_path, import_process, import_promises3, import_os, import_path2, import_child_process2, import_path3, import_promises4, import_os2, import_path4, import_child_process3, DIGEST_IMAGE, SKIP_WORKSPACE_DIRS, SECRET_WORKSPACE_FILE;
|
|
6919
|
-
var
|
|
6920
|
-
"../harness/dist/chunk-
|
|
6919
|
+
var init_chunk_CR6RE3A2 = __esm({
|
|
6920
|
+
"../harness/dist/chunk-CR6RE3A2.js"() {
|
|
6921
6921
|
"use strict";
|
|
6922
6922
|
init_cjs_shims();
|
|
6923
6923
|
import_child_process = require("child_process");
|
|
@@ -7276,13 +7276,13 @@ function validateSnapshot(snapshot, limits) {
|
|
|
7276
7276
|
if (!Number.isSafeInteger(limits.maximumFiles) || limits.maximumFiles < 1 || !Number.isSafeInteger(limits.maximumBytes) || limits.maximumBytes < 1 || snapshot.files.length > limits.maximumFiles) {
|
|
7277
7277
|
throw new CamelError("limit_exceeded", "Code snapshot exceeds its registered limits.");
|
|
7278
7278
|
}
|
|
7279
|
-
const
|
|
7279
|
+
const paths2 = /* @__PURE__ */ new Set();
|
|
7280
7280
|
let bytes = 0;
|
|
7281
7281
|
for (const file of snapshot.files) {
|
|
7282
|
-
if (!file.path || file.path.startsWith("/") || file.path.includes("\\") || file.path.split("/").some((part) => !part || part === "." || part === "..") ||
|
|
7282
|
+
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") {
|
|
7283
7283
|
throw new CamelError("state_conflict", "Code snapshot contains an invalid or duplicate path.");
|
|
7284
7284
|
}
|
|
7285
|
-
|
|
7285
|
+
paths2.add(file.path);
|
|
7286
7286
|
bytes += utf8Length(file.path) + utf8Length(file.content);
|
|
7287
7287
|
}
|
|
7288
7288
|
if (bytes > limits.maximumBytes) {
|
|
@@ -7433,8 +7433,8 @@ function boundedInteger(value2, spec) {
|
|
|
7433
7433
|
}
|
|
7434
7434
|
function boundedNumber(value2, spec) {
|
|
7435
7435
|
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.");
|
|
7436
|
-
const
|
|
7437
|
-
if (/e/i.test(
|
|
7436
|
+
const text4 = String(value2);
|
|
7437
|
+
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.");
|
|
7438
7438
|
return value2;
|
|
7439
7439
|
}
|
|
7440
7440
|
function enumMember(value2, spec) {
|
|
@@ -7617,8 +7617,8 @@ function validateUnsafeSelector(path, value2, tool) {
|
|
|
7617
7617
|
return void 0;
|
|
7618
7618
|
}
|
|
7619
7619
|
function looksLikeDestination(value2) {
|
|
7620
|
-
const
|
|
7621
|
-
return /^(?:[a-z][a-z0-9+.-]*:\/\/|\/|\\\\)/i.test(
|
|
7620
|
+
const text4 = value2.trim();
|
|
7621
|
+
return /^(?:[a-z][a-z0-9+.-]*:\/\/|\/|\\\\)/i.test(text4) || /^[\w.-]+\.[a-z]{2,}(?:[/:]|$)/i.test(text4);
|
|
7622
7622
|
}
|
|
7623
7623
|
var init_policy = __esm({
|
|
7624
7624
|
"../camel/dist/policy.js"() {
|
|
@@ -7792,9 +7792,9 @@ async function extractImports(builder, input) {
|
|
|
7792
7792
|
const sources = input.paths.filter(isSourcePath);
|
|
7793
7793
|
const known = new Set(sources);
|
|
7794
7794
|
for (const path of sources) {
|
|
7795
|
-
let
|
|
7795
|
+
let text4;
|
|
7796
7796
|
try {
|
|
7797
|
-
|
|
7797
|
+
text4 = await input.read(path);
|
|
7798
7798
|
} catch {
|
|
7799
7799
|
continue;
|
|
7800
7800
|
}
|
|
@@ -7802,13 +7802,13 @@ async function extractImports(builder, input) {
|
|
|
7802
7802
|
const file = builder.node(FILE, path, pkg ? { pkg } : void 0);
|
|
7803
7803
|
if (pkg) builder.edge(builder.node(PACKAGE, pkg), CONTAINS, file);
|
|
7804
7804
|
const specifiers = /* @__PURE__ */ new Set();
|
|
7805
|
-
for (const match of
|
|
7806
|
-
for (const match of
|
|
7805
|
+
for (const match of text4.matchAll(IMPORT_FROM)) specifiers.add(match[1]);
|
|
7806
|
+
for (const match of text4.matchAll(BARE_IMPORT)) specifiers.add(match[1]);
|
|
7807
7807
|
for (const specifier of specifiers) {
|
|
7808
7808
|
const resolved = resolveImport(path, specifier, known);
|
|
7809
7809
|
if (resolved) builder.edge(file, IMPORTS, nodeId(FILE, resolved));
|
|
7810
7810
|
}
|
|
7811
|
-
for (const name of exportedNames(
|
|
7811
|
+
for (const name of exportedNames(text4)) {
|
|
7812
7812
|
builder.edge(file, EXPORTS, builder.node(SYMBOL, name));
|
|
7813
7813
|
}
|
|
7814
7814
|
}
|
|
@@ -7821,16 +7821,16 @@ async function extractData(builder, input) {
|
|
|
7821
7821
|
};
|
|
7822
7822
|
for (const path of input.paths) {
|
|
7823
7823
|
if (!SOURCE_FILE.test(path) || input.ignore?.(path)) continue;
|
|
7824
|
-
let
|
|
7824
|
+
let text4;
|
|
7825
7825
|
try {
|
|
7826
|
-
|
|
7826
|
+
text4 = await input.read(path);
|
|
7827
7827
|
} catch {
|
|
7828
7828
|
continue;
|
|
7829
7829
|
}
|
|
7830
|
-
for (const statement of
|
|
7830
|
+
for (const statement of text4.matchAll(STATEMENT)) {
|
|
7831
7831
|
const verb = statement[1].toUpperCase().replace(/\s+/g, " ");
|
|
7832
7832
|
const start = statement.index ?? 0;
|
|
7833
|
-
const rest =
|
|
7833
|
+
const rest = text4.slice(start + statement[0].length, start + STATEMENT_WINDOW);
|
|
7834
7834
|
if (verb === "SELECT") {
|
|
7835
7835
|
for (const read3 of rest.matchAll(READ_TABLES)) touch(path, read3[1].toLowerCase(), TABLE, READS);
|
|
7836
7836
|
continue;
|
|
@@ -7846,16 +7846,16 @@ async function extractData(builder, input) {
|
|
|
7846
7846
|
for (const read3 of rest.matchAll(READ_TABLES)) touch(path, read3[1].toLowerCase(), TABLE, READS);
|
|
7847
7847
|
}
|
|
7848
7848
|
}
|
|
7849
|
-
for (const match of
|
|
7850
|
-
touch(path, `${match[1]}.${match[2]}`, NAMESPACE, accessFor(
|
|
7849
|
+
for (const match of text4.matchAll(NS_CONST)) {
|
|
7850
|
+
touch(path, `${match[1]}.${match[2]}`, NAMESPACE, accessFor(text4, match.index ?? 0));
|
|
7851
7851
|
}
|
|
7852
|
-
for (const match of
|
|
7853
|
-
touch(path, match[1], NAMESPACE, accessFor(
|
|
7852
|
+
for (const match of text4.matchAll(NS_LITERAL)) {
|
|
7853
|
+
touch(path, match[1], NAMESPACE, accessFor(text4, match.index ?? 0));
|
|
7854
7854
|
}
|
|
7855
7855
|
}
|
|
7856
7856
|
}
|
|
7857
|
-
function accessFor(
|
|
7858
|
-
const window =
|
|
7857
|
+
function accessFor(text4, index) {
|
|
7858
|
+
const window = text4.slice(Math.max(0, index - 160), index + 40);
|
|
7859
7859
|
return /\b(?:transact|update|delete|create|insert|Ops)\b/.test(window) ? WRITES : READS;
|
|
7860
7860
|
}
|
|
7861
7861
|
async function buildCodeGraph(input) {
|
|
@@ -7915,7 +7915,7 @@ var init_code2 = __esm({
|
|
|
7915
7915
|
}
|
|
7916
7916
|
});
|
|
7917
7917
|
|
|
7918
|
-
// ../harness/dist/chunk-
|
|
7918
|
+
// ../harness/dist/chunk-ISR434K7.js
|
|
7919
7919
|
async function digestStagedWorkspace(root, limits) {
|
|
7920
7920
|
const files = [];
|
|
7921
7921
|
const walk = async (directory) => {
|
|
@@ -8195,7 +8195,7 @@ function validateCodePatch(rawPatch, maxBytes) {
|
|
|
8195
8195
|
if (FORBIDDEN.test(patch2) || /(?:old|new)(?: file)? mode 120000/.test(patch2)) {
|
|
8196
8196
|
throw new TypeError("patch uses a forbidden binary, link, mode, rename, or copy operation");
|
|
8197
8197
|
}
|
|
8198
|
-
const
|
|
8198
|
+
const paths2 = [];
|
|
8199
8199
|
const lines = patch2.split("\n");
|
|
8200
8200
|
for (let index = 0; index < lines.length; index += 1) {
|
|
8201
8201
|
const line2 = lines[index];
|
|
@@ -8211,10 +8211,10 @@ function validateCodePatch(rawPatch, maxBytes) {
|
|
|
8211
8211
|
if (!validHeaderPath(oldPath, path, "a") || !validHeaderPath(newPath, path, "b")) {
|
|
8212
8212
|
throw new TypeError("patch file headers do not match the declared path");
|
|
8213
8213
|
}
|
|
8214
|
-
|
|
8214
|
+
paths2.push(path);
|
|
8215
8215
|
}
|
|
8216
|
-
if (!
|
|
8217
|
-
return
|
|
8216
|
+
if (!paths2.length || new Set(paths2).size !== paths2.length) throw new TypeError("patch has no diffs or repeats a path");
|
|
8217
|
+
return paths2;
|
|
8218
8218
|
}
|
|
8219
8219
|
function validHeaderPath(value2, path, prefix) {
|
|
8220
8220
|
return value2 === "/dev/null" || value2 === `${prefix}/${path}`;
|
|
@@ -8239,11 +8239,11 @@ function describePatchFailure(patch2, detail) {
|
|
|
8239
8239
|
const hint = hunks.length > 0 && contextless ? " A hunk has no context lines; include at least one unchanged line above or below each change." : "";
|
|
8240
8240
|
return `patch did not apply: ${detail}${hint}`;
|
|
8241
8241
|
}
|
|
8242
|
-
async function applyCodePatch(workspaceDir, rawPatch,
|
|
8242
|
+
async function applyCodePatch(workspaceDir, rawPatch, paths2) {
|
|
8243
8243
|
const patch2 = stripPatchEnvelope(rawPatch);
|
|
8244
8244
|
await gitApply(workspaceDir, patch2, true);
|
|
8245
8245
|
await gitApply(workspaceDir, patch2, false);
|
|
8246
|
-
for (const path of
|
|
8246
|
+
for (const path of paths2) {
|
|
8247
8247
|
try {
|
|
8248
8248
|
const info = await (0, import_promises6.lstat)(resolveCodePath(workspaceDir, path));
|
|
8249
8249
|
if (info.isSymbolicLink() || !info.isFile() && !info.isDirectory()) {
|
|
@@ -8265,8 +8265,8 @@ function gitApply(cwd, patch2, check) {
|
|
|
8265
8265
|
});
|
|
8266
8266
|
let stderr2 = "";
|
|
8267
8267
|
child.stderr.setEncoding("utf8");
|
|
8268
|
-
child.stderr.on("data", (
|
|
8269
|
-
if (stderr2.length < 4e3) stderr2 +=
|
|
8268
|
+
child.stderr.on("data", (text22) => {
|
|
8269
|
+
if (stderr2.length < 4e3) stderr2 += text22.slice(0, 4e3);
|
|
8270
8270
|
});
|
|
8271
8271
|
child.once("error", reject);
|
|
8272
8272
|
child.once("exit", (code) => code === 0 ? accept() : reject(new TypeError(describePatchFailure(patch2, stderr2.trim().slice(0, 500)))));
|
|
@@ -8290,8 +8290,8 @@ async function restoreCodeWorkspaceCheckpoint(input) {
|
|
|
8290
8290
|
const workspace = await stageWorkspace(input.trustedBaseDir, input.stage);
|
|
8291
8291
|
try {
|
|
8292
8292
|
if (checkpoint.patch) {
|
|
8293
|
-
const
|
|
8294
|
-
await applyCodePatch(workspace.workspaceDir, checkpoint.patch,
|
|
8293
|
+
const paths2 = validateCodePatch(checkpoint.patch, 256 * 1024);
|
|
8294
|
+
await applyCodePatch(workspace.workspaceDir, checkpoint.patch, paths2);
|
|
8295
8295
|
}
|
|
8296
8296
|
return { workspace, checkpoint };
|
|
8297
8297
|
} catch (error) {
|
|
@@ -8432,8 +8432,8 @@ async function verifyCodeCandidate(input) {
|
|
|
8432
8432
|
try {
|
|
8433
8433
|
const baseDigest = await digestStagedWorkspace(staged.workspaceDir, limits);
|
|
8434
8434
|
if (baseDigest !== input.trustedBaseDigest) throw new TypeError("trusted base does not match its registered digest");
|
|
8435
|
-
const
|
|
8436
|
-
await applyCodePatch(staged.workspaceDir, input.candidatePatch,
|
|
8435
|
+
const paths2 = validateCodePatch(input.candidatePatch, policy.maximumPatchBytes);
|
|
8436
|
+
await applyCodePatch(staged.workspaceDir, input.candidatePatch, paths2);
|
|
8437
8437
|
const sourceDigest = await digestStagedWorkspace(staged.workspaceDir, limits);
|
|
8438
8438
|
const policyDigest = digestPolicy(policy);
|
|
8439
8439
|
const patchDigest = digestBytes(input.candidatePatch);
|
|
@@ -8442,7 +8442,7 @@ async function verifyCodeCandidate(input) {
|
|
|
8442
8442
|
trustedBaseDigest: input.trustedBaseDigest,
|
|
8443
8443
|
patchDigest
|
|
8444
8444
|
});
|
|
8445
|
-
const changedTests = changedTestPaths(
|
|
8445
|
+
const changedTests = changedTestPaths(paths2, policy);
|
|
8446
8446
|
if (changedTests.length > policy.maximumChangedTests) throw new TypeError("candidate changes too many test files");
|
|
8447
8447
|
const recipes = [];
|
|
8448
8448
|
const logs = [];
|
|
@@ -8509,8 +8509,8 @@ function validate2(input) {
|
|
|
8509
8509
|
}
|
|
8510
8510
|
return result;
|
|
8511
8511
|
}
|
|
8512
|
-
function changedTestPaths(
|
|
8513
|
-
return
|
|
8512
|
+
function changedTestPaths(paths2, policy) {
|
|
8513
|
+
return paths2.filter((path) => policy.testPathSuffixes.some((suffix) => path.endsWith(suffix)) || policy.testPathPrefixes.some((prefix) => path.startsWith(prefix) || path.includes(`/${prefix}`))).sort();
|
|
8514
8514
|
}
|
|
8515
8515
|
function recipeReceipt(recipe2, result, artifacts) {
|
|
8516
8516
|
const status = result.timedOut ? "timed_out" : result.outputLimitExceeded ? "output_limited" : result.exitCode === 0 && artifacts.every((item) => item.status === "verified") ? "passed" : "failed";
|
|
@@ -9143,7 +9143,7 @@ function createWorkspaceFileRegistry(limit = DEFAULT_MAX_FILES, enumerate = regi
|
|
|
9143
9143
|
files(root) {
|
|
9144
9144
|
const existing = cache2.get(root);
|
|
9145
9145
|
if (existing) return existing;
|
|
9146
|
-
const pending = enumerate(root, limit).then((
|
|
9146
|
+
const pending = enumerate(root, limit).then((paths2) => Object.freeze(paths2));
|
|
9147
9147
|
cache2.set(root, pending);
|
|
9148
9148
|
void pending.catch(() => {
|
|
9149
9149
|
if (cache2.get(root) === pending) cache2.delete(root);
|
|
@@ -9156,7 +9156,7 @@ function createWorkspaceFileRegistry(limit = DEFAULT_MAX_FILES, enumerate = regi
|
|
|
9156
9156
|
};
|
|
9157
9157
|
}
|
|
9158
9158
|
async function registeredFiles(root, limit = DEFAULT_MAX_FILES) {
|
|
9159
|
-
const
|
|
9159
|
+
const paths2 = [];
|
|
9160
9160
|
const walk = async (directory) => {
|
|
9161
9161
|
for (const entry of await (0, import_promises9.readdir)(directory, { withFileTypes: true })) {
|
|
9162
9162
|
if (SKIP_WORKSPACE_DIRS.has(entry.name)) continue;
|
|
@@ -9170,26 +9170,26 @@ async function registeredFiles(root, limit = DEFAULT_MAX_FILES) {
|
|
|
9170
9170
|
} catch {
|
|
9171
9171
|
continue;
|
|
9172
9172
|
}
|
|
9173
|
-
|
|
9174
|
-
if (
|
|
9173
|
+
paths2.push(path);
|
|
9174
|
+
if (paths2.length > limit) throw new TypeError("workspace file registry exceeds its bound");
|
|
9175
9175
|
}
|
|
9176
9176
|
}
|
|
9177
9177
|
};
|
|
9178
9178
|
await walk((0, import_path9.resolve)(root));
|
|
9179
|
-
return
|
|
9179
|
+
return paths2.sort();
|
|
9180
9180
|
}
|
|
9181
|
-
function listWorkspace(
|
|
9181
|
+
function listWorkspace(paths2, options = {}) {
|
|
9182
9182
|
const max = options.maxEntries ?? 1e3;
|
|
9183
9183
|
const prefix = options.prefix?.replace(/\/+$/, "");
|
|
9184
|
-
const scoped = prefix ?
|
|
9184
|
+
const scoped = prefix ? paths2.filter((path) => path === prefix || path.startsWith(`${prefix}/`)) : [...paths2];
|
|
9185
9185
|
return scoped.slice(0, max);
|
|
9186
9186
|
}
|
|
9187
|
-
async function searchWorkspace(root,
|
|
9187
|
+
async function searchWorkspace(root, paths2, options) {
|
|
9188
9188
|
options.signal?.throwIfAborted();
|
|
9189
9189
|
if (!options.query) throw new TypeError("search query must be a non-empty string");
|
|
9190
9190
|
const maxResults = options.maxResults ?? DEFAULT_MAX_RESULTS;
|
|
9191
9191
|
const maxFileBytes = options.maxFileBytes ?? DEFAULT_MAX_FILE_BYTES;
|
|
9192
|
-
const scoped = listWorkspace(
|
|
9192
|
+
const scoped = listWorkspace(paths2, { ...options.prefix ? { prefix: options.prefix } : {}, maxEntries: paths2.length });
|
|
9193
9193
|
if (scoped.length === 0) return [];
|
|
9194
9194
|
try {
|
|
9195
9195
|
return await nativeSearch(root, scoped, { ...options, maxResults, maxFileBytes });
|
|
@@ -9198,11 +9198,11 @@ async function searchWorkspace(root, paths, options) {
|
|
|
9198
9198
|
return fallbackSearch(root, scoped, { ...options, maxResults, maxFileBytes });
|
|
9199
9199
|
}
|
|
9200
9200
|
}
|
|
9201
|
-
async function nativeSearch(root,
|
|
9201
|
+
async function nativeSearch(root, paths2, options) {
|
|
9202
9202
|
const batches = [];
|
|
9203
9203
|
let batch = [];
|
|
9204
9204
|
let bytes = 0;
|
|
9205
|
-
for (const path of
|
|
9205
|
+
for (const path of paths2) {
|
|
9206
9206
|
const size = Buffer.byteLength(path) + 1;
|
|
9207
9207
|
if (batch.length > 0 && bytes + size > MAX_NATIVE_ARG_BYTES) {
|
|
9208
9208
|
batches.push(batch);
|
|
@@ -9221,7 +9221,7 @@ async function nativeSearch(root, paths, options) {
|
|
|
9221
9221
|
}
|
|
9222
9222
|
return matches;
|
|
9223
9223
|
}
|
|
9224
|
-
function nativeSearchBatch(root,
|
|
9224
|
+
function nativeSearchBatch(root, paths2, options, remaining) {
|
|
9225
9225
|
return new Promise((resolveMatches, reject) => {
|
|
9226
9226
|
const args = [
|
|
9227
9227
|
"--fixed-strings",
|
|
@@ -9234,7 +9234,7 @@ function nativeSearchBatch(root, paths, options, remaining) {
|
|
|
9234
9234
|
options.caseSensitive === false ? "--ignore-case" : "--case-sensitive",
|
|
9235
9235
|
"--",
|
|
9236
9236
|
options.query,
|
|
9237
|
-
...
|
|
9237
|
+
...paths2
|
|
9238
9238
|
];
|
|
9239
9239
|
const child = (0, import_child_process6.spawn)("rg", args, {
|
|
9240
9240
|
cwd: root,
|
|
@@ -9380,16 +9380,16 @@ function createCodePolicyGate(options) {
|
|
|
9380
9380
|
}
|
|
9381
9381
|
};
|
|
9382
9382
|
}
|
|
9383
|
-
function directoryPrefixes(
|
|
9383
|
+
function directoryPrefixes(paths2) {
|
|
9384
9384
|
const prefixes = /* @__PURE__ */ new Set(["."]);
|
|
9385
|
-
for (const path of
|
|
9385
|
+
for (const path of paths2) {
|
|
9386
9386
|
const parts = path.split("/");
|
|
9387
9387
|
for (let index = 1; index < parts.length; index += 1) prefixes.add(parts.slice(0, index).join("/"));
|
|
9388
9388
|
}
|
|
9389
9389
|
return [...prefixes].sort();
|
|
9390
9390
|
}
|
|
9391
|
-
async function safePrefix(base,
|
|
9392
|
-
const prefixes = directoryPrefixes(
|
|
9391
|
+
async function safePrefix(base, paths2, prefix) {
|
|
9392
|
+
const prefixes = directoryPrefixes(paths2);
|
|
9393
9393
|
const conversions = await conversionRegistry(
|
|
9394
9394
|
[await registeredPolicy("code.prefix.v1", "code.prefixes.v1", prefixes)],
|
|
9395
9395
|
{ "code.prefixes.v1": prefixes }
|
|
@@ -9500,7 +9500,7 @@ function optionalInteger(value2) {
|
|
|
9500
9500
|
function response(request3, ok, content2, details) {
|
|
9501
9501
|
return { requestId: request3.requestId, ok, content: content2, ...details ? { details } : {} };
|
|
9502
9502
|
}
|
|
9503
|
-
function workspaceGraphs(workspaceDir,
|
|
9503
|
+
function workspaceGraphs(workspaceDir, paths2) {
|
|
9504
9504
|
const existing = cache.get(workspaceDir);
|
|
9505
9505
|
if (existing) return existing;
|
|
9506
9506
|
const read22 = (path) => (0, import_promises11.readFile)((0, import_path10.join)(workspaceDir, path), "utf8");
|
|
@@ -9508,7 +9508,7 @@ function workspaceGraphs(workspaceDir, paths) {
|
|
|
9508
9508
|
// No knownTables: a staged workspace may not carry migrations, and a filter
|
|
9509
9509
|
// that silently drops every table is worse than an unfiltered one. Callers
|
|
9510
9510
|
// with ground truth should build the graph themselves.
|
|
9511
|
-
graph: await buildCodeGraph({ paths, read: read22, data: { ignore: (path) => path.includes(".generated.") } })
|
|
9511
|
+
graph: await buildCodeGraph({ paths: paths2, read: read22, data: { ignore: (path) => path.includes(".generated.") } })
|
|
9512
9512
|
}))();
|
|
9513
9513
|
cache.set(workspaceDir, built);
|
|
9514
9514
|
return built;
|
|
@@ -9561,11 +9561,11 @@ async function read(context, request3, options, policy, registry) {
|
|
|
9561
9561
|
if (endLine < startLine || endLine - startLine + 1 > (options.maxReadLines ?? 2e3)) {
|
|
9562
9562
|
throw new TypeError("requested line range exceeds its bound");
|
|
9563
9563
|
}
|
|
9564
|
-
const
|
|
9565
|
-
if (!
|
|
9564
|
+
const paths2 = await registry.files(context.workspaceDir);
|
|
9565
|
+
if (!paths2.includes(path)) {
|
|
9566
9566
|
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.`);
|
|
9567
9567
|
}
|
|
9568
|
-
const allowed = await policy.read(policyContext(context, request3, options, { paths, path, startLine, endLine }));
|
|
9568
|
+
const allowed = await policy.read(policyContext(context, request3, options, { paths: paths2, path, startLine, endLine }));
|
|
9569
9569
|
if (!allowed) return response(request3, false, "tool denied by CaMeL policy");
|
|
9570
9570
|
const target = resolveCodePath(context.workspaceDir, path);
|
|
9571
9571
|
const info = await (0, import_promises10.stat)(target);
|
|
@@ -9587,16 +9587,16 @@ async function list(context, request3, options, policy, registry) {
|
|
|
9587
9587
|
const prefix = typeof raw === "string" && raw.length > 0 ? raw : void 0;
|
|
9588
9588
|
const maxEntries = optionalInteger(request3.input.maxEntries) ?? 1e3;
|
|
9589
9589
|
if (maxEntries > 5e3) throw new TypeError("maxEntries exceeds its bound");
|
|
9590
|
-
const
|
|
9591
|
-
const allowed = await policy.list(policyContext(context, request3, options, { paths, ...prefix ? { prefix } : {} }));
|
|
9590
|
+
const paths2 = await registry.files(context.workspaceDir);
|
|
9591
|
+
const allowed = await policy.list(policyContext(context, request3, options, { paths: paths2, ...prefix ? { prefix } : {} }));
|
|
9592
9592
|
if (!allowed) return response(request3, false, "tool denied by CaMeL policy");
|
|
9593
|
-
const entries = listWorkspace(
|
|
9593
|
+
const entries = listWorkspace(paths2, { ...prefix ? { prefix } : {}, maxEntries });
|
|
9594
9594
|
if (!entries.length) {
|
|
9595
9595
|
return response(request3, true, prefix ? `No files under "${prefix}".` : "Workspace is empty.", { count: 0 });
|
|
9596
9596
|
}
|
|
9597
|
-
const truncated = entries.length <
|
|
9598
|
-
const hint = !prefix &&
|
|
9599
|
-
\u2026 ${
|
|
9597
|
+
const truncated = entries.length < paths2.length && entries.length === maxEntries;
|
|
9598
|
+
const hint = !prefix && paths2.length > 500 ? `
|
|
9599
|
+
\u2026 ${paths2.length} files total. sandbox.overview is far cheaper for orientation; use a prefix here once you know the area.` : "";
|
|
9600
9600
|
return response(
|
|
9601
9601
|
request3,
|
|
9602
9602
|
true,
|
|
@@ -9614,10 +9614,10 @@ async function search(context, request3, options, policy, registry) {
|
|
|
9614
9614
|
const maxResults = optionalInteger(request3.input.maxResults) ?? 100;
|
|
9615
9615
|
if (maxResults > 500) throw new TypeError("maxResults exceeds its bound");
|
|
9616
9616
|
const caseSensitive = request3.input.caseSensitive === void 0 ? true : request3.input.caseSensitive === true;
|
|
9617
|
-
const
|
|
9618
|
-
const allowed = await policy.search(policyContext(context, request3, options, { paths, query, ...prefix ? { prefix } : {} }));
|
|
9617
|
+
const paths2 = await registry.files(context.workspaceDir);
|
|
9618
|
+
const allowed = await policy.search(policyContext(context, request3, options, { paths: paths2, query, ...prefix ? { prefix } : {} }));
|
|
9619
9619
|
if (!allowed) return response(request3, false, "tool denied by CaMeL policy");
|
|
9620
|
-
const matches = await searchWorkspace(context.workspaceDir,
|
|
9620
|
+
const matches = await searchWorkspace(context.workspaceDir, paths2, {
|
|
9621
9621
|
query,
|
|
9622
9622
|
maxResults,
|
|
9623
9623
|
caseSensitive,
|
|
@@ -9639,8 +9639,8 @@ async function graphQuery(context, request3, options, policy, registry) {
|
|
|
9639
9639
|
selector: query
|
|
9640
9640
|
}));
|
|
9641
9641
|
if (!allowed) return response(request3, false, "tool denied by CaMeL policy");
|
|
9642
|
-
const
|
|
9643
|
-
const graphs = await workspaceGraphs(context.workspaceDir,
|
|
9642
|
+
const paths2 = await registry.files(context.workspaceDir);
|
|
9643
|
+
const graphs = await workspaceGraphs(context.workspaceDir, paths2);
|
|
9644
9644
|
if (request3.tool === "sandbox.overview") {
|
|
9645
9645
|
return response(request3, true, renderOverview(graphs, query || void 0));
|
|
9646
9646
|
}
|
|
@@ -9702,16 +9702,16 @@ function toolFailureMessage(reason) {
|
|
|
9702
9702
|
async function patch(context, request3, options, policy, registry) {
|
|
9703
9703
|
exactKeys(request3.input, ["patch"]);
|
|
9704
9704
|
const value2 = stringField(request3.input, "patch");
|
|
9705
|
-
const
|
|
9706
|
-
if (
|
|
9705
|
+
const paths2 = validateCodePatch(value2, options.maxPatchBytes ?? 256 * 1024);
|
|
9706
|
+
if (paths2.some((path) => options.readOnlyPrefixes?.some((prefix) => path === prefix || path.startsWith(`${prefix}/`)))) {
|
|
9707
9707
|
throw new TypeError("patch targets a read-only reference source");
|
|
9708
9708
|
}
|
|
9709
9709
|
const allowed = await policy.patch(policyContext(context, request3, options, { patch: value2 }));
|
|
9710
9710
|
if (!allowed) return response(request3, false, "tool denied by CaMeL policy");
|
|
9711
|
-
await applyCodePatch(context.workspaceDir, value2,
|
|
9711
|
+
await applyCodePatch(context.workspaceDir, value2, paths2);
|
|
9712
9712
|
registry.invalidate(context.workspaceDir);
|
|
9713
9713
|
forgetWorkspaceGraphs(context.workspaceDir);
|
|
9714
|
-
return response(request3, true, `Applied patch to ${
|
|
9714
|
+
return response(request3, true, `Applied patch to ${paths2.length} file(s).`, { paths: paths2 });
|
|
9715
9715
|
}
|
|
9716
9716
|
async function recipe(context, request3, options, recipes, policy) {
|
|
9717
9717
|
exactKeys(request3.input, ["recipeId"]);
|
|
@@ -10058,16 +10058,107 @@ async function startGoalPursuit(input) {
|
|
|
10058
10058
|
async function appendCodeRuntimeEvent(control, command, event, refs) {
|
|
10059
10059
|
const eventId = `${command.commandId.slice(0, 45)}:${refs.length + 1}`;
|
|
10060
10060
|
refs.push(eventId);
|
|
10061
|
-
const
|
|
10061
|
+
const attributed = { ...event, interactionId: command.commandId };
|
|
10062
|
+
const bounded = attributed.type === "message" ? { ...attributed, body: attributed.body.trim().slice(0, 2e4) || `${attributed.actor} event` } : attributed;
|
|
10062
10063
|
await control.appendSessionEvent(command.sessionId, eventId, bounded);
|
|
10063
10064
|
}
|
|
10064
|
-
|
|
10065
|
-
|
|
10066
|
-
|
|
10065
|
+
function patchStats(value2) {
|
|
10066
|
+
if (typeof value2 !== "string") return {};
|
|
10067
|
+
let additions = 0;
|
|
10068
|
+
let deletions = 0;
|
|
10069
|
+
for (const line2 of value2.slice(0, 262144).split("\n")) {
|
|
10070
|
+
if (line2.startsWith("+++") || line2.startsWith("---")) continue;
|
|
10071
|
+
if (line2.startsWith("+")) additions += 1;
|
|
10072
|
+
else if (line2.startsWith("-")) deletions += 1;
|
|
10073
|
+
}
|
|
10074
|
+
return { ...additions ? { additions } : {}, ...deletions ? { deletions } : {} };
|
|
10075
|
+
}
|
|
10076
|
+
function searchResults(value2) {
|
|
10077
|
+
if (typeof value2 !== "string") return void 0;
|
|
10078
|
+
const results = value2.split("\n").flatMap((line2) => {
|
|
10079
|
+
const match = /^([^:\n]{1,1024}):(\d+):\s?(.*)$/.exec(line2);
|
|
10080
|
+
if (!match) return [];
|
|
10081
|
+
const lineNumber = Number(match[2]);
|
|
10082
|
+
const itemText = text3(match[3], 240);
|
|
10083
|
+
if (!Number.isSafeInteger(lineNumber) || lineNumber < 1) return [];
|
|
10084
|
+
return [{ path: match[1], line: lineNumber, ...itemText ? { text: itemText } : {} }];
|
|
10085
|
+
}).slice(0, 5);
|
|
10086
|
+
return results.length ? results : void 0;
|
|
10087
|
+
}
|
|
10088
|
+
function codeToolRequestPresentation(request3) {
|
|
10089
|
+
const input = request3.input;
|
|
10090
|
+
if (request3.tool === "sandbox.read") {
|
|
10091
|
+
const path = text3(input.path, 1024);
|
|
10092
|
+
if (!path) return void 0;
|
|
10093
|
+
const startLine = integer2(input.startLine);
|
|
10094
|
+
const endLine = integer2(input.endLine);
|
|
10095
|
+
return { kind: "read", path, ...startLine ? { startLine } : {}, ...endLine ? { endLine } : {} };
|
|
10096
|
+
}
|
|
10097
|
+
if (request3.tool === "sandbox.list") {
|
|
10098
|
+
const scope = text3(input.prefix, 1024);
|
|
10099
|
+
return { kind: "list", ...scope ? { scope } : {} };
|
|
10100
|
+
}
|
|
10101
|
+
if (request3.tool === "sandbox.search" || request3.tool === "sandbox.overview" || request3.tool === "sandbox.where_is" || request3.tool === "sandbox.who_imports" || request3.tool === "sandbox.who_touches") {
|
|
10102
|
+
const query = text3(input.query, 512);
|
|
10103
|
+
const scope = request3.tool === "sandbox.search" ? text3(input.prefix, 1024) : void 0;
|
|
10104
|
+
if (request3.tool === "sandbox.search" && !query) return void 0;
|
|
10105
|
+
return { kind: "query", ...query ? { query } : {}, ...scope ? { scope } : {} };
|
|
10106
|
+
}
|
|
10107
|
+
if (request3.tool === "sandbox.apply_patch") {
|
|
10108
|
+
return { kind: "patch", ...patchStats(input.patch) };
|
|
10109
|
+
}
|
|
10110
|
+
const recipeId = text3(input.recipeId, 120);
|
|
10111
|
+
return recipeId ? { kind: "recipe", recipeId } : void 0;
|
|
10112
|
+
}
|
|
10113
|
+
function codeToolResultPresentation(request3, response2) {
|
|
10114
|
+
const started = codeToolRequestPresentation(request3);
|
|
10115
|
+
if (!started || !response2.ok) return started;
|
|
10116
|
+
const details = record32(response2.details);
|
|
10117
|
+
if (started.kind === "read") {
|
|
10118
|
+
return {
|
|
10119
|
+
...started,
|
|
10120
|
+
...integer2(details?.startLine) ? { startLine: integer2(details?.startLine) } : {},
|
|
10121
|
+
...integer2(details?.endLine) ? { endLine: integer2(details?.endLine) } : {},
|
|
10122
|
+
...excerpt(response2.content) ? { excerpt: excerpt(response2.content) } : {}
|
|
10123
|
+
};
|
|
10124
|
+
}
|
|
10125
|
+
if (started.kind === "list") {
|
|
10126
|
+
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);
|
|
10127
|
+
return {
|
|
10128
|
+
...started,
|
|
10129
|
+
...integer2(details?.count) !== void 0 ? { count: integer2(details?.count) } : {},
|
|
10130
|
+
...listed.length ? { paths: listed } : {}
|
|
10131
|
+
};
|
|
10132
|
+
}
|
|
10133
|
+
if (started.kind === "query") {
|
|
10134
|
+
const results = request3.tool === "sandbox.search" ? searchResults(response2.content) : void 0;
|
|
10135
|
+
const resultExcerpt = request3.tool === "sandbox.search" ? void 0 : excerpt(response2.content);
|
|
10136
|
+
return {
|
|
10137
|
+
...started,
|
|
10138
|
+
...integer2(details?.count) !== void 0 ? { count: integer2(details?.count) } : {},
|
|
10139
|
+
...results ? { results } : {},
|
|
10140
|
+
...resultExcerpt ? { excerpt: resultExcerpt } : {}
|
|
10141
|
+
};
|
|
10142
|
+
}
|
|
10143
|
+
if (started.kind === "patch") {
|
|
10144
|
+
return { ...started, ...paths(details?.paths) ? { paths: paths(details?.paths) } : {} };
|
|
10145
|
+
}
|
|
10146
|
+
const output = response2.content.replace(/^Recipe [^\n]*\.?\s*/u, "");
|
|
10147
|
+
return {
|
|
10148
|
+
...started,
|
|
10149
|
+
...integer2(details?.exitCode) !== void 0 ? { exitCode: integer2(details?.exitCode) } : {},
|
|
10150
|
+
...typeof details?.timedOut === "boolean" ? { timedOut: details.timedOut } : {},
|
|
10151
|
+
...typeof details?.outputLimitExceeded === "boolean" ? { outputLimitExceeded: details.outputLimitExceeded } : {},
|
|
10152
|
+
...excerpt(output, true) ? { excerpt: excerpt(output, true) } : {}
|
|
10153
|
+
};
|
|
10154
|
+
}
|
|
10155
|
+
var import_crypto, import_promises5, import_path5, import_child_process4, import_promises6, import_path6, import_child_process5, import_process2, import_crypto2, import_crypto3, import_fs2, import_promises7, import_path7, import_promises8, import_os3, import_path8, import_ai4, import_ai5, import_child_process6, import_promises9, import_path9, import_promises10, import_promises11, import_path10, import_crypto4, CODE_RUNTIME_PROTOCOL_VERSION, CodeRuntimeReconciler, CodeRuntimeControlError, record5, invalid, RESERVED, SECRET, PATH, FORBIDDEN, ARTIFACT_PATH, PRIVATE_ARTIFACT_PART, SHA3, DIGEST3, ID3, RULE, DEFAULT_PREFIXES, DEFAULT_SUFFIXES, message, CodeRuntimeCheckpointManager, record22, SOURCE_LIMITS, RESERVED2, SECRET2, SOURCE_MAX_FILES, SOURCE_MAX_BYTES, SOURCE_SET_MAX_BYTES, V1_SYSTEM_PROMPT, V2_SYSTEM_PROMPT, V3_SYSTEM_PROMPT, SYSTEM_PROMPT_FOR, DEFAULT_MAX_FILES, DEFAULT_MAX_RESULTS, DEFAULT_MAX_FILE_BYTES, MAX_NATIVE_ARG_BYTES, DESTINATIONS, READ, LIST, SEARCH, GRAPH, PATCH, RECIPE, cache, shortId, GRAPH_TOOLS, MAX_MEMORY_BODY, POSITIVE, digestRuntimeValue, runtimeErrorMessage, text3, integer2, record32, excerpt, paths, TheseusRuntimeEngine;
|
|
10156
|
+
var init_chunk_ISR434K7 = __esm({
|
|
10157
|
+
"../harness/dist/chunk-ISR434K7.js"() {
|
|
10067
10158
|
"use strict";
|
|
10068
10159
|
init_cjs_shims();
|
|
10069
|
-
|
|
10070
|
-
|
|
10160
|
+
init_chunk_CR6RE3A2();
|
|
10161
|
+
init_chunk_RXNHCGWE();
|
|
10071
10162
|
import_crypto = require("crypto");
|
|
10072
10163
|
import_promises5 = require("fs/promises");
|
|
10073
10164
|
import_path5 = require("path");
|
|
@@ -10306,6 +10397,30 @@ Never claim a build or test passed unless odla_run_recipe returned that result.`
|
|
|
10306
10397
|
POSITIVE = (value2) => Number.isFinite(value2) && Number(value2) > 0 ? Number(value2) : void 0;
|
|
10307
10398
|
digestRuntimeValue = (value2) => `sha256:${(0, import_crypto4.createHash)("sha256").update(value2).digest("hex")}`;
|
|
10308
10399
|
runtimeErrorMessage = (value2) => value2 instanceof Error ? value2.message : String(value2);
|
|
10400
|
+
text3 = (value2, maximum) => {
|
|
10401
|
+
if (typeof value2 !== "string") return void 0;
|
|
10402
|
+
const bounded = value2.replace(/[\u0000-\u0008\u000b\u000c\u000e-\u001f\u007f]/g, " ").trim();
|
|
10403
|
+
return bounded ? bounded.slice(0, maximum) : void 0;
|
|
10404
|
+
};
|
|
10405
|
+
integer2 = (value2) => Number.isSafeInteger(value2) && Number(value2) >= 0 ? Number(value2) : void 0;
|
|
10406
|
+
record32 = (value2) => value2 && typeof value2 === "object" && !Array.isArray(value2) ? value2 : void 0;
|
|
10407
|
+
excerpt = (value2, tail = false) => {
|
|
10408
|
+
if (typeof value2 !== "string") return void 0;
|
|
10409
|
+
const safe = value2.replace(/[\u0000-\u0008\u000b\u000c\u000e-\u001f\u007f]/g, " ");
|
|
10410
|
+
const source = (tail ? safe.slice(-1e4) : safe.slice(0, 1e4)).trim();
|
|
10411
|
+
if (!source) return void 0;
|
|
10412
|
+
const lines = source.split("\n").filter((line2) => line2.trim()).map((line2) => line2.slice(0, 240));
|
|
10413
|
+
const selected = tail ? lines.slice(-10) : lines.slice(0, 10);
|
|
10414
|
+
return text3(selected.join("\n"), 2400);
|
|
10415
|
+
};
|
|
10416
|
+
paths = (value2) => {
|
|
10417
|
+
if (!Array.isArray(value2)) return void 0;
|
|
10418
|
+
const items = value2.flatMap((item) => {
|
|
10419
|
+
const path = text3(item, 1024);
|
|
10420
|
+
return path ? [path] : [];
|
|
10421
|
+
}).slice(0, 12);
|
|
10422
|
+
return items.length ? items : void 0;
|
|
10423
|
+
};
|
|
10309
10424
|
TheseusRuntimeEngine = class {
|
|
10310
10425
|
constructor(options) {
|
|
10311
10426
|
this.options = options;
|
|
@@ -10539,18 +10654,29 @@ Never claim a build or test passed unless odla_run_recipe returned that result.`
|
|
|
10539
10654
|
return {
|
|
10540
10655
|
execute: async (context, request3) => {
|
|
10541
10656
|
const startedAt = Date.now();
|
|
10657
|
+
const operationId = digestRuntimeValue(`${command.commandId}:${request3.requestId}`);
|
|
10658
|
+
const startedPresentation = codeToolRequestPresentation(request3);
|
|
10542
10659
|
await this.#event(
|
|
10543
10660
|
command,
|
|
10544
|
-
{
|
|
10661
|
+
{
|
|
10662
|
+
type: "tool",
|
|
10663
|
+
phase: "started",
|
|
10664
|
+
tool: request3.tool,
|
|
10665
|
+
operationId,
|
|
10666
|
+
...startedPresentation ? { presentation: startedPresentation } : {}
|
|
10667
|
+
},
|
|
10545
10668
|
active.conversationRefs
|
|
10546
10669
|
).catch(() => void 0);
|
|
10547
10670
|
const response2 = await broker.execute(context, request3);
|
|
10671
|
+
const completedPresentation = codeToolResultPresentation(request3, response2);
|
|
10548
10672
|
await this.#event(command, {
|
|
10549
10673
|
type: "tool",
|
|
10550
10674
|
phase: "completed",
|
|
10551
10675
|
tool: request3.tool,
|
|
10552
10676
|
ok: response2.ok,
|
|
10553
|
-
durationMs: Date.now() - startedAt
|
|
10677
|
+
durationMs: Date.now() - startedAt,
|
|
10678
|
+
operationId,
|
|
10679
|
+
...completedPresentation ? { presentation: completedPresentation } : {}
|
|
10554
10680
|
}, active.conversationRefs).catch(() => void 0);
|
|
10555
10681
|
return response2;
|
|
10556
10682
|
}
|
|
@@ -10591,8 +10717,8 @@ var init_node = __esm({
|
|
|
10591
10717
|
"../harness/dist/node.js"() {
|
|
10592
10718
|
"use strict";
|
|
10593
10719
|
init_cjs_shims();
|
|
10594
|
-
|
|
10595
|
-
|
|
10720
|
+
init_chunk_ISR434K7();
|
|
10721
|
+
init_chunk_CR6RE3A2();
|
|
10596
10722
|
MEASURED_PREMIUM = Object.freeze({
|
|
10597
10723
|
/** 3 racers vs pure depth at equal budget: 21,044 / 7,936. */
|
|
10598
10724
|
racePerRacer: 0.55,
|
|
@@ -12675,8 +12801,8 @@ function collectFields(parsed, allowClear) {
|
|
|
12675
12801
|
if (allowClear) out[spec.key] = null;
|
|
12676
12802
|
continue;
|
|
12677
12803
|
}
|
|
12678
|
-
const
|
|
12679
|
-
out[spec.key] = spec.num ? Number(
|
|
12804
|
+
const text4 = stringOpt(value2);
|
|
12805
|
+
out[spec.key] = spec.num ? Number(text4) : text4;
|
|
12680
12806
|
}
|
|
12681
12807
|
return out;
|
|
12682
12808
|
}
|
|
@@ -14273,14 +14399,14 @@ function statusMinutes(value2) {
|
|
|
14273
14399
|
}
|
|
14274
14400
|
async function read2(url, headers, doFetch) {
|
|
14275
14401
|
const response2 = await doFetch(url, { headers });
|
|
14276
|
-
const
|
|
14402
|
+
const text4 = await response2.text();
|
|
14277
14403
|
let body = {};
|
|
14278
|
-
if (
|
|
14404
|
+
if (text4) {
|
|
14279
14405
|
try {
|
|
14280
|
-
const value2 = JSON.parse(
|
|
14406
|
+
const value2 = JSON.parse(text4);
|
|
14281
14407
|
body = value2 && typeof value2 === "object" && !Array.isArray(value2) ? value2 : { value: value2 };
|
|
14282
14408
|
} catch {
|
|
14283
|
-
body = { message:
|
|
14409
|
+
body = { message: text4.slice(0, 300) };
|
|
14284
14410
|
}
|
|
14285
14411
|
}
|
|
14286
14412
|
return { httpStatus: response2.status, body };
|
|
@@ -14513,13 +14639,13 @@ async function monitorCommand(parsed, deps = {}) {
|
|
|
14513
14639
|
}
|
|
14514
14640
|
async function request2(url, init, doFetch) {
|
|
14515
14641
|
const response2 = await doFetch(url, init);
|
|
14516
|
-
const
|
|
14642
|
+
const text4 = await response2.text();
|
|
14517
14643
|
let body = {};
|
|
14518
14644
|
try {
|
|
14519
|
-
const parsed =
|
|
14645
|
+
const parsed = text4 ? JSON.parse(text4) : {};
|
|
14520
14646
|
body = record10(parsed) ? parsed : { value: parsed };
|
|
14521
14647
|
} catch {
|
|
14522
|
-
body = { message:
|
|
14648
|
+
body = { message: text4.slice(0, 500) };
|
|
14523
14649
|
}
|
|
14524
14650
|
if (!response2.ok) {
|
|
14525
14651
|
const error = record10(body.error) ? body.error : body;
|
|
@@ -14759,8 +14885,8 @@ function runtimeUrl(cfg, suffix = "") {
|
|
|
14759
14885
|
return `${cfg.platformUrl}/registry/apps/${encodeURIComponent(cfg.app.id)}/runtime-credentials${suffix}`;
|
|
14760
14886
|
}
|
|
14761
14887
|
async function safeError(response2) {
|
|
14762
|
-
const
|
|
14763
|
-
return redactSecrets(
|
|
14888
|
+
const text4 = await response2.text();
|
|
14889
|
+
return redactSecrets(text4.slice(0, 1e3));
|
|
14764
14890
|
}
|
|
14765
14891
|
async function finish(doFetch, cfg, token, sessionId, method) {
|
|
14766
14892
|
return doFetch(runtimeUrl(cfg, `/${encodeURIComponent(sessionId)}`), {
|
|
@@ -15255,6 +15381,7 @@ var init_surface = __esm({
|
|
|
15255
15381
|
project: { list: {}, add: {}, create: {}, use: {} },
|
|
15256
15382
|
handoff: {},
|
|
15257
15383
|
next: {},
|
|
15384
|
+
start: {},
|
|
15258
15385
|
watch: {}
|
|
15259
15386
|
},
|
|
15260
15387
|
provision: {},
|
|
@@ -15361,10 +15488,10 @@ var init_advisory_output = __esm({
|
|
|
15361
15488
|
// src/device-ttl.ts
|
|
15362
15489
|
function parseDeviceTtl(raw) {
|
|
15363
15490
|
if (raw === void 0 || raw === true) return void 0;
|
|
15364
|
-
const
|
|
15365
|
-
if (!
|
|
15366
|
-
if (
|
|
15367
|
-
const match = /^(\d+)\s*([dwy])$/.exec(
|
|
15491
|
+
const text4 = String(raw).trim().toLowerCase();
|
|
15492
|
+
if (!text4) return void 0;
|
|
15493
|
+
if (text4 === "forever" || text4 === "never") return 100 * 365 * DAY_MS;
|
|
15494
|
+
const match = /^(\d+)\s*([dwy])$/.exec(text4);
|
|
15368
15495
|
if (!match) {
|
|
15369
15496
|
throw new Error(
|
|
15370
15497
|
`--device-ttl expects a duration like 30d, 6w, 2y, or "forever" (got "${raw}")`
|
|
@@ -15731,12 +15858,12 @@ var init_runbook_actions = __esm({
|
|
|
15731
15858
|
});
|
|
15732
15859
|
|
|
15733
15860
|
// src/runbook-import.ts
|
|
15734
|
-
function parseRunbook(
|
|
15735
|
-
let rest =
|
|
15861
|
+
function parseRunbook(text4, slug) {
|
|
15862
|
+
let rest = text4;
|
|
15736
15863
|
const meta = {};
|
|
15737
|
-
const fm = /^---\r?\n([\s\S]*?)\r?\n---\r?\n?/.exec(
|
|
15864
|
+
const fm = /^---\r?\n([\s\S]*?)\r?\n---\r?\n?/.exec(text4);
|
|
15738
15865
|
if (fm) {
|
|
15739
|
-
rest =
|
|
15866
|
+
rest = text4.slice(fm[0].length);
|
|
15740
15867
|
for (const line2 of fm[1].split(/\r?\n/)) {
|
|
15741
15868
|
const pair = /^(\w+)\s*:\s*(.+)$/.exec(line2.trim());
|
|
15742
15869
|
if (!pair) continue;
|