@elmundi/ship-cli 0.8.1 → 0.11.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. package/README.md +415 -22
  2. package/bin/shipctl.mjs +165 -0
  3. package/lib/adapters/_fs.mjs +165 -0
  4. package/lib/adapters/agents/index.mjs +26 -0
  5. package/lib/adapters/ci/azure-pipelines.mjs +23 -0
  6. package/lib/adapters/ci/buildkite.mjs +24 -0
  7. package/lib/adapters/ci/circleci.mjs +23 -0
  8. package/lib/adapters/ci/gh-actions.mjs +29 -0
  9. package/lib/adapters/ci/gitlab-ci.mjs +23 -0
  10. package/lib/adapters/ci/jenkins.mjs +23 -0
  11. package/lib/adapters/ci/manual.mjs +18 -0
  12. package/lib/adapters/index.mjs +122 -0
  13. package/lib/adapters/language/dart.mjs +23 -0
  14. package/lib/adapters/language/go.mjs +23 -0
  15. package/lib/adapters/language/java.mjs +27 -0
  16. package/lib/adapters/language/js.mjs +32 -0
  17. package/lib/adapters/language/kotlin.mjs +48 -0
  18. package/lib/adapters/language/py.mjs +34 -0
  19. package/lib/adapters/language/rust.mjs +23 -0
  20. package/lib/adapters/language/swift.mjs +37 -0
  21. package/lib/adapters/language/ts.mjs +35 -0
  22. package/lib/adapters/trackers/azure-boards.mjs +49 -0
  23. package/lib/adapters/trackers/clickup.mjs +43 -0
  24. package/lib/adapters/trackers/github-issues.mjs +52 -0
  25. package/lib/adapters/trackers/jira.mjs +72 -0
  26. package/lib/adapters/trackers/linear.mjs +62 -0
  27. package/lib/adapters/trackers/none.mjs +18 -0
  28. package/lib/adapters/trackers/spreadsheet.mjs +28 -0
  29. package/lib/artifacts/fs-index.mjs +230 -0
  30. package/lib/bootstrap/render.mjs +373 -0
  31. package/lib/cache/store.mjs +422 -0
  32. package/lib/commands/bootstrap.mjs +4 -0
  33. package/lib/commands/callback.mjs +302 -0
  34. package/lib/commands/config.mjs +257 -0
  35. package/lib/commands/docs.mjs +1 -1
  36. package/lib/commands/doctor.mjs +583 -0
  37. package/lib/commands/feedback.mjs +355 -0
  38. package/lib/commands/help.mjs +96 -21
  39. package/lib/commands/init.mjs +830 -158
  40. package/lib/commands/kickoff.mjs +192 -0
  41. package/lib/commands/knowledge.mjs +368 -0
  42. package/lib/commands/lanes.mjs +502 -0
  43. package/lib/commands/manifest-catalog.mjs +102 -38
  44. package/lib/commands/migrate.mjs +204 -0
  45. package/lib/commands/new.mjs +452 -0
  46. package/lib/commands/patterns.mjs +9 -43
  47. package/lib/commands/run.mjs +617 -0
  48. package/lib/commands/sync.mjs +749 -0
  49. package/lib/commands/telemetry.mjs +390 -0
  50. package/lib/commands/verify.mjs +187 -0
  51. package/lib/config/io.mjs +232 -0
  52. package/lib/config/migrate.mjs +215 -0
  53. package/lib/config/schema.mjs +650 -0
  54. package/lib/detect.mjs +162 -19
  55. package/lib/feedback/drafts.mjs +129 -0
  56. package/lib/find-ship-root.mjs +16 -10
  57. package/lib/http.mjs +237 -11
  58. package/lib/state/idempotency.mjs +183 -0
  59. package/lib/state/lockfile.mjs +180 -0
  60. package/lib/telemetry/outbox.mjs +224 -0
  61. package/lib/templates.mjs +53 -65
  62. package/lib/verify/checks/agents-on-disk.mjs +58 -0
  63. package/lib/verify/checks/api-reachable.mjs +39 -0
  64. package/lib/verify/checks/artifacts-up-to-date.mjs +78 -0
  65. package/lib/verify/checks/bootstrap-files.mjs +67 -0
  66. package/lib/verify/checks/cache-integrity.mjs +51 -0
  67. package/lib/verify/checks/ci-secrets.mjs +86 -0
  68. package/lib/verify/checks/config-present.mjs +39 -0
  69. package/lib/verify/checks/gitignore-cache.mjs +51 -0
  70. package/lib/verify/checks/rules-markers.mjs +135 -0
  71. package/lib/verify/checks/stack-enums.mjs +33 -0
  72. package/lib/verify/checks/tracker-labels.mjs +91 -0
  73. package/lib/verify/registry.mjs +120 -0
  74. package/lib/version.mjs +34 -0
  75. package/package.json +10 -3
  76. package/bin/ship.mjs +0 -68
@@ -0,0 +1,355 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import readline from "node:readline";
4
+ import { spawn } from "node:child_process";
5
+ import {
6
+ findShipRoot,
7
+ readConfig,
8
+ } from "../config/io.mjs";
9
+ import {
10
+ draftsDir,
11
+ createDraft,
12
+ listDrafts,
13
+ readDraft,
14
+ removeDraft,
15
+ moveDraftToSent,
16
+ } from "../feedback/drafts.mjs";
17
+ import { postFeedback } from "../http.mjs";
18
+ import { appendEvent } from "../telemetry/outbox.mjs";
19
+
20
+ const ALLOWED_KINDS = ["pattern", "tool", "collection", "doc"];
21
+
22
+ function parseArgs(rest) {
23
+ const out = {
24
+ cwd: process.cwd(),
25
+ yes: false,
26
+ kind: null,
27
+ id: null,
28
+ version: null,
29
+ title: null,
30
+ summary: null,
31
+ recommendation: null,
32
+ positional: [],
33
+ };
34
+ const copy = [...rest];
35
+ const strFlag = (name, key) => {
36
+ if (copy[0] === name && copy[1] !== undefined) {
37
+ copy.shift();
38
+ out[key] = String(copy.shift());
39
+ return true;
40
+ }
41
+ const p = `${name}=`;
42
+ if (copy[0] && copy[0].startsWith(p)) {
43
+ out[key] = copy[0].slice(p.length);
44
+ copy.shift();
45
+ return true;
46
+ }
47
+ return false;
48
+ };
49
+ while (copy.length) {
50
+ if (copy[0] === "--cwd" && copy[1]) {
51
+ copy.shift();
52
+ out.cwd = String(copy.shift());
53
+ continue;
54
+ }
55
+ if (copy[0] && copy[0].startsWith("--cwd=")) {
56
+ out.cwd = copy.shift().slice("--cwd=".length);
57
+ continue;
58
+ }
59
+ if (copy[0] === "--yes" || copy[0] === "-y") {
60
+ out.yes = true;
61
+ copy.shift();
62
+ continue;
63
+ }
64
+ if (strFlag("--kind", "kind")) continue;
65
+ if (strFlag("--id", "id")) continue;
66
+ if (strFlag("--version", "version")) continue;
67
+ if (strFlag("--title", "title")) continue;
68
+ if (strFlag("--summary", "summary")) continue;
69
+ if (strFlag("--recommendation", "recommendation")) continue;
70
+ out.positional.push(copy.shift());
71
+ }
72
+ return out;
73
+ }
74
+
75
+ function requireShipRoot(cwd) {
76
+ const root = findShipRoot(cwd);
77
+ if (!root) {
78
+ console.error(".ship/ not found. Run 'shipctl config init' first.");
79
+ process.exit(10);
80
+ }
81
+ return root;
82
+ }
83
+
84
+ async function promptLine(msg) {
85
+ const rl = readline.createInterface({ input: process.stdin, output: process.stderr });
86
+ try {
87
+ return await new Promise((resolve) => rl.question(msg, resolve));
88
+ } finally {
89
+ rl.close();
90
+ }
91
+ }
92
+
93
+ function resolveBaseUrl(ctx, config) {
94
+ return (
95
+ ctx?.baseUrl ||
96
+ process.env.SHIP_API_BASE ||
97
+ config?.api?.base_url ||
98
+ "https://ship.elmundi.com"
99
+ ).replace(/\/$/, "");
100
+ }
101
+
102
+ async function cmdDraft(root, args) {
103
+ if (!args.kind || !ALLOWED_KINDS.includes(args.kind)) {
104
+ console.error(`--kind is required and must be one of: ${ALLOWED_KINDS.join(", ")}`);
105
+ process.exit(1);
106
+ }
107
+ if (!args.id) {
108
+ console.error("--id is required");
109
+ process.exit(1);
110
+ }
111
+
112
+ let title = args.title;
113
+ let summary = args.summary;
114
+
115
+ if ((!title || !summary) && process.stdin.isTTY) {
116
+ if (!title) title = (await promptLine("title: ")).trim();
117
+ if (!summary) summary = (await promptLine("summary: ")).trim();
118
+ }
119
+
120
+ if (!title || !summary) {
121
+ console.error("--title and --summary are required (interactive prompts unavailable).");
122
+ process.exit(1);
123
+ }
124
+
125
+ const { config } = readConfig(root);
126
+ const fp = createDraft(root, {
127
+ kind: args.kind,
128
+ id: args.id,
129
+ version: args.version,
130
+ title,
131
+ summary,
132
+ recommendation: args.recommendation,
133
+ stack: config.stack || {},
134
+ });
135
+ console.log(fp);
136
+ }
137
+
138
+ function cmdList(root) {
139
+ const drafts = listDrafts(root);
140
+ if (drafts.length === 0) {
141
+ console.log("(no feedback drafts)");
142
+ return;
143
+ }
144
+ for (const fp of drafts) {
145
+ try {
146
+ const { meta } = readDraft(fp);
147
+ const sent = fp.includes(`${path.sep}sent${path.sep}`) ? " [sent]" : "";
148
+ const base = path.basename(fp);
149
+ const ts = (base.match(/^([0-9]{4}-[0-9]{2}-[0-9]{2}-[0-9]{2}-[0-9]{2}-[0-9]{2})/) || [])[1] || "-";
150
+ const kind = meta.kind || "-";
151
+ const id = meta.id || "-";
152
+ const version = meta.version || "-";
153
+ const title = meta.title || "(untitled)";
154
+ console.log(`${ts} ${kind}/${id}@${version} — ${title}${sent}`);
155
+ } catch (e) {
156
+ console.log(`${fp} (invalid: ${e.message})`);
157
+ }
158
+ }
159
+ }
160
+
161
+ function cmdShow(args) {
162
+ const file = args.positional[1];
163
+ if (!file) {
164
+ console.error("usage: shipctl feedback show <draft-file>");
165
+ process.exit(1);
166
+ }
167
+ const resolved = path.resolve(file);
168
+ if (!fs.existsSync(resolved)) {
169
+ console.error(`not found: ${resolved}`);
170
+ process.exit(1);
171
+ }
172
+ console.log(fs.readFileSync(resolved, "utf8"));
173
+ }
174
+
175
+ function cmdEdit(args) {
176
+ const file = args.positional[1];
177
+ if (!file) {
178
+ console.error("usage: shipctl feedback edit <draft-file>");
179
+ process.exit(1);
180
+ }
181
+ const resolved = path.resolve(file);
182
+ if (!fs.existsSync(resolved)) {
183
+ console.error(`not found: ${resolved}`);
184
+ process.exit(1);
185
+ }
186
+ const editor = process.env.EDITOR || process.env.VISUAL;
187
+ if (!editor) {
188
+ console.log(resolved);
189
+ console.error("(hint: set $EDITOR to open drafts automatically)");
190
+ return;
191
+ }
192
+ const [cmd, ...cmdArgs] = editor.split(/\s+/);
193
+ const child = spawn(cmd, [...cmdArgs, resolved], { stdio: "inherit" });
194
+ child.on("exit", (code) => {
195
+ if (code !== 0) process.exit(code || 1);
196
+ });
197
+ }
198
+
199
+ async function cmdSubmit(ctx, root, args) {
200
+ const file = args.positional[1];
201
+ if (!file) {
202
+ console.error("usage: shipctl feedback submit <draft-file>");
203
+ process.exit(1);
204
+ }
205
+ const resolved = path.resolve(file);
206
+ if (!fs.existsSync(resolved)) {
207
+ console.error(`not found: ${resolved}`);
208
+ process.exit(1);
209
+ }
210
+
211
+ const { meta, body } = readDraft(resolved);
212
+ const missing = [];
213
+ if (!meta.kind) missing.push("kind");
214
+ if (!meta.id) missing.push("id");
215
+ if (!meta.title) missing.push("title");
216
+ // Summary lives in body (after '**Summary**:'); derive it for validation.
217
+ const summaryMatch = body.match(/\*\*Summary\*\*:\s*([^\n]+)/);
218
+ const summary = summaryMatch ? summaryMatch[1].trim() : "";
219
+ if (!summary) missing.push("summary");
220
+ if (missing.length) {
221
+ console.error(`missing required fields: ${missing.join(", ")}`);
222
+ process.exit(1);
223
+ }
224
+
225
+ if (!args.yes && process.stdin.isTTY) {
226
+ const ok = (await promptLine(`submit ${path.basename(resolved)}? [y/N] `)).trim();
227
+ if (!/^y(es)?$/i.test(ok)) {
228
+ console.error("aborted.");
229
+ process.exit(1);
230
+ }
231
+ }
232
+
233
+ const { config } = readConfig(root);
234
+ const baseUrl = resolveBaseUrl(ctx, config);
235
+
236
+ const stack = config.stack || {};
237
+ const stackStr = `tracker=${stack.tracker || "-"}, ci=${stack.ci || "-"}, agents=${
238
+ Array.isArray(stack.agents) ? stack.agents.join("+") || "-" : "-"
239
+ }, preset=${stack.preset || "-"}`;
240
+
241
+ const recommendationMatch = body.match(/\*\*Recommendation\*\*:\s*([^\n]+)/);
242
+ const recommendation = recommendationMatch ? recommendationMatch[1].trim() : "";
243
+ const recommendations = recommendation ? [recommendation] : [];
244
+
245
+ const payload = {
246
+ title: meta.title,
247
+ summary,
248
+ recommendations,
249
+ source_context: stackStr,
250
+ artifact: {
251
+ kind: meta.kind,
252
+ id: meta.id,
253
+ version: meta.version || undefined,
254
+ },
255
+ };
256
+
257
+ let data;
258
+ try {
259
+ data = await postFeedback(baseUrl, payload);
260
+ } catch (e) {
261
+ console.error(e.message || String(e));
262
+ process.exit(20);
263
+ }
264
+
265
+ const issueUrl = data?.issue_url || "(no issue_url in response)";
266
+ console.log(issueUrl);
267
+ if (data?.deduplicated) console.log("(deduplicated: comment added to existing issue)");
268
+
269
+ const sentPath = moveDraftToSent(root, resolved);
270
+ console.log(`moved: ${sentPath}`);
271
+
272
+ if (
273
+ config.telemetry?.share === true &&
274
+ config.telemetry?.scope?.improvement_drafts === true
275
+ ) {
276
+ try {
277
+ appendEvent(root, {
278
+ type: "feedback.submit",
279
+ anonymous_id: config.telemetry.anonymous_id,
280
+ payload: {
281
+ artifact: {
282
+ kind: meta.kind,
283
+ id: meta.id,
284
+ version: meta.version || null,
285
+ },
286
+ summary,
287
+ suggestion: recommendation || null,
288
+ stack: {
289
+ tracker: stack.tracker || null,
290
+ ci: stack.ci || null,
291
+ agents: stack.agents || [],
292
+ preset: stack.preset || null,
293
+ },
294
+ },
295
+ });
296
+ } catch (e) {
297
+ if (process.env.SHIP_DEBUG === "1") {
298
+ console.error(`[ship:feedback] failed to append telemetry: ${e.message}`);
299
+ }
300
+ }
301
+ }
302
+ }
303
+
304
+ function cmdRemove(args) {
305
+ const file = args.positional[1];
306
+ if (!file) {
307
+ console.error("usage: shipctl feedback remove <draft-file>");
308
+ process.exit(1);
309
+ }
310
+ const resolved = path.resolve(file);
311
+ if (!fs.existsSync(resolved)) {
312
+ console.error(`not found: ${resolved}`);
313
+ process.exit(1);
314
+ }
315
+ removeDraft(resolved);
316
+ console.log(`removed: ${resolved}`);
317
+ }
318
+
319
+ export async function feedbackCommand(ctx, rest) {
320
+ const args = parseArgs(rest);
321
+ const sub = args.positional[0];
322
+ const root = requireShipRoot(args.cwd);
323
+ // ensure drafts dir exists lazily when commands need it
324
+ if (sub === "list" || sub === "draft") fs.mkdirSync(draftsDir(root), { recursive: true });
325
+
326
+ switch (sub) {
327
+ case "draft":
328
+ await cmdDraft(root, args);
329
+ return;
330
+ case "list":
331
+ cmdList(root);
332
+ return;
333
+ case "show":
334
+ cmdShow(args);
335
+ return;
336
+ case "edit":
337
+ cmdEdit(args);
338
+ return;
339
+ case "submit":
340
+ await cmdSubmit(ctx, root, args);
341
+ return;
342
+ case "remove":
343
+ cmdRemove(args);
344
+ return;
345
+ default:
346
+ console.error(
347
+ "usage: shipctl feedback <draft|list|show|edit|submit|remove> [...]\n" +
348
+ " draft --kind <k> --id <id> [--version <v>] --title '...' --summary '...' [--recommendation '...']\n" +
349
+ " list\n" +
350
+ " show|edit|remove <draft-file>\n" +
351
+ " submit <draft-file> [--yes]",
352
+ );
353
+ process.exit(2);
354
+ }
355
+ }
@@ -1,39 +1,114 @@
1
1
  export function printHelp() {
2
- console.log(`Ship CLI — methodology on ship.elmundi.com (or SHIP_API_BASE) + init.
2
+ console.log(`Ship CLI — artifacts protocol on ship.elmundi.com (or SHIP_API_BASE) + init.
3
3
 
4
- ONE FLOW
5
- 1) ship search <query> — vector search (POST /search) over docs + prompts + README
6
- 2) ship docs fetch <path> — full markdown file by repo-relative path (POST /fetch { path })
7
- ship pattern|tool|workflow|collection fetch <id> — catalog entry body (POST /fetch { kind, id })
8
- 3) ship docs feedback … — improvement / retro note (POST /feedback)
4
+ ARTIFACTS PROTOCOL (RFC-0001)
5
+ 1) shipctl search <query> — vector search (POST /search) over docs + prompts
6
+ 2) shipctl docs fetch <path> — full markdown body by repo-relative path
7
+ shipctl pattern|tool|collection show|fetch <id>
8
+ versioned artifact body (POST /fetch { kind, id, version? })
9
+ 3) shipctl docs feedback … — improvement / retro note (POST /feedback)
10
+
11
+ Every consumed artifact should be recorded in the PR as \`<kind>:<id>@<version>\`.
9
12
 
10
13
  COMMANDS
11
- ship help
12
- ship search <query> [--top-k N]
14
+ shipctl help
15
+ shipctl search <query> [--top-k N]
16
+
17
+ shipctl docs fetch <repo-relative-path>
18
+ shipctl docs feedback --title "..." --summary "..." [--recommendation "…"]... [--source-context "…"]
19
+
20
+ shipctl pattern list | shipctl pattern show <id> | shipctl pattern fetch <id> | shipctl pattern search <query> [--top-k N]
21
+ shipctl tool … | shipctl collection … (same subcommands; plural aliases: patterns, tools, …)
13
22
 
14
- ship docs fetch <repo-relative-path>
15
- ship docs feedback --title "..." --summary "..." [--recommendation "…"]... [--source-context "…"]
23
+ shipctl init [--yes] [--force] [--dry-run] [--json] [--cwd <dir>]
24
+ [--agents <csv>]
25
+ [--tracker <name>] [--ci <name>] [--preset <name>]
26
+ [--language <name>] [--channel stable|edge]
27
+ [--copy-rules] [--copy-playbook] [--bootstrap]
28
+ [--telemetry on|off|ask]
16
29
 
17
- ship pattern list | ship pattern show <id> | ship pattern fetch <id> | ship pattern search <query> [--top-k N]
18
- ship tool | ship workflow … | ship collection … (same subcommands; plural aliases: patterns, tools, …)
30
+ shipctl doctor [--json] [--cwd <dir>] [--write-inventory] [--no-network]
31
+ inspect the repo, propose a stack, optionally write
32
+ .ship/inventory.json for 'shipctl init --bootstrap'.
19
33
 
20
- ship init [--yes] [--force] [--dry-run] [--only <id>] [--cwd <dir>]
34
+ shipctl config init|get|set|validate|show|path — .ship/config.yml management
35
+ shipctl sync [--check-only] [--only <kind:id>...] [--channel <c>] [--force-unpin]
36
+ [--dry-run] [--lock] [--json]
37
+ — fetch artifacts into .ship/cache. With --lock,
38
+ also writes .ship/shipctl.lock.json covering every
39
+ pattern the declared lanes depend on (Phase 4).
40
+
41
+ shipctl new <name> [--preset ...] [--tracker ...] [--ci ...] [--agents ...] [--here] [--yes]
42
+ — bootstrap a fresh repo: git init + README + .ship/config.yml
43
+ shipctl verify [--no-network] [--check <id,...>] [--severity warn|error|info] [--json]
44
+ — post-adoption liveness checks (local + config + network)
45
+ shipctl telemetry status|on|off|show-id|reset-id|flush|export|delete-my-data|buffer
46
+ — opt-in anonymous usage (RFC-0003); default OFF.
47
+ '--scope artifact_usage,improvement_drafts,errors' on 'on'
48
+ '--dry-run' on 'flush'; '--out <file>' on 'export'
49
+ shipctl feedback draft|list|show|edit|submit|remove
50
+ — local markdown drafts; submit creates a GitHub issue
51
+ via POST /feedback and moves the draft to sent/.
52
+ shipctl callback --status <ok|fail|cancelled> [--summary "..."] [--metric k=v]...
53
+ — report a pipeline run's terminal status to Ship.
54
+ Used inside workflow.yml 'if: always()' steps;
55
+ reads SHIP_RUN_TOKEN + SHIP_CALLBACK_URL from env.
56
+ shipctl kickoff [--pattern kickoff] [--version …] [--raw] [--json] [--cwd …]
57
+ — print the kickoff / workload pattern body for piping
58
+ into the customer's agent in CI (see artifacts/patterns/kickoff).
59
+ shipctl migrate [--dry-run] [--yes] [--json] [--cwd …]
60
+ — upgrade .ship/config.yml from v1 to v2 (lanes-as-config).
61
+ shipctl run --lane <id> [--trigger event|schedule|manual|once]
62
+ [--dry-run] [--offline] [--json] [--cwd …]
63
+ [--ship-run-id …] [--ship-callback-url …] [--ship-run-token …]
64
+ — RFC-0007 entry-point: resolve a lane from
65
+ .ship/config.yml, fetch its pattern, check idempotency,
66
+ emit the prompt, and report the callback.
67
+ shipctl lanes install [--only <csv>] [--ref <git-ref>] [--owner …] [--repo …]
68
+ [--shipctl-version <v>] [--dry-run] [--force] [--json] [--cwd …]
69
+ — generate .github/workflows/ship-<lane>.yml thin
70
+ wrappers that delegate to the reusable run-agent.yml.
71
+ shipctl lanes list [--json] [--cwd …]
72
+ — print the lane map from .ship/config.yml.
73
+ shipctl lanes remove [--only <csv>] [--dry-run] [--json] [--cwd …]
74
+ — delete generated ship-<lane>.yml wrappers.
75
+ shipctl knowledge init [--workspace <id>] [--repo <id|owner/name>] [--only <csv>] [--json]
76
+ — open a PR that seeds .ship/knowledge/*.md starter
77
+ buckets (code-style, ui-runbook). Reads SHIP_API_TOKEN.
78
+ shipctl bootstrap (stub)
21
79
 
22
80
  GLOBAL FLAGS
23
81
  --base-url URL Methodology API (default: SHIP_API_BASE or https://ship.elmundi.com/api/methodology)
24
82
  --json Machine-readable JSON
25
83
 
26
84
  LOCAL TREE
27
- pattern / tool / workflow / collection list|show|fetch read manifests from disk when cwd or SHIP_REPO
28
- is inside the Ship monorepo (search always uses HTTP).
85
+ pattern / tool / collection list|show|fetch scan
86
+ artifacts/<plural>/<id>/ARTIFACT.md on disk when cwd or SHIP_REPO is inside
87
+ the Ship monorepo (search always uses HTTP).
29
88
 
30
89
  INIT FLAGS
31
- --yes Non-interactive apply (use --dry-run first)
32
- --force Replace existing injected blocks
33
- --dry-run Preview only
34
- --only cursor | agents-md | claude-md | codex | copilot
35
- --cwd Target repo root
90
+ --yes Non-interactive apply (use --dry-run first)
91
+ --force Replace existing rule blocks and overwrite generated files
92
+ --dry-run Preview only
93
+ --json Emit a JSON summary suitable for CI
94
+ --agents <csv> Comma-separated agent ids. See list below.
95
+ --tracker <name> Stack tracker: linear|jira|github-issues|azure-boards|clickup|spreadsheet|none
96
+ --ci <name> Stack CI: gh-actions|gitlab-ci|buildkite|circleci|azure-pipelines|jenkins|manual
97
+ --preset <name> Stack preset: web-app|api-backend|mobile-app|cli|monorepo|adoption-minimum
98
+ --language <name> Stack language: ts|js|py|go|rust|java|kotlin|swift|dart|multi
99
+ --channel <name> Override api.channel: stable|edge
100
+ --copy-rules Install collection/agent-rules-<agent> files at their install_target
101
+ --copy-playbook Fetch collection/adoption-playbook into .ship/cache/ (skipped on 404)
102
+ --bootstrap Render CI/tracker scaffolding (mobile-app+gh-actions+linear skeletons today;
103
+ other combos emit SHIP_BOOTSTRAP_PLAN.md)
104
+ --telemetry on|off|ask — override the interactive telemetry prompt
105
+ --cwd Target repo root
106
+
107
+ SUPPORTED AGENTS
108
+ cursor, codex, claude, aider, cline, continue, windsurf, zed,
109
+ gemini, opencode, copilot, cursor-cloud, agents-md, claude-md
36
110
 
37
- For HTTP schemas see documentation/tools/backend-api.md in the Ship repo.
111
+ For HTTP schemas see artifacts/tools/methodology-api/ARTIFACT.md in the Ship repo.
112
+ Package: @elmundi/ship-cli (binary: shipctl).
38
113
  `);
39
114
  }