@uchibeke/gallivant 0.2.0 → 0.3.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.
Files changed (133) hide show
  1. package/README.md +120 -60
  2. package/SECURITY.md +9 -0
  3. package/bin/gallivant.mjs +41 -14
  4. package/bin/promote-bitbucket.mjs +40 -0
  5. package/bin/task-pr.mjs +9 -0
  6. package/bin/task-review.mjs +15 -0
  7. package/docs/README.md +6 -2
  8. package/docs/agent-setup.md +55 -41
  9. package/docs/architecture.md +11 -3
  10. package/docs/bitbucket-promotion.md +69 -0
  11. package/docs/bitbucket-review.md +330 -0
  12. package/docs/chains.md +30 -1
  13. package/docs/codex-cloud.md +7 -0
  14. package/docs/codex-review.md +50 -0
  15. package/docs/commands.md +103 -14
  16. package/docs/config.md +45 -13
  17. package/docs/execution.md +1 -1
  18. package/docs/first-party-review.md +266 -0
  19. package/docs/git-hosts.md +294 -0
  20. package/docs/guardrails.md +56 -0
  21. package/docs/install.md +137 -67
  22. package/docs/launch.md +7 -4
  23. package/docs/network-recovery.md +9 -0
  24. package/docs/openai-agents.md +3 -2
  25. package/docs/prd.md +23 -2
  26. package/docs/preparation.md +2 -2
  27. package/docs/release-qualification.md +1 -1
  28. package/docs/releasing.md +46 -22
  29. package/docs/task-delivery.md +5 -5
  30. package/docs/task-profiles.md +537 -0
  31. package/docs/tasks.md +59 -197
  32. package/lib/attribution.mjs +7 -3
  33. package/lib/block.mjs +10 -1
  34. package/lib/chains.mjs +101 -30
  35. package/lib/codex_cloud.mjs +2 -1
  36. package/lib/codex_cloud_input.mjs +15 -6
  37. package/lib/codex_cloud_result.mjs +1 -1
  38. package/lib/commands/doctor.mjs +22 -453
  39. package/lib/commands/init.mjs +281 -28
  40. package/lib/commands/register.mjs +81 -13
  41. package/lib/commands/resume.mjs +5 -1
  42. package/lib/commands/review.mjs +66 -0
  43. package/lib/commands/serve.mjs +8 -0
  44. package/lib/commands/start.mjs +30 -11
  45. package/lib/commands/status.mjs +18 -2
  46. package/lib/commands/task.mjs +9 -1
  47. package/lib/commands/up.mjs +19 -11
  48. package/lib/commands/why.mjs +7 -3
  49. package/lib/config.mjs +42 -9
  50. package/lib/context.mjs +28 -21
  51. package/lib/control.mjs +21 -6
  52. package/lib/credential.mjs +20 -14
  53. package/lib/deliverable.mjs +2 -0
  54. package/lib/events.mjs +96 -53
  55. package/lib/execution.mjs +132 -11
  56. package/lib/execution_preparation.mjs +16 -1
  57. package/lib/execution_result.mjs +26 -5
  58. package/lib/first_party_review.mjs +618 -0
  59. package/lib/fs.mjs +10 -3
  60. package/lib/gh.mjs +144 -56
  61. package/lib/git.mjs +133 -32
  62. package/lib/git_diff.mjs +121 -0
  63. package/lib/harness.mjs +14 -10
  64. package/lib/host_contract.mjs +71 -0
  65. package/lib/host_definitions.mjs +22 -0
  66. package/lib/hosts/bitbucket.mjs +553 -0
  67. package/lib/hosts/bitbucket_contract.mjs +57 -0
  68. package/lib/hosts/bitbucket_credential.mjs +62 -0
  69. package/lib/hosts/bitbucket_review.mjs +44 -0
  70. package/lib/hosts/bitbucket_review_producer.mjs +50 -0
  71. package/lib/hosts/github.mjs +57 -0
  72. package/lib/hosts/github_contract.mjs +27 -0
  73. package/lib/hosts/github_doctor.mjs +482 -0
  74. package/lib/hosts/github_review_summary.mjs +38 -0
  75. package/lib/hosts/transport_doctor.mjs +35 -0
  76. package/lib/hosts.mjs +130 -0
  77. package/lib/learning_qualification.mjs +1 -1
  78. package/lib/notify.mjs +1 -1
  79. package/lib/openai_agents_input.mjs +7 -2
  80. package/lib/openai_agents_sources.mjs +16 -8
  81. package/lib/plugin_package.mjs +13 -1
  82. package/lib/pr_operation.mjs +41 -0
  83. package/lib/prd.mjs +18 -3
  84. package/lib/preparation_codex.mjs +6 -1
  85. package/lib/probe.mjs +6 -4
  86. package/lib/process.mjs +24 -0
  87. package/lib/promotion.mjs +132 -0
  88. package/lib/promotion_git.mjs +63 -0
  89. package/lib/prompt.mjs +16 -13
  90. package/lib/provider_health.mjs +14 -3
  91. package/lib/repository.mjs +68 -0
  92. package/lib/repository_preflight.mjs +11 -0
  93. package/lib/review_evaluation.mjs +25 -0
  94. package/lib/review_evidence.mjs +500 -0
  95. package/lib/review_history.mjs +73 -0
  96. package/lib/review_image.mjs +145 -0
  97. package/lib/review_link.mjs +12 -0
  98. package/lib/review_policy.mjs +132 -0
  99. package/lib/review_policy_contract.mjs +18 -0
  100. package/lib/review_state.mjs +13 -0
  101. package/lib/review_visual.mjs +94 -0
  102. package/lib/runtime-environment.mjs +6 -0
  103. package/lib/runtime_node.mjs +3 -2
  104. package/lib/runtime_state.mjs +39 -5
  105. package/lib/sources/prd.mjs +6 -3
  106. package/lib/state.mjs +137 -24
  107. package/lib/task_completion.mjs +7 -3
  108. package/lib/task_contract.mjs +201 -27
  109. package/lib/task_delivery.mjs +9 -2
  110. package/lib/task_delivery_contract.mjs +13 -9
  111. package/lib/task_delivery_view.mjs +18 -2
  112. package/lib/task_environment.mjs +13 -1
  113. package/lib/task_limits.mjs +13 -0
  114. package/lib/task_model_config.mjs +99 -0
  115. package/lib/task_model_route.mjs +243 -0
  116. package/lib/task_prepare.mjs +21 -8
  117. package/lib/task_profile.mjs +1875 -0
  118. package/lib/task_repository_context.mjs +65 -0
  119. package/lib/tasks.mjs +252 -51
  120. package/lib/tick.mjs +373 -98
  121. package/lib/time.mjs +1 -0
  122. package/lib/tracker/pages.mjs +19 -5
  123. package/lib/tracker/review.mjs +21 -0
  124. package/lib/tracker_process.mjs +8 -1
  125. package/lib/verification_sandbox.mjs +2 -1
  126. package/lib/work_artifacts.mjs +79 -0
  127. package/npm-shrinkwrap.json +12 -3
  128. package/package.json +9 -3
  129. package/templates/plugin/task-delivery.SKILL.md +17 -10
  130. package/templates/plugin/task-intake-contract.json +18 -0
  131. package/templates/plugin/task-profile-requests.mjs +1448 -0
  132. package/templates/tracker/tracker.css +3 -0
  133. package/templates/tracker/tracker.js +38 -0
package/README.md CHANGED
@@ -2,86 +2,105 @@
2
2
 
3
3
  **Give an agent a task. Let the review loop run. Go outside.**
4
4
 
5
- Gallivant turns repository tasks into reviewed pull requests. It starts an agent,
6
- watches CI and reviewer feedback, and continues the same session to fix issues.
7
- You can follow progress and send corrections from a local dashboard. **You decide
8
- what gets merged.**
9
-
10
- Use it for code, documentation, research or content that belongs in a GitHub
11
- repository. Start with a plain-language request or a written brief.
5
+ Gallivant turns a repository task into a reviewed pull request. It runs a coding
6
+ agent in a separate checkout, opens the PR, watches CI and reviewer feedback, and
7
+ continues the same session until the PR is ready for you. You decide what merges.
12
8
 
13
9
  ```text
14
10
  Your task → agent works → PR → review + CI → fixes → ready for you
15
11
  ↑___________|
16
12
  ```
17
13
 
18
- ## Install
19
-
20
- You need **macOS or Linux, Node 22+, Git, GitHub CLI and jq**. For your first run,
21
- use signed-in **Codex CLI 0.160.0+** or **Claude Code 2.1.263+**. Provider usage is
22
- billed to your own account. [Full prerequisites](docs/install.md).
14
+ ## Set up in one command
23
15
 
24
- Check the [registry version](https://www.npmjs.com/package/@uchibeke/gallivant). Once a
25
- version is available, install it with `npm install -g @uchibeke/gallivant`. If the package
26
- is not published yet, install from source:
16
+ Run this inside the Git checkout you want to work in:
27
17
 
28
18
  ```sh
29
- git clone https://github.com/uchibeke/gallivant.git
30
- cd gallivant
31
- npm ci --ignore-scripts
32
- npm link
33
- gallivant --version
19
+ npx --yes @uchibeke/gallivant init --harness codex # or: --harness claude
34
20
  ```
35
21
 
36
- [Release status and checks](docs/releasing.md).
22
+ The setup flow below requires **0.2.1 or newer**. `npx` runs npm's latest published
23
+ version. Changes merged on `main` become available through npm after a
24
+ [versioned release](docs/releasing.md); check the registry with
25
+ `npm view @uchibeke/gallivant version`.
37
26
 
38
- ## Set up
27
+ `init` writes a private config at `~/.gallivant/config.json`, records this
28
+ repository, creates a separate directory for task checkouts, and ends with the
29
+ same report as `gallivant doctor`: one line per check and the exact fix for each
30
+ failing one. Run it again in another repository to add that repository; nothing
31
+ else in the config changes.
39
32
 
40
- ```sh
41
- gh auth status
42
- codex login status # use Claude sign-in if you choose Claude
43
- gallivant init --harness codex # or --harness claude
44
- gallivant doctor
45
- ```
33
+ Before you run it you need:
46
34
 
47
- `init` creates local configuration and a separate task-checkout directory. It
48
- preserves existing config, credentials and global agent settings. Follow the
49
- fixes from `doctor`; [setup instructions](docs/install.md) cover authentication,
50
- harness permissions and repository protection.
35
+ | Prerequisite | Check | If it fails |
36
+ | --- | --- | --- |
37
+ | macOS or Linux, Node 22+, Git, jq | `node --version`, `git --version`, `jq --version` | install from your package manager |
38
+ | GitHub CLI signed in | `gh auth status` | `gh auth login` |
39
+ | Codex CLI 0.160.0+ signed in | `codex login status` | `codex login` |
40
+ | or Claude Code 2.1.263+ signed in | `claude auth status` | `claude auth login` |
51
41
 
52
- Enable the Codex GitHub review integration on the target repository, or choose
53
- another reviewer. If you want CI and trusted human feedback without a review bot,
54
- explicitly configure `"reviewer": null`. The default waits for Codex review.
42
+ A signed-out `gh` or harness stops `init` before it writes anything, and the
43
+ message repeats the login command above. `init` never asks for passwords, tokens
44
+ or browser cookies; sign in with each tool's own flow. Inference is billed to
45
+ your own provider account.
55
46
 
56
- **Prefer an agent to handle setup?** Give it the
57
- [setup-agent instructions](docs/agent-setup.md). They cover inspection, installation,
58
- configuration, verification and the points where your input is required.
47
+ `npx` downloads and runs the package on demand. Nothing is installed globally
48
+ and no `gallivant` command is added to your PATH. If you want one:
59
49
 
60
- ## Run your first task
50
+ ```sh
51
+ npm install -g @uchibeke/gallivant
52
+ ```
61
53
 
62
- Inside a repository you can push to. This example uses Codex; if you configured
63
- Claude, replace `--harness codex` with `--harness claude` before running it:
54
+ The rest of this page writes `gallivant`. With `npx`, read that as
55
+ `npx --yes @uchibeke/gallivant`. Contributors who want to run from a source
56
+ checkout: see [installing from source](docs/install.md#install-from-source).
57
+
58
+ ## Finish what setup cannot do for you
59
+
60
+ `doctor` names these. `init` does not do them, because each needs a decision
61
+ from you or an account with a third party.
62
+
63
+ - **Reviewer.** The default loop waits for the Codex GitHub review integration
64
+ (`chatgpt-codex-connector[bot]`). Enable it on the repository, configure
65
+ another reviewer, or opt into a [qualified first-party reviewer](docs/first-party-review.md).
66
+ Explicit legacy no-review needs both `"reviewer": null` and `review.legacy_no_review: true`. Without one of these, the first PR waits for a review
67
+ that never arrives. See [the reviewer key](docs/config.md#the-reviewer-object).
68
+ - **Branch protection.** `doctor` prints the `gh api` call that creates a
69
+ ruleset blocking direct and force pushes to the default branch. Run it
70
+ yourself. Setup never changes repository settings.
71
+ - **Harness guardrails.** The APort hook for Claude or Codex is installed by its
72
+ own `npx @aporthq/aport-agent-guardrails` command, and Codex asks you to trust
73
+ the hook inside its own interface. Setup does not install hooks.
74
+ [Guardrails](docs/guardrails.md) explains what each control covers.
75
+ - **Spend.** Defaults are 30 fix rounds per PR and a 5 USD per-run cap that
76
+ only Claude enforces natively. Review [limits](docs/config.md) before
77
+ unattended work.
78
+
79
+ ## Run a first task
64
80
 
65
81
  ```sh
66
- cd /path/to/your/repository
67
82
  gallivant task "Document how to run the existing tests in CONTRIBUTING.md. Use the commands already defined in the repository. Change documentation only." \
68
- --harness codex --verify 'git diff --check' --run
83
+ --harness codex --verify 'git diff --check'
84
+ # Review the draft, then substitute its returned task ID and revision:
85
+ gallivant task start TASK_ID --revision REVISION --run
69
86
  gallivant start
70
87
  ```
71
88
 
72
- `task` prepares a brief and asks for missing information. `--run` authorizes
73
- implementation when that brief is ready, including after clarification. Omit it
74
- to inspect the draft first. Follow the printed `Next` action using your task's ID
75
- and revision. Preparation also uses inference.
76
-
77
- `gallivant start` opens **http://127.0.0.1:8791** and ensures the daemon is running.
78
- Without a PRD path, it does not submit another task. Closing the browser does not
79
- stop the work.
80
-
81
- With the default configuration, **ready** means the configured checks, reviewer
82
- and acceptance gate passed. Inspect status for skipped-gate warnings, review the
83
- PR and merge when you choose. Missing access, evidence or exhausted limits produce
84
- an inspectable stop instead.
89
+ `task` uses your harness to prepare a brief, which is a paid inference call,
90
+ and may ask you questions. Review the draft and answer any questions, then use
91
+ its printed `Next` action to approve that revision with `task start --run`.
92
+ Preparation always returns for review, even if its command includes `--run`.
93
+ The agent then works in a clone under `~/.gallivant-worktrees`,
94
+ pushes a branch, opens a PR against the default branch, and the daemon watches CI
95
+ and the reviewer, sending each round of feedback back to the same session.
96
+ `gallivant start` opens the dashboard at **http://127.0.0.1:8791** and keeps
97
+ the daemon running; closing the browser does not stop the work.
98
+
99
+ Expected outcome: a PR with a small CONTRIBUTING.md change and a completion
100
+ receipt in its body, and `gallivant status` showing the entry as **ready** once
101
+ checks, reviewer and the acceptance gate pass. You review and merge. Missing
102
+ access, failing checks or an exhausted round allowance produce an inspectable
103
+ stop instead; `gallivant why <handle>` explains it.
85
104
 
86
105
  ### Bring a written brief
87
106
 
@@ -96,6 +115,20 @@ gallivant start docs/prds/add-csv-export.md
96
115
  You do not have to write a PRD yourself. Both entry points use a validated brief
97
116
  and the same review loop. [Writing briefs](docs/prd.md) · [Task commands](docs/tasks.md).
98
117
 
118
+ ## How the review loop runs
119
+
120
+ 1. The agent implements the brief, runs the brief's verification commands and
121
+ opens the PR.
122
+ 2. Each tick (every two minutes by default) the daemon reads CI and reviewer
123
+ state. A blocking review or a failing check starts a fix round in the same
124
+ agent session, and the fix is pushed to the same PR.
125
+ 3. Rounds stop at `max_iterations` (60 by default), when the reviewer stays
126
+ silent for `stall_hours`, or when a run exceeds its timeout. Every stop is
127
+ recorded with a reason you can read with `gallivant why`.
128
+ 4. **Ready** means the configured checks, reviewer and acceptance gate passed.
129
+ Nothing merges automatically. Natural-language tasks stop at a review
130
+ handoff by default; choose `integrated` to keep watching until you merge.
131
+
99
132
  ## While it works
100
133
 
101
134
  | What you need | Action |
@@ -128,6 +161,9 @@ base. You can plan longer work while retaining the merge decision.
128
161
 
129
162
  ## Harness support
130
163
 
164
+ `init --harness` accepts `codex` and `claude`. Other adapters are configured by
165
+ hand in `config.json`; see [configuration](docs/config.md#execution-providers).
166
+
131
167
  | Harness (`harness` key) | Runs on | Prepare requests | Implementation status |
132
168
  | --- | --- | --- | --- |
133
169
  | Claude Code (`claude`) | Your host | Yes | Recommended; live usage evidence |
@@ -177,7 +213,7 @@ for the installed version's flags.
177
213
  daemon, including when execution is hosted. Gallivant is not a managed service.
178
214
  - **Your accounts pay for inference.** Subscriptions and API credits differ.
179
215
  There is no automatic provider fallback. Review [limits](docs/config.md) before
180
- unattended work; the default review allowance is 30 rounds.
216
+ unattended work; the default review allowance is 60 rounds.
181
217
  - **Your permissions apply.** Scope GitHub access to the required repositories.
182
218
  Harness permissions, OS sandboxing and optional APort checks are different
183
219
  controls. [Security boundaries](docs/guardrails.md).
@@ -190,9 +226,25 @@ for the installed version's flags.
190
226
 
191
227
  ## Documentation
192
228
 
193
- [Getting started](docs/install.md) · [Agent setup](docs/agent-setup.md) ·
194
- [Commands](docs/commands.md) · [Configuration](docs/config.md) ·
195
- [Dashboard](docs/app.md) · [All guides](docs/README.md)
229
+ | Need | Guide |
230
+ | --- | --- |
231
+ | Install and run your first task | [Getting started](docs/install.md) |
232
+ | Start from a request, answer questions, inspect results | [Natural-language tasks](docs/tasks.md) |
233
+ | Select the typed delivery profile and planner route for a request | [Typed delivery profiles](docs/task-profiles.md) |
234
+ | Write a brief or define noncoding acceptance checks | [PRD contract](docs/prd.md) |
235
+ | Use API-backed hosted execution | [OpenAI Agents](docs/openai-agents.md) |
236
+ | Dashboard messages, controls and recovery | [Dashboard](docs/app.md) · [Commands](docs/commands.md) |
237
+ | Models, credentials, limits and notifications | [Configuration](docs/config.md) |
238
+ | Plan sequential work | [Chains](docs/chains.md) |
239
+ | Embed task delivery in another application | [Task-delivery package](docs/task-delivery.md) |
240
+ | Understand internals or recorded qualification | [Documentation index](docs/README.md) |
241
+ | Set up from an agent | [Agent setup](docs/agent-setup.md) |
242
+ | Release, contribute or report a vulnerability | [Releasing](docs/releasing.md) · [Contributing](CONTRIBUTING.md) · [Security](SECURITY.md) |
243
+
244
+ **Asking a coding agent to set this up?** Give it the
245
+ [setup-agent instructions](docs/agent-setup.md). They cover inspection, the
246
+ `npx` command, the points where your login or decision is required, and what a
247
+ setup run may not do on its own.
196
248
 
197
249
  Embedding the same workflow in another application? See
198
250
  [task delivery](docs/task-delivery.md). Installing this CLI does not deploy a
@@ -200,3 +252,11 @@ hosted service or publish a chat plugin.
200
252
 
201
253
  [Contributing](CONTRIBUTING.md) · [Security reports](SECURITY.md) ·
202
254
  [Releasing](docs/releasing.md) · [Apache-2.0 license](LICENSE)
255
+
256
+ ## Bitbucket Cloud
257
+
258
+ Bitbucket Cloud tasks support the same independent local Codex review service as GitHub. The adapter captures an exact same-repository PR comparison through Bitbucket's commit, diffstat, merge-base and source APIs, then the shared service divides large evidence into bounded jobs. Activation still requires a successful live route qualification; until that and the disposable private/public review matrix pass, keep an existing run's explicit legacy no-review policy. A prior public disposable run qualified PR publication and receipt acceptance only, not semantic review. See the [setup, activation limits and troubleshooting guide](docs/bitbucket-review.md). Bitbucket-only setup needs no GitHub sign-in and does not install a pipeline or alter repository settings.
259
+
260
+ ## First-party review (opt-in)
261
+
262
+ New tasks can pin `external-required`, `first-party-required`, or `both-required`. Repositories with the configured external reviewer retain their existing default. First-party review requires a separately qualified restricted route; it never claims Git-host bot approval. GitHub and Bitbucket Cloud are the only evidence adapters currently implemented. See [selection, qualification and migration](docs/first-party-review.md) and the [current live qualification gap](docs/audit/first-party-review.md). Existing no-review runs keep that requirement until the audited policy command changes them and disclose the absence of semantic review.
package/SECURITY.md CHANGED
@@ -17,3 +17,12 @@ they need. Automatic approval is not equivalent to an operating-system sandbox.
17
17
  The [OpenAI Agents API adapter](docs/openai-agents.md) keeps service credentials
18
18
  on the coordinator and publishes returned artifacts through that coordinator.
19
19
  Its hosted execution controls differ from local harness hooks and sandboxes.
20
+
21
+ ## Bitbucket reviewer isolation
22
+
23
+ Use a separate reviewer account and keep its publication credential outside the
24
+ coding process's filesystem and environment access. A private file readable by
25
+ the coding identity does not provide isolation. The review model receives the
26
+ prepared diff and a read-only checkout; an operator publishes its exact-head
27
+ verdict. See [reviewer setup](docs/bitbucket-review.md#independent-local-codex-reviewer).
28
+ Bitbucket dispatch remains disabled pending live qualification.
package/bin/gallivant.mjs CHANGED
@@ -1,5 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  // CLI entry. Parses arguments, builds the context, calls one command. No logic lives here.
3
+ import { reviewCommand } from "../lib/commands/review.mjs";
3
4
  import { acquireCliMutation } from "../lib/daemon.mjs";
4
5
  import { parseArgs } from "node:util";
5
6
  import { makeContext } from "../lib/context.mjs";
@@ -15,7 +16,7 @@ import { newPrd } from "../lib/commands/new.mjs";
15
16
  import { resume } from "../lib/commands/resume.mjs";
16
17
  import { startServices } from "../lib/commands/start_services.mjs";
17
18
  import { trackerPort, stopTracker } from "../lib/tracker_process.mjs";
18
- import { init } from "../lib/commands/init.mjs";
19
+ import { init, renderInit } from "../lib/commands/init.mjs";
19
20
  import { VERSION } from "../lib/fs.mjs";
20
21
  import { hasConfig } from "../lib/config.mjs";
21
22
  import { resolveHandle } from "../lib/state.mjs";
@@ -28,8 +29,9 @@ import { safeDisplay } from "../lib/learning_data.mjs";
28
29
 
29
30
  const HELP = `gallivant: give an agent a task, let the review loop run, go outside.
30
31
 
31
- gallivant init [--harness codex|claude] [--worktrees <directory>]
32
- create a private config; never overwrite settings or sign in for you
32
+ gallivant init [--harness codex|claude] [--worktrees <directory>] [--host-config <json>] [--base <branch>]
33
+ set up the repository you are in: private config, this repo in repos,
34
+ then doctor's report. Safe to repeat; never signs in or overwrites settings
33
35
  gallivant --version print the installed version
34
36
  gallivant doctor [--send] [--probe] install checklist and health probe
35
37
  gallivant doctor --network <https-origin> [--json] bounded DNS/HTTPS diagnosis
@@ -50,15 +52,18 @@ const HELP = `gallivant: give an agent a task, let the review loop run, go outsi
50
52
  write a starting PRD into docs/prds/ of the repo you are in
51
53
  gallivant task [prepare] "<request>" [--stdin] [--dir <checkout>] [--repo <owner/repo>]
52
54
  [--base <branch>] [--harness <name>] [--context <file>] [--request-id <id>] [--run] [--json]
53
- [--completion-target delivery_ready|integrated] [--verify <command>] [--no-daemon]
54
- prepare an isolated brief; --run authorizes its exact ready revision
55
+ [--completion-target delivery_ready|integrated] [--delivery pull_request] [--route harness|model]
56
+ [--verify <command>] [--no-daemon]
57
+ prepare an isolated brief for review; approve later with task start --run
58
+ --delivery selects the typed delivery profile (the only delivery authority);
59
+ --route drafts through the connected harness or the operator's bounded model route
55
60
  Claude, Codex and OpenAI Agents support isolated preparation.
56
61
  Other local harnesses use written PRDs; Codex Cloud dispatch is unavailable
57
62
  gallivant task answer <task-id> --revision <n> --request-id <answer-id> --answer <question-id=text>
58
63
  resume saved questions; --answer, --context and --verify may repeat
59
64
  gallivant task inspect <task-id> [--json] | task list [--json]
60
65
  gallivant task resume|validate|start <task-id> --revision <n> [--run] [--no-daemon] [--json]
61
- shared versioned operations; start needs prior or --run authorization
66
+ shared versioned operations; start --run approves the reviewed revision
62
67
  gallivant ready <prd.md> [--check] check the PRD against the contract; flip it to ready when it passes
63
68
  gallivant start [prd.md] [--no-daemon] [--no-server] [--no-open] [--port 8791] [--base <branch>]
64
69
  start the daemon and dashboard, then open it; optionally start a ready PRD
@@ -66,6 +71,7 @@ const HELP = `gallivant: give an agent a task, let the review loop run, go outsi
66
71
  gallivant register <pr-url> [--harness <name>] [--session <id>] [--worktree <dir>]
67
72
  watch a hand-made PR; on an existing entry, reset it
68
73
  gallivant chain <name> <prd1.md> <prd2.md> ... [--base <branch>]
74
+ gallivant chain <name> --after <pr-url|handle> <next.md> ...
69
75
  queue ready PRDs; each starts after the previous PR is merged
70
76
  gallivant chain [<name>] [--cancel | --retry [--resnapshot]]
71
77
  inspect chains, stop future work, or retry after fixing a blocker
@@ -80,6 +86,15 @@ const HELP = `gallivant: give an agent a task, let the review loop run, go outsi
80
86
  --resnapshot makes an edited brief the one the gate judges
81
87
  --fresh-session replaces retired learned memory after settlement
82
88
  gallivant recheck <handle> queue a PR recheck without resetting its budget
89
+ gallivant review retry <handle> --reason <text>
90
+ retry confirmed incomplete or coordinator-cancelled review; retain pieces and limits
91
+ gallivant review qualify --repo <owner/repo> [--capability text|image] [--run [--wait] [--retry --reason <text>]]
92
+ inspect qualification; --run launches a bounded probe; --wait records its exit before returning
93
+ gallivant review status <handle> show pinned policy, owned verdict and unresolved review evidence
94
+ gallivant review policy <handle> --mode external-required|first-party-required|both-required --reason "..."
95
+ explicitly replace policy and re-evaluate the current head
96
+ gallivant review dispute <handle> --finding <id> --reason "..."
97
+ record a dispute for a person; never accepts the author's own dispute
83
98
  gallivant cancel <handle> stop further dispatch; request provider cancellation
84
99
  gallivant say <handle> --note "..." [--interrupt]
85
100
  send an update in the same session; --interrupt stops the active run first
@@ -93,15 +108,17 @@ const OPTIONS = {
93
108
  send: { type: "boolean" }, probe: { type: "boolean" }, help: { type: "boolean", short: "h" }, version: { type: "boolean", short: "v" },
94
109
  "no-server": { type: "boolean" }, "no-open": { type: "boolean" }, foreground: { type: "boolean" }, worktrees: { type: "string" },
95
110
  "no-daemon": { type: "boolean" }, note: { type: "string" }, resnapshot: { type: "boolean" }, "fresh-session": { type: "boolean" }, interrupt: { type: "boolean" },
96
- base: { type: "string" }, harness: { type: "string" }, session: { type: "string" }, worktree: { type: "string" }, dir: { type: "string" }, port: { type: "string" },
97
- cancel: { type: "boolean" }, retry: { type: "boolean" },
111
+ base: { type: "string" }, after: { type: "string" }, harness: { type: "string" }, session: { type: "string" }, worktree: { type: "string" }, dir: { type: "string" }, port: { type: "string" },
112
+ cancel: { type: "boolean" }, retry: { type: "boolean" }, wait: { type: "boolean" },
98
113
  run: { type: "boolean" }, stdin: { type: "boolean" }, repo: { type: "string" }, revision: { type: "string" },
99
114
  "request-id": { type: "string" }, context: { type: "string", multiple: true },
100
- "completion-target": { type: "string" },
115
+ "completion-target": { type: "string" }, delivery: { type: "string" }, route: { type: "string" },
101
116
  answer: { type: "string", multiple: true }, verify: { type: "string", multiple: true },
102
117
  since: { type: "string" }, until: { type: "string" }, "dry-run": { type: "boolean" },
103
118
  mode: { type: "string" }, status: { type: "string" }, from: { type: "string" }, reason: { type: "string" },
119
+ "host-config": { type: "string" },
104
120
  "key-path": { type: "string" }, "ssh-keygen": { type: "string" }, "learning-budget": { type: "string" },
121
+ finding: { type: "string" }, capability: { type: "string" },
105
122
  };
106
123
 
107
124
  async function dispatch(argv) {
@@ -110,10 +127,14 @@ async function dispatch(argv) {
110
127
  const [cmd, arg] = positionals;
111
128
  if (values.version) { console.log(VERSION); return 0; }
112
129
  if (values.help || !cmd || cmd === "help") { console.log(HELP); return 0; }
130
+ if (values.after !== undefined && (cmd !== "chain" || !values.after.trim())) throw new Error("--after requires a registered PR URL or handle when queuing a new chain");
113
131
  if (cmd === "init") {
114
- const r = await init({ harness: values.harness, worktrees: values.worktrees });
115
- console.log(`Created ${r.file}\nHarness: ${r.harness}\nWorktrees: ${r.config.worktrees}\n\nNext: gallivant doctor\nComplete the harness guardrail and repository setup before starting work:\n https://github.com/uchibeke/gallivant/blob/main/docs/install.md\nPackaged templates:\n ${r.templates.passport}\n ${r.templates.sandbox}`);
116
- return 0;
132
+ if (arg) throw new Error("init takes no positional argument; run it from inside the target checkout");
133
+ const r = await init({ harness: values.harness, worktrees: values.worktrees, hostConfig: values["host-config"], base: values.base });
134
+ const report = renderDoctor(r.doctor);
135
+ console.log(renderInit(r, report));
136
+ // Doctor's exit code, so a script or an agent reading only the status knows whether setup still has open items.
137
+ return report.exitCode;
117
138
  }
118
139
  if (values.foreground && cmd !== "serve") throw new Error("--foreground is available only with serve");
119
140
  if (values.foreground && values["no-server"]) throw new Error("--foreground cannot be combined with --no-server");
@@ -161,7 +182,7 @@ async function dispatch(argv) {
161
182
  }
162
183
  }
163
184
  const ctx = makeContext();
164
- const mutating = ["start", "resume", "register", "remove", "recheck", "say", "cancel"].includes(cmd) || cmd === "chain" && (positionals.length > 2 || values.cancel || values.retry);
185
+ const mutating = ["start", "resume", "register", "remove", "recheck", "say", "cancel"].includes(cmd) || cmd === "review" && arg !== "status" || cmd === "chain" && (positionals.length > 2 || values.cancel || values.retry);
165
186
  const owner = mutating ? acquireCliMutation(ctx.home) : null;
166
187
  try {
167
188
  if (cmd === "recheck" || cmd === "say" || cmd === "cancel") {
@@ -176,6 +197,11 @@ async function dispatch(argv) {
176
197
  return 0;
177
198
  }
178
199
  switch (cmd) {
200
+ case "review": {
201
+ const result = await reviewCommand(ctx, { action: arg, handle: positionals[2], repo: values.repo, mode: values.mode, reason: values.reason, finding: values.finding, run: values.run, capability: values.capability, retry: values.retry, wait: values.wait });
202
+ console.log(JSON.stringify(result, null, 2));
203
+ return result.qualified === false ? 1 : 0;
204
+ }
179
205
  case "chain": {
180
206
  const paths = positionals.slice(2);
181
207
  const operation = paths.length > 0 || values.retry;
@@ -184,7 +210,8 @@ async function dispatch(argv) {
184
210
  if (values.retry && paths.length) throw new Error("--retry uses the existing plan; do not pass PRD paths");
185
211
  if ((values.cancel || values.retry) && !arg) throw new Error("a chain name is required");
186
212
  if (values.base && !paths.length) throw new Error("--base is set when queuing a new chain");
187
- if (paths.length) await queueChain(ctx, { name: arg, paths, base: values.base });
213
+ if (values.after && (!paths.length || values.retry || values.cancel)) throw new Error("--after is set only when queuing a new chain with ready PRD paths");
214
+ if (paths.length) await queueChain(ctx, { name: arg, paths, base: values.base, after: values.after });
188
215
  else if (values.cancel) cancelChain(ctx, arg);
189
216
  else if (values.retry) await retryChain(ctx, { name: arg, resnapshot: values.resnapshot });
190
217
  console.log(renderChains(ctx, arg));
@@ -0,0 +1,40 @@
1
+ #!/usr/bin/env node
2
+ import { parseArgs } from "node:util";
3
+ import { readFile, writeFile } from "node:fs/promises";
4
+ import { makeContext } from "../lib/context.mjs";
5
+ import { promote } from "../lib/promotion.mjs";
6
+ import { makePromotionTransfer } from "../lib/promotion_git.mjs";
7
+
8
+ const help = `Usage: npm run promote:bitbucket -- --github-pr URL --bitbucket-repo bitbucket.org/workspace/repo [--bitbucket-pr N] [--base main] [--branch name] [--out plan.json]
9
+ Default: read-only dry run. Inspect the plan, then add --apply --expected-plan DIGEST.
10
+ Merged sources use retained exact acceptance. If the reported base changed, --accepted-plan plan.json supplies an optional archived-base fallback.
11
+ No force push, merge or deployment. See docs/bitbucket-promotion.md.`;
12
+ let transfer;
13
+ try {
14
+ const { values } = parseArgs({ options: {
15
+ "github-pr": { type: "string" }, "bitbucket-repo": { type: "string" }, "bitbucket-pr": { type: "string" },
16
+ base: { type: "string" }, branch: { type: "string" }, out: { type: "string" }, "accepted-plan": { type: "string" },
17
+ apply: { type: "boolean", default: false }, "expected-plan": { type: "string" }, help: { type: "boolean", short: "h" },
18
+ } });
19
+ if (values.help) console.log(help);
20
+ else {
21
+ if (!values["github-pr"] || !values["bitbucket-repo"]) throw new Error(help);
22
+ if (values.apply && values.out) throw new Error("--out saves a dry-run plan only; omit it when applying");
23
+ let acceptedPlan;
24
+ if (values["accepted-plan"]) {
25
+ const text = await readFile(values["accepted-plan"], "utf8");
26
+ if (Buffer.byteLength(text) > 1_048_576) throw new Error("Accepted plan is oversized");
27
+ acceptedPlan = JSON.parse(text);
28
+ }
29
+ const ctx = makeContext({ readOnly: true });
30
+ transfer = await makePromotionTransfer(ctx);
31
+ const result = await promote(ctx, {
32
+ githubPr: values["github-pr"], bitbucketRepo: values["bitbucket-repo"],
33
+ ...(values["bitbucket-pr"] !== undefined ? { bitbucketPr: Number(values["bitbucket-pr"]) } : {}),
34
+ branch: values.branch, base: values.base, acceptedPlan, apply: values.apply, expectedPlan: values["expected-plan"],
35
+ }, transfer);
36
+ if (values.out) await writeFile(values.out, `${JSON.stringify(result.plan, null, 2)}\n`, { flag: "wx", mode: 0o600 });
37
+ console.log(JSON.stringify(result, null, 2));
38
+ }
39
+ } catch (error) { console.error(error.message); process.exitCode = 1; }
40
+ finally { await transfer?.close(); }
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env node
2
+ import { prOperation } from "../lib/pr_operation.mjs";
3
+ try {
4
+ const result = await prOperation(process.argv.slice(2));
5
+ console.log(typeof result === "string" ? result : JSON.stringify(result, null, 2));
6
+ } catch (error) {
7
+ console.error(error.message);
8
+ process.exitCode = 1;
9
+ }
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env node
2
+ import { parseArgs } from "node:util";
3
+ import { readFileSync } from "node:fs";
4
+ import { makeBitbucketReviewProducer } from "../lib/hosts/bitbucket_review_producer.mjs";
5
+ try {
6
+ const { values, positionals } = parseArgs({ allowPositionals: true, options: Object.fromEntries(["config", "url", "input", "result"].map(key => [key, { type: "string" }])) });
7
+ if (positionals.length !== 1 || !["prepare", "publish"].includes(positionals[0]) || !values.config || !values.url) throw new Error("Use task-review prepare|publish --config <private-reviewer-config> --url <exact-PR-URL> [--input <prepared-json> --result <verdict-json>]");
8
+ const json = path => JSON.parse(readFileSync(path, "utf8"));
9
+ const producer = makeBitbucketReviewProducer({ config: json(values.config) });
10
+ const result = positionals[0] === "prepare" ? await producer.prepare(values.url) : await producer.publish(values.url, json(values.input), json(values.result));
11
+ console.log(JSON.stringify(result, null, 2));
12
+ } catch (error) {
13
+ console.error(error.message);
14
+ process.exitCode = 1;
15
+ }
package/docs/README.md CHANGED
@@ -1,7 +1,9 @@
1
1
  # Documentation
2
2
 
3
- Start with [installation and your first run](install.md), then choose how to
4
- describe the work. [Natural-language tasks](tasks.md) prepare a reviewable brief
3
+ Start with [installation and your first run](install.md): inside the target
4
+ checkout, `npx --yes @uchibeke/gallivant init --harness codex` (or
5
+ `--harness claude`) writes the config, records the repository and prints the
6
+ setup report. Then choose how to describe the work. [Natural-language tasks](tasks.md) prepare a reviewable brief
5
7
  from your request; [hand-authored PRDs](prd.md) let you write that brief directly.
6
8
  Both use the same validation, execution, GitHub review and completion workflow.
7
9
  Code, research and documentation can all be delivered as verifiable repository
@@ -15,9 +17,11 @@ requirements and checks.
15
17
  | Install, configure access and complete a first task | [Getting started](install.md) |
16
18
  | Ask an agent to inspect, install and verify setup | [Agent setup](agent-setup.md) |
17
19
  | Describe work, answer questions, inspect a draft and authorize execution | [Natural-language tasks](tasks.md) |
20
+ | Choose the typed delivery profile, planner route and review a prepared task | [Typed delivery profiles](task-profiles.md) |
18
21
  | Write a brief with acceptance criteria, source files and verification commands | [PRD contract](prd.md) |
19
22
  | Find commands, monitor progress, message or resume a run | [Commands](commands.md) |
20
23
  | Configure repositories, credentials, harnesses and execution limits | [Configuration](config.md) |
24
+ | Request and verify Codex reviews against the current commit | [Codex review procedure](codex-review.md) |
21
25
  | Use the local dashboard and understand product boundaries | [Application](app.md) |
22
26
  | Run coding work on an API-backed hosted environment | [OpenAI Agents API](openai-agents.md) |
23
27
  | Understand the unavailable Codex Cloud dispatch and its required qualification | [Codex Cloud](codex-cloud.md) |