codiedev 0.10.0-beta.5 → 0.10.0-beta.6
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 +4 -4
- package/dist/captureSignals.js +2 -0
- package/dist/cli.js +38 -50
- package/dist/codexHookTrust.js +67 -4
- package/dist/codie.js +23 -74
- package/dist/codieLauncher.js +18 -22
- package/dist/commands/agentTemplates.generated.js +136 -0
- package/dist/commands/agents.js +1066 -0
- package/dist/commands/agentsSdk.generated.js +7 -0
- package/dist/commands/doctor.js +12 -38
- package/dist/commands/evals.js +187 -0
- package/dist/commands/pack.js +1 -1
- package/dist/commands/traces.js +79 -15
- package/dist/commands/tracesLabel.js +348 -0
- package/dist/connect.js +11 -52
- package/dist/copilotHooks.js +0 -4
- package/dist/cursorHooks.js +0 -15
- package/dist/harnessDirs.js +4 -0
- package/dist/hook.js +33 -197
- package/dist/limitEventReporter.js +1 -1
- package/dist/managedPi.js +240 -0
- package/dist/mcp.js +0 -307
- package/dist/packs/harnesses.js +40 -3
- package/dist/packs/install.js +2 -1
- package/dist/piHooks.js +216 -0
- package/dist/piRuntime.js +120 -0
- package/dist/selfUpdate.js +47 -2
- package/dist/utils.js +232 -115
- package/package.json +5 -7
- package/dist/codieStartup.js +0 -27
- package/dist/commands/promote.js +0 -53
- package/dist/commands/react.js +0 -38
- package/dist/commands/reverseTicket.js +0 -444
- package/dist/commands/security.js +0 -156
- package/dist/prUrl.js +0 -28
- package/dist/security.js +0 -417
- package/dist/securityDeepScan.js +0 -235
- package/dist/securityDoctor.js +0 -61
- package/dist/securityFeature.js +0 -6
- package/dist/securityInstall.js +0 -232
- package/dist/securityInventory.js +0 -566
- package/dist/securityPilot.js +0 -59
- package/dist/securityPolicy.js +0 -181
- package/dist/securitySession.js +0 -72
package/dist/hook.js
CHANGED
|
@@ -53,15 +53,11 @@ const selfUpdate_1 = require("./selfUpdate");
|
|
|
53
53
|
const version_1 = require("./version");
|
|
54
54
|
const sync_1 = require("./packs/sync");
|
|
55
55
|
const captureLog_1 = require("./captureLog");
|
|
56
|
-
const security_1 = require("./security");
|
|
57
|
-
const securitySession_1 = require("./securitySession");
|
|
58
|
-
const securityPolicy_1 = require("./securityPolicy");
|
|
59
56
|
const subagents_1 = require("./subagents");
|
|
60
|
-
const securityFeature_1 = require("./securityFeature");
|
|
61
|
-
const securityInventory_1 = require("./securityInventory");
|
|
62
57
|
const captureExclusions_1 = require("./captureExclusions");
|
|
63
58
|
const cursorHooks_1 = require("./cursorHooks");
|
|
64
59
|
const copilotHooks_1 = require("./copilotHooks");
|
|
60
|
+
const piHooks_1 = require("./piHooks");
|
|
65
61
|
function buildDiscoveryContext(skills) {
|
|
66
62
|
if (skills.length === 0)
|
|
67
63
|
return null;
|
|
@@ -321,131 +317,6 @@ function postJsonForResponse(url, body, bearerToken, timeoutMs) {
|
|
|
321
317
|
req.end();
|
|
322
318
|
});
|
|
323
319
|
}
|
|
324
|
-
async function runSecurityHook(hookInput, phase, source, uploadTelemetry = true) {
|
|
325
|
-
const config = (0, utils_1.readConfig)();
|
|
326
|
-
if (!config || !(0, securityFeature_1.isAgentSecurityEnabled)(config))
|
|
327
|
-
return false;
|
|
328
|
-
const policy = (0, securityPolicy_1.readEndpointSecurityPolicy)(undefined, undefined, config.companyId);
|
|
329
|
-
const sessionId = hookInput.session_id ?? hookInput.sessionId;
|
|
330
|
-
const sessionSignal = phase === "pre" ? (0, securitySession_1.readSessionSecuritySignal)(sessionId) : undefined;
|
|
331
|
-
const localDecision = (0, security_1.evaluateToolSecurity)(hookInput, phase, policy, source, sessionSignal);
|
|
332
|
-
if (phase === "post" && (0, security_1.securityInputHasSensitivePath)(hookInput)) {
|
|
333
|
-
(0, securitySession_1.recordSensitiveReadSignal)(sessionId);
|
|
334
|
-
}
|
|
335
|
-
const event = (0, security_1.buildSecurityWorkflowEvent)(hookInput, phase, source);
|
|
336
|
-
if (event) {
|
|
337
|
-
event.localDecision = localDecision.action;
|
|
338
|
-
event.localCategory = localDecision.category;
|
|
339
|
-
}
|
|
340
|
-
if (localDecision.action === "block" && phase === "pre") {
|
|
341
|
-
(0, captureLog_1.appendCaptureLog)({
|
|
342
|
-
stage: "security",
|
|
343
|
-
sessionId: hookInput.session_id ?? hookInput.sessionId ?? "unknown",
|
|
344
|
-
outcome: "ok",
|
|
345
|
-
detail: `phase=${phase} localDecision=block category=${localDecision.category}`,
|
|
346
|
-
});
|
|
347
|
-
if (uploadTelemetry)
|
|
348
|
-
dispatchSecurityEventUpload(event);
|
|
349
|
-
const response = source === "cursor"
|
|
350
|
-
? (0, cursorHooks_1.cursorPreToolBlockResponse)(localDecision.reason ?? "Codie blocked this action")
|
|
351
|
-
: source === "copilot"
|
|
352
|
-
? (0, copilotHooks_1.copilotPreToolBlockResponse)(localDecision.reason ?? "Codie blocked this action")
|
|
353
|
-
: {
|
|
354
|
-
hookSpecificOutput: {
|
|
355
|
-
hookEventName: "PreToolUse",
|
|
356
|
-
permissionDecision: "deny",
|
|
357
|
-
permissionDecisionReason: localDecision.reason,
|
|
358
|
-
},
|
|
359
|
-
};
|
|
360
|
-
process.stdout.write(JSON.stringify(response));
|
|
361
|
-
return true;
|
|
362
|
-
}
|
|
363
|
-
if (event && uploadTelemetry)
|
|
364
|
-
dispatchSecurityEventUpload(event);
|
|
365
|
-
return false;
|
|
366
|
-
}
|
|
367
|
-
function runPromptSecurityHook(hookInput, source, uploadTelemetry = true) {
|
|
368
|
-
const config = (0, utils_1.readConfig)();
|
|
369
|
-
if (!config || !(0, securityFeature_1.isAgentSecurityEnabled)(config))
|
|
370
|
-
return false;
|
|
371
|
-
const decision = (0, security_1.evaluatePromptSecurity)(hookInput.prompt, (0, securityPolicy_1.readEndpointSecurityPolicy)(undefined, undefined, config.companyId), source);
|
|
372
|
-
if (decision.action !== "block")
|
|
373
|
-
return false;
|
|
374
|
-
(0, captureLog_1.appendCaptureLog)({
|
|
375
|
-
stage: "security",
|
|
376
|
-
sessionId: hookInput.session_id ?? hookInput.sessionId ?? "unknown",
|
|
377
|
-
outcome: "ok",
|
|
378
|
-
detail: `phase=prompt localDecision=block category=${decision.category} telemetry=${uploadTelemetry ? "enabled" : "suppressed"} cwd=${hookInput.cwd ?? "unknown"}`,
|
|
379
|
-
});
|
|
380
|
-
if (uploadTelemetry) {
|
|
381
|
-
dispatchSecurityEventUpload((0, security_1.buildBlockedSecurityPromptEvent)(hookInput, source, decision.category ?? "secret_in_prompt"));
|
|
382
|
-
}
|
|
383
|
-
if (source !== "copilot") {
|
|
384
|
-
const response = source === "cursor"
|
|
385
|
-
? (0, cursorHooks_1.cursorPromptBlockResponse)(decision.reason ?? "Codie blocked this prompt")
|
|
386
|
-
: { decision: "block", reason: decision.reason };
|
|
387
|
-
process.stdout.write(JSON.stringify(response));
|
|
388
|
-
}
|
|
389
|
-
return true;
|
|
390
|
-
}
|
|
391
|
-
function dispatchAllowedPromptSecurityEvent(hookInput, source) {
|
|
392
|
-
const config = (0, utils_1.readConfig)();
|
|
393
|
-
if (!config || !(0, securityFeature_1.isAgentSecurityEnabled)(config))
|
|
394
|
-
return;
|
|
395
|
-
const event = (0, security_1.buildSecurityPromptEvent)(hookInput, source, Date.now, (0, securityPolicy_1.readEndpointSecurityPolicy)(undefined, undefined, config.companyId));
|
|
396
|
-
if (event)
|
|
397
|
-
dispatchSecurityEventUpload(event);
|
|
398
|
-
}
|
|
399
|
-
function dispatchSecurityEventUpload(event) {
|
|
400
|
-
if (!event || !(0, securityFeature_1.isAgentSecurityEnabled)((0, utils_1.readConfig)()))
|
|
401
|
-
return;
|
|
402
|
-
try {
|
|
403
|
-
const child = (0, child_process_1.spawn)(process.execPath, [process.argv[1], "security-upload"], {
|
|
404
|
-
detached: true,
|
|
405
|
-
stdio: ["pipe", "ignore", "ignore"],
|
|
406
|
-
});
|
|
407
|
-
child.stdin?.end(JSON.stringify(event));
|
|
408
|
-
child.unref();
|
|
409
|
-
}
|
|
410
|
-
catch {
|
|
411
|
-
}
|
|
412
|
-
}
|
|
413
|
-
async function runSecurityEventUpload() {
|
|
414
|
-
const config = (0, utils_1.readConfig)();
|
|
415
|
-
if (!config || !(0, securityFeature_1.isAgentSecurityEnabled)(config))
|
|
416
|
-
return;
|
|
417
|
-
const startedAt = Date.now();
|
|
418
|
-
try {
|
|
419
|
-
const raw = await readStdin();
|
|
420
|
-
const event = JSON.parse(raw);
|
|
421
|
-
const cachedPolicy = (0, securityPolicy_1.readEndpointSecurityPolicy)(undefined, undefined, config.companyId);
|
|
422
|
-
const eventWithEndpoint = (0, security_1.withEndpointIdentity)(event, {
|
|
423
|
-
endpointId: config.deviceId,
|
|
424
|
-
endpointName: config.deviceName,
|
|
425
|
-
cliVersion: version_1.CLI_VERSION,
|
|
426
|
-
securityRuntimeVersion: security_1.SECURITY_RUNTIME_VERSION,
|
|
427
|
-
securityPolicyVersion: cachedPolicy?.policyVersion,
|
|
428
|
-
});
|
|
429
|
-
const result = await postJsonForResponse(`${config.backendUrl}/api/cli/securityEvent`, { ...eventWithEndpoint }, config.token, 5_000);
|
|
430
|
-
if (result?.policy?.schemaVersion === 1) {
|
|
431
|
-
(0, securityPolicy_1.writeEndpointSecurityPolicy)(result.policy, undefined, undefined, config.companyId);
|
|
432
|
-
}
|
|
433
|
-
(0, captureLog_1.appendCaptureLog)({
|
|
434
|
-
stage: "security",
|
|
435
|
-
sessionId: event.sessionId,
|
|
436
|
-
outcome: "ok",
|
|
437
|
-
detail: `phase=${event.phase} elapsedMs=${Date.now() - startedAt} verdict=${String(result?.verdict ?? "unknown")}`,
|
|
438
|
-
});
|
|
439
|
-
}
|
|
440
|
-
catch (err) {
|
|
441
|
-
(0, captureLog_1.appendCaptureLog)({
|
|
442
|
-
stage: "security",
|
|
443
|
-
sessionId: "upload",
|
|
444
|
-
outcome: "ERROR",
|
|
445
|
-
detail: `elapsedMs=${Date.now() - startedAt} ${err.message}`,
|
|
446
|
-
});
|
|
447
|
-
}
|
|
448
|
-
}
|
|
449
320
|
function postBytes(url, bytes, contentType) {
|
|
450
321
|
return new Promise((resolve, reject) => {
|
|
451
322
|
const parsed = new URL(url);
|
|
@@ -502,6 +373,8 @@ function resolveMode(arg) {
|
|
|
502
373
|
return "copilot";
|
|
503
374
|
if (arg === "capture-opencode" || arg === "capture-opencode-final")
|
|
504
375
|
return "opencode";
|
|
376
|
+
if (arg === "capture-pi" || arg === "capture-pi-final")
|
|
377
|
+
return "pi";
|
|
505
378
|
if (arg === "capture-desktop" || arg === "capture-desktop-final")
|
|
506
379
|
return "desktop";
|
|
507
380
|
return "claude-code";
|
|
@@ -542,17 +415,6 @@ async function main() {
|
|
|
542
415
|
}
|
|
543
416
|
process.exit(0);
|
|
544
417
|
}
|
|
545
|
-
if (process.argv[2] === "security-inventory-upload") {
|
|
546
|
-
const config = (0, utils_1.readConfig)();
|
|
547
|
-
if (config && (0, securityFeature_1.isAgentSecurityEnabled)(config)) {
|
|
548
|
-
const inventory = (0, securityInventory_1.buildSecurityInventory)({ workspace: process.argv[3] || process.cwd() });
|
|
549
|
-
try {
|
|
550
|
-
await (0, securityInventory_1.uploadSecurityInventory)(inventory, config);
|
|
551
|
-
}
|
|
552
|
-
catch { }
|
|
553
|
-
}
|
|
554
|
-
process.exit(0);
|
|
555
|
-
}
|
|
556
418
|
if (process.argv[2] === "backup-upload") {
|
|
557
419
|
const { runBackupUpload } = await Promise.resolve().then(() => __importStar(require("./backup/run")));
|
|
558
420
|
await runBackupUpload(process.argv[3]);
|
|
@@ -577,10 +439,6 @@ async function main() {
|
|
|
577
439
|
}
|
|
578
440
|
process.exit(0);
|
|
579
441
|
}
|
|
580
|
-
if (process.argv[2] === "security-upload") {
|
|
581
|
-
await runSecurityEventUpload();
|
|
582
|
-
process.exit(0);
|
|
583
|
-
}
|
|
584
442
|
if (process.argv[2] === "self-update") {
|
|
585
443
|
await (0, selfUpdate_1.runSelfUpdate)(process.argv[1]);
|
|
586
444
|
process.exit(0);
|
|
@@ -588,6 +446,7 @@ async function main() {
|
|
|
588
446
|
const migrated = process.env.CODIEDEV_VIA_LAUNCHER ? [] : (0, utils_1.migrateHooksToLauncher)();
|
|
589
447
|
if (migrated.length === 0)
|
|
590
448
|
(0, selfUpdate_1.maybeSpawnSelfUpdate)(process.argv[1]);
|
|
449
|
+
(0, selfUpdate_1.maybeRefreshInstructions)();
|
|
591
450
|
let hookInput = {};
|
|
592
451
|
try {
|
|
593
452
|
const raw = await readStdin();
|
|
@@ -603,54 +462,26 @@ async function main() {
|
|
|
603
462
|
catch {
|
|
604
463
|
process.exit(0);
|
|
605
464
|
}
|
|
606
|
-
|
|
607
|
-
const securityCommand = process.argv[2] ?? "";
|
|
608
|
-
const securityMatch = securityCommand.match(/^security-(pre|post|failure)(?:-(codex|cursor|codie|copilot))?$/);
|
|
609
|
-
if (securityMatch) {
|
|
610
|
-
const source = securityMatch[2] === "codex"
|
|
611
|
-
? "codex"
|
|
612
|
-
: securityMatch[2] === "cursor"
|
|
613
|
-
? "cursor"
|
|
614
|
-
: securityMatch[2] === "codie"
|
|
615
|
-
? "codie-harness"
|
|
616
|
-
: securityMatch[2] === "copilot"
|
|
617
|
-
? "copilot"
|
|
618
|
-
: "claude-code";
|
|
619
|
-
const calls = hookInput.copilotToolCalls;
|
|
620
|
-
const inputs = calls?.length
|
|
621
|
-
? calls.map((call) => ({ ...hookInput, tool_name: call.name, tool_input: call.input, tool_use_id: call.id }))
|
|
622
|
-
: [hookInput];
|
|
623
|
-
for (const input of inputs) {
|
|
624
|
-
if (await runSecurityHook(input, securityMatch[1], source, !captureIgnored))
|
|
625
|
-
break;
|
|
626
|
-
}
|
|
465
|
+
if (process.argv[2]?.startsWith("security-"))
|
|
627
466
|
process.exit(0);
|
|
628
|
-
|
|
467
|
+
const captureIgnored = (0, captureExclusions_1.shouldIgnoreCaptureInput)((0, utils_1.readConfig)(), hookInput);
|
|
629
468
|
const promptCommand = process.argv[2] ?? "";
|
|
630
|
-
if (promptCommand === "security-prompt-cursor") {
|
|
631
|
-
if (runPromptSecurityHook(hookInput, "cursor", !captureIgnored))
|
|
632
|
-
return;
|
|
633
|
-
if (captureIgnored)
|
|
634
|
-
return;
|
|
635
|
-
dispatchAllowedPromptSecurityEvent(hookInput, "cursor");
|
|
636
|
-
process.exit(0);
|
|
637
|
-
}
|
|
638
469
|
if (process.argv[2] === "discover" ||
|
|
639
470
|
process.argv[2] === "discover-codex" ||
|
|
640
471
|
process.argv[2] === "discover-codie" ||
|
|
641
|
-
process.argv[2] === "discover-copilot"
|
|
472
|
+
process.argv[2] === "discover-copilot" ||
|
|
473
|
+
process.argv[2] === "discover-pi") {
|
|
642
474
|
const source = promptCommand === "discover-codex"
|
|
643
475
|
? "codex"
|
|
644
476
|
: promptCommand === "discover-codie"
|
|
645
477
|
? "codie-harness"
|
|
646
478
|
: promptCommand === "discover-copilot"
|
|
647
479
|
? "copilot"
|
|
648
|
-
: "
|
|
649
|
-
|
|
650
|
-
|
|
480
|
+
: promptCommand === "discover-pi"
|
|
481
|
+
? "pi"
|
|
482
|
+
: "claude-code";
|
|
651
483
|
if (captureIgnored)
|
|
652
484
|
return;
|
|
653
|
-
dispatchAllowedPromptSecurityEvent(hookInput, source);
|
|
654
485
|
if (source === "codex")
|
|
655
486
|
await runCodexLimitSweep(hookInput.session_id);
|
|
656
487
|
if (source === "codex")
|
|
@@ -693,19 +524,10 @@ async function main() {
|
|
|
693
524
|
if (process.argv[2] === "session-start" ||
|
|
694
525
|
process.argv[2] === "session-start-cursor" ||
|
|
695
526
|
process.argv[2] === "session-start-copilot" ||
|
|
696
|
-
process.argv[2] === "session-start-opencode"
|
|
697
|
-
|
|
698
|
-
try {
|
|
699
|
-
const child = (0, child_process_1.spawn)(process.execPath, [process.argv[1], "security-inventory-upload", hookInput.cwd || process.cwd()], {
|
|
700
|
-
detached: true,
|
|
701
|
-
stdio: "ignore",
|
|
702
|
-
});
|
|
703
|
-
child.unref();
|
|
704
|
-
}
|
|
705
|
-
catch { }
|
|
706
|
-
}
|
|
527
|
+
process.argv[2] === "session-start-opencode" ||
|
|
528
|
+
process.argv[2] === "session-start-pi") {
|
|
707
529
|
(0, sync_1.maybeSpawnPackSync)({ connected: Boolean((0, utils_1.readConfig)()), cli: path.join(__dirname, "cli.js") });
|
|
708
|
-
const packNag = process.argv[2] === "session-start-opencode" ? null : (0, sync_1.packNagLine)();
|
|
530
|
+
const packNag = process.argv[2] === "session-start-opencode" || process.argv[2] === "session-start-pi" ? null : (0, sync_1.packNagLine)();
|
|
709
531
|
if (packNag && process.argv[2] === "session-start")
|
|
710
532
|
process.stdout.write(`${packNag}\n`);
|
|
711
533
|
await runSessionStart(hookInput, process.argv[2] === "session-start-opencode"
|
|
@@ -714,7 +536,9 @@ async function main() {
|
|
|
714
536
|
? "cursor"
|
|
715
537
|
: process.argv[2] === "session-start-copilot"
|
|
716
538
|
? "copilot"
|
|
717
|
-
: "
|
|
539
|
+
: process.argv[2] === "session-start-pi"
|
|
540
|
+
? "pi"
|
|
541
|
+
: "claude-code");
|
|
718
542
|
if ((0, utils_1.readConfig)() && (process.argv[2] === "session-start-cursor" || process.argv[2] === "session-start-copilot")) {
|
|
719
543
|
const source = process.argv[2] === "session-start-cursor" ? "cursor" : "copilot";
|
|
720
544
|
const { TEAM_SKILL_CONTEXT, teamSkillSessionOutput } = await Promise.resolve().then(() => __importStar(require("./teamSkillContext")));
|
|
@@ -731,11 +555,16 @@ async function main() {
|
|
|
731
555
|
else if ((process.argv[2] ?? "").endsWith("-copilot")) {
|
|
732
556
|
(0, utils_1.ensureCopilotCodiedevHooksInstalled)();
|
|
733
557
|
}
|
|
558
|
+
else if (/-pi(?:-final)?$/.test(process.argv[2] ?? "")) {
|
|
559
|
+
(0, utils_1.ensurePiExtensionInstalled)();
|
|
560
|
+
}
|
|
734
561
|
else {
|
|
735
562
|
(0, utils_1.ensureAllCodiedevHooksInstalled)();
|
|
736
563
|
}
|
|
737
564
|
if (process.argv[2] === "capture-codex")
|
|
738
565
|
(0, utils_1.ensureCodexLimitHookInstalled)();
|
|
566
|
+
if (/-opencode(?:-final)?$/.test(process.argv[2] ?? ""))
|
|
567
|
+
(0, utils_1.ensureOpenCodePluginCurrent)();
|
|
739
568
|
const { session_id, transcript_path, cwd, workspace_roots } = hookInput;
|
|
740
569
|
const launch = (0, launchContext_1.hookLaunch)(process.argv[2], hookInput, {
|
|
741
570
|
copilotClientName: process.argv[2]?.endsWith("-copilot")
|
|
@@ -745,7 +574,7 @@ async function main() {
|
|
|
745
574
|
const workspaceRoot = workspace_roots && workspace_roots.length > 0
|
|
746
575
|
? workspace_roots[0]
|
|
747
576
|
: cwd || process.cwd();
|
|
748
|
-
if (process.argv[2] === "backup" || process.argv[2] === "backup-cursor" || process.argv[2] === "backup-copilot") {
|
|
577
|
+
if (process.argv[2] === "backup" || process.argv[2] === "backup-cursor" || process.argv[2] === "backup-copilot" || process.argv[2] === "backup-pi") {
|
|
749
578
|
if (transcript_path && !(0, utils_1.isCodexRolloutPath)(transcript_path)) {
|
|
750
579
|
try {
|
|
751
580
|
(0, utils_1.dispatchCaptureFinish)({
|
|
@@ -753,7 +582,9 @@ async function main() {
|
|
|
753
582
|
? "capture-cursor"
|
|
754
583
|
: process.argv[2] === "backup-copilot"
|
|
755
584
|
? "capture-copilot"
|
|
756
|
-
: "
|
|
585
|
+
: process.argv[2] === "backup-pi"
|
|
586
|
+
? "capture-pi"
|
|
587
|
+
: "capture",
|
|
757
588
|
session_id,
|
|
758
589
|
transcript_path,
|
|
759
590
|
cwd,
|
|
@@ -878,7 +709,10 @@ async function runCaptureFinishInner(input, config, session_id, transcript_path,
|
|
|
878
709
|
transcriptContent = normalized.content;
|
|
879
710
|
copilotSubagents = normalized.subagents.count > 0 ? normalized.subagents : undefined;
|
|
880
711
|
}
|
|
881
|
-
if (
|
|
712
|
+
else if (parserMode === "pi") {
|
|
713
|
+
transcriptContent = (0, piHooks_1.normalizePiTranscript)(transcriptContent);
|
|
714
|
+
}
|
|
715
|
+
if (mode === "cursor" || mode === "copilot" || mode === "pi") {
|
|
882
716
|
try {
|
|
883
717
|
await (0, limitEventReporter_1.reportTranscriptLimitEvent)({ config, source: mode, sessionId: session_id, transcript: transcriptContent });
|
|
884
718
|
}
|
|
@@ -902,7 +736,9 @@ async function runCaptureFinishInner(input, config, session_id, transcript_path,
|
|
|
902
736
|
? "empty-cursor-transcript"
|
|
903
737
|
: parserMode === "copilot" && (0, copilotHooks_1.isCopilotTranscriptEmpty)(rawTranscriptContent)
|
|
904
738
|
? "empty-copilot-transcript"
|
|
905
|
-
:
|
|
739
|
+
: parserMode === "pi" && (0, piHooks_1.isPiTranscriptEmpty)(rawTranscriptContent)
|
|
740
|
+
? "empty-pi-transcript"
|
|
741
|
+
: null;
|
|
906
742
|
if (emptyReason) {
|
|
907
743
|
(0, captureLog_1.appendCaptureLog)({
|
|
908
744
|
stage: "capture-finish",
|
|
@@ -76,7 +76,7 @@ function postLimitEvent(config, payload, timeoutMs = 5_000) {
|
|
|
76
76
|
async function reportTranscriptLimitEvent(args) {
|
|
77
77
|
const parse = args.source === "codex"
|
|
78
78
|
? limitEvent_1.parseCodexLimitEventFromTranscript
|
|
79
|
-
: args.source === "cursor" || args.source === "copilot" ? limitEvent_1.parseNativeLimitEventFromTranscript : limitEvent_1.parseLimitEventFromTranscript;
|
|
79
|
+
: args.source === "cursor" || args.source === "copilot" || args.source === "pi" ? limitEvent_1.parseNativeLimitEventFromTranscript : limitEvent_1.parseLimitEventFromTranscript;
|
|
80
80
|
const parsed = parse(args.transcript);
|
|
81
81
|
if (!parsed && !args.emitMinimalOnMiss)
|
|
82
82
|
return false;
|
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.ManagedPiArgError = exports.GUARD_SOURCE = exports.BLOCKED_BASE_URL = exports.CAPTURE_FILE = exports.GUARD_FILE = exports.PI_PROVIDER_ENV = exports.PI_PROVIDER_ID = void 0;
|
|
37
|
+
exports.managedPiAgentDir = managedPiAgentDir;
|
|
38
|
+
exports.piProviderConfig = piProviderConfig;
|
|
39
|
+
exports.prepareManagedPiDir = prepareManagedPiDir;
|
|
40
|
+
exports.managedPiEnv = managedPiEnv;
|
|
41
|
+
exports.managedPiArgs = managedPiArgs;
|
|
42
|
+
exports.runManagedPi = runManagedPi;
|
|
43
|
+
const child_process_1 = require("child_process");
|
|
44
|
+
const fs = __importStar(require("fs"));
|
|
45
|
+
const path = __importStar(require("path"));
|
|
46
|
+
const codieLauncher_1 = require("./codieLauncher");
|
|
47
|
+
const piRuntime_1 = require("./piRuntime");
|
|
48
|
+
const utils_1 = require("./utils");
|
|
49
|
+
exports.PI_PROVIDER_ID = "codiedev";
|
|
50
|
+
exports.PI_PROVIDER_ENV = [
|
|
51
|
+
"ANTHROPIC_API_KEY", "ANTHROPIC_OAUTH_TOKEN", "OPENAI_API_KEY", "AZURE_OPENAI_API_KEY",
|
|
52
|
+
"AZURE_OPENAI_BASE_URL", "AZURE_OPENAI_RESOURCE_NAME", "DEEPSEEK_API_KEY", "GEMINI_API_KEY",
|
|
53
|
+
"GROQ_API_KEY", "CEREBRAS_API_KEY", "XAI_API_KEY", "FIREWORKS_API_KEY", "OPENROUTER_API_KEY",
|
|
54
|
+
"AI_GATEWAY_API_KEY", "ZAI_API_KEY", "MISTRAL_API_KEY", "MINIMAX_API_KEY", "MOONSHOT_API_KEY",
|
|
55
|
+
"OPENCODE_API_KEY", "KIMI_API_KEY", "CLOUDFLARE_API_KEY", "XIAOMI_API_KEY",
|
|
56
|
+
"XIAOMI_TOKEN_PLAN_CN_API_KEY", "XIAOMI_TOKEN_PLAN_AMS_API_KEY", "XIAOMI_TOKEN_PLAN_SGP_API_KEY",
|
|
57
|
+
"AWS_PROFILE", "AWS_ACCESS_KEY_ID", "AWS_SECRET_ACCESS_KEY", "AWS_SESSION_TOKEN",
|
|
58
|
+
"AWS_BEARER_TOKEN_BEDROCK", "GOOGLE_APPLICATION_CREDENTIALS", "GOOGLE_CLOUD_API_KEY",
|
|
59
|
+
"COPILOT_GITHUB_TOKEN",
|
|
60
|
+
];
|
|
61
|
+
const BLOCKED_SUBCOMMANDS = new Set(["install", "remove", "uninstall", "config"]);
|
|
62
|
+
exports.GUARD_FILE = "codie-guard.ts";
|
|
63
|
+
exports.CAPTURE_FILE = "codiedev-capture.ts";
|
|
64
|
+
exports.BLOCKED_BASE_URL = "http://127.0.0.1:9/blocked-by-codiedev";
|
|
65
|
+
exports.GUARD_SOURCE = `// Written by Codiedev on every \`codie --pi\` launch. Edits are overwritten.
|
|
66
|
+
import { execFileSync } from "node:child_process";
|
|
67
|
+
import { getProviders } from "@mariozechner/pi-ai";
|
|
68
|
+
|
|
69
|
+
const PROVIDER = ${JSON.stringify(exports.PI_PROVIDER_ID)};
|
|
70
|
+
const BLOCKED = ${JSON.stringify(exports.BLOCKED_BASE_URL)};
|
|
71
|
+
const ours = (m) => Boolean(m && m.provider === PROVIDER);
|
|
72
|
+
const label = (m) => (m ? m.provider + "/" + m.id : "that model");
|
|
73
|
+
// pi runs a header value starting with "!" as a shell command, so no value
|
|
74
|
+
// may start with one; branch and skill names are user-controlled.
|
|
75
|
+
const clean = (v, max) => String(v ?? "").replace(/[\\r\\n]/g, "").trim().replace(/^!+/, "").slice(0, max);
|
|
76
|
+
const git = (cwd, args) => { try { return execFileSync("git", args, { cwd, encoding: "utf8", stdio: ["ignore", "pipe", "ignore"], timeout: 1500 }).trim(); } catch { return ""; } };
|
|
77
|
+
|
|
78
|
+
export default function (pi) {
|
|
79
|
+
for (const p of getProviders()) if (p !== PROVIDER) pi.registerProvider(p, { baseUrl: BLOCKED });
|
|
80
|
+
|
|
81
|
+
let last;
|
|
82
|
+
const skills = new Set();
|
|
83
|
+
const fallback = (ctx) => last ?? ctx.modelRegistry.getAll().find(ours);
|
|
84
|
+
const pin = async (model, ctx) => {
|
|
85
|
+
const back = fallback(ctx);
|
|
86
|
+
if (back) await pi.setModel(back);
|
|
87
|
+
if (ctx.hasUI) ctx.ui.notify("codie: " + label(model) + " isn't a Codiedev-approved model" + (back ? "; using " + back.id : "") + ".", "warning");
|
|
88
|
+
};
|
|
89
|
+
const tag = (ctx) => {
|
|
90
|
+
const headers = {};
|
|
91
|
+
const session = clean(ctx.sessionManager?.getSessionId?.(), 200);
|
|
92
|
+
if (session) headers["X-Codiedev-Session-Id"] = session;
|
|
93
|
+
const repo = clean(git(ctx.cwd, ["remote", "get-url", "origin"]).replace(/\\/\\/[^/@]*@/, "//"), 2048);
|
|
94
|
+
if (repo) headers["X-Codiedev-Repo-Url"] = repo;
|
|
95
|
+
const branch = clean(git(ctx.cwd, ["branch", "--show-current"]), 200);
|
|
96
|
+
if (branch) headers["X-Codiedev-Branch"] = branch;
|
|
97
|
+
const sha = clean(git(ctx.cwd, ["rev-parse", "HEAD"]), 40);
|
|
98
|
+
if (/^[0-9a-f]{7,40}$/i.test(sha)) headers["X-Codiedev-Head-Sha"] = sha;
|
|
99
|
+
const list = clean([...skills].join(","), 4096);
|
|
100
|
+
if (list) headers["X-Codiedev-Skills-Used"] = list;
|
|
101
|
+
// pi replaces the provider's whole request config here, so the key name
|
|
102
|
+
// goes with the headers every time.
|
|
103
|
+
pi.registerProvider(PROVIDER, { apiKey: "CODIEDEV_GATEWAY_KEY", headers });
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
pi.on("session_start", async (_event, ctx) => {
|
|
107
|
+
skills.clear();
|
|
108
|
+
for (const m of ctx.modelRegistry.getAll()) if (!ours(m)) pi.registerProvider(m.provider, { baseUrl: BLOCKED });
|
|
109
|
+
if (ours(ctx.model)) last = ctx.model;
|
|
110
|
+
else await pin(ctx.model, ctx);
|
|
111
|
+
tag(ctx);
|
|
112
|
+
});
|
|
113
|
+
pi.on("model_select", async (event, ctx) => {
|
|
114
|
+
if (ours(event.model)) last = event.model;
|
|
115
|
+
else await pin(event.model, ctx);
|
|
116
|
+
});
|
|
117
|
+
pi.on("input", async (event) => {
|
|
118
|
+
const m = String(event?.text ?? "").match(/^\\/skill:([a-z0-9][a-z0-9_.:-]{0,119})(?:\\s|$)/i);
|
|
119
|
+
if (m && skills.size < 50) skills.add(m[1]);
|
|
120
|
+
});
|
|
121
|
+
pi.on("tool_result", async (event) => {
|
|
122
|
+
const p = String(event?.input?.path ?? "").replace(/\\\\/g, "/").match(/\\/([a-z0-9][a-z0-9_.:-]{0,119})\\/SKILL\\.md$/i);
|
|
123
|
+
if (event?.toolName === "read" && !event.isError && p && skills.size < 50) skills.add(p[1]);
|
|
124
|
+
});
|
|
125
|
+
// Before every model call in the turn: the agent may have switched branch.
|
|
126
|
+
pi.on("turn_start", async (_event, ctx) => tag(ctx));
|
|
127
|
+
pi.on("before_provider_request", (_event, ctx) => {
|
|
128
|
+
// Belt and braces: the request is already headed for BLOCKED.
|
|
129
|
+
if (!ours(ctx.model)) ctx.abort();
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
`;
|
|
133
|
+
function managedPiAgentDir(stateDir) {
|
|
134
|
+
return path.join(stateDir, "managed", "pi", "agent");
|
|
135
|
+
}
|
|
136
|
+
function piProviderConfig(gatewayUrl, catalog) {
|
|
137
|
+
return {
|
|
138
|
+
baseUrl: gatewayUrl.replace(/\/+$/, ""),
|
|
139
|
+
api: "openai-completions",
|
|
140
|
+
apiKey: "CODIEDEV_GATEWAY_KEY",
|
|
141
|
+
compat: { supportsDeveloperRole: false, supportsReasoningEffort: false },
|
|
142
|
+
models: catalog.map((model) => ({
|
|
143
|
+
id: (0, codieLauncher_1.bareModel)(model.id),
|
|
144
|
+
name: model.name || (0, codieLauncher_1.bareModel)(model.id),
|
|
145
|
+
...(model.limit ? { contextWindow: model.limit.context, maxTokens: model.limit.output } : {}),
|
|
146
|
+
...(model.cost ? { cost: { input: model.cost.input, output: model.cost.output, cacheRead: 0, cacheWrite: 0 } } : {}),
|
|
147
|
+
})),
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
function writeJsonAtomic(file, value) {
|
|
151
|
+
const tmp = `${file}.${process.pid}.tmp`;
|
|
152
|
+
fs.writeFileSync(tmp, JSON.stringify(value, null, 2) + "\n", { mode: 0o600 });
|
|
153
|
+
fs.renameSync(tmp, file);
|
|
154
|
+
}
|
|
155
|
+
function prepareManagedPiDir(opts) {
|
|
156
|
+
const { agentDir, gatewayUrl, catalog } = opts;
|
|
157
|
+
if (!catalog.length)
|
|
158
|
+
throw new Error("No company-approved models were returned by Codiedev");
|
|
159
|
+
const ids = catalog.map((model) => (0, codieLauncher_1.bareModel)(model.id));
|
|
160
|
+
const requested = (0, codieLauncher_1.bareModel)(opts.model ?? "");
|
|
161
|
+
if (requested && !ids.includes(requested)) {
|
|
162
|
+
throw new Error(`Primary agent model is not approved for this Codiedev account: ${requested}`);
|
|
163
|
+
}
|
|
164
|
+
fs.mkdirSync(agentDir, { recursive: true, mode: 0o700 });
|
|
165
|
+
writeJsonAtomic(path.join(agentDir, "models.json"), { providers: { [exports.PI_PROVIDER_ID]: piProviderConfig(gatewayUrl, catalog) } });
|
|
166
|
+
writeJsonAtomic(path.join(agentDir, "settings.json"), {
|
|
167
|
+
defaultProvider: exports.PI_PROVIDER_ID,
|
|
168
|
+
defaultModel: requested || ids[0],
|
|
169
|
+
enabledModels: ids.map((id) => `${exports.PI_PROVIDER_ID}/${id}`),
|
|
170
|
+
packages: [],
|
|
171
|
+
extensions: [],
|
|
172
|
+
skills: opts.skillPaths ?? [],
|
|
173
|
+
enableInstallTelemetry: false,
|
|
174
|
+
});
|
|
175
|
+
fs.rmSync(path.join(agentDir, "auth.json"), { force: true });
|
|
176
|
+
fs.rmSync(path.join(agentDir, "extensions"), { recursive: true, force: true });
|
|
177
|
+
const guard = path.join(agentDir, exports.GUARD_FILE);
|
|
178
|
+
fs.writeFileSync(guard, exports.GUARD_SOURCE, { mode: 0o600 });
|
|
179
|
+
const capture = path.join(agentDir, exports.CAPTURE_FILE);
|
|
180
|
+
fs.writeFileSync(capture, (0, utils_1.piExtensionSource)(), { mode: 0o600 });
|
|
181
|
+
return [guard, capture];
|
|
182
|
+
}
|
|
183
|
+
function managedPiEnv(env, agentDir, key, platform = process.platform) {
|
|
184
|
+
const blocked = new Set([...exports.PI_PROVIDER_ENV, "PI_CODING_AGENT_DIR"]);
|
|
185
|
+
const out = {};
|
|
186
|
+
for (const [k, v] of Object.entries(env)) {
|
|
187
|
+
if (blocked.has(platform === "win32" ? k.toUpperCase() : k))
|
|
188
|
+
continue;
|
|
189
|
+
out[k] = v;
|
|
190
|
+
}
|
|
191
|
+
out.PI_CODING_AGENT_DIR = agentDir;
|
|
192
|
+
out.PI_TELEMETRY = "0";
|
|
193
|
+
out.CODIEDEV_GATEWAY_KEY = key;
|
|
194
|
+
return out;
|
|
195
|
+
}
|
|
196
|
+
class ManagedPiArgError extends Error {
|
|
197
|
+
}
|
|
198
|
+
exports.ManagedPiArgError = ManagedPiArgError;
|
|
199
|
+
function managedPiArgs(args, extensions) {
|
|
200
|
+
if (args.length && BLOCKED_SUBCOMMANDS.has(args[0])) {
|
|
201
|
+
throw new ManagedPiArgError(`\`pi ${args[0]}\` changes extension sources, which codie --pi manages. Ask your Codiedev admin to approve a package instead.`);
|
|
202
|
+
}
|
|
203
|
+
for (let i = 0; i < args.length; i++) {
|
|
204
|
+
const a = args[i];
|
|
205
|
+
if (a === "--")
|
|
206
|
+
break;
|
|
207
|
+
const [flag, inline] = a.startsWith("--") && a.includes("=") ? [a.slice(0, a.indexOf("=")), a.slice(a.indexOf("=") + 1)] : [a, undefined];
|
|
208
|
+
if (flag === "--api-key")
|
|
209
|
+
throw new ManagedPiArgError("--api-key isn't allowed in codie --pi: models come from Codiedev.");
|
|
210
|
+
if (flag === "-e" || flag === "--extension")
|
|
211
|
+
throw new ManagedPiArgError(`${flag} isn't allowed in codie --pi: extensions are managed by Codiedev.`);
|
|
212
|
+
if (flag === "--provider") {
|
|
213
|
+
const value = inline ?? args[i + 1];
|
|
214
|
+
if (value !== exports.PI_PROVIDER_ID)
|
|
215
|
+
throw new ManagedPiArgError(`--provider ${value ?? "(none)"} isn't allowed in codie --pi: only Codiedev-approved models are available.`);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
return ["--no-extensions", ...extensions.flatMap((file) => ["-e", file]), ...args];
|
|
219
|
+
}
|
|
220
|
+
function runManagedPi(opts) {
|
|
221
|
+
const env = opts.env ?? process.env;
|
|
222
|
+
const agentDir = managedPiAgentDir(opts.stateDir);
|
|
223
|
+
const extensions = prepareManagedPiDir({
|
|
224
|
+
agentDir, gatewayUrl: opts.gatewayUrl, catalog: opts.catalog, model: env.CODIEDEV_MODEL,
|
|
225
|
+
skillPaths: opts.skillPaths,
|
|
226
|
+
});
|
|
227
|
+
const args = managedPiArgs(opts.args, extensions);
|
|
228
|
+
const bin = env.CODIEDEV_PI_BIN?.trim();
|
|
229
|
+
const [command, commandArgs] = bin
|
|
230
|
+
? [bin, args]
|
|
231
|
+
: [process.execPath, [(opts.resolvePi ?? (() => (0, piRuntime_1.ensurePiRuntime)({ stateDir: opts.stateDir })))(), ...args]];
|
|
232
|
+
const result = (0, child_process_1.spawnSync)(command, commandArgs, {
|
|
233
|
+
stdio: "inherit",
|
|
234
|
+
env: managedPiEnv(env, agentDir, opts.key),
|
|
235
|
+
shell: Boolean(bin) && process.platform === "win32",
|
|
236
|
+
});
|
|
237
|
+
if (result.error)
|
|
238
|
+
throw result.error;
|
|
239
|
+
return result.status === null ? 1 : result.status;
|
|
240
|
+
}
|