@elmundi/ship-cli 0.11.2 → 0.12.1
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 +255 -22
- package/bin/shipctl.mjs +11 -7
- package/lib/bootstrap/render.mjs +49 -0
- package/lib/commands/callback.mjs +457 -17
- package/lib/commands/config.mjs +1 -1
- package/lib/commands/docs.mjs +4 -4
- package/lib/commands/help.mjs +137 -77
- package/lib/commands/kickoff.mjs +3 -3
- package/lib/commands/knowledge.mjs +216 -18
- package/lib/commands/lanes.mjs +36 -11
- package/lib/commands/manifest-catalog.mjs +5 -5
- package/lib/commands/patterns.mjs +5 -5
- package/lib/commands/run.mjs +329 -89
- package/lib/commands/search.mjs +2 -2
- package/lib/commands/sync.mjs +83 -8
- package/lib/commands/trigger.mjs +200 -0
- package/lib/config/migrate.mjs +13 -5
- package/lib/config/schema.mjs +253 -2
- package/lib/config.mjs +3 -0
- package/lib/state/idempotency.mjs +1 -1
- package/lib/templates.mjs +3 -3
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,9 +1,32 @@
|
|
|
1
1
|
# @elmundi/ship-cli
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
`shipctl` is the command-line interface to **Ship**. Three jobs:
|
|
4
|
+
|
|
5
|
+
1. **Bootstrap a repo** so its agents (Cursor, Codex, Claude, Aider, Cline,
|
|
6
|
+
Continue, Windsurf, Zed, Gemini, OpenCode, Copilot, …) can consume Ship
|
|
7
|
+
artifacts the same way every other client does.
|
|
8
|
+
2. **Sync the catalog** of `pattern` / `tool` / `collection` artifacts into
|
|
9
|
+
`.ship/cache/` and pin versions for reproducible runs.
|
|
10
|
+
3. **Run lanes** (one-shot dispatch + GitHub Actions wrappers) and
|
|
11
|
+
**report Runs** so the operator console can render outcomes and route any
|
|
12
|
+
escalations into the Inbox.
|
|
4
13
|
|
|
5
14
|
Published as **`@elmundi/ship-cli`** under the [elmundi](https://www.npmjs.com/org/elmundi) org; the binary name is **`shipctl`**.
|
|
6
15
|
|
|
16
|
+
> **Vocabulary.** The CLI speaks the protocol layer, the operator console
|
|
17
|
+
> speaks the product layer. Both are correct; they refer to the same things.
|
|
18
|
+
>
|
|
19
|
+
> | CLI / YAML / API (literal) | Operator console (prose) |
|
|
20
|
+
> |----------------------------|--------------------------|
|
|
21
|
+
> | `lanes:` entries in `.ship/config.yml`, `--lane <id>` | **Automations** |
|
|
22
|
+
> | `pattern:` artifacts (RFC-0001) | **Plays** |
|
|
23
|
+
> | `pipeline_runs` rows + `shipctl callback` payloads | **Runs** |
|
|
24
|
+
> | clarifications / improvements / approvals queue | **Inbox** items |
|
|
25
|
+
>
|
|
26
|
+
> The CLI keeps `lanes:` / `pattern:` / `--lane` literal forever; we are
|
|
27
|
+
> never going to break the YAML and flag surface. Help text and prose
|
|
28
|
+
> reach for the operator nouns when describing what users see.
|
|
29
|
+
|
|
7
30
|
## Requirements
|
|
8
31
|
|
|
9
32
|
- **Node.js 20+**
|
|
@@ -78,7 +101,7 @@ Interactive run prints the plan and asks **Apply these changes? [y/N]**:
|
|
|
78
101
|
npx @elmundi/ship-cli init
|
|
79
102
|
```
|
|
80
103
|
|
|
81
|
-
After you confirm **`y`**, it writes/updates the files above. Injected content tells agents to **resolve Ship artifacts before use** via the CLI: **search → fetch → record `kind:id@version`** workflow, **`shipctl docs fetch`** for documentation paths, **`shipctl pattern|tool|
|
|
104
|
+
After you confirm **`y`**, it writes/updates the files above. Injected content tells agents to **resolve Ship artifacts before use** via the CLI: **search → fetch → record `kind:id@version`** workflow, **`shipctl docs fetch`** for documentation paths, **`shipctl pattern|tool|collection`** for catalog bodies, and **`shipctl docs feedback`** for safe retro notes.
|
|
82
105
|
|
|
83
106
|
### 5. Non-interactive (CI or scripts)
|
|
84
107
|
|
|
@@ -198,16 +221,30 @@ Next:
|
|
|
198
221
|
|
|
199
222
|
## Commands (quick reference)
|
|
200
223
|
|
|
201
|
-
| Command | Role |
|
|
202
|
-
|
|
203
|
-
| **`shipctl init`** |
|
|
204
|
-
| **`shipctl
|
|
205
|
-
| **`shipctl
|
|
206
|
-
| **`shipctl
|
|
224
|
+
| Command | Role | Manual |
|
|
225
|
+
|---------|------|--------|
|
|
226
|
+
| **`shipctl init`** | Bootstrap an existing repo: agent rules, `.ship/config.yml`, optional CI scaffolding. | `documentation/discovery.md` |
|
|
227
|
+
| **`shipctl new`** | Greenfield: `git init` + minimal README + `init`. | this README, `New & Verify` |
|
|
228
|
+
| **`shipctl doctor`** | Inspect repo, propose stack, optionally write `.ship/inventory.json`. | this README, `Doctor` |
|
|
229
|
+
| **`shipctl config`** | Safe edits to `.ship/config.yml` (`init` / `get` / `set` / `validate` / `show` / `path`). | `documentation/configuration.md` |
|
|
230
|
+
| **`shipctl search`** | Vector search over docs + prompts (`POST /search`). | `documentation/discovery.md` |
|
|
231
|
+
| **`shipctl docs fetch`**, **`shipctl docs feedback`** | Documentation file fetch and retro feedback. | `documentation/discovery.md` |
|
|
232
|
+
| **`shipctl pattern\|tool\|collection`** **`list \| show \| fetch \| search`** | Versioned artifact bodies; plural aliases (`patterns`, `tools`, `collections`) work. | `documentation/authoring.md` |
|
|
233
|
+
| **`shipctl sync`** | Pull artifacts into `.ship/cache/`; with `--lock` writes `.ship/shipctl.lock.json` covering every Play the declared lanes depend on. | this README, `Config & Sync` |
|
|
234
|
+
| **`shipctl run`** | One-shot dispatch entry point. `kind: once` runs locally; other lane kinds are queued for the workspace runner. Reports its terminal status via the callback URL Ship injected. | `documentation/automations.md`, this README |
|
|
235
|
+
| **`shipctl lanes`** | Generate / inspect / delete the `.github/workflows/ship-<lane>.yml` thin wrappers (`install` / `list` / `remove`). | `documentation/automations.md`, this README |
|
|
236
|
+
| **`shipctl kickoff`** | Print a Play's pattern body for piping into the customer's agent in CI. | `documentation/automations.md` |
|
|
237
|
+
| **`shipctl callback`** | Pattern-side: report a Run's terminal status + RunSummary outcome so Ship can render the row and route escalations into the Inbox. | this README |
|
|
238
|
+
| **`shipctl knowledge init`** | Open a PR that seeds `.ship/knowledge/*.md` starter buckets. | `documentation/knowledge-buckets.md` |
|
|
239
|
+
| **`shipctl telemetry`** | Opt-in anonymous usage events (default OFF). | this README, `Telemetry & Feedback` |
|
|
240
|
+
| **`shipctl feedback`** | Local markdown drafts → POST `/feedback` → GitHub issue. | this README |
|
|
241
|
+
| **`shipctl verify`** | Post-adoption liveness checks (local + config + network). | this README, `New & Verify` |
|
|
242
|
+
| **`shipctl migrate`** | Upgrade `.ship/config.yml` from v1 to v2 (lanes-as-config). | `documentation/configuration.md` |
|
|
243
|
+
| **`shipctl help`** | Top-level command list with the same vocabulary callout. | — |
|
|
207
244
|
|
|
208
245
|
**Maintainers / full Ship checkout:** if the current directory (or **`SHIP_REPO`**) is inside the Ship monorepo, **`list` / `show` / `fetch`** for catalogs can read manifests from **disk** instead of HTTP. **`shipctl search`** always uses HTTP.
|
|
209
246
|
|
|
210
|
-
Run **`shipctl help`** for
|
|
247
|
+
Run **`shipctl help`** for the operator-first overview with the same vocabulary callout printed at the top.
|
|
211
248
|
|
|
212
249
|
## Doctor
|
|
213
250
|
|
|
@@ -264,16 +301,20 @@ repo git history — `shipctl sync` caches them in `.ship/cache/`, which is
|
|
|
264
301
|
|
|
265
302
|
```
|
|
266
303
|
.ship/
|
|
267
|
-
├── config.yml # RFC-0002 schema; committed
|
|
304
|
+
├── config.yml # RFC-0002 schema; committed. `lanes:` entries
|
|
305
|
+
│ # are what the operator console renders as
|
|
306
|
+
│ # Automations.
|
|
268
307
|
├── state.json # last_sync_at, last_manifest_hash; gitignored
|
|
308
|
+
├── shipctl.lock.json # set by `shipctl sync --lock`; pins every
|
|
309
|
+
│ # pattern the declared lanes depend on
|
|
269
310
|
├── cache/ # per-repo artifact cache (gitignored)
|
|
270
311
|
│ ├── pattern/<id>@<v>/
|
|
271
312
|
│ │ ├── ARTIFACT.md # full body (frontmatter + content), per RFC-0005
|
|
272
313
|
│ │ └── .meta.json # source, sha256, fetched_at, etc.
|
|
273
314
|
│ ├── tool/<id>@<v>/…
|
|
274
|
-
│ ├── workflow/<id>@<v>/…
|
|
275
315
|
│ ├── collection/<id>@<v>/…
|
|
276
316
|
│ └── doc/…
|
|
317
|
+
├── knowledge/ # operator-edited markdown buckets, committed
|
|
277
318
|
├── telemetry-outbox.jsonl # buffered telemetry events (gitignored)
|
|
278
319
|
└── feedback-drafts/ # feedback draft markdowns (gitignored)
|
|
279
320
|
```
|
|
@@ -297,12 +338,12 @@ Value parsing for `config set`:
|
|
|
297
338
|
- Anything else → string.
|
|
298
339
|
|
|
299
340
|
Dotted keys under `artifacts.pins` preserve the embedded slash:
|
|
300
|
-
`artifacts.pins.pattern/
|
|
341
|
+
`artifacts.pins.pattern/role-developer`.
|
|
301
342
|
|
|
302
343
|
```bash
|
|
303
344
|
shipctl config set stack.agents [cursor,codex]
|
|
304
345
|
shipctl config set api.channel edge
|
|
305
|
-
shipctl config set artifacts.pins.pattern/
|
|
346
|
+
shipctl config set artifacts.pins.pattern/role-developer 1.4.2
|
|
306
347
|
```
|
|
307
348
|
|
|
308
349
|
### `shipctl sync`
|
|
@@ -311,9 +352,10 @@ shipctl config set artifacts.pins.pattern/cloud-developer 1.4.2
|
|
|
311
352
|
shipctl sync # pull latest for this stack
|
|
312
353
|
shipctl sync --check-only # report changes without writing cache
|
|
313
354
|
shipctl sync --dry-run # --check-only + planned HTTP calls
|
|
314
|
-
shipctl sync --only pattern:
|
|
355
|
+
shipctl sync --only pattern:role-developer [--only tool:gh-actions]
|
|
315
356
|
shipctl sync --channel edge
|
|
316
357
|
shipctl sync --force-unpin # temporarily ignore version pins
|
|
358
|
+
shipctl sync --lock # write .ship/shipctl.lock.json after sync
|
|
317
359
|
```
|
|
318
360
|
|
|
319
361
|
Summary format:
|
|
@@ -329,11 +371,189 @@ failed: 0
|
|
|
329
371
|
|
|
330
372
|
Pins are honoured: an entry whose manifest version does not satisfy the pin is
|
|
331
373
|
reported as `skipped_pin` unless `--force-unpin` is set. After a successful
|
|
332
|
-
sync, `.ship/state.json` records `last_sync_at` and `last_manifest_hash`.
|
|
374
|
+
sync, `.ship/state.json` records `last_sync_at` and `last_manifest_hash`. With
|
|
375
|
+
`--lock`, `shipctl sync` also writes `.ship/shipctl.lock.json` covering every
|
|
376
|
+
Play that the declared lanes depend on, so subsequent `shipctl run` invocations
|
|
377
|
+
can refuse to drift off the pinned set.
|
|
333
378
|
|
|
334
379
|
> Methodology docs never live in your repo. `shipctl sync` caches them in
|
|
335
380
|
> `.ship/cache/`, sealed by `content_sha256` from the Ship manifest.
|
|
336
381
|
|
|
382
|
+
## Run
|
|
383
|
+
|
|
384
|
+
`shipctl run` is the **one-shot dispatch entry point** for an Automation
|
|
385
|
+
(YAML key: `lanes:`). What it does depends on the lane's `kind`:
|
|
386
|
+
|
|
387
|
+
| `kind:` value | Behaviour of `shipctl run` |
|
|
388
|
+
|---------------|----------------------------|
|
|
389
|
+
| `once` | Executes the lane fully on the local machine (the pattern body is fed to the configured agent; the result is reported back via `shipctl callback`). |
|
|
390
|
+
| `lane` / `event` / `schedule` | Refuses to execute locally; the workspace's GitHub Actions runner picks the lane up via `.github/workflows/run-agent.yml`. The CLI exits with a clear message naming the lane id and its kind. |
|
|
391
|
+
|
|
392
|
+
```bash
|
|
393
|
+
# preview which patterns + parameters the lane would dispatch with
|
|
394
|
+
shipctl run --lane pr-self-review --dry-run
|
|
395
|
+
|
|
396
|
+
# fanout: the same pattern over every repo in the workspace
|
|
397
|
+
shipctl run --lane fleet-mobile-knowledge-refresh \
|
|
398
|
+
--pattern fleet-knowledge-pack \
|
|
399
|
+
--fanout matrix \
|
|
400
|
+
--trigger event \
|
|
401
|
+
--json
|
|
402
|
+
|
|
403
|
+
# CI usage: shipctl injects --ship-run-id / --ship-callback-url / --ship-run-token
|
|
404
|
+
# automatically; you only set them by hand when running outside the workspace runner
|
|
405
|
+
shipctl run --lane release-cut \
|
|
406
|
+
--ship-run-id "$SHIP_RUN_ID" \
|
|
407
|
+
--ship-callback-url "$SHIP_CALLBACK_URL" \
|
|
408
|
+
--ship-run-token "$SHIP_RUN_TOKEN"
|
|
409
|
+
```
|
|
410
|
+
|
|
411
|
+
Important flags:
|
|
412
|
+
|
|
413
|
+
- `--pattern <id>` — override the lane's default pattern (a composite Play may
|
|
414
|
+
declare several; this lets you target one specifically).
|
|
415
|
+
- `--fanout matrix|sequential|concurrent` — only meaningful for fleet-scope
|
|
416
|
+
lanes that target multiple repos.
|
|
417
|
+
- `--trigger event|schedule|manual|once` — the trigger the lane was wired for;
|
|
418
|
+
used to choose the payload shape.
|
|
419
|
+
- `--offline` — skip every HTTP probe (resolves patterns from `.ship/cache/`
|
|
420
|
+
only); useful for hermetic CI.
|
|
421
|
+
- `--dry-run` — print the dispatch plan and exit 0; no agent invocation.
|
|
422
|
+
|
|
423
|
+
A full Run lifecycle in production looks like: console (or schedule) creates a
|
|
424
|
+
`pipeline_run` row → workspace runner is dispatched → runner calls
|
|
425
|
+
`shipctl run --lane <id>` for `kind: once` lanes (or invokes the agent
|
|
426
|
+
directly for `kind: lane`) → the pattern calls `shipctl callback` with the
|
|
427
|
+
RunSummary → console renders the outcome row in `/runs` and any escalations
|
|
428
|
+
land in `/inbox`.
|
|
429
|
+
|
|
430
|
+
## Lanes
|
|
431
|
+
|
|
432
|
+
`shipctl lanes` manages the **thin GitHub Actions wrappers** that delegate to
|
|
433
|
+
the reusable `run-agent.yml` workflow. Each lane in `.ship/config.yml`
|
|
434
|
+
generates one `.github/workflows/ship-<lane>.yml` file. The file itself is a
|
|
435
|
+
~12-line yaml that does nothing more than `uses: ./.github/workflows/run-agent.yml`
|
|
436
|
+
with the right `lane:` input — all the logic lives in the reusable workflow,
|
|
437
|
+
so wrappers can be regenerated without touching execution semantics.
|
|
438
|
+
|
|
439
|
+
```bash
|
|
440
|
+
# write workflow files for every lane in config.yml
|
|
441
|
+
shipctl lanes install --dry-run
|
|
442
|
+
shipctl lanes install --yes
|
|
443
|
+
|
|
444
|
+
# only one lane (or a few)
|
|
445
|
+
shipctl lanes install --only pr-self-review,release-cut
|
|
446
|
+
|
|
447
|
+
# wire to a specific shipctl version pin
|
|
448
|
+
shipctl lanes install --shipctl-version 0.12.1 \
|
|
449
|
+
--owner elmundi --repo ship --ref v0.12.1
|
|
450
|
+
|
|
451
|
+
# inspect what's on disk vs config.yml
|
|
452
|
+
shipctl lanes list --json
|
|
453
|
+
|
|
454
|
+
# remove generated wrappers (does NOT touch lanes: config)
|
|
455
|
+
shipctl lanes remove --dry-run
|
|
456
|
+
shipctl lanes remove --only deprecated-lane --yes
|
|
457
|
+
```
|
|
458
|
+
|
|
459
|
+
Notes:
|
|
460
|
+
|
|
461
|
+
- `lanes install` writes files **only** for lanes with a configured trigger
|
|
462
|
+
(`on.push`, `on.schedule`, `on.workflow_dispatch`). `kind: once` lanes
|
|
463
|
+
intended to run only via `shipctl run` don't get a wrapper.
|
|
464
|
+
- The same wrapper covers a fleet-scope lane (one workflow file in your
|
|
465
|
+
pilot repo, fanout happens server-side via the matrix Ship dispatches).
|
|
466
|
+
- Removing a wrapper does **not** remove the lane from `.ship/config.yml`;
|
|
467
|
+
to fully retire an Automation, drop the `lanes.<id>` block from the YAML
|
|
468
|
+
and re-run `shipctl lanes install` so the file is reconciled.
|
|
469
|
+
|
|
470
|
+
## Callback
|
|
471
|
+
|
|
472
|
+
`shipctl callback` is what a Play's pattern calls to **close the loop on a
|
|
473
|
+
Run**. It POSTs a structured payload to the URL Ship injected into the
|
|
474
|
+
runner (`SHIP_CALLBACK_URL` env or `--callback-url`) so the operator console
|
|
475
|
+
can render an outcome-first row in `/runs` and route any escalations into
|
|
476
|
+
`/inbox`.
|
|
477
|
+
|
|
478
|
+
The flag surface is **protocol-stable** (the workspace API depends on it);
|
|
479
|
+
the help is grouped by intent.
|
|
480
|
+
|
|
481
|
+
### Identity (one of these is required)
|
|
482
|
+
|
|
483
|
+
```
|
|
484
|
+
--run-id <uuid> # falls back to SHIP_RUN_ID
|
|
485
|
+
--callback-url <url> # falls back to SHIP_CALLBACK_URL
|
|
486
|
+
SHIP_RUN_TOKEN=<jwt> # bearer for the callback URL (CI sets this)
|
|
487
|
+
SHIP_API_BASE=<url> # base for {api}/v1/runs/<id>/callback when only --run-id is set
|
|
488
|
+
```
|
|
489
|
+
|
|
490
|
+
### Status & summary
|
|
491
|
+
|
|
492
|
+
```
|
|
493
|
+
--status ok|fail|cancelled # required terminal state
|
|
494
|
+
--summary "Free text" # short human readout (kept in addition to outcome)
|
|
495
|
+
--metric key=value # repeatable; persisted as-is
|
|
496
|
+
```
|
|
497
|
+
|
|
498
|
+
### RunSummary outcome (Phase 3)
|
|
499
|
+
|
|
500
|
+
These map 1:1 to the `outcome:` JSONB column on `pipeline_runs` and to what
|
|
501
|
+
the console renders:
|
|
502
|
+
|
|
503
|
+
```
|
|
504
|
+
--outcome-text "Reviewed PR · 3 suggestions · 1 fix applied"
|
|
505
|
+
--findings-count 3
|
|
506
|
+
--severity high=1 --severity medium=2 # repeatable; map of sev → count
|
|
507
|
+
--artifact pr:"Auto-fix: typo":"https://...": # repeatable; type:title[:ref]
|
|
508
|
+
--artifact comment:"Self-review summary":"https://github.com/.../pull/42#…"
|
|
509
|
+
--escalation clarification:"agent_low_confidence" # repeatable; type:reason
|
|
510
|
+
--requires-approval # toggle the approval gate
|
|
511
|
+
--approval-payload '{"...": "..."}' # JSON forwarded to the Inbox item
|
|
512
|
+
```
|
|
513
|
+
|
|
514
|
+
You can also pass the full RunSummary as JSON via:
|
|
515
|
+
|
|
516
|
+
- `SHIP_RUN_OUTCOME=$JSON_STRING`
|
|
517
|
+
- `SHIP_RUN_OUTCOME_FILE=/path/to/outcome.json`
|
|
518
|
+
|
|
519
|
+
Flags merge on top of the env / file payload (CLI wins).
|
|
520
|
+
|
|
521
|
+
### Example (canonical pattern recipe)
|
|
522
|
+
|
|
523
|
+
```bash
|
|
524
|
+
shipctl callback --status ok \
|
|
525
|
+
--outcome-text "Reviewed PR · 3 suggestions · 1 fix applied" \
|
|
526
|
+
--findings-count 3 \
|
|
527
|
+
--severity high=1 --severity medium=2 \
|
|
528
|
+
--artifact comment:"PR self-review summary":"https://github.com/elmundi/ship/pull/42#issuecomment-…" \
|
|
529
|
+
--artifact pr:"Auto-fix: typo in README":"https://github.com/elmundi/ship/pull/43"
|
|
530
|
+
```
|
|
531
|
+
|
|
532
|
+
The same `## Reporting` block lives at the bottom of every top-Play pattern
|
|
533
|
+
(see `artifacts/patterns/flow-pr-self-review/ARTIFACT.md` for the canonical
|
|
534
|
+
example). When you author a new Play, copy that block as the contract you
|
|
535
|
+
expect runners to honour.
|
|
536
|
+
|
|
537
|
+
## Knowledge
|
|
538
|
+
|
|
539
|
+
`shipctl knowledge init` opens a PR in the target repo that seeds the
|
|
540
|
+
`.ship/knowledge/` starter buckets (e.g. `code-style.md`, `ui-runbook.md`).
|
|
541
|
+
The PR is intentionally minimal — operators are expected to fill the buckets
|
|
542
|
+
in over time.
|
|
543
|
+
|
|
544
|
+
```bash
|
|
545
|
+
# requires SHIP_API_TOKEN; targets the workspace's wired GitHub installation
|
|
546
|
+
shipctl knowledge init \
|
|
547
|
+
--workspace 11111111-1111-1111-1111-111111111111 \
|
|
548
|
+
--repo elmundi/ship-pilot \
|
|
549
|
+
--only code-style,ui-runbook \
|
|
550
|
+
--json
|
|
551
|
+
```
|
|
552
|
+
|
|
553
|
+
Behind the scenes, this hits the workspace API which uses the GitHub App
|
|
554
|
+
installation to open the PR. The buckets the Plays read at runtime live
|
|
555
|
+
under the same `.ship/knowledge/` tree the PR seeds.
|
|
556
|
+
|
|
337
557
|
## Telemetry & Feedback
|
|
338
558
|
|
|
339
559
|
Anonymous telemetry is **opt-in and OFF by default** (RFC-0003). Nothing leaves
|
|
@@ -376,18 +596,18 @@ anywhere:
|
|
|
376
596
|
|
|
377
597
|
```bash
|
|
378
598
|
# create a draft
|
|
379
|
-
shipctl feedback draft --kind pattern --id
|
|
599
|
+
shipctl feedback draft --kind pattern --id role-developer --version 1.4.2 \
|
|
380
600
|
--title "Missing mobile preview step" \
|
|
381
601
|
--summary "Evidence checklist misses mobile preview" \
|
|
382
602
|
--recommendation "Add a bullet under Evidence"
|
|
383
603
|
|
|
384
604
|
# review / edit (uses $EDITOR)
|
|
385
605
|
shipctl feedback list
|
|
386
|
-
shipctl feedback show .ship/feedback-drafts/2026-04-17-11-30-15-pattern-
|
|
387
|
-
shipctl feedback edit .ship/feedback-drafts/2026-04-17-11-30-15-pattern-
|
|
606
|
+
shipctl feedback show .ship/feedback-drafts/2026-04-17-11-30-15-pattern-role-developer.md
|
|
607
|
+
shipctl feedback edit .ship/feedback-drafts/2026-04-17-11-30-15-pattern-role-developer.md
|
|
388
608
|
|
|
389
609
|
# submit → POST /feedback → GitHub issue URL; draft moves to sent/
|
|
390
|
-
shipctl feedback submit .ship/feedback-drafts/2026-04-17-11-30-15-pattern-
|
|
610
|
+
shipctl feedback submit .ship/feedback-drafts/2026-04-17-11-30-15-pattern-role-developer.md --yes
|
|
391
611
|
```
|
|
392
612
|
|
|
393
613
|
Submission requires `kind`, `id`, `title`, and `summary`; missing fields fail
|
|
@@ -437,9 +657,9 @@ Post-adoption liveness check. A collection of independent checks under
|
|
|
437
657
|
on-disk signals.
|
|
438
658
|
- **network** (skip with `--no-network`) — `/health` (or `/patterns` as a
|
|
439
659
|
fallback) reachable, local cache matches the channel catalog aggregated
|
|
440
|
-
across `/patterns`, `/tools`, `/
|
|
441
|
-
|
|
442
|
-
|
|
660
|
+
across `/patterns`, `/tools`, `/collections`, Linear labels exist (needs
|
|
661
|
+
`LINEAR_API_KEY`), every `${{ secrets.X }}` reference in gh-actions
|
|
662
|
+
workflows is declared in `.env.example`.
|
|
443
663
|
|
|
444
664
|
Exit `0` when no check returned `fail`; warnings do not fail.
|
|
445
665
|
|
|
@@ -482,3 +702,16 @@ git push --follow-tags # publish workflow picks up v0.11.0
|
|
|
482
702
|
Repository secret **`NPM_TOKEN`** is required. Publish from the monorepo
|
|
483
703
|
root: **`npm publish -w @elmundi/ship-cli`** — not `npm publish --prefix cli`
|
|
484
704
|
(the root package is private).
|
|
705
|
+
|
|
706
|
+
## Reference
|
|
707
|
+
|
|
708
|
+
Protocol-stable surfaces:
|
|
709
|
+
|
|
710
|
+
- **Artifacts protocol** (`POST /search`, `POST /fetch`) — RFC-0001.
|
|
711
|
+
- **Stack block + presets + adapters** — RFCs 0002 / 0004 / 0006.
|
|
712
|
+
- **Telemetry** — RFC-0003.
|
|
713
|
+
- **Operator IA** (Plays / Automations / Runs / Inbox) — RFC-0010.
|
|
714
|
+
- **HTTP schemas live next to the source**: `artifacts/tools/methodology-api/ARTIFACT.md`.
|
|
715
|
+
|
|
716
|
+
Every consumed artifact should be recorded in the PR or commit log as
|
|
717
|
+
`<kind>:<id>@<version>` so reviewers can replay what the agent saw.
|
package/bin/shipctl.mjs
CHANGED
|
@@ -24,6 +24,7 @@ if (raw[0] === "--version" || raw[0] === "-v" || raw[0] === "version") {
|
|
|
24
24
|
const { _, ...g } = extractGlobalArgv(raw);
|
|
25
25
|
const ctx = {
|
|
26
26
|
baseUrl: g.baseUrl,
|
|
27
|
+
baseUrlSource: g.baseUrlSource,
|
|
27
28
|
json: g.json,
|
|
28
29
|
yes: g.yes,
|
|
29
30
|
force: g.force,
|
|
@@ -85,12 +86,6 @@ try {
|
|
|
85
86
|
process.exit(0);
|
|
86
87
|
}
|
|
87
88
|
|
|
88
|
-
if (cmd === "doctor") {
|
|
89
|
-
const { doctorCommand } = await import("../lib/commands/doctor.mjs");
|
|
90
|
-
await doctorCommand(ctx, rest);
|
|
91
|
-
process.exit(0);
|
|
92
|
-
}
|
|
93
|
-
|
|
94
89
|
if (cmd === "verify") {
|
|
95
90
|
const { verifyCommand } = await import("../lib/commands/verify.mjs");
|
|
96
91
|
await verifyCommand(ctx, rest);
|
|
@@ -127,6 +122,12 @@ try {
|
|
|
127
122
|
process.exit(0);
|
|
128
123
|
}
|
|
129
124
|
|
|
125
|
+
if (cmd === "trigger") {
|
|
126
|
+
const { triggerCommand } = await import("../lib/commands/trigger.mjs");
|
|
127
|
+
await triggerCommand(ctx, rest);
|
|
128
|
+
process.exit(0);
|
|
129
|
+
}
|
|
130
|
+
|
|
130
131
|
if (cmd === "kickoff") {
|
|
131
132
|
const { kickoffCommand } = await import("../lib/commands/kickoff.mjs");
|
|
132
133
|
await kickoffCommand(ctx, rest);
|
|
@@ -151,7 +152,10 @@ try {
|
|
|
151
152
|
process.exit(0);
|
|
152
153
|
}
|
|
153
154
|
|
|
154
|
-
|
|
155
|
+
/* `lanes` is the protocol-stable name; `automations` is the
|
|
156
|
+
* operator-friendly soft alias. Both dispatch to the same handler
|
|
157
|
+
* indefinitely — we are not deprecating the original. */
|
|
158
|
+
if (cmd === "lanes" || cmd === "automations") {
|
|
155
159
|
const { lanesCommand } = await import("../lib/commands/lanes.mjs");
|
|
156
160
|
await lanesCommand(ctx, rest);
|
|
157
161
|
process.exit(0);
|
package/lib/bootstrap/render.mjs
CHANGED
|
@@ -263,6 +263,55 @@ function buildRecommendedTools({ preset }) {
|
|
|
263
263
|
"Detox or Maestro for device-farm E2E",
|
|
264
264
|
"Expo Updates or CodePush for OTA patches",
|
|
265
265
|
],
|
|
266
|
+
"mobile-app-deep": [
|
|
267
|
+
"EAS Build / Fastlane for iOS + Android signed builds",
|
|
268
|
+
"Detox or Maestro for device-farm E2E",
|
|
269
|
+
"Expo Updates or CodePush for OTA patches",
|
|
270
|
+
"Crashlytics or Sentry for post-release crash-rate tracking",
|
|
271
|
+
"TestFlight external testing + Play closed-testing tracks",
|
|
272
|
+
],
|
|
273
|
+
"ml-project": [
|
|
274
|
+
"DVC / LakeFS / Delta Lake for dataset + model versioning",
|
|
275
|
+
"MLflow or Weights & Biases for eval tracking",
|
|
276
|
+
"Feast / Tecton / Databricks Feature Store for feature contracts",
|
|
277
|
+
"Great Expectations / Pandera for data validation",
|
|
278
|
+
],
|
|
279
|
+
platform: [
|
|
280
|
+
"Terraform + a state backend you can audit (S3 / Terraform Cloud)",
|
|
281
|
+
"Kyverno / OPA / Conftest for manifest-level policy gating",
|
|
282
|
+
"Infracost or cloud-pricing API for per-PR cost deltas",
|
|
283
|
+
"Prometheus / Datadog / CloudWatch for SLO burn-rate queries",
|
|
284
|
+
"Syft / Trivy / Grype for SBOM generation at release",
|
|
285
|
+
],
|
|
286
|
+
regulated: [
|
|
287
|
+
"Presidio / Nightfall / Transcend for PII detection helpers",
|
|
288
|
+
"An audit log store with hash-chain integrity (append-only DB / S3 with object-lock)",
|
|
289
|
+
"Vault / AWS Secrets Manager for scoped compliance credentials",
|
|
290
|
+
"Drata / Vanta / Secureframe for evidence-bundle sync (optional)",
|
|
291
|
+
],
|
|
292
|
+
"desktop-app": [
|
|
293
|
+
"Apple notarytool + Developer ID cert for macOS notarization",
|
|
294
|
+
"Windows Authenticode / EV code-signing cert + SignTool",
|
|
295
|
+
"electron-updater / Sparkle / Squirrel for staged auto-update",
|
|
296
|
+
"A crash-telemetry SDK (Sentry / Bugsnag) scoped to desktop builds",
|
|
297
|
+
"Per-platform installer toolchain (dmg, msi, deb, AppImage)",
|
|
298
|
+
],
|
|
299
|
+
firmware: [
|
|
300
|
+
"A cross-toolchain (arm-none-eabi-gcc / clang-embedded / IDF / Zephyr SDK)",
|
|
301
|
+
"PlatformIO / ESP-IDF / Zephyr / Yocto build system tied into CI",
|
|
302
|
+
"Renode or QEMU for simulated HIL runs on PR",
|
|
303
|
+
"An OTA backend (AWS IoT Jobs / Azure IoT Hub / Mender / Balena / Nerves)",
|
|
304
|
+
"Octopart / Digi-Key / Mouser API for BOM pricing + lifecycle",
|
|
305
|
+
"A bench power analyzer or logged DMM for power-profile ground truth",
|
|
306
|
+
],
|
|
307
|
+
game: [
|
|
308
|
+
"Your engine (Unity / Unreal / Godot) hooked into CI with headless builds",
|
|
309
|
+
"Perforce or Git LFS for binary art assets",
|
|
310
|
+
"Unity Cloud Build / UGS / Jenkins for per-PR cook builds",
|
|
311
|
+
"RenderDoc / Tracy / Unreal Insights for frametime capture",
|
|
312
|
+
"A crash-telemetry SDK (Backtrace / Sentry / Unity Cloud Diagnostics)",
|
|
313
|
+
"A localization TMS (Crowdin / Lokalise / Smartling) for event strings",
|
|
314
|
+
],
|
|
266
315
|
"web-app": [
|
|
267
316
|
"Playwright (hosted) for PR preview E2E",
|
|
268
317
|
"Preview deployments (Vercel / Netlify / Fly) per PR",
|