@odla-ai/cli 0.15.0 → 0.16.0
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 +2 -2
- package/dist/bin.cjs +80 -8
- package/dist/bin.cjs.map +1 -1
- package/dist/bin.js +1 -1
- package/dist/{chunk-E3CCYDIT.js → chunk-S3OYXHDG.js} +81 -9
- package/dist/chunk-S3OYXHDG.js.map +1 -0
- package/dist/index.cjs +80 -8
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/skills/odla-migrate/references/phase-2-db.md +2 -2
- package/dist/chunk-E3CCYDIT.js.map +0 -1
package/dist/bin.js
CHANGED
|
@@ -2398,7 +2398,7 @@ async function stageWorkspacePair(baselineSource, workspaceSource, options = {})
|
|
|
2398
2398
|
}
|
|
2399
2399
|
}
|
|
2400
2400
|
|
|
2401
|
-
// ../harness/dist/chunk-
|
|
2401
|
+
// ../harness/dist/chunk-4EM6NMET.js
|
|
2402
2402
|
import { createHash } from "crypto";
|
|
2403
2403
|
import { readFile, readdir as readdir2 } from "fs/promises";
|
|
2404
2404
|
import { relative as relative3, resolve as resolve4 } from "path";
|
|
@@ -2735,7 +2735,7 @@ function validateSnapshot(snapshot, limits) {
|
|
|
2735
2735
|
}
|
|
2736
2736
|
}
|
|
2737
2737
|
|
|
2738
|
-
// ../harness/dist/chunk-
|
|
2738
|
+
// ../harness/dist/chunk-4EM6NMET.js
|
|
2739
2739
|
import { spawn as spawn4 } from "child_process";
|
|
2740
2740
|
import { lstat as lstat2 } from "fs/promises";
|
|
2741
2741
|
import { resolve as resolve23, sep as sep3 } from "path";
|
|
@@ -3028,7 +3028,7 @@ function looksLikeDestination(value) {
|
|
|
3028
3028
|
return /^(?:[a-z][a-z0-9+.-]*:\/\/|\/|\\\\)/i.test(text) || /^[\w.-]+\.[a-z]{2,}(?:[/:]|$)/i.test(text);
|
|
3029
3029
|
}
|
|
3030
3030
|
|
|
3031
|
-
// ../harness/dist/chunk-
|
|
3031
|
+
// ../harness/dist/chunk-4EM6NMET.js
|
|
3032
3032
|
import { createHash as createHash3 } from "crypto";
|
|
3033
3033
|
async function digestStagedWorkspace(root, limits) {
|
|
3034
3034
|
const files = [];
|
|
@@ -3276,10 +3276,28 @@ async function parseSource(value) {
|
|
|
3276
3276
|
if (!file || typeof file.path !== "string" || typeof file.content !== "string") throw invalid("source file");
|
|
3277
3277
|
return { path: file.path, content: file.content };
|
|
3278
3278
|
});
|
|
3279
|
+
const referencesValue = snapshot.references === void 0 ? [] : snapshot.references;
|
|
3280
|
+
if (!Array.isArray(referencesValue) || referencesValue.length > 5) throw invalid("reference sources");
|
|
3281
|
+
const aliases = /* @__PURE__ */ new Set();
|
|
3282
|
+
const references = [];
|
|
3283
|
+
for (const item of referencesValue) {
|
|
3284
|
+
const reference = record3(item);
|
|
3285
|
+
if (!reference || typeof reference.alias !== "string" || !/^[a-z][a-z0-9-]{0,39}$/.test(reference.alias) || aliases.has(reference.alias) || reference.alias === "primary" || typeof reference.repository !== "string" || typeof reference.commitSha !== "string" || typeof reference.treeDigest !== "string" || !Array.isArray(reference.files)) throw invalid("reference source");
|
|
3286
|
+
aliases.add(reference.alias);
|
|
3287
|
+
const referenceFiles = reference.files.map((entry) => {
|
|
3288
|
+
const file = record3(entry);
|
|
3289
|
+
if (!file || typeof file.path !== "string" || typeof file.content !== "string") throw invalid("reference source file");
|
|
3290
|
+
return { path: file.path, content: file.content };
|
|
3291
|
+
});
|
|
3292
|
+
const source2 = { repository: reference.repository, commitSha: reference.commitSha, files: referenceFiles };
|
|
3293
|
+
const referenceDigest = await digestCodeRepositorySnapshot(source2, { maximumFiles: 1e4, maximumBytes: 16 * 1024 * 1024 });
|
|
3294
|
+
if (referenceDigest !== reference.treeDigest) throw invalid("reference source digest");
|
|
3295
|
+
references.push({ alias: reference.alias, ...source2, treeDigest: referenceDigest });
|
|
3296
|
+
}
|
|
3279
3297
|
const source = { repository: snapshot.repository, commitSha: snapshot.commitSha, files };
|
|
3280
3298
|
const digest = await digestCodeRepositorySnapshot(source, { maximumFiles: 1e4, maximumBytes: 16 * 1024 * 1024 });
|
|
3281
3299
|
if (digest !== snapshot.treeDigest) throw invalid("source digest");
|
|
3282
|
-
return { ...source, treeDigest: digest };
|
|
3300
|
+
return { ...source, treeDigest: digest, ...references.length ? { references } : {} };
|
|
3283
3301
|
}
|
|
3284
3302
|
function parseReview(value) {
|
|
3285
3303
|
const review = record3(record3(value)?.review);
|
|
@@ -3810,7 +3828,7 @@ var CodeRuntimeCheckpointManager = class {
|
|
|
3810
3828
|
await this.options.event(command, {
|
|
3811
3829
|
type: "message",
|
|
3812
3830
|
actor: "system",
|
|
3813
|
-
body: `Candidate ${candidate.candidateId} is ready for
|
|
3831
|
+
body: command.payload.sourceSet ? `Candidate ${candidate.candidateId} was verified and delivered to the session PR branch` : `Candidate ${candidate.candidateId} is ready for legacy owner publication approval`
|
|
3814
3832
|
}, pending.refs);
|
|
3815
3833
|
this.#pending.delete(command.commandId);
|
|
3816
3834
|
return true;
|
|
@@ -3837,12 +3855,51 @@ async function materializeCodeRuntimeSource(snapshot, tempRoot = tmpdir3()) {
|
|
|
3837
3855
|
await mkdir3(dirname4(target), { recursive: true });
|
|
3838
3856
|
await writeFile2(target, file.content, { flag: "wx", mode: 420 });
|
|
3839
3857
|
}
|
|
3858
|
+
for (const reference of snapshot.references ?? []) {
|
|
3859
|
+
validateAlias(reference.alias);
|
|
3860
|
+
if (!reference.files.length || reference.files.length > 1e4) throw new TypeError("Code reference file count is invalid");
|
|
3861
|
+
for (const file of reference.files) {
|
|
3862
|
+
validatePath(file.path);
|
|
3863
|
+
const path = `.odla-references/${reference.alias}/${file.path}`;
|
|
3864
|
+
if (seen.has(path)) throw new TypeError("Code reference repeats a path");
|
|
3865
|
+
seen.add(path);
|
|
3866
|
+
bytes += Buffer.byteLength(path) + Buffer.byteLength(file.content);
|
|
3867
|
+
if (bytes > 80 * 1024 * 1024) throw new TypeError("Code source set exceeds its byte bound");
|
|
3868
|
+
const target = resolve32(sourceDir, path);
|
|
3869
|
+
if (!target.startsWith(`${resolve32(sourceDir)}${sep22}`)) throw new TypeError("Code reference path escapes its root");
|
|
3870
|
+
await mkdir3(dirname4(target), { recursive: true });
|
|
3871
|
+
await writeFile2(target, file.content, { flag: "wx", mode: 292 });
|
|
3872
|
+
}
|
|
3873
|
+
}
|
|
3840
3874
|
return { sourceDir, cleanup: () => rm3(root, { recursive: true, force: true }) };
|
|
3841
3875
|
} catch (cause) {
|
|
3842
3876
|
await rm3(root, { recursive: true, force: true });
|
|
3843
3877
|
throw cause;
|
|
3844
3878
|
}
|
|
3845
3879
|
}
|
|
3880
|
+
function validateAlias(alias) {
|
|
3881
|
+
if (!/^[a-z][a-z0-9-]{0,39}$/.test(alias) || alias === "primary") {
|
|
3882
|
+
throw new TypeError("Code reference alias is invalid");
|
|
3883
|
+
}
|
|
3884
|
+
}
|
|
3885
|
+
async function attachCodeRuntimeReferences(workspace, references) {
|
|
3886
|
+
let bytes = 0;
|
|
3887
|
+
for (const reference of references) {
|
|
3888
|
+
validateAlias(reference.alias);
|
|
3889
|
+
for (const file of reference.files) {
|
|
3890
|
+
validatePath(file.path);
|
|
3891
|
+
const path = `.odla-references/${reference.alias}/${file.path}`;
|
|
3892
|
+
bytes += Buffer.byteLength(path) + Buffer.byteLength(file.content);
|
|
3893
|
+
if (bytes > 64 * 1024 * 1024) throw new TypeError("Code reference set exceeds its byte bound");
|
|
3894
|
+
for (const root of [workspace.baselineDir, workspace.workspaceDir]) {
|
|
3895
|
+
const target = resolve32(root, path);
|
|
3896
|
+
if (!target.startsWith(`${resolve32(root)}${sep22}`)) throw new TypeError("Code reference path escapes its root");
|
|
3897
|
+
await mkdir3(dirname4(target), { recursive: true });
|
|
3898
|
+
await writeFile2(target, file.content, { flag: "wx", mode: 292 });
|
|
3899
|
+
}
|
|
3900
|
+
}
|
|
3901
|
+
}
|
|
3902
|
+
}
|
|
3846
3903
|
function validatePath(path) {
|
|
3847
3904
|
const parts = path.split("/");
|
|
3848
3905
|
if (!path || path.startsWith("/") || path.includes("\\") || path.includes("\0") || parts.some((part) => !part || part === "." || part === ".." || RESERVED2.has(part) || SECRET2.test(part))) {
|
|
@@ -4041,6 +4098,9 @@ async function patch(context, request, options, policy) {
|
|
|
4041
4098
|
exactKeys(request.input, ["patch"]);
|
|
4042
4099
|
const value = stringField(request.input, "patch");
|
|
4043
4100
|
const paths = validateCodePatch(value, options.maxPatchBytes ?? 256 * 1024);
|
|
4101
|
+
if (paths.some((path) => options.readOnlyPrefixes?.some((prefix) => path === prefix || path.startsWith(`${prefix}/`)))) {
|
|
4102
|
+
throw new TypeError("patch targets a read-only reference source");
|
|
4103
|
+
}
|
|
4044
4104
|
const allowed = await policy.patch(policyContext(context, request, options, { patch: value }));
|
|
4045
4105
|
if (!allowed) return response(request, false, "tool denied by CaMeL policy");
|
|
4046
4106
|
await applyCodePatch(context.workspaceDir, value, paths);
|
|
@@ -4126,6 +4186,9 @@ function validateOptions(options) {
|
|
|
4126
4186
|
throw new TypeError("Code tool broker requires a reader and unique registered recipes");
|
|
4127
4187
|
}
|
|
4128
4188
|
for (const recipe2 of options.recipes) assertCodeBuildRecipe(recipe2);
|
|
4189
|
+
if (options.readOnlyPrefixes?.some((prefix) => !/^[A-Za-z0-9_.-]+$/.test(prefix) || prefix === "." || prefix === "..")) {
|
|
4190
|
+
throw new TypeError("Code tool broker read-only prefix is invalid");
|
|
4191
|
+
}
|
|
4129
4192
|
}
|
|
4130
4193
|
function exactKeys(input, allowed) {
|
|
4131
4194
|
if (Object.keys(input).some((key) => !allowed.includes(key))) throw new TypeError("tool input contains an unsupported field");
|
|
@@ -4233,7 +4296,8 @@ function createCodeRuntimeToolBroker(input, lease, role) {
|
|
|
4233
4296
|
recipes: input.recipes,
|
|
4234
4297
|
recipeExecutor: createContainerRecipeExecutor(input.engine),
|
|
4235
4298
|
recipeAuthorization: input.recipeAuthorization ?? "registered_recipe",
|
|
4236
|
-
readerId: `code-session:${lease.task.taskId}
|
|
4299
|
+
readerId: `code-session:${lease.task.taskId}`,
|
|
4300
|
+
readOnlyPrefixes: [".odla-references"]
|
|
4237
4301
|
});
|
|
4238
4302
|
return role === "coding" ? broker : { execute: (context, request) => request.tool === "sandbox.read" ? broker.execute(context, request) : Promise.resolve({ requestId: request.requestId, ok: false, content: "review sessions are read-only" }) };
|
|
4239
4303
|
}
|
|
@@ -4311,6 +4375,14 @@ var CodePiRuntimeEngine = class {
|
|
|
4311
4375
|
resume
|
|
4312
4376
|
});
|
|
4313
4377
|
({ workspace, sourceDigest, trustedBaseDigest: localTrustedBaseDigest } = prepared);
|
|
4378
|
+
if (command.payload.sourceSet) {
|
|
4379
|
+
const selected = await this.options.control.source(command.sessionId);
|
|
4380
|
+
if (selected.repository !== metadata2.repository || selected.commitSha !== metadata2.baseCommitSha || selected.treeDigest !== metadata2.sourceTreeDigest) {
|
|
4381
|
+
await workspace.cleanup();
|
|
4382
|
+
throw new TypeError("Code local source does not match the selected GitHub primary source");
|
|
4383
|
+
}
|
|
4384
|
+
await attachCodeRuntimeReferences(workspace, selected.references ?? []);
|
|
4385
|
+
}
|
|
4314
4386
|
} else {
|
|
4315
4387
|
const source = await this.options.control.source(command.sessionId);
|
|
4316
4388
|
const materialized = await materializeCodeRuntimeSource(source);
|
|
@@ -4338,8 +4410,8 @@ var CodePiRuntimeEngine = class {
|
|
|
4338
4410
|
repository: metadata2.repository,
|
|
4339
4411
|
sourceTreeDigest: metadata2.sourceTreeDigest,
|
|
4340
4412
|
trustedBaseDigest: requestedLocal ? localTrustedBaseDigest : await digestStagedWorkspace(workspace.baselineDir, {
|
|
4341
|
-
maxFiles:
|
|
4342
|
-
maxBytes:
|
|
4413
|
+
maxFiles: 2e4,
|
|
4414
|
+
maxBytes: 512 * 1024 * 1024
|
|
4343
4415
|
}),
|
|
4344
4416
|
planningInputDigest: metadata2.planningInputDigest ?? digestRuntimeValue(
|
|
4345
4417
|
JSON.stringify({ attestation: metadata2.attestationDigest, prompt: metadata2.prompt, tree: sourceDigest })
|
|
@@ -7674,4 +7746,4 @@ export {
|
|
|
7674
7746
|
exitCodeFor,
|
|
7675
7747
|
runCli
|
|
7676
7748
|
};
|
|
7677
|
-
//# sourceMappingURL=chunk-
|
|
7749
|
+
//# sourceMappingURL=chunk-S3OYXHDG.js.map
|