@allocator-one/harness-cli 1.15.1 → 1.17.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.
- package/README.md +256 -38
- package/dist/{chunk-FQWV5MIC.js → chunk-5THYIKLW.js} +26 -4
- package/dist/chunk-A4WZAC7L.js +563 -0
- package/dist/chunk-BHBEIT5I.js +1348 -0
- package/dist/{chunk-L2OWOZ4N.js → chunk-CEEQW6ZV.js} +411 -1556
- package/dist/chunk-W7BVOQQG.js +1448 -0
- package/dist/chunk-WSDFLMO6.js +717 -0
- package/dist/cli.js +1886 -1155
- package/dist/infraone-A3KDADRM.js +249 -0
- package/dist/infraone-V3IKKVBG.js +593 -0
- package/dist/infraone.js +372 -0
- package/dist/{login-page-KGEJFFXR.js → login-page-MFHNVTUV.js} +1 -1
- package/dist/{server-KVRQBVXI.js → server-TRXBTJSA.js} +37 -19
- package/package.json +4 -3
- package/skills/harness-code/SKILL.md +37 -0
- package/spec/openapi.json +4803 -25
package/README.md
CHANGED
|
@@ -196,7 +196,13 @@ wait conditions, `Waiting:` says how many still hold it, and a
|
|
|
196
196
|
`Wait conditions:` section lists each one (`[ ] gate "Finance sign-off" · <id>`,
|
|
197
197
|
`[ ] gate "Compliance sign-off" [compliance] owned by Compliance officer (role:compliance_officer) · <id>`,
|
|
198
198
|
`[x] not before … (satisfied …)`, `system event`) with the key and id
|
|
199
|
-
`harness gate satisfy` takes.
|
|
199
|
+
`harness gate satisfy` takes. An issue that belongs to a plan gets a
|
|
200
|
+
`Plan:` line naming the plan by its root identifier, which the `plan`
|
|
201
|
+
commands take, then its status, the revision it runs, and whether that
|
|
202
|
+
revision lists the issue (`Plan: FR-1 · released · revision 8 · not in revision`,
|
|
203
|
+
with `Operator step` for a step Operator runs). `--json` carries the same as
|
|
204
|
+
`plan` (`{id, root, status, held, revision, in_revision, executor}`, or
|
|
205
|
+
`null`).
|
|
200
206
|
`harness activity <id>` prints the issue's activity timeline: comments,
|
|
201
207
|
creation, state and assignee changes, wait-condition events
|
|
202
208
|
(`Ada satisfied the gate "Finance sign-off"`), and field changes
|
|
@@ -239,12 +245,18 @@ harness create --title "Fix login redirect" --type bug --priority high \
|
|
|
239
245
|
|
|
240
246
|
- `--claim`: atomic. It assigns you and moves the issue to the team's first
|
|
241
247
|
started state. A conflict (exit `1`, HTTP 409) names its reason: someone
|
|
242
|
-
else holds the issue, or it is not claimable yet.
|
|
243
|
-
next step
|
|
244
|
-
executor to `none` with `harness plan edit <plan
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
+
else holds the issue, or it is not claimable yet. Some reasons come with a
|
|
249
|
+
next step. `agent_step`: a person can't claim an Operator step; to do it
|
|
250
|
+
yourself, set its executor to `none` with `harness plan edit <plan>` and
|
|
251
|
+
release the plan again. `plan_not_released`, `not_in_plan_revision` and
|
|
252
|
+
`edited_since_release`: when the server names the one plan governing the
|
|
253
|
+
issue as the one to release, the error ends with the command
|
|
254
|
+
(`run harness plan release FR-1`). When several plans govern it, the
|
|
255
|
+
server names none as the one to release, and the error names the nearest
|
|
256
|
+
to look at instead (`harness plan show FR-1`). A completed plan, or a
|
|
257
|
+
server that does not name the plan, gets no such hint. `waiting_on_condition`:
|
|
258
|
+
`harness show` lists what it waits on; tick a gate with
|
|
259
|
+
`harness gate satisfy`. It cannot be combined with `--assignee`.
|
|
248
260
|
- `--state <name-or-type>`: moves the issue to the workflow state whose name
|
|
249
261
|
or type matches.
|
|
250
262
|
- `--title`, `--description`, `--design`, `--acceptance`, `--priority`,
|
|
@@ -355,12 +367,33 @@ nothing runs until a person releases one.
|
|
|
355
367
|
|
|
356
368
|
```sh
|
|
357
369
|
harness plan create --file plan.yaml --team IO --idempotency-key q3-report
|
|
358
|
-
harness plan
|
|
359
|
-
harness plan
|
|
370
|
+
harness plan list --team IO # the team's plans, by root
|
|
371
|
+
harness plan show IO-120 # by its root issue, or its id
|
|
372
|
+
harness plan release IO-120 --collaborator grace@example.com
|
|
360
373
|
harness gate satisfy IO-121 "Finance sign-off"
|
|
361
374
|
harness gate satisfy IO-121 compliance # by the gate's key
|
|
362
375
|
```
|
|
363
376
|
|
|
377
|
+
**Finding a plan.** Every plan command takes the plan's id or its root
|
|
378
|
+
issue's identifier (`FR-1`, in any casing). A step's identifier does not
|
|
379
|
+
open its plan: `harness show <issue>` names the plan an issue belongs to by
|
|
380
|
+
its root. `harness plan list` lists a team's plans, newest first, with
|
|
381
|
+
their root, status, whether they are held, the revision they run (`-`
|
|
382
|
+
before the first release) and their title:
|
|
383
|
+
|
|
384
|
+
```text
|
|
385
|
+
ROOT STATUS HELD REVISION TITLE
|
|
386
|
+
FR-1 released no 8 Format radar
|
|
387
|
+
FR-200 held yes - Next quarter
|
|
388
|
+
```
|
|
389
|
+
|
|
390
|
+
It takes `--team` (or `HARNESS_TEAM` or the repo config), `--status`
|
|
391
|
+
(`held`, `released`, `running`, `completed` or `needs_attention`) and
|
|
392
|
+
`--limit` (default 50, at most 100). There are no pages: when a list comes
|
|
393
|
+
back full, a stderr notice says older plans may exist. `--json` is the
|
|
394
|
+
server's list unchanged, each plan with its `id`, `root`, `title`,
|
|
395
|
+
`status`, `held`, `revision`, `released_at` and `inserted_at`.
|
|
396
|
+
|
|
364
397
|
**The plan file** is the API's request body, as JSON (`.json`) or YAML
|
|
365
398
|
(anything else, and stdin with `--file -`). YAML is read as YAML 1.2 and
|
|
366
399
|
held to what JSON can carry: dates stay strings, and a duplicate key, an
|
|
@@ -415,7 +448,10 @@ steps:
|
|
|
415
448
|
email). Only the owner can tick an owned gate. You can't name yourself as
|
|
416
449
|
an owner, and that includes a role you hold. `owner: null` or no owner
|
|
417
450
|
leaves the gate unowned.
|
|
418
|
-
- A plan has at most
|
|
451
|
+
- A plan has at most the organization's max plan steps, its root included:
|
|
452
|
+
1,000 unless a Harness admin changed it in Harness settings → Plans, and
|
|
453
|
+
never more than 2,000. Separately, it has at most 100 Operator steps,
|
|
454
|
+
the fixed limit of the delegated grant Operator runs them under.
|
|
419
455
|
- `--team` (or `HARNESS_TEAM` or the repo config) is the root's team and the
|
|
420
456
|
default team for people's steps. `--idempotency-key` works as it does for
|
|
421
457
|
`create`: if a create times out, run it again with the same key to get
|
|
@@ -431,6 +467,18 @@ harness: The plan is not valid; nothing was changed (HTTP 422)
|
|
|
431
467
|
plan: A plan with Operator steps needs a positive spend budget [spend_budget_required]
|
|
432
468
|
```
|
|
433
469
|
|
|
470
|
+
A plan over a step cap gets `too_many_steps`, once for each cap it is
|
|
471
|
+
over, and the line says which cap it is and whether anyone can raise it
|
|
472
|
+
(on create the root has no identifier yet, so the line starts `plan:`):
|
|
473
|
+
|
|
474
|
+
```text
|
|
475
|
+
FR-1: the plan has 1203 steps, above this organization's max plan steps (1000): a Harness admin can raise "Max plan steps" in Harness settings → Plans (max_plan_steps, up to 2000) [too_many_steps]
|
|
476
|
+
FR-1: the plan has 103 Operator steps, above the fixed limit of 100: Operator's delegated grant caps a plan's agent steps, and no setting raises it — hand some to people (executor none) or split the plan [too_many_steps]
|
|
477
|
+
```
|
|
478
|
+
|
|
479
|
+
The same applies to `plan edit` and `plan release`, which check the caps
|
|
480
|
+
again, and to the MCP tools' error text.
|
|
481
|
+
|
|
434
482
|
A gate's owner is checked the same way. The owner violations are
|
|
435
483
|
`invalid_owner`, `unknown_role`, `unknown_owner`, `owner_is_member`,
|
|
436
484
|
`owner_is_actor` (you named yourself), `owner_not_allowed` (an owner on a
|
|
@@ -438,10 +486,11 @@ condition that is not a gate), `expert_owner_requires_plan`, and
|
|
|
438
486
|
`duplicate_gate_key`. A `gate:` that conflicts with the condition's `kind`
|
|
439
487
|
or `key` is `invalid_condition`.
|
|
440
488
|
|
|
441
|
-
**Show.** `harness plan show <plan
|
|
489
|
+
**Show.** `harness plan show <plan>` prints the plan's status, budgets,
|
|
442
490
|
revision, and spend estimate, then every step in tree order (indented by
|
|
443
491
|
depth) with its key, executor, state, and status. The status is `ready`,
|
|
444
|
-
`held` (
|
|
492
|
+
`held` (an Operator step changed since the release, which waits for the
|
|
493
|
+
next one; a person's changed step stays `ready`), `not in revision` (added after it),
|
|
445
494
|
`waiting` (on a wait condition), `container`, `done`, `cancelled`,
|
|
446
495
|
`archived`, or `-`. The edges and each step's wait conditions come after
|
|
447
496
|
the steps. Each gate shows its key and owner. A `Waiting for:` section then
|
|
@@ -465,7 +514,7 @@ email), or an outside expert by email (`val@example.com (expert)`).
|
|
|
465
514
|
`[]` when nobody can tick, `null` for an unowned gate or when the holders
|
|
466
515
|
are not known).
|
|
467
516
|
|
|
468
|
-
**Edit.** `harness plan edit <plan
|
|
517
|
+
**Edit.** `harness plan edit <plan> --file edits.yaml` changes step
|
|
469
518
|
executors and keys, naming each step by its `step` key or `issue`
|
|
470
519
|
identifier, and the budgets (`retry_budget`, `spend_budget_cents`):
|
|
471
520
|
|
|
@@ -475,33 +524,38 @@ steps:
|
|
|
475
524
|
executor: none # hand the step to a person
|
|
476
525
|
```
|
|
477
526
|
|
|
478
|
-
Editing a released step
|
|
479
|
-
|
|
527
|
+
Editing a released Operator step, or handing one to a person, holds it
|
|
528
|
+
until the plan is released again. A person's step stays workable, and the
|
|
529
|
+
next release takes the change in; until then the plan lists every changed
|
|
530
|
+
step under `Changed since the release:`. A budget change needs the plan
|
|
531
|
+
held first. Descriptions, parents, and edges
|
|
480
532
|
are edited with the issue commands (`update`, `dep`). Conditions are set
|
|
481
533
|
when the plan is created. Editing them later goes through the API's issue
|
|
482
534
|
condition endpoints, which have no command yet; `gate satisfy` ticks a
|
|
483
535
|
gate.
|
|
484
536
|
|
|
485
|
-
**Release and hold.** `harness plan release <plan
|
|
486
|
-
you: it freezes the next revision
|
|
537
|
+
**Release and hold.** `harness plan release <plan>` releases the plan as
|
|
538
|
+
you: it freezes the next revision, which takes in the steps added or edited
|
|
539
|
+
since the last one, and lets ready steps run.
|
|
487
540
|
`--collaborator <id-or-email>` (repeatable) adds people to the plan room
|
|
488
541
|
where its Operator steps run, and `--retry-budget` and
|
|
489
542
|
`--spend-budget-cents` set the budgets. Each Operator step runs as a job
|
|
490
543
|
(`harness jobs` names its plan step), and the changes a job proposes need a
|
|
491
544
|
person's approval in the app, at the job's approval link. The CLI never
|
|
492
|
-
approves. `harness plan hold <plan
|
|
545
|
+
approves. `harness plan hold <plan>` pauses every step until the plan is
|
|
493
546
|
released again.
|
|
494
547
|
|
|
495
548
|
**Gates.** `harness gate satisfy <issue> <gate>` ticks a gate and
|
|
496
549
|
`harness gate unsatisfy <issue> <gate>` unticks it. `<gate>` is the gate's
|
|
497
|
-
key, its label, or its condition id, all shown by `harness show`.
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
550
|
+
key, its label, or its condition id, all shown by `harness show`. A condition
|
|
551
|
+
UUID writes directly without listing conditions, so a non-staff gate owner can
|
|
552
|
+
reach the server's write authorization. A UUID always addresses that condition,
|
|
553
|
+
even if another gate uses it as its key or label. Keys and labels require the
|
|
554
|
+
staff-only lookup; a denied lookup explains how to use a condition id instead.
|
|
555
|
+
When a name matches multiple gates, the command lists their ids instead of
|
|
556
|
+
choosing. Only when nothing matches exactly does a label or key match ignoring
|
|
557
|
+
case, and that too is refused when more than one gate matches. Ticking a gate
|
|
558
|
+
requires staff standing in the organization or a place in its plan's room. The server refuses an
|
|
505
559
|
Operator-only login (`operator-cli`) here, even for a person in the plan's
|
|
506
560
|
room: it reaches only the Operator commands, `whoami` and `logout`. Only
|
|
507
561
|
the owner can tick an owned gate, and only its owner or Harness staff can
|
|
@@ -513,8 +567,10 @@ harness: Cannot satisfy gate "Compliance sign-off" on IO-121: only its owner, Co
|
|
|
513
567
|
```
|
|
514
568
|
|
|
515
569
|
A gate with no owner by then gets the same error without a name. Against
|
|
516
|
-
a server that does not send the owner,
|
|
517
|
-
again to find it.
|
|
570
|
+
a server that does not send the owner, a key or label write reads the conditions
|
|
571
|
+
again to find it. A direct condition-id write never lists conditions, including
|
|
572
|
+
on errors, and leaves the owner unnamed if the refusal does not name one.
|
|
573
|
+
Direct writes also make no claim about other conditions still holding the issue.
|
|
518
574
|
|
|
519
575
|
**Conditions.** `harness conditions <issue>` lists an issue's wait
|
|
520
576
|
conditions, oldest first, one per line as `show` lists them: each one's
|
|
@@ -522,7 +578,9 @@ box, what it waits for (a gate's label, key and owner), when and by whom it
|
|
|
522
578
|
was satisfied, and its id. `--json` is the list as the server sends it.
|
|
523
579
|
|
|
524
580
|
A server without the plan API answers the plan commands with a 404, and the
|
|
525
|
-
error says that the server may predate plans.
|
|
581
|
+
error says that the server may predate plans. A root identifier that opens
|
|
582
|
+
no plan is the same 404 as an unknown id, and the error says how to find
|
|
583
|
+
the plan an issue belongs to.
|
|
526
584
|
|
|
527
585
|
## Outside experts
|
|
528
586
|
|
|
@@ -869,6 +927,121 @@ refusal exits 1 with the server's message and what it means
|
|
|
869
927
|
answers a capability that doesn't exist, ships disabled, or is switched off
|
|
870
928
|
with the same 404.
|
|
871
929
|
|
|
930
|
+
## Code index
|
|
931
|
+
|
|
932
|
+
```sh
|
|
933
|
+
harness code sync # sync this worktree’s overlay
|
|
934
|
+
harness code sync --path ../app # use that worktree’s host/org config
|
|
935
|
+
harness code status --json # active version and local freshness
|
|
936
|
+
harness code status --skipped # include the base’s skipped-files report
|
|
937
|
+
```
|
|
938
|
+
|
|
939
|
+
The repository must be shared through the organization’s Harness GitHub
|
|
940
|
+
connection and code indexing must be enabled for that org. The server builds
|
|
941
|
+
commit bases from GitHub. The CLI polls a fetching base with backoff, opens an
|
|
942
|
+
overlay sync, uploads only blobs that sync requests, and activates it. It never
|
|
943
|
+
uploads a base or follows source symlinks. A successful sync reports the server’s
|
|
944
|
+
state; `queued` means indexing has been requested, not that queries are ready.
|
|
945
|
+
Safe source reads require macOS 11 or later, or Linux with `/proc/self/fd`;
|
|
946
|
+
code sync refuses when these kernel facilities are unavailable.
|
|
947
|
+
|
|
948
|
+
Sync needs both `harness:read` and `harness:write`; ordinary `code status`
|
|
949
|
+
needs `harness:read`, and base-status requests also need `harness:write`. `--skipped` on sync or status asks the server for its base
|
|
950
|
+
exclusions (path and reason). Local binary, oversized, ignored and secret-shaped
|
|
951
|
+
files are excluded before upload. Built-in secret rules cannot be removed by
|
|
952
|
+
an ignore-file negation. Deny and secret-path matches use ASCII case-insensitive
|
|
953
|
+
checks; path identities are preserved. Served content expressions must exactly
|
|
954
|
+
match the reviewed sources bundled with this client, or be literal-only markers
|
|
955
|
+
matched as substrings. Other expressions stop sync with an upgrade message before
|
|
956
|
+
source scanning. Source content is never included in diagnostics.
|
|
957
|
+
|
|
958
|
+
`.harnesscodeignore` uses the code-index policy dialect, not Git's ignore
|
|
959
|
+
grammar: each line is trimmed; `#` and `!` lines are skipped; and a backslash
|
|
960
|
+
is literal. The CLI reports warnings for skipped `!` lines and backslashes.
|
|
961
|
+
Patterns are case-sensitive, limited to 256 bytes and eight `*` characters,
|
|
962
|
+
and an ignore file has at most 1,000 patterns and 64 KiB. The server's indexed
|
|
963
|
+
extensions are exact, so `.TS` is distinct from `.ts`.
|
|
964
|
+
|
|
965
|
+
The working copy's `.harnesscodeignore` governs its view. The CLI compares it with
|
|
966
|
+
the committed ignore file: newly ignored base paths become delete entries, and
|
|
967
|
+
newly included files are read from the worktree through the usual policy checks.
|
|
968
|
+
It never reads unchanged source content from the base. If ignore changes exceed
|
|
969
|
+
20,000 overlay paths, commit the ignore file so the server-built base honors it.
|
|
970
|
+
|
|
971
|
+
View/session state is isolated by server, organization, repository and worktree
|
|
972
|
+
under the user’s cache directory. `HARNESS_CODE_STATE_DIR` overrides the directory
|
|
973
|
+
and must be absolute. It stores control metadata and hashes, not source bytes or
|
|
974
|
+
tokens. Retrying the same interrupted overlay reuses its client ID. An uncertain
|
|
975
|
+
activation retains its opened sync ID and timestamp; the CLI reads that sync and
|
|
976
|
+
records its original pending version once it is no longer receiving. A missing sync
|
|
977
|
+
is treated as a replaced, never-activated sync only within 60 minutes; an older
|
|
978
|
+
missing sync fails closed. The server keeps a client ID unique per view and
|
|
979
|
+
manifest across states, so the CLI never uses one for a different manifest. A stale
|
|
980
|
+
policy is fetched again and the overlay rescanned. Syncs of the same local view are serialized: a
|
|
981
|
+
second sync is refused while one is running, because opening a sync can replace older
|
|
982
|
+
unactivated syncs on the server. If the process is forcibly interrupted, its error
|
|
983
|
+
message names the lock directory; remove it only after confirming no sync is running.
|
|
984
|
+
The server refuses overlays above 20,000 paths; sync against a newer base commit. A failed index is reported as `failed` with exit
|
|
985
|
+
code 1, while a worktree with no sync is `not_synced`.
|
|
986
|
+
|
|
987
|
+
### Query the active view
|
|
988
|
+
|
|
989
|
+
```sh
|
|
990
|
+
harness code search 'process' --kind function --limit 20
|
|
991
|
+
harness code explain 'OPAQUE_ID_FROM_SEARCH' --budget-tokens 4000
|
|
992
|
+
harness code affected --symbol 'OPAQUE_ID' --file src/app.ts --depth 3
|
|
993
|
+
harness code context --symbol 'OPAQUE_ID' --budget-tokens 2000 --json
|
|
994
|
+
harness code context 'name' --path ../app
|
|
995
|
+
```
|
|
996
|
+
|
|
997
|
+
Queries need `harness:read` and an existing view from `code sync`. They read its
|
|
998
|
+
active version, even while a later version is pending. The output includes base
|
|
999
|
+
commit, overlay digest, active version and pending progress. Querying neither
|
|
1000
|
+
scans nor uploads local source. No code-index MCP tools are registered.
|
|
1001
|
+
|
|
1002
|
+
Human output cites `path:line@sha256`, indexed snippets, version and base/overlay
|
|
1003
|
+
origin. Search citations may lack snippet text: use `context` to retrieve it.
|
|
1004
|
+
Context items that exceed the budget remain citations explicitly lacking text.
|
|
1005
|
+
JSON preserves server `data` and `meta`, adding a `guidance` array. Resolved,
|
|
1006
|
+
possible, name-only and unresolved references remain separate. A snippet budget
|
|
1007
|
+
covers the server's indexed text, not command formatting or metadata.
|
|
1008
|
+
|
|
1009
|
+
Contract 1.3 `meta.truncation` is always displayed: the returned count, the total
|
|
1010
|
+
if the server supplies it, limits and next command or narrowing hint. The CLI
|
|
1011
|
+
never invents a total or silently pages beyond the request. A `not_tracked`
|
|
1012
|
+
coverage answer gives a local `rg` hint instead of asserting there are no callers.
|
|
1013
|
+
Results cite the indexed snapshot; inspect the current file before editing it.
|
|
1014
|
+
|
|
1015
|
+
IDs are opaque. Swift IDs include declaration positions and can stop resolving
|
|
1016
|
+
when an edit moves a declaration; qualified names can include argument labels.
|
|
1017
|
+
Do not parse or reconstruct either. `not_found` asks you to search again, rather
|
|
1018
|
+
than blindly retrying an old symbol. `--include-ambiguous` and `--include-types`
|
|
1019
|
+
explicitly expand the affected walk; without them, possible/type impact is
|
|
1020
|
+
reported separately. Limits are bounded (search 1–100; depth 1–6; at most 200
|
|
1021
|
+
seeds; snippet budget 100–16,000, or 100–32,000 for context).
|
|
1022
|
+
|
|
1023
|
+
### Agent Skill
|
|
1024
|
+
|
|
1025
|
+
The portable source of truth ships as `skills/harness-code/SKILL.md` in both npm
|
|
1026
|
+
packages. Copy it into your consumer repo's skill tree, following that repo's
|
|
1027
|
+
adapters and metadata conventions. For an agent that discovers `.agents/skills`:
|
|
1028
|
+
|
|
1029
|
+
```sh
|
|
1030
|
+
mkdir -p .agents/skills
|
|
1031
|
+
cp -R "$(npm root -g)/@allocator-one/harness-cli/skills/harness-code" .agents/skills/
|
|
1032
|
+
```
|
|
1033
|
+
|
|
1034
|
+
A short `AGENTS.md`/`CLAUDE.md` snippet:
|
|
1035
|
+
|
|
1036
|
+
> For symbol relationships, callers, impact and cited context, use the
|
|
1037
|
+
> harness-code skill and `harness code search/explain/affected/context`. Start
|
|
1038
|
+
> with `code status`; use `rg` for literal text and `not_tracked` coverage.
|
|
1039
|
+
> Report truncation and indexed hashes/versions; search again after missing IDs.
|
|
1040
|
+
|
|
1041
|
+
Allocator-one adoption and a paired agent tool-use comparison against a grep-only
|
|
1042
|
+
baseline are delivered in the consumer follow-up to CLI-70, before publication.
|
|
1043
|
+
|
|
1044
|
+
|
|
872
1045
|
## Uploads
|
|
873
1046
|
|
|
874
1047
|
`harness upload <path>` uploads a file and prints a markdown reference to
|
|
@@ -942,6 +1115,31 @@ Login tokens have it; `aone_` tokens need to be minted with it. There is
|
|
|
942
1115
|
deliberately no MCP tool for keys, because a tool result is text the model
|
|
943
1116
|
can read.
|
|
944
1117
|
|
|
1118
|
+
## Review gate
|
|
1119
|
+
|
|
1120
|
+
A pull request merges only once its enforced Review Council gate, the
|
|
1121
|
+
attested review a gate workflow runs for its head, has converged. When that
|
|
1122
|
+
gate sits at `unverified`, these commands say why and recover it:
|
|
1123
|
+
|
|
1124
|
+
- `harness review status <pr>` prints the enforced and advisory status, the
|
|
1125
|
+
head's gate check, and a failed or timed-out latest attempt with its reason,
|
|
1126
|
+
whether its evidence was recorded, and what comes next. Next is either an
|
|
1127
|
+
automatic retry by Harness or a retry you request. `--json` returns the gate
|
|
1128
|
+
status as the server sends it.
|
|
1129
|
+
- `harness review retry <pr> [--reason <text>]` retries the latest attempt of
|
|
1130
|
+
the current head's gate check. It reads the head, the check and the attempt
|
|
1131
|
+
from the gate status, so you name only the pull request, and prints the new
|
|
1132
|
+
attempt (`--json`: `{attempt, outcome}`). Running it again for the same
|
|
1133
|
+
attempt returns the attempt already queued rather than paying for another
|
|
1134
|
+
review run. It needs a login with `reviews:write`. It refuses, saying why,
|
|
1135
|
+
while the attempt is still running, while Harness is retrying it itself, or
|
|
1136
|
+
when the head's advisory review has not converged.
|
|
1137
|
+
|
|
1138
|
+
`<pr>` is `owner/repo#<number>`, the pull request URL, or a bare number read
|
|
1139
|
+
against `--repo owner/repo` or this checkout's GitHub `origin`. Never dispatch
|
|
1140
|
+
the gate workflow by hand instead: a run without a registered attempt cannot
|
|
1141
|
+
approve the head.
|
|
1142
|
+
|
|
945
1143
|
## Scripting contract
|
|
946
1144
|
|
|
947
1145
|
- **`--json` on every command** except `mcp`. It replaces the human output
|
|
@@ -999,7 +1197,7 @@ command instead of the `npx` form. Any other MCP client can use the same command
|
|
|
999
1197
|
{ "mcpServers": { "harness": { "command": "npx", "args": ["-y", "@allocator-one/harness-cli", "mcp"] } } }
|
|
1000
1198
|
```
|
|
1001
1199
|
|
|
1002
|
-
The server exposes
|
|
1200
|
+
The server exposes 74 tools:
|
|
1003
1201
|
|
|
1004
1202
|
| Area | Tools |
|
|
1005
1203
|
| --- | --- |
|
|
@@ -1011,7 +1209,7 @@ The server exposes 72 tools:
|
|
|
1011
1209
|
| Labels | `label_list`, `label_create`, `label_update`, `label_delete` |
|
|
1012
1210
|
| Teams and states | `team_list`, `team_create`, `team_rename`, `team_set_default`, `workflow_states`, `state_add`, `state_update`, `state_order`, `state_delete` |
|
|
1013
1211
|
| People | `member_list`, `member_add`, `member_set_role`, `user_list` |
|
|
1014
|
-
| Plans and gates | `plan_create`, `plan_show`, `plan_edit`, `plan_release`, `plan_hold`, `gate_set`, `condition_list` |
|
|
1212
|
+
| Plans and gates | `plan_list`, `plan_create`, `plan_show`, `plan_edit`, `plan_release`, `plan_hold`, `gate_set`, `condition_list` |
|
|
1015
1213
|
| Outside experts | `assignment_list` |
|
|
1016
1214
|
| Operator jobs | `jobs_list`, `job_show`, `job_changes`, `job_start`, `job_steer`, `job_cancel`, `job_pause` |
|
|
1017
1215
|
| Continue and procedures | `job_continue`, `procedure_save`, `procedure_show`, `procedure_run` |
|
|
@@ -1040,7 +1238,9 @@ Some tools behave differently from their commands:
|
|
|
1040
1238
|
`steps`, `retry_budget`, and `spend_budget_cents` directly. As with every
|
|
1041
1239
|
tool, a top-level argument the tool does not declare is dropped.
|
|
1042
1240
|
`gate_set` takes `issue`, `gate` (a key, label, or condition id), and
|
|
1043
|
-
`satisfied`.
|
|
1241
|
+
`satisfied`. The plan tools' `id` is the plan's id or its root issue's
|
|
1242
|
+
identifier, as for the commands; `plan_list` takes `team`, `status` and
|
|
1243
|
+
`limit`, and `issue_show` carries the issue's `plan`.
|
|
1044
1244
|
- An API error's details come back in the tool error text: a validation
|
|
1045
1245
|
error's fields, and an invalid plan's violations, one per line by step
|
|
1046
1246
|
key.
|
|
@@ -1100,16 +1300,32 @@ directory the way git finds `.git`, gives every clone of a repo the same
|
|
|
1100
1300
|
defaults:
|
|
1101
1301
|
|
|
1102
1302
|
```json
|
|
1103
|
-
{ "team": "CLI" }
|
|
1303
|
+
{ "team": "CLI", "org": "3f96a9c0-1584-4c65-9c4b-056055024bc9" }
|
|
1104
1304
|
```
|
|
1105
1305
|
|
|
1106
1306
|
| Field | Effect |
|
|
1107
1307
|
| --- | --- |
|
|
1108
1308
|
| `team` | Default team key. Precedence: `--team`, then `HARNESS_TEAM`, then the repo config. |
|
|
1109
1309
|
| `url` | Target host. `HARNESS_API_URL` takes precedence. Before an automatic login opens a browser at a host that only the repo names, the CLI asks for confirmation, once per host. |
|
|
1110
|
-
| `org` |
|
|
1111
|
-
|
|
1112
|
-
A malformed file is ignored with a warning on stderr.
|
|
1310
|
+
| `org` | Organization UUID selecting an org-bound login. Login verifies the server-reported org before storing it. The org never derives a hostname or becomes an API header. |
|
|
1311
|
+
|
|
1312
|
+
A malformed file is ignored with a warning on stderr. An invalid org UUID
|
|
1313
|
+
refuses the command. With `org`, the host defaults to `https://harness.infra.one`
|
|
1314
|
+
unless `url` or `HARNESS_API_URL` specifies it. The repo-selected host passes
|
|
1315
|
+
the same once-per-host trust prompt as a repo `url` before browser login.
|
|
1316
|
+
|
|
1317
|
+
Sign in once with `harness login` from the repo and select its organization
|
|
1318
|
+
on the page. Org logins use separate host-and-org-keyed credential files,
|
|
1319
|
+
so logging into one org does not overwrite or revoke another org's login.
|
|
1320
|
+
The legacy `credentials.json` remains unchanged and is used by repos without
|
|
1321
|
+
`org`. When adding `org` to an existing repo, log in again for that org; the
|
|
1322
|
+
legacy credential is not assumed to belong to it. `logout` revokes and
|
|
1323
|
+
forgets only the selected login. Explicit `HARNESS_API_TOKEN` credentials
|
|
1324
|
+
override org selection; their authority remains whatever the server minted.
|
|
1325
|
+
An org-specific login accepts only a credential whose session describes that
|
|
1326
|
+
organization. Outside-expert `pxc_` credentials have no org description, so
|
|
1327
|
+
use them from a repo without `org` or pass them explicitly through
|
|
1328
|
+
`HARNESS_API_TOKEN`.
|
|
1113
1329
|
|
|
1114
1330
|
### Hosts and tokens
|
|
1115
1331
|
|
|
@@ -1123,13 +1339,14 @@ refuses with exit code 2 instead of sending the token there. Set
|
|
|
1123
1339
|
`HARNESS_API_URL` explicitly if you do mean that host. Without
|
|
1124
1340
|
`HARNESS_API_TOKEN`, a repo-named host needs a login of its own, and the
|
|
1125
1341
|
automatic login asks for confirmation first, as described above. Plain
|
|
1126
|
-
`http://` is accepted only for localhost
|
|
1342
|
+
`http://` is accepted only for `localhost`, any `*.localhost` host (such as
|
|
1343
|
+
a local `harness.infraone.localhost` dev server), `127.0.0.1` and `[::1]`.
|
|
1127
1344
|
|
|
1128
1345
|
### Environment variables
|
|
1129
1346
|
|
|
1130
1347
|
| Variable | Effect |
|
|
1131
1348
|
| --- | --- |
|
|
1132
|
-
| `HARNESS_API_URL` | Target host (https, or http against localhost only). |
|
|
1349
|
+
| `HARNESS_API_URL` | Target host (https, or http against `localhost`, `*.localhost`, `127.0.0.1` or `[::1]` only). |
|
|
1133
1350
|
| `HARNESS_API_TOKEN` | An `aone_…` API token, or an outside expert's `pxc_…` credential. It takes precedence over the stored login. Headless use only. |
|
|
1134
1351
|
| `HARNESS_ACTOR` | Write attribution, sent only when set. Without it the server attributes writes to the signed-in user, or for `aone_` tokens to the token's name. Headless use only. |
|
|
1135
1352
|
| `HARNESS_TEAM` | Default team key for commands that take `--team`. |
|
|
@@ -1143,6 +1360,7 @@ automatic login asks for confirmation first, as described above. Plain
|
|
|
1143
1360
|
|
|
1144
1361
|
| Path | Contents |
|
|
1145
1362
|
| --- | --- |
|
|
1363
|
+
| `~/.config/harness/credentials-org-<hash>.json` | A server-verified org login, keyed by host and org UUID, mode 0600; same `{url, token}` format. |
|
|
1146
1364
|
| `~/.config/harness/credentials.json` | The stored login: one `{url, token}` pair, mode 0600. |
|
|
1147
1365
|
| `~/.config/harness/trusted-hosts.json` | Repo-config hosts you agreed to log in to. |
|
|
1148
1366
|
| `~/.cache/harness/attachments/` | Images downloaded by `show` (or `HARNESS_CACHE_DIR`). |
|
|
@@ -11,14 +11,34 @@ var CLI_PACKAGE = pkg.name;
|
|
|
11
11
|
// src/invocation.ts
|
|
12
12
|
import { basename } from "path";
|
|
13
13
|
var OPERATOR_PACKAGE = "@allocator-one/operator";
|
|
14
|
-
|
|
14
|
+
var INFRAONE_PACKAGE = "@allocator-one/infraone";
|
|
15
|
+
var PACKAGES = {
|
|
16
|
+
harness: "@allocator-one/harness-cli",
|
|
17
|
+
operator: OPERATOR_PACKAGE,
|
|
18
|
+
infraone: INFRAONE_PACKAGE
|
|
19
|
+
};
|
|
20
|
+
var operatorMount = false;
|
|
21
|
+
function mountOperatorUnderInfraone() {
|
|
22
|
+
operatorMount = true;
|
|
23
|
+
}
|
|
24
|
+
function operatorMounted() {
|
|
25
|
+
return operatorMount;
|
|
26
|
+
}
|
|
27
|
+
function invokedName(argv1 = process.argv[1], packageName = CLI_PACKAGE, infraoneBinary = typeof __INFRAONE_BINARY__ !== "undefined" && __INFRAONE_BINARY__ === true) {
|
|
28
|
+
if (operatorMount) return "operator";
|
|
29
|
+
if (infraoneBinary) return "infraone";
|
|
15
30
|
const typed = basename(argv1 ?? "").replace(/\.[cm]?js$/i, "").toLowerCase();
|
|
16
|
-
if (typed === "operator" || typed === "harness") return typed;
|
|
17
|
-
|
|
31
|
+
if (typed === "operator" || typed === "harness" || typed === "infraone") return typed;
|
|
32
|
+
if (packageName === OPERATOR_PACKAGE) return "operator";
|
|
33
|
+
return packageName === INFRAONE_PACKAGE ? "infraone" : "harness";
|
|
18
34
|
}
|
|
19
35
|
function named(text, name = invokedName()) {
|
|
20
36
|
if (name === "harness") return text;
|
|
21
|
-
|
|
37
|
+
if (name === "operator" && operatorMount) return mountedNamed(text);
|
|
38
|
+
return text.replace(/^harness: /gm, `${name}: `).replace(/(?<![\w@/.-])harness (?=[a-z])(?!disagree)/g, `${name} `).replaceAll(PACKAGES.harness, PACKAGES[name]);
|
|
39
|
+
}
|
|
40
|
+
function mountedNamed(text) {
|
|
41
|
+
return text.replace(/^(?:harness|operator): /gm, "infraone: ").replace(/(?<![\w@/.-])(?<!infraone )(?:harness|operator) (?=[a-z[<])(?!disagree)/g, "infraone operator ").replaceAll(PACKAGES.harness, INFRAONE_PACKAGE).replaceAll(OPERATOR_PACKAGE, INFRAONE_PACKAGE);
|
|
22
42
|
}
|
|
23
43
|
var OPERATOR_COMMANDS = [
|
|
24
44
|
"run",
|
|
@@ -67,6 +87,8 @@ export {
|
|
|
67
87
|
CLI_VERSION,
|
|
68
88
|
CLI_PACKAGE,
|
|
69
89
|
OPERATOR_PACKAGE,
|
|
90
|
+
mountOperatorUnderInfraone,
|
|
91
|
+
operatorMounted,
|
|
70
92
|
invokedName,
|
|
71
93
|
named,
|
|
72
94
|
layoutOperatorHelp
|