quest-loop 0.3.4 → 0.3.5

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/CHANGELOG.md CHANGED
@@ -6,6 +6,19 @@ All notable changes to this project are documented here. The format follows
6
6
 
7
7
  ## Unreleased
8
8
 
9
+ ## [0.3.5] — 2026-07-08
10
+
11
+ ### Added
12
+ - `quest codex doctor --fix` and `quest claude doctor --fix` now repair
13
+ Quest-owned native-agent templates and provider plugin install/version state,
14
+ then rerun the same doctor checks.
15
+ - `quest codex open` and `quest claude open` now run the provider health gate
16
+ before launching the interactive provider from the project root.
17
+
18
+ ### Changed
19
+ - Stale Quest agent templates are replaced without `--force`; unrelated custom
20
+ files still require explicit replacement.
21
+
9
22
  ## [0.3.4] — 2026-07-08
10
23
 
11
24
  ### Changed
package/README.md CHANGED
@@ -57,8 +57,8 @@ Install Quest's project-scoped Claude agent templates and verify the local
57
57
  Claude setup with:
58
58
 
59
59
  ```bash
60
- quest claude install-agents --scope project
61
- quest claude doctor
60
+ quest claude doctor --fix
61
+ quest claude open
62
62
  ```
63
63
 
64
64
  For local development against a checkout, point Claude Code at the repo directly
@@ -84,16 +84,19 @@ Verify the install with:
84
84
 
85
85
  ```bash
86
86
  codex plugin list --marketplace quest
87
- quest codex install-agents --scope project
88
- quest codex doctor
87
+ quest codex doctor --fix
88
+ quest codex open
89
89
  codex debug prompt-input "noop"
90
90
  ```
91
91
 
92
- `quest codex doctor` checks the installed plugin version, Codex `multi_agent`
93
- support, hook parser, neutral skill roots, and installed native-agent templates.
94
- `codex debug prompt-input "noop"` should not print any hook parse warnings.
92
+ `quest codex doctor --fix` and `quest claude doctor --fix` install or refresh
93
+ Quest-owned native-agent templates and repair the provider plugin install/version
94
+ when the provider CLI supports it, then rerun doctor. `quest codex open` and
95
+ `quest claude open` run the same health gate before launching the interactive
96
+ provider. `codex debug prompt-input "noop"` should not print any hook parse
97
+ warnings.
95
98
 
96
- #### Updating the Codex plugin
99
+ #### Updating provider plugins
97
100
 
98
101
  Codex installs plugins from a marketplace snapshot. Pulling this Git repo or
99
102
  publishing a new tag is not enough to update the already-installed plugin cache.
@@ -103,10 +106,18 @@ Refresh the marketplace snapshot, then reinstall the plugin from it:
103
106
  codex plugin marketplace upgrade quest
104
107
  codex plugin add quest@quest
105
108
  codex plugin list --marketplace quest
106
- quest codex doctor
109
+ quest codex doctor --fix
107
110
  ```
108
111
 
109
- Then start a new Codex thread. If the update contains hook changes, re-run:
112
+ Claude updates through its plugin manager:
113
+
114
+ ```bash
115
+ claude plugin update quest@quest
116
+ quest claude doctor --fix
117
+ ```
118
+
119
+ Then start a new provider session. If the Codex update contains hook changes,
120
+ re-run:
110
121
 
111
122
  ```bash
112
123
  codex debug prompt-input "noop"
@@ -145,8 +156,9 @@ both providers:
145
156
  - `.claude/agents/quest-executor.md`
146
157
  - `.claude/agents/quest-reviewer.md`
147
158
 
148
- Use `quest init --no-agents` when you only want the `.quests/` store. If an
149
- existing project agent template would be replaced, init fails before creating
159
+ Use `quest init --no-agents` when you only want the `.quests/` store. Stale
160
+ Quest-owned agent templates are replaced automatically. If an existing file is
161
+ not recognizable as a Quest agent template, init fails before creating
150
162
  `.quests/`; inspect the conflicting files, run the explicit provider install
151
163
  command with `--force` only if you intend to replace them, then rerun
152
164
  `quest init`.
@@ -238,8 +250,8 @@ full base protocol lives in
238
250
  | `quest amend` | Append a numbered protocol amendment (retro output) |
239
251
  | `quest protocol` | Print the loop protocol + this store's local amendments |
240
252
  | `quest runs` | Show headless runner activity (from `.quests/runs.ndjson`) |
241
- | `quest codex` | Validate Codex-native setup and install Codex native agent templates |
242
- | `quest claude` | Validate Claude-native setup and install Claude native agent templates |
253
+ | `quest codex` | Validate, repair, install, or open Codex-native setup |
254
+ | `quest claude` | Validate, repair, install, or open Claude-native setup |
243
255
 
244
256
  ## quest-run (headless runner)
245
257
 
package/lib/cli.mjs CHANGED
@@ -5,13 +5,14 @@ import { parseArgs } from "node:util";
5
5
  import { readFileSync, existsSync, writeFileSync, appendFileSync } from "node:fs";
6
6
  import { join, dirname } from "node:path";
7
7
  import { fileURLToPath } from "node:url";
8
+ import { spawnSync } from "node:child_process";
8
9
  import { ConfigError, findStoreDir, loadConfig } from "./config.mjs";
9
10
  import { ContractError, lintRecord } from "./contract.mjs";
10
11
  import * as local from "./store-local.mjs";
11
12
  import * as github from "./store-github.mjs";
12
13
  import { openStore } from "./store.mjs";
13
14
  import { COMMANDS, renderCommandHelp, renderGeneralHelp, renderInitNextSteps, renderNoStore, renderStatusOverview } from "./help.mjs";
14
- import { claudeDoctor, doctor as codexDoctor, installAgents as installCodexAgents, installClaudeAgents, versionInfo } from "./codex-native.mjs";
15
+ import { claudeDoctor, claudeDoctorFix, codexDoctorFix, doctor as codexDoctor, installAgents as installCodexAgents, installClaudeAgents, nativeProjectRoot, versionInfo } from "./codex-native.mjs";
15
16
 
16
17
  const PLUGIN_ROOT = join(dirname(fileURLToPath(import.meta.url)), "..");
17
18
 
@@ -92,28 +93,87 @@ function preflightInitAgentInstall(cwd, env) {
92
93
  return plans;
93
94
  }
94
95
 
95
- async function runNativeSetupCommand(command, args, { out, cwd, env }, { label, doctor, install }) {
96
+ function printDoctorResult(command, result, out) {
97
+ if (result.repairs?.length) {
98
+ out(`${command} doctor --fix: repairs`);
99
+ for (const r of result.repairs) out(` ${r.ok ? "OK " : "ERR"} ${r.name}: ${r.command} (${r.detail})`);
100
+ }
101
+ for (const c of result.checks) out(`${c.ok ? "OK " : "ERR"} ${c.name}: ${c.detail}`);
102
+ out(result.ok ? `${command} doctor: OK` : `${command} doctor: problems found`);
103
+ }
104
+
105
+ function parseOpenArgs(args) {
106
+ const forwarded = [];
107
+ let dryRun = false;
108
+ for (let i = 0; i < args.length; i += 1) {
109
+ const arg = args[i];
110
+ if (arg === "--") {
111
+ forwarded.push(...args.slice(i + 1));
112
+ break;
113
+ }
114
+ if (arg === "--dry-run") {
115
+ dryRun = true;
116
+ continue;
117
+ }
118
+ if (arg === "--help" || arg === "-h") return { help: true };
119
+ forwarded.push(arg);
120
+ }
121
+ return { dryRun, forwarded };
122
+ }
123
+
124
+ function shellQuote(arg) {
125
+ return /^[A-Za-z0-9_./:=@+-]+$/.test(arg) ? arg : `'${String(arg).replaceAll("'", "'\\''")}'`;
126
+ }
127
+
128
+ function openInvocation(command, cwd, env, forwarded) {
129
+ const root = nativeProjectRoot(cwd, env);
130
+ if (command === "codex") return { cmd: "codex", args: ["-C", root, ...forwarded], cwd };
131
+ if (command === "claude") return { cmd: "claude", args: forwarded, cwd: root };
132
+ throw new Error(`unknown provider "${command}"`);
133
+ }
134
+
135
+ async function runNativeSetupCommand(command, args, { out, cwd, env }, { label, doctor, doctorFix, install }) {
96
136
  const [subcommand, ...rest] = args;
97
137
  if (!subcommand || subcommand === "help" || subcommand === "--help" || subcommand === "-h") {
98
138
  out(renderCommandHelp(command));
99
139
  return 0;
100
140
  }
101
141
  if (subcommand === "doctor") {
102
- const p = parse(command, rest, {}, { positionals: 0 });
142
+ const p = parse(command, rest, { fix: { type: "boolean" } }, { positionals: 0 });
103
143
  if (p.help) {
104
144
  out(renderCommandHelp(command));
105
145
  return 0;
106
146
  }
107
- const result = doctor({ cwd, env });
147
+ const result = p.values.fix ? doctorFix({ cwd, env }) : doctor({ cwd, env });
108
148
  if (p.values.json) out(JSON.stringify(result));
109
- else {
110
- for (const c of result.checks) out(`${c.ok ? "OK " : "ERR"} ${c.name}: ${c.detail}`);
111
- out(result.ok ? `${command} doctor: OK` : `${command} doctor: problems found`);
112
- }
149
+ else printDoctorResult(command, result, out);
113
150
  // 1 (generic diagnostic failure), not 5 — exit 5 is reserved for
114
151
  // ContractError (a quest contract violation), which a doctor finding is not.
115
152
  return result.ok ? 0 : 1;
116
153
  }
154
+ if (subcommand === "open") {
155
+ const p = parseOpenArgs(rest);
156
+ if (p.help) {
157
+ out(renderCommandHelp(command));
158
+ return 0;
159
+ }
160
+ const result = doctorFix({ cwd, env });
161
+ if (!result.ok) {
162
+ printDoctorResult(command, result, out);
163
+ out(`${command} open: not launching because doctor still reports problems`);
164
+ return 1;
165
+ }
166
+ const invocation = openInvocation(command, cwd, env, p.forwarded);
167
+ const rendered = [invocation.cmd, ...invocation.args].map(shellQuote).join(" ");
168
+ if (p.dryRun) {
169
+ out(`${command} open: health OK`);
170
+ out(`Would run: ${rendered}`);
171
+ return 0;
172
+ }
173
+ out(`${command} open: health OK; launching ${rendered}`);
174
+ const res = spawnSync(invocation.cmd, invocation.args, { cwd: invocation.cwd, env, stdio: "inherit" });
175
+ return typeof res.status === "number" ? res.status : 1;
176
+ }
117
177
  if (subcommand === "install-agents") {
118
178
  const p = parse(command, rest, {
119
179
  scope: { type: "string", default: "project" },
@@ -536,10 +596,10 @@ const HANDLERS = {
536
596
  },
537
597
 
538
598
  async codex(args, { out, cwd, env }) {
539
- return runNativeSetupCommand("codex", args, { out, cwd, env }, { label: "Codex", doctor: codexDoctor, install: installCodexAgents });
599
+ return runNativeSetupCommand("codex", args, { out, cwd, env }, { label: "Codex", doctor: codexDoctor, doctorFix: codexDoctorFix, install: installCodexAgents });
540
600
  },
541
601
 
542
602
  async claude(args, { out, cwd, env }) {
543
- return runNativeSetupCommand("claude", args, { out, cwd, env }, { label: "Claude", doctor: claudeDoctor, install: installClaudeAgents });
603
+ return runNativeSetupCommand("claude", args, { out, cwd, env }, { label: "Claude", doctor: claudeDoctor, doctorFix: claudeDoctorFix, install: installClaudeAgents });
544
604
  },
545
605
  };
@@ -9,6 +9,7 @@ import { fileURLToPath } from "node:url";
9
9
 
10
10
  const PLUGIN_ROOT = join(dirname(fileURLToPath(import.meta.url)), "..");
11
11
  const AGENTS = ["quest-executor", "quest-reviewer"];
12
+ const QUEST_CODEX_MARKETPLACE_SOURCE = ["roberts", "reberski/quest"].join("");
12
13
  const PROVIDERS = {
13
14
  codex: {
14
15
  label: "Codex",
@@ -160,7 +161,19 @@ export function versionInfo() {
160
161
  };
161
162
  }
162
163
 
163
- function installProviderAgents(provider, { scope = "project", dryRun = false, force = false, cwd = process.cwd(), env = process.env } = {}) {
164
+ function existingAgentMatchesName(provider, name, path) {
165
+ let text;
166
+ try {
167
+ text = readFileSync(path, "utf8");
168
+ } catch {
169
+ return false;
170
+ }
171
+ if (provider === "codex") return new RegExp(`^\\s*name\\s*=\\s*"${name}"\\s*$`, "m").test(text);
172
+ if (provider === "claude") return new RegExp(`^\\s*name:\\s*${name}\\s*$`, "m").test(text);
173
+ return false;
174
+ }
175
+
176
+ function installProviderAgents(provider, { scope = "project", dryRun = false, force = false, replaceStale = true, cwd = process.cwd(), env = process.env } = {}) {
164
177
  const cfg = providerConfig(provider);
165
178
  const dir = targetDir(provider, scope, cwd, env);
166
179
  const dirConflicts = [dirname(dir), dir]
@@ -175,9 +188,10 @@ function installProviderAgents(provider, { scope = "project", dryRun = false, fo
175
188
  const dest = join(dir, `${name}.${cfg.extension}`);
176
189
  const text = readFileSync(src, "utf8");
177
190
  const exists = existsSync(dest) || isSymlink(dest);
191
+ const staleQuestAgent = exists && !sameFile(dest, text) && existingAgentMatchesName(provider, name, dest);
178
192
  let action;
179
193
  if (exists && sameFile(dest, text)) action = "unchanged";
180
- else if (exists && !force) action = "conflict";
194
+ else if (exists && !force && !(replaceStale && staleQuestAgent)) action = "conflict";
181
195
  else action = exists ? "replace" : "create";
182
196
  return { name, path: dest, action, text };
183
197
  });
@@ -208,6 +222,10 @@ export function installClaudeAgents(options = {}) {
208
222
  return installProviderAgents("claude", options);
209
223
  }
210
224
 
225
+ export function nativeProjectRoot(cwd = process.cwd(), env = process.env) {
226
+ return projectRoot(cwd, env);
227
+ }
228
+
211
229
  function questCliPathCheck(cwd, env, versions) {
212
230
  const pathQuestVersion = runCmd("quest", ["--version"], { cwd, env });
213
231
  const pathVersion = pathQuestVersion.status === 0 ? pathQuestVersion.stdout.trim() : null;
@@ -243,7 +261,7 @@ function nativeAgentsCheck(provider, cwd, env) {
243
261
  }
244
262
  const agentDetail = [
245
263
  missing.length ? `missing: ${missing.join(", ")}` : null,
246
- stale.length ? `stale (run install-agents --force): ${stale.join(", ")}` : null,
264
+ stale.length ? `stale (run doctor --fix or install-agents): ${stale.join(", ")}` : null,
247
265
  ].filter(Boolean).join("; ") || `installed ${cfg.label} templates current: ${Object.values(found).join(", ")}`;
248
266
  return check(
249
267
  "native-agents",
@@ -418,3 +436,113 @@ export function claudeDoctor({ cwd = process.cwd(), env = process.env } = {}) {
418
436
 
419
437
  return { ok: checks.every((c) => c.ok), checks };
420
438
  }
439
+
440
+ function checkByName(result, name) {
441
+ return result.checks.find((c) => c.name === name);
442
+ }
443
+
444
+ function cmdDetail(res) {
445
+ const text = [res.stdout, res.stderr, res.error?.message].filter(Boolean).join("\n").trim();
446
+ return text || `exit ${res.status ?? "unknown"}`;
447
+ }
448
+
449
+ function repairRecord(name, command, res, extra = {}) {
450
+ return {
451
+ name,
452
+ command: command.join(" "),
453
+ ok: res.status === 0,
454
+ detail: cmdDetail(res),
455
+ ...extra,
456
+ };
457
+ }
458
+
459
+ function runRepairCommand(cmd, args, { cwd, env }) {
460
+ return runCmd(cmd, args, { cwd, env });
461
+ }
462
+
463
+ function codexMarketplacePresent(cwd, env) {
464
+ const res = runCmd("codex", ["plugin", "marketplace", "list", "--json"], { cwd, env });
465
+ if (res.status !== 0) return { ok: false, present: false, res };
466
+ try {
467
+ const parsed = JSON.parse(res.stdout || "{}");
468
+ const marketplaces = Array.isArray(parsed.marketplaces) ? parsed.marketplaces : [];
469
+ return { ok: true, present: marketplaces.some((m) => m.name === "quest" || m.root?.includes("/quest")) };
470
+ } catch {
471
+ return { ok: false, present: false, res };
472
+ }
473
+ }
474
+
475
+ function providerPluginNeedsRepair(provider, result) {
476
+ const names = provider === "codex"
477
+ ? ["plugin-installed", "plugin-version", "hook-parser", "single-neutral-skill-root"]
478
+ : ["plugin-installed", "plugin-version"];
479
+ return names.some((name) => checkByName(result, name)?.ok === false);
480
+ }
481
+
482
+ function repairProviderPlugin(provider, before, { cwd, env }) {
483
+ const cliName = provider === "codex" ? "codex-cli" : "claude-cli";
484
+ if (!checkByName(before, cliName)?.ok || !providerPluginNeedsRepair(provider, before)) return [];
485
+
486
+ const repairs = [];
487
+ if (provider === "codex") {
488
+ const marketplace = codexMarketplacePresent(cwd, env);
489
+ if (!marketplace.ok) {
490
+ repairs.push(repairRecord("plugin-marketplace-list", ["codex", "plugin", "marketplace", "list", "--json"], marketplace.res));
491
+ return repairs;
492
+ }
493
+ if (!marketplace.present) {
494
+ const addMarketplaceArgs = ["plugin", "marketplace", "add", QUEST_CODEX_MARKETPLACE_SOURCE];
495
+ const addMarketplace = runRepairCommand("codex", addMarketplaceArgs, { cwd, env });
496
+ repairs.push(repairRecord("plugin-marketplace-add", ["codex", ...addMarketplaceArgs], addMarketplace));
497
+ if (addMarketplace.status !== 0) return repairs;
498
+ }
499
+ const upgrade = runRepairCommand("codex", ["plugin", "marketplace", "upgrade", "quest"], { cwd, env });
500
+ repairs.push(repairRecord("plugin-marketplace-upgrade", ["codex", "plugin", "marketplace", "upgrade", "quest"], upgrade));
501
+ if (upgrade.status !== 0) return repairs;
502
+ const addPlugin = runRepairCommand("codex", ["plugin", "add", "quest@quest"], { cwd, env });
503
+ repairs.push(repairRecord("plugin-add", ["codex", "plugin", "add", "quest@quest"], addPlugin));
504
+ return repairs;
505
+ }
506
+
507
+ const installed = checkByName(before, "plugin-installed")?.installed;
508
+ const subcommand = installed ? "update" : "install";
509
+ const res = runRepairCommand("claude", ["plugin", subcommand, "quest@quest"], { cwd, env });
510
+ repairs.push(repairRecord(`plugin-${subcommand}`, ["claude", "plugin", subcommand, "quest@quest"], res));
511
+ return repairs;
512
+ }
513
+
514
+ function repairProviderAgents(provider, before, { cwd, env }) {
515
+ if (checkByName(before, "native-agents")?.ok !== false) return [];
516
+ const result = installProviderAgents(provider, { scope: "project", force: false, replaceStale: true, cwd, env });
517
+ return [{
518
+ name: "native-agents",
519
+ command: `quest ${provider} install-agents --scope project`,
520
+ ok: result.ok,
521
+ detail: result.ok ? `${result.actions.map((a) => `${a.action} ${a.path}`).join("; ")}` : `conflicts: ${result.conflicts.map((c) => c.path).join(", ")}`,
522
+ result,
523
+ }];
524
+ }
525
+
526
+ function doctorForProvider(provider, options) {
527
+ if (provider === "codex") return doctor(options);
528
+ if (provider === "claude") return claudeDoctor(options);
529
+ throw new Error(`unknown provider "${provider}"`);
530
+ }
531
+
532
+ function doctorWithFix(provider, { cwd = process.cwd(), env = process.env } = {}) {
533
+ const before = doctorForProvider(provider, { cwd, env });
534
+ const repairs = [
535
+ ...repairProviderAgents(provider, before, { cwd, env }),
536
+ ...repairProviderPlugin(provider, before, { cwd, env }),
537
+ ];
538
+ const after = doctorForProvider(provider, { cwd, env });
539
+ return { ok: after.ok, checks: after.checks, repairs, before };
540
+ }
541
+
542
+ export function codexDoctorFix(options = {}) {
543
+ return doctorWithFix("codex", options);
544
+ }
545
+
546
+ export function claudeDoctorFix(options = {}) {
547
+ return doctorWithFix("claude", options);
548
+ }
package/lib/help.mjs CHANGED
@@ -138,30 +138,34 @@ export const COMMANDS = {
138
138
  example: "quest runs --active",
139
139
  },
140
140
  codex: {
141
- purpose: "Inspect or install Quest's native Codex integration",
142
- usage: "quest codex doctor [--json] | quest codex install-agents [--scope project|user] [--dry-run] [--force] [--json]",
141
+ purpose: "Inspect, repair, install, or open Quest's native Codex integration",
142
+ usage: "quest codex doctor [--fix] [--json] | quest codex open [--dry-run] [-- <codex args>] | quest codex install-agents [--scope project|user] [--dry-run] [--force] [--json]",
143
143
  flags: [
144
144
  ["doctor", "check Codex CLI, multi-agent support, plugin install/version, hooks, skill roots, and native-agent templates"],
145
+ ["--fix", "repair missing/stale Quest agents and Quest plugin install/version when possible, then rerun doctor"],
146
+ ["open", "repair/check setup, then launch interactive Codex from the project root"],
145
147
  ["install-agents", "install quest-executor and quest-reviewer as native Codex custom agents"],
146
148
  ["--scope <s>", "project (default: .codex/agents at repo root) or user (~/.codex/agents)"],
147
149
  ["--dry-run", "show intended agent writes without changing files"],
148
- ["--force", "replace existing agent files"],
150
+ ["--force", "replace existing non-Quest agent files"],
149
151
  ["--json", "machine-readable output"],
150
152
  ],
151
- example: "quest codex install-agents --scope project && quest codex doctor",
153
+ example: "quest codex doctor --fix && quest codex open",
152
154
  },
153
155
  claude: {
154
- purpose: "Inspect or install Quest's native Claude Code integration",
155
- usage: "quest claude doctor [--json] | quest claude install-agents [--scope project|user] [--dry-run] [--force] [--json]",
156
+ purpose: "Inspect, repair, install, or open Quest's native Claude Code integration",
157
+ usage: "quest claude doctor [--fix] [--json] | quest claude open [--dry-run] [-- <claude args>] | quest claude install-agents [--scope project|user] [--dry-run] [--force] [--json]",
156
158
  flags: [
157
159
  ["doctor", "check Claude CLI, plugin install/version, and native-agent templates"],
160
+ ["--fix", "repair missing/stale Quest agents and Quest plugin install/version when possible, then rerun doctor"],
161
+ ["open", "repair/check setup, then launch interactive Claude Code from the project root"],
158
162
  ["install-agents", "install quest-executor and quest-reviewer as native Claude Code custom agents"],
159
163
  ["--scope <s>", "project (default: .claude/agents at repo root) or user (~/.claude/agents)"],
160
164
  ["--dry-run", "show intended agent writes without changing files"],
161
- ["--force", "replace existing agent files"],
165
+ ["--force", "replace existing non-Quest agent files"],
162
166
  ["--json", "machine-readable output"],
163
167
  ],
164
- example: "quest claude install-agents --scope project && quest claude doctor",
168
+ example: "quest claude doctor --fix && quest claude open",
165
169
  },
166
170
  };
167
171
 
@@ -221,9 +225,11 @@ export function renderInitNextSteps(backend, { agentsInstalled = true } = {}) {
221
225
  "",
222
226
  "Store created. Next steps:",
223
227
  ...(agentsInstalled ? [" 0. Restart agent sessions so newly installed project templates are loaded"] : []),
224
- " 1. Author a quest: quest create --help (or $quest:plan in your agent session)",
225
- " 2. Check it: quest lint --all",
226
- " 3. Work it: $quest:work <id> in-session, or quest-run <id> headless",
228
+ ...(agentsInstalled ? [" 1. Repair/check providers: quest codex doctor --fix (or quest claude doctor --fix)"] : []),
229
+ ...(agentsInstalled ? [" 2. Open provider: quest codex open (or quest claude open)"] : []),
230
+ ` ${agentsInstalled ? "3" : "1"}. Author a quest: quest create --help (or $quest:plan in your agent session)`,
231
+ ` ${agentsInstalled ? "4" : "2"}. Check it: quest lint --all`,
232
+ ` ${agentsInstalled ? "5" : "3"}. Work it: $quest:work <id> in-session, or quest-run <id> headless`,
227
233
  ...(agentsInstalled ? [] : [" Agent templates skipped; install later with `quest codex install-agents --scope project` and `quest claude install-agents --scope project`."]),
228
234
  ...(backend === "github" ? ["", "Records live as GitHub issues; config and amendments stay local in .quests/."] : []),
229
235
  ].join("\n");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "quest-loop",
3
- "version": "0.3.4",
3
+ "version": "0.3.5",
4
4
  "description": "Goal-loop engineering for coding agents: quest contracts, iterative execution with evidence checkpoints, Claude + Codex workers. Ships the `quest` store CLI and the `quest-run` headless runner.",
5
5
  "type": "module",
6
6
  "engines": { "node": ">=20" },
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: setup
3
- description: Use when setting up, validating, updating, or troubleshooting Quest's native Codex or Claude plugin integration.
4
- argument-hint: "[doctor|install-agents|init]"
3
+ description: Use when setting up, validating, updating, opening, or troubleshooting Quest's native Codex or Claude plugin integration.
4
+ argument-hint: "[doctor|fix|open|install-agents|init]"
5
5
  ---
6
6
 
7
7
  # Set up Quest native agents
@@ -19,9 +19,10 @@ agent templates for both providers:
19
19
  - `.claude/agents/quest-reviewer.md`
20
20
 
21
21
  Use `quest init --no-agents` when you only want the quest store. If an existing
22
- project template conflicts, init fails before creating `.quests/`; inspect the
23
- file, run the explicit provider install command with `--force` only when you
24
- intend replacement, then rerun `quest init`.
22
+ project template is stale and still identifies itself as Quest's agent, init
23
+ replaces it. If another file conflicts, init fails before creating `.quests/`;
24
+ inspect the file, run the explicit provider install command with `--force` only
25
+ when you intend replacement, then rerun `quest init`.
25
26
 
26
27
  Project-scoped agent templates install at the Git repository root. For a nested
27
28
  quest store, use `quest init --no-agents` in the nested directory and set
@@ -32,7 +33,7 @@ quest store, use `quest init --no-agents` in the nested directory and set
32
33
  Check the installed Codex-facing state from the actual Codex surfaces:
33
34
 
34
35
  ```bash
35
- quest codex doctor
36
+ quest codex doctor --fix
36
37
  ```
37
38
 
38
39
  This verifies the Codex CLI, `quest` binary on PATH, `multi_agent` and `goals`
@@ -45,7 +46,14 @@ use `quest-run --codex-goal-mode require` only as the headless fallback.
45
46
  Check the installed Claude-facing state from the actual Claude surfaces:
46
47
 
47
48
  ```bash
48
- quest claude doctor
49
+ quest claude doctor --fix
50
+ ```
51
+
52
+ Open an interactive provider only after the same repair/check gate passes:
53
+
54
+ ```bash
55
+ quest codex open
56
+ quest claude open
49
57
  ```
50
58
 
51
59
  ## Install Native Agents
@@ -70,9 +78,10 @@ quest claude install-agents --scope user
70
78
  ```
71
79
 
72
80
  If an existing file conflicts, inspect it first. Use `--force` only when you
73
- intend to replace that custom agent with Quest's bundled definition. Symlinked
74
- agent template files can be written through with `--force`; keep the provider
75
- agent directories themselves as real directories.
81
+ intend to replace that custom agent with Quest's bundled definition. Stale
82
+ Quest-owned templates are replaced without `--force`. Symlinked agent template
83
+ files can be written through with `--force`; keep the provider agent directories
84
+ themselves as real directories.
76
85
 
77
86
  ## Update Installed Plugin
78
87
 
@@ -82,7 +91,14 @@ refresh and reinstall, then start a new Codex thread:
82
91
  ```bash
83
92
  codex plugin marketplace upgrade quest
84
93
  codex plugin add quest@quest
85
- quest codex doctor
94
+ quest codex doctor --fix
95
+ ```
96
+
97
+ Claude updates through its plugin manager. After updating, restart Claude Code:
98
+
99
+ ```bash
100
+ claude plugin update quest@quest
101
+ quest claude doctor --fix
86
102
  ```
87
103
 
88
104
  If hooks changed, review/trust the updated hook definitions in Codex when