@rallycry/conveyor-agent 10.13.3 → 10.13.8
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-P4VWWR5O.js → chunk-AJZIO5QI.js} +97 -10
- package/dist/chunk-AJZIO5QI.js.map +1 -0
- package/dist/cli.js +217 -69
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +21 -2
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/runtime/entrypoint.sh +66 -6
- package/dist/chunk-P4VWWR5O.js.map +0 -1
package/dist/index.d.ts
CHANGED
|
@@ -3,6 +3,11 @@ import { RunnerMode, AgentSessionServiceMethods, AgentMode, PtyChatEventPayload,
|
|
|
3
3
|
export * from '@project/shared';
|
|
4
4
|
import { ChildProcess } from 'node:child_process';
|
|
5
5
|
|
|
6
|
+
/**
|
|
7
|
+
* The milestones an agent may declare — narrower than the server's full slug
|
|
8
|
+
* set, which also covers server-generated review verdicts.
|
|
9
|
+
*/
|
|
10
|
+
type AgentMilestone = NonNullable<AgentSessionServiceMethods["postAgentMessage"]["payload"]["milestone"]>;
|
|
6
11
|
interface AgentConnectionConfig {
|
|
7
12
|
apiUrl: string;
|
|
8
13
|
taskToken: string;
|
|
@@ -90,6 +95,8 @@ declare class AgentConnection {
|
|
|
90
95
|
private earlySpawnReviews;
|
|
91
96
|
private spawnTuiCallback;
|
|
92
97
|
private earlySpawnTuis;
|
|
98
|
+
private probeUsageCallback;
|
|
99
|
+
private earlyProbeUsage;
|
|
93
100
|
private ptyInputCallback;
|
|
94
101
|
private ptyResizeCallback;
|
|
95
102
|
constructor(config: AgentConnectionConfig);
|
|
@@ -148,6 +155,9 @@ declare class AgentConnection {
|
|
|
148
155
|
*/
|
|
149
156
|
reportReviewSpawnFailure(reviewSessionId: string, error?: string): void;
|
|
150
157
|
onSpawnTui(callback: (data: SpawnTuiData) => void): void;
|
|
158
|
+
/** Register the on-demand usage-refresh handler; drains an early-buffered
|
|
159
|
+
* `session:probeUsage` that arrived before the runner was ready. */
|
|
160
|
+
onProbeUsage(callback: () => void): void;
|
|
151
161
|
/**
|
|
152
162
|
* Report that a same-pod TUI/shell child failed to spawn (fire-and-forget).
|
|
153
163
|
* The server Ends the orphaned session — no fallback pod (unlike review).
|
|
@@ -183,8 +193,8 @@ declare class AgentConnection {
|
|
|
183
193
|
/** Subscribe to relayed (reconciled) terminal resizes. Returns an unsubscribe fn. */
|
|
184
194
|
onPtyResize(handler: (cols: number, rows: number) => void): () => void;
|
|
185
195
|
emitStatus(status: string, reason?: string, questionText?: string): Promise<void>;
|
|
186
|
-
postChatMessage(content: string): void;
|
|
187
|
-
postChatMessageAwait(content: string): Promise<void>;
|
|
196
|
+
postChatMessage(content: string, milestone?: AgentMilestone): void;
|
|
197
|
+
postChatMessageAwait(content: string, milestone?: AgentMilestone): Promise<void>;
|
|
188
198
|
private suppressIfDuplicate;
|
|
189
199
|
checkAndTrackDuplicate(content: string): {
|
|
190
200
|
duplicate: false;
|
|
@@ -237,6 +247,15 @@ declare class AgentConnection {
|
|
|
237
247
|
triggerIdentification(): Promise<{
|
|
238
248
|
identified: boolean;
|
|
239
249
|
}>;
|
|
250
|
+
handoffToImplementer(payload: {
|
|
251
|
+
storyPoints?: number;
|
|
252
|
+
message?: string;
|
|
253
|
+
}): Promise<{
|
|
254
|
+
handedOff: boolean;
|
|
255
|
+
agentName?: string;
|
|
256
|
+
model?: string;
|
|
257
|
+
reason?: string;
|
|
258
|
+
}>;
|
|
240
259
|
refreshAuthToken(): Promise<boolean>;
|
|
241
260
|
/**
|
|
242
261
|
* Refresh the in-process `CONVEYOR_TASK_TOKEN` from the bootstrap endpoint.
|
package/dist/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rallycry/conveyor-agent",
|
|
3
|
-
"version": "10.13.
|
|
3
|
+
"version": "10.13.8",
|
|
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
|
@@ -118,6 +118,31 @@ refresh_agent_version() {
|
|
|
118
118
|
fi
|
|
119
119
|
}
|
|
120
120
|
|
|
121
|
+
# ── Reclaim any root-owned $HOME config/state entries (bake defense-in-depth) ──
|
|
122
|
+
# Bake steps that run as root while ENV HOME points at /home/conveyor can leave
|
|
123
|
+
# root-owned entries under ~/.config / ~/.local (a uv install receipt in
|
|
124
|
+
# ~/.config once bricked every pod boot fleet-wide). This reclaims them so a
|
|
125
|
+
# baked ownership slip can't EACCES the entrypoint under `set -e`.
|
|
126
|
+
#
|
|
127
|
+
# CONDITIONAL, not `chown -R`: a `find … ! -user conveyor` walk is stat-only when
|
|
128
|
+
# the tree is already clean (the common case since the bake-side `HOME=/root`
|
|
129
|
+
# fix in 9815c8915 — current images carry ZERO root-owned files here), so it
|
|
130
|
+
# triggers no overlayfs copy-up. The former unconditional `chown -R` copied up
|
|
131
|
+
# ALL ~3.9k baked files (~63MB, dominated by ~/.config/opencode's 3,652 files)
|
|
132
|
+
# on EVERY boot even when nothing was root-owned — ~16s of I/O-bound
|
|
133
|
+
# uninterruptible-disk-sleep that reclaimed nothing, and the true owner of the
|
|
134
|
+
# "GCS-FUSE" boot gap. Runs in the PRE-BIND phase below (payload-independent, off
|
|
135
|
+
# the time-to-agent critical path) and before any mount symlinks exist, so it
|
|
136
|
+
# never follows into the FUSE mount. See
|
|
137
|
+
# docs/investigations/gcs-fuse-user-home-boot-cost-2026-07-15.md.
|
|
138
|
+
reclaim_home_ownership() {
|
|
139
|
+
local d
|
|
140
|
+
for d in /home/conveyor/.config /home/conveyor/.local; do
|
|
141
|
+
[ -d "${d}" ] || continue
|
|
142
|
+
sudo -n find "${d}" ! -user conveyor -exec chown conveyor:conveyor {} + 2>/dev/null || true
|
|
143
|
+
done
|
|
144
|
+
}
|
|
145
|
+
|
|
121
146
|
start_workspace_sshd
|
|
122
147
|
|
|
123
148
|
# ── Required env vars (injected by pod spec — v3: exactly these two) ──
|
|
@@ -134,6 +159,10 @@ export CLAUDESPACE_NAME="${INSTANCE_NAME}"
|
|
|
134
159
|
# ═══════════════════════════════════════════════════════════════════════════
|
|
135
160
|
PREWARM_DEV_LOOP_PID=""
|
|
136
161
|
refresh_agent_version
|
|
162
|
+
# Reclaim root-owned $HOME entries here, during standby, so the common (clean)
|
|
163
|
+
# case costs a stat-only walk off the critical path instead of a ~16s copy-up
|
|
164
|
+
# `chown -R` after the bundle arrives.
|
|
165
|
+
reclaim_home_ownership
|
|
137
166
|
|
|
138
167
|
# ═══════════════════════════════════════════════════════════════════════════
|
|
139
168
|
# PULL-BASED BOOTSTRAP — poll until the reconciler binds this pod to a
|
|
@@ -271,6 +300,27 @@ if [ -n "${ENV_KEYS}" ]; then
|
|
|
271
300
|
done <<< "${ENV_KEYS}"
|
|
272
301
|
echo "[boot] Injected ${ENV_COUNT} env vars from bootstrap bundle"
|
|
273
302
|
fi
|
|
303
|
+
|
|
304
|
+
# ── Boot timing instrumentation (env-inject → agent-launch breakdown) ──
|
|
305
|
+
# A ~16s window between "Injected env vars" and "Linking Claude state" was
|
|
306
|
+
# root-caused (2026-07-16) to the unconditional root-owned-$HOME `chown -R` that
|
|
307
|
+
# used to run here — NOT GCS-FUSE (the mount is idle during the gap). That chown
|
|
308
|
+
# is now a conditional pre-bind reclaim (see reclaim_home_ownership). These marks
|
|
309
|
+
# stay as a regression probe: they attribute the gap to each sub-step —
|
|
310
|
+
# mount-readiness stat vs first metadata write vs symlink wiring — so if the
|
|
311
|
+
# total ever balloons again a canary boot shows WHERE. EPOCHREALTIME is
|
|
312
|
+
# bash-native (no per-mark subprocess); the `//[.,]/` strip tolerates
|
|
313
|
+
# comma-decimal locales. Grep the boot log for `[boot-timing]`. See
|
|
314
|
+
# docs/investigations/gcs-fuse-user-home-boot-cost-2026-07-15.md.
|
|
315
|
+
BOOT_MARK_T0_US="${EPOCHREALTIME//[.,]/}"
|
|
316
|
+
boot_mark() {
|
|
317
|
+
if [ -z "${EPOCHREALTIME:-}" ]; then echo "[boot-timing] $1"; return 0; fi
|
|
318
|
+
local now_us="${EPOCHREALTIME//[.,]/}"
|
|
319
|
+
local delta_us=$(( now_us - BOOT_MARK_T0_US ))
|
|
320
|
+
printf '[boot-timing] +%d.%03ds %s\n' "$(( delta_us / 1000000 ))" "$(( (delta_us / 1000) % 1000 ))" "$1"
|
|
321
|
+
}
|
|
322
|
+
boot_mark "env injected — entering user-home wiring"
|
|
323
|
+
|
|
274
324
|
export ANTHROPIC_API_KEY=$(echo "${BOOTSTRAP_JSON}" | jq -r '.anthropicKey // empty')
|
|
275
325
|
export CLOUDSDK_AUTH_ACCESS_TOKEN=$(echo "${BOOTSTRAP_JSON}" | jq -r '.gcpToken // empty')
|
|
276
326
|
# WorkPreservation GCS tier (spec §Durability & snapshots): the upload URL is
|
|
@@ -333,17 +383,22 @@ seed_claude_json() {
|
|
|
333
383
|
USER_HOME_MOUNT="/mnt/conveyor-users"
|
|
334
384
|
USER_HOME_PROJECT_ID="${CONVEYOR_PROJECT_ID_FROM_BUNDLE:-${PROJECT_ID:-}}"
|
|
335
385
|
|
|
336
|
-
#
|
|
337
|
-
#
|
|
338
|
-
#
|
|
339
|
-
#
|
|
340
|
-
#
|
|
341
|
-
sudo -n chown -R conveyor:conveyor /home/conveyor/.config /home/conveyor/.local 2>/dev/null || true
|
|
386
|
+
# Root-owned $HOME reclaim moved OFF this critical path into the pre-bind phase
|
|
387
|
+
# (reclaim_home_ownership, called after refresh_agent_version) and made
|
|
388
|
+
# conditional — the former unconditional `chown -R` here cost ~16s of copy-up on
|
|
389
|
+
# every boot and was the real owner of this "GCS-FUSE" gap. See
|
|
390
|
+
# docs/investigations/gcs-fuse-user-home-boot-cost-2026-07-15.md.
|
|
342
391
|
|
|
392
|
+
# The `[ -d "${USER_HOME_MOUNT}" ]` test below is the first stat against the FUSE
|
|
393
|
+
# mount — if the gcsfuse sidecar is still handshaking it blocks here, so the
|
|
394
|
+
# mark straddles the readiness probe.
|
|
395
|
+
boot_mark "probing user-home mount presence"
|
|
343
396
|
if [ -n "${CONVEYOR_USER_ID}" ] && [ -n "${USER_HOME_PROJECT_ID}" ] && [ -d "${USER_HOME_MOUNT}" ]; then
|
|
344
397
|
USER_HOME_ROOT="${USER_HOME_MOUNT}/users/${CONVEYOR_USER_ID}/${USER_HOME_PROJECT_ID}"
|
|
398
|
+
boot_mark "user-home mount ready — linking Claude state"
|
|
345
399
|
echo "[pool] Linking Claude state to ${USER_HOME_ROOT}"
|
|
346
400
|
mkdir -p "${USER_HOME_ROOT}/.claude" "${USER_HOME_ROOT}/.config/claude" 2>/dev/null || true
|
|
401
|
+
boot_mark "mkdir into mount done (first metadata write)"
|
|
347
402
|
|
|
348
403
|
# Replace any image defaults with live symlinks into the mount for the SHARED,
|
|
349
404
|
# append-mostly Claude state: transcripts/plans/memory under ~/.claude and
|
|
@@ -365,6 +420,7 @@ if [ -n "${CONVEYOR_USER_ID}" ] && [ -n "${USER_HOME_PROJECT_ID}" ] && [ -d "${U
|
|
|
365
420
|
mkdir -p /home/conveyor/.config 2>/dev/null || true
|
|
366
421
|
ln -sfn "${USER_HOME_ROOT}/.claude" /home/conveyor/.claude
|
|
367
422
|
ln -sfn "${USER_HOME_ROOT}/.config/claude" /home/conveyor/.config/claude
|
|
423
|
+
boot_mark "~/.claude + ~/.config/claude symlinks wired"
|
|
368
424
|
|
|
369
425
|
# Pod-local ~/.claude.json: clear any symlink/file a prior boot or the image
|
|
370
426
|
# baked in, then seed a fresh real file on the pod's OWN disk (local
|
|
@@ -394,6 +450,7 @@ if [ -n "${CONVEYOR_USER_ID}" ] && [ -n "${USER_HOME_PROJECT_ID}" ] && [ -d "${U
|
|
|
394
450
|
fi
|
|
395
451
|
ln -sfn "${CRED_POD_LOCAL}" "${CRED_SHARED}" 2>/dev/null || true
|
|
396
452
|
chmod 600 "${CRED_POD_LOCAL}" 2>/dev/null || true
|
|
453
|
+
boot_mark "~/.claude.json seeded + credentials repointed"
|
|
397
454
|
|
|
398
455
|
# OpenCode state (sessions + config) persists the same way as ~/.claude.
|
|
399
456
|
mkdir -p "${USER_HOME_ROOT}/.local/share/opencode" "${USER_HOME_ROOT}/.config/opencode" 2>/dev/null || true
|
|
@@ -401,11 +458,13 @@ if [ -n "${CONVEYOR_USER_ID}" ] && [ -n "${USER_HOME_PROJECT_ID}" ] && [ -d "${U
|
|
|
401
458
|
mkdir -p /home/conveyor/.local/share 2>/dev/null || true
|
|
402
459
|
ln -sfn "${USER_HOME_ROOT}/.local/share/opencode" /home/conveyor/.local/share/opencode
|
|
403
460
|
ln -sfn "${USER_HOME_ROOT}/.config/opencode" /home/conveyor/.config/opencode
|
|
461
|
+
boot_mark "opencode state linked — user-home wiring complete"
|
|
404
462
|
else
|
|
405
463
|
echo "[pool] Skipping user-home symlink (userId='${CONVEYOR_USER_ID}', projectId='${USER_HOME_PROJECT_ID}', mount present: $([ -d "${USER_HOME_MOUNT}" ] && echo yes || echo no))"
|
|
406
464
|
# No persistent home — the CLI reads the pod-local config; seed it there so
|
|
407
465
|
# non-FUSE pods get the same first-run gate suppression as the mounted path.
|
|
408
466
|
seed_claude_json /home/conveyor/.claude.json
|
|
467
|
+
boot_mark "no user-home mount — pod-local seed only"
|
|
409
468
|
fi
|
|
410
469
|
|
|
411
470
|
# ── Wire published graphify bundles from the shared user-home mount ──
|
|
@@ -842,6 +901,7 @@ export CONVEYOR_WORKSPACE=/workspaces/repo
|
|
|
842
901
|
# Exit 0 = clean shutdown (idle timeout, task complete) — pod dies.
|
|
843
902
|
# Non-zero = crash — retry after a brief pause.
|
|
844
903
|
cd /workspaces/repo
|
|
904
|
+
boot_mark "launching agent (env-inject → agent-launch total)"
|
|
845
905
|
echo "[pool] Launching agent..."
|
|
846
906
|
set +e
|
|
847
907
|
# Belt-and-braces alongside the pod's preStop hook (which pkills the agent
|