@rallycry/conveyor-agent 11.0.6 → 11.0.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.
@@ -1,19 +1,22 @@
1
1
  import {
2
2
  startWorkbenchServer
3
- } from "./chunk-D57S4UR5.js";
3
+ } from "./chunk-IBAIJY7V.js";
4
4
  import {
5
5
  TOMBSTONE_MESSAGE,
6
6
  isLegacyEntrypointLaunch
7
7
  } from "./chunk-R3FDJQL6.js";
8
8
  import {
9
- readAgentVersion
10
- } from "./chunk-XORJ6SII.js";
11
- import "./chunk-W6VILPQE.js";
9
+ cloneReferenceRepos,
10
+ computeGraphifyEnv,
11
+ readAgentVersion,
12
+ refreshSkillsAfterCheckout,
13
+ runPreReadyBinds
14
+ } from "./chunk-SR66HQKB.js";
15
+ import "./chunk-JG3VMWRQ.js";
12
16
  import {
13
17
  GitPrepJob,
14
18
  defaultGit,
15
19
  ensureDir,
16
- redactToken,
17
20
  reportBootMilestone
18
21
  } from "./chunk-GL2DIQEQ.js";
19
22
  import "./chunk-W4LZ7R6Z.js";
@@ -29,7 +32,7 @@ import {
29
32
 
30
33
  // src/boot/index.ts
31
34
  import { spawn } from "child_process";
32
- import { statSync as statSync4 } from "fs";
35
+ import { statSync as statSync3 } from "fs";
33
36
  import { hostname as osHostname } from "os";
34
37
 
35
38
  // src/boot/bundle.ts
@@ -159,32 +162,6 @@ function buildChildEnv(opts) {
159
162
  return child;
160
163
  }
161
164
 
162
- // src/boot/graphify.ts
163
- var USER_HOME_MOUNT = "/mnt/conveyor-users";
164
- function computeGraphifyEnv(env, repoName, dirExists) {
165
- if (env.CONVEYOR_GRAPHIFY_DISABLE === "1") {
166
- return {};
167
- }
168
- const slug = env.CONVEYOR_GRAPHIFY_SLUG || repoName;
169
- if (!slug) {
170
- return {};
171
- }
172
- const primaryRoot = `${USER_HOME_MOUNT}/users/_shared/graphify`;
173
- const legacyRoot = `${USER_HOME_MOUNT}/_shared/graphify`;
174
- let sharedRoot = env.CONVEYOR_GRAPHIFY_SHARED_ROOT;
175
- if (!sharedRoot) {
176
- sharedRoot = dirExists(primaryRoot) || !dirExists(legacyRoot) ? primaryRoot : legacyRoot;
177
- }
178
- const dir = env.CONVEYOR_GRAPHIFY_DIR || `${sharedRoot}/${slug}/latest`;
179
- const graph = env.CONVEYOR_GRAPHIFY_GRAPH || `${dir}/graph.json`;
180
- return {
181
- CONVEYOR_GRAPHIFY_SLUG: slug,
182
- CONVEYOR_GRAPHIFY_SHARED_ROOT: sharedRoot,
183
- CONVEYOR_GRAPHIFY_DIR: dir,
184
- CONVEYOR_GRAPHIFY_GRAPH: graph
185
- };
186
- }
187
-
188
165
  // src/boot/logger.ts
189
166
  import { appendFileSync } from "fs";
190
167
  var BOOTSTRAP_LOG_PATH = "/tmp/claudespace-bootstrap.log";
@@ -605,9 +582,9 @@ var SEED_GATES = {
605
582
  }
606
583
  };
607
584
  var SEED_FABLE_OPTION = {
608
- value: "claude-fable-5[1m]",
585
+ value: "claude-fable-5-1[1m]",
609
586
  label: "Fable",
610
- description: "Fable 5 - most capable for your hardest and longest-running tasks"
587
+ description: "Fable 5.1 - most capable for your hardest and longest-running tasks"
611
588
  };
612
589
  function isPlainObject(value) {
613
590
  return typeof value === "object" && value !== null && !Array.isArray(value);
@@ -851,306 +828,10 @@ async function startWorkspaceSshd(exec, log, port = process.env.CONVEYOR_WORKSPA
851
828
  }
852
829
  }
853
830
 
854
- // src/boot/workspace-extras.ts
855
- import {
856
- appendFileSync as appendFileSync3,
857
- cpSync,
858
- existsSync as existsSync3,
859
- lstatSync as lstatSync2,
860
- mkdirSync as mkdirSync3,
861
- readdirSync as readdirSync2,
862
- readFileSync as readFileSync2,
863
- readlinkSync,
864
- rmSync as rmSync2,
865
- statSync as statSync3,
866
- symlinkSync as symlinkSync2
867
- } from "fs";
868
- import { dirname as dirname2, join as join5 } from "path";
869
- import { fileURLToPath } from "url";
870
- function errText(err) {
871
- return redactToken(err instanceof Error ? err.message : String(err));
872
- }
873
- function isDir2(path) {
874
- try {
875
- return statSync3(path).isDirectory();
876
- } catch {
877
- return false;
878
- }
879
- }
880
- function isSymlink(path) {
881
- try {
882
- return lstatSync2(path).isSymbolicLink();
883
- } catch {
884
- return false;
885
- }
886
- }
887
- var GRAPHIFY_BUNDLE_FILES = [
888
- "graph.json",
889
- "GRAPH_REPORT.md",
890
- "manifest.json",
891
- ".graphify_analysis.json",
892
- ".graphify_labels.json",
893
- "publish-manifest.json",
894
- "cost.json"
895
- ];
896
- function bindGraphifyBundle(workspace, graphifyEnv, log) {
897
- const slug = graphifyEnv.CONVEYOR_GRAPHIFY_SLUG;
898
- const sourceDir = graphifyEnv.CONVEYOR_GRAPHIFY_DIR;
899
- const graphFile = graphifyEnv.CONVEYOR_GRAPHIFY_GRAPH;
900
- if (!slug || !sourceDir || !graphFile) return;
901
- if (!existsSync3(graphFile)) {
902
- log.info(`[boot] Graphify bundle not found for '${slug}' at ${sourceDir}`);
903
- return;
904
- }
905
- const targetDir = join5(workspace, "graphify-out");
906
- try {
907
- mkdirSync3(targetDir, { recursive: true });
908
- } catch {
909
- log.warn(`[boot] WARN: unable to create graphify-out at ${targetDir}`);
910
- return;
911
- }
912
- for (const rel of GRAPHIFY_BUNDLE_FILES) {
913
- const source = join5(sourceDir, rel);
914
- const target = join5(targetDir, rel);
915
- if (!existsSync3(source)) continue;
916
- if (existsSync3(target) || isSymlink(target)) continue;
917
- try {
918
- symlinkSync2(source, target);
919
- } catch {
920
- }
921
- }
922
- log.info(`[boot] Bound graphify bundle '${slug}' into ${targetDir}`);
923
- }
924
- async function ensureGrimoireSubmodule(workspace, githubToken, git, log) {
925
- try {
926
- if (!existsSync3(join5(workspace, ".gitmodules"))) return;
927
- let paths = "";
928
- try {
929
- ({ stdout: paths } = await git(
930
- ["config", "--file", ".gitmodules", "--get-regexp", String.raw`submodule\..*\.path`],
931
- { cwd: workspace, timeoutMs: 1e4 }
932
- ));
933
- } catch {
934
- return;
935
- }
936
- if (!paths.split("\n").some((line) => line.trim().endsWith(".claude/grimoire"))) return;
937
- if (isDir2(join5(workspace, ".claude", "grimoire", "skills"))) return;
938
- if (!githubToken) {
939
- log.warn("[boot] WARN: grimoire submodule absent and no token to fetch it");
940
- return;
941
- }
942
- try {
943
- await git(
944
- [
945
- "-c",
946
- `url.https://x-access-token:${githubToken}@github.com/.insteadOf=https://github.com/`,
947
- "submodule",
948
- "update",
949
- "--init",
950
- ".claude/grimoire"
951
- ],
952
- { cwd: workspace, timeoutMs: 3e5 }
953
- );
954
- log.info("[boot] Initialized grimoire submodule");
955
- } catch (err) {
956
- log.warn(
957
- `[boot] WARN: grimoire submodule init failed (baked pods may lack rc-* skills): ${errText(err)}`
958
- );
959
- }
960
- } catch (err) {
961
- log.warn(`[boot] WARN: grimoire submodule check failed: ${errText(err)}`);
962
- }
963
- }
964
- function excludeLinkedSkills(workspace, names, log) {
965
- if (names.length === 0) return;
966
- const infoDir = join5(workspace, ".git", "info");
967
- if (!isDir2(join5(workspace, ".git"))) return;
968
- try {
969
- mkdirSync3(infoDir, { recursive: true });
970
- const excludePath = join5(infoDir, "exclude");
971
- const existing = existsSync3(excludePath) ? readFileSync2(excludePath, "utf8") : "";
972
- const missing = names.map((name) => `.claude/skills/${name}`).filter((line) => !existing.split("\n").includes(line));
973
- if (missing.length === 0) return;
974
- const prefix = existing.length > 0 && !existing.endsWith("\n") ? "\n" : "";
975
- appendFileSync3(excludePath, `${prefix}${missing.join("\n")}
976
- `);
977
- } catch (err) {
978
- log.warn(`[boot] WARN: unable to exclude grimoire skill links: ${errText(err)}`);
979
- }
980
- }
981
- function symlinkTargetsGrimoire(path) {
982
- try {
983
- return readlinkSync(path).includes(join5("grimoire", "skills"));
984
- } catch {
985
- return false;
986
- }
987
- }
988
- function linkGrimoireSkills(workspace, log) {
989
- const sourceDir = join5(workspace, ".claude", "grimoire", "skills");
990
- const targetDir = join5(workspace, ".claude", "skills");
991
- if (!isDir2(sourceDir)) return;
992
- try {
993
- mkdirSync3(targetDir, { recursive: true });
994
- } catch {
995
- log.warn(`[boot] WARN: unable to create ${targetDir}; skipping grimoire skill links`);
996
- return;
997
- }
998
- const linkedNames = [];
999
- let names = [];
1000
- try {
1001
- names = readdirSync2(sourceDir);
1002
- } catch {
1003
- return;
1004
- }
1005
- for (const name of names) {
1006
- if (!isDir2(join5(sourceDir, name))) continue;
1007
- const target = join5(targetDir, name);
1008
- if (existsSync3(target) && !isSymlink(target)) {
1009
- log.warn(`[boot] WARN: ${target} exists and is not a symlink; skipping`);
1010
- continue;
1011
- }
1012
- if (isSymlink(target) && !symlinkTargetsGrimoire(target)) continue;
1013
- try {
1014
- rmSync2(target, { force: true });
1015
- symlinkSync2(join5("..", "grimoire", "skills", name), target);
1016
- linkedNames.push(name);
1017
- } catch {
1018
- }
1019
- }
1020
- excludeLinkedSkills(workspace, linkedNames, log);
1021
- log.info(`[boot] Linked ${linkedNames.length} grimoire skills into ${targetDir}`);
1022
- }
1023
- function bundledSkillsDir(moduleUrl = import.meta.url) {
1024
- try {
1025
- const dir = join5(dirname2(fileURLToPath(moduleUrl)), "..", "skills");
1026
- return isDir2(dir) ? dir : null;
1027
- } catch {
1028
- return null;
1029
- }
1030
- }
1031
- function materializeBundledSkills(workspace, log, sourceDirOverride) {
1032
- const sourceDir = sourceDirOverride === void 0 ? bundledSkillsDir() : sourceDirOverride;
1033
- if (!sourceDir) {
1034
- log.warn(
1035
- "[boot] WARN: no bundled skills payload in this agent build. Cloud modes that invoke a skill will have no workflow to follow. This is a packaging fault (tsup copySkillsPayload did not run), not a workspace problem."
1036
- );
1037
- return;
1038
- }
1039
- const targetDir = join5(workspace, ".claude", "skills");
1040
- try {
1041
- mkdirSync3(targetDir, { recursive: true });
1042
- } catch {
1043
- log.warn(`[boot] WARN: unable to create ${targetDir}; skipping bundled skills`);
1044
- return;
1045
- }
1046
- const copied = [];
1047
- let names = [];
1048
- try {
1049
- names = readdirSync2(sourceDir);
1050
- } catch {
1051
- return;
1052
- }
1053
- for (const name of names) {
1054
- if (!isDir2(join5(sourceDir, name))) continue;
1055
- const target = join5(targetDir, name);
1056
- if (existsSync3(target) || isSymlink(target)) continue;
1057
- try {
1058
- cpSync(join5(sourceDir, name), target, { recursive: true, dereference: true });
1059
- copied.push(name);
1060
- } catch {
1061
- }
1062
- }
1063
- excludeLinkedSkills(workspace, copied, log);
1064
- log.info(`[boot] Materialized ${copied.length} bundled skills into ${targetDir}`);
1065
- }
1066
- async function neutralizeGrimoirePointer(workspace, git, log) {
1067
- if (!existsSync3(join5(workspace, ".claude", "grimoire"))) return;
1068
- try {
1069
- await git(["update-index", "--assume-unchanged", ".claude/grimoire"], {
1070
- cwd: workspace,
1071
- timeoutMs: 1e4
1072
- });
1073
- log.info("[boot] Marked .claude/grimoire assume-unchanged (submodule pointer drift is noise)");
1074
- } catch (err) {
1075
- log.warn(`[boot] WARN: grimoire assume-unchanged failed: ${errText(err)}`);
1076
- }
1077
- }
1078
- function parseReferenceRepos(refsJson) {
1079
- let parsed;
1080
- try {
1081
- parsed = JSON.parse(refsJson);
1082
- } catch {
1083
- return [];
1084
- }
1085
- if (!Array.isArray(parsed)) return [];
1086
- const refs = [];
1087
- for (const entry of parsed) {
1088
- if (typeof entry !== "object" || entry === null) continue;
1089
- const raw = entry;
1090
- const str = (key) => typeof raw[key] === "string" ? raw[key] : "";
1091
- const ref = {
1092
- slug: str("slug"),
1093
- owner: str("owner"),
1094
- name: str("name"),
1095
- branch: str("branch") || "main",
1096
- token: str("token")
1097
- };
1098
- if (ref.token && ref.slug && ref.owner && ref.name) refs.push(ref);
1099
- }
1100
- return refs;
1101
- }
1102
- async function runPreReadyBinds(workspace, bundle, git, log) {
1103
- const graphifyEnv = computeGraphifyEnv(process.env, bundle.gitPlan.repoName, isDir2);
1104
- bindGraphifyBundle(workspace, graphifyEnv, log);
1105
- await ensureGrimoireSubmodule(workspace, bundle.githubToken ?? "", git, log);
1106
- linkGrimoireSkills(workspace, log);
1107
- materializeBundledSkills(workspace, log);
1108
- await neutralizeGrimoirePointer(workspace, git, log);
1109
- }
1110
- async function cloneReferenceRepos(refsJson, git, log, referencesDir = "/workspaces/references") {
1111
- if (!refsJson) return;
1112
- const refs = parseReferenceRepos(refsJson);
1113
- if (refs.length === 0) return;
1114
- try {
1115
- mkdirSync3(referencesDir, { recursive: true });
1116
- } catch {
1117
- return;
1118
- }
1119
- for (const ref of refs) {
1120
- const dest = join5(referencesDir, ref.slug);
1121
- if (existsSync3(join5(dest, ".git"))) continue;
1122
- try {
1123
- await git(
1124
- [
1125
- "clone",
1126
- "--depth",
1127
- "1",
1128
- "--single-branch",
1129
- "--branch",
1130
- ref.branch,
1131
- `https://x-access-token:${ref.token}@github.com/${ref.owner}/${ref.name}.git`,
1132
- dest
1133
- ],
1134
- { timeoutMs: 6e5 }
1135
- );
1136
- try {
1137
- await git(
1138
- ["remote", "set-url", "origin", `https://github.com/${ref.owner}/${ref.name}.git`],
1139
- { cwd: dest, timeoutMs: 1e4 }
1140
- );
1141
- } catch {
1142
- }
1143
- log.info(`[boot] cloned reference ${ref.slug} (${ref.owner}/${ref.name}@${ref.branch})`);
1144
- } catch {
1145
- log.warn(`[boot] WARN: reference clone failed: ${ref.slug}`);
1146
- }
1147
- }
1148
- }
1149
-
1150
831
  // src/boot/workbench-boot-deps.ts
1151
832
  var WORKSPACE_DIR = "/workspaces/repo";
1152
833
  var HOME_DIR = "/home/conveyor";
1153
- var USER_HOME_MOUNT2 = "/mnt/conveyor-users";
834
+ var USER_HOME_MOUNT = "/mnt/conveyor-users";
1154
835
  function sleep(ms) {
1155
836
  return new Promise((resolve) => {
1156
837
  setTimeout(resolve, ms);
@@ -1183,6 +864,14 @@ function defaultWorkbenchBootDeps() {
1183
864
  }),
1184
865
  bindsBeforeReady: (ctx, bundle) => runPreReadyBinds(WORKSPACE_DIR, bundle, defaultGit, ctx.log),
1185
866
  cloneReferences: (ctx, bundle) => cloneReferenceRepos(bundle.envVars?.REFERENCE_REPOS_JSON, defaultGit, ctx.log),
867
+ refreshSkills: async (ctx) => {
868
+ const { filled, shadowed, stale } = await refreshSkillsAfterCheckout(
869
+ WORKSPACE_DIR,
870
+ defaultGit,
871
+ ctx.log
872
+ );
873
+ return { t: "refreshSkills", filled, shadowed, stale };
874
+ },
1186
875
  ensureWorkspaceDir: (ctx) => {
1187
876
  ensureDir(WORKSPACE_DIR);
1188
877
  ctx.log.info(`[boot] ensured workspace dir ${WORKSPACE_DIR}`);
@@ -1190,7 +879,7 @@ function defaultWorkbenchBootDeps() {
1190
879
  wireHome: (ctx) => {
1191
880
  void wireUserHome({
1192
881
  home: HOME_DIR,
1193
- userHomeMount: USER_HOME_MOUNT2,
882
+ userHomeMount: USER_HOME_MOUNT,
1194
883
  userId: ctx.childEnv?.CONVEYOR_USER_ID,
1195
884
  projectId: ctx.childEnv?.CONVEYOR_PROJECT_ID ?? ctx.childEnv?.PROJECT_ID,
1196
885
  sharedDir: process.env.CONVEYOR_SHARED_DIR,
@@ -1239,6 +928,7 @@ async function runWorkbenchBoot(ctx, overrides = {}) {
1239
928
  token: ctx.bootstrapToken,
1240
929
  version: readAgentVersion() ?? "unknown",
1241
930
  getGitStatus: () => toGitStatusFrame(job.status),
931
+ refreshSkills: () => deps.refreshSkills(ctx),
1242
932
  oomWatchdog: oomWatchdogOptionsFromEnv(ctx.log)
1243
933
  });
1244
934
  ctx.log.info("[boot] step=startDaemon listen socket up (startupProbe gate open)");
@@ -1261,7 +951,7 @@ async function runWorkbenchBoot(ctx, overrides = {}) {
1261
951
 
1262
952
  // src/boot/index.ts
1263
953
  var HOME_DIR2 = "/home/conveyor";
1264
- var USER_HOME_MOUNT3 = "/mnt/conveyor-users";
954
+ var USER_HOME_MOUNT2 = "/mnt/conveyor-users";
1265
955
  function defaultBootDeps() {
1266
956
  return {
1267
957
  fetchFn: fetch,
@@ -1272,7 +962,7 @@ function defaultBootDeps() {
1272
962
  exec: defaultExec,
1273
963
  dirExists: (path) => {
1274
964
  try {
1275
- return statSync4(path).isDirectory();
965
+ return statSync3(path).isDirectory();
1276
966
  } catch {
1277
967
  return false;
1278
968
  }
@@ -1349,7 +1039,7 @@ function agentBootSteps(deps = defaultBootDeps(), signal = new AbortController()
1349
1039
  if (ctx.bundle) {
1350
1040
  void wireUserHome({
1351
1041
  home: HOME_DIR2,
1352
- userHomeMount: USER_HOME_MOUNT3,
1042
+ userHomeMount: USER_HOME_MOUNT2,
1353
1043
  userId: ctx.childEnv?.CONVEYOR_USER_ID,
1354
1044
  projectId: ctx.childEnv?.CONVEYOR_PROJECT_ID ?? ctx.childEnv?.PROJECT_ID,
1355
1045
  sharedDir: process.env.CONVEYOR_SHARED_DIR,
@@ -5,7 +5,7 @@ import {
5
5
  readWorkspaceBytes,
6
6
  statWorkspacePath,
7
7
  workspacePathExists
8
- } from "./chunk-HFUVAHII.js";
8
+ } from "./chunk-APP6Y2D7.js";
9
9
  import {
10
10
  reportBootMilestone
11
11
  } from "./chunk-GL2DIQEQ.js";
@@ -16,7 +16,7 @@ import {
16
16
  } from "./chunk-W4LZ7R6Z.js";
17
17
  import {
18
18
  getWorkbenchClient
19
- } from "./chunk-EXQ6AHOY.js";
19
+ } from "./chunk-TOTCEWJD.js";
20
20
  import {
21
21
  workbenchEnabled
22
22
  } from "./chunk-KMB3BU4S.js";
@@ -20,7 +20,7 @@ import {
20
20
  import {
21
21
  WorkbenchError,
22
22
  getWorkbenchClient
23
- } from "./chunk-EXQ6AHOY.js";
23
+ } from "./chunk-TOTCEWJD.js";
24
24
  import {
25
25
  workbenchEnabled
26
26
  } from "./chunk-KMB3BU4S.js";
@@ -2548,6 +2548,7 @@ export {
2548
2548
  statWorkspacePath,
2549
2549
  workspacePathExists,
2550
2550
  GIT_TIMEOUT_MS,
2551
+ git,
2551
2552
  updateRemoteToken,
2552
2553
  verifyGitCredential,
2553
2554
  forceFreshMintBlocked,
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  loadPtySpawn
3
- } from "./chunk-W6VILPQE.js";
3
+ } from "./chunk-JG3VMWRQ.js";
4
4
  import {
5
5
  terminateProcessGroup
6
6
  } from "./chunk-W4LZ7R6Z.js";
@@ -99,6 +99,19 @@ function handleConnection(socket, opts, liveOps) {
99
99
  });
100
100
  socket.on("data", (chunk) => reader.push(chunk));
101
101
  }
102
+ async function runRefreshSkills(socket, opts) {
103
+ const empty = { t: "refreshSkills", filled: [], shadowed: [], stale: [] };
104
+ try {
105
+ writeFrame(socket, await opts.refreshSkills?.() ?? empty);
106
+ } catch (err) {
107
+ writeFrame(socket, {
108
+ t: "error",
109
+ message: err instanceof Error ? err.message : String(err),
110
+ code: errCode(err)
111
+ });
112
+ }
113
+ socket.end();
114
+ }
102
115
  function dispatch(socket, req, sink, opts, liveOps) {
103
116
  if (!req || typeof req !== "object" || !timingSafeTokenEqual(req.token ?? "", opts.token)) {
104
117
  writeFrame(socket, { t: "error", message: "unauthorized", code: "unauthorized" });
@@ -114,6 +127,9 @@ function dispatch(socket, req, sink, opts, liveOps) {
114
127
  writeFrame(socket, opts.getGitStatus?.() ?? { t: "gitStatus", state: "ready" });
115
128
  socket.end();
116
129
  return;
130
+ case "refreshSkills":
131
+ void runRefreshSkills(socket, opts);
132
+ return;
117
133
  case "exec":
118
134
  runExec(socket, req, sink, liveOps);
119
135
  return;
@@ -200,7 +200,7 @@ async function loadPtySpawn() {
200
200
  async function resolvePtySpawn() {
201
201
  const { workbenchEnabled } = await import("./mode-ZJSOSLGU.js");
202
202
  if (!workbenchEnabled()) return loadPtySpawn();
203
- const { getWorkbenchClient } = await import("./client-IG6C5F2G.js");
203
+ const { getWorkbenchClient } = await import("./client-6AUPKKMV.js");
204
204
  return (file, args, options) => getWorkbenchClient().spawnPty(file, args, options);
205
205
  }
206
206
  function sessionTempBase() {
@@ -1,7 +1,8 @@
1
1
  import {
2
2
  mapChatHistory,
3
- readAgentVersion
4
- } from "./chunk-XORJ6SII.js";
3
+ readAgentVersion,
4
+ refreshSkillsAfterCheckout
5
+ } from "./chunk-SR66HQKB.js";
5
6
  import {
6
7
  MAX_BETWEEN_TURN_BUFFER,
7
8
  MAX_DIAGNOSTIC_OUTPUT,
@@ -28,7 +29,7 @@ import {
28
29
  spawnOptionsFingerprint,
29
30
  transcriptSize,
30
31
  turnOptionsFrom
31
- } from "./chunk-W6VILPQE.js";
32
+ } from "./chunk-JG3VMWRQ.js";
32
33
  import {
33
34
  AgentConnection,
34
35
  CodespacePortVisibility,
@@ -44,6 +45,7 @@ import {
44
45
  forceFreshCooldownNotice,
45
46
  forceFreshMintBlocked,
46
47
  getCurrentBranch,
48
+ git,
47
49
  hasUncommittedChanges,
48
50
  hasUnpushedCommits,
49
51
  pushToOrigin,
@@ -57,7 +59,7 @@ import {
57
59
  statWorkspacePath,
58
60
  updateRemoteToken,
59
61
  verifyGitCredential
60
- } from "./chunk-HFUVAHII.js";
62
+ } from "./chunk-APP6Y2D7.js";
61
63
  import {
62
64
  registerBootMilestoneSocketFallback,
63
65
  reportBootMilestone
@@ -78,7 +80,7 @@ import {
78
80
  } from "./chunk-IA45XHOA.js";
79
81
  import {
80
82
  getWorkbenchClient
81
- } from "./chunk-EXQ6AHOY.js";
83
+ } from "./chunk-TOTCEWJD.js";
82
84
  import {
83
85
  workbenchEnabled
84
86
  } from "./chunk-KMB3BU4S.js";
@@ -232,7 +234,7 @@ var EXTERNAL_AGENT_MESSAGE_SOURCE = "external_agent";
232
234
  var DEFAULT_SONNET_MODEL = "claude-sonnet-5";
233
235
  var DEFAULT_OPUS_MODEL = "claude-opus-5";
234
236
  var DEFAULT_HAIKU_MODEL = "claude-haiku-4-5-20251001";
235
- var FABLE_MODEL = "claude-fable-5";
237
+ var FABLE_MODEL = "claude-fable-5-1";
236
238
  var PREVIOUS_SONNET_MODEL = "claude-sonnet-4-6";
237
239
  var PREVIOUS_OPUS_MODEL = "claude-opus-4-8";
238
240
  var PTY_STREAM_PORT_BASE = 7420;
@@ -1938,7 +1940,7 @@ var ANTHROPIC_CATALOG = [
1938
1940
  anthropicEntry(PREVIOUS_SONNET_MODEL, "Sonnet 4.6", 3, 15),
1939
1941
  // The Haiku line (4.5 and older) predates the tuning surface and 400s on it.
1940
1942
  anthropicEntry(DEFAULT_HAIKU_MODEL, "Haiku 4.5", 1, 5, { supportsEffort: false }),
1941
- anthropicEntry(FABLE_MODEL, "Fable 5 (experimental)", 10, 50, { experimental: true })
1943
+ anthropicEntry(FABLE_MODEL, "Fable 5.1", 10, 50)
1942
1944
  ];
1943
1945
  var HUMAN_PROSE_WRITING_STYLE = `## Writing style for humans
1944
1946
  When you write prose a person will read \u2014 chat messages, plan updates, PR titles and bodies, PR review guides (the \`publish_review_guide\` overview and section explanations), review comments \u2014 follow these rules (based on ASD-STE100 Simplified Technical English):
@@ -4342,7 +4344,7 @@ function seedWorkspaceTrust(config, trustCwd) {
4342
4344
  var FABLE_MODEL_OPTION = {
4343
4345
  value: `${FABLE_MODEL}[1m]`,
4344
4346
  label: "Fable",
4345
- description: "Fable 5 - most capable for your hardest and longest-running tasks"
4347
+ description: "Fable 5.1 - most capable for your hardest and longest-running tasks"
4346
4348
  };
4347
4349
  function seedFableModelOption(config) {
4348
4350
  const cache = Array.isArray(config.additionalModelOptionsCache) ? config.additionalModelOptionsCache : [];
@@ -15188,6 +15190,7 @@ var SessionRunner = class _SessionRunner {
15188
15190
  process.stderr.write("[conveyor-agent] WARNING: task-branch checkout failed\n");
15189
15191
  }
15190
15192
  if (ok) void reportBootMilestone({ key: "branch_ready" });
15193
+ await this.refreshSkillsForCheckout();
15191
15194
  }
15192
15195
  if (!this.stopped) {
15193
15196
  this.lifecycle.startGitFlush();
@@ -15247,6 +15250,40 @@ var SessionRunner = class _SessionRunner {
15247
15250
  await this.run();
15248
15251
  }
15249
15252
  // ── Core loop ──────────────────────────────────────────────────────
15253
+ /**
15254
+ * Re-run the skill floor against the tree `ensureOnTaskBranch` just produced.
15255
+ *
15256
+ * Split-mode pods keep the repo in the WORKBENCH container, so this routes
15257
+ * over the launcher: running it in-process here would materialize skills into
15258
+ * the AGENT container's own copy of /workspaces/repo — still on the base
15259
+ * branch, already complete — and look like it worked while Claude spawned on
15260
+ * the untouched real tree. Codespaces/local (no workbench) run it directly.
15261
+ *
15262
+ * Best-effort by design: a failure warns and boot continues, exactly like the
15263
+ * pre-ready binds it repeats.
15264
+ */
15265
+ async refreshSkillsForCheckout() {
15266
+ const write = (msg) => void process.stderr.write(`[conveyor-agent] ${msg}
15267
+ `);
15268
+ try {
15269
+ const result = workbenchEnabled() ? await getWorkbenchClient().refreshSkills() : await refreshSkillsAfterCheckout(
15270
+ this.config.workspaceDir,
15271
+ async (args, opts) => ({
15272
+ stdout: await git(opts?.cwd ?? this.config.workspaceDir, args, opts?.timeoutMs)
15273
+ }),
15274
+ { info: write, warn: write, error: write }
15275
+ );
15276
+ const { filled, shadowed, stale } = result;
15277
+ if (filled.length + shadowed.length + stale.length === 0) return;
15278
+ write(
15279
+ `post-checkout skill refresh: filled=[${filled.join(", ")}] shadowed=[${shadowed.join(", ")}] unusable=[${stale.join(", ")}]`
15280
+ );
15281
+ } catch (err) {
15282
+ write(
15283
+ `WARNING: post-checkout skill refresh failed: ${err instanceof Error ? err.message : String(err)}`
15284
+ );
15285
+ }
15286
+ }
15250
15287
  // oxlint-disable-next-line complexity -- dormant idle paths add branches but are tightly coupled to the loop
15251
15288
  async coreLoop() {
15252
15289
  while (!this.stopped) {
@@ -0,0 +1,464 @@
1
+ import {
2
+ redactToken
3
+ } from "./chunk-GL2DIQEQ.js";
4
+
5
+ // src/boot/graphify.ts
6
+ var USER_HOME_MOUNT = "/mnt/conveyor-users";
7
+ function computeGraphifyEnv(env, repoName, dirExists) {
8
+ if (env.CONVEYOR_GRAPHIFY_DISABLE === "1") {
9
+ return {};
10
+ }
11
+ const slug = env.CONVEYOR_GRAPHIFY_SLUG || repoName;
12
+ if (!slug) {
13
+ return {};
14
+ }
15
+ const primaryRoot = `${USER_HOME_MOUNT}/users/_shared/graphify`;
16
+ const legacyRoot = `${USER_HOME_MOUNT}/_shared/graphify`;
17
+ let sharedRoot = env.CONVEYOR_GRAPHIFY_SHARED_ROOT;
18
+ if (!sharedRoot) {
19
+ sharedRoot = dirExists(primaryRoot) || !dirExists(legacyRoot) ? primaryRoot : legacyRoot;
20
+ }
21
+ const dir = env.CONVEYOR_GRAPHIFY_DIR || `${sharedRoot}/${slug}/latest`;
22
+ const graph = env.CONVEYOR_GRAPHIFY_GRAPH || `${dir}/graph.json`;
23
+ return {
24
+ CONVEYOR_GRAPHIFY_SLUG: slug,
25
+ CONVEYOR_GRAPHIFY_SHARED_ROOT: sharedRoot,
26
+ CONVEYOR_GRAPHIFY_DIR: dir,
27
+ CONVEYOR_GRAPHIFY_GRAPH: graph
28
+ };
29
+ }
30
+
31
+ // src/runner/session-runner-helpers.ts
32
+ import { readFileSync } from "fs";
33
+ import { dirname, join } from "path";
34
+ import { fileURLToPath } from "url";
35
+ function mapChatHistory(messages) {
36
+ if (!messages) return [];
37
+ return messages.map((m) => ({
38
+ id: m.id,
39
+ role: m.role ?? "user",
40
+ content: m.content ?? "",
41
+ userId: m.userId,
42
+ userName: m.user?.name ?? void 0,
43
+ createdAt: m.createdAt,
44
+ ...m.source ? { source: m.source } : {},
45
+ ...m.files && m.files.length > 0 ? {
46
+ files: m.files.map((f) => ({
47
+ fileId: f.id,
48
+ fileName: f.fileName,
49
+ mimeType: f.mimeType,
50
+ fileSize: f.fileSize,
51
+ downloadUrl: f.downloadUrl ?? "",
52
+ content: f.content,
53
+ contentEncoding: f.contentEncoding
54
+ }))
55
+ } : {}
56
+ }));
57
+ }
58
+ function readAgentVersion() {
59
+ try {
60
+ const here = dirname(fileURLToPath(import.meta.url));
61
+ for (const rel of ["../package.json", "../../package.json"]) {
62
+ try {
63
+ const pkg = JSON.parse(readFileSync(join(here, rel), "utf-8"));
64
+ if (pkg.version) return pkg.version;
65
+ } catch {
66
+ }
67
+ }
68
+ } catch {
69
+ }
70
+ return null;
71
+ }
72
+
73
+ // src/boot/workspace-extras.ts
74
+ import {
75
+ appendFileSync,
76
+ cpSync,
77
+ existsSync,
78
+ lstatSync,
79
+ mkdirSync,
80
+ readdirSync,
81
+ readFileSync as readFileSync2,
82
+ readlinkSync,
83
+ renameSync,
84
+ rmSync,
85
+ statSync,
86
+ symlinkSync
87
+ } from "fs";
88
+ import { dirname as dirname2, join as join2 } from "path";
89
+ import { fileURLToPath as fileURLToPath2 } from "url";
90
+ function errText(err) {
91
+ return redactToken(err instanceof Error ? err.message : String(err));
92
+ }
93
+ function isDir(path) {
94
+ try {
95
+ return statSync(path).isDirectory();
96
+ } catch {
97
+ return false;
98
+ }
99
+ }
100
+ function isSymlink(path) {
101
+ try {
102
+ return lstatSync(path).isSymbolicLink();
103
+ } catch {
104
+ return false;
105
+ }
106
+ }
107
+ function isDanglingSymlink(path) {
108
+ return !existsSync(path) && isSymlink(path);
109
+ }
110
+ var GRAPHIFY_BUNDLE_FILES = [
111
+ "graph.json",
112
+ "GRAPH_REPORT.md",
113
+ "manifest.json",
114
+ ".graphify_analysis.json",
115
+ ".graphify_labels.json",
116
+ "publish-manifest.json",
117
+ "cost.json"
118
+ ];
119
+ function bindGraphifyBundle(workspace, graphifyEnv, log) {
120
+ const slug = graphifyEnv.CONVEYOR_GRAPHIFY_SLUG;
121
+ const sourceDir = graphifyEnv.CONVEYOR_GRAPHIFY_DIR;
122
+ const graphFile = graphifyEnv.CONVEYOR_GRAPHIFY_GRAPH;
123
+ if (!slug || !sourceDir || !graphFile) return;
124
+ if (!existsSync(graphFile)) {
125
+ log.info(`[boot] Graphify bundle not found for '${slug}' at ${sourceDir}`);
126
+ return;
127
+ }
128
+ const targetDir = join2(workspace, "graphify-out");
129
+ try {
130
+ mkdirSync(targetDir, { recursive: true });
131
+ } catch {
132
+ log.warn(`[boot] WARN: unable to create graphify-out at ${targetDir}`);
133
+ return;
134
+ }
135
+ for (const rel of GRAPHIFY_BUNDLE_FILES) {
136
+ const source = join2(sourceDir, rel);
137
+ const target = join2(targetDir, rel);
138
+ if (!existsSync(source)) continue;
139
+ if (existsSync(target) || isSymlink(target)) continue;
140
+ try {
141
+ symlinkSync(source, target);
142
+ } catch {
143
+ }
144
+ }
145
+ log.info(`[boot] Bound graphify bundle '${slug}' into ${targetDir}`);
146
+ }
147
+ async function ensureGrimoireSubmodule(workspace, githubToken, git, log) {
148
+ try {
149
+ if (!existsSync(join2(workspace, ".gitmodules"))) return;
150
+ let paths = "";
151
+ try {
152
+ ({ stdout: paths } = await git(
153
+ ["config", "--file", ".gitmodules", "--get-regexp", String.raw`submodule\..*\.path`],
154
+ { cwd: workspace, timeoutMs: 1e4 }
155
+ ));
156
+ } catch {
157
+ return;
158
+ }
159
+ if (!paths.split("\n").some((line) => line.trim().endsWith(".claude/grimoire"))) return;
160
+ if (isDir(join2(workspace, ".claude", "grimoire", "skills"))) return;
161
+ if (!githubToken) {
162
+ log.warn("[boot] WARN: grimoire submodule absent and no token to fetch it");
163
+ return;
164
+ }
165
+ try {
166
+ await git(
167
+ [
168
+ "-c",
169
+ `url.https://x-access-token:${githubToken}@github.com/.insteadOf=https://github.com/`,
170
+ "submodule",
171
+ "update",
172
+ "--init",
173
+ ".claude/grimoire"
174
+ ],
175
+ { cwd: workspace, timeoutMs: 3e5 }
176
+ );
177
+ log.info("[boot] Initialized grimoire submodule");
178
+ } catch (err) {
179
+ log.warn(
180
+ `[boot] WARN: grimoire submodule init failed (baked pods may lack rc-* skills): ${errText(err)}`
181
+ );
182
+ }
183
+ } catch (err) {
184
+ log.warn(`[boot] WARN: grimoire submodule check failed: ${errText(err)}`);
185
+ }
186
+ }
187
+ function excludeLinkedSkills(workspace, names, log) {
188
+ if (names.length === 0) return;
189
+ const infoDir = join2(workspace, ".git", "info");
190
+ if (!isDir(join2(workspace, ".git"))) return;
191
+ try {
192
+ mkdirSync(infoDir, { recursive: true });
193
+ const excludePath = join2(infoDir, "exclude");
194
+ const existing = existsSync(excludePath) ? readFileSync2(excludePath, "utf8") : "";
195
+ const missing = names.map((name) => `.claude/skills/${name}`).filter((line) => !existing.split("\n").includes(line));
196
+ if (missing.length === 0) return;
197
+ const prefix = existing.length > 0 && !existing.endsWith("\n") ? "\n" : "";
198
+ appendFileSync(excludePath, `${prefix}${missing.join("\n")}
199
+ `);
200
+ } catch (err) {
201
+ log.warn(`[boot] WARN: unable to exclude grimoire skill links: ${errText(err)}`);
202
+ }
203
+ }
204
+ function symlinkTargetsGrimoire(path) {
205
+ try {
206
+ return readlinkSync(path).includes(join2("grimoire", "skills"));
207
+ } catch {
208
+ return false;
209
+ }
210
+ }
211
+ function linkGrimoireSkills(workspace, log) {
212
+ const sourceDir = join2(workspace, ".claude", "grimoire", "skills");
213
+ const targetDir = join2(workspace, ".claude", "skills");
214
+ if (!isDir(sourceDir)) return;
215
+ try {
216
+ mkdirSync(targetDir, { recursive: true });
217
+ } catch {
218
+ log.warn(`[boot] WARN: unable to create ${targetDir}; skipping grimoire skill links`);
219
+ return;
220
+ }
221
+ const linkedNames = [];
222
+ let names = [];
223
+ try {
224
+ names = readdirSync(sourceDir);
225
+ } catch {
226
+ return;
227
+ }
228
+ for (const name of names) {
229
+ if (!isDir(join2(sourceDir, name))) continue;
230
+ const target = join2(targetDir, name);
231
+ if (existsSync(target) && !isSymlink(target)) {
232
+ log.warn(`[boot] WARN: ${target} exists and is not a symlink; skipping`);
233
+ continue;
234
+ }
235
+ if (isSymlink(target) && !symlinkTargetsGrimoire(target)) continue;
236
+ try {
237
+ rmSync(target, { force: true });
238
+ symlinkSync(join2("..", "grimoire", "skills", name), target);
239
+ linkedNames.push(name);
240
+ } catch {
241
+ }
242
+ }
243
+ excludeLinkedSkills(workspace, linkedNames, log);
244
+ log.info(`[boot] Linked ${linkedNames.length} grimoire skills into ${targetDir}`);
245
+ }
246
+ function bundledSkillsDir(moduleUrl = import.meta.url) {
247
+ try {
248
+ const dir = join2(dirname2(fileURLToPath2(moduleUrl)), "..", "skills");
249
+ return isDir(dir) ? dir : null;
250
+ } catch {
251
+ return null;
252
+ }
253
+ }
254
+ var EMPTY_MATERIALIZE = { filled: [], shadowed: [], stale: [] };
255
+ async function hideShadowedPins(workspace, names, git, log) {
256
+ if (names.length === 0) return;
257
+ const paths = names.map((name) => `.claude/skills/${name}`);
258
+ if (!git) {
259
+ log.warn(
260
+ `[boot] WARN: replaced skill pin(s) ${names.join(", ")} stay visible to git (no git runner supplied)`
261
+ );
262
+ return;
263
+ }
264
+ try {
265
+ await git(["update-index", "--assume-unchanged", ...paths], {
266
+ cwd: workspace,
267
+ timeoutMs: 1e4
268
+ });
269
+ } catch (err) {
270
+ log.warn(`[boot] WARN: unable to hide replaced skill pins from git: ${errText(err)}`);
271
+ }
272
+ }
273
+ function readlinkOr(path) {
274
+ try {
275
+ return readlinkSync(path);
276
+ } catch {
277
+ return "unknown target";
278
+ }
279
+ }
280
+ function fillOneSkill(sourceDir, targetDir, name, log) {
281
+ if (!isDir(join2(sourceDir, name))) return null;
282
+ const target = join2(targetDir, name);
283
+ const dangling = isDanglingSymlink(target);
284
+ if (!dangling && (existsSync(target) || isSymlink(target))) return null;
285
+ if (!dangling) {
286
+ try {
287
+ cpSync(join2(sourceDir, name), target, { recursive: true, dereference: true });
288
+ return "filled";
289
+ } catch {
290
+ return null;
291
+ }
292
+ }
293
+ log.warn(
294
+ `[boot] WARN: repo skill '${name}' pointed at a missing target (${readlinkOr(target)}); shadowing it with this agent build's bundled copy`
295
+ );
296
+ const staging = join2(targetDir, `.${name}.conveyor-staging`);
297
+ try {
298
+ rmSync(staging, { recursive: true, force: true });
299
+ cpSync(join2(sourceDir, name), staging, { recursive: true, dereference: true });
300
+ rmSync(target, { force: true });
301
+ renameSync(staging, target);
302
+ return "shadowed";
303
+ } catch (err) {
304
+ try {
305
+ rmSync(staging, { recursive: true, force: true });
306
+ } catch {
307
+ }
308
+ log.warn(
309
+ `[boot] WARN: could not replace dangling skill pin '${name}' (${errText(err)}) \u2014 it stays unusable in this session's skill registry`
310
+ );
311
+ return "stale";
312
+ }
313
+ }
314
+ function reportStalePins(targetDir, bundled, log) {
315
+ let present = [];
316
+ try {
317
+ present = readdirSync(targetDir);
318
+ } catch {
319
+ return [];
320
+ }
321
+ const stale = present.filter(
322
+ (name) => !bundled.has(name) && isDanglingSymlink(join2(targetDir, name))
323
+ );
324
+ for (const name of stale) {
325
+ log.warn(
326
+ `[boot] WARN: repo skill '${name}' is a dangling pin and this agent build has no bundled copy \u2014 it will not appear in the session's skill registry`
327
+ );
328
+ }
329
+ return stale;
330
+ }
331
+ async function materializeBundledSkills(workspace, log, sourceDirOverride, git) {
332
+ const sourceDir = sourceDirOverride === void 0 ? bundledSkillsDir() : sourceDirOverride;
333
+ if (!sourceDir) {
334
+ log.warn(
335
+ "[boot] WARN: no bundled skills payload in this agent build. Cloud modes that invoke a skill will have no workflow to follow. This is a packaging fault (tsup copySkillsPayload did not run), not a workspace problem."
336
+ );
337
+ return EMPTY_MATERIALIZE;
338
+ }
339
+ const targetDir = join2(workspace, ".claude", "skills");
340
+ try {
341
+ mkdirSync(targetDir, { recursive: true });
342
+ } catch {
343
+ log.warn(`[boot] WARN: unable to create ${targetDir}; skipping bundled skills`);
344
+ return EMPTY_MATERIALIZE;
345
+ }
346
+ const filled = [];
347
+ const shadowed = [];
348
+ const unreplaced = [];
349
+ let names = [];
350
+ try {
351
+ names = readdirSync(sourceDir);
352
+ } catch {
353
+ return EMPTY_MATERIALIZE;
354
+ }
355
+ for (const name of names) {
356
+ const outcome = fillOneSkill(sourceDir, targetDir, name, log);
357
+ if (outcome === "filled") filled.push(name);
358
+ else if (outcome === "shadowed") shadowed.push(name);
359
+ else if (outcome === "stale") unreplaced.push(name);
360
+ }
361
+ const stale = [...unreplaced, ...reportStalePins(targetDir, new Set(names), log)];
362
+ excludeLinkedSkills(workspace, [...filled, ...shadowed], log);
363
+ await hideShadowedPins(workspace, shadowed, git, log);
364
+ log.info(
365
+ `[boot] Materialized ${filled.length} bundled skills into ${targetDir}` + (shadowed.length > 0 ? `; replaced ${shadowed.length} dangling pin(s)` : "") + (stale.length > 0 ? `; ${stale.length} dangling pin(s) left unusable` : "")
366
+ );
367
+ return { filled, shadowed, stale };
368
+ }
369
+ function refreshSkillsAfterCheckout(workspace, git, log, sourceDirOverride) {
370
+ linkGrimoireSkills(workspace, log);
371
+ return materializeBundledSkills(workspace, log, sourceDirOverride, git);
372
+ }
373
+ async function neutralizeGrimoirePointer(workspace, git, log) {
374
+ if (!existsSync(join2(workspace, ".claude", "grimoire"))) return;
375
+ try {
376
+ await git(["update-index", "--assume-unchanged", ".claude/grimoire"], {
377
+ cwd: workspace,
378
+ timeoutMs: 1e4
379
+ });
380
+ log.info("[boot] Marked .claude/grimoire assume-unchanged (submodule pointer drift is noise)");
381
+ } catch (err) {
382
+ log.warn(`[boot] WARN: grimoire assume-unchanged failed: ${errText(err)}`);
383
+ }
384
+ }
385
+ function parseReferenceRepos(refsJson) {
386
+ let parsed;
387
+ try {
388
+ parsed = JSON.parse(refsJson);
389
+ } catch {
390
+ return [];
391
+ }
392
+ if (!Array.isArray(parsed)) return [];
393
+ const refs = [];
394
+ for (const entry of parsed) {
395
+ if (typeof entry !== "object" || entry === null) continue;
396
+ const raw = entry;
397
+ const str = (key) => typeof raw[key] === "string" ? raw[key] : "";
398
+ const ref = {
399
+ slug: str("slug"),
400
+ owner: str("owner"),
401
+ name: str("name"),
402
+ branch: str("branch") || "main",
403
+ token: str("token")
404
+ };
405
+ if (ref.token && ref.slug && ref.owner && ref.name) refs.push(ref);
406
+ }
407
+ return refs;
408
+ }
409
+ async function runPreReadyBinds(workspace, bundle, git, log) {
410
+ const graphifyEnv = computeGraphifyEnv(process.env, bundle.gitPlan.repoName, isDir);
411
+ bindGraphifyBundle(workspace, graphifyEnv, log);
412
+ await ensureGrimoireSubmodule(workspace, bundle.githubToken ?? "", git, log);
413
+ linkGrimoireSkills(workspace, log);
414
+ await materializeBundledSkills(workspace, log, void 0, git);
415
+ await neutralizeGrimoirePointer(workspace, git, log);
416
+ }
417
+ async function cloneReferenceRepos(refsJson, git, log, referencesDir = "/workspaces/references") {
418
+ if (!refsJson) return;
419
+ const refs = parseReferenceRepos(refsJson);
420
+ if (refs.length === 0) return;
421
+ try {
422
+ mkdirSync(referencesDir, { recursive: true });
423
+ } catch {
424
+ return;
425
+ }
426
+ for (const ref of refs) {
427
+ const dest = join2(referencesDir, ref.slug);
428
+ if (existsSync(join2(dest, ".git"))) continue;
429
+ try {
430
+ await git(
431
+ [
432
+ "clone",
433
+ "--depth",
434
+ "1",
435
+ "--single-branch",
436
+ "--branch",
437
+ ref.branch,
438
+ `https://x-access-token:${ref.token}@github.com/${ref.owner}/${ref.name}.git`,
439
+ dest
440
+ ],
441
+ { timeoutMs: 6e5 }
442
+ );
443
+ try {
444
+ await git(
445
+ ["remote", "set-url", "origin", `https://github.com/${ref.owner}/${ref.name}.git`],
446
+ { cwd: dest, timeoutMs: 1e4 }
447
+ );
448
+ } catch {
449
+ }
450
+ log.info(`[boot] cloned reference ${ref.slug} (${ref.owner}/${ref.name}@${ref.branch})`);
451
+ } catch {
452
+ log.warn(`[boot] WARN: reference clone failed: ${ref.slug}`);
453
+ }
454
+ }
455
+ }
456
+
457
+ export {
458
+ computeGraphifyEnv,
459
+ refreshSkillsAfterCheckout,
460
+ runPreReadyBinds,
461
+ cloneReferenceRepos,
462
+ mapChatHistory,
463
+ readAgentVersion
464
+ };
@@ -138,6 +138,24 @@ var WorkbenchClient = class {
138
138
  );
139
139
  });
140
140
  }
141
+ /** Ask the workbench — which owns the repo filesystem in split mode — to
142
+ * re-run the skill floor after the agent's authoritative task-branch
143
+ * checkout. A daemon without a provider answers an empty result. */
144
+ refreshSkills() {
145
+ return new Promise((resolve, reject) => {
146
+ let result = null;
147
+ this.open(
148
+ { op: "refreshSkills" },
149
+ (frame) => {
150
+ if (frame.t === "refreshSkills") result = frame;
151
+ },
152
+ (error) => {
153
+ if (result) resolve(result);
154
+ else reject(error ?? new WorkbenchError("connection closed before refreshSkills"));
155
+ }
156
+ );
157
+ });
158
+ }
141
159
  /** Mirrors setup/commands.ts runSetupCommand (shell form, streamed output,
142
160
  * abort → graceful term-group kill, non-zero exit rejects). */
143
161
  runSetupCommand(cmd, cwd, onOutput, signal) {
package/dist/cli.js CHANGED
@@ -7,7 +7,7 @@ import {
7
7
  WorkspaceCommandSupervisor,
8
8
  startWorkspaceCommandsAfterConnect,
9
9
  stopWorkspaceCommands
10
- } from "./chunk-UHMCBCQL.js";
10
+ } from "./chunk-43XITDZP.js";
11
11
  import {
12
12
  DEFAULT_SONNET_MODEL,
13
13
  PtyHarness,
@@ -27,13 +27,13 @@ import {
27
27
  resolveTuiKindFromEnv,
28
28
  runUsageProbe,
29
29
  sampleKeyUsage
30
- } from "./chunk-GUYMLASA.js";
31
- import "./chunk-XORJ6SII.js";
30
+ } from "./chunk-SKTCDL4K.js";
31
+ import "./chunk-SR66HQKB.js";
32
32
  import {
33
33
  inheritedEnv,
34
34
  resolvePtySpawn,
35
35
  sessionTempBase
36
- } from "./chunk-W6VILPQE.js";
36
+ } from "./chunk-JG3VMWRQ.js";
37
37
  import {
38
38
  AgentConnection,
39
39
  CodespacePortVisibility,
@@ -44,12 +44,12 @@ import {
44
44
  createServiceLogger,
45
45
  fetchBootstrap,
46
46
  loadConveyorConfig
47
- } from "./chunk-HFUVAHII.js";
47
+ } from "./chunk-APP6Y2D7.js";
48
48
  import "./chunk-GL2DIQEQ.js";
49
49
  import "./chunk-W4LZ7R6Z.js";
50
50
  import "./chunk-7P6QZHXZ.js";
51
51
  import "./chunk-IA45XHOA.js";
52
- import "./chunk-EXQ6AHOY.js";
52
+ import "./chunk-TOTCEWJD.js";
53
53
  import "./chunk-KMB3BU4S.js";
54
54
  import "./chunk-6Q6LQBWO.js";
55
55
 
@@ -1201,7 +1201,7 @@ function wireSpawnChildren(mode, connection, supervisors, logger7) {
1201
1201
 
1202
1202
  // src/cli.ts
1203
1203
  if (process.argv[2] === "boot") {
1204
- const { runBoot } = await import("./boot-7XH4FFLO.js");
1204
+ const { runBoot } = await import("./boot-ZE6BM7L2.js");
1205
1205
  process.exit(await runBoot(process.argv.slice(3)));
1206
1206
  }
1207
1207
  if (isLegacyEntrypointLaunch(process.env)) {
@@ -1303,7 +1303,7 @@ process.on("unhandledRejection", (reason) => {
1303
1303
  process.exit(1);
1304
1304
  });
1305
1305
  if (process.env.CONVEYOR_MODE === "workbench") {
1306
- const { startWorkbenchServer } = await import("./server-2Z5V3IPA.js");
1306
+ const { startWorkbenchServer } = await import("./server-2IZBKD3Q.js");
1307
1307
  const { oomWatchdogOptionsFromEnv } = await import("./oom-watchdog-PAC5OJJG.js");
1308
1308
  const { DEFAULT_WORKBENCH_PORT } = await import("./protocol-QBCYO4GI.js");
1309
1309
  const port = Number(process.env.CONVEYOR_WORKBENCH_PORT) || DEFAULT_WORKBENCH_PORT;
@@ -1454,7 +1454,7 @@ if (!RUNNER_MODES.includes(CONVEYOR_MODE)) {
1454
1454
  process.exit(1);
1455
1455
  }
1456
1456
  if (CONVEYOR_MODE === "serving") {
1457
- const { runServingSession } = await import("./serve-boot-IFUIGFEH.js");
1457
+ const { runServingSession } = await import("./serve-boot-ESZKFN5M.js");
1458
1458
  exitContext.runnerMode = "serving";
1459
1459
  exitContext.sessionId = process.env.CONVEYOR_SESSION_ID ?? exitContext.sessionId;
1460
1460
  const outcome = await runServingSession({
@@ -4,7 +4,7 @@ import {
4
4
  WorkbenchError,
5
5
  getWorkbenchClient,
6
6
  resetWorkbenchClient
7
- } from "./chunk-EXQ6AHOY.js";
7
+ } from "./chunk-TOTCEWJD.js";
8
8
  import "./chunk-KMB3BU4S.js";
9
9
  import "./chunk-6Q6LQBWO.js";
10
10
  export {
package/dist/index.d.ts CHANGED
@@ -851,6 +851,19 @@ declare class SessionRunner {
851
851
  run(): Promise<void>;
852
852
  /** Convenience wrapper: connect() then run(). */
853
853
  start(): Promise<void>;
854
+ /**
855
+ * Re-run the skill floor against the tree `ensureOnTaskBranch` just produced.
856
+ *
857
+ * Split-mode pods keep the repo in the WORKBENCH container, so this routes
858
+ * over the launcher: running it in-process here would materialize skills into
859
+ * the AGENT container's own copy of /workspaces/repo — still on the base
860
+ * branch, already complete — and look like it worked while Claude spawned on
861
+ * the untouched real tree. Codespaces/local (no workbench) run it directly.
862
+ *
863
+ * Best-effort by design: a failure warns and boot continues, exactly like the
864
+ * pre-ready binds it repeats.
865
+ */
866
+ private refreshSkillsForCheckout;
854
867
  private coreLoop;
855
868
  /**
856
869
  * Handle dormant-after-completed idle. Returns true if a critical message
package/dist/index.js CHANGED
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  SessionRunner,
3
3
  unshallowRepo
4
- } from "./chunk-GUYMLASA.js";
5
- import "./chunk-XORJ6SII.js";
6
- import "./chunk-W6VILPQE.js";
4
+ } from "./chunk-SKTCDL4K.js";
5
+ import "./chunk-SR66HQKB.js";
6
+ import "./chunk-JG3VMWRQ.js";
7
7
  import {
8
8
  AgentConnection,
9
9
  GIT_TIMEOUT_MS,
@@ -17,7 +17,7 @@ import {
17
17
  stageAndCommit,
18
18
  updateRemoteToken,
19
19
  workspacePathExists
20
- } from "./chunk-HFUVAHII.js";
20
+ } from "./chunk-APP6Y2D7.js";
21
21
  import "./chunk-GL2DIQEQ.js";
22
22
  import {
23
23
  runAuthTokenCommand,
@@ -28,7 +28,7 @@ import "./chunk-7P6QZHXZ.js";
28
28
  import "./chunk-IA45XHOA.js";
29
29
  import {
30
30
  getWorkbenchClient
31
- } from "./chunk-EXQ6AHOY.js";
31
+ } from "./chunk-TOTCEWJD.js";
32
32
  import {
33
33
  workbenchEnabled
34
34
  } from "./chunk-KMB3BU4S.js";
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  WorkspaceCommandSupervisor
3
- } from "./chunk-UHMCBCQL.js";
3
+ } from "./chunk-43XITDZP.js";
4
4
  import {
5
5
  AgentConnection,
6
6
  CodespacePortVisibility,
@@ -11,11 +11,11 @@ import {
11
11
  createServiceLogger,
12
12
  ensureOnTaskBranch,
13
13
  loadConveyorConfig
14
- } from "./chunk-HFUVAHII.js";
14
+ } from "./chunk-APP6Y2D7.js";
15
15
  import "./chunk-GL2DIQEQ.js";
16
16
  import "./chunk-W4LZ7R6Z.js";
17
17
  import "./chunk-IA45XHOA.js";
18
- import "./chunk-EXQ6AHOY.js";
18
+ import "./chunk-TOTCEWJD.js";
19
19
  import "./chunk-KMB3BU4S.js";
20
20
  import "./chunk-6Q6LQBWO.js";
21
21
 
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  startWorkbenchServer
3
- } from "./chunk-D57S4UR5.js";
4
- import "./chunk-W6VILPQE.js";
3
+ } from "./chunk-IBAIJY7V.js";
4
+ import "./chunk-JG3VMWRQ.js";
5
5
  import "./chunk-W4LZ7R6Z.js";
6
6
  import "./chunk-6Q6LQBWO.js";
7
7
  import "./chunk-6W6UZ4SJ.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rallycry/conveyor-agent",
3
- "version": "11.0.6",
3
+ "version": "11.0.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",
@@ -38,7 +38,7 @@
38
38
  "typecheck": "tsgo --noEmit"
39
39
  },
40
40
  "dependencies": {
41
- "@anthropic-ai/claude-agent-sdk": "^0.3.246",
41
+ "@anthropic-ai/claude-agent-sdk": "^0.3.257",
42
42
  "@modelcontextprotocol/sdk": "^1.30.0",
43
43
  "node-pty": "^1.0.0",
44
44
  "socket.io-client": "^4.8.3",
@@ -1,46 +0,0 @@
1
- // src/runner/session-runner-helpers.ts
2
- import { readFileSync } from "fs";
3
- import { dirname, join } from "path";
4
- import { fileURLToPath } from "url";
5
- function mapChatHistory(messages) {
6
- if (!messages) return [];
7
- return messages.map((m) => ({
8
- id: m.id,
9
- role: m.role ?? "user",
10
- content: m.content ?? "",
11
- userId: m.userId,
12
- userName: m.user?.name ?? void 0,
13
- createdAt: m.createdAt,
14
- ...m.source ? { source: m.source } : {},
15
- ...m.files && m.files.length > 0 ? {
16
- files: m.files.map((f) => ({
17
- fileId: f.id,
18
- fileName: f.fileName,
19
- mimeType: f.mimeType,
20
- fileSize: f.fileSize,
21
- downloadUrl: f.downloadUrl ?? "",
22
- content: f.content,
23
- contentEncoding: f.contentEncoding
24
- }))
25
- } : {}
26
- }));
27
- }
28
- function readAgentVersion() {
29
- try {
30
- const here = dirname(fileURLToPath(import.meta.url));
31
- for (const rel of ["../package.json", "../../package.json"]) {
32
- try {
33
- const pkg = JSON.parse(readFileSync(join(here, rel), "utf-8"));
34
- if (pkg.version) return pkg.version;
35
- } catch {
36
- }
37
- }
38
- } catch {
39
- }
40
- return null;
41
- }
42
-
43
- export {
44
- mapChatHistory,
45
- readAgentVersion
46
- };