@odla-ai/cli 0.16.2 → 0.16.4
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 +9 -6
- package/dist/bin.cjs +237 -102
- package/dist/bin.cjs.map +1 -1
- package/dist/bin.js +1 -1
- package/dist/{chunk-PQX6SKYJ.js → chunk-GAFC4EPJ.js} +227 -93
- package/dist/chunk-GAFC4EPJ.js.map +1 -0
- package/dist/index.cjs +239 -102
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +16 -4
- package/dist/index.d.ts +16 -4
- package/dist/index.js +3 -1
- package/dist/runtime/pi-agent.js +330317 -0
- package/package.json +2 -2
- package/skills/odla-migrate/references/phase-2-db.md +2 -2
- package/dist/chunk-PQX6SKYJ.js.map +0 -1
package/dist/bin.cjs
CHANGED
|
@@ -1939,13 +1939,13 @@ function printStatus(status, json, out) {
|
|
|
1939
1939
|
|
|
1940
1940
|
// src/code-connect.ts
|
|
1941
1941
|
var import_node_fs7 = require("fs");
|
|
1942
|
-
var
|
|
1943
|
-
var
|
|
1942
|
+
var import_node_os2 = require("os");
|
|
1943
|
+
var import_node_path5 = require("path");
|
|
1944
1944
|
|
|
1945
|
-
// ../harness/dist/chunk-
|
|
1945
|
+
// ../harness/dist/chunk-QTUEF2HZ.js
|
|
1946
1946
|
var HARNESS_PROTOCOL_VERSION = 1;
|
|
1947
1947
|
|
|
1948
|
-
// ../harness/dist/chunk-
|
|
1948
|
+
// ../harness/dist/chunk-GE6CCN7W.js
|
|
1949
1949
|
var CONTROL = /[\u0000-\u0008\u000b\u000c\u000e-\u001f\u007f]/;
|
|
1950
1950
|
var HarnessProtocolError = class extends Error {
|
|
1951
1951
|
name = "HarnessProtocolError";
|
|
@@ -2023,7 +2023,7 @@ function encodeAgentInput(message2) {
|
|
|
2023
2023
|
`;
|
|
2024
2024
|
}
|
|
2025
2025
|
|
|
2026
|
-
// ../harness/dist/chunk-
|
|
2026
|
+
// ../harness/dist/chunk-NOBK6PCT.js
|
|
2027
2027
|
var import_child_process = require("child_process");
|
|
2028
2028
|
var import_fs = require("fs");
|
|
2029
2029
|
var import_promises2 = require("fs/promises");
|
|
@@ -2076,7 +2076,7 @@ async function selectContainerEngine(requested = "auto", options = {}) {
|
|
|
2076
2076
|
throw new TypeError("no rootless Podman found; install Podman or explicitly choose --engine docker after reviewing its daemon boundary");
|
|
2077
2077
|
}
|
|
2078
2078
|
if (platform === "darwin") {
|
|
2079
|
-
throw new TypeError("
|
|
2079
|
+
throw new TypeError("Apple container is not installed; on Apple Silicon macOS 26 run `brew install container`, then retry (Podman Machine is the fallback)");
|
|
2080
2080
|
}
|
|
2081
2081
|
throw new TypeError("no supported container engine found");
|
|
2082
2082
|
}
|
|
@@ -2540,7 +2540,7 @@ async function stageWorkspacePair(baselineSource, workspaceSource, options = {})
|
|
|
2540
2540
|
}
|
|
2541
2541
|
}
|
|
2542
2542
|
|
|
2543
|
-
// ../harness/dist/chunk-
|
|
2543
|
+
// ../harness/dist/chunk-6J2ZETST.js
|
|
2544
2544
|
var import_crypto = require("crypto");
|
|
2545
2545
|
var import_promises5 = require("fs/promises");
|
|
2546
2546
|
var import_path5 = require("path");
|
|
@@ -2877,7 +2877,7 @@ function validateSnapshot(snapshot, limits) {
|
|
|
2877
2877
|
}
|
|
2878
2878
|
}
|
|
2879
2879
|
|
|
2880
|
-
// ../harness/dist/chunk-
|
|
2880
|
+
// ../harness/dist/chunk-6J2ZETST.js
|
|
2881
2881
|
var import_child_process4 = require("child_process");
|
|
2882
2882
|
var import_promises6 = require("fs/promises");
|
|
2883
2883
|
var import_path6 = require("path");
|
|
@@ -3170,7 +3170,7 @@ function looksLikeDestination(value) {
|
|
|
3170
3170
|
return /^(?:[a-z][a-z0-9+.-]*:\/\/|\/|\\\\)/i.test(text) || /^[\w.-]+\.[a-z]{2,}(?:[/:]|$)/i.test(text);
|
|
3171
3171
|
}
|
|
3172
3172
|
|
|
3173
|
-
// ../harness/dist/chunk-
|
|
3173
|
+
// ../harness/dist/chunk-6J2ZETST.js
|
|
3174
3174
|
var import_crypto4 = require("crypto");
|
|
3175
3175
|
async function digestStagedWorkspace(root, limits) {
|
|
3176
3176
|
const files = [];
|
|
@@ -4361,6 +4361,7 @@ function codeCommandMetadata(payload, resume) {
|
|
|
4361
4361
|
const role = payload.role;
|
|
4362
4362
|
const title = payload.title;
|
|
4363
4363
|
const prompt = payload.prompt;
|
|
4364
|
+
const maxTokensPerInteraction = payload.maxTokensPerInteraction ?? 32e3;
|
|
4364
4365
|
if (role !== "coding" && role !== "review" || typeof title !== "string" || typeof prompt !== "string") {
|
|
4365
4366
|
throw new TypeError(`invalid Code ${resume ? "resume" : "start"} metadata`);
|
|
4366
4367
|
}
|
|
@@ -4372,10 +4373,14 @@ function codeCommandMetadata(payload, resume) {
|
|
|
4372
4373
|
if (typeof repository !== "string" || !repository.includes("/") || typeof baseCommitSha !== "string" || !/^[0-9a-f]{40}$/.test(baseCommitSha) || typeof sourceTreeDigest !== "string" || !/^sha256:[0-9a-f]{64}$/.test(sourceTreeDigest)) {
|
|
4373
4374
|
throw new TypeError(`invalid Code ${resume ? "resume" : "start"} trusted base`);
|
|
4374
4375
|
}
|
|
4376
|
+
if (!Number.isSafeInteger(maxTokensPerInteraction) || Number(maxTokensPerInteraction) < 4e3 || Number(maxTokensPerInteraction) > 2e5) {
|
|
4377
|
+
throw new TypeError(`invalid Code ${resume ? "resume" : "start"} interaction token limit`);
|
|
4378
|
+
}
|
|
4375
4379
|
return {
|
|
4376
4380
|
role,
|
|
4377
4381
|
title,
|
|
4378
4382
|
prompt,
|
|
4383
|
+
maxTokensPerInteraction: Number(maxTokensPerInteraction),
|
|
4379
4384
|
planningInputDigest: typeof planning === "string" && /^sha256:[0-9a-f]{64}$/.test(planning) ? planning : null,
|
|
4380
4385
|
attestationDigest: typeof attestation === "string" ? attestation : "resume",
|
|
4381
4386
|
repository,
|
|
@@ -4451,6 +4456,57 @@ function createCodeRuntimeToolBroker(input, lease, role) {
|
|
|
4451
4456
|
});
|
|
4452
4457
|
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" }) };
|
|
4453
4458
|
}
|
|
4459
|
+
async function handleCodeRuntimeInference(input) {
|
|
4460
|
+
const { command, metadata: metadata2, request, state } = input;
|
|
4461
|
+
if (state.tokens >= metadata2.maxTokensPerInteraction) {
|
|
4462
|
+
if (!state.noticeEmitted) {
|
|
4463
|
+
state.noticeEmitted = true;
|
|
4464
|
+
await input.event({
|
|
4465
|
+
type: "message",
|
|
4466
|
+
actor: "system",
|
|
4467
|
+
body: `Pi paused at the ${metadata2.maxTokensPerInteraction.toLocaleString("en-US")}-token per-interaction limit. Send a new instruction to continue.`
|
|
4468
|
+
}).catch(() => void 0);
|
|
4469
|
+
}
|
|
4470
|
+
return {
|
|
4471
|
+
protocolVersion: HARNESS_PROTOCOL_VERSION,
|
|
4472
|
+
type: "inference.response",
|
|
4473
|
+
requestId: request.requestId,
|
|
4474
|
+
response: {
|
|
4475
|
+
id: `budget:${command.commandId}`,
|
|
4476
|
+
provider: "openai",
|
|
4477
|
+
model: "interaction-budget",
|
|
4478
|
+
role: "assistant",
|
|
4479
|
+
content: [{ type: "text", text: "Pause now. The owner-set token limit for this interaction has been reached." }],
|
|
4480
|
+
stopReason: "end_turn",
|
|
4481
|
+
usage: { inputTokens: 0, outputTokens: 0 }
|
|
4482
|
+
}
|
|
4483
|
+
};
|
|
4484
|
+
}
|
|
4485
|
+
const startedAt = Date.now();
|
|
4486
|
+
const response2 = await input.control.infer(command.sessionId, {
|
|
4487
|
+
requestId: request.requestId,
|
|
4488
|
+
interactionId: command.commandId,
|
|
4489
|
+
call: request.call
|
|
4490
|
+
});
|
|
4491
|
+
state.tokens += response2.receipt.inputTokens + response2.receipt.outputTokens;
|
|
4492
|
+
await input.event({
|
|
4493
|
+
type: "usage",
|
|
4494
|
+
provider: response2.receipt.provider,
|
|
4495
|
+
model: response2.receipt.model,
|
|
4496
|
+
inputTokens: response2.receipt.inputTokens,
|
|
4497
|
+
outputTokens: response2.receipt.outputTokens,
|
|
4498
|
+
durationMs: Date.now() - startedAt,
|
|
4499
|
+
interactionId: command.commandId,
|
|
4500
|
+
interactionTokens: state.tokens,
|
|
4501
|
+
interactionMaxTokens: metadata2.maxTokensPerInteraction
|
|
4502
|
+
}).catch(() => void 0);
|
|
4503
|
+
return {
|
|
4504
|
+
protocolVersion: HARNESS_PROTOCOL_VERSION,
|
|
4505
|
+
type: "inference.response",
|
|
4506
|
+
requestId: request.requestId,
|
|
4507
|
+
response: response2.response
|
|
4508
|
+
};
|
|
4509
|
+
}
|
|
4454
4510
|
async function appendCodeRuntimeEvent(control, command, event, refs) {
|
|
4455
4511
|
const eventId = `${command.commandId.slice(0, 45)}:${refs.length + 1}`;
|
|
4456
4512
|
refs.push(eventId);
|
|
@@ -4480,6 +4536,7 @@ function runtimeResultError(value) {
|
|
|
4480
4536
|
var CodePiRuntimeEngine = class {
|
|
4481
4537
|
constructor(options) {
|
|
4482
4538
|
this.options = options;
|
|
4539
|
+
if (options.imageAuthorization === "cli_embedded" && !/^odla-ai\/pi-agent:embedded-sha256-[0-9a-f]{64}$/.test(options.image)) throw new TypeError("CLI-embedded Pi image must use its content-addressed local tag");
|
|
4483
4540
|
this.#run = options.runAttempt ?? runContainerAttempt;
|
|
4484
4541
|
this.#buildPolicyDigest = digestRuntimeValue(JSON.stringify(options.recipes));
|
|
4485
4542
|
this.#checkpoints = new CodeRuntimeCheckpointManager({
|
|
@@ -4562,6 +4619,7 @@ var CodePiRuntimeEngine = class {
|
|
|
4562
4619
|
acknowledged: false,
|
|
4563
4620
|
role: metadata2.role,
|
|
4564
4621
|
title: metadata2.title,
|
|
4622
|
+
maxTokensPerInteraction: metadata2.maxTokensPerInteraction,
|
|
4565
4623
|
baseCommitSha: metadata2.baseCommitSha,
|
|
4566
4624
|
repository: metadata2.repository,
|
|
4567
4625
|
sourceTreeDigest: metadata2.sourceTreeDigest,
|
|
@@ -4598,6 +4656,11 @@ var CodePiRuntimeEngine = class {
|
|
|
4598
4656
|
if (!active || typeof prompt !== "string" || !prompt.trim() || prompt.length > 2e4) {
|
|
4599
4657
|
throw new TypeError("prompt requires an active Code session and bounded text");
|
|
4600
4658
|
}
|
|
4659
|
+
const requestedLimit = command.payload.maxTokensPerInteraction ?? active.maxTokensPerInteraction;
|
|
4660
|
+
if (!Number.isSafeInteger(requestedLimit) || Number(requestedLimit) < 4e3 || Number(requestedLimit) > 2e5) {
|
|
4661
|
+
throw new TypeError("prompt requires a valid interaction token limit");
|
|
4662
|
+
}
|
|
4663
|
+
active.maxTokensPerInteraction = Number(requestedLimit);
|
|
4601
4664
|
await active.done;
|
|
4602
4665
|
active.abort = new AbortController();
|
|
4603
4666
|
active.acknowledged = false;
|
|
@@ -4606,6 +4669,7 @@ var CodePiRuntimeEngine = class {
|
|
|
4606
4669
|
role: active.role,
|
|
4607
4670
|
title: active.title,
|
|
4608
4671
|
prompt,
|
|
4672
|
+
maxTokensPerInteraction: active.maxTokensPerInteraction,
|
|
4609
4673
|
planningInputDigest: active.planningInputDigest,
|
|
4610
4674
|
attestationDigest: "follow-up",
|
|
4611
4675
|
repository: active.repository,
|
|
@@ -4634,9 +4698,11 @@ var CodePiRuntimeEngine = class {
|
|
|
4634
4698
|
}, lease, metadata2.role);
|
|
4635
4699
|
const startedAt = Date.now();
|
|
4636
4700
|
let completionSeen = false;
|
|
4701
|
+
const interaction = { tokens: 0, noticeEmitted: false };
|
|
4637
4702
|
const result = await this.#run({
|
|
4638
4703
|
engine: this.options.engine,
|
|
4639
4704
|
image: this.options.image,
|
|
4705
|
+
allowUnpinnedImage: this.options.imageAuthorization === "cli_embedded",
|
|
4640
4706
|
workspaceDir: active.workspace.workspaceDir,
|
|
4641
4707
|
workspaceAccess: "none",
|
|
4642
4708
|
task: lease.task,
|
|
@@ -4649,25 +4715,18 @@ var CodePiRuntimeEngine = class {
|
|
|
4649
4715
|
}, active.conversationRefs),
|
|
4650
4716
|
onMessage: async (output) => {
|
|
4651
4717
|
if (output.type === "inference.request") {
|
|
4652
|
-
|
|
4653
|
-
|
|
4654
|
-
|
|
4655
|
-
|
|
4718
|
+
return handleCodeRuntimeInference({
|
|
4719
|
+
command,
|
|
4720
|
+
metadata: metadata2,
|
|
4721
|
+
request: output,
|
|
4722
|
+
state: interaction,
|
|
4723
|
+
control: this.options.control,
|
|
4724
|
+
event: (event) => this.#event(
|
|
4725
|
+
command,
|
|
4726
|
+
event,
|
|
4727
|
+
active.conversationRefs
|
|
4728
|
+
)
|
|
4656
4729
|
});
|
|
4657
|
-
await this.#event(command, {
|
|
4658
|
-
type: "usage",
|
|
4659
|
-
provider: response2.receipt.provider,
|
|
4660
|
-
model: response2.receipt.model,
|
|
4661
|
-
inputTokens: response2.receipt.inputTokens,
|
|
4662
|
-
outputTokens: response2.receipt.outputTokens,
|
|
4663
|
-
durationMs: Date.now() - inferenceStarted
|
|
4664
|
-
}, active.conversationRefs).catch(() => void 0);
|
|
4665
|
-
return {
|
|
4666
|
-
protocolVersion: HARNESS_PROTOCOL_VERSION,
|
|
4667
|
-
type: "inference.response",
|
|
4668
|
-
requestId: output.requestId,
|
|
4669
|
-
response: response2.response
|
|
4670
|
-
};
|
|
4671
4730
|
}
|
|
4672
4731
|
if (output.type === "tool.request") {
|
|
4673
4732
|
const toolStarted = Date.now();
|
|
@@ -5153,25 +5212,23 @@ function digestText(value) {
|
|
|
5153
5212
|
|
|
5154
5213
|
// src/code-images.ts
|
|
5155
5214
|
var import_node_child_process4 = require("child_process");
|
|
5156
|
-
|
|
5157
|
-
|
|
5158
|
-
|
|
5159
|
-
|
|
5160
|
-
|
|
5161
|
-
if (error) reject(new Error(`could not prepare pinned Code image ${image}`));
|
|
5162
|
-
else accept();
|
|
5163
|
-
});
|
|
5164
|
-
});
|
|
5165
|
-
}
|
|
5166
|
-
}
|
|
5215
|
+
var import_node_crypto2 = require("crypto");
|
|
5216
|
+
var import_promises10 = require("fs/promises");
|
|
5217
|
+
var import_node_os = require("os");
|
|
5218
|
+
var import_node_path4 = require("path");
|
|
5219
|
+
var import_node_url2 = require("url");
|
|
5167
5220
|
|
|
5168
5221
|
// src/code-runtime-config.ts
|
|
5169
|
-
var CODE_PI_IMAGE = "
|
|
5222
|
+
var CODE_PI_IMAGE = "odla-ai/pi-agent:embedded";
|
|
5223
|
+
var CODE_NODE_IMAGE = "node:24-alpine@sha256:a0b9bf06e4e6193cf7a0f58816cc935ff8c2a908f81e6f1a95432d679c54fbfd";
|
|
5170
5224
|
var CODE_BUILD_RECIPES = Object.freeze([{
|
|
5171
5225
|
id: "odla-code-contracts",
|
|
5172
|
-
image:
|
|
5226
|
+
image: CODE_NODE_IMAGE,
|
|
5173
5227
|
command: [
|
|
5174
5228
|
"node",
|
|
5229
|
+
// The clean source mount deliberately has no node_modules. Reuse the
|
|
5230
|
+
// semver copy inside this digest-pinned npm image without network access.
|
|
5231
|
+
"--import=data:text/javascript,import%20Module%20from%20%22node%3Amodule%22%3Bprocess.env.NODE_PATH%3D%22%2Fusr%2Flocal%2Flib%2Fnode_modules%2Fnpm%2Fnode_modules%22%3BModule._initPaths%28%29",
|
|
5175
5232
|
"--test",
|
|
5176
5233
|
"scripts/lib/directories.test.mjs",
|
|
5177
5234
|
"scripts/lib/internal-deps.test.mjs",
|
|
@@ -5186,10 +5243,84 @@ var CODE_BUILD_RECIPES = Object.freeze([{
|
|
|
5186
5243
|
pids: 128
|
|
5187
5244
|
}]);
|
|
5188
5245
|
|
|
5246
|
+
// src/code-images.ts
|
|
5247
|
+
var runCodeImageCommand = (command, args, stdio) => new Promise((accept, reject) => {
|
|
5248
|
+
const child = (0, import_node_child_process4.spawn)(command, [...args], { shell: false, stdio });
|
|
5249
|
+
child.once("error", reject);
|
|
5250
|
+
child.once("exit", (code, signal) => {
|
|
5251
|
+
if (code === 0) accept();
|
|
5252
|
+
else reject(new Error(`${command} ${args.join(" ")} exited ${code ?? signal ?? "without a status"}`));
|
|
5253
|
+
});
|
|
5254
|
+
});
|
|
5255
|
+
async function prepareCodeImages(engine, images, run = runCodeImageCommand, buildEmbedded = buildEmbeddedPiImage, nameEmbedded = embeddedPiImageName) {
|
|
5256
|
+
if (engine === "container") {
|
|
5257
|
+
try {
|
|
5258
|
+
await run(engine, ["system", "start"], "inherit");
|
|
5259
|
+
} catch {
|
|
5260
|
+
throw new Error("Apple container could not start; run `container system start` once to complete its lightweight VM setup, then retry");
|
|
5261
|
+
}
|
|
5262
|
+
}
|
|
5263
|
+
const prepared = [];
|
|
5264
|
+
for (const image of images) {
|
|
5265
|
+
const runtimeImage = image === CODE_PI_IMAGE ? await nameEmbedded() : image;
|
|
5266
|
+
const inspectArgs = ["image", "inspect", runtimeImage];
|
|
5267
|
+
try {
|
|
5268
|
+
await run(engine, inspectArgs, "ignore");
|
|
5269
|
+
prepared.push(runtimeImage);
|
|
5270
|
+
continue;
|
|
5271
|
+
} catch {
|
|
5272
|
+
}
|
|
5273
|
+
if (image === CODE_PI_IMAGE) {
|
|
5274
|
+
try {
|
|
5275
|
+
await buildEmbedded(engine, runtimeImage, run);
|
|
5276
|
+
} catch (error) {
|
|
5277
|
+
const detail = error instanceof Error && error.message ? `: ${error.message}` : "";
|
|
5278
|
+
throw new Error(`could not prepare CLI-embedded Code image${detail}`);
|
|
5279
|
+
}
|
|
5280
|
+
prepared.push(runtimeImage);
|
|
5281
|
+
continue;
|
|
5282
|
+
}
|
|
5283
|
+
const args = engine === "container" ? ["image", "pull", image] : ["pull", image];
|
|
5284
|
+
try {
|
|
5285
|
+
await run(engine, args, "inherit");
|
|
5286
|
+
} catch (error) {
|
|
5287
|
+
const detail = error instanceof Error && error.message ? `: ${error.message}` : "";
|
|
5288
|
+
throw new Error(`could not prepare pinned Code image ${image}${detail}`);
|
|
5289
|
+
}
|
|
5290
|
+
prepared.push(image);
|
|
5291
|
+
}
|
|
5292
|
+
return prepared;
|
|
5293
|
+
}
|
|
5294
|
+
function embeddedPiAssetPath() {
|
|
5295
|
+
return (0, import_node_url2.fileURLToPath)(new URL("./runtime/pi-agent.js", importMetaUrl));
|
|
5296
|
+
}
|
|
5297
|
+
async function embeddedPiImageName() {
|
|
5298
|
+
const bundle = await (0, import_promises10.readFile)(embeddedPiAssetPath()).catch(() => {
|
|
5299
|
+
throw new Error("CLI-embedded Pi runtime is missing; reinstall this exact @odla-ai/cli version");
|
|
5300
|
+
});
|
|
5301
|
+
return `odla-ai/pi-agent:embedded-sha256-${(0, import_node_crypto2.createHash)("sha256").update(bundle).digest("hex")}`;
|
|
5302
|
+
}
|
|
5303
|
+
async function buildEmbeddedPiImage(engine, image, run) {
|
|
5304
|
+
const context = await (0, import_promises10.mkdtemp)((0, import_node_path4.join)((0, import_node_os.tmpdir)(), "odla-code-pi-"));
|
|
5305
|
+
try {
|
|
5306
|
+
await (0, import_promises10.copyFile)(embeddedPiAssetPath(), (0, import_node_path4.join)(context, "pi-agent.js"));
|
|
5307
|
+
await (0, import_promises10.writeFile)((0, import_node_path4.join)(context, "Dockerfile"), [
|
|
5308
|
+
`FROM ${CODE_NODE_IMAGE}`,
|
|
5309
|
+
"COPY pi-agent.js /opt/odla/pi-agent.js",
|
|
5310
|
+
"WORKDIR /workspace",
|
|
5311
|
+
'ENTRYPOINT ["node", "/opt/odla/pi-agent.js"]',
|
|
5312
|
+
""
|
|
5313
|
+
].join("\n"), { mode: 384 });
|
|
5314
|
+
await run(engine, ["build", "--tag", image, context], "inherit");
|
|
5315
|
+
} finally {
|
|
5316
|
+
await (0, import_promises10.rm)(context, { recursive: true, force: true });
|
|
5317
|
+
}
|
|
5318
|
+
}
|
|
5319
|
+
|
|
5189
5320
|
// src/code-connect.ts
|
|
5190
5321
|
async function codeConnect(options) {
|
|
5191
5322
|
const cwd = options.cwd ?? process.cwd();
|
|
5192
|
-
const configPath = (0,
|
|
5323
|
+
const configPath = (0, import_node_path5.resolve)(cwd, options.configPath);
|
|
5193
5324
|
const cfg = (0, import_node_fs7.existsSync)(configPath) ? await loadProjectConfig(configPath) : null;
|
|
5194
5325
|
const requestedAppId = options.appId?.trim();
|
|
5195
5326
|
if (requestedAppId && !/^[a-z0-9][a-z0-9-]{1,62}$/.test(requestedAppId)) {
|
|
@@ -5218,12 +5349,13 @@ async function codeConnect(options) {
|
|
|
5218
5349
|
const out = options.stdout ?? console;
|
|
5219
5350
|
const doFetch = options.fetch ?? fetch;
|
|
5220
5351
|
const engine = await (options.selectEngine ?? selectContainerEngine)(options.engine ?? "auto");
|
|
5221
|
-
await (options.prepareImages ?? prepareCodeImages)(
|
|
5222
|
-
|
|
5223
|
-
...new Set(CODE_BUILD_RECIPES.map((recipe2) => recipe2.image))
|
|
5224
|
-
|
|
5352
|
+
const [piImage] = await (options.prepareImages ?? prepareCodeImages)(
|
|
5353
|
+
engine,
|
|
5354
|
+
[CODE_PI_IMAGE, ...new Set(CODE_BUILD_RECIPES.map((recipe2) => recipe2.image))]
|
|
5355
|
+
);
|
|
5356
|
+
if (!piImage || !/^odla-ai\/pi-agent:embedded-sha256-[0-9a-f]{64}$/.test(piImage)) throw new Error("Code image preflight did not produce the content-addressed embedded Pi runtime");
|
|
5225
5357
|
const hostPlatform = process.platform === "darwin" ? "macos" : "linux";
|
|
5226
|
-
const hostName = (options.name ?? (0,
|
|
5358
|
+
const hostName = (options.name ?? (0, import_node_os2.hostname)()).trim();
|
|
5227
5359
|
if (!hostName || hostName.length > 120) throw new Error("--name must contain 1 to 120 characters");
|
|
5228
5360
|
const repository = await inferGitHubRepository(cwd, options.readGitOrigin);
|
|
5229
5361
|
const localSource = await (options.prepareLocalSource ?? prepareCodeLocalSource)(
|
|
@@ -5260,12 +5392,13 @@ async function codeConnect(options) {
|
|
|
5260
5392
|
platform: hostPlatform,
|
|
5261
5393
|
arch: process.arch,
|
|
5262
5394
|
engines: [engine],
|
|
5263
|
-
cpuCount: (0,
|
|
5264
|
-
memoryBytes: (0,
|
|
5395
|
+
cpuCount: (0, import_node_os2.cpus)().length,
|
|
5396
|
+
memoryBytes: (0, import_node_os2.totalmem)(),
|
|
5265
5397
|
source: descriptor2,
|
|
5266
5398
|
images: {
|
|
5267
5399
|
ready: true,
|
|
5268
|
-
pi:
|
|
5400
|
+
pi: piImage,
|
|
5401
|
+
piSource: "cli_embedded",
|
|
5269
5402
|
recipes: CODE_BUILD_RECIPES.map((recipe2) => ({ id: recipe2.id, image: recipe2.image }))
|
|
5270
5403
|
}
|
|
5271
5404
|
};
|
|
@@ -5280,6 +5413,7 @@ async function codeConnect(options) {
|
|
|
5280
5413
|
engine,
|
|
5281
5414
|
capabilities,
|
|
5282
5415
|
localSource,
|
|
5416
|
+
piImage,
|
|
5283
5417
|
heartbeatMs,
|
|
5284
5418
|
once: options.once === true,
|
|
5285
5419
|
signal: options.signal,
|
|
@@ -5309,7 +5443,8 @@ async function runCodeRuntime(input) {
|
|
|
5309
5443
|
const commandEngine = new CodePiRuntimeEngine({
|
|
5310
5444
|
control,
|
|
5311
5445
|
engine: input.engine,
|
|
5312
|
-
image:
|
|
5446
|
+
image: input.piImage ?? input.capabilities.images.pi,
|
|
5447
|
+
imageAuthorization: "cli_embedded",
|
|
5313
5448
|
recipes: CODE_BUILD_RECIPES,
|
|
5314
5449
|
recipeAuthorization: "registered_recipe",
|
|
5315
5450
|
localSource: input.localSource,
|
|
@@ -5406,12 +5541,12 @@ async function codeCommand(parsed, dependencies) {
|
|
|
5406
5541
|
// src/doctor-checks.ts
|
|
5407
5542
|
var import_node_child_process6 = require("child_process");
|
|
5408
5543
|
var import_node_fs9 = require("fs");
|
|
5409
|
-
var
|
|
5544
|
+
var import_node_path7 = require("path");
|
|
5410
5545
|
|
|
5411
5546
|
// src/wrangler.ts
|
|
5412
5547
|
var import_node_child_process5 = require("child_process");
|
|
5413
5548
|
var import_node_fs8 = require("fs");
|
|
5414
|
-
var
|
|
5549
|
+
var import_node_path6 = require("path");
|
|
5415
5550
|
var defaultRunner = (cmd, args, opts) => new Promise((resolvePromise, reject) => {
|
|
5416
5551
|
const child = (0, import_node_child_process5.spawn)(cmd, args, { cwd: opts?.cwd, stdio: ["pipe", "pipe", "pipe"] });
|
|
5417
5552
|
let stdout = "";
|
|
@@ -5425,7 +5560,7 @@ var defaultRunner = (cmd, args, opts) => new Promise((resolvePromise, reject) =>
|
|
|
5425
5560
|
var WRANGLER_CONFIG_FILES = ["wrangler.jsonc", "wrangler.json", "wrangler.toml"];
|
|
5426
5561
|
function findWranglerConfig(rootDir) {
|
|
5427
5562
|
for (const name of WRANGLER_CONFIG_FILES) {
|
|
5428
|
-
const path = (0,
|
|
5563
|
+
const path = (0, import_node_path6.join)(rootDir, name);
|
|
5429
5564
|
if ((0, import_node_fs8.existsSync)(path)) return path;
|
|
5430
5565
|
}
|
|
5431
5566
|
return null;
|
|
@@ -5531,10 +5666,10 @@ function wranglerWarnings(rootDir) {
|
|
|
5531
5666
|
for (const { label, block } of blocks) {
|
|
5532
5667
|
const assets = block.assets;
|
|
5533
5668
|
if (assets?.directory) {
|
|
5534
|
-
const dir = (0,
|
|
5535
|
-
if (dir === (0,
|
|
5669
|
+
const dir = (0, import_node_path7.resolve)(rootDir, assets.directory);
|
|
5670
|
+
if (dir === (0, import_node_path7.resolve)(rootDir)) {
|
|
5536
5671
|
warnings.push(`${label}assets.directory is the project root \u2014 point it at a dedicated build dir (wrangler dev fails with "spawn EBADF")`);
|
|
5537
|
-
} else if ((0, import_node_fs9.existsSync)((0,
|
|
5672
|
+
} else if ((0, import_node_fs9.existsSync)((0, import_node_path7.join)(dir, "node_modules"))) {
|
|
5538
5673
|
warnings.push(`${label}assets.directory contains node_modules \u2014 wrangler dev's watcher will exhaust file descriptors`);
|
|
5539
5674
|
}
|
|
5540
5675
|
}
|
|
@@ -5569,7 +5704,7 @@ function o11yProjectWarnings(rootDir) {
|
|
|
5569
5704
|
warnings.push("cannot verify o11y Worker instrumentation \u2014 add a parseable wrangler.jsonc/json config");
|
|
5570
5705
|
return warnings;
|
|
5571
5706
|
}
|
|
5572
|
-
const main = typeof config.main === "string" ? (0,
|
|
5707
|
+
const main = typeof config.main === "string" ? (0, import_node_path7.resolve)(rootDir, config.main) : null;
|
|
5573
5708
|
if (!main || !(0, import_node_fs9.existsSync)(main)) {
|
|
5574
5709
|
warnings.push("cannot verify o11y Worker instrumentation \u2014 wrangler main is missing or unreadable");
|
|
5575
5710
|
} else {
|
|
@@ -5599,7 +5734,7 @@ function calendarProjectWarnings(rootDir) {
|
|
|
5599
5734
|
}
|
|
5600
5735
|
function readPackageJson(rootDir) {
|
|
5601
5736
|
try {
|
|
5602
|
-
return JSON.parse((0, import_node_fs9.readFileSync)((0,
|
|
5737
|
+
return JSON.parse((0, import_node_fs9.readFileSync)((0, import_node_path7.join)(rootDir, "package.json"), "utf8"));
|
|
5603
5738
|
} catch {
|
|
5604
5739
|
return null;
|
|
5605
5740
|
}
|
|
@@ -5801,11 +5936,11 @@ function harnessOption(value, flag) {
|
|
|
5801
5936
|
|
|
5802
5937
|
// src/init.ts
|
|
5803
5938
|
var import_node_fs10 = require("fs");
|
|
5804
|
-
var
|
|
5939
|
+
var import_node_path8 = require("path");
|
|
5805
5940
|
function initProject(options) {
|
|
5806
5941
|
const out = options.stdout ?? console;
|
|
5807
|
-
const rootDir = (0,
|
|
5808
|
-
const configPath = (0,
|
|
5942
|
+
const rootDir = (0, import_node_path8.resolve)(options.rootDir ?? process.cwd());
|
|
5943
|
+
const configPath = (0, import_node_path8.resolve)(rootDir, options.configPath ?? "odla.config.mjs");
|
|
5809
5944
|
if ((0, import_node_fs10.existsSync)(configPath) && !options.force) {
|
|
5810
5945
|
throw new Error(`${configPath} already exists. Pass --force to overwrite.`);
|
|
5811
5946
|
}
|
|
@@ -5816,12 +5951,12 @@ function initProject(options) {
|
|
|
5816
5951
|
const services = options.services?.length ? options.services : ["db", "ai"];
|
|
5817
5952
|
if (services.includes("calendar") && !services.includes("db")) throw new Error("--services calendar requires db");
|
|
5818
5953
|
const aiProvider = options.aiProvider ?? "anthropic";
|
|
5819
|
-
(0, import_node_fs10.mkdirSync)((0,
|
|
5820
|
-
(0, import_node_fs10.mkdirSync)((0,
|
|
5821
|
-
(0, import_node_fs10.mkdirSync)((0,
|
|
5954
|
+
(0, import_node_fs10.mkdirSync)((0, import_node_path8.dirname)(configPath), { recursive: true });
|
|
5955
|
+
(0, import_node_fs10.mkdirSync)((0, import_node_path8.resolve)(rootDir, "src/odla"), { recursive: true });
|
|
5956
|
+
(0, import_node_fs10.mkdirSync)((0, import_node_path8.resolve)(rootDir, ".odla"), { recursive: true });
|
|
5822
5957
|
(0, import_node_fs10.writeFileSync)(configPath, configTemplate({ appId: options.appId, name: options.name, envs, services, aiProvider }));
|
|
5823
|
-
writeIfMissing((0,
|
|
5824
|
-
writeIfMissing((0,
|
|
5958
|
+
writeIfMissing((0, import_node_path8.resolve)(rootDir, "src/odla/schema.mjs"), schemaTemplate());
|
|
5959
|
+
writeIfMissing((0, import_node_path8.resolve)(rootDir, "src/odla/rules.mjs"), rulesTemplate());
|
|
5825
5960
|
ensureGitignore(rootDir);
|
|
5826
5961
|
out.log(`created ${relativeDisplay(configPath, rootDir)}`);
|
|
5827
5962
|
out.log("created src/odla/schema.mjs and src/odla/rules.mjs");
|
|
@@ -6471,7 +6606,7 @@ async function resolveVaultWrite(options) {
|
|
|
6471
6606
|
}
|
|
6472
6607
|
|
|
6473
6608
|
// src/security-command-context.ts
|
|
6474
|
-
var
|
|
6609
|
+
var import_promises11 = require("readline/promises");
|
|
6475
6610
|
async function hostedSecurityContext(parsed, dependencies) {
|
|
6476
6611
|
const configPath = stringOpt(parsed.options.config) ?? "odla.config.mjs";
|
|
6477
6612
|
const cfg = await loadProjectConfig(configPath);
|
|
@@ -6497,7 +6632,7 @@ async function hostedSecurityContext(parsed, dependencies) {
|
|
|
6497
6632
|
async function interactiveConfirmation(message2, dependencies) {
|
|
6498
6633
|
if (dependencies.confirm) return dependencies.confirm(message2);
|
|
6499
6634
|
if (!process.stdin.isTTY || !process.stdout.isTTY) return false;
|
|
6500
|
-
const prompt = (0,
|
|
6635
|
+
const prompt = (0, import_promises11.createInterface)({ input: process.stdin, output: process.stdout });
|
|
6501
6636
|
try {
|
|
6502
6637
|
const answer = await prompt.question(`${message2} [y/N] `);
|
|
6503
6638
|
return /^y(?:es)?$/i.test(answer.trim());
|
|
@@ -6624,7 +6759,7 @@ function hostedSeverity(value, flag) {
|
|
|
6624
6759
|
var import_security2 = require("@odla-ai/security");
|
|
6625
6760
|
|
|
6626
6761
|
// src/security.ts
|
|
6627
|
-
var
|
|
6762
|
+
var import_node_path9 = require("path");
|
|
6628
6763
|
var import_security = require("@odla-ai/security");
|
|
6629
6764
|
var import_node3 = require("@odla-ai/security/node");
|
|
6630
6765
|
async function runHostedSecurity(options) {
|
|
@@ -6636,9 +6771,9 @@ async function runHostedSecurity(options) {
|
|
|
6636
6771
|
const appId = selfAudit ? "odla-ai" : cfg.app.id;
|
|
6637
6772
|
const env = selfAudit ? "prod" : selectEnv(options.env, cfg.envs, cfg.configPath, cfg.rootDir);
|
|
6638
6773
|
const platform = options.platform ?? cfg?.platformUrl ?? "https://odla.ai";
|
|
6639
|
-
const target = (0,
|
|
6640
|
-
const output = (0,
|
|
6641
|
-
const outputRelative = (0,
|
|
6774
|
+
const target = (0, import_node_path9.resolve)(options.target ?? cfg?.rootDir ?? ".");
|
|
6775
|
+
const output = (0, import_node_path9.resolve)(options.out ?? (0, import_node_path9.resolve)(target, ".odla/security/hosted"));
|
|
6776
|
+
const outputRelative = (0, import_node_path9.relative)(target, output).split(import_node_path9.sep).join("/");
|
|
6642
6777
|
if (!outputRelative) throw new Error("Hosted security output cannot be the repository root");
|
|
6643
6778
|
const profile = profileFor(options.profile ?? "odla", options.maxHuntTasks ?? 12);
|
|
6644
6779
|
const tokenRequest = {
|
|
@@ -6650,7 +6785,7 @@ async function runHostedSecurity(options) {
|
|
|
6650
6785
|
};
|
|
6651
6786
|
const token = await injectedToken(options, tokenRequest);
|
|
6652
6787
|
const snapshot = await (0, import_node3.snapshotDirectory)(target, {
|
|
6653
|
-
exclude: !outputRelative.startsWith("../") && !(0,
|
|
6788
|
+
exclude: !outputRelative.startsWith("../") && !(0, import_node_path9.isAbsolute)(outputRelative) ? [outputRelative] : []
|
|
6654
6789
|
});
|
|
6655
6790
|
const hosted = await (0, import_security.createPlatformSecurityReasoners)({
|
|
6656
6791
|
platform,
|
|
@@ -6668,7 +6803,7 @@ async function runHostedSecurity(options) {
|
|
|
6668
6803
|
});
|
|
6669
6804
|
const harness = (0, import_security.createSecurityHarness)({
|
|
6670
6805
|
profile,
|
|
6671
|
-
store: new import_node3.FileRunStore((0,
|
|
6806
|
+
store: new import_node3.FileRunStore((0, import_node_path9.resolve)(output, "state")),
|
|
6672
6807
|
discoveryReasoner: hosted.discoveryReasoner,
|
|
6673
6808
|
validationReasoner: hosted.validationReasoner,
|
|
6674
6809
|
policy: {
|
|
@@ -6692,7 +6827,7 @@ async function runHostedSecurity(options) {
|
|
|
6692
6827
|
function selectEnv(requested, declared, configPath, rootDir) {
|
|
6693
6828
|
const env = requested ?? (declared.includes("dev") ? "dev" : declared[0]);
|
|
6694
6829
|
if (!env || !declared.includes(env)) {
|
|
6695
|
-
const shown = (0,
|
|
6830
|
+
const shown = (0, import_node_path9.relative)(rootDir, configPath) || configPath;
|
|
6696
6831
|
throw new Error(`env "${env ?? ""}" is not declared in ${shown}`);
|
|
6697
6832
|
}
|
|
6698
6833
|
return env;
|
|
@@ -6721,7 +6856,7 @@ function printSummary(out, appId, env, run, report2, output) {
|
|
|
6721
6856
|
out.log(` coverage: ${report2.coverageStatus} ${complete}/${report2.coverage.length} blocked=${report2.metrics.blockedCells} shallow=${report2.metrics.shallowCells} unscheduled=${report2.metrics.unscheduledCells} budget_exhausted=${report2.metrics.budgetExhaustedCells}`);
|
|
6722
6857
|
if (report2.callBudget) out.log(` calls: discovery=${formatBudget(report2.callBudget.discovery)} validation=${formatBudget(report2.callBudget.validation)}`);
|
|
6723
6858
|
out.log(` findings: confirmed=${report2.metrics.confirmed} needs_reproduction=${report2.metrics.needsReproduction} candidates=${report2.metrics.candidates}`);
|
|
6724
|
-
out.log(` report: ${(0,
|
|
6859
|
+
out.log(` report: ${(0, import_node_path9.resolve)(output, "REPORT.md")}`);
|
|
6725
6860
|
}
|
|
6726
6861
|
function formatBudget(usage) {
|
|
6727
6862
|
return usage ? `${usage.usedCalls}/${usage.maxCalls} skipped=${usage.skippedCalls}` : "caller-managed";
|
|
@@ -7160,9 +7295,9 @@ async function securityStatus(parsed, dependencies) {
|
|
|
7160
7295
|
|
|
7161
7296
|
// src/skill.ts
|
|
7162
7297
|
var import_node_fs11 = require("fs");
|
|
7163
|
-
var
|
|
7164
|
-
var
|
|
7165
|
-
var
|
|
7298
|
+
var import_node_os3 = require("os");
|
|
7299
|
+
var import_node_path10 = require("path");
|
|
7300
|
+
var import_node_url3 = require("url");
|
|
7166
7301
|
|
|
7167
7302
|
// src/skill-adapters.ts
|
|
7168
7303
|
var PROJECT_INSTRUCTIONS = `<!-- odla-ai agent setup:start -->
|
|
@@ -7218,12 +7353,12 @@ runbook. Do not substitute a remote documentation page for the installed copy.
|
|
|
7218
7353
|
var AGENT_HARNESSES = ["claude", "codex", "cursor", "copilot", "gemini", "agents"];
|
|
7219
7354
|
function installSkill(options = {}) {
|
|
7220
7355
|
const out = options.stdout ?? console;
|
|
7221
|
-
const sourceDir = options.sourceDir ?? (0,
|
|
7356
|
+
const sourceDir = options.sourceDir ?? (0, import_node_url3.fileURLToPath)(new URL("../skills", importMetaUrl));
|
|
7222
7357
|
const files = listFiles(sourceDir);
|
|
7223
7358
|
if (files.length === 0) throw new Error(`no bundled skills found at ${sourceDir}`);
|
|
7224
7359
|
const harnesses = normalizeHarnesses(options.harnesses, options.global === true);
|
|
7225
|
-
const root = (0,
|
|
7226
|
-
const home = (0,
|
|
7360
|
+
const root = (0, import_node_path10.resolve)(options.dir ?? process.cwd());
|
|
7361
|
+
const home = (0, import_node_path10.resolve)(options.homeDir ?? (0, import_node_os3.homedir)());
|
|
7227
7362
|
const plans = /* @__PURE__ */ new Map();
|
|
7228
7363
|
const targets = /* @__PURE__ */ new Map();
|
|
7229
7364
|
const rememberTarget = (harness, target) => {
|
|
@@ -7237,48 +7372,48 @@ function installSkill(options = {}) {
|
|
|
7237
7372
|
plans.set(target, { target, content, boundary, managedMerge });
|
|
7238
7373
|
};
|
|
7239
7374
|
const planSkillTree = (targetDir2, boundary = root) => {
|
|
7240
|
-
for (const rel of files) plan((0,
|
|
7375
|
+
for (const rel of files) plan((0, import_node_path10.join)(targetDir2, rel), (0, import_node_fs11.readFileSync)((0, import_node_path10.join)(sourceDir, rel), "utf8"), false, boundary);
|
|
7241
7376
|
};
|
|
7242
7377
|
let targetDir;
|
|
7243
7378
|
if (options.global) {
|
|
7244
|
-
const claudeRoot = (0,
|
|
7245
|
-
const codexRoot = (0,
|
|
7379
|
+
const claudeRoot = (0, import_node_path10.join)(home, ".claude", "skills");
|
|
7380
|
+
const codexRoot = (0, import_node_path10.resolve)(options.codexHomeDir ?? process.env.CODEX_HOME ?? (0, import_node_path10.join)(home, ".codex"), "skills");
|
|
7246
7381
|
targetDir = harnesses[0] === "codex" ? codexRoot : claudeRoot;
|
|
7247
7382
|
for (const harness of harnesses) {
|
|
7248
7383
|
const skillRoot = harness === "claude" ? claudeRoot : codexRoot;
|
|
7249
|
-
planSkillTree(skillRoot, harness === "claude" ? home : (0,
|
|
7384
|
+
planSkillTree(skillRoot, harness === "claude" ? home : (0, import_node_path10.dirname)((0, import_node_path10.dirname)(codexRoot)));
|
|
7250
7385
|
rememberTarget(harness, skillRoot);
|
|
7251
7386
|
}
|
|
7252
7387
|
} else {
|
|
7253
|
-
const sharedRoot = (0,
|
|
7388
|
+
const sharedRoot = (0, import_node_path10.join)(root, ".agents", "skills");
|
|
7254
7389
|
planSkillTree(sharedRoot);
|
|
7255
|
-
const claudeRoot = (0,
|
|
7390
|
+
const claudeRoot = (0, import_node_path10.join)(root, ".claude", "skills");
|
|
7256
7391
|
targetDir = harnesses.includes("claude") ? claudeRoot : sharedRoot;
|
|
7257
7392
|
for (const harness of harnesses) rememberTarget(harness, sharedRoot);
|
|
7258
7393
|
if (harnesses.includes("claude")) {
|
|
7259
7394
|
for (const skill of skillNames(files)) {
|
|
7260
|
-
const canonical = (0, import_node_fs11.readFileSync)((0,
|
|
7261
|
-
plan((0,
|
|
7395
|
+
const canonical = (0, import_node_fs11.readFileSync)((0, import_node_path10.join)(sourceDir, skill, "SKILL.md"), "utf8");
|
|
7396
|
+
plan((0, import_node_path10.join)(claudeRoot, skill, "SKILL.md"), claudeAdapter(skill, canonical));
|
|
7262
7397
|
}
|
|
7263
7398
|
rememberTarget("claude", claudeRoot);
|
|
7264
7399
|
}
|
|
7265
7400
|
if (harnesses.includes("cursor")) {
|
|
7266
|
-
const cursorRule = (0,
|
|
7401
|
+
const cursorRule = (0, import_node_path10.join)(root, ".cursor", "rules", "odla.mdc");
|
|
7267
7402
|
plan(cursorRule, CURSOR_RULE);
|
|
7268
7403
|
rememberTarget("cursor", cursorRule);
|
|
7269
7404
|
}
|
|
7270
7405
|
if (harnesses.includes("agents")) {
|
|
7271
|
-
const agentsFile = (0,
|
|
7406
|
+
const agentsFile = (0, import_node_path10.join)(root, "AGENTS.md");
|
|
7272
7407
|
plan(agentsFile, managedFileContent(agentsFile, PROJECT_INSTRUCTIONS, options.force === true, root), true);
|
|
7273
7408
|
rememberTarget("agents", agentsFile);
|
|
7274
7409
|
}
|
|
7275
7410
|
if (harnesses.includes("copilot")) {
|
|
7276
|
-
const copilotFile = (0,
|
|
7411
|
+
const copilotFile = (0, import_node_path10.join)(root, ".github", "copilot-instructions.md");
|
|
7277
7412
|
plan(copilotFile, managedFileContent(copilotFile, PROJECT_INSTRUCTIONS, options.force === true, root), true);
|
|
7278
7413
|
rememberTarget("copilot", copilotFile);
|
|
7279
7414
|
}
|
|
7280
7415
|
if (harnesses.includes("gemini")) {
|
|
7281
|
-
const geminiFile = (0,
|
|
7416
|
+
const geminiFile = (0, import_node_path10.join)(root, "GEMINI.md");
|
|
7282
7417
|
plan(geminiFile, managedFileContent(geminiFile, PROJECT_INSTRUCTIONS, options.force === true, root), true);
|
|
7283
7418
|
rememberTarget("gemini", geminiFile);
|
|
7284
7419
|
}
|
|
@@ -7314,7 +7449,7 @@ ${conflicts.map((f) => ` - ${f}`).join("\n")}`
|
|
|
7314
7449
|
}
|
|
7315
7450
|
for (const file of plans.values()) {
|
|
7316
7451
|
if (!(0, import_node_fs11.existsSync)(file.target) || (0, import_node_fs11.readFileSync)(file.target, "utf8") !== file.content) {
|
|
7317
|
-
(0, import_node_fs11.mkdirSync)((0,
|
|
7452
|
+
(0, import_node_fs11.mkdirSync)((0, import_node_path10.dirname)(file.target), { recursive: true });
|
|
7318
7453
|
(0, import_node_fs11.writeFileSync)(file.target, file.content);
|
|
7319
7454
|
}
|
|
7320
7455
|
}
|
|
@@ -7334,7 +7469,7 @@ ${conflicts.map((f) => ` - ${f}`).join("\n")}`
|
|
|
7334
7469
|
};
|
|
7335
7470
|
}
|
|
7336
7471
|
function pathsUnder(root, paths) {
|
|
7337
|
-
return [...paths].map((path) => (0,
|
|
7472
|
+
return [...paths].map((path) => (0, import_node_path10.relative)(root, path)).filter((path) => path !== ".." && !path.startsWith(`..${import_node_path10.sep}`) && !(0, import_node_path10.isAbsolute)(path)).sort();
|
|
7338
7473
|
}
|
|
7339
7474
|
function normalizeHarnesses(values, global) {
|
|
7340
7475
|
const requested = values?.length ? values : ["claude"];
|
|
@@ -7379,13 +7514,13 @@ function managedFileContent(path, block, force, boundary) {
|
|
|
7379
7514
|
return `${current.slice(0, startAt)}${block}${current.slice(afterEnd)}`;
|
|
7380
7515
|
}
|
|
7381
7516
|
function symlinkedComponent(boundary, target) {
|
|
7382
|
-
const rel = (0,
|
|
7383
|
-
if (rel === ".." || rel.startsWith(`..${
|
|
7517
|
+
const rel = (0, import_node_path10.relative)(boundary, target);
|
|
7518
|
+
if (rel === ".." || rel.startsWith(`..${import_node_path10.sep}`) || (0, import_node_path10.isAbsolute)(rel)) {
|
|
7384
7519
|
throw new Error(`agent setup target escapes its install root: ${target}`);
|
|
7385
7520
|
}
|
|
7386
7521
|
let current = boundary;
|
|
7387
|
-
for (const part of rel.split(
|
|
7388
|
-
current = (0,
|
|
7522
|
+
for (const part of rel.split(import_node_path10.sep).filter(Boolean)) {
|
|
7523
|
+
current = (0, import_node_path10.join)(current, part);
|
|
7389
7524
|
try {
|
|
7390
7525
|
if ((0, import_node_fs11.lstatSync)(current).isSymbolicLink()) return current;
|
|
7391
7526
|
} catch (error) {
|
|
@@ -7402,9 +7537,9 @@ function listFiles(dir) {
|
|
|
7402
7537
|
const results = [];
|
|
7403
7538
|
const walk = (current) => {
|
|
7404
7539
|
for (const entry of (0, import_node_fs11.readdirSync)(current, { withFileTypes: true })) {
|
|
7405
|
-
const path = (0,
|
|
7540
|
+
const path = (0, import_node_path10.join)(current, entry.name);
|
|
7406
7541
|
if (entry.isDirectory()) walk(path);
|
|
7407
|
-
else results.push((0,
|
|
7542
|
+
else results.push((0, import_node_path10.relative)(dir, path));
|
|
7408
7543
|
}
|
|
7409
7544
|
};
|
|
7410
7545
|
walk(dir);
|