@tekmidian/pai 0.37.0 → 0.38.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.
@@ -12,7 +12,7 @@ import { a as schedulerLogPath, i as paiSocketPath, n as daemonLogPath, r as dae
12
12
  import { t as PaiClient } from "./ipc-client-BmypMNYk.mjs";
13
13
  import { a as expandHome, c as UNROUTED, i as ensureConfigDir, n as CONFIG_FILE$2, o as loadConfig, s as OWNER_LABEL_PREFIX, t as CONFIG_DIR } from "./config-B64vFg14.mjs";
14
14
  import { r as humanDuration, t as createStorageBackend } from "./factory-DD2T33C9.mjs";
15
- import { A as readJsonStrict, C as loadStatus, D as workersLogDir, E as ledgerPath, O as WorkersConfigError, S as openPaneForWorker, T as eventsPath, _ as stopProxy, a as setRole, b as checkPaneForWorker, c as useProvider, d as replayOutput, f as statusLineOutput, g as ensureProxyRunning, h as DEFAULT_PROXY_PORT, i as setProviderEnabled, j as writeJsonAtomic, k as readWorkersSection, l as followWorkers, m as testProvider, n as describeProviders, o as setWorkersEnabled, p as runWorker, r as removeProvider, s as unsetRole, t as addProvider, u as psOutput, v as sayToWorker, x as openFollowPane, y as describeMcp } from "./providers-sXcK5bDZ.mjs";
15
+ import { A as ledgerPath, C as checkPaneForWorker, E as loadStatus, F as readJsonStrict, I as writeJsonAtomic, M as PROVIDER_TAGS, N as WorkersConfigError, O as parseRunnerArgs, P as readWorkersSection, S as describeMcp, T as openPaneForWorker, _ as testProvider, a as setClass, b as stopProxy, c as unsetClass, d as followWorkers, f as psOutput, g as runWorker, h as runChain, i as removeProvider, j as workersLogDir, k as eventsPath, l as updateProvider, m as statusLineOutput, n as classTargetText, o as setProviderEnabled, p as replayOutput, r as describeProviders, s as setWorkersEnabled, t as addProvider, u as useProvider, v as DEFAULT_PROXY_PORT, w as openFollowPane, x as sayToWorker, y as ensureProxyRunning } from "./providers-DUshcB-d.mjs";
16
16
  import { s as kgQuery } from "./kg-entity-r8duqhi9.mjs";
17
17
  import { _ as scanSessions, a as renderDedupedSessions, c as probeResume, d as callAiBroker, f as fetchLiveSessions, g as resolveSessionByNameOrId, h as fmtAge, i as normalizeName$2, l as restoreTopLevel, m as sendToSession, o as hasConversation, p as revealItermSession, r as buildDeduped, s as launchInDir, t as cmdMain, u as printExitDir } from "./main-resolver-DlaLOFBA.mjs";
18
18
  import { appendFileSync, chmodSync, copyFileSync, createReadStream, existsSync, lstatSync, mkdirSync, readFileSync, readdirSync, readlinkSync, realpathSync, renameSync, statSync, symlinkSync, unlinkSync, writeFileSync } from "node:fs";
@@ -6253,7 +6253,7 @@ async function stepWorkers(rl) {
6253
6253
  return { workers: {
6254
6254
  enabled: false,
6255
6255
  providers: {},
6256
- roles: {}
6256
+ classes: {}
6257
6257
  } };
6258
6258
  }
6259
6259
  line$1();
@@ -6265,14 +6265,14 @@ async function stepWorkers(rl) {
6265
6265
  line$1(c.dim(" --key-file ~/.config/example/api_key \\"));
6266
6266
  line$1(c.dim(" --model example-4.7 --fast-model example-4.7-flash"));
6267
6267
  line$1();
6268
- line$1(" The first provider turns workers on and seeds the roles.");
6268
+ line$1(" The first provider turns workers on and seeds the classes.");
6269
6269
  line$1();
6270
6270
  const r = installWorkers();
6271
6271
  for (const l of r.lines) line$1(` ${l}`);
6272
6272
  return { workers: {
6273
6273
  enabled: false,
6274
6274
  providers: {},
6275
- roles: {}
6275
+ classes: {}
6276
6276
  } };
6277
6277
  }
6278
6278
 
@@ -13577,6 +13577,99 @@ function registerSessionCommands(sessionCmd, getDb) {
13577
13577
  });
13578
13578
  }
13579
13579
 
13580
+ //#endregion
13581
+ //#region src/workers/agents.ts
13582
+ /**
13583
+ * agents.ts — run agent definitions (~/.claude/agents/<name>.md) as workers.
13584
+ *
13585
+ * The file format is the Claude Code agent one: YAML front matter (`model`,
13586
+ * `tools`, `description`) followed by a Markdown body that is the agent's
13587
+ * system prompt. `pai worker run --agent <name>` loads it and maps it onto
13588
+ * the worker runner:
13589
+ *
13590
+ * - body → --append-system-prompt (prepended, so an explicit caller
13591
+ * flag still wins);
13592
+ * - tools → --allowedTools;
13593
+ * - model → a task class (haiku→simple, sonnet→implement, opus→complex),
13594
+ * unless --class is given.
13595
+ */
13596
+ /** Directory the agent library lives in. */
13597
+ function agentsDir() {
13598
+ return join(homedir(), ".claude", "agents");
13599
+ }
13600
+ function agentPath(name) {
13601
+ return join(agentsDir(), `${name}.md`);
13602
+ }
13603
+ /** `key: value` (bare) or `key: [a, b]` / `key:\n - a\n - b` (list). */
13604
+ function parseFrontMatter(text) {
13605
+ const out = {};
13606
+ let key = "";
13607
+ for (const raw of text.split("\n")) {
13608
+ const listItem = /^\s+-\s+(.*)$/.exec(raw);
13609
+ if (listItem && key) {
13610
+ const cur = out[key];
13611
+ const item = listItem[1].trim().replace(/^["']|["']$/g, "");
13612
+ out[key] = Array.isArray(cur) ? [...cur, item] : [item];
13613
+ continue;
13614
+ }
13615
+ const kv = /^([A-Za-z0-9_-]+):\s*(.*)$/.exec(raw);
13616
+ if (!kv) continue;
13617
+ key = kv[1];
13618
+ const val = kv[2].trim();
13619
+ if (!val) out[key] = [];
13620
+ else if (val.startsWith("[") && val.endsWith("]")) out[key] = val.slice(1, -1).split(",").map((s) => s.trim().replace(/^["']|["']$/g, "")).filter(Boolean);
13621
+ else out[key] = val.replace(/^["']|["']$/g, "");
13622
+ }
13623
+ return out;
13624
+ }
13625
+ /** Parse an agent file's text (front matter + body). Throws on empty body. */
13626
+ function parseAgentFile(name, text, path) {
13627
+ const m = /^---\n([\s\S]*?)\n---\n?([\s\S]*)$/.exec(text);
13628
+ if (!m) throw new Error(`${path}: expected YAML front matter (--- … ---) before the agent body`);
13629
+ const fm = parseFrontMatter(m[1]);
13630
+ const body = m[2].trim();
13631
+ if (!body) throw new Error(`${path}: the agent body (after the front matter) is empty`);
13632
+ const def = {
13633
+ name,
13634
+ body,
13635
+ path
13636
+ };
13637
+ if (typeof fm.model === "string" && fm.model) def.model = fm.model;
13638
+ if (Array.isArray(fm.tools) && fm.tools.length) def.tools = fm.tools;
13639
+ if (typeof fm.description === "string" && fm.description) def.description = fm.description;
13640
+ return def;
13641
+ }
13642
+ /** Load ~/.claude/agents/<name>.md; the error names the library when missing. */
13643
+ function loadAgent(name) {
13644
+ const path = agentPath(name);
13645
+ let text;
13646
+ try {
13647
+ text = readFileSync(path, "utf8");
13648
+ } catch {
13649
+ throw new Error(`no agent named "${name}" at ${path}. The agent library lives in ~/.claude/agents/<name>.md and runs on workers.`);
13650
+ }
13651
+ return parseAgentFile(name, text, path);
13652
+ }
13653
+ /** Map an agent's front-matter model to a worker class. */
13654
+ function modelToClass(model) {
13655
+ if (!model) return void 0;
13656
+ const m = model.toLowerCase();
13657
+ if (m.includes("haiku")) return "simple";
13658
+ if (m.includes("sonnet")) return "implement";
13659
+ if (m.includes("opus")) return "complex";
13660
+ }
13661
+ /** Extra claude args the definition contributes (before the caller's own). */
13662
+ function agentClaudeArgs(def) {
13663
+ const args = [];
13664
+ if (def.tools?.length) args.push("--allowedTools", def.tools.join(","));
13665
+ args.push("--append-system-prompt", def.body);
13666
+ return args;
13667
+ }
13668
+ /** `<agent>: <first 50 chars of prompt>` — the default label for a run. */
13669
+ function agentLabel(name, prompt) {
13670
+ return `${name}: ${prompt ?? "(no prompt)"}`.slice(0, name.length + 2 + 50);
13671
+ }
13672
+
13580
13673
  //#endregion
13581
13674
  //#region src/cli/commands/worker/providers.ts
13582
13675
  function fail$1(e) {
@@ -13599,14 +13692,37 @@ function parseIntArg$1(v) {
13599
13692
  if (Number.isNaN(n) || n <= 0) throw new WorkersConfigError(`expected a positive number, got "${v}"`);
13600
13693
  return n;
13601
13694
  }
13602
- /** `glm/fast` | `{provider, mcp}` → one printable target line. */
13603
- function roleTargetText(target) {
13604
- if (typeof target === "string") return target;
13605
- if (typeof target === "object" && target !== null) {
13606
- const t = target;
13607
- return `${t.provider ?? "?"}${t.mcp?.length ? ` +mcp(${t.mcp.join(",")})` : ""}`;
13695
+ function parseCostTier(v) {
13696
+ const n = parseInt(v, 10);
13697
+ if (!Number.isInteger(n) || n < 1 || n > 5) throw new WorkersConfigError(`cost tier must be an integer 1 (cheapest) … 5 (most expensive), got "${v}"`);
13698
+ return n;
13699
+ }
13700
+ /** `--tags a,b` (repeatable) validated tag list. */
13701
+ function collectTags(vals) {
13702
+ const out = [];
13703
+ for (const v of vals ?? []) for (const t of v.split(",").map((s) => s.trim()).filter(Boolean)) {
13704
+ if (!PROVIDER_TAGS.includes(t)) throw new WorkersConfigError(`"${t}" is not a tag (from: ${PROVIDER_TAGS.join(", ")})`);
13705
+ if (!out.includes(t)) out.push(t);
13608
13706
  }
13609
- return String(target);
13707
+ return out;
13708
+ }
13709
+ /** Positional target + constraint flags → a ClassTarget for setClass. */
13710
+ function buildClassTarget(target, opts) {
13711
+ const hasConstraints = opts.provider !== void 0 || opts.mcp !== void 0 || opts.maxCostTier !== void 0 || opts.requireTags !== void 0 || opts.order !== void 0;
13712
+ if (target !== void 0 && !hasConstraints) return target;
13713
+ const obj = {};
13714
+ if (target !== void 0) obj.provider = target.split("/")[0];
13715
+ if (opts.provider !== void 0) obj.provider = opts.provider;
13716
+ if (opts.mcp !== void 0) obj.mcp = opts.mcp.split(",").map((s) => s.trim()).filter(Boolean);
13717
+ if (opts.maxCostTier !== void 0) obj.maxCostTier = opts.maxCostTier;
13718
+ if (opts.requireTags !== void 0) obj.requireTags = opts.requireTags;
13719
+ if (opts.order !== void 0) obj.order = opts.order.split(",").map((s) => s.trim()).filter(Boolean);
13720
+ if (target !== void 0 && target.includes("/") && obj.provider) {
13721
+ const alias = target.split("/")[1];
13722
+ if (alias && alias !== "default") throw new WorkersConfigError(`a provider alias ("${alias}") cannot be combined with constraint flags — use the plain "<target>" form for pinning`);
13723
+ }
13724
+ if (!Object.keys(obj).length) throw new WorkersConfigError("give a target (provider, provider/fast) or a constraint (--max-cost-tier, --require-tags, …)");
13725
+ return obj;
13610
13726
  }
13611
13727
  function registerWorkerProviderCommands(providersCmd) {
13612
13728
  providersCmd.description("Providers: list (default), add, remove, use, enable, disable, test").action(() => {
@@ -13617,13 +13733,14 @@ function registerWorkerProviderCommands(providersCmd) {
13617
13733
  console.log(dim$1(` workers are ${workers.enabled ? "on" : "off"} — pai worker ${workers.enabled ? "off" : "on"}`));
13618
13734
  console.log();
13619
13735
  });
13620
- providersCmd.command("add <name>").description("Add a provider; the first one also turns workers on and seeds roles.\nExample: pai worker providers add glm --base-url https://…/anthropic \\\n --key-file ~/.config/zai/api_key --model glm-5.3 --fast-model glm-5.3-flash\nOpenAI-protocol: --protocol openai --upstream-url https://…/v1 (runs via the PAI proxy).\nCodex (ChatGPT plan): --engine codex — runs through the Codex CLI.").option("--base-url <url>", "Anthropic-compatible API base URL (required unless --protocol openai)").requiredOption("--model <model>", "Default model id for this provider").option("--key-file <path>", "File holding the API token (0600); omit for token \"local\"").option("--fast-model <model>", "Cheaper model for spotchecks and routing").option("--env <name=value>", "Extra env for runs (repeatable)", (v, acc) => [...acc, v], []).option("--note <text>", "Human note shown in `providers list`").option("--protocol <proto>", "anthropic (default) or openai — openai runs through the local PAI proxy").option("--upstream-url <url>", "Chat Completions base URL (required for --protocol openai)").option("--engine <engine>", "claude (default) or codex — codex runs `codex exec --json`").option("--context-window <tokens>", "Context window for the meter (default 200000; init event overrides)", parseIntArg$1).option("--quota-probe <url>", "URL whose JSON first number is the quota percent (0-100)").action((name, opts) => {
13736
+ providersCmd.command("add <name>").description("Add a provider; the first one also turns workers on and seeds classes.\nExample: pai worker providers add glm --base-url https://…/anthropic \\\n --key-file ~/.config/zai/api_key --model glm-5.3 --fast-model glm-5.3-flash\nOpenAI-protocol: --protocol openai --upstream-url https://…/v1 (runs via the PAI proxy).\nCodex (ChatGPT plan): --engine codex — runs through the Codex CLI.").option("--base-url <url>", "Anthropic-compatible API base URL (required unless --protocol openai)").requiredOption("--model <model>", "Default model id for this provider").option("--key-file <path>", "File holding the API token (0600); omit for token \"local\"").option("--fast-model <model>", "Cheaper model for spotchecks and routing").option("--env <name=value>", "Extra env for runs (repeatable)", (v, acc) => [...acc, v], []).option("--note <text>", "Human note shown in `providers list`").option("--protocol <proto>", "anthropic (default) or openai — openai runs through the local PAI proxy").option("--upstream-url <url>", "Chat Completions base URL (required for --protocol openai)").option("--engine <engine>", "claude (default) or codex — codex runs `codex exec --json`").option("--context-window <tokens>", "Context window for the meter (default 200000; init event overrides)", parseIntArg$1).option("--quota-probe <url>", "URL whose JSON first number is the quota percent (0-100)").option("--cost-tier <1-5>", "Cost tier 1 (cheapest) … 5 (most expensive; default 3)", parseCostTier).option("--tags <tags>", "Capability tags, comma-separated (from: " + PROVIDER_TAGS.join(", ") + ")", (v, acc) => [...acc, v], []).action((name, opts) => {
13621
13737
  try {
13622
13738
  const protocol = opts.protocol;
13623
13739
  const engine = opts.engine;
13624
13740
  if (protocol && protocol !== "anthropic" && protocol !== "openai") throw new WorkersConfigError(`--protocol must be anthropic or openai, got "${protocol}"`);
13625
13741
  if (engine && engine !== "claude" && engine !== "codex") throw new WorkersConfigError(`--engine must be claude or codex, got "${engine}"`);
13626
13742
  if (protocol !== "openai" && !opts.baseUrl) throw new WorkersConfigError("--base-url is required (only --protocol openai goes without it)");
13743
+ const tags = collectTags(opts.tags);
13627
13744
  addProvider({
13628
13745
  name,
13629
13746
  baseUrl: opts.baseUrl ?? "",
@@ -13636,7 +13753,9 @@ function registerWorkerProviderCommands(providersCmd) {
13636
13753
  ...opts.upstreamUrl ? { upstreamUrl: opts.upstreamUrl } : {},
13637
13754
  ...engine ? { engine } : {},
13638
13755
  ...opts.contextWindow ? { contextWindow: opts.contextWindow } : {},
13639
- quotaProbe: opts.quotaProbe
13756
+ quotaProbe: opts.quotaProbe,
13757
+ ...opts.costTier !== void 0 ? { costTier: opts.costTier } : {},
13758
+ ...tags.length ? { tags } : {}
13640
13759
  });
13641
13760
  const { workers } = readWorkersSection();
13642
13761
  console.log(ok$1(`provider ${name} added`));
@@ -13646,7 +13765,22 @@ function registerWorkerProviderCommands(providersCmd) {
13646
13765
  fail$1(e);
13647
13766
  }
13648
13767
  });
13649
- providersCmd.command("remove <name>").description("Remove a provider and any roles pointing at it").action((name) => {
13768
+ providersCmd.command("update <name>").description("Change cost tier and tags of a provider (routing constraints use these)").option("--cost-tier <1-5>", "Cost tier 1 (cheapest) … 5 (most expensive)", parseCostTier).option("--tags <tags>", "Capability tags, comma-separated (from: " + PROVIDER_TAGS.join(", ") + "); --tags '' clears", (v, acc) => [...acc, v], []).action((name, opts) => {
13769
+ try {
13770
+ if (opts.costTier === void 0 && opts.tags === void 0) throw new WorkersConfigError("nothing to update — pass --cost-tier and/or --tags");
13771
+ const tags = opts.tags === void 0 ? void 0 : collectTags(opts.tags);
13772
+ updateProvider(name, {
13773
+ ...opts.costTier !== void 0 ? { costTier: opts.costTier } : {},
13774
+ ...tags !== void 0 ? { tags } : {}
13775
+ });
13776
+ console.log(ok$1(`provider ${name} updated`));
13777
+ const { workers } = readWorkersSection();
13778
+ for (const line of describeProviders(workers)) console.log(dim$1(` ${line}`));
13779
+ } catch (e) {
13780
+ fail$1(e);
13781
+ }
13782
+ });
13783
+ providersCmd.command("remove <name>").description("Remove a provider and any classes pointing at it").action((name) => {
13650
13784
  try {
13651
13785
  removeProvider(name);
13652
13786
  console.log(ok$1(`provider ${name} removed`));
@@ -13654,7 +13788,7 @@ function registerWorkerProviderCommands(providersCmd) {
13654
13788
  fail$1(e);
13655
13789
  }
13656
13790
  });
13657
- providersCmd.command("use <name>").description("Make this provider the active one for runs without --provider/--role").action((name) => {
13791
+ providersCmd.command("use <name>").description("Make this provider the active one for runs without --provider/--class").action((name) => {
13658
13792
  try {
13659
13793
  useProvider(name);
13660
13794
  console.log(ok$1(`active provider: ${name}`));
@@ -13699,43 +13833,40 @@ function registerWorkerProviderCommands(providersCmd) {
13699
13833
  }
13700
13834
  });
13701
13835
  }
13702
- /** `pai worker roles` — role → provider[/fast] assignment. */
13703
- function registerWorkerRoleCommands(workerCmd) {
13704
- const rolesCmd = workerCmd.command("roles").description("Roles: which provider serves implement / research / spotcheck").action(() => {
13705
- const { workers } = readWorkersSection();
13706
- const entries = Object.entries(workers.roles);
13707
- if (!entries.length) {
13708
- console.log(dim$1(" no roles set — runs use the active provider"));
13709
- return;
13710
- }
13711
- for (const [role, target] of entries) console.log(` ${role.padEnd(12)} ${roleTargetText(target)}`);
13712
- });
13713
- rolesCmd.command("list").description("List roles and their providers (default action)").action(() => {
13714
- const { workers } = readWorkersSection();
13715
- const entries = Object.entries(workers.roles);
13716
- if (!entries.length) {
13717
- console.log(dim$1(" no roles set — runs use the active provider"));
13718
- return;
13719
- }
13720
- for (const [role, target] of entries) console.log(` ${role.padEnd(12)} ${roleTargetText(target)}`);
13721
- });
13722
- rolesCmd.command("set <role> <provider[/alias]>").description("Point a role at a provider, optionally its fast model (e.g. glm/fast)").action((role, target) => {
13836
+ function printClasses() {
13837
+ const { workers } = readWorkersSection();
13838
+ const entries = Object.entries(workers.classes);
13839
+ if (!entries.length) {
13840
+ console.log(dim$1(" no classes set — runs use the active provider (or auto routing)"));
13841
+ return;
13842
+ }
13843
+ for (const [cls, target] of entries) console.log(` ${cls.padEnd(12)} ${classTargetText(target)}`);
13844
+ }
13845
+ function registerClassSubcommands(classesCmd) {
13846
+ classesCmd.command("list").description("List classes and their targets (default action)").action(() => printClasses());
13847
+ classesCmd.command("set <class> [target]").description("Point a class at a provider (or provider/fast), or give only constraints:\nclasses set research --max-cost-tier 2 --require-tags long-context,reasoning").option("--provider <name>", "Pin the class to this provider (object form)").option("--mcp <names>", "MCP servers/sets for runs of this class (comma-separated)").option("--max-cost-tier <1-5>", "Auto-routing considers only providers up to this cost tier", parseCostTier).option("--require-tags <tags>", "Auto-routing needs these tags (comma-separated)", (v) => v.split(",").map((s) => s.trim()).filter(Boolean)).option("--order <providers>", "Per-class routing order overriding workers.routing.order (comma-separated)").action((cls, target, opts) => {
13723
13848
  try {
13724
- setRole(role, target);
13725
- console.log(ok$1(`role ${role} → ${target}`));
13849
+ const built = buildClassTarget(target, opts);
13850
+ setClass(cls, built);
13851
+ console.log(ok$1(`class ${cls} → ${classTargetText(built)}`));
13726
13852
  } catch (e) {
13727
13853
  fail$1(e);
13728
13854
  }
13729
13855
  });
13730
- rolesCmd.command("unset <role>").description("Remove a role (runs then use the active provider)").action((role) => {
13856
+ classesCmd.command("unset <class>").description("Remove a class (runs then use the active provider)").action((cls) => {
13731
13857
  try {
13732
- unsetRole(role);
13733
- console.log(ok$1(`role ${role} removed`));
13858
+ unsetClass(cls);
13859
+ console.log(ok$1(`class ${cls} removed`));
13734
13860
  } catch (e) {
13735
13861
  fail$1(e);
13736
13862
  }
13737
13863
  });
13738
13864
  }
13865
+ /** `pai worker classes` — class → target assignment (roles is the old name). */
13866
+ function registerWorkerClassCommands(workerCmd) {
13867
+ registerClassSubcommands(workerCmd.command("classes").description("Classes: which provider serves draft / implement / review / …").action(() => printClasses()));
13868
+ registerClassSubcommands(workerCmd.command("roles", { hidden: true }).description("Alias of `classes` (roles was renamed to classes)").action(() => printClasses()));
13869
+ }
13739
13870
 
13740
13871
  //#endregion
13741
13872
  //#region src/cli/commands/worker/index.ts
@@ -13749,16 +13880,43 @@ function fail(e) {
13749
13880
  process.exitCode = 1;
13750
13881
  }
13751
13882
  function registerWorkerCommands(workerCmd) {
13752
- workerCmd.command("run").description("Run one claude-code worker through the configured provider.\nUnknown options are passed to claude verbatim (e.g. -p, --allowedTools);\n--output-format/--verbose are handled here.").allowUnknownOption(true).option("--provider <name>", "Provider to run on (default: active, else routing order)").option("--role <role>", "Use the provider of this role (implement, research, spotcheck, )").option("--model <model>", "Override the provider's model for this run").option("--label <text>", "Short task label shown in ps / follow / status line").option("--mcp <names>", "MCP servers/sets this worker may use (comma-separated; see `pai worker mcp`)").option("--no-pane", "Do not open a follow pane for this worker").argument("[args...]", "claude arguments, e.g. -p '<task>' --allowedTools 'Read,Edit,Bash'").action(async (args, opts) => {
13883
+ workerCmd.command("run").description("Run one claude-code worker through the configured provider.\nUnknown options are passed to claude verbatim (e.g. -p, --allowedTools);\n--output-format/--verbose are handled here.\n--chain draft,implement[,review] runs a spec-first pipeline;\n--agent <name> runs an agent definition from ~/.claude/agents.").allowUnknownOption(true).option("--provider <name>", "Provider to run on (default: active, else routing order)").option("--class <name>", "Use the provider of this class (draft, implement, review, research, spotcheck, simple, complex, image)").option("--role <name>", "Alias of --class (roles were renamed to classes)").option("--chain <stages>", "Comma-separated stage classes, e.g. draft,implement or draft,implement,review").option("--agent <name>", "Run the agent definition ~/.claude/agents/<name>.md on a worker").option("--model <model>", "Override the provider's model for this run").option("--label <text>", "Short task label shown in ps / follow / status line").option("--mcp <names>", "MCP servers/sets this worker may use (comma-separated; see `pai worker mcp`)").option("--no-pane", "Do not open a follow pane for this worker").argument("[args...]", "claude arguments, e.g. -p '<task>' --allowedTools 'Read,Edit,Bash'").action(async (args, opts) => {
13753
13884
  try {
13885
+ const className = opts.class ?? opts.role;
13886
+ let claudeArgs = args;
13887
+ let label = opts.label;
13888
+ let agentClass;
13889
+ if (opts.agent) {
13890
+ const def = loadAgent(opts.agent);
13891
+ claudeArgs = [...agentClaudeArgs(def), ...args];
13892
+ agentClass = modelToClass(def.model);
13893
+ if (!label) label = agentLabel(opts.agent, parseRunnerArgs(args).prompt);
13894
+ }
13895
+ if (opts.chain) {
13896
+ const brief = parseRunnerArgs(claudeArgs).prompt;
13897
+ if (!brief) throw new Error("--chain needs the task as -p '<brief>'");
13898
+ const rc = await runChain({
13899
+ stages: opts.chain.split(","),
13900
+ className: className ?? agentClass,
13901
+ providerFlag: opts.provider,
13902
+ modelFlag: opts.model,
13903
+ label,
13904
+ noPane: opts.pane === false,
13905
+ mcpFlag: opts.mcp,
13906
+ brief,
13907
+ claudeArgs
13908
+ });
13909
+ process.exitCode = rc;
13910
+ return;
13911
+ }
13754
13912
  const rc = await runWorker({
13755
13913
  providerFlag: opts.provider,
13756
- role: opts.role,
13914
+ className: className ?? agentClass,
13757
13915
  modelFlag: opts.model,
13758
- label: opts.label,
13916
+ label,
13759
13917
  mcpFlag: opts.mcp,
13760
13918
  noPane: opts.pane === false,
13761
- claudeArgs: args
13919
+ claudeArgs
13762
13920
  });
13763
13921
  process.exitCode = rc;
13764
13922
  } catch (e) {
@@ -13799,13 +13957,13 @@ function registerWorkerCommands(workerCmd) {
13799
13957
  process.exitCode = code ?? 1;
13800
13958
  });
13801
13959
  });
13802
- workerCmd.command("pane [id]").description("Open the follow pane for a worker (or one shared pane for this session)").option("--check", "Only report whether the pane is open, plus the profile file's path and font").action(async (id, opts) => {
13960
+ workerCmd.command("pane [id]").description("Open the follow pane for a worker (or one shared pane for this session)").option("--check", "Only report whether the pane is open, plus the profile file's path, font, and the hosting window's bounds").action(async (id, opts) => {
13803
13961
  try {
13804
13962
  const { workers } = readWorkersSection();
13805
13963
  const logDir = currentLogDir();
13806
13964
  const term = process.env.ITERM_SESSION_ID ?? "";
13807
13965
  if (id) {
13808
- const msg = opts.check ? await checkPaneForWorker(id, workers.pane.fontSize) : await openPaneForWorker(logDir, workers, id, term);
13966
+ const msg = opts.check ? await checkPaneForWorker(id, workers.pane.fontSize, term) : await openPaneForWorker(logDir, workers, id, term);
13809
13967
  console.log(msg);
13810
13968
  } else console.log(await openFollowPane(logDir, workers, term, opts.check === true));
13811
13969
  } catch (e) {
@@ -13955,7 +14113,7 @@ function registerWorkerCommands(workerCmd) {
13955
14113
  }
13956
14114
  });
13957
14115
  registerWorkerProviderCommands(workerCmd.command("providers").description("Providers: list, add, remove, use, enable, disable, test"));
13958
- registerWorkerRoleCommands(workerCmd);
14116
+ registerWorkerClassCommands(workerCmd);
13959
14117
  }
13960
14118
  function parseIntArg(v) {
13961
14119
  const n = parseInt(v, 10);
@@ -15872,4 +16030,4 @@ claude() {
15872
16030
 
15873
16031
  //#endregion
15874
16032
  export { drainStdio as n, buildProgram as t };
15875
- //# sourceMappingURL=program-CEIHn_Ma.mjs.map
16033
+ //# sourceMappingURL=program-Y0hAiVy8.mjs.map