@rallycry/conveyor-agent 10.0.6 → 10.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-37ZIDX6S.js → chunk-EDEMOFUN.js} +848 -115
- package/dist/chunk-EDEMOFUN.js.map +1 -0
- package/dist/cli.js +192 -5
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +59 -5
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/runtime/entrypoint.sh +22 -15
- package/dist/chunk-37ZIDX6S.js.map +0 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as _project_shared from '@project/shared';
|
|
2
|
-
import { AgentSessionServiceMethods, AgentMode, WorkspaceDiscoveredPort, AgentQuestion, AgentRunnerStatus, BootstrapBundle } from '@project/shared';
|
|
2
|
+
import { RunnerMode, AgentSessionServiceMethods, AgentMode, WorkspaceDiscoveredPort, AgentQuestion, AgentRunnerStatus, BootstrapBundle } from '@project/shared';
|
|
3
3
|
export * from '@project/shared';
|
|
4
4
|
import { ChildProcess } from 'node:child_process';
|
|
5
5
|
|
|
@@ -7,7 +7,7 @@ interface AgentConnectionConfig {
|
|
|
7
7
|
apiUrl: string;
|
|
8
8
|
taskToken: string;
|
|
9
9
|
sessionId: string;
|
|
10
|
-
runnerMode?:
|
|
10
|
+
runnerMode?: RunnerMode;
|
|
11
11
|
}
|
|
12
12
|
interface IncomingMessage {
|
|
13
13
|
content: string;
|
|
@@ -66,7 +66,17 @@ declare class AgentConnection {
|
|
|
66
66
|
get connected(): boolean;
|
|
67
67
|
private static readonly CALL_CONNECT_WAIT_MS;
|
|
68
68
|
private static readonly CALL_ACK_TIMEOUT_MS;
|
|
69
|
+
private static readonly SOCKET_RECYCLE_BASE_MS;
|
|
70
|
+
private static readonly SOCKET_RECYCLE_JITTER_MS;
|
|
71
|
+
private static readonly SOCKET_RECYCLE_BUSY_POLL_MS;
|
|
72
|
+
private recycleTimer;
|
|
73
|
+
private pendingCalls;
|
|
69
74
|
call<M extends keyof AgentSessionServiceMethods>(method: M, payload: AgentSessionServiceMethods[M]["payload"]): Promise<AgentSessionServiceMethods[M]["response"]>;
|
|
75
|
+
/** (Re)arm the recycle timer — called on every successful (re)connect. */
|
|
76
|
+
private scheduleSocketRecycle;
|
|
77
|
+
private clearSocketRecycle;
|
|
78
|
+
private armRecycleTimer;
|
|
79
|
+
private attemptSocketRecycle;
|
|
70
80
|
/** Resolve once `socket` reports connected, or reject after `timeoutMs`. */
|
|
71
81
|
private waitForConnected;
|
|
72
82
|
/** Emit an RPC and resolve on ack, rejecting if no ack arrives in time. */
|
|
@@ -109,6 +119,13 @@ declare class AgentConnection {
|
|
|
109
119
|
cols: number;
|
|
110
120
|
rows: number;
|
|
111
121
|
}): void;
|
|
122
|
+
/**
|
|
123
|
+
* Report that the interactive CLI process for this session has died and no
|
|
124
|
+
* respawn is imminent (fire-and-forget). The server clears the scrollback
|
|
125
|
+
* ring and broadcasts pty:ended so clients hide the Connected-TUI tab. Old
|
|
126
|
+
* servers that don't know the method reject harmlessly.
|
|
127
|
+
*/
|
|
128
|
+
sendPtyEnded(): void;
|
|
112
129
|
/** Subscribe to relayed keystrokes. Returns an unsubscribe fn. */
|
|
113
130
|
onPtyInput(handler: (data: string) => void): () => void;
|
|
114
131
|
/** Subscribe to relayed (reconciled) terminal resizes. Returns an unsubscribe fn. */
|
|
@@ -210,7 +227,7 @@ declare class ModeController {
|
|
|
210
227
|
private _pendingModeRestart;
|
|
211
228
|
private _runnerMode;
|
|
212
229
|
private _isAuto;
|
|
213
|
-
constructor(initialMode: AgentMode, runnerMode?:
|
|
230
|
+
constructor(initialMode: AgentMode, runnerMode?: RunnerMode, isAuto?: boolean);
|
|
214
231
|
get mode(): AgentMode;
|
|
215
232
|
get isAuto(): boolean;
|
|
216
233
|
get hasExitedPlanMode(): boolean;
|
|
@@ -231,7 +248,21 @@ declare class ModeController {
|
|
|
231
248
|
applyServerMode(agentMode: AgentMode | null | undefined, isAuto: boolean | undefined): void;
|
|
232
249
|
/** Resolve the initial mode based on task context */
|
|
233
250
|
resolveInitialMode(context: ModeTaskContext): AgentMode;
|
|
234
|
-
/**
|
|
251
|
+
/**
|
|
252
|
+
* A FRESH auto task runs the read-only plan turn first (`--permission-mode plan`):
|
|
253
|
+
* resolveInitialMode leaves it in `auto` with `_hasExitedPlanMode = false`, and
|
|
254
|
+
* once the agent finishes it calls ExitPlanMode → building. Only tasks that have
|
|
255
|
+
* already progressed past the fresh stage bypass planning and build immediately
|
|
256
|
+
* with `--dangerously-skip-permissions`:
|
|
257
|
+
*
|
|
258
|
+
* - a build already underway (status past `Planning`/`Open`),
|
|
259
|
+
* - a PR already open (safety net if status lags),
|
|
260
|
+
* - a release (booted `InProgress`), or
|
|
261
|
+
* - a pod restart mid-build (DB `agentMode` stays `"auto"` but status advanced).
|
|
262
|
+
*
|
|
263
|
+
* Runtime Build-after-Discovery never reaches this gate as `auto` — the server's
|
|
264
|
+
* `resolveModeToSend` rewrites it to `"building"` for any non-`Planning` task.
|
|
265
|
+
*/
|
|
235
266
|
canBypassPlanning(context: ModeTaskContext): boolean;
|
|
236
267
|
/** Handle mode change from server */
|
|
237
268
|
handleModeChange(newMode: AgentMode): ModeAction;
|
|
@@ -260,6 +291,11 @@ interface LifecycleConfig {
|
|
|
260
291
|
* persistent state (local, workspace, GitHub Codespaces) that don't lose
|
|
261
292
|
* in-flight work on a crash. */
|
|
262
293
|
gitFlushIntervalMs: number;
|
|
294
|
+
/** Claude key usage sample interval (default: 5 min). Polls the Anthropic
|
|
295
|
+
* OAuth usage endpoint and reports session/weekly rate-limit utilization for
|
|
296
|
+
* the running subscription key. Deliberately NOT the heartbeat cadence — the
|
|
297
|
+
* endpoint is rate-limited. Set to `0` to disable the timer entirely. */
|
|
298
|
+
usageSampleIntervalMs: number;
|
|
263
299
|
}
|
|
264
300
|
interface LifecycleCallbacks {
|
|
265
301
|
onHeartbeat: () => void;
|
|
@@ -267,6 +303,7 @@ interface LifecycleCallbacks {
|
|
|
267
303
|
onDormantTimeout: () => void;
|
|
268
304
|
onTokenRefresh: () => void;
|
|
269
305
|
onGitFlush: () => void;
|
|
306
|
+
onUsageSample: () => void;
|
|
270
307
|
}
|
|
271
308
|
declare class Lifecycle {
|
|
272
309
|
readonly config: LifecycleConfig;
|
|
@@ -277,6 +314,7 @@ declare class Lifecycle {
|
|
|
277
314
|
private idleCheckInterval;
|
|
278
315
|
private dormantTimer;
|
|
279
316
|
private gitFlushTimer;
|
|
317
|
+
private usageSampleTimer;
|
|
280
318
|
constructor(config: LifecycleConfig, callbacks: LifecycleCallbacks);
|
|
281
319
|
startHeartbeat(): void;
|
|
282
320
|
stopHeartbeat(): void;
|
|
@@ -284,6 +322,8 @@ declare class Lifecycle {
|
|
|
284
322
|
stopTokenRefresh(): void;
|
|
285
323
|
startGitFlush(): void;
|
|
286
324
|
stopGitFlush(): void;
|
|
325
|
+
startUsageSample(): void;
|
|
326
|
+
stopUsageSample(): void;
|
|
287
327
|
startIdleTimer(): void;
|
|
288
328
|
cancelIdleTimer(): void;
|
|
289
329
|
/** Start (or restart) the dormant timer.
|
|
@@ -302,7 +342,7 @@ declare class Lifecycle {
|
|
|
302
342
|
interface SessionRunnerConfig {
|
|
303
343
|
connection: AgentConnectionConfig;
|
|
304
344
|
agentMode?: AgentMode;
|
|
305
|
-
runnerMode?:
|
|
345
|
+
runnerMode?: RunnerMode;
|
|
306
346
|
isAuto?: boolean;
|
|
307
347
|
workspaceDir: string;
|
|
308
348
|
model?: string;
|
|
@@ -415,11 +455,25 @@ declare class SessionRunner {
|
|
|
415
455
|
injectMessage(msg: IncomingMessage): void;
|
|
416
456
|
/** Run queryBridge.execute, swallowing abort errors from stop/softStop. */
|
|
417
457
|
private executeQuery;
|
|
458
|
+
/**
|
|
459
|
+
* A human typed into the parked, idle Connected-TUI (keep-alive PTY). Wake the
|
|
460
|
+
* core loop with a sentinel so it drains a passive turn. No-op once stopped.
|
|
461
|
+
*/
|
|
462
|
+
private onPassiveTuiActivity;
|
|
463
|
+
/** Run queryBridge.executePassive, swallowing abort errors from stop/softStop. */
|
|
464
|
+
private executePassive;
|
|
418
465
|
/** Periodic best-effort WIP commit + push during normal agent execution.
|
|
419
466
|
* Covers ungraceful pod termination (OOMKilled, node crash/eviction) where
|
|
420
467
|
* the preStop hook + SIGTERM flush don't get a chance to run. No-ops on a
|
|
421
468
|
* clean tree. Guarded so two ticks can't overlap. Never throws. */
|
|
422
469
|
private periodicGitFlush;
|
|
470
|
+
/** Sample the running Claude subscription key's rate-limit utilization from the
|
|
471
|
+
* Anthropic OAuth usage endpoint and report it as `rate_limit_update` events.
|
|
472
|
+
* The API (`persistRateLimitSnapshot`) attributes them to the key this session
|
|
473
|
+
* launched under, keeping User Settings + the PtY-tab usage widget fresh and
|
|
474
|
+
* `selectBestKey` rotation honest. Best-effort — never throws, no-op when the
|
|
475
|
+
* pod has no OAuth token (e.g. API-key projects). */
|
|
476
|
+
private sampleAndReportKeyUsage;
|
|
423
477
|
/** PUT the WorkPreservation snapshot tar to the bundle's capability URL
|
|
424
478
|
* when this pod is v3 (CONVEYOR_SNAPSHOT_UPLOAD_URL set). Never throws. */
|
|
425
479
|
private uploadGcsSnapshotIfConfigured;
|
package/dist/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rallycry/conveyor-agent",
|
|
3
|
-
"version": "10.0
|
|
3
|
+
"version": "10.2.0",
|
|
4
4
|
"description": "Conveyor Agent Runner v10 - PTY harness for the task chat (SDK harness for audit/project-chat). Agent-as-User architecture with BaseService patterns. Works locally too.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"agent",
|
package/runtime/entrypoint.sh
CHANGED
|
@@ -217,10 +217,16 @@ if [ "${SESSION_MODE}" = "review" ]; then
|
|
|
217
217
|
# branch), so a role check can't identify them — gating on role=reader here
|
|
218
218
|
# is what let review pods fall through to the default task runner and boot
|
|
219
219
|
# the parent's task agent in discovery mode. The agent CLI's RunnerMode is
|
|
220
|
-
# spelled "code-review" (cli.ts validates task|pm|code-review); the bare
|
|
220
|
+
# spelled "code-review" (cli.ts validates task|pm|code-review|adhoc); the bare
|
|
221
221
|
# "review" is the agentMode/tag axis, NOT a runner mode — passing it here
|
|
222
222
|
# made the agent exit "Invalid CONVEYOR_MODE" and crash-loop every 10s.
|
|
223
223
|
export CONVEYOR_MODE="code-review"
|
|
224
|
+
elif [ "${SESSION_MODE}" = "adhoc" ]; then
|
|
225
|
+
# Task-less USER SCRATCH pod (Sessions view): the agent runs an interactive
|
|
226
|
+
# `claude` TUI relayed to the web terminal — no autonomous loop, no task. Must
|
|
227
|
+
# be checked BEFORE the project branch below: an adhoc session is also
|
|
228
|
+
# task-less with a projectId claim, but it must NOT boot the pm project runner.
|
|
229
|
+
export CONVEYOR_MODE="adhoc"
|
|
224
230
|
elif [ -z "${CONVEYOR_TASK_ID:-}" ] && [ -n "${CONVEYOR_PROJECT_ID_CLAIM}" ]; then
|
|
225
231
|
# Task-less project pod: the agent boots the project runner in pm mode
|
|
226
232
|
# (see conveyor-agent setup/project-identity.ts — pm is required).
|
|
@@ -352,20 +358,21 @@ fi
|
|
|
352
358
|
GIT_READY_MARKER="/workspaces/.conveyor-git-ready"
|
|
353
359
|
GIT_FAILED_MARKER="/workspaces/.conveyor-git-failed"
|
|
354
360
|
|
|
355
|
-
|
|
356
|
-
# The baked/pooled repo is not user-owned until this git gate succeeds.
|
|
357
|
-
# stale image-generated dirt so assignment checkout can move to the
|
|
358
|
-
# branch/ref instead of being blocked by
|
|
361
|
+
reset_tracked_repo_changes_before_assignment_checkout() {
|
|
362
|
+
# The baked/pooled repo is not user-owned until this git gate succeeds. Reset
|
|
363
|
+
# stale tracked image-generated dirt so assignment checkout can move to the
|
|
364
|
+
# requested branch/ref instead of being blocked by files like dependency
|
|
365
|
+
# stamps. Do not `git clean`: untracked prebake artifacts may be intentional.
|
|
366
|
+
# The assignment checkouts additionally pass -f: an UNTRACKED bake artifact
|
|
367
|
+
# can collide with a path the TARGET ref tracks (e.g. a dependency stamp
|
|
368
|
+
# committed on an older PR branch), which this reset cannot clear — checkout
|
|
369
|
+
# then refuses with "untracked working tree files would be overwritten".
|
|
370
|
+
# Forcing is safe here for the same not-user-owned reason.
|
|
359
371
|
if ! _reset_out=$(git -C repo reset --hard HEAD 2>&1); then
|
|
360
372
|
echo "[pool] ERROR: failed to clean tracked repo changes before checkout: ${_reset_out}" >&2
|
|
361
373
|
printf '%s' "pre-checkout reset failed" > "$GIT_FAILED_MARKER"
|
|
362
374
|
return 1
|
|
363
375
|
fi
|
|
364
|
-
if ! _clean_out=$(git -C repo clean -ffd 2>&1); then
|
|
365
|
-
echo "[pool] ERROR: failed to clean untracked repo files before checkout: ${_clean_out}" >&2
|
|
366
|
-
printf '%s' "pre-checkout clean failed" > "$GIT_FAILED_MARKER"
|
|
367
|
-
return 1
|
|
368
|
-
fi
|
|
369
376
|
return 0
|
|
370
377
|
}
|
|
371
378
|
|
|
@@ -391,7 +398,7 @@ sync_task_branch_to_repo() {
|
|
|
391
398
|
echo "[pool] WARN: fetch origin/${DEV_BRANCH} failed: ${_fetch_dev_out}" >&2
|
|
392
399
|
fi
|
|
393
400
|
|
|
394
|
-
if !
|
|
401
|
+
if ! reset_tracked_repo_changes_before_assignment_checkout; then
|
|
395
402
|
return 1
|
|
396
403
|
fi
|
|
397
404
|
|
|
@@ -402,7 +409,7 @@ sync_task_branch_to_repo() {
|
|
|
402
409
|
printf '%s' "fetch checkout ref ${CHECKOUT_REF} failed" > "$GIT_FAILED_MARKER"
|
|
403
410
|
return 1
|
|
404
411
|
fi
|
|
405
|
-
if ! _checkout_out=$(git -C repo checkout -B "${BRANCH}" "refs/remotes/origin/pr-checkout" 2>&1); then
|
|
412
|
+
if ! _checkout_out=$(git -C repo checkout -f -B "${BRANCH}" "refs/remotes/origin/pr-checkout" 2>&1); then
|
|
406
413
|
echo "[pool] ERROR: Repo checkout of ${CHECKOUT_REF} failed: ${_checkout_out}" >&2
|
|
407
414
|
printf '%s' "checkout of ${CHECKOUT_REF} failed" > "$GIT_FAILED_MARKER"
|
|
408
415
|
return 1
|
|
@@ -417,7 +424,7 @@ sync_task_branch_to_repo() {
|
|
|
417
424
|
if echo "${_fetch_out}" | grep -q "couldn't find remote ref"; then
|
|
418
425
|
echo "[pool] Branch missing on origin — creating from base '${DEV_BRANCH}'"
|
|
419
426
|
# Create the branch locally from the base branch
|
|
420
|
-
if ! _create_out=$(git -C repo checkout -B "${BRANCH}" "origin/${DEV_BRANCH}" 2>&1); then
|
|
427
|
+
if ! _create_out=$(git -C repo checkout -f -B "${BRANCH}" "origin/${DEV_BRANCH}" 2>&1); then
|
|
421
428
|
echo "[pool] ERROR: Failed to create branch '${BRANCH}' from '${DEV_BRANCH}': ${_create_out}" >&2
|
|
422
429
|
printf '%s' "create branch ${BRANCH} from ${DEV_BRANCH} failed" > "$GIT_FAILED_MARKER"
|
|
423
430
|
return 1
|
|
@@ -439,7 +446,7 @@ sync_task_branch_to_repo() {
|
|
|
439
446
|
# Use `checkout -B` to create or reset the local branch tracking origin.
|
|
440
447
|
# This leaves HEAD attached to a real branch (not detached) so `git status`,
|
|
441
448
|
# `git push`, and any tool that keys off branch state work correctly.
|
|
442
|
-
if ! _checkout_out=$(git -C repo checkout -B "${BRANCH}" "origin/${BRANCH}" 2>&1); then
|
|
449
|
+
if ! _checkout_out=$(git -C repo checkout -f -B "${BRANCH}" "origin/${BRANCH}" 2>&1); then
|
|
443
450
|
echo "[pool] ERROR: Repo checkout of ${BRANCH} failed: ${_checkout_out}" >&2
|
|
444
451
|
printf '%s' "checkout of ${BRANCH} failed" > "$GIT_FAILED_MARKER"
|
|
445
452
|
return 1
|
|
@@ -512,7 +519,7 @@ prepare_workspace_git() {
|
|
|
512
519
|
printf '%s' "post-assignment fetch of ${CHECKOUT_REF} failed" > "$GIT_FAILED_MARKER"
|
|
513
520
|
return 1
|
|
514
521
|
fi
|
|
515
|
-
if ! _checkout_out=$(git -C repo checkout -B "${BRANCH}" "refs/remotes/origin/pr-checkout" 2>&1); then
|
|
522
|
+
if ! _checkout_out=$(git -C repo checkout -f -B "${BRANCH}" "refs/remotes/origin/pr-checkout" 2>&1); then
|
|
516
523
|
echo "[pool] ERROR: post-assignment checkout of ${CHECKOUT_REF} failed: ${_checkout_out}" >&2
|
|
517
524
|
printf '%s' "post-assignment checkout of ${CHECKOUT_REF} failed" > "$GIT_FAILED_MARKER"
|
|
518
525
|
return 1
|