@jpcasabiancai/cayenne 0.5.12 → 0.5.14
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/cli.js +341 -61
- package/package.json +2 -2
package/dist/cli.js
CHANGED
|
@@ -1586,7 +1586,7 @@ var init_documents = __esm({
|
|
|
1586
1586
|
|
|
1587
1587
|
// ../../packages/shared/src/protocol/events.ts
|
|
1588
1588
|
import { z as z14 } from "zod";
|
|
1589
|
-
var SessionStatus, SessionEvent, SESSION_EVENT_NAME, sessionTopic, runnerTopic, terminalTopic, activityFeedTopic;
|
|
1589
|
+
var SessionStatus, RenewalReason, SessionEvent, SESSION_EVENT_NAME, sessionTopic, runnerTopic, terminalTopic, activityFeedTopic;
|
|
1590
1590
|
var init_events = __esm({
|
|
1591
1591
|
"../../packages/shared/src/protocol/events.ts"() {
|
|
1592
1592
|
"use strict";
|
|
@@ -1600,6 +1600,13 @@ var init_events = __esm({
|
|
|
1600
1600
|
"error",
|
|
1601
1601
|
"archived"
|
|
1602
1602
|
]);
|
|
1603
|
+
RenewalReason = z14.enum([
|
|
1604
|
+
"autopilot_threshold",
|
|
1605
|
+
"threshold",
|
|
1606
|
+
"visibility",
|
|
1607
|
+
"manual",
|
|
1608
|
+
"compaction"
|
|
1609
|
+
]);
|
|
1603
1610
|
SessionEvent = z14.discriminatedUnion("type", [
|
|
1604
1611
|
z14.object({
|
|
1605
1612
|
type: z14.literal("session.status"),
|
|
@@ -1654,7 +1661,16 @@ var init_events = __esm({
|
|
|
1654
1661
|
segment: z14.number().int().nonnegative(),
|
|
1655
1662
|
fromTokens: z14.number().int().optional(),
|
|
1656
1663
|
toTokens: z14.number().int().optional(),
|
|
1657
|
-
error: z14.string().optional()
|
|
1664
|
+
error: z14.string().optional(),
|
|
1665
|
+
// Added 2026-10-23 (Auto Pilot 03, D62); absent from runners ≤ 0.5.13.
|
|
1666
|
+
reason: RenewalReason.optional()
|
|
1667
|
+
}),
|
|
1668
|
+
// Auto Pilot 03 (D62), protocol §3: sent once after `renewal { phase: 'done' }`, naming the new
|
|
1669
|
+
// segment `n + 1` and why it renewed.
|
|
1670
|
+
z14.object({
|
|
1671
|
+
type: z14.literal("session.renewed"),
|
|
1672
|
+
segment: z14.number().int().min(1),
|
|
1673
|
+
reason: RenewalReason
|
|
1658
1674
|
})
|
|
1659
1675
|
]);
|
|
1660
1676
|
SESSION_EVENT_NAME = "evt";
|
|
@@ -2594,7 +2610,7 @@ var init_registry = __esm({
|
|
|
2594
2610
|
"use strict";
|
|
2595
2611
|
REDACTED = "[REDACTED]";
|
|
2596
2612
|
MIN_SECRET_LENGTH = 16;
|
|
2597
|
-
GITHUB_TOKEN_SHAPE = /(?:gh[pousr]_|github_pat_)[A-Za-z0-9_]{20,
|
|
2613
|
+
GITHUB_TOKEN_SHAPE = /(?:ghs_[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+|(?:gh[pousr]_|github_pat_)[A-Za-z0-9_]{20,})/;
|
|
2598
2614
|
GITHUB_TOKEN_SHAPES = new RegExp(GITHUB_TOKEN_SHAPE.source, "g");
|
|
2599
2615
|
secrets = createSecretRegistry();
|
|
2600
2616
|
isError = (value) => value instanceof Error || types.isNativeError(value);
|
|
@@ -3469,7 +3485,7 @@ function statusSummary(porcelain) {
|
|
|
3469
3485
|
if (lines.length > MAX_STATUS_PATHS) out.push(` \u2026 ${lines.length - MAX_STATUS_PATHS} more`);
|
|
3470
3486
|
return out;
|
|
3471
3487
|
}
|
|
3472
|
-
function buildAppendix(git, todos, docs, claims) {
|
|
3488
|
+
function buildAppendix(git, todos, docs, claims, extra = []) {
|
|
3473
3489
|
const out = [APPENDIX_HEADING];
|
|
3474
3490
|
if (git) {
|
|
3475
3491
|
out.push(`Branch: ${git.branch === null ? "(detached or none)" : field(git.branch, CAP_PATH)}`);
|
|
@@ -3504,7 +3520,9 @@ function buildAppendix(git, todos, docs, claims) {
|
|
|
3504
3520
|
} else {
|
|
3505
3521
|
out.push("Active claims: none");
|
|
3506
3522
|
}
|
|
3507
|
-
|
|
3523
|
+
const tail = extra.map((section2) => `
|
|
3524
|
+
${section2}`).join("");
|
|
3525
|
+
return `${truncateHead(out.join("\n"), MAX_APPENDIX_TOKENS - estimateTokens(tail))}${tail}`;
|
|
3508
3526
|
}
|
|
3509
3527
|
function captureHandoff(turn, clock, timeoutMs = HANDOFF_TIMEOUT_MS) {
|
|
3510
3528
|
return new Promise((resolve7) => {
|
|
@@ -10052,7 +10070,7 @@ var init_token_client = __esm({
|
|
|
10052
10070
|
"src/repos/token-client.ts"() {
|
|
10053
10071
|
"use strict";
|
|
10054
10072
|
init_src();
|
|
10055
|
-
TOKEN_SHAPE = /^[A-Za-z0-9_]{20,
|
|
10073
|
+
TOKEN_SHAPE = /^[A-Za-z0-9_.-]{20,}$/;
|
|
10056
10074
|
DEFAULT_TIMEOUT_MS = 9e4;
|
|
10057
10075
|
}
|
|
10058
10076
|
});
|
|
@@ -10335,6 +10353,49 @@ var init_attachments2 = __esm({
|
|
|
10335
10353
|
}
|
|
10336
10354
|
});
|
|
10337
10355
|
|
|
10356
|
+
// src/sessions/autopilot-runs.ts
|
|
10357
|
+
function autopilotRunsReader(db, log = logger) {
|
|
10358
|
+
const running = (sessionId, columns) => db.from("autopilot_runs").select(columns).eq("session_id", sessionId).eq("status", "running").maybeSingle();
|
|
10359
|
+
const failed6 = (sessionId, err) => {
|
|
10360
|
+
const e = err;
|
|
10361
|
+
log.warn({ sessionId, code: e?.code, err: e?.message }, "autopilot_runs read failed");
|
|
10362
|
+
};
|
|
10363
|
+
return {
|
|
10364
|
+
isAutopilotRunning: async (sessionId) => {
|
|
10365
|
+
try {
|
|
10366
|
+
const { data, error } = await running(sessionId, "id");
|
|
10367
|
+
if (error) throw error;
|
|
10368
|
+
return data !== null;
|
|
10369
|
+
} catch (err) {
|
|
10370
|
+
failed6(sessionId, err);
|
|
10371
|
+
return false;
|
|
10372
|
+
}
|
|
10373
|
+
},
|
|
10374
|
+
/** Null too for a run `ownerId`, the session's owner, did not start. */
|
|
10375
|
+
autopilotRun: async (sessionId, ownerId) => {
|
|
10376
|
+
try {
|
|
10377
|
+
const { data, error } = await running(sessionId, "objective, done_when, owner_id");
|
|
10378
|
+
if (error) throw error;
|
|
10379
|
+
if (!data || data.owner_id !== ownerId) return null;
|
|
10380
|
+
return {
|
|
10381
|
+
objective: data.objective,
|
|
10382
|
+
doneWhen: data.done_when,
|
|
10383
|
+
unmetDoneWhen: data.done_when
|
|
10384
|
+
};
|
|
10385
|
+
} catch (err) {
|
|
10386
|
+
failed6(sessionId, err);
|
|
10387
|
+
return null;
|
|
10388
|
+
}
|
|
10389
|
+
}
|
|
10390
|
+
};
|
|
10391
|
+
}
|
|
10392
|
+
var init_autopilot_runs = __esm({
|
|
10393
|
+
"src/sessions/autopilot-runs.ts"() {
|
|
10394
|
+
"use strict";
|
|
10395
|
+
init_log();
|
|
10396
|
+
}
|
|
10397
|
+
});
|
|
10398
|
+
|
|
10338
10399
|
// src/fs/list.ts
|
|
10339
10400
|
import { readdirSync as readdirSync3, realpathSync as realpathSync12, statSync as statSync7 } from "fs";
|
|
10340
10401
|
import { join as join22, relative as relative7, sep as sep10 } from "path";
|
|
@@ -10851,9 +10912,14 @@ var init_format = __esm({
|
|
|
10851
10912
|
});
|
|
10852
10913
|
|
|
10853
10914
|
// src/renewal/threshold.ts
|
|
10854
|
-
function renewThreshold(
|
|
10855
|
-
const {
|
|
10856
|
-
if (
|
|
10915
|
+
function renewThreshold(s) {
|
|
10916
|
+
const { window, workspaceThreshold } = s;
|
|
10917
|
+
if (window === null || !Number.isFinite(window) || window <= 0) return null;
|
|
10918
|
+
if (s.autopilot) {
|
|
10919
|
+
const t2 = Math.floor(AUTOPILOT_WINDOW_SHARE * window);
|
|
10920
|
+
return t2 > 0 ? t2 : null;
|
|
10921
|
+
}
|
|
10922
|
+
if (!Number.isFinite(workspaceThreshold)) return null;
|
|
10857
10923
|
const t = Math.min(Math.floor(workspaceThreshold), Math.floor(WINDOW_SHARE * window));
|
|
10858
10924
|
return t < MIN_RENEW_THRESHOLD ? null : t;
|
|
10859
10925
|
}
|
|
@@ -10873,12 +10939,13 @@ function autoCompactWindowFor(window) {
|
|
|
10873
10939
|
const above = Math.floor(WINDOW_SHARE * w) + AUTOCOMPACT_BUFFER + AUTOCOMPACT_MARGIN;
|
|
10874
10940
|
return Math.min(w, Math.max(Math.floor(0.9 * w), above));
|
|
10875
10941
|
}
|
|
10876
|
-
var MIN_RENEW_THRESHOLD, WINDOW_SHARE, KNOWN_CONTEXT_WINDOWS, AUTOCOMPACT_BUFFER, AUTOCOMPACT_MARGIN;
|
|
10942
|
+
var MIN_RENEW_THRESHOLD, WINDOW_SHARE, AUTOPILOT_WINDOW_SHARE, KNOWN_CONTEXT_WINDOWS, AUTOCOMPACT_BUFFER, AUTOCOMPACT_MARGIN;
|
|
10877
10943
|
var init_threshold = __esm({
|
|
10878
10944
|
"src/renewal/threshold.ts"() {
|
|
10879
10945
|
"use strict";
|
|
10880
10946
|
MIN_RENEW_THRESHOLD = 1e5;
|
|
10881
10947
|
WINDOW_SHARE = 0.75;
|
|
10948
|
+
AUTOPILOT_WINDOW_SHARE = 0.4;
|
|
10882
10949
|
KNOWN_CONTEXT_WINDOWS = {
|
|
10883
10950
|
"claude-opus-5-5": 1e6
|
|
10884
10951
|
};
|
|
@@ -10888,13 +10955,26 @@ var init_threshold = __esm({
|
|
|
10888
10955
|
});
|
|
10889
10956
|
|
|
10890
10957
|
// src/renewal/rotation.ts
|
|
10958
|
+
function memberContinuation(lastMemberPrompt, mode) {
|
|
10959
|
+
if (lastMemberPrompt === null) return null;
|
|
10960
|
+
return { text: continuationText(lastMemberPrompt), auto: AUTO_CONTINUE_MODES.has(mode) };
|
|
10961
|
+
}
|
|
10891
10962
|
function handoffBlock(segment, handoff) {
|
|
10892
|
-
const frame = (
|
|
10963
|
+
const frame = (body) => `${HANDOFF_PREAMBLE}
|
|
10893
10964
|
<handoff segment="${segment}">
|
|
10894
|
-
${
|
|
10965
|
+
${body}
|
|
10895
10966
|
</handoff>`;
|
|
10896
|
-
const
|
|
10897
|
-
|
|
10967
|
+
const max = HANDOFF_MAX_TOKENS - estimateTokens(frame(""));
|
|
10968
|
+
const text3 = escapeAngles(handoff);
|
|
10969
|
+
const at = text3.lastIndexOf(`
|
|
10970
|
+
|
|
10971
|
+
${APPENDIX_HEADING}
|
|
10972
|
+
`);
|
|
10973
|
+
const appendix = at < 0 ? "" : text3.slice(at);
|
|
10974
|
+
if (at < 0 || estimateTokens(appendix) > 2 * MAX_APPENDIX_TOKENS) {
|
|
10975
|
+
return frame(truncateHead(text3, max));
|
|
10976
|
+
}
|
|
10977
|
+
return frame(`${truncateHead(text3.slice(0, at), max - estimateTokens(appendix))}${appendix}`);
|
|
10898
10978
|
}
|
|
10899
10979
|
function continuationText(lastMemberPrompt) {
|
|
10900
10980
|
const quoted3 = lastMemberPrompt.replace(/[«»]/g, '"');
|
|
@@ -10911,12 +10991,12 @@ function buildFirstInput(args) {
|
|
|
10911
10991
|
${args.queuedPrompt}`, send: "now" };
|
|
10912
10992
|
}
|
|
10913
10993
|
if (args.queuedPrompt !== null) return { text: block, send: "withNextPrompt" };
|
|
10914
|
-
if (args.endedOnNudge && args.
|
|
10994
|
+
if (args.endedOnNudge && args.continuation !== null) {
|
|
10915
10995
|
return {
|
|
10916
10996
|
text: `${block}
|
|
10917
10997
|
|
|
10918
|
-
${
|
|
10919
|
-
send:
|
|
10998
|
+
${args.continuation.text}`,
|
|
10999
|
+
send: args.continuation.auto ? "now" : "continue"
|
|
10920
11000
|
};
|
|
10921
11001
|
}
|
|
10922
11002
|
return { text: block, send: "withNextPrompt" };
|
|
@@ -10946,6 +11026,8 @@ var init_rotation = __esm({
|
|
|
10946
11026
|
cost = 0;
|
|
10947
11027
|
handoff = null;
|
|
10948
11028
|
reason = "renewal";
|
|
11029
|
+
why = "threshold";
|
|
11030
|
+
plainRetry = false;
|
|
10949
11031
|
/** Why a pending `requestRenew` was made: `manual` unless the runner asked for itself. */
|
|
10950
11032
|
requested = "manual";
|
|
10951
11033
|
constructor(options) {
|
|
@@ -10962,6 +11044,27 @@ var init_rotation = __esm({
|
|
|
10962
11044
|
get enabled() {
|
|
10963
11045
|
return this.threshold !== null;
|
|
10964
11046
|
}
|
|
11047
|
+
/**
|
|
11048
|
+
* What decided the current (or last) renewal. A plain retry after a failure keeps it; a
|
|
11049
|
+
* `requestRenew` that is due at that turn end names its own.
|
|
11050
|
+
*/
|
|
11051
|
+
get cause() {
|
|
11052
|
+
return this.why;
|
|
11053
|
+
}
|
|
11054
|
+
/** The current renewal is the one retry of a failed one, not asked for again (`cause` kept). */
|
|
11055
|
+
get retrying() {
|
|
11056
|
+
return this.plainRetry;
|
|
11057
|
+
}
|
|
11058
|
+
/**
|
|
11059
|
+
* The threshold changed between turns (an Auto Pilot run started or stopped, Auto Pilot 03).
|
|
11060
|
+
* The next `midTurn` and `turnEnd` go by it, except while `nudged`: the threshold that nudged
|
|
11061
|
+
* stays until that turn end renews, since the model was already told the chat will. Returns
|
|
11062
|
+
* the threshold in effect.
|
|
11063
|
+
*/
|
|
11064
|
+
setThreshold(threshold) {
|
|
11065
|
+
if (this.current !== "nudged") this.threshold = threshold;
|
|
11066
|
+
return this.threshold;
|
|
11067
|
+
}
|
|
10965
11068
|
/** The mode changed (a `setMode` update or a mode command): the continuation follows it. */
|
|
10966
11069
|
setMode(mode) {
|
|
10967
11070
|
this.mode = mode;
|
|
@@ -11014,11 +11117,17 @@ var init_rotation = __esm({
|
|
|
11014
11117
|
due = this.manual || this.current === "nudged" || input.tokens >= this.threshold;
|
|
11015
11118
|
}
|
|
11016
11119
|
if (!due) return [];
|
|
11120
|
+
this.plainRetry = this.current === "failed" && !this.manual;
|
|
11017
11121
|
if (this.current === "failed") {
|
|
11018
11122
|
this.retryArmed = false;
|
|
11123
|
+
if (this.manual) {
|
|
11124
|
+
this.reason = this.requested;
|
|
11125
|
+
this.why = this.requested === "manual" ? "manual" : "visibility";
|
|
11126
|
+
}
|
|
11019
11127
|
} else {
|
|
11020
11128
|
this.endedOnNudge = this.current === "nudged";
|
|
11021
11129
|
this.reason = this.manual ? this.requested : "renewal";
|
|
11130
|
+
this.why = !this.manual ? "threshold" : this.requested === "manual" ? "manual" : "visibility";
|
|
11022
11131
|
}
|
|
11023
11132
|
this.manual = false;
|
|
11024
11133
|
this.current = "handoff";
|
|
@@ -11068,9 +11177,8 @@ var init_rotation = __esm({
|
|
|
11068
11177
|
segment: n,
|
|
11069
11178
|
handoff: this.handoff.text,
|
|
11070
11179
|
queuedPrompt: input.queuedPrompt,
|
|
11071
|
-
|
|
11072
|
-
endedOnNudge: this.endedOnNudge
|
|
11073
|
-
mode: this.mode
|
|
11180
|
+
continuation: input.autopilotContinuation ? { text: input.autopilotContinuation, auto: true } : memberContinuation(input.lastMemberPrompt, this.mode),
|
|
11181
|
+
endedOnNudge: this.endedOnNudge
|
|
11074
11182
|
});
|
|
11075
11183
|
const actions = [
|
|
11076
11184
|
{
|
|
@@ -12363,7 +12471,7 @@ function asInterrupted(row) {
|
|
|
12363
12471
|
)
|
|
12364
12472
|
};
|
|
12365
12473
|
}
|
|
12366
|
-
var SESSION_FLAG_SETTINGS, SESSION_ASK_TOOLS, GUARD_FAILED, WRITE_TOOLS_MATCHER, CONTEXT_HOOK_TIMEOUT_MS, ASK_TOOL_REASON, CAYENNE_CHECK_MS, CAYENNE_CHECK_POLL_MS, CAYENNE_UNCONFIRMED, TOOL_FAILED, toResult, INTERRUPTED, STOPPED_TURN, ClaudeSession;
|
|
12474
|
+
var SESSION_FLAG_SETTINGS, SESSION_ASK_TOOLS, GUARD_FAILED, WRITE_TOOLS_MATCHER, CONTEXT_HOOK_TIMEOUT_MS, ASK_TOOL_REASON, CAYENNE_CHECK_MS, CAYENNE_CHECK_POLL_MS, CAYENNE_UNLISTED_POLL_MS, CAYENNE_UNCONFIRMED, TOOL_FAILED, toResult, INTERRUPTED, STOPPED_TURN, ClaudeSession;
|
|
12367
12475
|
var init_session2 = __esm({
|
|
12368
12476
|
"src/claude/session.ts"() {
|
|
12369
12477
|
"use strict";
|
|
@@ -12386,6 +12494,7 @@ var init_session2 = __esm({
|
|
|
12386
12494
|
ASK_TOOL_REASON = "This session was started from a task, so every shell command needs the member's approval.";
|
|
12387
12495
|
CAYENNE_CHECK_MS = 1e4;
|
|
12388
12496
|
CAYENNE_CHECK_POLL_MS = 100;
|
|
12497
|
+
CAYENNE_UNLISTED_POLL_MS = 1e3;
|
|
12389
12498
|
CAYENNE_UNCONFIRMED = "Refused: the cayenne MCP server is not confirmed as the runner\u2019s own.";
|
|
12390
12499
|
TOOL_FAILED = "Cayenne could not answer this call.";
|
|
12391
12500
|
toResult = (a) => ({
|
|
@@ -12665,15 +12774,21 @@ var init_session2 = __esm({
|
|
|
12665
12774
|
*
|
|
12666
12775
|
* Any other answer stops the session. A `cayenne` with another `serverInfo` or config type is a
|
|
12667
12776
|
* foreign server (`CAYENNE_NAME_TAKEN`); one never confirmed (connected without `serverInfo`, a
|
|
12668
|
-
* status other than `pending`, still pending
|
|
12669
|
-
*
|
|
12670
|
-
*
|
|
12777
|
+
* status other than `pending`, still pending at the deadline, a status call that fails) ends with
|
|
12778
|
+
* `CAYENNE_UNCONFIRMED_EXIT`, the reason logged at warn. Until confirmed, `canUseTool` refuses
|
|
12779
|
+
* every `cayenne` tool. A session already stopping or ended is left alone.
|
|
12780
|
+
*
|
|
12781
|
+
* An unlisted `cayenne` is waited for, not stopped: the CLI answers `[]` before it registers its
|
|
12782
|
+
* MCP servers, and on a slow network that took longer than the window (three chats killed
|
|
12783
|
+
* 2026-10-21/22). Nothing answers under the name meanwhile, so no tool of it can be called.
|
|
12671
12784
|
*/
|
|
12672
12785
|
async confirmCayenne(q) {
|
|
12673
12786
|
let deadline;
|
|
12787
|
+
let unlistedSince;
|
|
12788
|
+
let unlistedWarned = false;
|
|
12789
|
+
const warn = this.opts.log?.warn ?? ((obj, m) => logger.warn(obj, m));
|
|
12674
12790
|
const end = (fatal, fields, msg) => {
|
|
12675
12791
|
if (this.ending) return false;
|
|
12676
|
-
const warn = this.opts.log?.warn ?? ((obj, m) => logger.warn(obj, m));
|
|
12677
12792
|
warn({ providerSessionId: this.providerSessionId, ...fields }, msg);
|
|
12678
12793
|
this.fatal = fatal;
|
|
12679
12794
|
void this.stop();
|
|
@@ -12688,21 +12803,33 @@ var init_session2 = __esm({
|
|
|
12688
12803
|
for (; ; ) {
|
|
12689
12804
|
if (this.ending) return false;
|
|
12690
12805
|
const statuses = await q.mcpServerStatus();
|
|
12691
|
-
deadline ??= Date.now() + CAYENNE_CHECK_MS;
|
|
12692
12806
|
const entry = statuses.find((s) => s.name === CAYENNE_SERVER);
|
|
12693
|
-
|
|
12694
|
-
|
|
12807
|
+
if (!entry) {
|
|
12808
|
+
unlistedSince ??= Date.now();
|
|
12809
|
+
if (!unlistedWarned && Date.now() - unlistedSince >= CAYENNE_CHECK_MS) {
|
|
12810
|
+
unlistedWarned = true;
|
|
12811
|
+
warn(
|
|
12812
|
+
{ providerSessionId: this.providerSessionId },
|
|
12813
|
+
"cayenne MCP server not listed yet; its tools stay refused until it is"
|
|
12814
|
+
);
|
|
12815
|
+
}
|
|
12816
|
+
await new Promise((r) => setTimeout(r, CAYENNE_UNLISTED_POLL_MS));
|
|
12817
|
+
continue;
|
|
12818
|
+
}
|
|
12819
|
+
deadline ??= Date.now() + CAYENNE_CHECK_MS;
|
|
12820
|
+
const config2 = entry.config;
|
|
12821
|
+
const info = entry.serverInfo;
|
|
12695
12822
|
if (config2 !== void 0 && config2.type !== "sdk" || info !== void 0 && (info.name !== CAYENNE_SERVER || info.version !== this.cayenneVersion)) {
|
|
12696
|
-
return end(CAYENNE_NAME_TAKEN, { scope: entry
|
|
12823
|
+
return end(CAYENNE_NAME_TAKEN, { scope: entry.scope }, CAYENNE_NAME_TAKEN);
|
|
12697
12824
|
}
|
|
12698
|
-
if (entry
|
|
12825
|
+
if (entry.status === "connected") {
|
|
12699
12826
|
return info !== void 0 || unconfirmed("connected without serverInfo", entry.scope);
|
|
12700
12827
|
}
|
|
12701
|
-
if (entry
|
|
12828
|
+
if (entry.status !== "pending") {
|
|
12702
12829
|
return unconfirmed(`status ${entry.status}`, entry.scope);
|
|
12703
12830
|
}
|
|
12704
12831
|
if (Date.now() >= deadline) {
|
|
12705
|
-
return unconfirmed(
|
|
12832
|
+
return unconfirmed("still pending", entry.scope);
|
|
12706
12833
|
}
|
|
12707
12834
|
await new Promise((r) => setTimeout(r, CAYENNE_CHECK_POLL_MS));
|
|
12708
12835
|
}
|
|
@@ -14889,6 +15016,50 @@ var init_materialise = __esm({
|
|
|
14889
15016
|
}
|
|
14890
15017
|
});
|
|
14891
15018
|
|
|
15019
|
+
// src/sessions/autopilot-renewal.ts
|
|
15020
|
+
function autopilotAppendix(run) {
|
|
15021
|
+
const met = run.doneWhen.length - run.unmetDoneWhen.length;
|
|
15022
|
+
const out = [
|
|
15023
|
+
AUTOPILOT_HEADING,
|
|
15024
|
+
`Objective: ${field(run.objective, CAP_OBJECTIVE)}`,
|
|
15025
|
+
`Done-when items met: ${Math.max(0, met)} of ${run.doneWhen.length}`
|
|
15026
|
+
];
|
|
15027
|
+
if (run.unmetDoneWhen.length) {
|
|
15028
|
+
out.push("Done when (not yet met):");
|
|
15029
|
+
for (const item of run.unmetDoneWhen) out.push(`- ${field(item, CAP_ITEM)}`);
|
|
15030
|
+
} else {
|
|
15031
|
+
out.push("Done when (not yet met): none");
|
|
15032
|
+
}
|
|
15033
|
+
const text3 = out.join("\n");
|
|
15034
|
+
if (text3.length <= MAX_AUTOPILOT_APPENDIX) return text3;
|
|
15035
|
+
const head = text3.slice(0, MAX_AUTOPILOT_APPENDIX - 2);
|
|
15036
|
+
return `${head.slice(0, head.lastIndexOf("\n"))}
|
|
15037
|
+
\u2026`;
|
|
15038
|
+
}
|
|
15039
|
+
function autopilotContinuation(run) {
|
|
15040
|
+
let clean3 = run.objective.replace(CONTROL, " ").replace(/\s+/g, " ").trim().replace(/[«»]/g, '"');
|
|
15041
|
+
if (clean3.length > CAP_OBJECTIVE) clean3 = `${clean3.slice(0, CAP_OBJECTIVE - 1)}\u2026`;
|
|
15042
|
+
const quoted3 = escapeAngles(clean3);
|
|
15043
|
+
return `Continue toward the objective the member set for Auto Pilot: \xAB${quoted3}\xBB. The handoff above is reference.`;
|
|
15044
|
+
}
|
|
15045
|
+
function renewalReason(p) {
|
|
15046
|
+
if (p.manual) return "manual";
|
|
15047
|
+
if (p.visibility) return "visibility";
|
|
15048
|
+
if (p.compacted) return "compaction";
|
|
15049
|
+
return p.autopilot ? "autopilot_threshold" : "threshold";
|
|
15050
|
+
}
|
|
15051
|
+
var AUTOPILOT_HEADING, MAX_AUTOPILOT_APPENDIX, CAP_OBJECTIVE, CAP_ITEM;
|
|
15052
|
+
var init_autopilot_renewal = __esm({
|
|
15053
|
+
"src/sessions/autopilot-renewal.ts"() {
|
|
15054
|
+
"use strict";
|
|
15055
|
+
init_handoff();
|
|
15056
|
+
AUTOPILOT_HEADING = "## Auto Pilot";
|
|
15057
|
+
MAX_AUTOPILOT_APPENDIX = 2400;
|
|
15058
|
+
CAP_OBJECTIVE = 800;
|
|
15059
|
+
CAP_ITEM = 240;
|
|
15060
|
+
}
|
|
15061
|
+
});
|
|
15062
|
+
|
|
14892
15063
|
// src/sessions/managed-git-guard.ts
|
|
14893
15064
|
import { realpathSync as realpathSync15 } from "fs";
|
|
14894
15065
|
import { isAbsolute as isAbsolute18, relative as relative11, resolve as resolve4, sep as sep15 } from "path";
|
|
@@ -15665,6 +15836,7 @@ var init_manager = __esm({
|
|
|
15665
15836
|
init_registry();
|
|
15666
15837
|
init_materialise();
|
|
15667
15838
|
init_attachments2();
|
|
15839
|
+
init_autopilot_renewal();
|
|
15668
15840
|
init_managed_git_guard();
|
|
15669
15841
|
init_relay();
|
|
15670
15842
|
init_repo_settings();
|
|
@@ -15729,6 +15901,8 @@ var init_manager = __esm({
|
|
|
15729
15901
|
pendingBlock: null,
|
|
15730
15902
|
manualPending: false,
|
|
15731
15903
|
lastPrompt: null,
|
|
15904
|
+
autopilot: false,
|
|
15905
|
+
cause: null,
|
|
15732
15906
|
todos: null
|
|
15733
15907
|
});
|
|
15734
15908
|
scopeOf2 = (v) => v === "private" || v === "workspace" ? v : null;
|
|
@@ -15885,7 +16059,9 @@ var init_manager = __esm({
|
|
|
15885
16059
|
try {
|
|
15886
16060
|
this.assertNotRemoving(cwd);
|
|
15887
16061
|
} catch (err) {
|
|
15888
|
-
|
|
16062
|
+
const failure2 = this.giveBack(repo?.creds, err);
|
|
16063
|
+
await this.recordStartFailure(sessionId);
|
|
16064
|
+
throw failure2;
|
|
15889
16065
|
}
|
|
15890
16066
|
const started = this.markStarting(cwd, sessionId);
|
|
15891
16067
|
const introspect = this.deps.introspect ?? ((dir, at) => introspectRepo(
|
|
@@ -15939,7 +16115,9 @@ var init_manager = __esm({
|
|
|
15939
16115
|
);
|
|
15940
16116
|
} catch (err) {
|
|
15941
16117
|
this.discardSkills(sessionId);
|
|
15942
|
-
|
|
16118
|
+
const failure2 = this.giveBack(repo?.creds, err);
|
|
16119
|
+
await this.recordStartFailure(sessionId);
|
|
16120
|
+
throw failure2;
|
|
15943
16121
|
} finally {
|
|
15944
16122
|
started();
|
|
15945
16123
|
}
|
|
@@ -16109,9 +16287,18 @@ var init_manager = __esm({
|
|
|
16109
16287
|
repo: { ownerId, repositoryId: repository.id, creds }
|
|
16110
16288
|
};
|
|
16111
16289
|
} catch (err) {
|
|
16112
|
-
|
|
16290
|
+
const failure2 = this.giveBack(creds, err);
|
|
16291
|
+
await this.recordStartFailure(sessionId);
|
|
16292
|
+
throw failure2;
|
|
16113
16293
|
}
|
|
16114
16294
|
}
|
|
16295
|
+
/** A failed first start has no live channel; persist its status without ending a live retry. */
|
|
16296
|
+
async recordStartFailure(sessionId) {
|
|
16297
|
+
if (this.live.has(sessionId)) return;
|
|
16298
|
+
await this.updateSession(sessionId, { status: "error" }).catch(
|
|
16299
|
+
(err) => this.deps.log.warn({ err, sessionId }, "failed startup status could not be recorded")
|
|
16300
|
+
);
|
|
16301
|
+
}
|
|
16115
16302
|
/**
|
|
16116
16303
|
* A repository chat's recorded worktree, proven as a resume needs it (§2.9): this runner's record,
|
|
16117
16304
|
* still the same worktree, shaped `<root>/<owner>/<name>/.cayenne/worktrees/chat-<hex>` for this
|
|
@@ -16943,14 +17130,19 @@ var init_manager = __esm({
|
|
|
16943
17130
|
* turns. Returns `{ scheduled: true }` at once and never waits for the renewal, so a
|
|
16944
17131
|
* `session.permission.respond` or `session.interrupt` queued behind it in the session lane runs
|
|
16945
17132
|
* while the renewal waits for the turn to end (§2.1). Progress goes out as `renewal` events.
|
|
16946
|
-
* Refused when
|
|
16947
|
-
* renewed (Codex: no hook can deny the handoff turn's tools; a backend
|
|
17133
|
+
* Refused when no threshold applies (below 100,000 tokens outside an Auto Pilot run), and for a
|
|
17134
|
+
* session that cannot be renewed (Codex: no hook can deny the handoff turn's tools; a backend
|
|
17135
|
+
* without 0042).
|
|
16948
17136
|
*/
|
|
16949
17137
|
async requestRenewal(sessionId, createdBy) {
|
|
16950
17138
|
const live = await this.ensureLive(sessionId, createdBy);
|
|
16951
17139
|
this.assertCodexOwner(sessionId, createdBy);
|
|
16952
17140
|
const r = live.renewal;
|
|
16953
17141
|
if (!this.renewable(live)) throw new Error(RENEWAL_NOT_AVAILABLE);
|
|
17142
|
+
if (r.machine && r.window !== null && !r.busy) {
|
|
17143
|
+
r.autopilot = await this.autopilotRunning(sessionId);
|
|
17144
|
+
await this.ensureMachine(sessionId, live, r.window);
|
|
17145
|
+
}
|
|
16954
17146
|
const machine = r.machine;
|
|
16955
17147
|
if (machine && !machine.enabled) throw new Error(RENEWAL_NOT_AVAILABLE);
|
|
16956
17148
|
if (r.busy) return { scheduled: true };
|
|
@@ -19275,8 +19467,9 @@ var init_manager = __esm({
|
|
|
19275
19467
|
* failed turn, a pending permission), so they are never left waiting for a turn that won't come.
|
|
19276
19468
|
*/
|
|
19277
19469
|
async turnEndRenewal(sessionId, live, r) {
|
|
19278
|
-
const usage = await this.measure(sessionId, live);
|
|
19279
19470
|
const rn = live.renewal;
|
|
19471
|
+
if (this.renewable(live)) rn.autopilot = await this.autopilotRunning(sessionId);
|
|
19472
|
+
const usage = await this.measure(sessionId, live);
|
|
19280
19473
|
await this.noteScope(sessionId, live);
|
|
19281
19474
|
if (rn.busy || live.stopping || live.dropping) return [];
|
|
19282
19475
|
if (live.turns.owed > 0) return [];
|
|
@@ -19442,10 +19635,14 @@ var init_manager = __esm({
|
|
|
19442
19635
|
async ensureMachine(sessionId, live, window) {
|
|
19443
19636
|
const rn = live.renewal;
|
|
19444
19637
|
if (rn.segment === null) return;
|
|
19445
|
-
if (rn.machine && (rn.window === window || rn.machine.state !== "idle")) return;
|
|
19446
19638
|
rn.workspaceThreshold ??= await this.workspaceThreshold();
|
|
19639
|
+
const subject = { autopilot: rn.autopilot, workspaceThreshold: rn.workspaceThreshold };
|
|
19640
|
+
if (rn.machine && rn.window !== null && (rn.window === window || rn.machine.state !== "idle")) {
|
|
19641
|
+
rn.threshold = rn.machine.setThreshold(renewThreshold({ ...subject, window: rn.window }));
|
|
19642
|
+
return;
|
|
19643
|
+
}
|
|
19447
19644
|
rn.window = window;
|
|
19448
|
-
rn.threshold = renewThreshold({
|
|
19645
|
+
rn.threshold = renewThreshold({ ...subject, window });
|
|
19449
19646
|
rn.machine = new RenewalMachine({
|
|
19450
19647
|
segment: rn.segment,
|
|
19451
19648
|
threshold: rn.threshold,
|
|
@@ -19458,15 +19655,55 @@ var init_manager = __esm({
|
|
|
19458
19655
|
if (rn.machine.enabled) {
|
|
19459
19656
|
rn.machine.requestRenew("manual");
|
|
19460
19657
|
} else {
|
|
19461
|
-
await this.renewalEvent(
|
|
19462
|
-
|
|
19463
|
-
phase: "failed",
|
|
19464
|
-
|
|
19465
|
-
|
|
19466
|
-
});
|
|
19658
|
+
await this.renewalEvent(
|
|
19659
|
+
sessionId,
|
|
19660
|
+
{ kind: "event", phase: "failed", segment: rn.segment, error: RENEWAL_NOT_AVAILABLE },
|
|
19661
|
+
"manual"
|
|
19662
|
+
);
|
|
19467
19663
|
}
|
|
19468
19664
|
}
|
|
19469
19665
|
}
|
|
19666
|
+
/**
|
|
19667
|
+
* `ManagerDeps.isAutopilotRunning`; false when absent, when it rejects (logged), and when the
|
|
19668
|
+
* runner no longer serves the session's owner: a run's continuation is a turn no command is
|
|
19669
|
+
* behind, so it must not outlive the owner's place on the roster.
|
|
19670
|
+
*/
|
|
19671
|
+
async autopilotRunning(sessionId) {
|
|
19672
|
+
const ask2 = this.deps.isAutopilotRunning;
|
|
19673
|
+
if (!ask2) return false;
|
|
19674
|
+
try {
|
|
19675
|
+
return await ask2(sessionId) === true && await this.servedOwner(sessionId) !== null;
|
|
19676
|
+
} catch (err) {
|
|
19677
|
+
this.deps.log.warn(
|
|
19678
|
+
{ sessionId, err: err instanceof Error ? err.message : String(err) },
|
|
19679
|
+
"reading the Auto Pilot run failed; renewing as without one"
|
|
19680
|
+
);
|
|
19681
|
+
return false;
|
|
19682
|
+
}
|
|
19683
|
+
}
|
|
19684
|
+
/**
|
|
19685
|
+
* `ManagerDeps.autopilotRun`; null when absent, and when it rejects (logged with the error only,
|
|
19686
|
+
* never the run's text).
|
|
19687
|
+
*/
|
|
19688
|
+
async autopilotBrief(sessionId) {
|
|
19689
|
+
const read2 = this.deps.autopilotRun;
|
|
19690
|
+
if (!read2) return null;
|
|
19691
|
+
try {
|
|
19692
|
+
const owner2 = await this.servedOwner(sessionId);
|
|
19693
|
+
return owner2 === null ? null : await read2(sessionId, owner2);
|
|
19694
|
+
} catch (err) {
|
|
19695
|
+
this.deps.log.warn(
|
|
19696
|
+
{ sessionId, err: err instanceof Error ? err.message : String(err) },
|
|
19697
|
+
"reading the Auto Pilot run failed; renewing as without one"
|
|
19698
|
+
);
|
|
19699
|
+
return null;
|
|
19700
|
+
}
|
|
19701
|
+
}
|
|
19702
|
+
/** The session's owner while this runner serves them, else null. Throws when unreadable. */
|
|
19703
|
+
async servedOwner(sessionId) {
|
|
19704
|
+
const owner2 = await this.sessionOwner(sessionId);
|
|
19705
|
+
return this.serves(owner2) ? owner2 : null;
|
|
19706
|
+
}
|
|
19470
19707
|
/** `workspace_settings.renewal_threshold_tokens`; the column default when it cannot be read. */
|
|
19471
19708
|
async workspaceThreshold() {
|
|
19472
19709
|
const { data, error } = await this.deps.db.from("workspace_settings").select("renewal_threshold_tokens").eq("workspace_id", this.deps.workspaceId).maybeSingle();
|
|
@@ -19500,15 +19737,37 @@ var init_manager = __esm({
|
|
|
19500
19737
|
rn.busy = true;
|
|
19501
19738
|
try {
|
|
19502
19739
|
if (!machine || n === null) return;
|
|
19740
|
+
if (!machine.retrying || !rn.cause) {
|
|
19741
|
+
const cause = machine.cause;
|
|
19742
|
+
rn.cause = {
|
|
19743
|
+
autopilot: rn.autopilot,
|
|
19744
|
+
reason: renewalReason({
|
|
19745
|
+
autopilot: rn.autopilot,
|
|
19746
|
+
manual: cause === "manual",
|
|
19747
|
+
visibility: cause === "visibility",
|
|
19748
|
+
compacted: false
|
|
19749
|
+
})
|
|
19750
|
+
};
|
|
19751
|
+
}
|
|
19752
|
+
const reason = rn.cause.reason;
|
|
19503
19753
|
let prompt = null;
|
|
19504
19754
|
for (const a of start2) {
|
|
19505
|
-
if (a.kind === "event") await this.renewalEvent(sessionId, a);
|
|
19755
|
+
if (a.kind === "event") await this.renewalEvent(sessionId, a, reason);
|
|
19506
19756
|
else if (a.kind === "runHandoffTurn") prompt = a.prompt;
|
|
19507
19757
|
}
|
|
19508
19758
|
if (prompt === null) return;
|
|
19509
19759
|
const result = await this.runHandoffTurn(live, prompt);
|
|
19510
19760
|
if (gone2()) return;
|
|
19511
|
-
const
|
|
19761
|
+
const autopilot = rn.cause.autopilot;
|
|
19762
|
+
let run = autopilot ? await this.autopilotBrief(sessionId) : null;
|
|
19763
|
+
if (gone2()) return;
|
|
19764
|
+
const handoff = await this.handoffFor(
|
|
19765
|
+
sessionId,
|
|
19766
|
+
live,
|
|
19767
|
+
n,
|
|
19768
|
+
result,
|
|
19769
|
+
run ? [autopilotAppendix(run)] : []
|
|
19770
|
+
);
|
|
19512
19771
|
try {
|
|
19513
19772
|
for (const a of machine.handoffCaptured(handoff)) {
|
|
19514
19773
|
if (a.kind === "saveHandoff") {
|
|
@@ -19518,7 +19777,7 @@ var init_manager = __esm({
|
|
|
19518
19777
|
() => this.deps.db.from("chat_segments").update({ handoff: a.handoff, handoff_source: a.handoffSource }).eq("session_id", sessionId).eq("idx", a.segment)
|
|
19519
19778
|
);
|
|
19520
19779
|
} else if (a.kind === "event") {
|
|
19521
|
-
await this.renewalEvent(sessionId, a);
|
|
19780
|
+
await this.renewalEvent(sessionId, a, reason);
|
|
19522
19781
|
} else if (a.kind === "startQuery") {
|
|
19523
19782
|
next = await this.startRenewedQuery(sessionId, live);
|
|
19524
19783
|
}
|
|
@@ -19527,10 +19786,13 @@ var init_manager = __esm({
|
|
|
19527
19786
|
const providerSessionId = next?.providerSessionId;
|
|
19528
19787
|
if (!next || !providerSessionId) throw new Error("the new query has no session id");
|
|
19529
19788
|
const first = rn.queued[0] ?? null;
|
|
19789
|
+
if (run && !first && !await this.autopilotRunning(sessionId)) run = null;
|
|
19790
|
+
if (gone2()) return;
|
|
19530
19791
|
const actions = machine.queryStarted({
|
|
19531
19792
|
providerSessionId,
|
|
19532
19793
|
queuedPrompt: first?.text ?? null,
|
|
19533
|
-
lastMemberPrompt: rn.lastPrompt
|
|
19794
|
+
lastMemberPrompt: autopilot ? null : rn.lastPrompt,
|
|
19795
|
+
autopilotContinuation: run ? this.secrets.redact(autopilotContinuation(run)) : null
|
|
19534
19796
|
});
|
|
19535
19797
|
await this.rotateSegment(sessionId, live, n, handoff.text, actions, next, first);
|
|
19536
19798
|
} catch (err) {
|
|
@@ -19598,12 +19860,12 @@ var init_manager = __esm({
|
|
|
19598
19860
|
* before the memory pipeline) or the segment's last messages; plus the deterministic appendix.
|
|
19599
19861
|
* Scrubbed (D50) before it is stored and before it becomes segment `n + 1`'s first input.
|
|
19600
19862
|
*/
|
|
19601
|
-
async handoffFor(sessionId, live, n, result) {
|
|
19863
|
+
async handoffFor(sessionId, live, n, result, extra = []) {
|
|
19602
19864
|
const fromModel = result.kind === "ok" && estimateTokens(result.text.trim()) >= MIN_HANDOFF_TOKENS;
|
|
19603
19865
|
const messages = fromModel ? [] : await this.segmentMessages(sessionId, n);
|
|
19604
19866
|
const ceiling = live.roots.find((root) => isAtOrBelow3(live.cwd, root)) ?? live.cwd;
|
|
19605
19867
|
const git = await this.appendixGitState(live.cwd, ceiling).catch(() => null);
|
|
19606
|
-
const appendix = buildAppendix(git, live.renewal.todos, [], []);
|
|
19868
|
+
const appendix = buildAppendix(git, live.renewal.todos, [], [], extra);
|
|
19607
19869
|
const handoff = resolveHandoff({ result, digest: null, messages, appendix });
|
|
19608
19870
|
return { ...handoff, text: this.secrets.redact(handoff.text) };
|
|
19609
19871
|
}
|
|
@@ -19751,7 +20013,8 @@ var init_manager = __esm({
|
|
|
19751
20013
|
case "event":
|
|
19752
20014
|
await this.renewalEvent(
|
|
19753
20015
|
sessionId,
|
|
19754
|
-
a.phase === "done" ? { ...a, toTokens: await this.firstReading(next) } : a
|
|
20016
|
+
a.phase === "done" ? { ...a, toTokens: await this.firstReading(next) } : a,
|
|
20017
|
+
live.renewal.cause?.reason
|
|
19755
20018
|
);
|
|
19756
20019
|
break;
|
|
19757
20020
|
default:
|
|
@@ -20025,7 +20288,8 @@ ${text3}`;
|
|
|
20025
20288
|
if (machine.state !== "failed" && live.renewal.machine === machine) live.renewal.machine = null;
|
|
20026
20289
|
for (const a of actions) {
|
|
20027
20290
|
if (a.kind === "clearHandoff") await this.clearHandoff(sessionId, a.segment);
|
|
20028
|
-
else if (a.kind === "event")
|
|
20291
|
+
else if (a.kind === "event")
|
|
20292
|
+
await this.renewalEvent(sessionId, a, live.renewal.cause?.reason);
|
|
20029
20293
|
}
|
|
20030
20294
|
if (live.renewal.scopeRenewalOwed && live.renewal.queued.length > 0) {
|
|
20031
20295
|
try {
|
|
@@ -20076,16 +20340,23 @@ ${text3}`;
|
|
|
20076
20340
|
throw new Error(`PROVIDER_ERROR: ${what} failed: ${error.message}`);
|
|
20077
20341
|
}
|
|
20078
20342
|
}
|
|
20079
|
-
/**
|
|
20080
|
-
|
|
20343
|
+
/**
|
|
20344
|
+
* A machine `event` action as a `renewal` session event (protocol §3), carrying the renewal's
|
|
20345
|
+
* `reason` when it is known; `done` is followed by one `session.renewed` naming it.
|
|
20346
|
+
*/
|
|
20347
|
+
async renewalEvent(sessionId, a, reason) {
|
|
20081
20348
|
await this.broadcast(sessionId, {
|
|
20082
20349
|
type: "renewal",
|
|
20083
20350
|
phase: a.phase,
|
|
20084
20351
|
segment: a.segment,
|
|
20085
20352
|
...a.fromTokens === void 0 ? {} : { fromTokens: a.fromTokens },
|
|
20086
20353
|
...a.toTokens === void 0 ? {} : { toTokens: a.toTokens },
|
|
20087
|
-
...a.error === void 0 ? {} : { error: this.cap(a.error) }
|
|
20354
|
+
...a.error === void 0 ? {} : { error: this.cap(a.error) },
|
|
20355
|
+
...reason === void 0 ? {} : { reason }
|
|
20088
20356
|
});
|
|
20357
|
+
if (a.phase === "done" && reason !== void 0) {
|
|
20358
|
+
await this.broadcast(sessionId, { type: "session.renewed", segment: a.segment, reason });
|
|
20359
|
+
}
|
|
20089
20360
|
}
|
|
20090
20361
|
/**
|
|
20091
20362
|
* Expire a request the session settled itself, and say so when this write is what settled the
|
|
@@ -22404,7 +22675,9 @@ async function compose(cfg, lock, host, preflight) {
|
|
|
22404
22675
|
publishWrites: makePublishWrites(db),
|
|
22405
22676
|
poll: prPoll,
|
|
22406
22677
|
gh: runGh
|
|
22407
|
-
}
|
|
22678
|
+
},
|
|
22679
|
+
// Auto Pilot 03: an active run renews at 40% of the window and continues on its own.
|
|
22680
|
+
...autopilotRunsReader(db, logger)
|
|
22408
22681
|
});
|
|
22409
22682
|
let ownerServed = liveRoster.serves(identity.userId);
|
|
22410
22683
|
let ownerTransition = Promise.resolve();
|
|
@@ -22794,6 +23067,7 @@ var init_start = __esm({
|
|
|
22794
23067
|
init_roster();
|
|
22795
23068
|
init_registry();
|
|
22796
23069
|
init_attachments2();
|
|
23070
|
+
init_autopilot_runs();
|
|
22797
23071
|
init_handlers();
|
|
22798
23072
|
init_manager();
|
|
22799
23073
|
init_repo_sessions();
|
|
@@ -23163,7 +23437,9 @@ var isInside = (dir, path) => {
|
|
|
23163
23437
|
};
|
|
23164
23438
|
function isTemporary(path, tmpDir = tmpdir()) {
|
|
23165
23439
|
const roots = [resolve(tmpDir), realOrSpelled(tmpDir)];
|
|
23166
|
-
return [resolve(path), realOrSpelled(path)].some(
|
|
23440
|
+
return [resolve(path), realOrSpelled(path)].some(
|
|
23441
|
+
(p) => p.split(sep).includes("cmux-cli-shims") || roots.some((root) => isInside(root, p))
|
|
23442
|
+
);
|
|
23167
23443
|
}
|
|
23168
23444
|
async function resolveClaude(exec4, tmpDir) {
|
|
23169
23445
|
const candidates = await whichAll(exec4, "claude");
|
|
@@ -23180,8 +23456,9 @@ Put the claude CLI itself on PATH, or run this from another terminal: https://cl
|
|
|
23180
23456
|
"claude CLI not found on PATH. The runner spawns it to run sessions.\nInstall it first: https://claude.com/claude-code"
|
|
23181
23457
|
);
|
|
23182
23458
|
}
|
|
23183
|
-
function buildPathEnv(nodePath, claudePath) {
|
|
23459
|
+
function buildPathEnv(nodePath, claudePath, codexPath) {
|
|
23184
23460
|
const dirs = ["/usr/bin", "/bin", "/usr/sbin", "/sbin", dirname2(nodePath), dirname2(claudePath)];
|
|
23461
|
+
if (codexPath) dirs.push(dirname2(codexPath));
|
|
23185
23462
|
return [...new Set(dirs)].join(":");
|
|
23186
23463
|
}
|
|
23187
23464
|
function readInstalledVersion(appDir, pkg) {
|
|
@@ -23203,6 +23480,9 @@ function readInstallRecord(cayenneHome2) {
|
|
|
23203
23480
|
}
|
|
23204
23481
|
async function installApp(deps) {
|
|
23205
23482
|
const claudePath = await resolveClaude(deps.exec, deps.tmpDir ?? tmpdir());
|
|
23483
|
+
const codexPath = (await whichAll(deps.exec, "codex")).find(
|
|
23484
|
+
(path) => !isTemporary(path, deps.tmpDir ?? tmpdir())
|
|
23485
|
+
);
|
|
23206
23486
|
const appDir = join6(deps.cayenneHome, "app");
|
|
23207
23487
|
mkdirSync3(appDir, { recursive: true, mode: 448 });
|
|
23208
23488
|
const install = await deps.exec("npm", [
|
|
@@ -23227,7 +23507,7 @@ async function installApp(deps) {
|
|
|
23227
23507
|
claudePath,
|
|
23228
23508
|
cliPath,
|
|
23229
23509
|
appDir,
|
|
23230
|
-
pathEnv: buildPathEnv(nodePath, claudePath),
|
|
23510
|
+
pathEnv: buildPathEnv(nodePath, claudePath, codexPath),
|
|
23231
23511
|
installedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
23232
23512
|
};
|
|
23233
23513
|
const binDir = join6(deps.cayenneHome, "bin");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jpcasabiancai/cayenne",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.14",
|
|
4
4
|
"files": [
|
|
5
5
|
"dist/cli.js"
|
|
6
6
|
],
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
"test": "vitest run"
|
|
34
34
|
},
|
|
35
35
|
"dependencies": {
|
|
36
|
-
"@anthropic-ai/claude-agent-sdk": "0.3.
|
|
36
|
+
"@anthropic-ai/claude-agent-sdk": "0.3.312",
|
|
37
37
|
"@anthropic-ai/sdk": "0.123.0",
|
|
38
38
|
"@modelcontextprotocol/sdk": "1.30.0",
|
|
39
39
|
"@supabase/supabase-js": "2.115.0",
|