cngkit 1.1.1 → 1.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE CHANGED
@@ -4,4 +4,4 @@ This software is provided as personal, opinionated Curly.ng tooling.
4
4
 
5
5
  You can use it, modify it, and share it. If it helps you, support the workshop.
6
6
 
7
- Support: https://curly.ng/donate
7
+ Support: https://curly.ng/support
package/README.md CHANGED
@@ -1,30 +1,51 @@
1
1
  # cngkit
2
2
 
3
- Opinionated Curly.ng CLI kit for repo sync, Harness knowledges, and website tooling.
3
+ Opinionated Curly.ng CLI kit for Coderoom collaboration, Harness knowledges, and website tooling.
4
4
 
5
5
  ```bash
6
6
  npx cngkit
7
7
  ```
8
8
 
9
- The CLI provides a real-time repository sync room and a terminal front door to
9
+ The CLI provides Coderoom collaboration, secret scrubbing, and a terminal front door to
10
10
  the Cloudflare-backed Harness knowledges catalog:
11
11
 
12
- - `cngkit share` starts a room from the current directory.
13
- - `cngkit join <room-code>` joins another machine to that room.
14
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
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` placeholders.
16
+ - `cngkit scrub [path] --yes` rewrites detected secret values inline with `[CNGKIT_SECRET:<detector>:<verified|unverified>]` placeholders.
17
17
  - `cngkit knowledges status` prints the remote catalog state.
18
18
  - `cngkit knowledges audiences` lists available audience filters.
19
- - `cngkit knowledges search <query>` runs semantic search against Cloudflare Vectorize.
20
- - `cngkit knowledges list [query]` lists known subskills.
21
- - `cngkit knowledges files [query]` lists uploaded catalog files.
22
- - `cngkit knowledges read <file-path>` reads a catalog file excerpt.
23
- - `cngkit knowledges grep <pattern>` searches catalog file contents.
24
- - `cngkit knowledges glob [pattern]` lists catalog files by supported glob pattern.
19
+ - `cngkit knowledges search <query> [--limit n]` runs semantic search against Cloudflare Vectorize (default limit 5).
20
+ - `cngkit knowledges list [query] [--limit n]` lists known subskills (default limit 25).
21
+ - `cngkit knowledges files [query] [--audience id] [--limit n]` lists uploaded catalog files (default limit 25).
22
+ - `cngkit knowledges read <file-path> [--offset n] [--limit n]` reads a catalog file excerpt (default limit 200).
23
+ - `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 `/`).
24
+ - `cngkit knowledges glob [pattern] [--path path]` lists catalog files by supported glob pattern (default pattern `**/*.md`, default path `/`).
25
25
  - `.git/` and files ignored by the repo's `.gitignore` are not synced.
26
26
  - Later changes override earlier changes for the MVP conflict rule.
27
27
 
28
+ Help is baked into the CLI as Markdown with progressive disclosure:
29
+
30
+ ```bash
31
+ cngkit --help
32
+ cngkit scrub --help
33
+ cngkit knowledges --help
34
+ cngkit knowledges read --help
35
+ cngkit knowledges grep --help
36
+ cngkit knowledges glob --help
37
+ ```
38
+
39
+ Global options accepted by every command:
40
+
41
+ - `--api-base-url <url>` overrides the Curly backend URL (default: `CNGKIT_API_BASE_URL` or `https://curly.ng`).
42
+ - `--version` prints the installed `cngkit` version.
43
+ - `--help` / `-h` prints the progressive help for the current command.
44
+
45
+ The canonical CLI spec lives at `docs/superpowers/specs/2026-06-25-cngkit-cli-spec.md`
46
+ in the repository. The baked help source lives in `src/help-specs.ts`; keep both
47
+ aligned when changing command behavior.
48
+
28
49
  `scrub` requires the `trufflehog` binary on `PATH`. On macOS, install it with:
29
50
 
30
51
  ```bash
@@ -33,6 +54,22 @@ brew install trufflehog
33
54
 
34
55
  Inline masking is intentionally gated behind `--yes` because it rewrites files in place.
35
56
 
57
+ ## Coderoom
58
+
59
+ Coderoom is for quickly uniting developers around one working tree. One developer starts
60
+ a room, another joins it, and the Curly backend relays file changes through the
61
+ `/api/cng/sync/:roomCode` WebSocket room.
62
+
63
+ ```bash
64
+ cngkit coderoom share
65
+ cngkit coderoom join <room-code>
66
+ ```
67
+
68
+ The frontend helper lives at `/coderoom`. It presents Coderoom as a Drive-like
69
+ shared workspace: a room code acts like a share link, connected machines act like
70
+ collaborators, and file events act like the activity stream. Current Coderoom
71
+ rooms are live relays, not durable cloud storage.
72
+
36
73
  ## Harness Knowledges
37
74
 
38
75
  The `knowledges` command group reads the Cloudflare-backed Harness catalog from the
@@ -49,12 +86,19 @@ cngkit knowledges glob "**/*.md" --path /libraries/lib-cloudflare
49
86
  ```
50
87
 
51
88
  Add `--json` to any `knowledges` command when another tool should consume the
52
- raw API response. `grep` also accepts `--output-mode <content|files_with_matches|count>`,
53
- `--include <glob>`, `--context <n>`, and `--case-insensitive`.
89
+ raw API response. `grep` also accepts `--output-mode <content|files_with_matches|count>`
90
+ (default `content`), `--include <glob>` (default `*`), `--context <n>` (default `0`), and
91
+ `--case-insensitive`. Result limits default to `5` for `search` and `25` for `list` and
92
+ `files`; `read` defaults to `200` lines with a backend cap of `2000`, and accepts `--offset`
93
+ for paging.
94
+
95
+ `read` and `grep` accept shorthand catalog paths: `/libraries/lib-cloudflare/SUBSKILL.md`
96
+ expands to `skills/knowledges/subskills/libraries/lib-cloudflare/SUBSKILL.md`, mirroring the
97
+ Claude `read`/`grep` tool convention.
54
98
 
55
99
  This package is mostly personal tooling for Curly.ng. It is intentionally opinionated,
56
100
  small, and practical rather than a general synchronization platform.
57
101
 
58
102
  ## License
59
103
 
60
- Beerware. If this helps you, support the workshop: https://curly.ng/donate
104
+ Beerware. If this helps you, support the workshop: https://curly.ng/support
package/dist/cli.cjs CHANGED
@@ -7443,7 +7443,7 @@ var logging;
7443
7443
  // src/config.ts
7444
7444
  var import_node_crypto = require("crypto");
7445
7445
  var import_node_process = __toESM(require("process"), 1);
7446
- var packageVersion = "1.1.1";
7446
+ var packageVersion = "1.1.3";
7447
7447
  var defaultApiBaseUrl = "https://curly.ng";
7448
7448
  function resolveApiBaseUrl(options) {
7449
7449
  return options.apiBaseUrl ?? import_node_process.default.env.CNGKIT_API_BASE_URL ?? defaultApiBaseUrl;
@@ -7515,11 +7515,14 @@ function browserOpenCommand(url2) {
7515
7515
  // src/help-specs.ts
7516
7516
  var commandList = [
7517
7517
  "`cngkit login` - open Curly.ng login.",
7518
- "`cngkit share [room-code]` - start a live repo sync room.",
7519
- "`cngkit join <room-code>` - join a live repo sync room.",
7518
+ "`cngkit coderoom ...` - unite developers in a live shared code room.",
7520
7519
  "`cngkit scrub [path]` - scan for secrets and optionally mask them inline.",
7521
7520
  "`cngkit knowledges ...` - read the hosted Harness catalog."
7522
7521
  ].join("\n");
7522
+ var coderoomCommandList = [
7523
+ "`share [room-code]` - start a live room from the current directory.",
7524
+ "`join <room-code>` - join another developer's live room from the current directory."
7525
+ ].join("\n");
7523
7526
  var knowledgesCommandList = [
7524
7527
  "`status` - print remote catalog state.",
7525
7528
  "`audiences` - list valid audience filters.",
@@ -7552,6 +7555,8 @@ ${commandList}
7552
7555
 
7553
7556
  \`\`\`bash
7554
7557
  cngkit <command> --help
7558
+ cngkit coderoom --help
7559
+ cngkit coderoom <subcommand> --help
7555
7560
  cngkit knowledges --help
7556
7561
  cngkit knowledges <subcommand> --help
7557
7562
  \`\`\`
@@ -7591,16 +7596,51 @@ cngkit login
7591
7596
  `
7592
7597
  },
7593
7598
  {
7594
- title: "share",
7595
- aliases: ["share", "sync", "repo-sync"],
7596
- body: `# cngkit share
7599
+ title: "coderoom",
7600
+ aliases: ["coderoom", "code-room", "repo-sync"],
7601
+ body: `# cngkit coderoom
7602
+
7603
+ Coderoom is the fast way to unite developers around one working tree. It gives a pair or team a temporary shared room over the Curly backend so one developer can share local file changes and another can join from their own machine.
7604
+
7605
+ It is intentionally closer to a Drive-like project room than a raw socket command: the room code is the shared folder link, each connected machine is a collaborator, and the file stream is the activity feed. The browser experience at \`/coderoom\` provides the helper surface for copying commands and explaining the room model.
7606
+
7607
+ ## Usage
7608
+
7609
+ \`\`\`bash
7610
+ cngkit coderoom <subcommand> [options]
7611
+ \`\`\`
7612
+
7613
+ ## Subcommands
7614
+
7615
+ ${coderoomCommandList}
7616
+
7617
+ ## Common Flow
7618
+
7619
+ \`\`\`bash
7620
+ cngkit coderoom share
7621
+ cngkit coderoom join <room-code>
7622
+ \`\`\`
7623
+
7624
+ ## Backend Contract
7625
+
7626
+ - Connects to \`/api/cng/sync/:roomCode\` on the configured Curly backend.
7627
+ - Uses WebSocket transport backed by the \`CngSyncRoom\` Durable Object.
7628
+ - Sends an initial snapshot, then file and delete events.
7629
+ - Last received change wins.
7630
+ - Current rooms are live relays, not durable cloud storage. The Drive-like frontend is the collaboration shell around that live primitive.
7631
+ `
7632
+ },
7633
+ {
7634
+ title: "coderoom share",
7635
+ aliases: ["coderoom-share"],
7636
+ body: `# cngkit coderoom share
7597
7637
 
7598
7638
  Start a real-time repository sync room from the current directory.
7599
7639
 
7600
7640
  ## Usage
7601
7641
 
7602
7642
  \`\`\`bash
7603
- cngkit share [room-code]
7643
+ cngkit coderoom share [room-code]
7604
7644
  \`\`\`
7605
7645
 
7606
7646
  ## Backend Contract
@@ -7623,21 +7663,21 @@ cngkit share [room-code]
7623
7663
  `
7624
7664
  },
7625
7665
  {
7626
- title: "join",
7627
- aliases: ["join"],
7628
- body: `# cngkit join
7666
+ title: "coderoom join",
7667
+ aliases: ["coderoom-join"],
7668
+ body: `# cngkit coderoom join
7629
7669
 
7630
7670
  Join an existing real-time repository sync room in the current directory.
7631
7671
 
7632
7672
  ## Usage
7633
7673
 
7634
7674
  \`\`\`bash
7635
- cngkit join <room-code>
7675
+ cngkit coderoom join <room-code>
7636
7676
  \`\`\`
7637
7677
 
7638
7678
  ## Backend Contract
7639
7679
 
7640
- Same transport and filesystem contract as \`cngkit share\`. The supplied room code selects the Durable Object room.
7680
+ Same transport and filesystem contract as \`cngkit coderoom share\`. The supplied room code selects the Durable Object room.
7641
7681
 
7642
7682
  ## Output Contract
7643
7683
 
@@ -7691,11 +7731,21 @@ ${knowledgesCommandList}
7691
7731
  ## Progressive Help
7692
7732
 
7693
7733
  \`\`\`bash
7734
+ cngkit knowledges <subcommand> --help
7694
7735
  cngkit knowledges read --help
7695
7736
  cngkit knowledges grep --help
7696
7737
  cngkit knowledges glob --help
7697
7738
  \`\`\`
7698
7739
 
7740
+ ## Common Examples
7741
+
7742
+ \`\`\`bash
7743
+ cngkit knowledges search "cloudflare backend" --limit 3
7744
+ cngkit knowledges read /libraries/lib-cloudflare/SUBSKILL.md --limit 80
7745
+ cngkit knowledges grep Cloudflare --path /libraries/lib-cloudflare --output-mode files_with_matches
7746
+ cngkit knowledges glob "**/*.md" --path /libraries/lib-cloudflare
7747
+ \`\`\`
7748
+
7699
7749
  ## AI-Friendly Output
7700
7750
 
7701
7751
  - Default output is line-oriented and intended to be directly usable by agents.
@@ -7853,6 +7903,7 @@ cngkit knowledges grep <pattern> [--path <path>] [--include <glob>] [--output-mo
7853
7903
  - \`pattern\`: JavaScript regular expression source.
7854
7904
  - \`--path\`: catalog path prefix. Default: \`/\`.
7855
7905
  - \`--include\`: filename include filter. Default: \`*\`.
7906
+ - Modes: content, files_with_matches, or count.
7856
7907
  - \`--output-mode\`: \`content\`, \`files_with_matches\`, or \`count\`. Default: \`content\`.
7857
7908
  - \`--context\`: context lines around content matches. Default: \`0\`. Backend max: \`20\`.
7858
7909
  - \`--case-insensitive\`: maps to backend \`case_insensitive=true\`.
@@ -8080,8 +8131,15 @@ function parseJsonRecord(line) {
8080
8131
  return void 0;
8081
8132
  }
8082
8133
  }
8134
+ function isJsonRecord(value) {
8135
+ if (typeof value !== "object" || value === null || Array.isArray(value)) {
8136
+ return false;
8137
+ }
8138
+ const prototype = Object.getPrototypeOf(value);
8139
+ return prototype === Object.prototype || prototype === null;
8140
+ }
8083
8141
  function readRecord(value) {
8084
- return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
8142
+ return isJsonRecord(value) ? value : void 0;
8085
8143
  }
8086
8144
  function readString(value) {
8087
8145
  return typeof value === "string" && value.length > 0 ? value : void 0;
@@ -24716,6 +24774,17 @@ async function waitForSessionClose(socket, watcher) {
24716
24774
  }
24717
24775
 
24718
24776
  // src/commands.ts
24777
+ async function runCoderoomCommand(args, options, output) {
24778
+ const [subcommand, ...subcommandArgs] = args ?? [];
24779
+ switch (subcommand) {
24780
+ case "share":
24781
+ return runShareCommand(subcommandArgs[0], options, output);
24782
+ case "join":
24783
+ return runJoinCommand(subcommandArgs[0], options, output);
24784
+ default:
24785
+ throw new Error("Missing coderoom command. Usage: cngkit coderoom <share|join>");
24786
+ }
24787
+ }
24719
24788
  async function runKnowledgesCommand(args, options, output, dependencies) {
24720
24789
  const [subcommand, ...subcommandArgs] = args ?? [];
24721
24790
  if (subcommand === void 0 || subcommand === "help") {
@@ -24762,7 +24831,7 @@ async function runShareCommand(roomCode, options, output) {
24762
24831
  }
24763
24832
  async function runJoinCommand(roomCode, options, output) {
24764
24833
  if (!roomCode) {
24765
- throw new Error("Missing room code. Usage: cngkit join <room-code>");
24834
+ throw new Error("Missing room code. Usage: cngkit coderoom join <room-code>");
24766
24835
  }
24767
24836
  await printBackendStatus(options, output);
24768
24837
  await runSyncSession("join", roomCode, options, output);
@@ -25124,7 +25193,7 @@ function printMarkdownHelpIfRequested(argv) {
25124
25193
  }
25125
25194
  if (commandName === "help") {
25126
25195
  const [topicName, subtopicName] = argv.slice(3);
25127
- const topic = topicName === "knowledges" && subtopicName ? `knowledges-${subtopicName}` : topicName;
25196
+ const topic = (topicName === "knowledges" || topicName === "coderoom") && subtopicName ? `${topicName}-${subtopicName}` : topicName;
25128
25197
  consoleOutput.info(formatCngkitHelp(topic));
25129
25198
  return true;
25130
25199
  }
@@ -25138,6 +25207,11 @@ function printMarkdownHelpIfRequested(argv) {
25138
25207
  consoleOutput.info(formatKnowledgesHelp(topic));
25139
25208
  return true;
25140
25209
  }
25210
+ if (commandName === "coderoom") {
25211
+ const topic = commandArgs.find((argument, index) => index !== helpIndex && !argument.startsWith("-"));
25212
+ consoleOutput.info(formatCngkitHelp(topic ? `coderoom-${topic}` : "coderoom"));
25213
+ return true;
25214
+ }
25141
25215
  consoleOutput.info(formatCngkitHelp(commandName));
25142
25216
  return true;
25143
25217
  }
@@ -25151,11 +25225,8 @@ cli.option(
25151
25225
  cli.command("login", "Open Curly login in your browser").action((options) => {
25152
25226
  void runLoginCommand(options, consoleOutput).catch(handleFatalError);
25153
25227
  });
25154
- cli.command("share [room-code]", "Start a real-time repo sync room from the current directory").action((roomCode, options) => {
25155
- void runShareCommand(roomCode, options, consoleOutput).catch(handleFatalError);
25156
- });
25157
- cli.command("join <room-code>", "Join a real-time repo sync room in the current directory").action((roomCode, options) => {
25158
- void runJoinCommand(roomCode, options, consoleOutput).catch(handleFatalError);
25228
+ cli.command("coderoom [...args]", "Start or join a real-time repo sync room").action((args, options) => {
25229
+ void runCoderoomCommand(args, options, consoleOutput).catch(handleFatalError);
25159
25230
  });
25160
25231
  cli.command("scrub [path]", "Scan for secrets with TruffleHog and optionally mask them inline").option("--mask", "Compatibility alias for inline scrubbing; --yes is still required").option("--yes", "Confirm and run inline scrubbing").action((targetPath, options) => {
25161
25232
  void runScrubCommand(targetPath, options, consoleOutput).catch(handleFatalError);