cngkit 1.1.0 → 1.1.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.
package/README.md CHANGED
@@ -1,17 +1,17 @@
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
16
  - `cngkit scrub [path] --yes` rewrites detected secret values inline with `CNGKIT_SECRET` placeholders.
17
17
  - `cngkit knowledges status` prints the remote catalog state.
@@ -25,6 +25,21 @@ the Cloudflare-backed Harness knowledges catalog:
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
+ The canonical CLI spec lives at `docs/superpowers/specs/2026-06-25-cngkit-cli-spec.md`
40
+ in the repository. The baked help source lives in `src/help-specs.ts`; keep both
41
+ aligned when changing command behavior.
42
+
28
43
  `scrub` requires the `trufflehog` binary on `PATH`. On macOS, install it with:
29
44
 
30
45
  ```bash
@@ -33,6 +48,22 @@ brew install trufflehog
33
48
 
34
49
  Inline masking is intentionally gated behind `--yes` because it rewrites files in place.
35
50
 
51
+ ## Coderoom
52
+
53
+ Coderoom is for quickly uniting developers around one working tree. One developer starts
54
+ a room, another joins it, and the Curly backend relays file changes through the
55
+ `/api/cng/sync/:roomCode` WebSocket room.
56
+
57
+ ```bash
58
+ cngkit coderoom share
59
+ cngkit coderoom join <room-code>
60
+ ```
61
+
62
+ The frontend helper lives at `/coderoom`. It presents Coderoom as a Drive-like
63
+ shared workspace: a room code acts like a share link, connected machines act like
64
+ collaborators, and file events act like the activity stream. Current Coderoom
65
+ rooms are live relays, not durable cloud storage.
66
+
36
67
  ## Harness Knowledges
37
68
 
38
69
  The `knowledges` command group reads the Cloudflare-backed Harness catalog from the
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.0";
7446
+ var packageVersion = "1.1.2";
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;
@@ -7512,6 +7512,477 @@ function browserOpenCommand(url2) {
7512
7512
  return { command: "xdg-open", args: [url2] };
7513
7513
  }
7514
7514
 
7515
+ // src/help-specs.ts
7516
+ var commandList = [
7517
+ "`cngkit login` - open Curly.ng login.",
7518
+ "`cngkit coderoom ...` - unite developers in a live shared code room.",
7519
+ "`cngkit scrub [path]` - scan for secrets and optionally mask them inline.",
7520
+ "`cngkit knowledges ...` - read the hosted Harness catalog."
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");
7526
+ var knowledgesCommandList = [
7527
+ "`status` - print remote catalog state.",
7528
+ "`audiences` - list valid audience filters.",
7529
+ "`search <query>` - semantic search over Cloudflare Vectorize-backed records.",
7530
+ "`list [query]` - list known subskills.",
7531
+ "`files [query]` - list uploaded catalog files.",
7532
+ "`read <file-path>` - Claude-style file read.",
7533
+ "`grep <pattern>` - Claude-style content search.",
7534
+ "`glob [pattern]` - Claude-style file discovery."
7535
+ ].join("\n");
7536
+ var helpTopics = [
7537
+ {
7538
+ title: "cngkit",
7539
+ aliases: ["", "overview", "help"],
7540
+ body: `# cngkit
7541
+
7542
+ Curly.ng operator CLI for backend-connected repo sync, secret scrubbing, and Harness knowledges access.
7543
+
7544
+ ## Usage
7545
+
7546
+ \`\`\`bash
7547
+ cngkit <command> [options]
7548
+ \`\`\`
7549
+
7550
+ ## Commands
7551
+
7552
+ ${commandList}
7553
+
7554
+ ## Progressive Help
7555
+
7556
+ \`\`\`bash
7557
+ cngkit <command> --help
7558
+ cngkit coderoom --help
7559
+ cngkit coderoom <subcommand> --help
7560
+ cngkit knowledges --help
7561
+ cngkit knowledges <subcommand> --help
7562
+ \`\`\`
7563
+
7564
+ The CLI intentionally prints plain Markdown or line-oriented text with no color-only state, tables that require terminal width, or hidden interactive prompts. Add \`--json\` to read-only knowledges commands when another agent or tool needs structured backend data.
7565
+
7566
+ ## Backend
7567
+
7568
+ Default API: \`https://curly.ng\`
7569
+
7570
+ Override with:
7571
+
7572
+ \`\`\`bash
7573
+ cngkit --api-base-url <url> ...
7574
+ CNGKIT_API_BASE_URL=<url> cngkit ...
7575
+ \`\`\`
7576
+ `
7577
+ },
7578
+ {
7579
+ title: "login",
7580
+ aliases: ["login"],
7581
+ body: `# cngkit login
7582
+
7583
+ Open Curly.ng login in a browser. In headless environments, print the URL so an agent can surface it to the operator.
7584
+
7585
+ ## Usage
7586
+
7587
+ \`\`\`bash
7588
+ cngkit login
7589
+ \`\`\`
7590
+
7591
+ ## Output Contract
7592
+
7593
+ - First line names the login URL being opened.
7594
+ - If no local browser opener exists, the CLI prints a direct URL.
7595
+ - No credentials are printed or persisted by this command.
7596
+ `
7597
+ },
7598
+ {
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
7637
+
7638
+ Start a real-time repository sync room from the current directory.
7639
+
7640
+ ## Usage
7641
+
7642
+ \`\`\`bash
7643
+ cngkit coderoom share [room-code]
7644
+ \`\`\`
7645
+
7646
+ ## Backend Contract
7647
+
7648
+ - Connects to \`/api/cng/sync/:roomCode\` on the configured Curly backend.
7649
+ - Uses WebSocket transport backed by the \`CngSyncRoom\` Durable Object.
7650
+ - Sends an initial snapshot, then file and delete events.
7651
+ - Last received change wins.
7652
+
7653
+ ## Filesystem Contract
7654
+
7655
+ - Preserves \`.git/\`.
7656
+ - Preserves files ignored by the repo's \`.gitignore\`.
7657
+ - Sends regular files as base64 payloads in the sync protocol.
7658
+
7659
+ ## Output Contract
7660
+
7661
+ - Prints room code, repo root, peer id, backend health, and concise sync events.
7662
+ - Keeps running until the socket closes or the process receives a termination signal.
7663
+ `
7664
+ },
7665
+ {
7666
+ title: "coderoom join",
7667
+ aliases: ["coderoom-join"],
7668
+ body: `# cngkit coderoom join
7669
+
7670
+ Join an existing real-time repository sync room in the current directory.
7671
+
7672
+ ## Usage
7673
+
7674
+ \`\`\`bash
7675
+ cngkit coderoom join <room-code>
7676
+ \`\`\`
7677
+
7678
+ ## Backend Contract
7679
+
7680
+ Same transport and filesystem contract as \`cngkit coderoom share\`. The supplied room code selects the Durable Object room.
7681
+
7682
+ ## Output Contract
7683
+
7684
+ - Prints backend health, room code, repo root, peer id, and concise sync events.
7685
+ - Missing room code exits with a usage error.
7686
+ `
7687
+ },
7688
+ {
7689
+ title: "scrub",
7690
+ aliases: ["scrub"],
7691
+ body: `# cngkit scrub
7692
+
7693
+ Scan a file or directory for secrets with TruffleHog. Report-only is the default. Inline masking requires \`--yes\`.
7694
+
7695
+ ## Usage
7696
+
7697
+ \`\`\`bash
7698
+ cngkit scrub [path]
7699
+ cngkit scrub [path] --yes
7700
+ \`\`\`
7701
+
7702
+ ## Requirements
7703
+
7704
+ - \`trufflehog\` must be available on \`PATH\`.
7705
+
7706
+ ## Safety Contract
7707
+
7708
+ - Default mode does not rewrite files.
7709
+ - \`--yes\` rewrites detected secret values inline with \`[CNGKIT_SECRET:<detector>:<verified|unverified>]\` placeholders.
7710
+ - \`--mask\` is accepted as a compatibility alias, but still requires \`--yes\`.
7711
+ - Raw and redacted secret values are never printed in the report.
7712
+ `
7713
+ },
7714
+ {
7715
+ title: "knowledges",
7716
+ aliases: ["knowledges", "knowledge"],
7717
+ body: `# cngkit knowledges
7718
+
7719
+ Read the hosted Harness knowledges catalog from the Curly backend. These commands are read-only and use the generated \`@cng/client\` SDK against public backend routes.
7720
+
7721
+ ## Usage
7722
+
7723
+ \`\`\`bash
7724
+ cngkit knowledges <subcommand> [options]
7725
+ \`\`\`
7726
+
7727
+ ## Subcommands
7728
+
7729
+ ${knowledgesCommandList}
7730
+
7731
+ ## Progressive Help
7732
+
7733
+ \`\`\`bash
7734
+ cngkit knowledges <subcommand> --help
7735
+ cngkit knowledges read --help
7736
+ cngkit knowledges grep --help
7737
+ cngkit knowledges glob --help
7738
+ \`\`\`
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
+
7749
+ ## AI-Friendly Output
7750
+
7751
+ - Default output is line-oriented and intended to be directly usable by agents.
7752
+ - \`read\` prints file content with no wrapper before any truncation note.
7753
+ - \`grep --output-mode content\` prints \`path:line\` blocks.
7754
+ - \`grep --output-mode files_with_matches\` and \`glob\` print one path per line.
7755
+ - \`--json\` prints the typed backend data payload for machine consumption.
7756
+ `
7757
+ },
7758
+ {
7759
+ title: "knowledges status",
7760
+ aliases: ["knowledges-status", "status"],
7761
+ body: `# cngkit knowledges status
7762
+
7763
+ Print remote Harness catalog state from \`GET /api/harness/knowledges/catalog\`.
7764
+
7765
+ ## Usage
7766
+
7767
+ \`\`\`bash
7768
+ cngkit knowledges status [--json]
7769
+ \`\`\`
7770
+
7771
+ ## Output Contract
7772
+
7773
+ - Text mode prints catalog name, file count, blob count, Vectorize binding, and latest run when present.
7774
+ - \`--json\` prints the backend data payload.
7775
+ `
7776
+ },
7777
+ {
7778
+ title: "knowledges audiences",
7779
+ aliases: ["knowledges-audiences", "audiences"],
7780
+ body: `# cngkit knowledges audiences
7781
+
7782
+ List valid audience filters from \`GET /api/harness/knowledges/audiences\`.
7783
+
7784
+ ## Usage
7785
+
7786
+ \`\`\`bash
7787
+ cngkit knowledges audiences [--json]
7788
+ \`\`\`
7789
+
7790
+ Use this before \`cngkit knowledges files --audience <id>\`.
7791
+ `
7792
+ },
7793
+ {
7794
+ title: "knowledges search",
7795
+ aliases: ["knowledges-search", "search"],
7796
+ body: `# cngkit knowledges search
7797
+
7798
+ Run semantic search against the Cloudflare Vectorize-backed Harness index.
7799
+
7800
+ ## Usage
7801
+
7802
+ \`\`\`bash
7803
+ cngkit knowledges search <query> [--limit <n>] [--json]
7804
+ \`\`\`
7805
+
7806
+ ## Defaults
7807
+
7808
+ - \`--limit\`: \`5\`
7809
+
7810
+ ## Example
7811
+
7812
+ \`\`\`bash
7813
+ cngkit knowledges search "cloudflare backend" --limit 3
7814
+ \`\`\`
7815
+ `
7816
+ },
7817
+ {
7818
+ title: "knowledges list",
7819
+ aliases: ["knowledges-list", "list"],
7820
+ body: `# cngkit knowledges list
7821
+
7822
+ List known subskills from \`GET /api/harness/knowledges/subskills\`, optionally filtered locally by query.
7823
+
7824
+ ## Usage
7825
+
7826
+ \`\`\`bash
7827
+ cngkit knowledges list [query] [--limit <n>] [--json]
7828
+ \`\`\`
7829
+
7830
+ ## Defaults
7831
+
7832
+ - \`--limit\`: \`25\`
7833
+ `
7834
+ },
7835
+ {
7836
+ title: "knowledges files",
7837
+ aliases: ["knowledges-files", "files"],
7838
+ body: `# cngkit knowledges files
7839
+
7840
+ List uploaded catalog files from \`GET /api/harness/knowledges/files\`.
7841
+
7842
+ ## Usage
7843
+
7844
+ \`\`\`bash
7845
+ cngkit knowledges files [query] [--audience <id>] [--limit <n>] [--json]
7846
+ \`\`\`
7847
+
7848
+ ## Defaults
7849
+
7850
+ - \`--limit\`: \`25\`
7851
+ - \`--audience\`: omitted
7852
+
7853
+ Run \`cngkit knowledges audiences\` to discover supported audience ids.
7854
+ `
7855
+ },
7856
+ {
7857
+ title: "knowledges read",
7858
+ aliases: ["knowledges-read", "read"],
7859
+ body: `# cngkit knowledges read
7860
+
7861
+ Claude-style read tool for hosted Harness catalog files. Backed by \`GET /api/harness/filesystem/read\` and \`HarnessReadQuerySchema\`.
7862
+
7863
+ ## Usage
7864
+
7865
+ \`\`\`bash
7866
+ cngkit knowledges read <file-path> [--offset <n>] [--limit <n>] [--json]
7867
+ \`\`\`
7868
+
7869
+ ## Inputs
7870
+
7871
+ - \`file-path\`: normalized catalog path. Shorthand paths such as \`/libraries/lib-cloudflare/SUBSKILL.md\` are expanded to \`skills/knowledges/subskills/libraries/lib-cloudflare/SUBSKILL.md\`.
7872
+ - \`--offset\`: zero-based starting line. Default: \`0\`.
7873
+ - \`--limit\`: maximum lines. Default in CLI: \`200\`. Backend max: \`2000\`.
7874
+
7875
+ ## Output Contract
7876
+
7877
+ - Text mode prints only the returned file content first.
7878
+ - If truncated, a final bracketed truncation note is printed after the content.
7879
+ - \`--json\` prints \`{ file_path, content, total_lines, offset, limit, truncated }\`.
7880
+
7881
+ ## Example
7882
+
7883
+ \`\`\`bash
7884
+ cngkit knowledges read /libraries/lib-cloudflare/SUBSKILL.md --limit 80
7885
+ \`\`\`
7886
+ `
7887
+ },
7888
+ {
7889
+ title: "knowledges grep",
7890
+ aliases: ["knowledges-grep", "grep"],
7891
+ body: `# cngkit knowledges grep
7892
+
7893
+ Claude-style grep tool for hosted Harness catalog files. Backed by \`GET /api/harness/filesystem/grep\` and \`HarnessGrepQuerySchema\`.
7894
+
7895
+ ## Usage
7896
+
7897
+ \`\`\`bash
7898
+ cngkit knowledges grep <pattern> [--path <path>] [--include <glob>] [--output-mode <mode>] [--context <n>] [--case-insensitive] [--json]
7899
+ \`\`\`
7900
+
7901
+ ## Inputs
7902
+
7903
+ - \`pattern\`: JavaScript regular expression source.
7904
+ - \`--path\`: catalog path prefix. Default: \`/\`.
7905
+ - \`--include\`: filename include filter. Default: \`*\`.
7906
+ - Modes: content, files_with_matches, or count.
7907
+ - \`--output-mode\`: \`content\`, \`files_with_matches\`, or \`count\`. Default: \`content\`.
7908
+ - \`--context\`: context lines around content matches. Default: \`0\`. Backend max: \`20\`.
7909
+ - \`--case-insensitive\`: maps to backend \`case_insensitive=true\`.
7910
+
7911
+ ## Output Contract
7912
+
7913
+ - \`content\`: prints blocks as \`file_path:line_number\`, optional context lines, then \`> matching line\`.
7914
+ - \`files_with_matches\`: prints one matching file path per line.
7915
+ - \`count\`: prints \`file_path: match_count\` lines.
7916
+ - \`--json\` prints the typed backend response union.
7917
+
7918
+ ## Examples
7919
+
7920
+ \`\`\`bash
7921
+ cngkit knowledges grep Cloudflare --path /libraries/lib-cloudflare --output-mode files_with_matches
7922
+ cngkit knowledges grep "Vectorize|D1" --path /libraries/lib-cloudflare --context 2
7923
+ \`\`\`
7924
+ `
7925
+ },
7926
+ {
7927
+ title: "knowledges glob",
7928
+ aliases: ["knowledges-glob", "glob"],
7929
+ body: `# cngkit knowledges glob
7930
+
7931
+ Claude-style glob tool for hosted Harness catalog files. Backed by \`GET /api/harness/filesystem/glob\` and \`HarnessGlobQuerySchema\`.
7932
+
7933
+ ## Usage
7934
+
7935
+ \`\`\`bash
7936
+ cngkit knowledges glob [pattern] [--path <path>] [--json]
7937
+ \`\`\`
7938
+
7939
+ ## Inputs
7940
+
7941
+ - \`pattern\`: supported glob pattern. CLI default: \`**/*.md\`.
7942
+ - \`--path\`: catalog path prefix. Default: \`/\`.
7943
+
7944
+ ## Supported Patterns
7945
+
7946
+ - \`**/*.md\`
7947
+ - \`**/*.SUBSKILL.md\`
7948
+ - \`**/SKILL.md\`
7949
+ - \`*.md\`
7950
+ - \`*.SUBSKILL.md\`
7951
+ - \`SKILL.md\`
7952
+
7953
+ ## Output Contract
7954
+
7955
+ - Text mode prints one file path per line.
7956
+ - If truncated, a final bracketed truncation note is printed.
7957
+ - \`--json\` prints \`{ files, total_files, truncated }\`.
7958
+
7959
+ ## Example
7960
+
7961
+ \`\`\`bash
7962
+ cngkit knowledges glob "**/*.md" --path /libraries/lib-cloudflare
7963
+ \`\`\`
7964
+ `
7965
+ }
7966
+ ];
7967
+ var helpTopicByAlias = /* @__PURE__ */ new Map();
7968
+ for (const topic of helpTopics) {
7969
+ for (const alias of topic.aliases) {
7970
+ helpTopicByAlias.set(alias, topic);
7971
+ }
7972
+ }
7973
+ function formatCngkitHelp(topicName) {
7974
+ const normalizedTopicName = normalizeHelpTopicName(topicName);
7975
+ return (helpTopicByAlias.get(normalizedTopicName) ?? helpTopicByAlias.get(""))?.body.trim() ?? "";
7976
+ }
7977
+ function formatKnowledgesHelp(topicName) {
7978
+ const normalizedTopicName = normalizeHelpTopicName(topicName);
7979
+ const topicKey = normalizedTopicName ? `knowledges-${normalizedTopicName}` : "knowledges";
7980
+ return formatCngkitHelp(topicKey);
7981
+ }
7982
+ function normalizeHelpTopicName(value) {
7983
+ return value?.trim().toLowerCase().replace(/\s+/g, "-") ?? "";
7984
+ }
7985
+
7515
7986
  // src/scrub/masker.ts
7516
7987
  var import_promises = __toESM(require("fs/promises"), 1);
7517
7988
  var import_node_path = __toESM(require("path"), 1);
@@ -24296,8 +24767,23 @@ async function waitForSessionClose(socket, watcher) {
24296
24767
  }
24297
24768
 
24298
24769
  // src/commands.ts
24770
+ async function runCoderoomCommand(args, options, output) {
24771
+ const [subcommand, ...subcommandArgs] = args ?? [];
24772
+ switch (subcommand) {
24773
+ case "share":
24774
+ return runShareCommand(subcommandArgs[0], options, output);
24775
+ case "join":
24776
+ return runJoinCommand(subcommandArgs[0], options, output);
24777
+ default:
24778
+ throw new Error("Missing coderoom command. Usage: cngkit coderoom <share|join>");
24779
+ }
24780
+ }
24299
24781
  async function runKnowledgesCommand(args, options, output, dependencies) {
24300
24782
  const [subcommand, ...subcommandArgs] = args ?? [];
24783
+ if (subcommand === void 0 || subcommand === "help") {
24784
+ output.info(formatKnowledgesHelp(subcommandArgs[0]));
24785
+ return;
24786
+ }
24301
24787
  switch (subcommand) {
24302
24788
  case "status":
24303
24789
  return runKnowStatusCommand(options, output, dependencies);
@@ -24338,7 +24824,7 @@ async function runShareCommand(roomCode, options, output) {
24338
24824
  }
24339
24825
  async function runJoinCommand(roomCode, options, output) {
24340
24826
  if (!roomCode) {
24341
- throw new Error("Missing room code. Usage: cngkit join <room-code>");
24827
+ throw new Error("Missing room code. Usage: cngkit coderoom join <room-code>");
24342
24828
  }
24343
24829
  await printBackendStatus(options, output);
24344
24830
  await runSyncSession("join", roomCode, options, output);
@@ -24692,6 +25178,39 @@ function handleFatalError(error51) {
24692
25178
  consoleOutput.error(formatError2(error51));
24693
25179
  import_node_process5.default.exitCode = 1;
24694
25180
  }
25181
+ function printMarkdownHelpIfRequested(argv) {
25182
+ const commandName = argv[2];
25183
+ if (commandName === void 0 || commandName === "--help" || commandName === "-h") {
25184
+ consoleOutput.info(formatCngkitHelp());
25185
+ return true;
25186
+ }
25187
+ if (commandName === "help") {
25188
+ const [topicName, subtopicName] = argv.slice(3);
25189
+ const topic = (topicName === "knowledges" || topicName === "coderoom") && subtopicName ? `${topicName}-${subtopicName}` : topicName;
25190
+ consoleOutput.info(formatCngkitHelp(topic));
25191
+ return true;
25192
+ }
25193
+ const commandArgs = argv.slice(3);
25194
+ const helpIndex = commandArgs.findIndex((argument) => argument === "--help" || argument === "-h");
25195
+ if (helpIndex < 0) {
25196
+ return false;
25197
+ }
25198
+ if (commandName === "knowledges") {
25199
+ const topic = commandArgs.find((argument, index) => index !== helpIndex && !argument.startsWith("-"));
25200
+ consoleOutput.info(formatKnowledgesHelp(topic));
25201
+ return true;
25202
+ }
25203
+ if (commandName === "coderoom") {
25204
+ const topic = commandArgs.find((argument, index) => index !== helpIndex && !argument.startsWith("-"));
25205
+ consoleOutput.info(formatCngkitHelp(topic ? `coderoom-${topic}` : "coderoom"));
25206
+ return true;
25207
+ }
25208
+ consoleOutput.info(formatCngkitHelp(commandName));
25209
+ return true;
25210
+ }
25211
+ if (printMarkdownHelpIfRequested(import_node_process5.default.argv)) {
25212
+ import_node_process5.default.exit(0);
25213
+ }
24695
25214
  cli.option(
24696
25215
  "--api-base-url <url>",
24697
25216
  "Curly API base URL. Default: CNGKIT_API_BASE_URL or https://curly.ng"
@@ -24699,11 +25218,8 @@ cli.option(
24699
25218
  cli.command("login", "Open Curly login in your browser").action((options) => {
24700
25219
  void runLoginCommand(options, consoleOutput).catch(handleFatalError);
24701
25220
  });
24702
- cli.command("share [room-code]", "Start a real-time repo sync room from the current directory").action((roomCode, options) => {
24703
- void runShareCommand(roomCode, options, consoleOutput).catch(handleFatalError);
24704
- });
24705
- cli.command("join <room-code>", "Join a real-time repo sync room in the current directory").action((roomCode, options) => {
24706
- void runJoinCommand(roomCode, options, consoleOutput).catch(handleFatalError);
25221
+ cli.command("coderoom [...args]", "Start or join a real-time repo sync room").action((args, options) => {
25222
+ void runCoderoomCommand(args, options, consoleOutput).catch(handleFatalError);
24707
25223
  });
24708
25224
  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) => {
24709
25225
  void runScrubCommand(targetPath, options, consoleOutput).catch(handleFatalError);