@odla-ai/cli 0.42.0 → 0.42.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin.cjs +185 -38
- package/dist/bin.cjs.map +1 -1
- package/dist/bin.js +1 -1
- package/dist/{chunk-74DXL2MT.js → chunk-K6ATAKGR.js} +185 -38
- package/dist/chunk-K6ATAKGR.js.map +1 -0
- package/dist/{cli-EGZGMIKB.js → cli-4FCRBWED.js} +2 -2
- package/dist/index.cjs +184 -37
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +1 -1
- package/package.json +2 -2
- package/skills/odla/SKILL.md +6 -6
- package/skills/odla/references/agent-identity.md +4 -3
- package/skills/odla/references/pm-work-intake.md +9 -10
- package/skills/odla/references/pm.md +9 -11
- package/dist/chunk-74DXL2MT.js.map +0 -1
- /package/dist/{cli-EGZGMIKB.js.map → cli-4FCRBWED.js.map} +0 -0
package/dist/bin.cjs
CHANGED
|
@@ -7915,7 +7915,7 @@ var init_code2 = __esm({
|
|
|
7915
7915
|
}
|
|
7916
7916
|
});
|
|
7917
7917
|
|
|
7918
|
-
// ../harness/dist/chunk-
|
|
7918
|
+
// ../harness/dist/chunk-GYWQM76X.js
|
|
7919
7919
|
async function digestStagedWorkspace(root, limits) {
|
|
7920
7920
|
const files = [];
|
|
7921
7921
|
const walk = async (directory) => {
|
|
@@ -8862,18 +8862,26 @@ async function materializeCommandWorkspace(input) {
|
|
|
8862
8862
|
}
|
|
8863
8863
|
function codeSkill(opts) {
|
|
8864
8864
|
let seq = 0;
|
|
8865
|
+
let nextCompletion = 1;
|
|
8866
|
+
const completed = /* @__PURE__ */ new Map();
|
|
8865
8867
|
const call4 = async (tool, input, signal) => {
|
|
8868
|
+
const sequence = ++seq;
|
|
8866
8869
|
const startedAt = Date.now();
|
|
8867
8870
|
const response2 = await opts.broker.execute(
|
|
8868
8871
|
{ lease: opts.lease, workspaceDir: opts.workspaceDir, signal },
|
|
8869
|
-
{ requestId: `bench-${tool}-${
|
|
8872
|
+
{ requestId: `bench-${tool}-${sequence}`, tool, input }
|
|
8870
8873
|
);
|
|
8871
|
-
|
|
8874
|
+
completed.set(sequence, {
|
|
8872
8875
|
tool,
|
|
8873
8876
|
ok: response2.ok,
|
|
8874
8877
|
durationMs: Date.now() - startedAt,
|
|
8875
8878
|
...response2.ok ? {} : { error: String(response2.content).slice(0, 300) }
|
|
8876
8879
|
});
|
|
8880
|
+
while (completed.has(nextCompletion)) {
|
|
8881
|
+
const completion = completed.get(nextCompletion);
|
|
8882
|
+
completed.delete(nextCompletion++);
|
|
8883
|
+
opts.onToolCall?.(completion);
|
|
8884
|
+
}
|
|
8877
8885
|
return { content: response2.content, isError: !response2.ok };
|
|
8878
8886
|
};
|
|
8879
8887
|
const read22 = {
|
|
@@ -8889,6 +8897,7 @@ function codeSkill(opts) {
|
|
|
8889
8897
|
},
|
|
8890
8898
|
additionalProperties: false
|
|
8891
8899
|
},
|
|
8900
|
+
concurrency: "parallel",
|
|
8892
8901
|
handler: (input, ctx) => call4("sandbox.read", input, ctx.signal)
|
|
8893
8902
|
};
|
|
8894
8903
|
const applyPatch = {
|
|
@@ -8930,6 +8939,7 @@ function codeSkill(opts) {
|
|
|
8930
8939
|
},
|
|
8931
8940
|
additionalProperties: false
|
|
8932
8941
|
},
|
|
8942
|
+
concurrency: "parallel",
|
|
8933
8943
|
handler: (input, ctx) => call4("sandbox.list", input, ctx.signal)
|
|
8934
8944
|
};
|
|
8935
8945
|
const searchFiles = {
|
|
@@ -8946,11 +8956,13 @@ function codeSkill(opts) {
|
|
|
8946
8956
|
},
|
|
8947
8957
|
additionalProperties: false
|
|
8948
8958
|
},
|
|
8959
|
+
concurrency: "parallel",
|
|
8949
8960
|
handler: (input, ctx) => call4("sandbox.search", input, ctx.signal)
|
|
8950
8961
|
};
|
|
8951
8962
|
const graphTool = (name, tool, description, required) => ({
|
|
8952
8963
|
name,
|
|
8953
8964
|
description,
|
|
8965
|
+
concurrency: "parallel",
|
|
8954
8966
|
inputSchema: {
|
|
8955
8967
|
type: "object",
|
|
8956
8968
|
...required ? { required: ["query"] } : {},
|
|
@@ -9125,6 +9137,24 @@ function createCodeRuntimeInference(options) {
|
|
|
9125
9137
|
catalog: {}
|
|
9126
9138
|
};
|
|
9127
9139
|
}
|
|
9140
|
+
function createWorkspaceFileRegistry(limit = DEFAULT_MAX_FILES, enumerate = registeredFiles) {
|
|
9141
|
+
const cache2 = /* @__PURE__ */ new Map();
|
|
9142
|
+
return {
|
|
9143
|
+
files(root) {
|
|
9144
|
+
const existing = cache2.get(root);
|
|
9145
|
+
if (existing) return existing;
|
|
9146
|
+
const pending = enumerate(root, limit).then((paths) => Object.freeze(paths));
|
|
9147
|
+
cache2.set(root, pending);
|
|
9148
|
+
void pending.catch(() => {
|
|
9149
|
+
if (cache2.get(root) === pending) cache2.delete(root);
|
|
9150
|
+
});
|
|
9151
|
+
return pending;
|
|
9152
|
+
},
|
|
9153
|
+
invalidate(root) {
|
|
9154
|
+
cache2.delete(root);
|
|
9155
|
+
}
|
|
9156
|
+
};
|
|
9157
|
+
}
|
|
9128
9158
|
async function registeredFiles(root, limit = DEFAULT_MAX_FILES) {
|
|
9129
9159
|
const paths = [];
|
|
9130
9160
|
const walk = async (directory) => {
|
|
@@ -9155,28 +9185,121 @@ function listWorkspace(paths, options = {}) {
|
|
|
9155
9185
|
return scoped.slice(0, max);
|
|
9156
9186
|
}
|
|
9157
9187
|
async function searchWorkspace(root, paths, options) {
|
|
9158
|
-
|
|
9159
|
-
if (!query) throw new TypeError("search query must be a non-empty string");
|
|
9188
|
+
options.signal?.throwIfAborted();
|
|
9189
|
+
if (!options.query) throw new TypeError("search query must be a non-empty string");
|
|
9160
9190
|
const maxResults = options.maxResults ?? DEFAULT_MAX_RESULTS;
|
|
9161
9191
|
const maxFileBytes = options.maxFileBytes ?? DEFAULT_MAX_FILE_BYTES;
|
|
9162
9192
|
const scoped = listWorkspace(paths, { ...options.prefix ? { prefix: options.prefix } : {}, maxEntries: paths.length });
|
|
9193
|
+
if (scoped.length === 0) return [];
|
|
9194
|
+
try {
|
|
9195
|
+
return await nativeSearch(root, scoped, { ...options, maxResults, maxFileBytes });
|
|
9196
|
+
} catch (error) {
|
|
9197
|
+
options.signal?.throwIfAborted();
|
|
9198
|
+
return fallbackSearch(root, scoped, { ...options, maxResults, maxFileBytes });
|
|
9199
|
+
}
|
|
9200
|
+
}
|
|
9201
|
+
async function nativeSearch(root, paths, options) {
|
|
9202
|
+
const batches = [];
|
|
9203
|
+
let batch = [];
|
|
9204
|
+
let bytes = 0;
|
|
9205
|
+
for (const path of paths) {
|
|
9206
|
+
const size = Buffer.byteLength(path) + 1;
|
|
9207
|
+
if (batch.length > 0 && bytes + size > MAX_NATIVE_ARG_BYTES) {
|
|
9208
|
+
batches.push(batch);
|
|
9209
|
+
batch = [];
|
|
9210
|
+
bytes = 0;
|
|
9211
|
+
}
|
|
9212
|
+
batch.push(path);
|
|
9213
|
+
bytes += size;
|
|
9214
|
+
}
|
|
9215
|
+
if (batch.length > 0) batches.push(batch);
|
|
9216
|
+
const matches = [];
|
|
9217
|
+
for (const files of batches) {
|
|
9218
|
+
const remaining = options.maxResults - matches.length;
|
|
9219
|
+
if (remaining <= 0) break;
|
|
9220
|
+
matches.push(...await nativeSearchBatch(root, files, options, remaining));
|
|
9221
|
+
}
|
|
9222
|
+
return matches;
|
|
9223
|
+
}
|
|
9224
|
+
function nativeSearchBatch(root, paths, options, remaining) {
|
|
9225
|
+
return new Promise((resolveMatches, reject) => {
|
|
9226
|
+
const args = [
|
|
9227
|
+
"--fixed-strings",
|
|
9228
|
+
"--json",
|
|
9229
|
+
"--no-messages",
|
|
9230
|
+
"--sort=path",
|
|
9231
|
+
`--max-filesize=${options.maxFileBytes}`,
|
|
9232
|
+
"--max-columns=4096",
|
|
9233
|
+
"--max-columns-preview",
|
|
9234
|
+
options.caseSensitive === false ? "--ignore-case" : "--case-sensitive",
|
|
9235
|
+
"--",
|
|
9236
|
+
options.query,
|
|
9237
|
+
...paths
|
|
9238
|
+
];
|
|
9239
|
+
const child = (0, import_child_process6.spawn)("rg", args, {
|
|
9240
|
+
cwd: root,
|
|
9241
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
9242
|
+
...options.signal ? { signal: options.signal } : {}
|
|
9243
|
+
});
|
|
9244
|
+
const matches = [];
|
|
9245
|
+
let carry = "";
|
|
9246
|
+
let stopped = false;
|
|
9247
|
+
const consume = (line2) => {
|
|
9248
|
+
if (matches.length >= remaining) return;
|
|
9249
|
+
let event;
|
|
9250
|
+
try {
|
|
9251
|
+
event = JSON.parse(line2);
|
|
9252
|
+
} catch {
|
|
9253
|
+
return;
|
|
9254
|
+
}
|
|
9255
|
+
const path = event.data?.path?.text;
|
|
9256
|
+
const lineNumber = event.data?.line_number;
|
|
9257
|
+
const source = event.data?.lines?.text;
|
|
9258
|
+
if (event.type !== "match" || path === void 0 || lineNumber === void 0 || source === void 0) return;
|
|
9259
|
+
matches.push({ path, line: lineNumber, text: source.trim().slice(0, 240) });
|
|
9260
|
+
if (matches.length >= remaining) {
|
|
9261
|
+
stopped = true;
|
|
9262
|
+
child.kill();
|
|
9263
|
+
}
|
|
9264
|
+
};
|
|
9265
|
+
child.stdout.setEncoding("utf8");
|
|
9266
|
+
child.stdout.on("data", (chunk) => {
|
|
9267
|
+
carry += chunk;
|
|
9268
|
+
let newline = carry.indexOf("\n");
|
|
9269
|
+
while (newline >= 0) {
|
|
9270
|
+
consume(carry.slice(0, newline));
|
|
9271
|
+
carry = carry.slice(newline + 1);
|
|
9272
|
+
newline = carry.indexOf("\n");
|
|
9273
|
+
}
|
|
9274
|
+
});
|
|
9275
|
+
child.once("error", reject);
|
|
9276
|
+
child.once("close", (code) => {
|
|
9277
|
+
if (carry) consume(carry);
|
|
9278
|
+
if (stopped || code === 0 || code === 1) resolveMatches(matches);
|
|
9279
|
+
else reject(new Error(`native search exited with status ${code ?? "unknown"}`));
|
|
9280
|
+
});
|
|
9281
|
+
});
|
|
9282
|
+
}
|
|
9283
|
+
async function fallbackSearch(root, scoped, options) {
|
|
9284
|
+
const query = options.caseSensitive === false ? options.query.toLowerCase() : options.query;
|
|
9163
9285
|
const matches = [];
|
|
9164
9286
|
for (const path of scoped) {
|
|
9165
|
-
|
|
9287
|
+
options.signal?.throwIfAborted();
|
|
9288
|
+
if (matches.length >= options.maxResults) break;
|
|
9166
9289
|
let source;
|
|
9167
9290
|
try {
|
|
9168
9291
|
source = await (0, import_promises9.readFile)((0, import_path9.resolve)(root, path));
|
|
9169
9292
|
} catch {
|
|
9170
9293
|
continue;
|
|
9171
9294
|
}
|
|
9172
|
-
if (source.byteLength > maxFileBytes || source.includes(0)) continue;
|
|
9295
|
+
if (source.byteLength > options.maxFileBytes || source.includes(0)) continue;
|
|
9173
9296
|
const lines = source.toString("utf8").split("\n");
|
|
9174
9297
|
for (let index = 0; index < lines.length; index += 1) {
|
|
9175
9298
|
const raw = lines[index];
|
|
9176
9299
|
const haystack = options.caseSensitive === false ? raw.toLowerCase() : raw;
|
|
9177
9300
|
if (!haystack.includes(query)) continue;
|
|
9178
9301
|
matches.push({ path, line: index + 1, text: raw.trim().slice(0, 240) });
|
|
9179
|
-
if (matches.length >= maxResults) break;
|
|
9302
|
+
if (matches.length >= options.maxResults) break;
|
|
9180
9303
|
}
|
|
9181
9304
|
}
|
|
9182
9305
|
return matches;
|
|
@@ -9390,6 +9513,9 @@ function workspaceGraphs(workspaceDir, paths) {
|
|
|
9390
9513
|
cache.set(workspaceDir, built);
|
|
9391
9514
|
return built;
|
|
9392
9515
|
}
|
|
9516
|
+
function forgetWorkspaceGraphs(workspaceDir) {
|
|
9517
|
+
cache.delete(workspaceDir);
|
|
9518
|
+
}
|
|
9393
9519
|
function renderOverview(graphs, prefix) {
|
|
9394
9520
|
const rows = rollup(graphs.graph, FILE, prefix === void 0 ? {} : { prefix });
|
|
9395
9521
|
if (rows.length === 0) return prefix ? `No source under "${prefix}".` : "No source files.";
|
|
@@ -9427,7 +9553,7 @@ function renderWhoTouches(graphs, query) {
|
|
|
9427
9553
|
].join("\n");
|
|
9428
9554
|
}).join("\n\n");
|
|
9429
9555
|
}
|
|
9430
|
-
async function read(context, request3, options, policy) {
|
|
9556
|
+
async function read(context, request3, options, policy, registry) {
|
|
9431
9557
|
exactKeys(request3.input, ["path", "startLine", "endLine"]);
|
|
9432
9558
|
const path = stringField(request3.input, "path");
|
|
9433
9559
|
const startLine = optionalInteger(request3.input.startLine) ?? 1;
|
|
@@ -9435,7 +9561,7 @@ async function read(context, request3, options, policy) {
|
|
|
9435
9561
|
if (endLine < startLine || endLine - startLine + 1 > (options.maxReadLines ?? 2e3)) {
|
|
9436
9562
|
throw new TypeError("requested line range exceeds its bound");
|
|
9437
9563
|
}
|
|
9438
|
-
const paths = await
|
|
9564
|
+
const paths = await registry.files(context.workspaceDir);
|
|
9439
9565
|
if (!paths.includes(path)) {
|
|
9440
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.`);
|
|
9441
9567
|
}
|
|
@@ -9455,13 +9581,13 @@ async function read(context, request3, options, policy) {
|
|
|
9455
9581
|
}
|
|
9456
9582
|
return response(request3, true, content2, { path, startLine, endLine: Math.min(endLine, lines.length) });
|
|
9457
9583
|
}
|
|
9458
|
-
async function list(context, request3, options, policy) {
|
|
9584
|
+
async function list(context, request3, options, policy, registry) {
|
|
9459
9585
|
exactKeys(request3.input, ["prefix", "maxEntries"]);
|
|
9460
9586
|
const raw = request3.input.prefix;
|
|
9461
9587
|
const prefix = typeof raw === "string" && raw.length > 0 ? raw : void 0;
|
|
9462
9588
|
const maxEntries = optionalInteger(request3.input.maxEntries) ?? 1e3;
|
|
9463
9589
|
if (maxEntries > 5e3) throw new TypeError("maxEntries exceeds its bound");
|
|
9464
|
-
const paths = await
|
|
9590
|
+
const paths = await registry.files(context.workspaceDir);
|
|
9465
9591
|
const allowed = await policy.list(policyContext(context, request3, options, { paths, ...prefix ? { prefix } : {} }));
|
|
9466
9592
|
if (!allowed) return response(request3, false, "tool denied by CaMeL policy");
|
|
9467
9593
|
const entries = listWorkspace(paths, { ...prefix ? { prefix } : {}, maxEntries });
|
|
@@ -9479,7 +9605,7 @@ async function list(context, request3, options, policy) {
|
|
|
9479
9605
|
{ count: entries.length, truncated }
|
|
9480
9606
|
);
|
|
9481
9607
|
}
|
|
9482
|
-
async function search(context, request3, options, policy) {
|
|
9608
|
+
async function search(context, request3, options, policy, registry) {
|
|
9483
9609
|
exactKeys(request3.input, ["query", "prefix", "maxResults", "caseSensitive"]);
|
|
9484
9610
|
const query = stringField(request3.input, "query");
|
|
9485
9611
|
if (query.length > 512) throw new TypeError("search query exceeds its bound");
|
|
@@ -9488,21 +9614,22 @@ async function search(context, request3, options, policy) {
|
|
|
9488
9614
|
const maxResults = optionalInteger(request3.input.maxResults) ?? 100;
|
|
9489
9615
|
if (maxResults > 500) throw new TypeError("maxResults exceeds its bound");
|
|
9490
9616
|
const caseSensitive = request3.input.caseSensitive === void 0 ? true : request3.input.caseSensitive === true;
|
|
9491
|
-
const paths = await
|
|
9617
|
+
const paths = await registry.files(context.workspaceDir);
|
|
9492
9618
|
const allowed = await policy.search(policyContext(context, request3, options, { paths, query, ...prefix ? { prefix } : {} }));
|
|
9493
9619
|
if (!allowed) return response(request3, false, "tool denied by CaMeL policy");
|
|
9494
9620
|
const matches = await searchWorkspace(context.workspaceDir, paths, {
|
|
9495
9621
|
query,
|
|
9496
9622
|
maxResults,
|
|
9497
9623
|
caseSensitive,
|
|
9498
|
-
...prefix ? { prefix } : {}
|
|
9624
|
+
...prefix ? { prefix } : {},
|
|
9625
|
+
...context.signal ? { signal: context.signal } : {}
|
|
9499
9626
|
});
|
|
9500
9627
|
if (!matches.length) return response(request3, true, `No match for "${query}".`, { count: 0 });
|
|
9501
9628
|
return response(request3, true, matches.map((match) => `${match.path}:${match.line}: ${match.text}`).join("\n"), {
|
|
9502
9629
|
count: matches.length
|
|
9503
9630
|
});
|
|
9504
9631
|
}
|
|
9505
|
-
async function graphQuery(context, request3, options, policy) {
|
|
9632
|
+
async function graphQuery(context, request3, options, policy, registry) {
|
|
9506
9633
|
exactKeys(request3.input, ["query"]);
|
|
9507
9634
|
const raw = request3.input.query;
|
|
9508
9635
|
const query = typeof raw === "string" ? raw : "";
|
|
@@ -9512,7 +9639,7 @@ async function graphQuery(context, request3, options, policy) {
|
|
|
9512
9639
|
selector: query
|
|
9513
9640
|
}));
|
|
9514
9641
|
if (!allowed) return response(request3, false, "tool denied by CaMeL policy");
|
|
9515
|
-
const paths = await
|
|
9642
|
+
const paths = await registry.files(context.workspaceDir);
|
|
9516
9643
|
const graphs = await workspaceGraphs(context.workspaceDir, paths);
|
|
9517
9644
|
if (request3.tool === "sandbox.overview") {
|
|
9518
9645
|
return response(request3, true, renderOverview(graphs, query || void 0));
|
|
@@ -9526,23 +9653,38 @@ function createCodeToolBroker(options) {
|
|
|
9526
9653
|
validateOptions(options);
|
|
9527
9654
|
const recipes = new Map(options.recipes.map((recipe2) => [recipe2.id, recipe2]));
|
|
9528
9655
|
const policy = createCodePolicyGate(options);
|
|
9529
|
-
|
|
9656
|
+
const registry = createWorkspaceFileRegistry();
|
|
9657
|
+
let barrier = Promise.resolve();
|
|
9658
|
+
const activeReads = /* @__PURE__ */ new Set();
|
|
9530
9659
|
return {
|
|
9531
9660
|
execute(context, request3) {
|
|
9532
|
-
|
|
9533
|
-
|
|
9661
|
+
if (isReadTool(request3.tool)) {
|
|
9662
|
+
const result2 = barrier.then(() => route2(context, request3, options, recipes, policy, registry));
|
|
9663
|
+
const settled = result2.then(() => void 0, () => void 0);
|
|
9664
|
+
activeReads.add(settled);
|
|
9665
|
+
void settled.then(() => {
|
|
9666
|
+
activeReads.delete(settled);
|
|
9667
|
+
});
|
|
9668
|
+
return result2;
|
|
9669
|
+
}
|
|
9670
|
+
const earlierReads = [...activeReads];
|
|
9671
|
+
const result = barrier.then(() => Promise.all(earlierReads)).then(() => route2(context, request3, options, recipes, policy, registry));
|
|
9672
|
+
barrier = result.then(() => void 0, () => void 0);
|
|
9534
9673
|
return result;
|
|
9535
9674
|
}
|
|
9536
9675
|
};
|
|
9537
9676
|
}
|
|
9538
|
-
|
|
9677
|
+
function isReadTool(tool) {
|
|
9678
|
+
return tool === "sandbox.read" || tool === "sandbox.list" || tool === "sandbox.search" || GRAPH_TOOLS.has(tool);
|
|
9679
|
+
}
|
|
9680
|
+
async function route2(context, request3, options, recipes, policy, registry) {
|
|
9539
9681
|
try {
|
|
9540
9682
|
if (context.signal?.aborted) throw new TypeError("tool request was cancelled");
|
|
9541
|
-
if (request3.tool === "sandbox.read") return await read(context, request3, options, policy);
|
|
9542
|
-
if (request3.tool === "sandbox.list") return await list(context, request3, options, policy);
|
|
9543
|
-
if (request3.tool === "sandbox.search") return await search(context, request3, options, policy);
|
|
9544
|
-
if (GRAPH_TOOLS.has(request3.tool)) return await graphQuery(context, request3, options, policy);
|
|
9545
|
-
if (request3.tool === "sandbox.apply_patch") return await patch(context, request3, options, policy);
|
|
9683
|
+
if (request3.tool === "sandbox.read") return await read(context, request3, options, policy, registry);
|
|
9684
|
+
if (request3.tool === "sandbox.list") return await list(context, request3, options, policy, registry);
|
|
9685
|
+
if (request3.tool === "sandbox.search") return await search(context, request3, options, policy, registry);
|
|
9686
|
+
if (GRAPH_TOOLS.has(request3.tool)) return await graphQuery(context, request3, options, policy, registry);
|
|
9687
|
+
if (request3.tool === "sandbox.apply_patch") return await patch(context, request3, options, policy, registry);
|
|
9546
9688
|
return await recipe(context, request3, options, recipes, policy);
|
|
9547
9689
|
} catch (reason) {
|
|
9548
9690
|
return response(request3, false, toolFailureMessage(reason));
|
|
@@ -9557,7 +9699,7 @@ function toolFailureMessage(reason) {
|
|
|
9557
9699
|
if (code === "EACCES" || code === "EPERM") return "that path is not readable through this tool";
|
|
9558
9700
|
return "tool failed closed";
|
|
9559
9701
|
}
|
|
9560
|
-
async function patch(context, request3, options, policy) {
|
|
9702
|
+
async function patch(context, request3, options, policy, registry) {
|
|
9561
9703
|
exactKeys(request3.input, ["patch"]);
|
|
9562
9704
|
const value2 = stringField(request3.input, "patch");
|
|
9563
9705
|
const paths = validateCodePatch(value2, options.maxPatchBytes ?? 256 * 1024);
|
|
@@ -9567,6 +9709,8 @@ async function patch(context, request3, options, policy) {
|
|
|
9567
9709
|
const allowed = await policy.patch(policyContext(context, request3, options, { patch: value2 }));
|
|
9568
9710
|
if (!allowed) return response(request3, false, "tool denied by CaMeL policy");
|
|
9569
9711
|
await applyCodePatch(context.workspaceDir, value2, paths);
|
|
9712
|
+
registry.invalidate(context.workspaceDir);
|
|
9713
|
+
forgetWorkspaceGraphs(context.workspaceDir);
|
|
9570
9714
|
return response(request3, true, `Applied patch to ${paths.length} file(s).`, { paths });
|
|
9571
9715
|
}
|
|
9572
9716
|
async function recipe(context, request3, options, recipes, policy) {
|
|
@@ -9917,9 +10061,9 @@ async function appendCodeRuntimeEvent(control, command, event, refs) {
|
|
|
9917
10061
|
const bounded = event.type === "message" ? { ...event, body: event.body.trim().slice(0, 2e4) || `${event.actor} event` } : event;
|
|
9918
10062
|
await control.appendSessionEvent(command.sessionId, eventId, bounded);
|
|
9919
10063
|
}
|
|
9920
|
-
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_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, DESTINATIONS, READ, LIST, SEARCH, GRAPH, PATCH, RECIPE, cache, shortId, GRAPH_TOOLS, MAX_MEMORY_BODY, POSITIVE, digestRuntimeValue, runtimeErrorMessage, TheseusRuntimeEngine;
|
|
9921
|
-
var
|
|
9922
|
-
"../harness/dist/chunk-
|
|
10064
|
+
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, TheseusRuntimeEngine;
|
|
10065
|
+
var init_chunk_GYWQM76X = __esm({
|
|
10066
|
+
"../harness/dist/chunk-GYWQM76X.js"() {
|
|
9923
10067
|
"use strict";
|
|
9924
10068
|
init_cjs_shims();
|
|
9925
10069
|
init_chunk_K76I2TCQ();
|
|
@@ -9945,6 +10089,7 @@ var init_chunk_QZXCQSPZ = __esm({
|
|
|
9945
10089
|
import_path8 = require("path");
|
|
9946
10090
|
import_ai4 = require("@odla-ai/ai");
|
|
9947
10091
|
import_ai5 = require("@odla-ai/ai");
|
|
10092
|
+
import_child_process6 = require("child_process");
|
|
9948
10093
|
import_promises9 = require("fs/promises");
|
|
9949
10094
|
import_path9 = require("path");
|
|
9950
10095
|
init_dist();
|
|
@@ -10073,7 +10218,10 @@ Never claim a build or test passed unless odla_run_recipe returned that result.`
|
|
|
10073
10218
|
V2_SYSTEM_PROMPT = `You are the coding agent inside an odla Code harness.
|
|
10074
10219
|
Start by orienting: odla_list shows the files in the workspace and odla_search
|
|
10075
10220
|
finds a literal string across them. Prefer those over guessing a path.
|
|
10076
|
-
Then odla_read a bounded range, and odla_apply_git_diff to mutate.
|
|
10221
|
+
Then odla_read a bounded range, and odla_apply_git_diff to mutate. When you
|
|
10222
|
+
need several independent searches or file ranges, issue those read-only calls
|
|
10223
|
+
together in one turn; their results stay ordered and the harness overlaps them.
|
|
10224
|
+
Never issue odla_apply_git_diff or odla_run_recipe alongside another tool call.
|
|
10077
10225
|
For mutations, call odla_apply_git_diff with raw git diff text. It must start
|
|
10078
10226
|
with "diff --git a/<path> b/<path>", include matching "---" and "+++" file
|
|
10079
10227
|
headers and numbered "@@" hunks, and never use "*** Begin Patch" wrappers.
|
|
@@ -10105,6 +10253,7 @@ Never claim a build or test passed unless odla_run_recipe returned that result.`
|
|
|
10105
10253
|
DEFAULT_MAX_FILES = 2e4;
|
|
10106
10254
|
DEFAULT_MAX_RESULTS = 100;
|
|
10107
10255
|
DEFAULT_MAX_FILE_BYTES = 512 * 1024;
|
|
10256
|
+
MAX_NATIVE_ARG_BYTES = 96 * 1024;
|
|
10108
10257
|
DESTINATIONS = "code-workspaces.v1";
|
|
10109
10258
|
READ = descriptor("sandbox.read", "scoped_data_read", {
|
|
10110
10259
|
workspace: "destination",
|
|
@@ -10442,7 +10591,7 @@ var init_node = __esm({
|
|
|
10442
10591
|
"../harness/dist/node.js"() {
|
|
10443
10592
|
"use strict";
|
|
10444
10593
|
init_cjs_shims();
|
|
10445
|
-
|
|
10594
|
+
init_chunk_GYWQM76X();
|
|
10446
10595
|
init_chunk_K76I2TCQ();
|
|
10447
10596
|
MEASURED_PREMIUM = Object.freeze({
|
|
10448
10597
|
/** 3 racers vs pure depth at equal budget: 21,044 / 7,936. */
|
|
@@ -11684,12 +11833,10 @@ Commands:
|
|
|
11684
11833
|
explicitly. Same device-grant auth as "app".
|
|
11685
11834
|
Status changes and comments post to each item's @odla-ai/chat
|
|
11686
11835
|
discussion thread.
|
|
11687
|
-
|
|
11688
|
-
|
|
11689
|
-
|
|
11690
|
-
|
|
11691
|
-
pm.plan agent promotes. This is deliberate, not a permission
|
|
11692
|
-
gap \u2014 it was reported as one.
|
|
11836
|
+
Creating or promoting a task in Ready requires a complete
|
|
11837
|
+
execution contract and a reviewed revision. Any caller with PM
|
|
11838
|
+
mutation access to that app/project may do it; claims coordinate
|
|
11839
|
+
execution but never own or lock the PM record.
|
|
11693
11840
|
bug Intent-first alias for PM bugs. "bug report" writes to
|
|
11694
11841
|
odla PM; odla product defects do not belong in GitHub Issues.
|
|
11695
11842
|
discuss Group discussions (via @odla-ai/chat) for the apps you co-own:
|