@trawlme/cli 3.12.0 → 3.12.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 (74) hide show
  1. package/README.md +2 -2
  2. package/dist/commands/create.d.ts +0 -28
  3. package/dist/commands/create.js +0 -89
  4. package/dist/commands/doctor.d.ts +0 -79
  5. package/dist/commands/doctor.js +1 -187
  6. package/dist/commands/login.js +0 -67
  7. package/dist/commands/ping.d.ts +0 -15
  8. package/dist/commands/ping.js +0 -15
  9. package/dist/commands/scraps.d.ts +0 -120
  10. package/dist/commands/scraps.js +10 -724
  11. package/dist/commands/skills.js +0 -22
  12. package/dist/commands/spec.d.ts +0 -85
  13. package/dist/commands/spec.js +0 -67
  14. package/dist/commands/telemetry.js +0 -4
  15. package/dist/commands/token.js +0 -28
  16. package/dist/commands/upgrade.js +0 -22
  17. package/dist/commands/whoami.d.ts +0 -12
  18. package/dist/commands/whoami.js +0 -6
  19. package/dist/index.d.ts +0 -188
  20. package/dist/index.js +0 -349
  21. package/dist/lib/api.d.ts +0 -78
  22. package/dist/lib/api.js +1 -320
  23. package/dist/lib/cdp-pipe.d.ts +0 -72
  24. package/dist/lib/cdp-pipe.js +1 -81
  25. package/dist/lib/chrome-discovery.d.ts +0 -11
  26. package/dist/lib/chrome-discovery.js +0 -19
  27. package/dist/lib/chrome-launch.d.ts +0 -40
  28. package/dist/lib/chrome-launch.js +0 -69
  29. package/dist/lib/config.d.ts +0 -53
  30. package/dist/lib/config.js +0 -55
  31. package/dist/lib/confirm.d.ts +0 -55
  32. package/dist/lib/confirm.js +0 -47
  33. package/dist/lib/docs.d.ts +0 -123
  34. package/dist/lib/docs.js +0 -169
  35. package/dist/lib/errors.d.ts +0 -134
  36. package/dist/lib/errors.js +0 -151
  37. package/dist/lib/format.d.ts +0 -6
  38. package/dist/lib/format.js +0 -6
  39. package/dist/lib/json.d.ts +0 -35
  40. package/dist/lib/json.js +0 -48
  41. package/dist/lib/jwt.d.ts +0 -7
  42. package/dist/lib/jwt.js +0 -7
  43. package/dist/lib/pinch.d.ts +0 -53
  44. package/dist/lib/pinch.js +6 -112
  45. package/dist/lib/pinchAnimation.d.ts +0 -16
  46. package/dist/lib/pinchAnimation.js +8 -29
  47. package/dist/lib/posthog.d.ts +0 -9
  48. package/dist/lib/posthog.js +0 -23
  49. package/dist/lib/prompt.js +1 -20
  50. package/dist/lib/secure-transport.d.ts +0 -7
  51. package/dist/lib/secure-transport.js +0 -24
  52. package/dist/lib/session-capture-guard.d.ts +0 -15
  53. package/dist/lib/session-capture-guard.js +0 -5
  54. package/dist/lib/session-capture.d.ts +0 -125
  55. package/dist/lib/session-capture.js +0 -281
  56. package/dist/lib/skills.d.ts +0 -175
  57. package/dist/lib/skills.js +1 -216
  58. package/dist/lib/skillsNudge.d.ts +0 -17
  59. package/dist/lib/skillsNudge.js +0 -83
  60. package/dist/lib/spinner.d.ts +0 -39
  61. package/dist/lib/spinner.js +0 -40
  62. package/dist/lib/storage-state.d.ts +0 -112
  63. package/dist/lib/storage-state.js +0 -131
  64. package/dist/lib/tips.d.ts +0 -38
  65. package/dist/lib/tips.js +0 -77
  66. package/dist/lib/updateCheckWorker.js +0 -14
  67. package/dist/lib/updateNotifier.d.ts +0 -17
  68. package/dist/lib/updateNotifier.js +0 -53
  69. package/dist/lib/validate.d.ts +0 -8
  70. package/dist/lib/validate.js +0 -8
  71. package/dist/lib/version.d.ts +0 -12
  72. package/dist/lib/version.js +1 -13
  73. package/docs/agent-quickstart.md +2 -2
  74. package/package.json +2 -2
@@ -1,140 +1,17 @@
1
- /**
2
- * trawl_cli#185 — ONE source of truth for the docs URL(s) an agent (or
3
- * human) can be pointed at from three surfaces: `spec --json` (top-level
4
- * `docsUrl`/`llmsUrl` + a per-command `docs` deep link), a run's JSON
5
- * payload (`doctor`/`data --errors`/`run-info`, keyed on `failureKind` —
6
- * NOT errors.ts's unrelated `ErrorEnvelope.kind`, see the doc comment on
7
- * `FAILURE_KIND_DOC_PATHS` below), and the `--help` footer. Three hardcoded
8
- * lists here would diverge within months — that exact "same fact computed
9
- * in two places" defect has recurred repeatedly across this epic — so every
10
- * surface reads these same tables/functions, never its own copy.
11
- *
12
- * Resolution ladder (issue #185 — all three rungs REQUIRED, in this order,
13
- * evaluated PER FIELD, never as one bundled decision — see `resolveDocsUrls`):
14
- *
15
- * 1. Prefer the server. `externalDocs.url` on the OpenAPI document at
16
- * `<apiBase>/api/spec.json` is the standard OpenAPI field for exactly
17
- * this, and reading it makes a self-hosted install work with ZERO CLI
18
- * change. It is unset (null) server-side today, so this is
19
- * forward-looking — build it anyway, and it must win outright over rung
20
- * 2 when present. The one caller allowed to fetch it is `spec.ts`'s own
21
- * action, bounded and swallowed-on-failure (mirrors lib/tips.ts's
22
- * `isReferralProgramUserFacing`) — a deliberate, once-per-invocation
23
- * agent probe, not "every command". Every other surface (an error
24
- * payload on an arbitrary failing command, the `--help` footer) must
25
- * never add a network call or a failure mode to a command nobody asked
26
- * to hit the docs host for — see `resolveDocsUrls`'s `externalDocsUrl`
27
- * parameter, which only ever arrives pre-fetched.
28
- * 2. Else derive, by stripping a leading `api.` host label from the
29
- * configured API base — but ONLY for a KNOWN first-party `trawl.me`
30
- * host. `api.trawl.me` -> `trawl.me` (prod: API and docs are genuinely
31
- * on different hosts); `dev.trawl.me` (no `api.` prefix) -> unchanged
32
- * (dev serves docs on the SAME host as its API). A generic, unscoped
33
- * `api.`-strip applied to ANY host is itself a guess — it assumes a
34
- * self-hosted `api.acme.internal` serves docs at `acme.internal`, which
35
- * nothing here can know. Scoping the strip to `trawl.me` is what makes
36
- * rung 3 (below) ever actually fire for a self-hosted base.
37
- * 3. Else OMIT the field entirely. Never emit a guessed URL (issue's Rule
38
- * 3): a wrong URL sends an agent to a 404 WITH CONFIDENCE, worse than no
39
- * URL at all — a self-hosted install with no server-declared
40
- * `externalDocs` and a base outside `trawl.me` gets no `docsUrl`/
41
- * `llmsUrl`, not a hopeful default pointed at OUR docs host.
42
- *
43
- * `llmsUrl` has no OpenAPI-standard field to read (rung 1 contributes
44
- * nothing to it) — deriving it from the ORIGIN of a server-declared
45
- * `externalDocs.url` would itself be a guess for a self-hosted install
46
- * (rule 3 again), so `llmsUrl` resolves ONLY via rung 2 (the known-host
47
- * derivation) or omission. It never rides along with a rung-1 `docsUrl`.
48
- *
49
- * PROVENANCE (defect fix, reviewer repro against a live mock server): the
50
- * top-level `docsUrl` above is deliberately the FLATTENED "whichever rung
51
- * won" value — right for a human reading `spec --json`'s top-level field,
52
- * WRONG as an input to `resolveCommandDocsUrl`/`resolveFailureKindDocsUrl`
53
- * below. Those two append one of THIS CLI's own hardcoded guide slugs
54
- * (`COMMAND_DOC_PATHS`/`FAILURE_KIND_DOC_PATHS`) onto whatever `docsUrl`
55
- * resolved — safe onto a rung-2 root we derived ourselves (we know
56
- * trawl.me's guide tree), never safe onto a rung-1 root (an arbitrary
57
- * third party's own docs site, self-hosted, with no reason to carry our
58
- * slugs). A mock server declaring `externalDocs.url: 'http://h/guide'`
59
- * used to get `http://h/guide/build-your-scrap/account-sessions` appended
60
- * — a confidently-wrong 404. So `DocsUrls.docsUrlIsDerived` carries rung
61
- * provenance ALONGSIDE the string (never flattened to a bare string again)
62
- * and both deep-link functions now take the whole `DocsUrls`-shaped object
63
- * and gate construction on that flag — see its own doc comment below.
64
- */
65
1
  export interface DocsUrls {
66
2
  docsUrl?: string;
67
3
  llmsUrl?: string;
68
- /**
69
- * True iff `docsUrl` came from rung 2 (THIS CLI's own derivation from a
70
- * KNOWN `trawl.me` host) — the only case where it is safe to append one of
71
- * this CLI's own guide slugs onto it (see `resolveCommandDocsUrl`/
72
- * `resolveFailureKindDocsUrl`). False when `docsUrl` is a rung-1
73
- * SERVER-declared root instead — an arbitrary third party's own docs site,
74
- * which has no reason to host our guide slugs, even when that server
75
- * happens to run on a `trawl.me` host. Always a defined boolean whenever
76
- * `docsUrl` itself is present; undefined only when `docsUrl` is undefined
77
- * too (rung 3 — nothing resolved at all).
78
- */
79
4
  docsUrlIsDerived?: boolean;
80
5
  }
81
- /**
82
- * Rung 2 — see the module doc comment. Returns `{ protocol, host }` for a
83
- * KNOWN first-party API base (preserving the base's own protocol rather
84
- * than assuming `https:`), or `null` when the base isn't recognized
85
- * (self-hosted, a custom domain, `localhost`, an unparseable string, …) —
86
- * `null` must propagate to omission (rung 3), never to a guessed host.
87
- */
88
6
  export declare function deriveDocsOrigin(apiBaseUrl: string): {
89
7
  protocol: string;
90
8
  host: string;
91
9
  } | null;
92
- /** Same rung as `deriveDocsOrigin`, collapsed to just the host string —
93
- * convenience for a caller that only needs the derived host, not the
94
- * protocol (kept as its own export since `docs.test.ts` exercises the host
95
- * derivation independently of protocol handling). */
96
10
  export declare function deriveDocsHost(apiBaseUrl: string): string | null;
97
- /**
98
- * The full ladder, PER FIELD (see module doc comment for why `llmsUrl`
99
- * cannot ride along with a rung-1 `docsUrl`). Pure and synchronous — no
100
- * network, safe to call from any surface (an error payload, the `--help`
101
- * footer) without adding latency or a new failure mode. `externalDocsUrl`
102
- * is rung 1's input: only ever supplied by `spec.ts`'s action, after its
103
- * own bounded, swallowed-on-failure fetch — every other caller omits it and
104
- * gets rungs 2/3 only.
105
- */
106
11
  export declare function resolveDocsUrls(opts: {
107
12
  apiBaseUrl: string;
108
13
  externalDocsUrl?: string | null;
109
14
  }): DocsUrls;
110
- /**
111
- * `resolveCommandDocsUrl` returns `undefined` (never a bare path or a
112
- * relative link) whenever any of three things is missing — `docsUrl`
113
- * unresolved (rung 3 already fired), `docsUrl` resolved but NOT derived
114
- * (rung 1 — a server-declared root; see `DocsUrls.docsUrlIsDerived`'s doc
115
- * comment for why appending our own guide slug onto a third party's root is
116
- * exactly the confidently-wrong-404 defect this gate closes), or no guide is
117
- * mapped for this command — so a spec consumer never has to special-case a
118
- * partial value. Takes the whole resolved `DocsUrls` object (never a bare
119
- * string) specifically so this provenance can never again be flattened away
120
- * before it reaches here.
121
- */
122
15
  export declare function resolveCommandDocsUrl(commandName: string, docs: Pick<DocsUrls, 'docsUrl' | 'docsUrlIsDerived'>): string | undefined;
123
- /** Same "undefined unless docsUrl is resolved AND derived (rung 2)" gate as
124
- * `resolveCommandDocsUrl` above, same reason — never append this CLI's own
125
- * guide slug onto a rung-1 server-declared root. Callers MUST gate the call
126
- * on their own staleness rule first (e.g. `doctor.ts`'s `isAuthWall`) — this
127
- * function only knows the string-to-path mapping, not whether a stamped
128
- * `failureKind` is still live on a run patched afterward. */
129
16
  export declare function resolveFailureKindDocsUrl(kind: string | null | undefined, docs: Pick<DocsUrls, 'docsUrl' | 'docsUrlIsDerived'>): string | undefined;
130
- /**
131
- * `--help` footer text (issue #185 scope item 3) — a single dim line, for
132
- * humans, e.g. "Docs: https://trawl.me/docs". Returns `undefined` (never an
133
- * empty or guessed line) when no `docsUrl` resolved — mirrors
134
- * lib/tips.ts's shape (a pure function separated from IO, so it's testable
135
- * without mocking chalk/console) but NOT its TTY gate: tips.ts suppresses a
136
- * promotional nudge from piped output, but a docs line inside `--help |
137
- * less` is exactly the kind of thing worth keeping. Un-colored here — the
138
- * caller (index.ts) applies `chalk.dim` so this stays trivially testable.
139
- */
140
17
  export declare function docsFooterLine(docsUrl?: string): string | undefined;
package/dist/lib/docs.js CHANGED
@@ -1,78 +1,4 @@
1
- /**
2
- * trawl_cli#185 — ONE source of truth for the docs URL(s) an agent (or
3
- * human) can be pointed at from three surfaces: `spec --json` (top-level
4
- * `docsUrl`/`llmsUrl` + a per-command `docs` deep link), a run's JSON
5
- * payload (`doctor`/`data --errors`/`run-info`, keyed on `failureKind` —
6
- * NOT errors.ts's unrelated `ErrorEnvelope.kind`, see the doc comment on
7
- * `FAILURE_KIND_DOC_PATHS` below), and the `--help` footer. Three hardcoded
8
- * lists here would diverge within months — that exact "same fact computed
9
- * in two places" defect has recurred repeatedly across this epic — so every
10
- * surface reads these same tables/functions, never its own copy.
11
- *
12
- * Resolution ladder (issue #185 — all three rungs REQUIRED, in this order,
13
- * evaluated PER FIELD, never as one bundled decision — see `resolveDocsUrls`):
14
- *
15
- * 1. Prefer the server. `externalDocs.url` on the OpenAPI document at
16
- * `<apiBase>/api/spec.json` is the standard OpenAPI field for exactly
17
- * this, and reading it makes a self-hosted install work with ZERO CLI
18
- * change. It is unset (null) server-side today, so this is
19
- * forward-looking — build it anyway, and it must win outright over rung
20
- * 2 when present. The one caller allowed to fetch it is `spec.ts`'s own
21
- * action, bounded and swallowed-on-failure (mirrors lib/tips.ts's
22
- * `isReferralProgramUserFacing`) — a deliberate, once-per-invocation
23
- * agent probe, not "every command". Every other surface (an error
24
- * payload on an arbitrary failing command, the `--help` footer) must
25
- * never add a network call or a failure mode to a command nobody asked
26
- * to hit the docs host for — see `resolveDocsUrls`'s `externalDocsUrl`
27
- * parameter, which only ever arrives pre-fetched.
28
- * 2. Else derive, by stripping a leading `api.` host label from the
29
- * configured API base — but ONLY for a KNOWN first-party `trawl.me`
30
- * host. `api.trawl.me` -> `trawl.me` (prod: API and docs are genuinely
31
- * on different hosts); `dev.trawl.me` (no `api.` prefix) -> unchanged
32
- * (dev serves docs on the SAME host as its API). A generic, unscoped
33
- * `api.`-strip applied to ANY host is itself a guess — it assumes a
34
- * self-hosted `api.acme.internal` serves docs at `acme.internal`, which
35
- * nothing here can know. Scoping the strip to `trawl.me` is what makes
36
- * rung 3 (below) ever actually fire for a self-hosted base.
37
- * 3. Else OMIT the field entirely. Never emit a guessed URL (issue's Rule
38
- * 3): a wrong URL sends an agent to a 404 WITH CONFIDENCE, worse than no
39
- * URL at all — a self-hosted install with no server-declared
40
- * `externalDocs` and a base outside `trawl.me` gets no `docsUrl`/
41
- * `llmsUrl`, not a hopeful default pointed at OUR docs host.
42
- *
43
- * `llmsUrl` has no OpenAPI-standard field to read (rung 1 contributes
44
- * nothing to it) — deriving it from the ORIGIN of a server-declared
45
- * `externalDocs.url` would itself be a guess for a self-hosted install
46
- * (rule 3 again), so `llmsUrl` resolves ONLY via rung 2 (the known-host
47
- * derivation) or omission. It never rides along with a rung-1 `docsUrl`.
48
- *
49
- * PROVENANCE (defect fix, reviewer repro against a live mock server): the
50
- * top-level `docsUrl` above is deliberately the FLATTENED "whichever rung
51
- * won" value — right for a human reading `spec --json`'s top-level field,
52
- * WRONG as an input to `resolveCommandDocsUrl`/`resolveFailureKindDocsUrl`
53
- * below. Those two append one of THIS CLI's own hardcoded guide slugs
54
- * (`COMMAND_DOC_PATHS`/`FAILURE_KIND_DOC_PATHS`) onto whatever `docsUrl`
55
- * resolved — safe onto a rung-2 root we derived ourselves (we know
56
- * trawl.me's guide tree), never safe onto a rung-1 root (an arbitrary
57
- * third party's own docs site, self-hosted, with no reason to carry our
58
- * slugs). A mock server declaring `externalDocs.url: 'http://h/guide'`
59
- * used to get `http://h/guide/build-your-scrap/account-sessions` appended
60
- * — a confidently-wrong 404. So `DocsUrls.docsUrlIsDerived` carries rung
61
- * provenance ALONGSIDE the string (never flattened to a bare string again)
62
- * and both deep-link functions now take the whole `DocsUrls`-shaped object
63
- * and gate construction on that flag — see its own doc comment below.
64
- */
65
- /** The one first-party domain this CLI knows to serve docs — see rung 2 in
66
- * the module doc comment above. Deliberately not "any host", so an
67
- * unrecognized (self-hosted/custom) base falls through to omission. */
68
1
  const KNOWN_DOCS_DOMAIN = 'trawl.me';
69
- /**
70
- * Rung 2 — see the module doc comment. Returns `{ protocol, host }` for a
71
- * KNOWN first-party API base (preserving the base's own protocol rather
72
- * than assuming `https:`), or `null` when the base isn't recognized
73
- * (self-hosted, a custom domain, `localhost`, an unparseable string, …) —
74
- * `null` must propagate to omission (rung 3), never to a guessed host.
75
- */
76
2
  export function deriveDocsOrigin(apiBaseUrl) {
77
3
  let url;
78
4
  try {
@@ -88,22 +14,9 @@ export function deriveDocsOrigin(apiBaseUrl) {
88
14
  }
89
15
  return null;
90
16
  }
91
- /** Same rung as `deriveDocsOrigin`, collapsed to just the host string —
92
- * convenience for a caller that only needs the derived host, not the
93
- * protocol (kept as its own export since `docs.test.ts` exercises the host
94
- * derivation independently of protocol handling). */
95
17
  export function deriveDocsHost(apiBaseUrl) {
96
18
  return deriveDocsOrigin(apiBaseUrl)?.host ?? null;
97
19
  }
98
- /**
99
- * The full ladder, PER FIELD (see module doc comment for why `llmsUrl`
100
- * cannot ride along with a rung-1 `docsUrl`). Pure and synchronous — no
101
- * network, safe to call from any surface (an error payload, the `--help`
102
- * footer) without adding latency or a new failure mode. `externalDocsUrl`
103
- * is rung 1's input: only ever supplied by `spec.ts`'s action, after its
104
- * own bounded, swallowed-on-failure fetch — every other caller omits it and
105
- * gets rungs 2/3 only.
106
- */
107
20
  export function resolveDocsUrls(opts) {
108
21
  const origin = deriveDocsOrigin(opts.apiBaseUrl);
109
22
  const derived = origin
@@ -114,95 +27,29 @@ export function resolveDocsUrls(opts) {
114
27
  }
115
28
  : {};
116
29
  if (opts.externalDocsUrl) {
117
- // Rung 1 wins for docsUrl outright; llmsUrl stays rung-2-only (see doc
118
- // comment) — a self-hosted `externalDocsUrl` outside `trawl.me` yields
119
- // `{ docsUrl: <server's own> }` with `llmsUrl` omitted, never guessed.
120
- // `docsUrlIsDerived: false` regardless of whether rung 2 ALSO resolved
121
- // (e.g. a `trawl.me`-hosted server declaring its own externalDocs) — a
122
- // server-declared root is never "derived" by THIS CLI, and never a safe
123
- // base for our own guide slugs (see DocsUrls.docsUrlIsDerived).
124
30
  return derived.llmsUrl
125
31
  ? { docsUrl: opts.externalDocsUrl, llmsUrl: derived.llmsUrl, docsUrlIsDerived: false }
126
32
  : { docsUrl: opts.externalDocsUrl, docsUrlIsDerived: false };
127
33
  }
128
34
  return derived;
129
35
  }
130
- /** Join a docs root (e.g. `https://trawl.me/docs`) with a guide path
131
- * suffix (e.g. `build-your-scrap/account-sessions`) — plain string
132
- * concatenation, deliberately NOT `new URL(suffix, docsUrl)`: a
133
- * leading-slash suffix resolved against a URL with its own path component
134
- * (`/docs`) would resolve relative to the ORIGIN, silently dropping
135
- * `/docs` from the result (`new URL('/x', 'https://h/docs')` ==
136
- * `https://h/x`, not `https://h/docs/x`). */
137
36
  function joinDocsPath(docsUrl, suffix) {
138
37
  return `${docsUrl.replace(/\/+$/, '')}/${suffix.replace(/^\/+/, '')}`;
139
38
  }
140
- /**
141
- * The single source for the account-sessions guide slug — referenced by
142
- * BOTH `COMMAND_DOC_PATHS` and `FAILURE_KIND_DOC_PATHS` below. Those two
143
- * tables key on different fields (a CLI command's full path name vs a run's
144
- * `failureKind`) and legitimately stay separate, but they name the SAME
145
- * guide, so the path literal itself must exist exactly once: this is the
146
- * "same fact computed in two places" defect class this module's own doc
147
- * comment says it exists to prevent, and it has recurred repeatedly across
148
- * this epic. Renaming the guide used to require editing two literals in
149
- * lockstep — miss one and one surface (a run's `docs` field, or `spec
150
- * --json`'s per-command deep link) silently 404s while the other still
151
- * works (trawl_cli#185 review).
152
- */
153
39
  const ACCOUNT_SESSIONS_GUIDE_PATH = 'build-your-scrap/account-sessions';
154
- /**
155
- * Per-command deep links (issue #185 scope item 1) — a command's FULL path
156
- * name (matches `CliSpecCommand.name` in spec.ts, e.g.
157
- * `"scraps account session set"`) is matched against `prefix` either
158
- * exactly or as a whole path SEGMENT prefix (`startsWith(prefix + ' ')`) —
159
- * never a bare substring, so a hypothetical future `scraps accounting`
160
- * command could never false-match the `scraps account` entry below.
161
- */
162
40
  const COMMAND_DOC_PATHS = Object.freeze([
163
- // Every account/session-management command — set, delete, clear-session,
164
- // status, and the nested `session set` — is covered by one prefix entry
165
- // rather than one row per leaf, so a new leaf added under `scraps account`
166
- // later (e.g. a future `session capture`, trawl_cli#183) inherits the
167
- // link for free instead of needing its own row.
168
41
  { prefix: 'scraps account', path: ACCOUNT_SESSIONS_GUIDE_PATH },
169
42
  ]);
170
43
  function docsPathForCommand(commandName) {
171
44
  const match = COMMAND_DOC_PATHS.find((e) => commandName === e.prefix || commandName.startsWith(`${e.prefix} `));
172
45
  return match ? match.path : null;
173
46
  }
174
- /**
175
- * `resolveCommandDocsUrl` returns `undefined` (never a bare path or a
176
- * relative link) whenever any of three things is missing — `docsUrl`
177
- * unresolved (rung 3 already fired), `docsUrl` resolved but NOT derived
178
- * (rung 1 — a server-declared root; see `DocsUrls.docsUrlIsDerived`'s doc
179
- * comment for why appending our own guide slug onto a third party's root is
180
- * exactly the confidently-wrong-404 defect this gate closes), or no guide is
181
- * mapped for this command — so a spec consumer never has to special-case a
182
- * partial value. Takes the whole resolved `DocsUrls` object (never a bare
183
- * string) specifically so this provenance can never again be flattened away
184
- * before it reaches here.
185
- */
186
47
  export function resolveCommandDocsUrl(commandName, docs) {
187
48
  if (!docs.docsUrl || !docs.docsUrlIsDerived)
188
49
  return undefined;
189
50
  const path = docsPathForCommand(commandName);
190
51
  return path ? joinDocsPath(docs.docsUrl, path) : undefined;
191
52
  }
192
- /**
193
- * failureKind -> guide path (issue #185 scope item 2). Keyed on trawl_node's
194
- * run-level `failureKind` field (trawl_node#1975, surfaced by this CLI's
195
- * own `doctor`/`data --errors`/`run-info` JSON payloads since cli#182) —
196
- * this is a DIFFERENT axis from errors.ts's `ErrorEnvelope.kind` (a CLI
197
- * transport/execution outcome like `"auth"` meaning "you're not logged
198
- * into trawl", `"network"`, `"usage"`, …). Both happen to use the string
199
- * `"auth"` for unrelated things: this table's `'auth'` means "the SCRAPED
200
- * TARGET site showed a login wall", errors.ts's `'auth'` means "the TRAWL
201
- * API rejected your OWN credentials". Never merge these two tables — they
202
- * are keyed off different fields on different objects, and conflating them
203
- * would either miss the run-level guide or wrongly attach it to an
204
- * unrelated CLI auth failure.
205
- */
206
53
  const FAILURE_KIND_DOC_PATHS = Object.freeze({
207
54
  auth: ACCOUNT_SESSIONS_GUIDE_PATH,
208
55
  });
@@ -211,28 +58,12 @@ function docsPathForFailureKind(kind) {
211
58
  return null;
212
59
  return FAILURE_KIND_DOC_PATHS[kind] ?? null;
213
60
  }
214
- /** Same "undefined unless docsUrl is resolved AND derived (rung 2)" gate as
215
- * `resolveCommandDocsUrl` above, same reason — never append this CLI's own
216
- * guide slug onto a rung-1 server-declared root. Callers MUST gate the call
217
- * on their own staleness rule first (e.g. `doctor.ts`'s `isAuthWall`) — this
218
- * function only knows the string-to-path mapping, not whether a stamped
219
- * `failureKind` is still live on a run patched afterward. */
220
61
  export function resolveFailureKindDocsUrl(kind, docs) {
221
62
  if (!docs.docsUrl || !docs.docsUrlIsDerived)
222
63
  return undefined;
223
64
  const path = docsPathForFailureKind(kind);
224
65
  return path ? joinDocsPath(docs.docsUrl, path) : undefined;
225
66
  }
226
- /**
227
- * `--help` footer text (issue #185 scope item 3) — a single dim line, for
228
- * humans, e.g. "Docs: https://trawl.me/docs". Returns `undefined` (never an
229
- * empty or guessed line) when no `docsUrl` resolved — mirrors
230
- * lib/tips.ts's shape (a pure function separated from IO, so it's testable
231
- * without mocking chalk/console) but NOT its TTY gate: tips.ts suppresses a
232
- * promotional nudge from piped output, but a docs line inside `--help |
233
- * less` is exactly the kind of thing worth keeping. Un-colored here — the
234
- * caller (index.ts) applies `chalk.dim` so this stays trivially testable.
235
- */
236
67
  export function docsFooterLine(docsUrl) {
237
68
  return docsUrl ? `Docs: ${docsUrl}` : undefined;
238
69
  }
@@ -1,58 +1,21 @@
1
- /**
2
- * Thrown for CLI usage / input-validation failures (bad flag value, malformed
3
- * JSON, invalid ObjectId, missing required prompt input, …). Distinguished
4
- * from ApiError/NetworkError so the top-level handler can map it to its own
5
- * exit code (2) instead of the generic uniform 1 every other bug collapses
6
- * into. (#71)
7
- */
8
1
  export declare class UsageError extends Error {
9
2
  constructor(message: string);
10
3
  }
11
- /**
12
- * Thrown for a business-logic REFUSAL the server explicitly reported back
13
- * (e.g. a tier-ceiling override the registry cap rejected) — distinct from
14
- * an arbitrary unmapped bug. Before this, `reportTierRefusal` routed a bare
15
- * `new Error(message)` through here, which fell through to the generic
16
- * `kind:"unknown"` bucket — indistinguishable from a genuine crash, even
17
- * though the README sells `kind` as the machine discriminant an agent
18
- * branches on. Same exit code (1: a business-logic refusal, not a usage
19
- * error) as before — only the `kind` differs. (#107 review F3)
20
- */
21
4
  export declare class RefusalError extends Error {
22
5
  constructor(message: string);
23
6
  }
24
- /**
25
- * Commander prefixes every one of its own usage-error messages with the
26
- * literal `"error: "` (see `missingArgument`/`unknownOption`/`unknownCommand`
27
- * etc. in commander's `command.js`) — harmless for its own plain default
28
- * line, but redundant once this CLI reuses that message itself: (1) baked
29
- * into a `--json` envelope's `message` field, a human-facing "error: " prefix
30
- * is dead weight for a machine parser that already reads `kind:"usage"`; (2)
31
- * reformatted through the app's own `chalk.red('✗ ' + message)` convention it
32
- * would double up as "✗ error: unknown option …". Idempotent — a message
33
- * that never had the prefix passes through unchanged. (#149 items 1/2)
34
- */
35
7
  export declare function stripCommanderErrorPrefix(message: string): string;
36
8
  export interface ErrorEnvelope {
37
9
  message: string;
38
10
  status?: number;
39
11
  kind: string;
40
- /** Is retrying the SAME command, unchanged, worth it? */
41
12
  retryable: boolean;
42
- /** Commands worth running next, most useful first. Empty when there is
43
- * nothing honest to suggest — never filled to look helpful. */
44
13
  next?: string[];
45
14
  }
46
15
  export interface ClassifiedError {
47
16
  exitCode: number;
48
17
  envelope: ErrorEnvelope;
49
18
  }
50
- /**
51
- * The exit-code taxonomy (#71 findings 13/14/60), named once so
52
- * `classifyError` below and `spec.ts`'s `buildSpec()` (#170) read the SAME
53
- * numbers instead of `spec.ts` hand-listing its own copy — exactly the kind
54
- * of second source of truth `tests/contracts/` exists to catch drifting.
55
- */
56
19
  export declare const EXIT_CODES: Readonly<{
57
20
  SUCCESS: 0;
58
21
  UNKNOWN: 1;
@@ -61,116 +24,19 @@ export declare const EXIT_CODES: Readonly<{
61
24
  NOT_FOUND: 4;
62
25
  NETWORK: 5;
63
26
  }>;
64
- /** `trawl spec --json`'s `exitCodes` field — a short label per code. Code
65
- * `1` is shared by several `kind`s (`api`, `refused`, `unknown`); the label
66
- * names the generic/unmapped bucket it represents, not an exhaustive list. */
67
27
  export declare const EXIT_CODE_LABELS: Readonly<Record<string, string>>;
68
- /**
69
- * #170 — ONE frozen map, keyed by the existing `kind`, driving the
70
- * envelope's new `retryable`/`next` fields. This is also the exhaustive set
71
- * of `kind`s `classifyError` can produce — `ERROR_KINDS` below derives its
72
- * list from these keys rather than hand-listing them a second time, and
73
- * `spec.ts`'s `buildSpec()` reads `ERROR_KINDS`, never its own copy.
74
- *
75
- * `network` is the one kind worth retrying unchanged. `auth` isn't
76
- * retryable but has an honest next step (`trawl login --token <jwt>`).
77
- * Everything else (`usage`/`not_found`/`api`/`refused`/`unknown`) is neither
78
- * — retrying a bad flag, a missing resource, or an unmapped bug with no new
79
- * information just repeats the same failure.
80
- *
81
- * #170 review F8 — `next` must be an EXECUTABLE next command, not just a verb
82
- * name: bare `trawl login` still blocks on an interactive prompt (email then
83
- * password) — for a non-interactive caller (stdin closed, the exact
84
- * situation an auth failure implies) it fails immediately with its OWN usage
85
- * error instead of the login the agent was told to run. `trawl login --token
86
- * <jwt>` is the one form of `login` that never prompts.
87
- */
88
28
  export declare const RETRY_POLICY: Readonly<Record<string, {
89
29
  retryable: boolean;
90
30
  next?: readonly string[];
91
31
  }>>;
92
- /** Every `kind` string `classifyError` can produce — derived from
93
- * `RETRY_POLICY`'s keys (see its doc comment), never a second hand list. */
94
32
  export declare const ERROR_KINDS: readonly string[];
95
- /**
96
- * Every `kind` a real `--json` error envelope can carry — NOT the same set
97
- * as `ERROR_KINDS`. `ERROR_KINDS` is deliberately narrow (exactly what
98
- * `classifyError` produces, see its own doc comment — `RETRY_POLICY` must
99
- * keep meaning that, `retryFieldsFor` relies on it), but three more kinds
100
- * reach a real envelope from hand-built emitters that never go through
101
- * `classifyError` at all:
102
- * - `in_progress` — `src/commands/scraps.ts`, `data <id>`'s `reportDataState`
103
- * call for a run still in flight
104
- * - `run_failed` — same file, same helper, for a last run that failed
105
- * - `upgrade_failed` — `src/commands/upgrade.ts`, when `npm install -g` itself fails
106
- *
107
- * `spec.ts`'s `errorKinds` field publishes THIS constant, never
108
- * `ERROR_KINDS` — an agent that builds its allow-list from the published
109
- * spec must not reject a perfectly valid `{"error":{"kind":"in_progress",…}}`
110
- * envelope just because it was hand-built instead of classified. Built as a
111
- * union (spread `ERROR_KINDS` + list the hand-built kinds) rather than a
112
- * second hand-copy of the first group, so the classifyError kinds are
113
- * PROVABLY a subset — see errors.test.ts's exhaustiveness check.
114
- *
115
- * Adding a new hand-built `kind:` literal anywhere in `src/` means
116
- * registering it here too, or the published spec will lie about it exactly
117
- * like this constant exists to prevent.
118
- */
119
33
  export declare const ENVELOPE_KINDS: readonly string[];
120
- /**
121
- * #170 review F7 — `spec --json`'s flat `exitCodes` map (`EXIT_CODE_LABELS`)
122
- * publishes ONE label per code, which is honest about code `1` being a
123
- * generic/unmapped bucket but says nothing about which `kind`s actually land
124
- * there. An agent building an `exitCode -> kind` table off `exitCodes` alone
125
- * reads `"1":"unknown"` and treats every other kind sharing that code
126
- * (`api`/`refused`/`in_progress`/`run_failed`/`upgrade_failed`) as an
127
- * unmapped bug it should give up on — instead of honouring the very
128
- * `retryable`/`next` fields those envelopes correctly carry.
129
- *
130
- * This is the inverse direction, `kind -> exitCode`, one entry per
131
- * `ENVELOPE_KINDS` member — additive (published as a SIBLING field,
132
- * `kindExitCodes`, never replacing `exitCodes`) and keyed off the same
133
- * `EXIT_CODES` constants every real call site already uses, so a future exit
134
- * code change here can't silently drift from `classifyError`/
135
- * `reportDataState`/`upgrade.ts`'s actual behaviour without also changing the
136
- * single source those all draw from. errors.test.ts asserts every entry here
137
- * against classifyError's REAL returned exitCode for that kind — the closest
138
- * an exhaustive hand-map can get to "derived", short of `classifyError`
139
- * itself being rewritten to loop over a shared table (out of scope here).
140
- */
141
34
  export declare const KIND_EXIT_CODES: Readonly<Record<string, number>>;
142
- /**
143
- * Look up the frozen default `retryable`/`next` for a `kind`. Total (never
144
- * throws) — a `kind` outside `RETRY_POLICY` (e.g. `scraps data`'s own
145
- * `run_failed`/`in_progress` states, which aren't part of `classifyError`'s
146
- * taxonomy) falls back to the conservative "not retryable, nothing to
147
- * suggest" default. Callers with a genuine kind-is-wrong override (an
148
- * `ApiError` 429, `scraps data`'s `in_progress` refusal) pass their own
149
- * `retryable`/`next` instead of trusting this lookup — see classifyError and
150
- * scraps.ts's `reportDataState`.
151
- */
152
35
  export declare function retryFieldsFor(kind: string): {
153
36
  retryable: boolean;
154
37
  next?: string[];
155
38
  };
156
- /**
157
- * Central status → exit-code map (#71 findings 13/14/60). Agents driving this
158
- * CLI unattended need to tell "you're not logged in" (3) from "that id
159
- * doesn't exist" (4) from "the network/API is unreachable" (5) from "you
160
- * passed a bad flag" (2) — a uniform exit 1 collapses all of these into one
161
- * undifferentiable signal.
162
- */
163
39
  export declare function classifyError(err: unknown): ClassifiedError;
164
- /**
165
- * Print a classified error to the correct stream and return its exit code.
166
- * stdout is reserved for payload — under --json the error itself IS the
167
- * payload (`{"error":{message,status,kind,retryable,next?}}`); otherwise the
168
- * human-readable line goes to stderr, never stdout. (#71 findings 13/14/60)
169
- *
170
- * `quiet` skips the human-readable stderr line (used when the caller already
171
- * printed a fuller diagnostic, e.g. a raw stack trace under --debug) while
172
- * still emitting the --json payload when requested.
173
- */
174
40
  export declare function reportError(err: unknown, opts?: {
175
41
  json?: boolean;
176
42
  quiet?: boolean;