@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
|
@@ -365,10 +365,10 @@ function isManagedDevVar(line2) {
|
|
|
365
365
|
const match = line2.match(/^\s*(?:export\s+)?([A-Z][A-Z0-9_]*)\s*=/);
|
|
366
366
|
return !!match?.[1] && MANAGED_DEV_VARS.has(match[1]);
|
|
367
367
|
}
|
|
368
|
-
function writePrivateText(path,
|
|
368
|
+
function writePrivateText(path, text4) {
|
|
369
369
|
mkdirSync2(dirname3(path), { recursive: true });
|
|
370
370
|
const temporary = `${path}.tmp-${process.pid}-${Date.now()}`;
|
|
371
|
-
writeFileSync(temporary,
|
|
371
|
+
writeFileSync(temporary, text4, { mode: 384 });
|
|
372
372
|
chmodSync2(temporary, 384);
|
|
373
373
|
renameSync(temporary, path);
|
|
374
374
|
}
|
|
@@ -808,12 +808,12 @@ async function readAdminAiAudit(request3) {
|
|
|
808
808
|
}
|
|
809
809
|
}
|
|
810
810
|
async function responseBody(response2) {
|
|
811
|
-
const
|
|
812
|
-
if (!
|
|
811
|
+
const text4 = await response2.text();
|
|
812
|
+
if (!text4) return {};
|
|
813
813
|
try {
|
|
814
|
-
return JSON.parse(
|
|
814
|
+
return JSON.parse(text4);
|
|
815
815
|
} catch {
|
|
816
|
-
return { message:
|
|
816
|
+
return { message: text4.slice(0, 300) };
|
|
817
817
|
}
|
|
818
818
|
}
|
|
819
819
|
function apiError(status, body) {
|
|
@@ -915,12 +915,12 @@ function timestamp2(value2) {
|
|
|
915
915
|
return Number.isFinite(date.valueOf()) ? date.toISOString() : "";
|
|
916
916
|
}
|
|
917
917
|
async function responseBody2(res) {
|
|
918
|
-
const
|
|
919
|
-
if (!
|
|
918
|
+
const text4 = await res.text();
|
|
919
|
+
if (!text4) return {};
|
|
920
920
|
try {
|
|
921
|
-
return JSON.parse(
|
|
921
|
+
return JSON.parse(text4);
|
|
922
922
|
} catch {
|
|
923
|
-
return { message:
|
|
923
|
+
return { message: text4.slice(0, 300) };
|
|
924
924
|
}
|
|
925
925
|
}
|
|
926
926
|
function apiError2(action2, status, body) {
|
|
@@ -1096,12 +1096,12 @@ function catalogModels(body) {
|
|
|
1096
1096
|
return body.catalog.models.filter((value2) => isRecord3(value2) && typeof value2.id === "string" && typeof value2.provider === "string");
|
|
1097
1097
|
}
|
|
1098
1098
|
async function responseBody3(res) {
|
|
1099
|
-
const
|
|
1100
|
-
if (!
|
|
1099
|
+
const text4 = await res.text();
|
|
1100
|
+
if (!text4) return {};
|
|
1101
1101
|
try {
|
|
1102
|
-
return JSON.parse(
|
|
1102
|
+
return JSON.parse(text4);
|
|
1103
1103
|
} catch {
|
|
1104
|
-
return { message:
|
|
1104
|
+
return { message: text4.slice(0, 300) };
|
|
1105
1105
|
}
|
|
1106
1106
|
}
|
|
1107
1107
|
function apiError3(action2, status, body) {
|
|
@@ -2474,8 +2474,8 @@ async function appImport(options) {
|
|
|
2474
2474
|
const out = options.stdout ?? console;
|
|
2475
2475
|
const say = options.json ? (line2) => out.error(line2) : (line2) => out.log(line2);
|
|
2476
2476
|
const { tenant } = resolveTenant(cfg, options.env);
|
|
2477
|
-
const
|
|
2478
|
-
const { format, sources } = parseImport(
|
|
2477
|
+
const text4 = options.file === "-" ? (options.readStdin ?? (() => readFileSync5(0, "utf8")))() : readFileSync5(options.file, "utf8");
|
|
2478
|
+
const { format, sources } = parseImport(text4, options.ns);
|
|
2479
2479
|
if (format === "namespace-map" && options.ns) {
|
|
2480
2480
|
throw new Error("--ns cannot be combined with a {namespace: rows} file \u2014 the file already names each namespace");
|
|
2481
2481
|
}
|
|
@@ -2691,7 +2691,7 @@ var EXTENSIONS = {
|
|
|
2691
2691
|
"text/html": "html",
|
|
2692
2692
|
"application/json": "json"
|
|
2693
2693
|
};
|
|
2694
|
-
var encode = (
|
|
2694
|
+
var encode = (text4) => new TextEncoder().encode(text4);
|
|
2695
2695
|
function assetFileName(uuid, mime) {
|
|
2696
2696
|
const ext = EXTENSIONS[mime.split(";")[0].trim().toLowerCase()] ?? "bin";
|
|
2697
2697
|
return `${uuid.replace(/[^a-zA-Z0-9._-]/g, "_")}.${ext}`;
|
|
@@ -3549,9 +3549,9 @@ async function assertTenantAdminAccess(doFetch, cfg, env, token) {
|
|
|
3549
3549
|
}
|
|
3550
3550
|
throw new Error(`${env}: tenant access preflight (${tenantId}) failed: ${res.status} ${await safeText5(res)}`);
|
|
3551
3551
|
}
|
|
3552
|
-
function errorCode(
|
|
3552
|
+
function errorCode(text4) {
|
|
3553
3553
|
try {
|
|
3554
|
-
const body = JSON.parse(
|
|
3554
|
+
const body = JSON.parse(text4);
|
|
3555
3555
|
return typeof body.error?.code === "string" ? body.error.code : null;
|
|
3556
3556
|
} catch {
|
|
3557
3557
|
return null;
|
|
@@ -4286,15 +4286,15 @@ function readWranglerConfig(path) {
|
|
|
4286
4286
|
return null;
|
|
4287
4287
|
}
|
|
4288
4288
|
}
|
|
4289
|
-
function stripJsonComments(
|
|
4289
|
+
function stripJsonComments(text4) {
|
|
4290
4290
|
let result = "";
|
|
4291
4291
|
let inString = false;
|
|
4292
|
-
for (let i = 0; i <
|
|
4293
|
-
const ch =
|
|
4292
|
+
for (let i = 0; i < text4.length; i++) {
|
|
4293
|
+
const ch = text4[i];
|
|
4294
4294
|
if (inString) {
|
|
4295
4295
|
result += ch;
|
|
4296
4296
|
if (ch === "\\") {
|
|
4297
|
-
result +=
|
|
4297
|
+
result += text4[i + 1] ?? "";
|
|
4298
4298
|
i++;
|
|
4299
4299
|
} else if (ch === '"') {
|
|
4300
4300
|
inString = false;
|
|
@@ -4306,14 +4306,14 @@ function stripJsonComments(text3) {
|
|
|
4306
4306
|
result += ch;
|
|
4307
4307
|
continue;
|
|
4308
4308
|
}
|
|
4309
|
-
if (ch === "/" &&
|
|
4310
|
-
while (i <
|
|
4309
|
+
if (ch === "/" && text4[i + 1] === "/") {
|
|
4310
|
+
while (i < text4.length && text4[i] !== "\n") i++;
|
|
4311
4311
|
result += "\n";
|
|
4312
4312
|
continue;
|
|
4313
4313
|
}
|
|
4314
|
-
if (ch === "/" &&
|
|
4314
|
+
if (ch === "/" && text4[i + 1] === "*") {
|
|
4315
4315
|
i += 2;
|
|
4316
|
-
while (i <
|
|
4316
|
+
while (i < text4.length && !(text4[i] === "*" && text4[i + 1] === "/")) i++;
|
|
4317
4317
|
i++;
|
|
4318
4318
|
continue;
|
|
4319
4319
|
}
|
|
@@ -4827,9 +4827,9 @@ function initProject(options) {
|
|
|
4827
4827
|
out.log("created src/odla/schema.mjs and src/odla/rules.mjs");
|
|
4828
4828
|
out.log("updated .gitignore for local odla credentials");
|
|
4829
4829
|
}
|
|
4830
|
-
function writeIfMissing(path,
|
|
4830
|
+
function writeIfMissing(path, text4) {
|
|
4831
4831
|
if (existsSync9(path)) return;
|
|
4832
|
-
writeFileSync2(path,
|
|
4832
|
+
writeFileSync2(path, text4);
|
|
4833
4833
|
}
|
|
4834
4834
|
function configTemplate(input) {
|
|
4835
4835
|
const calendar = input.services.includes("calendar") ? ` calendar: {
|
|
@@ -5041,13 +5041,13 @@ async function secretsSetClerkKey(options) {
|
|
|
5041
5041
|
body: JSON.stringify({ value: value2 })
|
|
5042
5042
|
});
|
|
5043
5043
|
if (!res.ok) {
|
|
5044
|
-
const
|
|
5045
|
-
throw new Error(`store Clerk secret key failed (${res.status}): ${
|
|
5044
|
+
const text4 = scrubValue((await res.text().catch(() => "")).slice(0, 300), value2);
|
|
5045
|
+
throw new Error(`store Clerk secret key failed (${res.status}): ${text4 || "request failed"}`);
|
|
5046
5046
|
}
|
|
5047
5047
|
out.log(`Clerk secret key stored for ${tenantId} ($clerk_secret, reserved + write-only; the value was never echoed)`);
|
|
5048
5048
|
}
|
|
5049
|
-
function scrubValue(
|
|
5050
|
-
return redactSecrets(
|
|
5049
|
+
function scrubValue(text4, value2) {
|
|
5050
|
+
return redactSecrets(text4).split(value2).join("[value redacted]");
|
|
5051
5051
|
}
|
|
5052
5052
|
async function resolveVaultWrite(options) {
|
|
5053
5053
|
const out = options.stdout ?? console;
|
|
@@ -5339,8 +5339,8 @@ ${conflicts.map((f) => ` - ${f}`).join("\n")}`
|
|
|
5339
5339
|
harnesses: installations
|
|
5340
5340
|
};
|
|
5341
5341
|
}
|
|
5342
|
-
function pathsUnder(root,
|
|
5343
|
-
return [...
|
|
5342
|
+
function pathsUnder(root, paths2) {
|
|
5343
|
+
return [...paths2].map((path) => relative2(root, path)).filter((path) => path !== ".." && !path.startsWith(`..${sep}`) && !isAbsolute3(path)).sort();
|
|
5344
5344
|
}
|
|
5345
5345
|
function normalizeHarnesses(values, global) {
|
|
5346
5346
|
const requested = values?.length ? values : ["claude"];
|
|
@@ -5769,10 +5769,10 @@ import { existsSync as existsSync11 } from "fs";
|
|
|
5769
5769
|
import { cpus, hostname, totalmem } from "os";
|
|
5770
5770
|
import { resolve as resolve11 } from "path";
|
|
5771
5771
|
|
|
5772
|
-
// ../harness/dist/chunk-
|
|
5772
|
+
// ../harness/dist/chunk-RXNHCGWE.js
|
|
5773
5773
|
var HARNESS_PROTOCOL_VERSION = 1;
|
|
5774
5774
|
|
|
5775
|
-
// ../harness/dist/chunk-
|
|
5775
|
+
// ../harness/dist/chunk-CR6RE3A2.js
|
|
5776
5776
|
import { execFile, spawn as spawn3 } from "child_process";
|
|
5777
5777
|
import { constants } from "fs";
|
|
5778
5778
|
import { access } from "fs/promises";
|
|
@@ -6024,12 +6024,12 @@ async function gitSourceFiles(sourceDir, maxFiles, maxBytes) {
|
|
|
6024
6024
|
});
|
|
6025
6025
|
if (outputBytes > 8 * 1024 * 1024) throw new Error("git file inventory exceeds 8 MiB");
|
|
6026
6026
|
if (code !== 0) throw new Error(`git file inventory failed: ${Buffer.concat(stderr2).toString("utf8").slice(0, 1e3)}`);
|
|
6027
|
-
const
|
|
6028
|
-
if (
|
|
6027
|
+
const paths2 = Buffer.concat(stdout).toString("utf8").split("\0").filter(Boolean).sort();
|
|
6028
|
+
if (paths2.length > maxFiles) throw new Error(`workspace exceeds ${maxFiles} files`);
|
|
6029
6029
|
const root = resolve22(sourceDir);
|
|
6030
6030
|
const files = [];
|
|
6031
6031
|
let bytes = 0;
|
|
6032
|
-
for (const relativePath of
|
|
6032
|
+
for (const relativePath of paths2) {
|
|
6033
6033
|
if (!allowedWorkspacePath(relativePath)) continue;
|
|
6034
6034
|
const source = resolve22(root, relativePath);
|
|
6035
6035
|
if (!source.startsWith(`${root}${sep22}`)) throw new TypeError("git file path escapes workspace");
|
|
@@ -6145,7 +6145,7 @@ async function stageWorkspacePair(baselineSource, workspaceSource, options = {})
|
|
|
6145
6145
|
}
|
|
6146
6146
|
}
|
|
6147
6147
|
|
|
6148
|
-
// ../harness/dist/chunk-
|
|
6148
|
+
// ../harness/dist/chunk-ISR434K7.js
|
|
6149
6149
|
import { createHash as createHash3 } from "crypto";
|
|
6150
6150
|
import { readFile as readFile2, readdir as readdir2 } from "fs/promises";
|
|
6151
6151
|
import { relative as relative4, resolve as resolve10 } from "path";
|
|
@@ -6468,13 +6468,13 @@ function validateSnapshot(snapshot, limits) {
|
|
|
6468
6468
|
if (!Number.isSafeInteger(limits.maximumFiles) || limits.maximumFiles < 1 || !Number.isSafeInteger(limits.maximumBytes) || limits.maximumBytes < 1 || snapshot.files.length > limits.maximumFiles) {
|
|
6469
6469
|
throw new CamelError("limit_exceeded", "Code snapshot exceeds its registered limits.");
|
|
6470
6470
|
}
|
|
6471
|
-
const
|
|
6471
|
+
const paths2 = /* @__PURE__ */ new Set();
|
|
6472
6472
|
let bytes = 0;
|
|
6473
6473
|
for (const file of snapshot.files) {
|
|
6474
|
-
if (!file.path || file.path.startsWith("/") || file.path.includes("\\") || file.path.split("/").some((part) => !part || part === "." || part === "..") ||
|
|
6474
|
+
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") {
|
|
6475
6475
|
throw new CamelError("state_conflict", "Code snapshot contains an invalid or duplicate path.");
|
|
6476
6476
|
}
|
|
6477
|
-
|
|
6477
|
+
paths2.add(file.path);
|
|
6478
6478
|
bytes += utf8Length(file.path) + utf8Length(file.content);
|
|
6479
6479
|
}
|
|
6480
6480
|
if (bytes > limits.maximumBytes) {
|
|
@@ -6482,7 +6482,7 @@ function validateSnapshot(snapshot, limits) {
|
|
|
6482
6482
|
}
|
|
6483
6483
|
}
|
|
6484
6484
|
|
|
6485
|
-
// ../harness/dist/chunk-
|
|
6485
|
+
// ../harness/dist/chunk-ISR434K7.js
|
|
6486
6486
|
import { spawn as spawn4 } from "child_process";
|
|
6487
6487
|
import { lstat as lstat2 } from "fs/promises";
|
|
6488
6488
|
import { resolve as resolve23, sep as sep3 } from "path";
|
|
@@ -6628,8 +6628,8 @@ function boundedInteger(value2, spec) {
|
|
|
6628
6628
|
}
|
|
6629
6629
|
function boundedNumber(value2, spec) {
|
|
6630
6630
|
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.");
|
|
6631
|
-
const
|
|
6632
|
-
if (/e/i.test(
|
|
6631
|
+
const text4 = String(value2);
|
|
6632
|
+
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.");
|
|
6633
6633
|
return value2;
|
|
6634
6634
|
}
|
|
6635
6635
|
function enumMember(value2, spec) {
|
|
@@ -6785,11 +6785,11 @@ function validateUnsafeSelector(path, value2, tool) {
|
|
|
6785
6785
|
return void 0;
|
|
6786
6786
|
}
|
|
6787
6787
|
function looksLikeDestination(value2) {
|
|
6788
|
-
const
|
|
6789
|
-
return /^(?:[a-z][a-z0-9+.-]*:\/\/|\/|\\\\)/i.test(
|
|
6788
|
+
const text4 = value2.trim();
|
|
6789
|
+
return /^(?:[a-z][a-z0-9+.-]*:\/\/|\/|\\\\)/i.test(text4) || /^[\w.-]+\.[a-z]{2,}(?:[/:]|$)/i.test(text4);
|
|
6790
6790
|
}
|
|
6791
6791
|
|
|
6792
|
-
// ../harness/dist/chunk-
|
|
6792
|
+
// ../harness/dist/chunk-ISR434K7.js
|
|
6793
6793
|
import { readFile as readFile4, stat as stat2 } from "fs/promises";
|
|
6794
6794
|
import { readFile as readFile3 } from "fs/promises";
|
|
6795
6795
|
import { join as join33 } from "path";
|
|
@@ -6954,9 +6954,9 @@ async function extractImports(builder, input) {
|
|
|
6954
6954
|
const sources = input.paths.filter(isSourcePath);
|
|
6955
6955
|
const known = new Set(sources);
|
|
6956
6956
|
for (const path of sources) {
|
|
6957
|
-
let
|
|
6957
|
+
let text4;
|
|
6958
6958
|
try {
|
|
6959
|
-
|
|
6959
|
+
text4 = await input.read(path);
|
|
6960
6960
|
} catch {
|
|
6961
6961
|
continue;
|
|
6962
6962
|
}
|
|
@@ -6964,13 +6964,13 @@ async function extractImports(builder, input) {
|
|
|
6964
6964
|
const file = builder.node(FILE, path, pkg ? { pkg } : void 0);
|
|
6965
6965
|
if (pkg) builder.edge(builder.node(PACKAGE, pkg), CONTAINS, file);
|
|
6966
6966
|
const specifiers = /* @__PURE__ */ new Set();
|
|
6967
|
-
for (const match of
|
|
6968
|
-
for (const match of
|
|
6967
|
+
for (const match of text4.matchAll(IMPORT_FROM)) specifiers.add(match[1]);
|
|
6968
|
+
for (const match of text4.matchAll(BARE_IMPORT)) specifiers.add(match[1]);
|
|
6969
6969
|
for (const specifier of specifiers) {
|
|
6970
6970
|
const resolved = resolveImport(path, specifier, known);
|
|
6971
6971
|
if (resolved) builder.edge(file, IMPORTS, nodeId(FILE, resolved));
|
|
6972
6972
|
}
|
|
6973
|
-
for (const name of exportedNames(
|
|
6973
|
+
for (const name of exportedNames(text4)) {
|
|
6974
6974
|
builder.edge(file, EXPORTS, builder.node(SYMBOL, name));
|
|
6975
6975
|
}
|
|
6976
6976
|
}
|
|
@@ -7011,16 +7011,16 @@ async function extractData(builder, input) {
|
|
|
7011
7011
|
};
|
|
7012
7012
|
for (const path of input.paths) {
|
|
7013
7013
|
if (!SOURCE_FILE.test(path) || input.ignore?.(path)) continue;
|
|
7014
|
-
let
|
|
7014
|
+
let text4;
|
|
7015
7015
|
try {
|
|
7016
|
-
|
|
7016
|
+
text4 = await input.read(path);
|
|
7017
7017
|
} catch {
|
|
7018
7018
|
continue;
|
|
7019
7019
|
}
|
|
7020
|
-
for (const statement of
|
|
7020
|
+
for (const statement of text4.matchAll(STATEMENT)) {
|
|
7021
7021
|
const verb = statement[1].toUpperCase().replace(/\s+/g, " ");
|
|
7022
7022
|
const start = statement.index ?? 0;
|
|
7023
|
-
const rest =
|
|
7023
|
+
const rest = text4.slice(start + statement[0].length, start + STATEMENT_WINDOW);
|
|
7024
7024
|
if (verb === "SELECT") {
|
|
7025
7025
|
for (const read3 of rest.matchAll(READ_TABLES)) touch(path, read3[1].toLowerCase(), TABLE, READS);
|
|
7026
7026
|
continue;
|
|
@@ -7036,16 +7036,16 @@ async function extractData(builder, input) {
|
|
|
7036
7036
|
for (const read3 of rest.matchAll(READ_TABLES)) touch(path, read3[1].toLowerCase(), TABLE, READS);
|
|
7037
7037
|
}
|
|
7038
7038
|
}
|
|
7039
|
-
for (const match of
|
|
7040
|
-
touch(path, `${match[1]}.${match[2]}`, NAMESPACE, accessFor(
|
|
7039
|
+
for (const match of text4.matchAll(NS_CONST)) {
|
|
7040
|
+
touch(path, `${match[1]}.${match[2]}`, NAMESPACE, accessFor(text4, match.index ?? 0));
|
|
7041
7041
|
}
|
|
7042
|
-
for (const match of
|
|
7043
|
-
touch(path, match[1], NAMESPACE, accessFor(
|
|
7042
|
+
for (const match of text4.matchAll(NS_LITERAL)) {
|
|
7043
|
+
touch(path, match[1], NAMESPACE, accessFor(text4, match.index ?? 0));
|
|
7044
7044
|
}
|
|
7045
7045
|
}
|
|
7046
7046
|
}
|
|
7047
|
-
function accessFor(
|
|
7048
|
-
const window =
|
|
7047
|
+
function accessFor(text4, index) {
|
|
7048
|
+
const window = text4.slice(Math.max(0, index - 160), index + 40);
|
|
7049
7049
|
return /\b(?:transact|update|delete|create|insert|Ops)\b/.test(window) ? WRITES : READS;
|
|
7050
7050
|
}
|
|
7051
7051
|
async function buildCodeGraph(input) {
|
|
@@ -7057,7 +7057,7 @@ async function buildCodeGraph(input) {
|
|
|
7057
7057
|
return builder.build();
|
|
7058
7058
|
}
|
|
7059
7059
|
|
|
7060
|
-
// ../harness/dist/chunk-
|
|
7060
|
+
// ../harness/dist/chunk-ISR434K7.js
|
|
7061
7061
|
import { createHash as createHash32 } from "crypto";
|
|
7062
7062
|
async function digestStagedWorkspace(root, limits) {
|
|
7063
7063
|
const files = [];
|
|
@@ -7385,7 +7385,7 @@ function validateCodePatch(rawPatch, maxBytes) {
|
|
|
7385
7385
|
if (FORBIDDEN.test(patch2) || /(?:old|new)(?: file)? mode 120000/.test(patch2)) {
|
|
7386
7386
|
throw new TypeError("patch uses a forbidden binary, link, mode, rename, or copy operation");
|
|
7387
7387
|
}
|
|
7388
|
-
const
|
|
7388
|
+
const paths2 = [];
|
|
7389
7389
|
const lines = patch2.split("\n");
|
|
7390
7390
|
for (let index = 0; index < lines.length; index += 1) {
|
|
7391
7391
|
const line2 = lines[index];
|
|
@@ -7401,10 +7401,10 @@ function validateCodePatch(rawPatch, maxBytes) {
|
|
|
7401
7401
|
if (!validHeaderPath(oldPath, path, "a") || !validHeaderPath(newPath, path, "b")) {
|
|
7402
7402
|
throw new TypeError("patch file headers do not match the declared path");
|
|
7403
7403
|
}
|
|
7404
|
-
|
|
7404
|
+
paths2.push(path);
|
|
7405
7405
|
}
|
|
7406
|
-
if (!
|
|
7407
|
-
return
|
|
7406
|
+
if (!paths2.length || new Set(paths2).size !== paths2.length) throw new TypeError("patch has no diffs or repeats a path");
|
|
7407
|
+
return paths2;
|
|
7408
7408
|
}
|
|
7409
7409
|
function validHeaderPath(value2, path, prefix) {
|
|
7410
7410
|
return value2 === "/dev/null" || value2 === `${prefix}/${path}`;
|
|
@@ -7429,11 +7429,11 @@ function describePatchFailure(patch2, detail) {
|
|
|
7429
7429
|
const hint = hunks.length > 0 && contextless ? " A hunk has no context lines; include at least one unchanged line above or below each change." : "";
|
|
7430
7430
|
return `patch did not apply: ${detail}${hint}`;
|
|
7431
7431
|
}
|
|
7432
|
-
async function applyCodePatch(workspaceDir, rawPatch,
|
|
7432
|
+
async function applyCodePatch(workspaceDir, rawPatch, paths2) {
|
|
7433
7433
|
const patch2 = stripPatchEnvelope(rawPatch);
|
|
7434
7434
|
await gitApply(workspaceDir, patch2, true);
|
|
7435
7435
|
await gitApply(workspaceDir, patch2, false);
|
|
7436
|
-
for (const path of
|
|
7436
|
+
for (const path of paths2) {
|
|
7437
7437
|
try {
|
|
7438
7438
|
const info = await lstat2(resolveCodePath(workspaceDir, path));
|
|
7439
7439
|
if (info.isSymbolicLink() || !info.isFile() && !info.isDirectory()) {
|
|
@@ -7455,8 +7455,8 @@ function gitApply(cwd, patch2, check) {
|
|
|
7455
7455
|
});
|
|
7456
7456
|
let stderr2 = "";
|
|
7457
7457
|
child.stderr.setEncoding("utf8");
|
|
7458
|
-
child.stderr.on("data", (
|
|
7459
|
-
if (stderr2.length < 4e3) stderr2 +=
|
|
7458
|
+
child.stderr.on("data", (text22) => {
|
|
7459
|
+
if (stderr2.length < 4e3) stderr2 += text22.slice(0, 4e3);
|
|
7460
7460
|
});
|
|
7461
7461
|
child.once("error", reject);
|
|
7462
7462
|
child.once("exit", (code) => code === 0 ? accept() : reject(new TypeError(describePatchFailure(patch2, stderr2.trim().slice(0, 500)))));
|
|
@@ -7480,8 +7480,8 @@ async function restoreCodeWorkspaceCheckpoint(input) {
|
|
|
7480
7480
|
const workspace = await stageWorkspace(input.trustedBaseDir, input.stage);
|
|
7481
7481
|
try {
|
|
7482
7482
|
if (checkpoint.patch) {
|
|
7483
|
-
const
|
|
7484
|
-
await applyCodePatch(workspace.workspaceDir, checkpoint.patch,
|
|
7483
|
+
const paths2 = validateCodePatch(checkpoint.patch, 256 * 1024);
|
|
7484
|
+
await applyCodePatch(workspace.workspaceDir, checkpoint.patch, paths2);
|
|
7485
7485
|
}
|
|
7486
7486
|
return { workspace, checkpoint };
|
|
7487
7487
|
} catch (error) {
|
|
@@ -7630,8 +7630,8 @@ async function verifyCodeCandidate(input) {
|
|
|
7630
7630
|
try {
|
|
7631
7631
|
const baseDigest = await digestStagedWorkspace(staged.workspaceDir, limits);
|
|
7632
7632
|
if (baseDigest !== input.trustedBaseDigest) throw new TypeError("trusted base does not match its registered digest");
|
|
7633
|
-
const
|
|
7634
|
-
await applyCodePatch(staged.workspaceDir, input.candidatePatch,
|
|
7633
|
+
const paths2 = validateCodePatch(input.candidatePatch, policy.maximumPatchBytes);
|
|
7634
|
+
await applyCodePatch(staged.workspaceDir, input.candidatePatch, paths2);
|
|
7635
7635
|
const sourceDigest = await digestStagedWorkspace(staged.workspaceDir, limits);
|
|
7636
7636
|
const policyDigest = digestPolicy(policy);
|
|
7637
7637
|
const patchDigest = digestBytes(input.candidatePatch);
|
|
@@ -7640,7 +7640,7 @@ async function verifyCodeCandidate(input) {
|
|
|
7640
7640
|
trustedBaseDigest: input.trustedBaseDigest,
|
|
7641
7641
|
patchDigest
|
|
7642
7642
|
});
|
|
7643
|
-
const changedTests = changedTestPaths(
|
|
7643
|
+
const changedTests = changedTestPaths(paths2, policy);
|
|
7644
7644
|
if (changedTests.length > policy.maximumChangedTests) throw new TypeError("candidate changes too many test files");
|
|
7645
7645
|
const recipes = [];
|
|
7646
7646
|
const logs = [];
|
|
@@ -7707,8 +7707,8 @@ function validate2(input) {
|
|
|
7707
7707
|
}
|
|
7708
7708
|
return result;
|
|
7709
7709
|
}
|
|
7710
|
-
function changedTestPaths(
|
|
7711
|
-
return
|
|
7710
|
+
function changedTestPaths(paths2, policy) {
|
|
7711
|
+
return paths2.filter((path) => policy.testPathSuffixes.some((suffix) => path.endsWith(suffix)) || policy.testPathPrefixes.some((prefix) => path.startsWith(prefix) || path.includes(`/${prefix}`))).sort();
|
|
7712
7712
|
}
|
|
7713
7713
|
function recipeReceipt(recipe2, result, artifacts) {
|
|
7714
7714
|
const status = result.timedOut ? "timed_out" : result.outputLimitExceeded ? "output_limited" : result.exitCode === 0 && artifacts.every((item) => item.status === "verified") ? "passed" : "failed";
|
|
@@ -8439,7 +8439,7 @@ function createWorkspaceFileRegistry(limit = DEFAULT_MAX_FILES, enumerate = regi
|
|
|
8439
8439
|
files(root) {
|
|
8440
8440
|
const existing = cache2.get(root);
|
|
8441
8441
|
if (existing) return existing;
|
|
8442
|
-
const pending = enumerate(root, limit).then((
|
|
8442
|
+
const pending = enumerate(root, limit).then((paths2) => Object.freeze(paths2));
|
|
8443
8443
|
cache2.set(root, pending);
|
|
8444
8444
|
void pending.catch(() => {
|
|
8445
8445
|
if (cache2.get(root) === pending) cache2.delete(root);
|
|
@@ -8452,7 +8452,7 @@ function createWorkspaceFileRegistry(limit = DEFAULT_MAX_FILES, enumerate = regi
|
|
|
8452
8452
|
};
|
|
8453
8453
|
}
|
|
8454
8454
|
async function registeredFiles(root, limit = DEFAULT_MAX_FILES) {
|
|
8455
|
-
const
|
|
8455
|
+
const paths2 = [];
|
|
8456
8456
|
const walk = async (directory) => {
|
|
8457
8457
|
for (const entry of await readdir22(directory, { withFileTypes: true })) {
|
|
8458
8458
|
if (SKIP_WORKSPACE_DIRS.has(entry.name)) continue;
|
|
@@ -8466,26 +8466,26 @@ async function registeredFiles(root, limit = DEFAULT_MAX_FILES) {
|
|
|
8466
8466
|
} catch {
|
|
8467
8467
|
continue;
|
|
8468
8468
|
}
|
|
8469
|
-
|
|
8470
|
-
if (
|
|
8469
|
+
paths2.push(path);
|
|
8470
|
+
if (paths2.length > limit) throw new TypeError("workspace file registry exceeds its bound");
|
|
8471
8471
|
}
|
|
8472
8472
|
}
|
|
8473
8473
|
};
|
|
8474
8474
|
await walk(resolve42(root));
|
|
8475
|
-
return
|
|
8475
|
+
return paths2.sort();
|
|
8476
8476
|
}
|
|
8477
|
-
function listWorkspace(
|
|
8477
|
+
function listWorkspace(paths2, options = {}) {
|
|
8478
8478
|
const max = options.maxEntries ?? 1e3;
|
|
8479
8479
|
const prefix = options.prefix?.replace(/\/+$/, "");
|
|
8480
|
-
const scoped = prefix ?
|
|
8480
|
+
const scoped = prefix ? paths2.filter((path) => path === prefix || path.startsWith(`${prefix}/`)) : [...paths2];
|
|
8481
8481
|
return scoped.slice(0, max);
|
|
8482
8482
|
}
|
|
8483
|
-
async function searchWorkspace(root,
|
|
8483
|
+
async function searchWorkspace(root, paths2, options) {
|
|
8484
8484
|
options.signal?.throwIfAborted();
|
|
8485
8485
|
if (!options.query) throw new TypeError("search query must be a non-empty string");
|
|
8486
8486
|
const maxResults = options.maxResults ?? DEFAULT_MAX_RESULTS;
|
|
8487
8487
|
const maxFileBytes = options.maxFileBytes ?? DEFAULT_MAX_FILE_BYTES;
|
|
8488
|
-
const scoped = listWorkspace(
|
|
8488
|
+
const scoped = listWorkspace(paths2, { ...options.prefix ? { prefix: options.prefix } : {}, maxEntries: paths2.length });
|
|
8489
8489
|
if (scoped.length === 0) return [];
|
|
8490
8490
|
try {
|
|
8491
8491
|
return await nativeSearch(root, scoped, { ...options, maxResults, maxFileBytes });
|
|
@@ -8495,11 +8495,11 @@ async function searchWorkspace(root, paths, options) {
|
|
|
8495
8495
|
}
|
|
8496
8496
|
}
|
|
8497
8497
|
var MAX_NATIVE_ARG_BYTES = 96 * 1024;
|
|
8498
|
-
async function nativeSearch(root,
|
|
8498
|
+
async function nativeSearch(root, paths2, options) {
|
|
8499
8499
|
const batches = [];
|
|
8500
8500
|
let batch = [];
|
|
8501
8501
|
let bytes = 0;
|
|
8502
|
-
for (const path of
|
|
8502
|
+
for (const path of paths2) {
|
|
8503
8503
|
const size = Buffer.byteLength(path) + 1;
|
|
8504
8504
|
if (batch.length > 0 && bytes + size > MAX_NATIVE_ARG_BYTES) {
|
|
8505
8505
|
batches.push(batch);
|
|
@@ -8518,7 +8518,7 @@ async function nativeSearch(root, paths, options) {
|
|
|
8518
8518
|
}
|
|
8519
8519
|
return matches;
|
|
8520
8520
|
}
|
|
8521
|
-
function nativeSearchBatch(root,
|
|
8521
|
+
function nativeSearchBatch(root, paths2, options, remaining) {
|
|
8522
8522
|
return new Promise((resolveMatches, reject) => {
|
|
8523
8523
|
const args = [
|
|
8524
8524
|
"--fixed-strings",
|
|
@@ -8531,7 +8531,7 @@ function nativeSearchBatch(root, paths, options, remaining) {
|
|
|
8531
8531
|
options.caseSensitive === false ? "--ignore-case" : "--case-sensitive",
|
|
8532
8532
|
"--",
|
|
8533
8533
|
options.query,
|
|
8534
|
-
...
|
|
8534
|
+
...paths2
|
|
8535
8535
|
];
|
|
8536
8536
|
const child = spawn33("rg", args, {
|
|
8537
8537
|
cwd: root,
|
|
@@ -8717,16 +8717,16 @@ function createCodePolicyGate(options) {
|
|
|
8717
8717
|
}
|
|
8718
8718
|
};
|
|
8719
8719
|
}
|
|
8720
|
-
function directoryPrefixes(
|
|
8720
|
+
function directoryPrefixes(paths2) {
|
|
8721
8721
|
const prefixes = /* @__PURE__ */ new Set(["."]);
|
|
8722
|
-
for (const path of
|
|
8722
|
+
for (const path of paths2) {
|
|
8723
8723
|
const parts = path.split("/");
|
|
8724
8724
|
for (let index = 1; index < parts.length; index += 1) prefixes.add(parts.slice(0, index).join("/"));
|
|
8725
8725
|
}
|
|
8726
8726
|
return [...prefixes].sort();
|
|
8727
8727
|
}
|
|
8728
|
-
async function safePrefix(base,
|
|
8729
|
-
const prefixes = directoryPrefixes(
|
|
8728
|
+
async function safePrefix(base, paths2, prefix) {
|
|
8729
|
+
const prefixes = directoryPrefixes(paths2);
|
|
8730
8730
|
const conversions = await conversionRegistry(
|
|
8731
8731
|
[await registeredPolicy("code.prefix.v1", "code.prefixes.v1", prefixes)],
|
|
8732
8732
|
{ "code.prefixes.v1": prefixes }
|
|
@@ -8838,7 +8838,7 @@ function response(request3, ok, content2, details) {
|
|
|
8838
8838
|
return { requestId: request3.requestId, ok, content: content2, ...details ? { details } : {} };
|
|
8839
8839
|
}
|
|
8840
8840
|
var cache = /* @__PURE__ */ new Map();
|
|
8841
|
-
function workspaceGraphs(workspaceDir,
|
|
8841
|
+
function workspaceGraphs(workspaceDir, paths2) {
|
|
8842
8842
|
const existing = cache.get(workspaceDir);
|
|
8843
8843
|
if (existing) return existing;
|
|
8844
8844
|
const read22 = (path) => readFile3(join33(workspaceDir, path), "utf8");
|
|
@@ -8846,7 +8846,7 @@ function workspaceGraphs(workspaceDir, paths) {
|
|
|
8846
8846
|
// No knownTables: a staged workspace may not carry migrations, and a filter
|
|
8847
8847
|
// that silently drops every table is worse than an unfiltered one. Callers
|
|
8848
8848
|
// with ground truth should build the graph themselves.
|
|
8849
|
-
graph: await buildCodeGraph({ paths, read: read22, data: { ignore: (path) => path.includes(".generated.") } })
|
|
8849
|
+
graph: await buildCodeGraph({ paths: paths2, read: read22, data: { ignore: (path) => path.includes(".generated.") } })
|
|
8850
8850
|
}))();
|
|
8851
8851
|
cache.set(workspaceDir, built);
|
|
8852
8852
|
return built;
|
|
@@ -8906,11 +8906,11 @@ async function read(context, request3, options, policy, registry) {
|
|
|
8906
8906
|
if (endLine < startLine || endLine - startLine + 1 > (options.maxReadLines ?? 2e3)) {
|
|
8907
8907
|
throw new TypeError("requested line range exceeds its bound");
|
|
8908
8908
|
}
|
|
8909
|
-
const
|
|
8910
|
-
if (!
|
|
8909
|
+
const paths2 = await registry.files(context.workspaceDir);
|
|
8910
|
+
if (!paths2.includes(path)) {
|
|
8911
8911
|
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.`);
|
|
8912
8912
|
}
|
|
8913
|
-
const allowed = await policy.read(policyContext(context, request3, options, { paths, path, startLine, endLine }));
|
|
8913
|
+
const allowed = await policy.read(policyContext(context, request3, options, { paths: paths2, path, startLine, endLine }));
|
|
8914
8914
|
if (!allowed) return response(request3, false, "tool denied by CaMeL policy");
|
|
8915
8915
|
const target = resolveCodePath(context.workspaceDir, path);
|
|
8916
8916
|
const info = await stat2(target);
|
|
@@ -8932,16 +8932,16 @@ async function list(context, request3, options, policy, registry) {
|
|
|
8932
8932
|
const prefix = typeof raw === "string" && raw.length > 0 ? raw : void 0;
|
|
8933
8933
|
const maxEntries = optionalInteger(request3.input.maxEntries) ?? 1e3;
|
|
8934
8934
|
if (maxEntries > 5e3) throw new TypeError("maxEntries exceeds its bound");
|
|
8935
|
-
const
|
|
8936
|
-
const allowed = await policy.list(policyContext(context, request3, options, { paths, ...prefix ? { prefix } : {} }));
|
|
8935
|
+
const paths2 = await registry.files(context.workspaceDir);
|
|
8936
|
+
const allowed = await policy.list(policyContext(context, request3, options, { paths: paths2, ...prefix ? { prefix } : {} }));
|
|
8937
8937
|
if (!allowed) return response(request3, false, "tool denied by CaMeL policy");
|
|
8938
|
-
const entries = listWorkspace(
|
|
8938
|
+
const entries = listWorkspace(paths2, { ...prefix ? { prefix } : {}, maxEntries });
|
|
8939
8939
|
if (!entries.length) {
|
|
8940
8940
|
return response(request3, true, prefix ? `No files under "${prefix}".` : "Workspace is empty.", { count: 0 });
|
|
8941
8941
|
}
|
|
8942
|
-
const truncated = entries.length <
|
|
8943
|
-
const hint = !prefix &&
|
|
8944
|
-
\u2026 ${
|
|
8942
|
+
const truncated = entries.length < paths2.length && entries.length === maxEntries;
|
|
8943
|
+
const hint = !prefix && paths2.length > 500 ? `
|
|
8944
|
+
\u2026 ${paths2.length} files total. sandbox.overview is far cheaper for orientation; use a prefix here once you know the area.` : "";
|
|
8945
8945
|
return response(
|
|
8946
8946
|
request3,
|
|
8947
8947
|
true,
|
|
@@ -8959,10 +8959,10 @@ async function search(context, request3, options, policy, registry) {
|
|
|
8959
8959
|
const maxResults = optionalInteger(request3.input.maxResults) ?? 100;
|
|
8960
8960
|
if (maxResults > 500) throw new TypeError("maxResults exceeds its bound");
|
|
8961
8961
|
const caseSensitive = request3.input.caseSensitive === void 0 ? true : request3.input.caseSensitive === true;
|
|
8962
|
-
const
|
|
8963
|
-
const allowed = await policy.search(policyContext(context, request3, options, { paths, query, ...prefix ? { prefix } : {} }));
|
|
8962
|
+
const paths2 = await registry.files(context.workspaceDir);
|
|
8963
|
+
const allowed = await policy.search(policyContext(context, request3, options, { paths: paths2, query, ...prefix ? { prefix } : {} }));
|
|
8964
8964
|
if (!allowed) return response(request3, false, "tool denied by CaMeL policy");
|
|
8965
|
-
const matches = await searchWorkspace(context.workspaceDir,
|
|
8965
|
+
const matches = await searchWorkspace(context.workspaceDir, paths2, {
|
|
8966
8966
|
query,
|
|
8967
8967
|
maxResults,
|
|
8968
8968
|
caseSensitive,
|
|
@@ -8984,8 +8984,8 @@ async function graphQuery(context, request3, options, policy, registry) {
|
|
|
8984
8984
|
selector: query
|
|
8985
8985
|
}));
|
|
8986
8986
|
if (!allowed) return response(request3, false, "tool denied by CaMeL policy");
|
|
8987
|
-
const
|
|
8988
|
-
const graphs = await workspaceGraphs(context.workspaceDir,
|
|
8987
|
+
const paths2 = await registry.files(context.workspaceDir);
|
|
8988
|
+
const graphs = await workspaceGraphs(context.workspaceDir, paths2);
|
|
8989
8989
|
if (request3.tool === "sandbox.overview") {
|
|
8990
8990
|
return response(request3, true, renderOverview(graphs, query || void 0));
|
|
8991
8991
|
}
|
|
@@ -9047,16 +9047,16 @@ function toolFailureMessage(reason) {
|
|
|
9047
9047
|
async function patch(context, request3, options, policy, registry) {
|
|
9048
9048
|
exactKeys(request3.input, ["patch"]);
|
|
9049
9049
|
const value2 = stringField(request3.input, "patch");
|
|
9050
|
-
const
|
|
9051
|
-
if (
|
|
9050
|
+
const paths2 = validateCodePatch(value2, options.maxPatchBytes ?? 256 * 1024);
|
|
9051
|
+
if (paths2.some((path) => options.readOnlyPrefixes?.some((prefix) => path === prefix || path.startsWith(`${prefix}/`)))) {
|
|
9052
9052
|
throw new TypeError("patch targets a read-only reference source");
|
|
9053
9053
|
}
|
|
9054
9054
|
const allowed = await policy.patch(policyContext(context, request3, options, { patch: value2 }));
|
|
9055
9055
|
if (!allowed) return response(request3, false, "tool denied by CaMeL policy");
|
|
9056
|
-
await applyCodePatch(context.workspaceDir, value2,
|
|
9056
|
+
await applyCodePatch(context.workspaceDir, value2, paths2);
|
|
9057
9057
|
registry.invalidate(context.workspaceDir);
|
|
9058
9058
|
forgetWorkspaceGraphs(context.workspaceDir);
|
|
9059
|
-
return response(request3, true, `Applied patch to ${
|
|
9059
|
+
return response(request3, true, `Applied patch to ${paths2.length} file(s).`, { paths: paths2 });
|
|
9060
9060
|
}
|
|
9061
9061
|
async function recipe(context, request3, options, recipes, policy) {
|
|
9062
9062
|
exactKeys(request3.input, ["recipeId"]);
|
|
@@ -9405,11 +9405,126 @@ async function startGoalPursuit(input) {
|
|
|
9405
9405
|
async function appendCodeRuntimeEvent(control, command, event, refs) {
|
|
9406
9406
|
const eventId = `${command.commandId.slice(0, 45)}:${refs.length + 1}`;
|
|
9407
9407
|
refs.push(eventId);
|
|
9408
|
-
const
|
|
9408
|
+
const attributed = { ...event, interactionId: command.commandId };
|
|
9409
|
+
const bounded = attributed.type === "message" ? { ...attributed, body: attributed.body.trim().slice(0, 2e4) || `${attributed.actor} event` } : attributed;
|
|
9409
9410
|
await control.appendSessionEvent(command.sessionId, eventId, bounded);
|
|
9410
9411
|
}
|
|
9411
9412
|
var digestRuntimeValue = (value2) => `sha256:${createHash32("sha256").update(value2).digest("hex")}`;
|
|
9412
9413
|
var runtimeErrorMessage = (value2) => value2 instanceof Error ? value2.message : String(value2);
|
|
9414
|
+
var text3 = (value2, maximum) => {
|
|
9415
|
+
if (typeof value2 !== "string") return void 0;
|
|
9416
|
+
const bounded = value2.replace(/[\u0000-\u0008\u000b\u000c\u000e-\u001f\u007f]/g, " ").trim();
|
|
9417
|
+
return bounded ? bounded.slice(0, maximum) : void 0;
|
|
9418
|
+
};
|
|
9419
|
+
var integer2 = (value2) => Number.isSafeInteger(value2) && Number(value2) >= 0 ? Number(value2) : void 0;
|
|
9420
|
+
var record32 = (value2) => value2 && typeof value2 === "object" && !Array.isArray(value2) ? value2 : void 0;
|
|
9421
|
+
var excerpt = (value2, tail = false) => {
|
|
9422
|
+
if (typeof value2 !== "string") return void 0;
|
|
9423
|
+
const safe = value2.replace(/[\u0000-\u0008\u000b\u000c\u000e-\u001f\u007f]/g, " ");
|
|
9424
|
+
const source = (tail ? safe.slice(-1e4) : safe.slice(0, 1e4)).trim();
|
|
9425
|
+
if (!source) return void 0;
|
|
9426
|
+
const lines = source.split("\n").filter((line2) => line2.trim()).map((line2) => line2.slice(0, 240));
|
|
9427
|
+
const selected = tail ? lines.slice(-10) : lines.slice(0, 10);
|
|
9428
|
+
return text3(selected.join("\n"), 2400);
|
|
9429
|
+
};
|
|
9430
|
+
var paths = (value2) => {
|
|
9431
|
+
if (!Array.isArray(value2)) return void 0;
|
|
9432
|
+
const items = value2.flatMap((item) => {
|
|
9433
|
+
const path = text3(item, 1024);
|
|
9434
|
+
return path ? [path] : [];
|
|
9435
|
+
}).slice(0, 12);
|
|
9436
|
+
return items.length ? items : void 0;
|
|
9437
|
+
};
|
|
9438
|
+
function patchStats(value2) {
|
|
9439
|
+
if (typeof value2 !== "string") return {};
|
|
9440
|
+
let additions = 0;
|
|
9441
|
+
let deletions = 0;
|
|
9442
|
+
for (const line2 of value2.slice(0, 262144).split("\n")) {
|
|
9443
|
+
if (line2.startsWith("+++") || line2.startsWith("---")) continue;
|
|
9444
|
+
if (line2.startsWith("+")) additions += 1;
|
|
9445
|
+
else if (line2.startsWith("-")) deletions += 1;
|
|
9446
|
+
}
|
|
9447
|
+
return { ...additions ? { additions } : {}, ...deletions ? { deletions } : {} };
|
|
9448
|
+
}
|
|
9449
|
+
function searchResults(value2) {
|
|
9450
|
+
if (typeof value2 !== "string") return void 0;
|
|
9451
|
+
const results = value2.split("\n").flatMap((line2) => {
|
|
9452
|
+
const match = /^([^:\n]{1,1024}):(\d+):\s?(.*)$/.exec(line2);
|
|
9453
|
+
if (!match) return [];
|
|
9454
|
+
const lineNumber = Number(match[2]);
|
|
9455
|
+
const itemText = text3(match[3], 240);
|
|
9456
|
+
if (!Number.isSafeInteger(lineNumber) || lineNumber < 1) return [];
|
|
9457
|
+
return [{ path: match[1], line: lineNumber, ...itemText ? { text: itemText } : {} }];
|
|
9458
|
+
}).slice(0, 5);
|
|
9459
|
+
return results.length ? results : void 0;
|
|
9460
|
+
}
|
|
9461
|
+
function codeToolRequestPresentation(request3) {
|
|
9462
|
+
const input = request3.input;
|
|
9463
|
+
if (request3.tool === "sandbox.read") {
|
|
9464
|
+
const path = text3(input.path, 1024);
|
|
9465
|
+
if (!path) return void 0;
|
|
9466
|
+
const startLine = integer2(input.startLine);
|
|
9467
|
+
const endLine = integer2(input.endLine);
|
|
9468
|
+
return { kind: "read", path, ...startLine ? { startLine } : {}, ...endLine ? { endLine } : {} };
|
|
9469
|
+
}
|
|
9470
|
+
if (request3.tool === "sandbox.list") {
|
|
9471
|
+
const scope = text3(input.prefix, 1024);
|
|
9472
|
+
return { kind: "list", ...scope ? { scope } : {} };
|
|
9473
|
+
}
|
|
9474
|
+
if (request3.tool === "sandbox.search" || request3.tool === "sandbox.overview" || request3.tool === "sandbox.where_is" || request3.tool === "sandbox.who_imports" || request3.tool === "sandbox.who_touches") {
|
|
9475
|
+
const query = text3(input.query, 512);
|
|
9476
|
+
const scope = request3.tool === "sandbox.search" ? text3(input.prefix, 1024) : void 0;
|
|
9477
|
+
if (request3.tool === "sandbox.search" && !query) return void 0;
|
|
9478
|
+
return { kind: "query", ...query ? { query } : {}, ...scope ? { scope } : {} };
|
|
9479
|
+
}
|
|
9480
|
+
if (request3.tool === "sandbox.apply_patch") {
|
|
9481
|
+
return { kind: "patch", ...patchStats(input.patch) };
|
|
9482
|
+
}
|
|
9483
|
+
const recipeId = text3(input.recipeId, 120);
|
|
9484
|
+
return recipeId ? { kind: "recipe", recipeId } : void 0;
|
|
9485
|
+
}
|
|
9486
|
+
function codeToolResultPresentation(request3, response2) {
|
|
9487
|
+
const started = codeToolRequestPresentation(request3);
|
|
9488
|
+
if (!started || !response2.ok) return started;
|
|
9489
|
+
const details = record32(response2.details);
|
|
9490
|
+
if (started.kind === "read") {
|
|
9491
|
+
return {
|
|
9492
|
+
...started,
|
|
9493
|
+
...integer2(details?.startLine) ? { startLine: integer2(details?.startLine) } : {},
|
|
9494
|
+
...integer2(details?.endLine) ? { endLine: integer2(details?.endLine) } : {},
|
|
9495
|
+
...excerpt(response2.content) ? { excerpt: excerpt(response2.content) } : {}
|
|
9496
|
+
};
|
|
9497
|
+
}
|
|
9498
|
+
if (started.kind === "list") {
|
|
9499
|
+
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);
|
|
9500
|
+
return {
|
|
9501
|
+
...started,
|
|
9502
|
+
...integer2(details?.count) !== void 0 ? { count: integer2(details?.count) } : {},
|
|
9503
|
+
...listed.length ? { paths: listed } : {}
|
|
9504
|
+
};
|
|
9505
|
+
}
|
|
9506
|
+
if (started.kind === "query") {
|
|
9507
|
+
const results = request3.tool === "sandbox.search" ? searchResults(response2.content) : void 0;
|
|
9508
|
+
const resultExcerpt = request3.tool === "sandbox.search" ? void 0 : excerpt(response2.content);
|
|
9509
|
+
return {
|
|
9510
|
+
...started,
|
|
9511
|
+
...integer2(details?.count) !== void 0 ? { count: integer2(details?.count) } : {},
|
|
9512
|
+
...results ? { results } : {},
|
|
9513
|
+
...resultExcerpt ? { excerpt: resultExcerpt } : {}
|
|
9514
|
+
};
|
|
9515
|
+
}
|
|
9516
|
+
if (started.kind === "patch") {
|
|
9517
|
+
return { ...started, ...paths(details?.paths) ? { paths: paths(details?.paths) } : {} };
|
|
9518
|
+
}
|
|
9519
|
+
const output = response2.content.replace(/^Recipe [^\n]*\.?\s*/u, "");
|
|
9520
|
+
return {
|
|
9521
|
+
...started,
|
|
9522
|
+
...integer2(details?.exitCode) !== void 0 ? { exitCode: integer2(details?.exitCode) } : {},
|
|
9523
|
+
...typeof details?.timedOut === "boolean" ? { timedOut: details.timedOut } : {},
|
|
9524
|
+
...typeof details?.outputLimitExceeded === "boolean" ? { outputLimitExceeded: details.outputLimitExceeded } : {},
|
|
9525
|
+
...excerpt(output, true) ? { excerpt: excerpt(output, true) } : {}
|
|
9526
|
+
};
|
|
9527
|
+
}
|
|
9413
9528
|
var TheseusRuntimeEngine = class {
|
|
9414
9529
|
constructor(options) {
|
|
9415
9530
|
this.options = options;
|
|
@@ -9643,18 +9758,29 @@ var TheseusRuntimeEngine = class {
|
|
|
9643
9758
|
return {
|
|
9644
9759
|
execute: async (context, request3) => {
|
|
9645
9760
|
const startedAt = Date.now();
|
|
9761
|
+
const operationId = digestRuntimeValue(`${command.commandId}:${request3.requestId}`);
|
|
9762
|
+
const startedPresentation = codeToolRequestPresentation(request3);
|
|
9646
9763
|
await this.#event(
|
|
9647
9764
|
command,
|
|
9648
|
-
{
|
|
9765
|
+
{
|
|
9766
|
+
type: "tool",
|
|
9767
|
+
phase: "started",
|
|
9768
|
+
tool: request3.tool,
|
|
9769
|
+
operationId,
|
|
9770
|
+
...startedPresentation ? { presentation: startedPresentation } : {}
|
|
9771
|
+
},
|
|
9649
9772
|
active.conversationRefs
|
|
9650
9773
|
).catch(() => void 0);
|
|
9651
9774
|
const response2 = await broker.execute(context, request3);
|
|
9775
|
+
const completedPresentation = codeToolResultPresentation(request3, response2);
|
|
9652
9776
|
await this.#event(command, {
|
|
9653
9777
|
type: "tool",
|
|
9654
9778
|
phase: "completed",
|
|
9655
9779
|
tool: request3.tool,
|
|
9656
9780
|
ok: response2.ok,
|
|
9657
|
-
durationMs: Date.now() - startedAt
|
|
9781
|
+
durationMs: Date.now() - startedAt,
|
|
9782
|
+
operationId,
|
|
9783
|
+
...completedPresentation ? { presentation: completedPresentation } : {}
|
|
9658
9784
|
}, active.conversationRefs).catch(() => void 0);
|
|
9659
9785
|
return response2;
|
|
9660
9786
|
}
|
|
@@ -11688,8 +11814,8 @@ function collectFields(parsed, allowClear) {
|
|
|
11688
11814
|
if (allowClear) out[spec.key] = null;
|
|
11689
11815
|
continue;
|
|
11690
11816
|
}
|
|
11691
|
-
const
|
|
11692
|
-
out[spec.key] = spec.num ? Number(
|
|
11817
|
+
const text4 = stringOpt(value2);
|
|
11818
|
+
out[spec.key] = spec.num ? Number(text4) : text4;
|
|
11693
11819
|
}
|
|
11694
11820
|
return out;
|
|
11695
11821
|
}
|
|
@@ -13101,14 +13227,14 @@ function statusMinutes(value2) {
|
|
|
13101
13227
|
}
|
|
13102
13228
|
async function read2(url, headers, doFetch) {
|
|
13103
13229
|
const response2 = await doFetch(url, { headers });
|
|
13104
|
-
const
|
|
13230
|
+
const text4 = await response2.text();
|
|
13105
13231
|
let body = {};
|
|
13106
|
-
if (
|
|
13232
|
+
if (text4) {
|
|
13107
13233
|
try {
|
|
13108
|
-
const value2 = JSON.parse(
|
|
13234
|
+
const value2 = JSON.parse(text4);
|
|
13109
13235
|
body = value2 && typeof value2 === "object" && !Array.isArray(value2) ? value2 : { value: value2 };
|
|
13110
13236
|
} catch {
|
|
13111
|
-
body = { message:
|
|
13237
|
+
body = { message: text4.slice(0, 300) };
|
|
13112
13238
|
}
|
|
13113
13239
|
}
|
|
13114
13240
|
return { httpStatus: response2.status, body };
|
|
@@ -13338,13 +13464,13 @@ async function monitorCommand(parsed, deps = {}) {
|
|
|
13338
13464
|
}
|
|
13339
13465
|
async function request2(url, init, doFetch) {
|
|
13340
13466
|
const response2 = await doFetch(url, init);
|
|
13341
|
-
const
|
|
13467
|
+
const text4 = await response2.text();
|
|
13342
13468
|
let body = {};
|
|
13343
13469
|
try {
|
|
13344
|
-
const parsed =
|
|
13470
|
+
const parsed = text4 ? JSON.parse(text4) : {};
|
|
13345
13471
|
body = record10(parsed) ? parsed : { value: parsed };
|
|
13346
13472
|
} catch {
|
|
13347
|
-
body = { message:
|
|
13473
|
+
body = { message: text4.slice(0, 500) };
|
|
13348
13474
|
}
|
|
13349
13475
|
if (!response2.ok) {
|
|
13350
13476
|
const error = record10(body.error) ? body.error : body;
|
|
@@ -13547,8 +13673,8 @@ function runtimeUrl(cfg, suffix = "") {
|
|
|
13547
13673
|
return `${cfg.platformUrl}/registry/apps/${encodeURIComponent(cfg.app.id)}/runtime-credentials${suffix}`;
|
|
13548
13674
|
}
|
|
13549
13675
|
async function safeError(response2) {
|
|
13550
|
-
const
|
|
13551
|
-
return redactSecrets(
|
|
13676
|
+
const text4 = await response2.text();
|
|
13677
|
+
return redactSecrets(text4.slice(0, 1e3));
|
|
13552
13678
|
}
|
|
13553
13679
|
async function finish(doFetch, cfg, token, sessionId, method) {
|
|
13554
13680
|
return doFetch(runtimeUrl(cfg, `/${encodeURIComponent(sessionId)}`), {
|
|
@@ -13967,6 +14093,7 @@ var COMMAND_SURFACE = {
|
|
|
13967
14093
|
project: { list: {}, add: {}, create: {}, use: {} },
|
|
13968
14094
|
handoff: {},
|
|
13969
14095
|
next: {},
|
|
14096
|
+
start: {},
|
|
13970
14097
|
watch: {}
|
|
13971
14098
|
},
|
|
13972
14099
|
provision: {},
|
|
@@ -14041,13 +14168,13 @@ function invocationPath(words2) {
|
|
|
14041
14168
|
return path;
|
|
14042
14169
|
}
|
|
14043
14170
|
function surfacePaths(node = COMMAND_SURFACE, prefix = []) {
|
|
14044
|
-
const
|
|
14171
|
+
const paths2 = [];
|
|
14045
14172
|
for (const [word, child] of Object.entries(node)) {
|
|
14046
14173
|
const path = [...prefix, word];
|
|
14047
|
-
|
|
14048
|
-
|
|
14174
|
+
paths2.push(path);
|
|
14175
|
+
paths2.push(...surfacePaths(child, path));
|
|
14049
14176
|
}
|
|
14050
|
-
return
|
|
14177
|
+
return paths2;
|
|
14051
14178
|
}
|
|
14052
14179
|
|
|
14053
14180
|
// src/record.ts
|
|
@@ -14110,10 +14237,10 @@ var DAY_MS = 24 * 60 * 60 * 1e3;
|
|
|
14110
14237
|
var UNITS = { d: DAY_MS, w: 7 * DAY_MS, y: 365 * DAY_MS };
|
|
14111
14238
|
function parseDeviceTtl(raw) {
|
|
14112
14239
|
if (raw === void 0 || raw === true) return void 0;
|
|
14113
|
-
const
|
|
14114
|
-
if (!
|
|
14115
|
-
if (
|
|
14116
|
-
const match = /^(\d+)\s*([dwy])$/.exec(
|
|
14240
|
+
const text4 = String(raw).trim().toLowerCase();
|
|
14241
|
+
if (!text4) return void 0;
|
|
14242
|
+
if (text4 === "forever" || text4 === "never") return 100 * 365 * DAY_MS;
|
|
14243
|
+
const match = /^(\d+)\s*([dwy])$/.exec(text4);
|
|
14117
14244
|
if (!match) {
|
|
14118
14245
|
throw new Error(
|
|
14119
14246
|
`--device-ttl expects a duration like 30d, 6w, 2y, or "forever" (got "${raw}")`
|
|
@@ -14446,12 +14573,12 @@ async function runbookRemove(ctx, slug) {
|
|
|
14446
14573
|
// src/runbook-import.ts
|
|
14447
14574
|
import { readFileSync as readFileSync11, readdirSync as readdirSync2, statSync } from "fs";
|
|
14448
14575
|
import { basename as basename2, join as join15 } from "path";
|
|
14449
|
-
function parseRunbook(
|
|
14450
|
-
let rest =
|
|
14576
|
+
function parseRunbook(text4, slug) {
|
|
14577
|
+
let rest = text4;
|
|
14451
14578
|
const meta = {};
|
|
14452
|
-
const fm = /^---\r?\n([\s\S]*?)\r?\n---\r?\n?/.exec(
|
|
14579
|
+
const fm = /^---\r?\n([\s\S]*?)\r?\n---\r?\n?/.exec(text4);
|
|
14453
14580
|
if (fm) {
|
|
14454
|
-
rest =
|
|
14581
|
+
rest = text4.slice(fm[0].length);
|
|
14455
14582
|
for (const line2 of fm[1].split(/\r?\n/)) {
|
|
14456
14583
|
const pair = /^(\w+)\s*:\s*(.+)$/.exec(line2.trim());
|
|
14457
14584
|
if (!pair) continue;
|
|
@@ -16076,4 +16203,4 @@ export {
|
|
|
16076
16203
|
isTerminalHostedSecurityStatus,
|
|
16077
16204
|
runCli
|
|
16078
16205
|
};
|
|
16079
|
-
//# sourceMappingURL=chunk-
|
|
16206
|
+
//# sourceMappingURL=chunk-T4OPSRME.js.map
|