agent-conveyor 0.1.19 → 0.1.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -154,18 +154,36 @@ The GitHub Pages version lives at
154
154
  Use `node scripts/check-landing-page.mjs` for a docs-only desktop/mobile
155
155
  screenshot gate; this does not run the full package release smoke.
156
156
 
157
+ ### Codex Operator Plugin
158
+
159
+ Agent Conveyor also ships Codex-app-only operator scaffolding for visible
160
+ manager/worker sessions from any project. Install the package, then install
161
+ and inspect the plugin:
162
+
163
+ ```bash
164
+ npm install -g agent-conveyor
165
+ conveyor install-plugin
166
+ conveyor plugin-status
167
+ ```
168
+
169
+ The per-project default ledger for operator sessions is
170
+ `.codex-workers/workerctl.db`. The initial included skills are
171
+ `conveyor-create-pair`, `conveyor-create-worker-set`,
172
+ `conveyor-check-status`, and `conveyor-whats-next-nudger`.
173
+
157
174
  After install, the intended Codex app entry point is natural language. Open a
158
175
  new Codex app session in the target repo and say:
159
176
 
160
177
  ```text
161
- Use the manage-codex-workers skill.
178
+ Use the conveyor-create-pair skill.
162
179
 
163
180
  Set up a Codex app Ralph loop for issue CTL.
164
181
  Require adversarial proof before another worker iteration.
165
182
  ```
166
183
 
167
- The installed skill should call the `conveyor` CLI, choose names, create the
168
- no-tmux binding with `create-disposable-binding`, point the worker at
184
+ For multiple workers, start with `Use the conveyor-create-worker-set skill`.
185
+ The installed plugin skill should call the `conveyor` CLI, choose names, create
186
+ the no-tmux binding with `create-disposable-binding`, point the worker at
169
187
  `worker-inbox`, and use `loop-status` plus telemetry receipts before reporting
170
188
  that the loop is ready. When the manager is itself running in the Codex app and
171
189
  thread tools are available, the skill should first call `create_thread` for a
@@ -186,6 +204,9 @@ print `CONVEYOR POLL`, `CONVEYOR RECEIVED`, `WORK`, `CONVEYOR SEND`, and
186
204
  audit proof, not a replacement for the live session story. Idle polls may be a
187
205
  single `CONVEYOR IDLE` line.
188
206
 
207
+ For bounded follow-up passes after the first worker result, use
208
+ `Use the conveyor-whats-next-nudger skill`.
209
+
189
210
  Dispatch is core infrastructure for supervised worker/manager pairs. The
190
211
  `pair` workflow starts a detached Dispatch watch process by default so worker
191
212
  completion is routed to the bound manager mechanically. For manually bound
@@ -171,6 +171,15 @@ export function runTypescriptRuntimeCommand(options) {
171
171
  if (parsed.command === "install-skills") {
172
172
  return runInstallSkillsCommand(parsed, options);
173
173
  }
174
+ if (parsed.command === "plugin-path") {
175
+ return runPluginPathCommand(parsed, options);
176
+ }
177
+ if (parsed.command === "plugin-status") {
178
+ return runPluginStatusCommand(parsed, options);
179
+ }
180
+ if (parsed.command === "install-plugin") {
181
+ return runInstallPluginCommand(parsed, options);
182
+ }
174
183
  if (parsed.command === "bind") {
175
184
  return runBindCommand(parsed, options);
176
185
  }
@@ -1086,7 +1095,7 @@ function parseRuntimeArgs(args, env) {
1086
1095
  index += 1;
1087
1096
  }
1088
1097
  else if (arg === "--codex-home") {
1089
- if (command !== "install-skills") {
1098
+ if (command !== "install-skills" && command !== "install-plugin" && command !== "plugin-status" && command !== "plugin-path") {
1090
1099
  return { command, enabled, error: "Unsupported TypeScript runtime option: --codex-home", explicit, flags, task };
1091
1100
  }
1092
1101
  const value = valueAfter(queue, index, arg);
@@ -6655,7 +6664,7 @@ function runInstallSkillsCommand(parsed, options) {
6655
6664
  if (unsupported) {
6656
6665
  return unsupportedRuntimeResult(parsed, unsupported);
6657
6666
  }
6658
- const codexHome = resolve(expandUserPath(parsed.flags.codexHome ?? options.env?.CODEX_HOME ?? join(homedir(), ".codex")));
6667
+ const codexHome = resolveCodexHome(parsed, options);
6659
6668
  const skills = installableSkillSources();
6660
6669
  const targets = skills.map((skill) => ({
6661
6670
  name: skill.name,
@@ -6687,6 +6696,199 @@ function runInstallSkillsCommand(parsed, options) {
6687
6696
  const lines = targets.map((target) => `${parsed.flags.dryRun ? "would install" : "installed"} ${target.name} skill in ${target.target}`);
6688
6697
  return { exitCode: 0, handled: true, stdout: `${lines.join("\n")}\n` };
6689
6698
  }
6699
+ const AGENT_CONVEYOR_PLUGIN_NAME = "agent-conveyor";
6700
+ const AGENT_CONVEYOR_PLUGIN_SKILLS = [
6701
+ "conveyor-create-pair",
6702
+ "conveyor-create-worker-set",
6703
+ "conveyor-check-status",
6704
+ "conveyor-whats-next-nudger",
6705
+ ];
6706
+ function resolveCodexHome(parsed, options) {
6707
+ return resolve(expandUserPath(parsed.flags.codexHome ?? options.env?.CODEX_HOME ?? join(homedir(), ".codex")));
6708
+ }
6709
+ function packageVersionFromRoot(packageRoot) {
6710
+ const packageJsonPath = join(packageRoot, "package.json");
6711
+ const parsed = JSON.parse(readFileSync(packageJsonPath, "utf8"));
6712
+ if (!isPlainRecord(parsed) || typeof parsed.version !== "string" || parsed.version.length === 0) {
6713
+ throw new Error(`Package version not found in ${packageJsonPath}.`);
6714
+ }
6715
+ return parsed.version;
6716
+ }
6717
+ function pluginPaths(parsed, options) {
6718
+ const codexHome = resolveCodexHome(parsed, options);
6719
+ const packageRoot = packageRootFromRuntimeModule();
6720
+ const packageVersion = packageVersionFromRoot(packageRoot);
6721
+ const pluginCacheRoot = join(codexHome, "plugins", "cache", AGENT_CONVEYOR_PLUGIN_NAME, AGENT_CONVEYOR_PLUGIN_NAME);
6722
+ return {
6723
+ codex_home: codexHome,
6724
+ package_root: packageRoot,
6725
+ plugin_cache_root: pluginCacheRoot,
6726
+ plugin_install_root: join(pluginCacheRoot, packageVersion),
6727
+ plugin_source: join(packageRoot, "plugin", AGENT_CONVEYOR_PLUGIN_NAME),
6728
+ skills_install_root: join(codexHome, "skills"),
6729
+ };
6730
+ }
6731
+ function readAgentConveyorPluginManifest(source) {
6732
+ const manifestPath = join(source, "plugin.json");
6733
+ const parsed = JSON.parse(readFileSync(manifestPath, "utf8"));
6734
+ if (!isPlainRecord(parsed)) {
6735
+ throw new Error(`Agent Conveyor plugin manifest must be a JSON object: ${manifestPath}`);
6736
+ }
6737
+ if (parsed.name !== AGENT_CONVEYOR_PLUGIN_NAME) {
6738
+ throw new Error(`Agent Conveyor plugin manifest name must be "${AGENT_CONVEYOR_PLUGIN_NAME}": ${manifestPath}`);
6739
+ }
6740
+ if (typeof parsed.version !== "string") {
6741
+ throw new Error(`Agent Conveyor plugin manifest is missing a string version: ${manifestPath}`);
6742
+ }
6743
+ return {
6744
+ name: parsed.name,
6745
+ version: parsed.version,
6746
+ skills: Array.isArray(parsed.skills) ? parsed.skills.filter((skill) => typeof skill === "string") : undefined,
6747
+ };
6748
+ }
6749
+ function assertPluginVersionMatchesPackage(manifest, packageVersion) {
6750
+ if (manifest.version !== packageVersion) {
6751
+ throw new Error(`Agent Conveyor plugin version ${manifest.version} does not match package version ${packageVersion}.`);
6752
+ }
6753
+ }
6754
+ function pluginSkillTargets(paths) {
6755
+ return AGENT_CONVEYOR_PLUGIN_SKILLS.map((name) => {
6756
+ const target = join(paths.skills_install_root, name);
6757
+ return {
6758
+ installed: existsSync(join(target, "SKILL.md")),
6759
+ name,
6760
+ source: join(paths.plugin_source, "skills", name),
6761
+ target,
6762
+ };
6763
+ });
6764
+ }
6765
+ function installedAgentConveyorPluginManifest(paths) {
6766
+ const manifestPath = join(paths.plugin_install_root, "plugin.json");
6767
+ if (!existsSync(manifestPath)) {
6768
+ return null;
6769
+ }
6770
+ const parsed = JSON.parse(readFileSync(manifestPath, "utf8"));
6771
+ if (!isPlainRecord(parsed) || parsed.name !== AGENT_CONVEYOR_PLUGIN_NAME || typeof parsed.version !== "string") {
6772
+ return null;
6773
+ }
6774
+ return {
6775
+ name: parsed.name,
6776
+ version: parsed.version,
6777
+ skills: Array.isArray(parsed.skills) ? parsed.skills.filter((skill) => typeof skill === "string") : undefined,
6778
+ };
6779
+ }
6780
+ function agentConveyorPluginStatus(parsed, options) {
6781
+ const paths = pluginPaths(parsed, options);
6782
+ const packageVersion = packageVersionFromRoot(paths.package_root);
6783
+ const manifest = readAgentConveyorPluginManifest(paths.plugin_source);
6784
+ const installedManifest = installedAgentConveyorPluginManifest(paths);
6785
+ const installedVersion = installedManifest?.version ?? null;
6786
+ const skills = pluginSkillTargets(paths);
6787
+ const installed = installedManifest !== null && skills.every((skill) => skill.installed);
6788
+ return {
6789
+ installed,
6790
+ installed_version: installedVersion,
6791
+ package_version: packageVersion,
6792
+ paths,
6793
+ plugin_version: manifest.version,
6794
+ skills,
6795
+ version_matches: installed && installedVersion === packageVersion && manifest.version === packageVersion,
6796
+ };
6797
+ }
6798
+ function unsupportedPluginOptions(parsed) {
6799
+ if (parsed.task !== null) {
6800
+ return `Unexpected argument: ${parsed.task}`;
6801
+ }
6802
+ return null;
6803
+ }
6804
+ function runPluginPathCommand(parsed, options) {
6805
+ const unsupported = unsupportedPluginOptions(parsed);
6806
+ if (unsupported) {
6807
+ return unsupportedRuntimeResult(parsed, unsupported);
6808
+ }
6809
+ const paths = pluginPaths(parsed, options);
6810
+ if (parsed.flags.json) {
6811
+ return jsonResult(paths);
6812
+ }
6813
+ return {
6814
+ exitCode: 0,
6815
+ handled: true,
6816
+ stdout: [
6817
+ `codex_home: ${paths.codex_home}`,
6818
+ `package_root: ${paths.package_root}`,
6819
+ `plugin_cache_root: ${paths.plugin_cache_root}`,
6820
+ `plugin_install_root: ${paths.plugin_install_root}`,
6821
+ `plugin_source: ${paths.plugin_source}`,
6822
+ `skills_install_root: ${paths.skills_install_root}`,
6823
+ "",
6824
+ ].join("\n"),
6825
+ };
6826
+ }
6827
+ function runPluginStatusCommand(parsed, options) {
6828
+ const unsupported = unsupportedPluginOptions(parsed);
6829
+ if (unsupported) {
6830
+ return unsupportedRuntimeResult(parsed, unsupported);
6831
+ }
6832
+ const status = agentConveyorPluginStatus(parsed, options);
6833
+ if (parsed.flags.json) {
6834
+ return jsonResult(status);
6835
+ }
6836
+ const skillLines = status.skills.map((skill) => `skill ${skill.name}: ${skill.installed ? "installed" : "missing"}`);
6837
+ return {
6838
+ exitCode: 0,
6839
+ handled: true,
6840
+ stdout: [
6841
+ `installed: ${status.installed}`,
6842
+ `installed_version: ${status.installed_version ?? "none"}`,
6843
+ `package_version: ${status.package_version}`,
6844
+ `plugin_version: ${status.plugin_version}`,
6845
+ `version_matches: ${status.version_matches}`,
6846
+ ...skillLines,
6847
+ "",
6848
+ ].join("\n"),
6849
+ };
6850
+ }
6851
+ function runInstallPluginCommand(parsed, options) {
6852
+ const unsupported = unsupportedPluginOptions(parsed);
6853
+ if (unsupported) {
6854
+ return unsupportedRuntimeResult(parsed, unsupported);
6855
+ }
6856
+ const paths = pluginPaths(parsed, options);
6857
+ const packageVersion = packageVersionFromRoot(paths.package_root);
6858
+ const manifest = readAgentConveyorPluginManifest(paths.plugin_source);
6859
+ assertPluginVersionMatchesPackage(manifest, packageVersion);
6860
+ const skillTargets = pluginSkillTargets(paths);
6861
+ for (const target of skillTargets) {
6862
+ if (!existsSync(join(target.source, "SKILL.md"))) {
6863
+ throw new Error(`Agent Conveyor plugin skill not found: ${target.source}`);
6864
+ }
6865
+ }
6866
+ if (!parsed.flags.dryRun) {
6867
+ rmSync(paths.plugin_install_root, { force: true, recursive: true });
6868
+ mkdirSync(dirname(paths.plugin_install_root), { recursive: true });
6869
+ cpSync(paths.plugin_source, paths.plugin_install_root, { recursive: true });
6870
+ for (const target of skillTargets) {
6871
+ rmSync(target.target, { force: true, recursive: true });
6872
+ mkdirSync(dirname(target.target), { recursive: true });
6873
+ cpSync(target.source, target.target, { recursive: true });
6874
+ }
6875
+ }
6876
+ const status = agentConveyorPluginStatus(parsed, options);
6877
+ const payload = {
6878
+ ...status,
6879
+ dry_run: parsed.flags.dryRun,
6880
+ installed: status.installed,
6881
+ installed_skills: parsed.flags.dryRun ? [] : skillTargets.map((target) => target.name),
6882
+ };
6883
+ if (parsed.flags.json) {
6884
+ return jsonResult(payload);
6885
+ }
6886
+ const lines = [
6887
+ `${parsed.flags.dryRun ? "would install" : "installed"} ${AGENT_CONVEYOR_PLUGIN_NAME} plugin in ${paths.plugin_install_root}`,
6888
+ ...skillTargets.map((target) => `${parsed.flags.dryRun ? "would install" : "installed"} ${target.name} skill in ${target.target}`),
6889
+ ];
6890
+ return { exitCode: 0, handled: true, stdout: `${lines.join("\n")}\n` };
6891
+ }
6690
6892
  function dashboardLaunchPayload(parsed) {
6691
6893
  const queryParams = new URLSearchParams();
6692
6894
  if (parsed.flags.taskName) {
@@ -15486,6 +15688,9 @@ function isDefaultRuntimeCommand(command) {
15486
15688
  || command === "start-test"
15487
15689
  || command === "dashboard"
15488
15690
  || command === "install-skills"
15691
+ || command === "install-plugin"
15692
+ || command === "plugin-status"
15693
+ || command === "plugin-path"
15489
15694
  || command === "replay"
15490
15695
  || command === "export-task"
15491
15696
  || command === "tasks"