cngkit 1.1.7 → 1.1.9

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 (45) hide show
  1. package/README.md +261 -82
  2. package/dist/{chunk-EQEIX7N5.js → chunk-575IBOIA.js} +2 -2
  3. package/dist/{chunk-EQEIX7N5.js.map → chunk-575IBOIA.js.map} +1 -1
  4. package/dist/{chunk-QEZQGKFX.js → chunk-CHSTTMTO.js} +2 -2
  5. package/dist/{chunk-TZKXST4G.js → chunk-LWZPSJVC.js} +48 -20
  6. package/dist/chunk-LWZPSJVC.js.map +1 -0
  7. package/dist/{chunk-Z4DDLEWR.js → chunk-NTF45QBC.js} +4 -12
  8. package/dist/chunk-NTF45QBC.js.map +1 -0
  9. package/dist/{chunk-HUZZPV5E.js → chunk-OKKJBRUU.js} +16 -12
  10. package/dist/chunk-OKKJBRUU.js.map +1 -0
  11. package/dist/chunk-OTQRKCFP.js +139 -0
  12. package/dist/chunk-OTQRKCFP.js.map +1 -0
  13. package/dist/{chunk-VI5XQH3U.js → chunk-WPBMAXXM.js} +3 -3
  14. package/dist/{chunk-VI5XQH3U.js.map → chunk-WPBMAXXM.js.map} +1 -1
  15. package/dist/cli.js +8 -8
  16. package/dist/cli.js.map +1 -1
  17. package/dist/commands/coderoom/index.js +4 -4
  18. package/dist/commands/coderoom/index.js.map +1 -1
  19. package/dist/commands/coderoom/join.js +5 -5
  20. package/dist/commands/coderoom/share.js +5 -5
  21. package/dist/commands/index.js +4 -4
  22. package/dist/commands/index.js.map +1 -1
  23. package/dist/commands/knowledges/audiences.js +6 -6
  24. package/dist/commands/knowledges/files.js +6 -6
  25. package/dist/commands/knowledges/glob.js +6 -6
  26. package/dist/commands/knowledges/grep.js +6 -6
  27. package/dist/commands/knowledges/index.js +4 -4
  28. package/dist/commands/knowledges/index.js.map +1 -1
  29. package/dist/commands/knowledges/list.js +6 -6
  30. package/dist/commands/knowledges/read.js +6 -6
  31. package/dist/commands/knowledges/search.js +6 -6
  32. package/dist/commands/knowledges/status.js +6 -6
  33. package/dist/commands/login.js +5 -5
  34. package/dist/commands/login.js.map +1 -1
  35. package/dist/commands/scrub.js +7 -7
  36. package/dist/commands/scrub.js.map +1 -1
  37. package/dist/commands/transcripts.js +9 -9
  38. package/dist/commands/transcripts.js.map +1 -1
  39. package/package.json +6 -1
  40. package/dist/chunk-HUZZPV5E.js.map +0 -1
  41. package/dist/chunk-TZKXST4G.js.map +0 -1
  42. package/dist/chunk-XDXRVTPK.js +0 -18
  43. package/dist/chunk-XDXRVTPK.js.map +0 -1
  44. package/dist/chunk-Z4DDLEWR.js.map +0 -1
  45. /package/dist/{chunk-QEZQGKFX.js.map → chunk-CHSTTMTO.js.map} +0 -0
package/README.md CHANGED
@@ -1,130 +1,309 @@
1
1
  # cngkit
2
2
 
3
- Opinionated Curly.ng CLI kit for Coderoom collaboration, Harness knowledges, and website tooling.
3
+ [![npm version](https://img.shields.io/npm/v/cngkit.svg)](https://www.npmjs.com/package/cngkit)
4
+ [![Node.js >= 20](https://img.shields.io/badge/node-%3E%3D20-339933)](https://nodejs.org/)
5
+
6
+ Curly.ng's operator CLI for shared code rooms, safe local cleanup, local agent transcript
7
+ inspection, and terminal access to the hosted Harness knowledge catalog.
8
+
9
+ `cngkit` is built for developers and AI agents who need practical commands that work
10
+ well in terminals, scripts, and coding assistants. Human-facing status lines use Ink
11
+ styling when the terminal supports color. Data-heavy output stays plain and easy to pipe.
12
+
13
+ ## Quick Start
14
+
15
+ Run it without installing:
4
16
 
5
17
  ```bash
6
- npx cngkit
18
+ npx --yes cngkit@latest --help
7
19
  ```
8
20
 
9
- The CLI provides Coderoom collaboration, secret scrubbing, and a terminal front door to
10
- the Cloudflare-backed Harness knowledges catalog:
21
+ Or install it globally:
11
22
 
12
- - `cngkit login` opens Curly.ng login in a browser, or prints the URL in headless environments.
13
- - `cngkit coderoom share [room-code]` starts a live shared code room from the current directory.
14
- - `cngkit coderoom join <room-code>` joins another developer's shared code room.
15
- - `cngkit scrub [path]` scans a file or directory with TruffleHog and prints a redacted report.
16
- - `cngkit scrub [path] --yes` rewrites detected secret values inline with `[CNGKIT_SECRET:<detector>:<verified|unverified>]` placeholders.
17
- - `cngkit transcripts list [--source all|codex|claude] [--limit n]` lists recent local Claude/Codex transcript files.
18
- - `cngkit transcripts read <path-or-session-id> [--limit n]` prints normalized user/assistant transcript entries.
19
- - `cngkit transcripts grep <query> [--limit n] [--file-limit n]` searches recent local transcript entries.
20
- - `cngkit knowledges status` prints the remote catalog state.
21
- - `cngkit knowledges audiences` lists available audience filters.
22
- - `cngkit knowledges search <query> [--limit n]` runs semantic search against Cloudflare Vectorize (default limit 5).
23
- - `cngkit knowledges list [query] [--limit n]` lists known subskills (default limit 25).
24
- - `cngkit knowledges files [query] [--audience id] [--limit n]` lists uploaded catalog files (default limit 25).
25
- - `cngkit knowledges read <file-path> [--offset n] [--limit n]` reads a catalog file excerpt (default limit 200).
26
- - `cngkit knowledges grep <pattern> [--path path] [--include glob] [--output-mode content|files_with_matches|count] [--context n] [--case-insensitive]` searches catalog file contents (default mode `content`, default path `/`).
27
- - `cngkit knowledges glob [pattern] [--path path]` lists catalog files by supported glob pattern (default pattern `**/*.md`, default path `/`).
28
- - `.git/` and files ignored by the repo's `.gitignore` are not synced.
29
- - Later changes override earlier changes for the MVP conflict rule.
23
+ ```bash
24
+ npm install -g cngkit
25
+ cngkit --help
26
+ ```
30
27
 
31
- Help is baked into the CLI as Markdown with progressive disclosure:
28
+ Check the installed version:
32
29
 
33
30
  ```bash
34
- cngkit --help
35
- cngkit scrub --help
36
- cngkit transcripts --help
37
- cngkit knowledges --help
38
- cngkit knowledges read --help
39
- cngkit knowledges grep --help
40
- cngkit knowledges glob --help
31
+ cngkit --version
41
32
  ```
42
33
 
43
- Global options accepted by every command:
34
+ `cngkit` requires Node.js 20 or newer.
44
35
 
45
- - `--api-base-url <url>` overrides the Curly backend URL (default: `CNGKIT_API_BASE_URL` or `https://curly.ng`).
46
- - `--version` prints the installed `cngkit` version.
47
- - `--help` / `-h` prints the progressive help for the current command.
36
+ ## What It Does
48
37
 
49
- The canonical CLI spec lives at `docs/superpowers/specs/2026-06-25-cngkit-cli-spec.md`
50
- in the repository. The baked help source lives in `src/cli/help-specs.ts`; keep both
51
- aligned when changing command behavior.
38
+ ```bash
39
+ cngkit login
40
+ cngkit coderoom share
41
+ cngkit coderoom join <room-code>
42
+ cngkit scrub [path]
43
+ cngkit transcripts list --limit 12
44
+ cngkit knowledges search "cloudflare backend" --limit 3
45
+ cngkit knowledges read /libraries/lib-cloudflare/SUBSKILL.md --limit 80
46
+ ```
52
47
 
53
- Command routing is implemented with Pastel route files under `src/commands/`, rendered
54
- through the Ink runner in `src/cli/command-runner.tsx`. The route files are interface
55
- adapters only. Command behavior lives under `src/features/<feature>/`, and shared
56
- runtime concerns such as config, output, browser opening, and API client construction
57
- live under `src/shared/`. `tsup` emits a file-preserving ESM build so the published
58
- package contains `dist/cli.js` plus `dist/commands/**`; the private workspace client
59
- stays bundled while public runtime packages remain normal package dependencies.
48
+ The CLI currently has four main jobs:
60
49
 
61
- `scrub` requires the `trufflehog` binary on `PATH`. On macOS, install it with:
50
+ - **Coderoom**: start or join a live shared working-tree room.
51
+ - **Scrub**: scan local files for secrets and optionally mask them inline.
52
+ - **Transcripts**: inspect local Claude and Codex transcript files from the terminal.
53
+ - **Knowledges**: search and read the hosted Harness knowledge catalog.
54
+
55
+ ## Coderoom
56
+
57
+ Coderoom is a live room for quickly sharing a working tree with another developer or agent.
58
+ One machine starts a room, another joins with the room code, and the Curly backend relays
59
+ file changes.
60
+
61
+ Start a room:
62
+
63
+ ```bash
64
+ cngkit coderoom share
65
+ ```
66
+
67
+ Join a room:
68
+
69
+ ```bash
70
+ cngkit coderoom join <room-code>
71
+ ```
72
+
73
+ Use your own room code:
74
+
75
+ ```bash
76
+ cngkit coderoom share design-review-01
77
+ ```
78
+
79
+ Coderoom deliberately skips `.git/` and files ignored by `.gitignore`. It is a live relay,
80
+ not durable cloud storage or a backup system. The current conflict rule is simple: the latest
81
+ received change wins.
82
+
83
+ ## Harness Knowledges
84
+
85
+ The `knowledges` commands read the Cloudflare-backed Harness catalog from Curly.ng. They are
86
+ read-only and designed for AI-friendly terminal use.
87
+
88
+ Check catalog health:
89
+
90
+ ```bash
91
+ cngkit knowledges status
92
+ ```
93
+
94
+ Find relevant knowledge:
95
+
96
+ ```bash
97
+ cngkit knowledges search "cloudflare backend" --limit 3
98
+ ```
99
+
100
+ Read a catalog file:
101
+
102
+ ```bash
103
+ cngkit knowledges read /libraries/lib-cloudflare/SUBSKILL.md --limit 80
104
+ ```
105
+
106
+ List matching files:
107
+
108
+ ```bash
109
+ cngkit knowledges glob "**/*.md" --path /libraries/lib-cloudflare
110
+ ```
111
+
112
+ Search inside files:
113
+
114
+ ```bash
115
+ cngkit knowledges grep Cloudflare --path /libraries/lib-cloudflare --output-mode files_with_matches
116
+ ```
117
+
118
+ Return JSON for another tool:
119
+
120
+ ```bash
121
+ cngkit knowledges status --json
122
+ cngkit knowledges search "vector search" --limit 5 --json
123
+ ```
124
+
125
+ Catalog path shortcuts are supported. For example:
126
+
127
+ ```text
128
+ /libraries/lib-cloudflare/SUBSKILL.md
129
+ ```
130
+
131
+ maps to:
132
+
133
+ ```text
134
+ skills/knowledges/subskills/libraries/lib-cloudflare/SUBSKILL.md
135
+ ```
136
+
137
+ ## Secret Scrubbing
138
+
139
+ `scrub` scans a file or directory with TruffleHog and prints a redacted report.
140
+
141
+ ```bash
142
+ cngkit scrub .
143
+ ```
144
+
145
+ Inline masking rewrites files, so it is gated behind `--yes`:
146
+
147
+ ```bash
148
+ cngkit scrub . --yes
149
+ ```
150
+
151
+ Masked values use this format:
152
+
153
+ ```text
154
+ [CNGKIT_SECRET:<detector>:<verified|unverified>]
155
+ ```
156
+
157
+ `scrub` requires the `trufflehog` binary on `PATH`.
158
+
159
+ macOS install:
62
160
 
63
161
  ```bash
64
162
  brew install trufflehog
65
163
  ```
66
164
 
67
- Inline masking is intentionally gated behind `--yes` because it rewrites files in place.
165
+ Safety notes:
166
+
167
+ - The default mode is report-only.
168
+ - Raw secret values are never printed.
169
+ - `--mask` is accepted as a compatibility alias, but inline changes still require `--yes`.
68
170
 
69
171
  ## Local Agent Transcripts
70
172
 
71
- The `transcripts` command reads local JSONL logs from `~/.codex/sessions`,
72
- `~/.codex/archived_sessions`, `~/.claude/projects`, and `~/.claude/history.jsonl`.
73
- It is local-only operator tooling: transcript contents are not uploaded to the Curly backend.
173
+ `transcripts` reads local JSONL files from:
174
+
175
+ - `~/.codex/sessions`
176
+ - `~/.codex/archived_sessions`
177
+ - `~/.claude/projects`
178
+ - `~/.claude/history.jsonl`
179
+
180
+ List recent transcript files:
74
181
 
75
182
  ```bash
76
183
  cngkit transcripts list --limit 12
184
+ ```
185
+
186
+ Read a transcript by path or partial session id:
187
+
188
+ ```bash
77
189
  cngkit transcripts read <path-or-session-id> --source codex --limit 80
190
+ ```
191
+
192
+ Search recent transcript entries:
193
+
194
+ ```bash
78
195
  cngkit transcripts grep "deploy failed" --source all --file-limit 60 --limit 20
79
196
  ```
80
197
 
81
- By default, `read` and `grep` print only user/assistant text and skip internal prompt,
82
- hook, and tool noise. Use `--include-internal` when debugging transcript plumbing.
198
+ Transcript commands are local-only. They do not upload transcript content to Curly.ng.
199
+ By default, they print user and assistant text and skip internal prompt, hook, and tool noise.
200
+ Use `--include-internal` when debugging transcript plumbing.
83
201
 
84
- ## Coderoom
202
+ ## Backend Selection
85
203
 
86
- Coderoom is for quickly uniting developers around one working tree. One developer starts
87
- a room, another joins it, and the Curly backend relays file changes through the
88
- `/api/cng/sync/:roomCode` WebSocket room.
204
+ By default, `cngkit` talks to:
205
+
206
+ ```text
207
+ https://curly.ng
208
+ ```
209
+
210
+ Override the backend for one command:
89
211
 
90
212
  ```bash
91
- cngkit coderoom share
92
- cngkit coderoom join <room-code>
213
+ cngkit --api-base-url https://curly.ng knowledges status
93
214
  ```
94
215
 
95
- The frontend helper lives at `/coderoom`. It presents Coderoom as a Drive-like
96
- shared workspace: a room code acts like a share link, connected machines act like
97
- collaborators, and file events act like the activity stream. Current Coderoom
98
- rooms are live relays, not durable cloud storage.
216
+ Or with an environment variable:
99
217
 
100
- ## Harness Knowledges
218
+ ```bash
219
+ CNGKIT_API_BASE_URL=https://curly.ng cngkit knowledges status
220
+ ```
221
+
222
+ ## Help
101
223
 
102
- The `knowledges` command group reads the Cloudflare-backed Harness catalog from the
103
- Curly API. These commands are read-only:
224
+ Help is baked into the CLI as Markdown:
104
225
 
105
226
  ```bash
106
- cngkit knowledges status
107
- cngkit knowledges audiences
108
- cngkit knowledges search "cloudflare backend" --limit 3
109
- cngkit knowledges files "vector search" --audience builders
110
- cngkit knowledges read /libraries/lib-cloudflare/SUBSKILL.md --limit 80
111
- cngkit knowledges grep Cloudflare --path /libraries/lib-cloudflare --output-mode files_with_matches
112
- cngkit knowledges glob "**/*.md" --path /libraries/lib-cloudflare
227
+ cngkit --help
228
+ cngkit help
229
+ cngkit help knowledges
230
+ cngkit coderoom --help
231
+ cngkit knowledges read --help
232
+ cngkit transcripts --help
233
+ ```
234
+
235
+ Help uses terminal Markdown rendering in interactive terminals. Status, warnings, and errors
236
+ use Ink color when the terminal supports it, but `--json`, file reads, glob results, grep
237
+ results, and piped output stay clean.
238
+
239
+ ## Terminal UI Stack
240
+
241
+ `cngkit` uses the Ink family without adding a custom command framework:
242
+
243
+ - **Pastel** owns command and subcommand routing through files under `src/commands/`.
244
+ - **Ink** owns terminal rendering through built-in components such as `<Text>`.
245
+ - **marked-terminal** owns terminal Markdown rendering for help screens.
246
+ - **Zod** owns option and argument schemas for each route.
247
+
248
+ So yes, subcommands are built in through Pastel's nested route files. Adding a
249
+ subcommand is normally a new `.tsx` file under the matching command folder:
250
+
251
+ ```text
252
+ src/commands/
253
+ coderoom/
254
+ share.tsx cngkit coderoom share
255
+ join.tsx cngkit coderoom join
256
+ knowledges/
257
+ read.tsx cngkit knowledges read
258
+ grep.tsx cngkit knowledges grep
259
+ glob.tsx cngkit knowledges glob
113
260
  ```
114
261
 
115
- Add `--json` to any `knowledges` command when another tool should consume the
116
- raw API response. `grep` also accepts `--output-mode <content|files_with_matches|count>`
117
- (default `content`), `--include <glob>` (default `*`), `--context <n>` (default `0`), and
118
- `--case-insensitive`. Result limits default to `5` for `search` and `25` for `list` and
119
- `files`; `read` defaults to `200` lines with a backend cap of `2000`, and accepts `--offset`
120
- for paging.
262
+ The CLI does not hand-roll ANSI escape codes. Status styles go through Ink's built-in
263
+ `<Text color="..." bold dimColor>` support, and help screens use a shared Chalk-backed
264
+ Markdown theme through `marked-terminal`. Commands that return content for agents or shell
265
+ pipelines write raw lines instead.
266
+
267
+ ## For Contributors
268
+
269
+ The package source lives in `apps/cng`.
270
+
271
+ ```text
272
+ src/
273
+ cli/ Pastel bootstrap support, help text, option schemas, Ink output runner
274
+ commands/ Thin Pastel route files
275
+ features/ Command behavior grouped by feature
276
+ shared/ Config, output, browser, API client, shared command utilities
277
+ ```
278
+
279
+ The route files under `src/commands/` should stay thin. Put behavior in
280
+ `src/features/<feature>/`, and put cross-feature runtime helpers in `src/shared/`.
281
+ For output, use the shared `CommandOutput` methods:
282
+
283
+ - `success`, `warning`, `info`, `muted`, and `error` for human-facing terminal status.
284
+ - `markdown` for help screens and terminal-only Markdown display.
285
+ - `raw` for JSON, file content, file paths, grep results, and anything another tool may parse.
286
+
287
+ Useful local checks:
288
+
289
+ ```bash
290
+ pnpm --filter cngkit run typecheck
291
+ pnpm --filter cngkit run lint
292
+ pnpm --filter cngkit run build
293
+ pnpm --filter cngkit run smoke
294
+ ```
295
+
296
+ Release and install the newest npm package on the current machine:
297
+
298
+ ```bash
299
+ pnpm --filter cngkit run deploy
300
+ ```
121
301
 
122
- `read` and `grep` accept shorthand catalog paths: `/libraries/lib-cloudflare/SUBSKILL.md`
123
- expands to `skills/knowledges/subskills/libraries/lib-cloudflare/SUBSKILL.md`, mirroring the
124
- Claude `read`/`grep` tool convention.
302
+ That command runs typecheck, lint, build, smoke, npm pack dry-run, npm publish, registry
303
+ verification, `npm install -g cngkit@latest`, and a final global `cngkit --version` check.
125
304
 
126
- This package is mostly personal tooling for Curly.ng. It is intentionally opinionated,
127
- small, and practical rather than a general synchronization platform.
305
+ The package build uses `tsup` to emit a file-preserving ESM build. The published binary is
306
+ `dist/cli.js`, and Pastel discovers command files under `dist/commands/**`.
128
307
 
129
308
  ## License
130
309
 
@@ -1,7 +1,7 @@
1
1
  // src/shared/config.ts
2
2
  import { randomBytes, randomUUID } from "crypto";
3
3
  import process from "process";
4
- var packageVersion = "1.1.7";
4
+ var packageVersion = "1.1.9";
5
5
  var defaultApiBaseUrl = "https://curly.ng";
6
6
  function resolveApiBaseUrl(options) {
7
7
  return options.apiBaseUrl ?? process.env.CNGKIT_API_BASE_URL ?? defaultApiBaseUrl;
@@ -19,4 +19,4 @@ export {
19
19
  createRoomCode,
20
20
  createPeerId
21
21
  };
22
- //# sourceMappingURL=chunk-EQEIX7N5.js.map
22
+ //# sourceMappingURL=chunk-575IBOIA.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/shared/config.ts"],"sourcesContent":["import { randomBytes, randomUUID } from \"node:crypto\";\nimport process from \"node:process\";\n\nexport const packageVersion = \"1.1.7\";\nexport const defaultApiBaseUrl = \"https://curly.ng\";\n\nexport type GlobalCommandOptions = {\n apiBaseUrl?: string;\n};\n\nexport function resolveApiBaseUrl(options: GlobalCommandOptions): string {\n return options.apiBaseUrl ?? process.env.CNGKIT_API_BASE_URL ?? defaultApiBaseUrl;\n}\n\nexport function createRoomCode(): string {\n return randomBytes(4).toString(\"hex\").toUpperCase();\n}\n\nexport function createPeerId(): string {\n return randomUUID();\n}\n"],"mappings":";AAAA,SAAS,aAAa,kBAAkB;AACxC,OAAO,aAAa;AAEb,IAAM,iBAAiB;AACvB,IAAM,oBAAoB;AAM1B,SAAS,kBAAkB,SAAuC;AACvE,SAAO,QAAQ,cAAc,QAAQ,IAAI,uBAAuB;AAClE;AAEO,SAAS,iBAAyB;AACvC,SAAO,YAAY,CAAC,EAAE,SAAS,KAAK,EAAE,YAAY;AACpD;AAEO,SAAS,eAAuB;AACrC,SAAO,WAAW;AACpB;","names":[]}
1
+ {"version":3,"sources":["../src/shared/config.ts"],"sourcesContent":["import { randomBytes, randomUUID } from \"node:crypto\";\nimport process from \"node:process\";\n\nexport const packageVersion = \"1.1.9\";\nexport const defaultApiBaseUrl = \"https://curly.ng\";\n\nexport type GlobalCommandOptions = {\n apiBaseUrl?: string;\n};\n\nexport function resolveApiBaseUrl(options: GlobalCommandOptions): string {\n return options.apiBaseUrl ?? process.env.CNGKIT_API_BASE_URL ?? defaultApiBaseUrl;\n}\n\nexport function createRoomCode(): string {\n return randomBytes(4).toString(\"hex\").toUpperCase();\n}\n\nexport function createPeerId(): string {\n return randomUUID();\n}\n"],"mappings":";AAAA,SAAS,aAAa,kBAAkB;AACxC,OAAO,aAAa;AAEb,IAAM,iBAAiB;AACvB,IAAM,oBAAoB;AAM1B,SAAS,kBAAkB,SAAuC;AACvE,SAAO,QAAQ,cAAc,QAAQ,IAAI,uBAAuB;AAClE;AAEO,SAAS,iBAAyB;AACvC,SAAO,YAAY,CAAC,EAAE,SAAS,KAAK,EAAE,YAAY;AACpD;AAEO,SAAS,eAAuB;AACrC,SAAO,WAAW;AACpB;","names":[]}
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  resolveApiBaseUrl
3
- } from "./chunk-EQEIX7N5.js";
3
+ } from "./chunk-575IBOIA.js";
4
4
  import {
5
5
  __export
6
6
  } from "./chunk-PZ5AY32C.js";
@@ -3231,4 +3231,4 @@ export {
3231
3231
  createCngApiClient,
3232
3232
  readBackendHealth
3233
3233
  };
3234
- //# sourceMappingURL=chunk-QEZQGKFX.js.map
3234
+ //# sourceMappingURL=chunk-CHSTTMTO.js.map
@@ -6,7 +6,7 @@ import {
6
6
  } from "./chunk-QZEB4VMX.js";
7
7
  import {
8
8
  createCngApiClient
9
- } from "./chunk-QEZQGKFX.js";
9
+ } from "./chunk-CHSTTMTO.js";
10
10
 
11
11
  // src/features/knowledges/knowledges-api.ts
12
12
  function createKnowledgesApi(options) {
@@ -110,7 +110,7 @@ async function runKnowStatusCommand(options, output, dependencies) {
110
110
  const api = dependencies?.api ?? createKnowledgesApi(options);
111
111
  const response = await api.getCatalog();
112
112
  if (options.json) {
113
- output.info(formatJson(response.data));
113
+ output.raw(formatJson(response.data));
114
114
  return;
115
115
  }
116
116
  const latestRun = response.data.latestRun;
@@ -134,7 +134,7 @@ async function runKnowAudiencesCommand(options, output, dependencies) {
134
134
  const api = dependencies?.api ?? createKnowledgesApi(options);
135
135
  const response = await api.listAudiences();
136
136
  if (options.json) {
137
- output.info(formatJson(response.data));
137
+ output.raw(formatJson(response.data));
138
138
  return;
139
139
  }
140
140
  const lines = response.data.audiences.flatMap((audience) => [
@@ -150,7 +150,7 @@ async function runKnowSearchCommand(query, options, output, dependencies) {
150
150
  const api = dependencies?.api ?? createKnowledgesApi(options);
151
151
  const response = await api.search(query, coerceLimit(options.limit, 5));
152
152
  if (options.json) {
153
- output.info(formatJson(response.data));
153
+ output.raw(formatJson(response.data));
154
154
  return;
155
155
  }
156
156
  const lines = response.data.results.flatMap((result, index) => [
@@ -158,7 +158,11 @@ async function runKnowSearchCommand(query, options, output, dependencies) {
158
158
  ` score ${result.score.toFixed(3)} | ${result.path}`,
159
159
  ` ${singleLine(result.description || result.contentPreview)}`
160
160
  ]);
161
- output.info(lines.length > 0 ? lines.join("\n") : `No results for "${query}".`);
161
+ if (lines.length > 0) {
162
+ output.info(lines.join("\n"));
163
+ return;
164
+ }
165
+ output.warning(`No results for "${query}".`);
162
166
  }
163
167
  async function runKnowListCommand(query, options, output, dependencies) {
164
168
  const api = dependencies?.api ?? createKnowledgesApi(options);
@@ -172,7 +176,7 @@ async function runKnowListCommand(query, options, output, dependencies) {
172
176
  return [subskill.name, subskill.title, subskill.description, subskill.type].join(" ").toLowerCase().includes(normalizedQuery);
173
177
  }).slice(0, limit);
174
178
  if (options.json) {
175
- output.info(formatJson({ subskills, total: subskills.length }));
179
+ output.raw(formatJson({ subskills, total: subskills.length }));
176
180
  return;
177
181
  }
178
182
  const lines = subskills.flatMap((subskill) => [
@@ -180,7 +184,11 @@ async function runKnowListCommand(query, options, output, dependencies) {
180
184
  ` ${subskill.title} | files ${subskill.fileCount} | rating ${subskill.rating}`,
181
185
  ` ${singleLine(subskill.description)}`
182
186
  ]);
183
- output.info(lines.length > 0 ? lines.join("\n") : "No matching subskills.");
187
+ if (lines.length > 0) {
188
+ output.info(lines.join("\n"));
189
+ return;
190
+ }
191
+ output.warning("No matching subskills.");
184
192
  }
185
193
  async function runKnowFilesCommand(query, options, output, dependencies) {
186
194
  const api = dependencies?.api ?? createKnowledgesApi(options);
@@ -190,7 +198,7 @@ async function runKnowFilesCommand(query, options, output, dependencies) {
190
198
  limit: coerceLimit(options.limit, 25)
191
199
  });
192
200
  if (options.json) {
193
- output.info(formatJson(response.data));
201
+ output.raw(formatJson(response.data));
194
202
  return;
195
203
  }
196
204
  const lines = response.data.files.map((file) => {
@@ -198,7 +206,11 @@ async function runKnowFilesCommand(query, options, output, dependencies) {
198
206
  return `${file.path}
199
207
  ${title}`;
200
208
  });
201
- output.info(lines.length > 0 ? lines.join("\n") : "No matching files.");
209
+ if (lines.length > 0) {
210
+ output.info(lines.join("\n"));
211
+ return;
212
+ }
213
+ output.warning("No matching files.");
202
214
  }
203
215
  async function runKnowReadCommand(filePath, options, output, dependencies) {
204
216
  if (!filePath) {
@@ -211,12 +223,12 @@ async function runKnowReadCommand(filePath, options, output, dependencies) {
211
223
  limit: coerceLimit(options.limit, 200, 2e3)
212
224
  });
213
225
  if (options.json) {
214
- output.info(formatJson(response.data));
226
+ output.raw(formatJson(response.data));
215
227
  return;
216
228
  }
217
- output.info(response.data.content);
229
+ output.raw(response.data.content);
218
230
  if (response.data.truncated) {
219
- output.info(
231
+ output.warning(
220
232
  `[truncated: showing ${response.data.limit} lines from offset ${response.data.offset} of ${response.data.total_lines}]`
221
233
  );
222
234
  }
@@ -236,18 +248,26 @@ async function runKnowGrepCommand(pattern, options, output, dependencies) {
236
248
  ignoreCase: options.caseInsensitive === true
237
249
  });
238
250
  if (options.json) {
239
- output.info(formatJson(response.data));
251
+ output.raw(formatJson(response.data));
240
252
  return;
241
253
  }
242
254
  if (response.data.mode === "files_with_matches") {
243
255
  const files = limit ? response.data.files.slice(0, limit) : response.data.files;
244
- output.info(files.length > 0 ? files.join("\n") : `No files matched "${pattern}".`);
256
+ if (files.length > 0) {
257
+ output.raw(files.join("\n"));
258
+ return;
259
+ }
260
+ output.warning(`No files matched "${pattern}".`);
245
261
  return;
246
262
  }
247
263
  if (response.data.mode === "count") {
248
264
  const counts = limit ? response.data.counts.slice(0, limit) : response.data.counts;
249
265
  const lines2 = counts.map((count) => `${count.file_path}: ${count.match_count}`);
250
- output.info(lines2.length > 0 ? lines2.join("\n") : `No matches for "${pattern}".`);
266
+ if (lines2.length > 0) {
267
+ output.raw(lines2.join("\n"));
268
+ return;
269
+ }
270
+ output.warning(`No matches for "${pattern}".`);
251
271
  return;
252
272
  }
253
273
  const matches = limit ? response.data.matches.slice(0, limit) : response.data.matches;
@@ -257,7 +277,11 @@ async function runKnowGrepCommand(pattern, options, output, dependencies) {
257
277
  `> ${match.line}`,
258
278
  ...match.context_after.map((line) => ` ${line}`)
259
279
  ]);
260
- output.info(lines.length > 0 ? lines.join("\n") : `No matches for "${pattern}".`);
280
+ if (lines.length > 0) {
281
+ output.raw(lines.join("\n"));
282
+ return;
283
+ }
284
+ output.warning(`No matches for "${pattern}".`);
261
285
  }
262
286
  async function runKnowGlobCommand(pattern, options, output, dependencies) {
263
287
  const api = dependencies?.api ?? createKnowledgesApi(options);
@@ -267,14 +291,18 @@ async function runKnowGlobCommand(pattern, options, output, dependencies) {
267
291
  path: normalizeCatalogPath(options.path ?? "/")
268
292
  });
269
293
  if (options.json) {
270
- output.info(formatJson(response.data));
294
+ output.raw(formatJson(response.data));
271
295
  return;
272
296
  }
273
297
  const files = limit ? response.data.files.slice(0, limit) : response.data.files;
274
298
  const wasClientTruncated = limit ? response.data.files.length > limit : false;
275
- output.info(files.length > 0 ? files.join("\n") : "No matching files.");
299
+ if (files.length > 0) {
300
+ output.raw(files.join("\n"));
301
+ } else {
302
+ output.warning("No matching files.");
303
+ }
276
304
  if (response.data.truncated || wasClientTruncated) {
277
- output.info(`[truncated: ${response.data.total_files} total files]`);
305
+ output.warning(`[truncated: ${response.data.total_files} total files]`);
278
306
  }
279
307
  }
280
308
 
@@ -288,4 +316,4 @@ export {
288
316
  runKnowGrepCommand,
289
317
  runKnowGlobCommand
290
318
  };
291
- //# sourceMappingURL=chunk-TZKXST4G.js.map
319
+ //# sourceMappingURL=chunk-LWZPSJVC.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/features/knowledges/knowledges-api.ts","../src/features/knowledges/knowledges-input.ts","../src/features/knowledges/run-knowledges-command.ts"],"sourcesContent":["import type { CngApi } from \"@cng/client\";\n\nimport { createCngApiClient } from \"../../shared/api-client.js\";\nimport type { GlobalCommandOptions } from \"../../shared/config.js\";\n\nexport type KnowCommandDependencies = {\n api?: KnowledgesApi;\n};\n\nexport type KnowledgesApi = {\n getCatalog(): Promise<CngApi.HarnessCatalogSummaryApiResponse>;\n listAudiences(): Promise<CngApi.HarnessAudiencesApiResponse>;\n search(query: string, limit: number): Promise<CngApi.HarnessSemanticSearchApiResponse>;\n listSubskills(): Promise<CngApi.HarnessSubskillsApiResponse>;\n listFiles(options: {\n query?: string;\n audience?: CngApi.HarnessAudienceId;\n limit: number;\n }): Promise<CngApi.HarnessSubskillAssetsApiResponse>;\n read(options: {\n filePath: string;\n offset?: number;\n limit: number;\n }): Promise<CngApi.HarnessReadApiResponse>;\n grep(options: {\n pattern: string;\n path: string;\n include: string;\n mode: CngApi.HarnessGrepOutputMode;\n context: number;\n ignoreCase: boolean;\n }): Promise<CngApi.HarnessGrepApiResponse>;\n glob(options: { pattern: string; path: string }): Promise<CngApi.HarnessGlobApiResponse>;\n};\n\nexport function createKnowledgesApi(options: GlobalCommandOptions): KnowledgesApi {\n const client = createCngApiClient(options);\n\n return {\n getCatalog: () => client.harnessKnowledges.getHarnessKnowledgesCatalog(),\n listAudiences: () => client.harnessKnowledges.listHarnessKnowledgesAudiences(),\n search: (query, limit) =>\n client.harnessKnowledges.searchHarnessKnowledges({\n q: query,\n limit,\n }),\n listSubskills: () => client.harnessKnowledges.listHarnessKnowledgesSubskills(),\n listFiles: ({ query, audience, limit }) =>\n client.harnessKnowledges.listHarnessSubskillAssets({\n ...(query ? { q: query } : {}),\n ...(audience ? { audience } : {}),\n limit,\n }),\n read: ({ filePath, offset, limit }) =>\n client.harnessFilesystem.getHarnessFilesystemRead({\n file_path: filePath,\n offset,\n limit,\n }),\n grep: ({ pattern, path, include, mode, context, ignoreCase }) =>\n client.harnessFilesystem.getHarnessFilesystemGrep({\n pattern,\n path,\n include,\n output_mode: mode,\n context,\n case_insensitive: ignoreCase ? \"true\" : undefined,\n }),\n glob: ({ pattern, path }) =>\n client.harnessFilesystem.getHarnessFilesystemGlob({\n pattern,\n path,\n }),\n };\n}\n","import type { CngApi } from \"@cng/client\";\n\nexport function normalizeAudienceId(value: string | undefined): CngApi.HarnessAudienceId | undefined {\n if (value === undefined) {\n return undefined;\n }\n\n switch (value) {\n case \"all\":\n case \"operators\":\n case \"builders\":\n case \"researchers\":\n case \"agent-makers\":\n return value;\n default:\n throw new Error(\n `Unknown audience \"${value}\". Run cngkit knowledges audiences to see supported values.`\n );\n }\n}\n\nexport function normalizeCatalogPath(value: string): string {\n const trimmed = value.trim();\n if (trimmed === \"/\" || trimmed === \"\") {\n return \"skills\";\n }\n\n const relativePath = trimmed.replace(/^\\/+/, \"\");\n if (relativePath.startsWith(\"skills/knowledges/\")) {\n return relativePath;\n }\n\n const [firstSegment, ...restSegments] = relativePath.split(\"/\");\n if (!firstSegment) {\n return relativePath;\n }\n\n switch (firstSegment) {\n case \"concepts\":\n case \"domains\":\n case \"formats\":\n case \"languages\":\n case \"libraries\":\n case \"patterns\":\n case \"platforms\":\n case \"procedures\":\n case \"protocols\":\n case \"tools\":\n return `skills/knowledges/subskills/${firstSegment}${restSegments.length > 0 ? `/${restSegments.join(\"/\")}` : \"\"}`;\n default:\n return relativePath;\n }\n}\n\nexport function normalizeGrepMode(value: string | undefined): CngApi.HarnessGrepOutputMode {\n if (value === undefined) {\n return \"content\";\n }\n\n switch (value) {\n case \"content\":\n case \"files_with_matches\":\n case \"count\":\n return value;\n default:\n throw new Error(\"Unknown grep mode. Use one of: content, files_with_matches, count.\");\n }\n}\n","import { formatKnowledgesHelp } from \"../../cli/help-specs.js\";\nimport {\n coerceLimit,\n coerceOptionalNumber,\n formatJson,\n optionalJoinedArgument,\n singleLine,\n type JsonOutputOptions,\n type NumberOption,\n} from \"../../shared/command-utils.js\";\nimport type { GlobalCommandOptions } from \"../../shared/config.js\";\nimport type { CommandOutput } from \"../../shared/output.js\";\nimport { createKnowledgesApi, type KnowCommandDependencies } from \"./knowledges-api.js\";\nimport { normalizeAudienceId, normalizeCatalogPath, normalizeGrepMode } from \"./knowledges-input.js\";\n\nexport type KnowStatusCommandOptions = GlobalCommandOptions & JsonOutputOptions;\n\nexport type KnowAudiencesCommandOptions = GlobalCommandOptions & JsonOutputOptions;\n\nexport type KnowSearchCommandOptions = GlobalCommandOptions &\n JsonOutputOptions & {\n limit?: NumberOption;\n };\n\nexport type KnowListCommandOptions = GlobalCommandOptions &\n JsonOutputOptions & {\n limit?: NumberOption;\n };\n\nexport type KnowFilesCommandOptions = GlobalCommandOptions &\n JsonOutputOptions & {\n audience?: string;\n limit?: NumberOption;\n };\n\nexport type KnowReadCommandOptions = GlobalCommandOptions &\n JsonOutputOptions & {\n offset?: NumberOption;\n limit?: NumberOption;\n };\n\nexport type KnowGrepCommandOptions = GlobalCommandOptions &\n JsonOutputOptions & {\n path?: string;\n include?: string;\n outputMode?: string;\n context?: NumberOption;\n caseInsensitive?: boolean;\n limit?: NumberOption;\n };\n\nexport type KnowGlobCommandOptions = GlobalCommandOptions &\n JsonOutputOptions & {\n path?: string;\n limit?: NumberOption;\n };\n\nexport type KnowledgesCliOptions = KnowFilesCommandOptions &\n KnowGlobCommandOptions &\n KnowGrepCommandOptions &\n KnowReadCommandOptions &\n KnowSearchCommandOptions;\n\nexport async function runKnowledgesCommand(\n args: string[] | undefined,\n options: KnowledgesCliOptions,\n output: CommandOutput,\n dependencies?: KnowCommandDependencies\n): Promise<void> {\n const [subcommand, ...subcommandArgs] = args ?? [];\n\n if (subcommand === undefined || subcommand === \"help\") {\n output.markdown(formatKnowledgesHelp(subcommandArgs[0]));\n return;\n }\n\n switch (subcommand) {\n case \"status\":\n return runKnowStatusCommand(options, output, dependencies);\n case \"audiences\":\n return runKnowAudiencesCommand(options, output, dependencies);\n case \"search\":\n return runKnowSearchCommand(optionalJoinedArgument(subcommandArgs), options, output, dependencies);\n case \"list\":\n return runKnowListCommand(optionalJoinedArgument(subcommandArgs), options, output, dependencies);\n case \"files\":\n return runKnowFilesCommand(optionalJoinedArgument(subcommandArgs), options, output, dependencies);\n case \"read\":\n return runKnowReadCommand(subcommandArgs[0], options, output, dependencies);\n case \"grep\":\n return runKnowGrepCommand(optionalJoinedArgument(subcommandArgs), options, output, dependencies);\n case \"glob\":\n return runKnowGlobCommand(optionalJoinedArgument(subcommandArgs), options, output, dependencies);\n default:\n throw new Error(\n \"Missing knowledges command. Usage: cngkit knowledges <status|audiences|search|list|files|read|grep|glob>\"\n );\n }\n}\n\nexport async function runKnowStatusCommand(\n options: KnowStatusCommandOptions,\n output: CommandOutput,\n dependencies?: KnowCommandDependencies\n): Promise<void> {\n const api = dependencies?.api ?? createKnowledgesApi(options);\n const response = await api.getCatalog();\n\n if (options.json) {\n output.raw(formatJson(response.data));\n return;\n }\n\n const latestRun = response.data.latestRun;\n const lines = [\n `Catalog: ${response.data.name}`,\n `Files: ${response.data.files}`,\n `Blobs: ${response.data.blobs}`,\n `Vectorize: ${response.data.vectorize.index} (${response.data.vectorize.binding})`,\n ];\n\n if (latestRun) {\n lines.push(`Latest run: ${latestRun.status} (${latestRun.id})`);\n if (latestRun.updated_at) {\n lines.push(`Updated: ${latestRun.updated_at}`);\n }\n } else {\n lines.push(\"Latest run: none\");\n }\n\n output.info(lines.join(\"\\n\"));\n}\n\nexport async function runKnowAudiencesCommand(\n options: KnowAudiencesCommandOptions,\n output: CommandOutput,\n dependencies?: KnowCommandDependencies\n): Promise<void> {\n const api = dependencies?.api ?? createKnowledgesApi(options);\n const response = await api.listAudiences();\n\n if (options.json) {\n output.raw(formatJson(response.data));\n return;\n }\n\n const lines = response.data.audiences.flatMap((audience) => [\n `${audience.id} - ${audience.label}`,\n ` ${singleLine(audience.help)}`,\n ]);\n\n output.info(lines.length > 0 ? lines.join(\"\\n\") : \"No audiences available.\");\n}\n\nexport async function runKnowSearchCommand(\n query: string | undefined,\n options: KnowSearchCommandOptions,\n output: CommandOutput,\n dependencies?: KnowCommandDependencies\n): Promise<void> {\n if (!query) {\n throw new Error(\"Missing search query. Usage: cngkit knowledges search <query>\");\n }\n\n const api = dependencies?.api ?? createKnowledgesApi(options);\n const response = await api.search(query, coerceLimit(options.limit, 5));\n\n if (options.json) {\n output.raw(formatJson(response.data));\n return;\n }\n\n const lines = response.data.results.flatMap((result, index) => [\n `${index + 1}. ${result.title} (${result.subskillName})`,\n ` score ${result.score.toFixed(3)} | ${result.path}`,\n ` ${singleLine(result.description || result.contentPreview)}`,\n ]);\n\n if (lines.length > 0) {\n output.info(lines.join(\"\\n\"));\n return;\n }\n\n output.warning(`No results for \"${query}\".`);\n}\n\nexport async function runKnowListCommand(\n query: string | undefined,\n options: KnowListCommandOptions,\n output: CommandOutput,\n dependencies?: KnowCommandDependencies\n): Promise<void> {\n const api = dependencies?.api ?? createKnowledgesApi(options);\n const response = await api.listSubskills();\n const limit = coerceLimit(options.limit, 25);\n const normalizedQuery = query?.toLowerCase();\n const subskills = response.data.subskills\n .filter((subskill) => {\n if (!normalizedQuery) {\n return true;\n }\n return [subskill.name, subskill.title, subskill.description, subskill.type]\n .join(\" \")\n .toLowerCase()\n .includes(normalizedQuery);\n })\n .slice(0, limit);\n\n if (options.json) {\n output.raw(formatJson({ subskills, total: subskills.length }));\n return;\n }\n\n const lines = subskills.flatMap((subskill) => [\n `${subskill.name} [${subskill.type}]`,\n ` ${subskill.title} | files ${subskill.fileCount} | rating ${subskill.rating}`,\n ` ${singleLine(subskill.description)}`,\n ]);\n\n if (lines.length > 0) {\n output.info(lines.join(\"\\n\"));\n return;\n }\n\n output.warning(\"No matching subskills.\");\n}\n\nexport async function runKnowFilesCommand(\n query: string | undefined,\n options: KnowFilesCommandOptions,\n output: CommandOutput,\n dependencies?: KnowCommandDependencies\n): Promise<void> {\n const api = dependencies?.api ?? createKnowledgesApi(options);\n const response = await api.listFiles({\n query,\n audience: normalizeAudienceId(options.audience),\n limit: coerceLimit(options.limit, 25),\n });\n\n if (options.json) {\n output.raw(formatJson(response.data));\n return;\n }\n\n const lines = response.data.files.map((file) => {\n const title = file.display_title ?? file.title ?? file.subskill_name ?? \"Untitled\";\n return `${file.path}\\n ${title}`;\n });\n\n if (lines.length > 0) {\n output.info(lines.join(\"\\n\"));\n return;\n }\n\n output.warning(\"No matching files.\");\n}\n\nexport async function runKnowReadCommand(\n filePath: string | undefined,\n options: KnowReadCommandOptions,\n output: CommandOutput,\n dependencies?: KnowCommandDependencies\n): Promise<void> {\n if (!filePath) {\n throw new Error(\"Missing file_path. Usage: cngkit knowledges read <file_path>\");\n }\n\n const api = dependencies?.api ?? createKnowledgesApi(options);\n const response = await api.read({\n filePath: normalizeCatalogPath(filePath),\n offset: coerceOptionalNumber(options.offset),\n limit: coerceLimit(options.limit, 200, 2000),\n });\n\n if (options.json) {\n output.raw(formatJson(response.data));\n return;\n }\n\n output.raw(response.data.content);\n if (response.data.truncated) {\n output.warning(\n `[truncated: showing ${response.data.limit} lines from offset ${response.data.offset} of ${response.data.total_lines}]`\n );\n }\n}\n\nexport async function runKnowGrepCommand(\n pattern: string | undefined,\n options: KnowGrepCommandOptions,\n output: CommandOutput,\n dependencies?: KnowCommandDependencies\n): Promise<void> {\n if (!pattern) {\n throw new Error(\"Missing pattern. Usage: cngkit knowledges grep <pattern>\");\n }\n\n const api = dependencies?.api ?? createKnowledgesApi(options);\n const limit = options.limit !== undefined ? coerceOptionalNumber(options.limit) : undefined;\n const response = await api.grep({\n pattern,\n path: normalizeCatalogPath(options.path ?? \"/\"),\n include: options.include ?? \"*\",\n mode: normalizeGrepMode(options.outputMode),\n context: coerceLimit(options.context, 0, 20),\n ignoreCase: options.caseInsensitive === true,\n });\n\n if (options.json) {\n output.raw(formatJson(response.data));\n return;\n }\n\n if (response.data.mode === \"files_with_matches\") {\n const files = limit ? response.data.files.slice(0, limit) : response.data.files;\n if (files.length > 0) {\n output.raw(files.join(\"\\n\"));\n return;\n }\n\n output.warning(`No files matched \"${pattern}\".`);\n return;\n }\n\n if (response.data.mode === \"count\") {\n const counts = limit ? response.data.counts.slice(0, limit) : response.data.counts;\n const lines = counts.map((count) => `${count.file_path}: ${count.match_count}`);\n if (lines.length > 0) {\n output.raw(lines.join(\"\\n\"));\n return;\n }\n\n output.warning(`No matches for \"${pattern}\".`);\n return;\n }\n\n const matches = limit ? response.data.matches.slice(0, limit) : response.data.matches;\n const lines = matches.flatMap((match) => [\n `${match.file_path}:${match.line_number}`,\n ...match.context_before.map((line) => ` ${line}`),\n `> ${match.line}`,\n ...match.context_after.map((line) => ` ${line}`),\n ]);\n\n if (lines.length > 0) {\n output.raw(lines.join(\"\\n\"));\n return;\n }\n\n output.warning(`No matches for \"${pattern}\".`);\n}\n\nexport async function runKnowGlobCommand(\n pattern: string | undefined,\n options: KnowGlobCommandOptions,\n output: CommandOutput,\n dependencies?: KnowCommandDependencies\n): Promise<void> {\n const api = dependencies?.api ?? createKnowledgesApi(options);\n const limit = options.limit !== undefined ? coerceOptionalNumber(options.limit) : undefined;\n const response = await api.glob({\n pattern: pattern ?? \"**/*.md\",\n path: normalizeCatalogPath(options.path ?? \"/\"),\n });\n\n if (options.json) {\n output.raw(formatJson(response.data));\n return;\n }\n\n const files = limit ? response.data.files.slice(0, limit) : response.data.files;\n const wasClientTruncated = limit ? response.data.files.length > limit : false;\n\n if (files.length > 0) {\n output.raw(files.join(\"\\n\"));\n } else {\n output.warning(\"No matching files.\");\n }\n if (response.data.truncated || wasClientTruncated) {\n output.warning(`[truncated: ${response.data.total_files} total files]`);\n }\n}\n"],"mappings":"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","names":["lines"]}