@allocator-one/harness-cli 1.15.0 → 1.16.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 +192 -47
- package/dist/chunk-FQWV5MIC.js +73 -0
- package/dist/{chunk-I2S2JVCQ.js → chunk-GVTZKAXC.js} +432 -107
- package/dist/cli.js +455 -158
- package/dist/{login-page-UVUKFFTT.js → login-page-KGEJFFXR.js} +12 -5
- package/dist/{server-O7CX2ZCC.js → server-F6YRKNC2.js} +78 -17
- package/package.json +1 -1
- package/spec/openapi.json +6593 -4421
package/README.md
CHANGED
|
@@ -63,7 +63,10 @@ Only the presentation depends on the name you typed:
|
|
|
63
63
|
`harness mcp` under `harness`. The tools are the same.
|
|
64
64
|
|
|
65
65
|
Messages, exit codes and `--json` output are the same under both names, so
|
|
66
|
-
a script written for `harness` works with `operator` unchanged. The
|
|
66
|
+
a script written for `harness` works with `operator` unchanged. The
|
|
67
|
+
exceptions are the version label and the hints that tell you what to
|
|
68
|
+
type, such as `operator login`: they name the command you typed, because
|
|
69
|
+
someone who installed only `@allocator-one/operator` has no `harness`. The CLI
|
|
67
70
|
tells the names apart by the command path it was started with. Launchers
|
|
68
71
|
that start it by its file path instead, such as npm's Windows shims, pnpm,
|
|
69
72
|
Volta and Yarn PnP, hide that path. In that case the CLI goes by the
|
|
@@ -84,8 +87,29 @@ worktree, and agent slot on the machine.
|
|
|
84
87
|
- `harness logout`: revokes the stored login on the server and deletes it
|
|
85
88
|
locally.
|
|
86
89
|
- `harness whoami`: shows the resolved host and where the credential came
|
|
87
|
-
from.
|
|
88
|
-
|
|
90
|
+
from. For a login it also shows the kind of credential, the user, the
|
|
91
|
+
organization and when it expires, as `GET /api/v1/session` describes it.
|
|
92
|
+
On a server without that route, or with an `aone_…` API token, those
|
|
93
|
+
fields are `null` under `--json`. With an outside expert's `pxc_…`
|
|
94
|
+
credential it names the expert's role and plan instead (see
|
|
95
|
+
[Outside experts](#outside-experts)).
|
|
96
|
+
|
|
97
|
+
A login gets one of two kinds of credential. The server picks the kind from
|
|
98
|
+
your standing in the organization you choose:
|
|
99
|
+
|
|
100
|
+
- `harness-cli` is the full credential that Harness staff get.
|
|
101
|
+
- `operator-cli` is the Operator-only credential that any other admin or
|
|
102
|
+
member Operator serves gets. It reaches the Operator commands, `whoami`
|
|
103
|
+
and `logout`, and the server refuses everything else (issues, plans,
|
|
104
|
+
gates) with 403.
|
|
105
|
+
|
|
106
|
+
`login` says after signing in which kind you got (`kind` under `--json`).
|
|
107
|
+
If the new credential fails verification, nothing is stored. A credential
|
|
108
|
+
the browser login just minted is then revoked, in one best-effort attempt,
|
|
109
|
+
so a 30-day credential isn't left behind. A token you pasted is never
|
|
110
|
+
revoked, whatever the failure, since you may be using it elsewhere.
|
|
111
|
+
Holders keep their kind even after gaining staff standing: they log in again
|
|
112
|
+
to get the full credential.
|
|
89
113
|
|
|
90
114
|
`operator login`, `operator logout` and `operator whoami` are the same
|
|
91
115
|
commands and use the same stored login.
|
|
@@ -160,14 +184,25 @@ design, acceptance criteria, notes, and comments (up to 20, cached locally)
|
|
|
160
184
|
and prints their paths. Screenshots are often the reproduction, so read
|
|
161
185
|
them. `--no-images` skips the downloads. If a download fails, a stderr
|
|
162
186
|
notice says so and the command still succeeds. `harness comments <id>`
|
|
163
|
-
prints the full, untruncated comment thread with comment ids.
|
|
187
|
+
prints the full, untruncated comment thread with comment ids, oldest first.
|
|
188
|
+
It requests up to 200 comments per page and follows the oldest comment id
|
|
189
|
+
until the server reports `has_more=false`. `--json` and the MCP
|
|
190
|
+
`comment_list` tool return the same complete array of full comment objects.
|
|
191
|
+
Missing pagination metadata, repeated comment ids, or an older-page failure
|
|
192
|
+
produce an error without presenting a partial thread as complete. The
|
|
164
193
|
`Blocked:` line names a cancelled or archived blocker as such
|
|
165
194
|
(`yes, by CLI-3 (cancelled), CLI-4 (archived), CLI-5`). When the issue has
|
|
166
195
|
wait conditions, `Waiting:` says how many still hold it, and a
|
|
167
196
|
`Wait conditions:` section lists each one (`[ ] gate "Finance sign-off" · <id>`,
|
|
168
197
|
`[ ] gate "Compliance sign-off" [compliance] owned by Compliance officer (role:compliance_officer) · <id>`,
|
|
169
198
|
`[x] not before … (satisfied …)`, `system event`) with the key and id
|
|
170
|
-
`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`).
|
|
171
206
|
`harness activity <id>` prints the issue's activity timeline: comments,
|
|
172
207
|
creation, state and assignee changes, wait-condition events
|
|
173
208
|
(`Ada satisfied the gate "Finance sign-off"`), and field changes
|
|
@@ -210,12 +245,18 @@ harness create --title "Fix login redirect" --type bug --priority high \
|
|
|
210
245
|
|
|
211
246
|
- `--claim`: atomic. It assigns you and moves the issue to the team's first
|
|
212
247
|
started state. A conflict (exit `1`, HTTP 409) names its reason: someone
|
|
213
|
-
else holds the issue, or it is not claimable yet.
|
|
214
|
-
next step
|
|
215
|
-
executor to `none` with `harness plan edit <plan
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
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`.
|
|
219
260
|
- `--state <name-or-type>`: moves the issue to the workflow state whose name
|
|
220
261
|
or type matches.
|
|
221
262
|
- `--title`, `--description`, `--design`, `--acceptance`, `--priority`,
|
|
@@ -326,12 +367,33 @@ nothing runs until a person releases one.
|
|
|
326
367
|
|
|
327
368
|
```sh
|
|
328
369
|
harness plan create --file plan.yaml --team IO --idempotency-key q3-report
|
|
329
|
-
harness plan
|
|
330
|
-
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
|
|
331
373
|
harness gate satisfy IO-121 "Finance sign-off"
|
|
332
374
|
harness gate satisfy IO-121 compliance # by the gate's key
|
|
333
375
|
```
|
|
334
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
|
+
|
|
335
397
|
**The plan file** is the API's request body, as JSON (`.json`) or YAML
|
|
336
398
|
(anything else, and stdin with `--file -`). YAML is read as YAML 1.2 and
|
|
337
399
|
held to what JSON can carry: dates stay strings, and a duplicate key, an
|
|
@@ -386,7 +448,10 @@ steps:
|
|
|
386
448
|
email). Only the owner can tick an owned gate. You can't name yourself as
|
|
387
449
|
an owner, and that includes a role you hold. `owner: null` or no owner
|
|
388
450
|
leaves the gate unowned.
|
|
389
|
-
- 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.
|
|
390
455
|
- `--team` (or `HARNESS_TEAM` or the repo config) is the root's team and the
|
|
391
456
|
default team for people's steps. `--idempotency-key` works as it does for
|
|
392
457
|
`create`: if a create times out, run it again with the same key to get
|
|
@@ -402,6 +467,18 @@ harness: The plan is not valid; nothing was changed (HTTP 422)
|
|
|
402
467
|
plan: A plan with Operator steps needs a positive spend budget [spend_budget_required]
|
|
403
468
|
```
|
|
404
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
|
+
|
|
405
482
|
A gate's owner is checked the same way. The owner violations are
|
|
406
483
|
`invalid_owner`, `unknown_role`, `unknown_owner`, `owner_is_member`,
|
|
407
484
|
`owner_is_actor` (you named yourself), `owner_not_allowed` (an owner on a
|
|
@@ -409,10 +486,11 @@ condition that is not a gate), `expert_owner_requires_plan`, and
|
|
|
409
486
|
`duplicate_gate_key`. A `gate:` that conflicts with the condition's `kind`
|
|
410
487
|
or `key` is `invalid_condition`.
|
|
411
488
|
|
|
412
|
-
**Show.** `harness plan show <plan
|
|
489
|
+
**Show.** `harness plan show <plan>` prints the plan's status, budgets,
|
|
413
490
|
revision, and spend estimate, then every step in tree order (indented by
|
|
414
491
|
depth) with its key, executor, state, and status. The status is `ready`,
|
|
415
|
-
`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),
|
|
416
494
|
`waiting` (on a wait condition), `container`, `done`, `cancelled`,
|
|
417
495
|
`archived`, or `-`. The edges and each step's wait conditions come after
|
|
418
496
|
the steps. Each gate shows its key and owner. A `Waiting for:` section then
|
|
@@ -436,7 +514,7 @@ email), or an outside expert by email (`val@example.com (expert)`).
|
|
|
436
514
|
`[]` when nobody can tick, `null` for an unowned gate or when the holders
|
|
437
515
|
are not known).
|
|
438
516
|
|
|
439
|
-
**Edit.** `harness plan edit <plan
|
|
517
|
+
**Edit.** `harness plan edit <plan> --file edits.yaml` changes step
|
|
440
518
|
executors and keys, naming each step by its `step` key or `issue`
|
|
441
519
|
identifier, and the budgets (`retry_budget`, `spend_budget_cents`):
|
|
442
520
|
|
|
@@ -446,41 +524,53 @@ steps:
|
|
|
446
524
|
executor: none # hand the step to a person
|
|
447
525
|
```
|
|
448
526
|
|
|
449
|
-
Editing a released step
|
|
450
|
-
|
|
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
|
|
451
532
|
are edited with the issue commands (`update`, `dep`). Conditions are set
|
|
452
533
|
when the plan is created. Editing them later goes through the API's issue
|
|
453
534
|
condition endpoints, which have no command yet; `gate satisfy` ticks a
|
|
454
535
|
gate.
|
|
455
536
|
|
|
456
|
-
**Release and hold.** `harness plan release <plan
|
|
457
|
-
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.
|
|
458
540
|
`--collaborator <id-or-email>` (repeatable) adds people to the plan room
|
|
459
541
|
where its Operator steps run, and `--retry-budget` and
|
|
460
|
-
`--spend-budget-cents` set the budgets.
|
|
461
|
-
|
|
542
|
+
`--spend-budget-cents` set the budgets. Each Operator step runs as a job
|
|
543
|
+
(`harness jobs` names its plan step), and the changes a job proposes need a
|
|
544
|
+
person's approval in the app, at the job's approval link. The CLI never
|
|
545
|
+
approves. `harness plan hold <plan>` pauses every step until the plan is
|
|
546
|
+
released again.
|
|
462
547
|
|
|
463
548
|
**Gates.** `harness gate satisfy <issue> <gate>` ticks a gate and
|
|
464
549
|
`harness gate unsatisfy <issue> <gate>` unticks it. `<gate>` is the gate's
|
|
465
|
-
key, its label, or its condition id, all shown by `harness show`.
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
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
|
|
559
|
+
Operator-only login (`operator-cli`) here, even for a person in the plan's
|
|
560
|
+
room: it reaches only the Operator commands, `whoami` and `logout`. Only
|
|
561
|
+
the owner can tick an owned gate, and only its owner or Harness staff can
|
|
562
|
+
untick it. Anyone else gets an error that names the gate's owner as of
|
|
563
|
+
the refusal, which the server sends with it, and exits `1`:
|
|
476
564
|
|
|
477
565
|
```text
|
|
478
566
|
harness: Cannot satisfy gate "Compliance sign-off" on IO-121: only its owner, Compliance officer (role:compliance_officer), can tick it (HTTP 403)
|
|
479
567
|
```
|
|
480
568
|
|
|
481
569
|
A gate with no owner by then gets the same error without a name. Against
|
|
482
|
-
a server that does not send the owner,
|
|
483
|
-
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.
|
|
484
574
|
|
|
485
575
|
**Conditions.** `harness conditions <issue>` lists an issue's wait
|
|
486
576
|
conditions, oldest first, one per line as `show` lists them: each one's
|
|
@@ -488,7 +578,9 @@ box, what it waits for (a gate's label, key and owner), when and by whom it
|
|
|
488
578
|
was satisfied, and its id. `--json` is the list as the server sends it.
|
|
489
579
|
|
|
490
580
|
A server without the plan API answers the plan commands with a 404, and the
|
|
491
|
-
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.
|
|
492
584
|
|
|
493
585
|
## Outside experts
|
|
494
586
|
|
|
@@ -908,6 +1000,31 @@ Login tokens have it; `aone_` tokens need to be minted with it. There is
|
|
|
908
1000
|
deliberately no MCP tool for keys, because a tool result is text the model
|
|
909
1001
|
can read.
|
|
910
1002
|
|
|
1003
|
+
## Review gate
|
|
1004
|
+
|
|
1005
|
+
A pull request merges only once its enforced Review Council gate, the
|
|
1006
|
+
attested review a gate workflow runs for its head, has converged. When that
|
|
1007
|
+
gate sits at `unverified`, these commands say why and recover it:
|
|
1008
|
+
|
|
1009
|
+
- `harness review status <pr>` prints the enforced and advisory status, the
|
|
1010
|
+
head's gate check, and a failed or timed-out latest attempt with its reason,
|
|
1011
|
+
whether its evidence was recorded, and what comes next. Next is either an
|
|
1012
|
+
automatic retry by Harness or a retry you request. `--json` returns the gate
|
|
1013
|
+
status as the server sends it.
|
|
1014
|
+
- `harness review retry <pr> [--reason <text>]` retries the latest attempt of
|
|
1015
|
+
the current head's gate check. It reads the head, the check and the attempt
|
|
1016
|
+
from the gate status, so you name only the pull request, and prints the new
|
|
1017
|
+
attempt (`--json`: `{attempt, outcome}`). Running it again for the same
|
|
1018
|
+
attempt returns the attempt already queued rather than paying for another
|
|
1019
|
+
review run. It needs a login with `reviews:write`. It refuses, saying why,
|
|
1020
|
+
while the attempt is still running, while Harness is retrying it itself, or
|
|
1021
|
+
when the head's advisory review has not converged.
|
|
1022
|
+
|
|
1023
|
+
`<pr>` is `owner/repo#<number>`, the pull request URL, or a bare number read
|
|
1024
|
+
against `--repo owner/repo` or this checkout's GitHub `origin`. Never dispatch
|
|
1025
|
+
the gate workflow by hand instead: a run without a registered attempt cannot
|
|
1026
|
+
approve the head.
|
|
1027
|
+
|
|
911
1028
|
## Scripting contract
|
|
912
1029
|
|
|
913
1030
|
- **`--json` on every command** except `mcp`. It replaces the human output
|
|
@@ -965,7 +1082,7 @@ command instead of the `npx` form. Any other MCP client can use the same command
|
|
|
965
1082
|
{ "mcpServers": { "harness": { "command": "npx", "args": ["-y", "@allocator-one/harness-cli", "mcp"] } } }
|
|
966
1083
|
```
|
|
967
1084
|
|
|
968
|
-
The server exposes
|
|
1085
|
+
The server exposes 74 tools:
|
|
969
1086
|
|
|
970
1087
|
| Area | Tools |
|
|
971
1088
|
| --- | --- |
|
|
@@ -977,9 +1094,9 @@ The server exposes 72 tools:
|
|
|
977
1094
|
| Labels | `label_list`, `label_create`, `label_update`, `label_delete` |
|
|
978
1095
|
| Teams and states | `team_list`, `team_create`, `team_rename`, `team_set_default`, `workflow_states`, `state_add`, `state_update`, `state_order`, `state_delete` |
|
|
979
1096
|
| People | `member_list`, `member_add`, `member_set_role`, `user_list` |
|
|
980
|
-
| Plans and gates | `plan_create`, `plan_show`, `plan_edit`, `plan_release`, `plan_hold`, `gate_set`, `condition_list` |
|
|
1097
|
+
| Plans and gates | `plan_list`, `plan_create`, `plan_show`, `plan_edit`, `plan_release`, `plan_hold`, `gate_set`, `condition_list` |
|
|
981
1098
|
| Outside experts | `assignment_list` |
|
|
982
|
-
| Operator jobs | `jobs_list`, `job_show`, `job_changes`, `job_steer`, `job_cancel`, `job_pause` |
|
|
1099
|
+
| Operator jobs | `jobs_list`, `job_show`, `job_changes`, `job_start`, `job_steer`, `job_cancel`, `job_pause` |
|
|
983
1100
|
| Continue and procedures | `job_continue`, `procedure_save`, `procedure_show`, `procedure_run` |
|
|
984
1101
|
| Operator's catalog | `tools_search` (without `query` it browses the index; `domain`, `cursor`, `all`), `skills_list` |
|
|
985
1102
|
| Other | `stats`, `upload` |
|
|
@@ -1006,7 +1123,9 @@ Some tools behave differently from their commands:
|
|
|
1006
1123
|
`steps`, `retry_budget`, and `spend_budget_cents` directly. As with every
|
|
1007
1124
|
tool, a top-level argument the tool does not declare is dropped.
|
|
1008
1125
|
`gate_set` takes `issue`, `gate` (a key, label, or condition id), and
|
|
1009
|
-
`satisfied`.
|
|
1126
|
+
`satisfied`. The plan tools' `id` is the plan's id or its root issue's
|
|
1127
|
+
identifier, as for the commands; `plan_list` takes `team`, `status` and
|
|
1128
|
+
`limit`, and `issue_show` carries the issue's `plan`.
|
|
1010
1129
|
- An API error's details come back in the tool error text: a validation
|
|
1011
1130
|
error's fields, and an invalid plan's violations, one per line by step
|
|
1012
1131
|
key.
|
|
@@ -1021,6 +1140,14 @@ Some tools behave differently from their commands:
|
|
|
1021
1140
|
`cancelled`, or `waiting_on` is set. A person has to act exactly when
|
|
1022
1141
|
`waiting_on` is set; a job paused without it resumes by itself. Neither
|
|
1023
1142
|
tool approves anything; give a person the `approval_url`.
|
|
1143
|
+
- `job_start` is the CLI's `run`: `outcome`, and optionally `budget` (US
|
|
1144
|
+
dollars; only the organization's admins) and `skill`; there is no `team`.
|
|
1145
|
+
It returns `job_id`, `state`, `workbench_url` and, when a change set
|
|
1146
|
+
waits, `approval_url`, and never approves: give a person the link. Each
|
|
1147
|
+
call starts another job, so it is never retried; after an "Outcome
|
|
1148
|
+
unknown" error look with `jobs_list` (`mine`) before calling again. It
|
|
1149
|
+
carries `idempotentHint: false` and `destructiveHint: false`. The endpoint
|
|
1150
|
+
needs a server that has the Operator start-job API.
|
|
1024
1151
|
- `job_steer`, `job_cancel` and `job_pause` return the job as `job_show`
|
|
1025
1152
|
does. None is idempotent, so none is retried: after an error that leaves
|
|
1026
1153
|
the outcome unknown, read the job with `job_show` before calling one
|
|
@@ -1058,16 +1185,32 @@ directory the way git finds `.git`, gives every clone of a repo the same
|
|
|
1058
1185
|
defaults:
|
|
1059
1186
|
|
|
1060
1187
|
```json
|
|
1061
|
-
{ "team": "CLI" }
|
|
1188
|
+
{ "team": "CLI", "org": "3f96a9c0-1584-4c65-9c4b-056055024bc9" }
|
|
1062
1189
|
```
|
|
1063
1190
|
|
|
1064
1191
|
| Field | Effect |
|
|
1065
1192
|
| --- | --- |
|
|
1066
1193
|
| `team` | Default team key. Precedence: `--team`, then `HARNESS_TEAM`, then the repo config. |
|
|
1067
1194
|
| `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. |
|
|
1068
|
-
| `org` |
|
|
1069
|
-
|
|
1070
|
-
A malformed file is ignored with a warning on stderr.
|
|
1195
|
+
| `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. |
|
|
1196
|
+
|
|
1197
|
+
A malformed file is ignored with a warning on stderr. An invalid org UUID
|
|
1198
|
+
refuses the command. With `org`, the host defaults to `https://harness.infra.one`
|
|
1199
|
+
unless `url` or `HARNESS_API_URL` specifies it. The repo-selected host passes
|
|
1200
|
+
the same once-per-host trust prompt as a repo `url` before browser login.
|
|
1201
|
+
|
|
1202
|
+
Sign in once with `harness login` from the repo and select its organization
|
|
1203
|
+
on the page. Org logins use separate host-and-org-keyed credential files,
|
|
1204
|
+
so logging into one org does not overwrite or revoke another org's login.
|
|
1205
|
+
The legacy `credentials.json` remains unchanged and is used by repos without
|
|
1206
|
+
`org`. When adding `org` to an existing repo, log in again for that org; the
|
|
1207
|
+
legacy credential is not assumed to belong to it. `logout` revokes and
|
|
1208
|
+
forgets only the selected login. Explicit `HARNESS_API_TOKEN` credentials
|
|
1209
|
+
override org selection; their authority remains whatever the server minted.
|
|
1210
|
+
An org-specific login accepts only a credential whose session describes that
|
|
1211
|
+
organization. Outside-expert `pxc_` credentials have no org description, so
|
|
1212
|
+
use them from a repo without `org` or pass them explicitly through
|
|
1213
|
+
`HARNESS_API_TOKEN`.
|
|
1071
1214
|
|
|
1072
1215
|
### Hosts and tokens
|
|
1073
1216
|
|
|
@@ -1081,13 +1224,14 @@ refuses with exit code 2 instead of sending the token there. Set
|
|
|
1081
1224
|
`HARNESS_API_URL` explicitly if you do mean that host. Without
|
|
1082
1225
|
`HARNESS_API_TOKEN`, a repo-named host needs a login of its own, and the
|
|
1083
1226
|
automatic login asks for confirmation first, as described above. Plain
|
|
1084
|
-
`http://` is accepted only for localhost
|
|
1227
|
+
`http://` is accepted only for `localhost`, any `*.localhost` host (such as
|
|
1228
|
+
a local `harness.infraone.localhost` dev server), `127.0.0.1` and `[::1]`.
|
|
1085
1229
|
|
|
1086
1230
|
### Environment variables
|
|
1087
1231
|
|
|
1088
1232
|
| Variable | Effect |
|
|
1089
1233
|
| --- | --- |
|
|
1090
|
-
| `HARNESS_API_URL` | Target host (https, or http against localhost only). |
|
|
1234
|
+
| `HARNESS_API_URL` | Target host (https, or http against `localhost`, `*.localhost`, `127.0.0.1` or `[::1]` only). |
|
|
1091
1235
|
| `HARNESS_API_TOKEN` | An `aone_…` API token, or an outside expert's `pxc_…` credential. It takes precedence over the stored login. Headless use only. |
|
|
1092
1236
|
| `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. |
|
|
1093
1237
|
| `HARNESS_TEAM` | Default team key for commands that take `--team`. |
|
|
@@ -1101,6 +1245,7 @@ automatic login asks for confirmation first, as described above. Plain
|
|
|
1101
1245
|
|
|
1102
1246
|
| Path | Contents |
|
|
1103
1247
|
| --- | --- |
|
|
1248
|
+
| `~/.config/harness/credentials-org-<hash>.json` | A server-verified org login, keyed by host and org UUID, mode 0600; same `{url, token}` format. |
|
|
1104
1249
|
| `~/.config/harness/credentials.json` | The stored login: one `{url, token}` pair, mode 0600. |
|
|
1105
1250
|
| `~/.config/harness/trusted-hosts.json` | Repo-config hosts you agreed to log in to. |
|
|
1106
1251
|
| `~/.cache/harness/attachments/` | Images downloaded by `show` (or `HARNESS_CACHE_DIR`). |
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/version.ts
|
|
4
|
+
import { readFileSync } from "fs";
|
|
5
|
+
var pkg = JSON.parse(
|
|
6
|
+
readFileSync(new URL("../package.json", import.meta.url), "utf8")
|
|
7
|
+
);
|
|
8
|
+
var CLI_VERSION = pkg.version;
|
|
9
|
+
var CLI_PACKAGE = pkg.name;
|
|
10
|
+
|
|
11
|
+
// src/invocation.ts
|
|
12
|
+
import { basename } from "path";
|
|
13
|
+
var OPERATOR_PACKAGE = "@allocator-one/operator";
|
|
14
|
+
function invokedName(argv1 = process.argv[1], packageName = CLI_PACKAGE) {
|
|
15
|
+
const typed = basename(argv1 ?? "").replace(/\.[cm]?js$/i, "").toLowerCase();
|
|
16
|
+
if (typed === "operator" || typed === "harness") return typed;
|
|
17
|
+
return packageName === OPERATOR_PACKAGE ? "operator" : "harness";
|
|
18
|
+
}
|
|
19
|
+
function named(text, name = invokedName()) {
|
|
20
|
+
if (name === "harness") return text;
|
|
21
|
+
return text.replace(/^harness: /gm, `${name}: `).replace(/(?<![\w@/.-])harness (?=[a-z])(?!disagree)/g, `${name} `).replaceAll("@allocator-one/harness-cli", OPERATOR_PACKAGE);
|
|
22
|
+
}
|
|
23
|
+
var OPERATOR_COMMANDS = [
|
|
24
|
+
"run",
|
|
25
|
+
"jobs",
|
|
26
|
+
"job",
|
|
27
|
+
"watch",
|
|
28
|
+
"steer",
|
|
29
|
+
"cancel",
|
|
30
|
+
"pause",
|
|
31
|
+
"continue",
|
|
32
|
+
"procedure",
|
|
33
|
+
"plan",
|
|
34
|
+
"gate",
|
|
35
|
+
"conditions",
|
|
36
|
+
"assignments",
|
|
37
|
+
"tools",
|
|
38
|
+
"tool",
|
|
39
|
+
"skills",
|
|
40
|
+
"mcp"
|
|
41
|
+
];
|
|
42
|
+
var GENERAL_COMMANDS = [
|
|
43
|
+
"login",
|
|
44
|
+
"logout",
|
|
45
|
+
"whoami",
|
|
46
|
+
"version",
|
|
47
|
+
"keys"
|
|
48
|
+
];
|
|
49
|
+
var OPERATOR_HEADING = "Operator:";
|
|
50
|
+
var ISSUES_HEADING = "Issues:";
|
|
51
|
+
var GENERAL_HEADING = "General:";
|
|
52
|
+
function layoutOperatorHelp(program) {
|
|
53
|
+
const rank = (name) => {
|
|
54
|
+
const operator = OPERATOR_COMMANDS.indexOf(name);
|
|
55
|
+
if (operator !== -1) return operator;
|
|
56
|
+
return GENERAL_COMMANDS.includes(name) ? 2 * OPERATOR_COMMANDS.length : OPERATOR_COMMANDS.length;
|
|
57
|
+
};
|
|
58
|
+
const heading = (name) => OPERATOR_COMMANDS.includes(name) ? OPERATOR_HEADING : GENERAL_COMMANDS.includes(name) ? GENERAL_HEADING : ISSUES_HEADING;
|
|
59
|
+
for (const command of program.commands) command.helpGroup(heading(command.name()));
|
|
60
|
+
program.commands.sort(
|
|
61
|
+
(left, right) => rank(left.name()) - rank(right.name())
|
|
62
|
+
);
|
|
63
|
+
program.commandsGroup(GENERAL_HEADING).helpCommand(true);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export {
|
|
67
|
+
CLI_VERSION,
|
|
68
|
+
CLI_PACKAGE,
|
|
69
|
+
OPERATOR_PACKAGE,
|
|
70
|
+
invokedName,
|
|
71
|
+
named,
|
|
72
|
+
layoutOperatorHelp
|
|
73
|
+
};
|