cngkit 1.1.22 → 1.1.24

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 (70) hide show
  1. package/README.md +24 -8
  2. package/dist/{chunk-AS7FIJWP.js → chunk-2Y5FMKFS.js} +3 -4
  3. package/dist/chunk-2Y5FMKFS.js.map +1 -0
  4. package/dist/{chunk-VMTXY4KQ.js → chunk-3VDQDFHG.js} +14 -6
  5. package/dist/chunk-3VDQDFHG.js.map +1 -0
  6. package/dist/{chunk-TIY4RTXC.js → chunk-4Q2LNYVU.js} +12 -15
  7. package/dist/chunk-4Q2LNYVU.js.map +1 -0
  8. package/dist/{chunk-KURN5BJ6.js → chunk-EG3QD47O.js} +90 -15
  9. package/dist/chunk-EG3QD47O.js.map +1 -0
  10. package/dist/{chunk-DCW4RKLC.js → chunk-H5LPFVPJ.js} +10 -8
  11. package/dist/{chunk-DCW4RKLC.js.map → chunk-H5LPFVPJ.js.map} +1 -1
  12. package/dist/{chunk-BRFWVQI4.js → chunk-LC4CYVCT.js} +1 -1
  13. package/dist/chunk-LC4CYVCT.js.map +1 -0
  14. package/dist/{chunk-YALWTRIP.js → chunk-LNFZT3R3.js} +2 -2
  15. package/dist/{chunk-JNHW72SU.js → chunk-QCAHQE7Q.js} +14 -9
  16. package/dist/chunk-QCAHQE7Q.js.map +1 -0
  17. package/dist/{chunk-N255PYL7.js → chunk-SRZRHLRJ.js} +2 -2
  18. package/dist/{chunk-3BATDTKU.js → chunk-YPGDQ6P2.js} +2 -4
  19. package/dist/chunk-YPGDQ6P2.js.map +1 -0
  20. package/dist/{chunk-NLAANOBW.js → chunk-ZFBOTEAS.js} +2 -2
  21. package/dist/cli.js +2 -2
  22. package/dist/cli.js.map +1 -1
  23. package/dist/commands/coderoom/index.js +3 -3
  24. package/dist/commands/coderoom/join.js +14 -5
  25. package/dist/commands/coderoom/join.js.map +1 -1
  26. package/dist/commands/coderoom/share.js +4 -4
  27. package/dist/commands/hookify/index.js +3 -3
  28. package/dist/commands/hookify/ingest.js +3 -3
  29. package/dist/commands/hooks/index.js +3 -3
  30. package/dist/commands/hooks/install.js +3 -3
  31. package/dist/commands/hooks/uninstall.js +3 -3
  32. package/dist/commands/index.js +3 -3
  33. package/dist/commands/knowledges/audiences.js +6 -6
  34. package/dist/commands/knowledges/cat.js +6 -6
  35. package/dist/commands/knowledges/files.js +6 -6
  36. package/dist/commands/knowledges/find.js +6 -6
  37. package/dist/commands/knowledges/find.js.map +1 -1
  38. package/dist/commands/knowledges/glob.js +5 -5
  39. package/dist/commands/knowledges/grep.js +5 -5
  40. package/dist/commands/knowledges/grep.js.map +1 -1
  41. package/dist/commands/knowledges/head.js +6 -6
  42. package/dist/commands/knowledges/index.js +3 -3
  43. package/dist/commands/knowledges/list.js +6 -6
  44. package/dist/commands/knowledges/ls.js +6 -6
  45. package/dist/commands/knowledges/ls.js.map +1 -1
  46. package/dist/commands/knowledges/read.js +5 -5
  47. package/dist/commands/knowledges/read.js.map +1 -1
  48. package/dist/commands/knowledges/realpath.js +3 -3
  49. package/dist/commands/knowledges/realpath.js.map +1 -1
  50. package/dist/commands/knowledges/search.js +6 -6
  51. package/dist/commands/knowledges/stat.js +6 -6
  52. package/dist/commands/knowledges/status.js +6 -6
  53. package/dist/commands/knowledges/tail.js +6 -6
  54. package/dist/commands/knowledges/tree.js +6 -6
  55. package/dist/commands/login.js +2 -2
  56. package/dist/commands/scrub.js +17 -14
  57. package/dist/commands/scrub.js.map +1 -1
  58. package/dist/commands/transcripts.js +41 -31
  59. package/dist/commands/transcripts.js.map +1 -1
  60. package/package.json +1 -1
  61. package/dist/chunk-3BATDTKU.js.map +0 -1
  62. package/dist/chunk-AS7FIJWP.js.map +0 -1
  63. package/dist/chunk-BRFWVQI4.js.map +0 -1
  64. package/dist/chunk-JNHW72SU.js.map +0 -1
  65. package/dist/chunk-KURN5BJ6.js.map +0 -1
  66. package/dist/chunk-TIY4RTXC.js.map +0 -1
  67. package/dist/chunk-VMTXY4KQ.js.map +0 -1
  68. /package/dist/{chunk-YALWTRIP.js.map → chunk-LNFZT3R3.js.map} +0 -0
  69. /package/dist/{chunk-N255PYL7.js.map → chunk-SRZRHLRJ.js.map} +0 -0
  70. /package/dist/{chunk-NLAANOBW.js.map → chunk-ZFBOTEAS.js.map} +0 -0
package/README.md CHANGED
@@ -10,6 +10,19 @@ inspection, and terminal access to the hosted Harness knowledge catalog.
10
10
  well in terminals, scripts, and coding assistants. Human-facing status lines use Ink
11
11
  styling when the terminal supports color. Data-heavy output stays plain and easy to pipe.
12
12
 
13
+ ## Important Notice
14
+
15
+ `cngkit` is a personal-use project. I publish it because it solves problems I run into
16
+ in my own operator workflow, not because it is a polished community-maintained open-source
17
+ platform.
18
+
19
+ Assume backend-backed commands send their inputs, metadata, and command context to the
20
+ owner-operated Curly.ng backend for processing. Do not use this package as a self-contained
21
+ offline tool or neutral third-party service boundary.
22
+
23
+ If you need this to become a real open-source project, a self-hostable system, or a package
24
+ with stronger data-processing guarantees, reach out first.
25
+
13
26
  ## Quick Start
14
27
 
15
28
  Run it without installing:
@@ -59,8 +72,9 @@ The CLI currently has six main jobs:
59
72
  ## Coderoom
60
73
 
61
74
  Coderoom is a live room for quickly sharing a working tree with another developer or agent.
62
- One machine creates a server-owned room code, another asks to join with that code,
63
- and the creator approves the request before files sync.
75
+ One machine creates a server-owned room code and prints a copy-ready partner command with
76
+ a guest acceptance token. The partner can join with that command without a separate approval
77
+ prompt; joins without the token still wait for host approval.
64
78
 
65
79
  Start a room:
66
80
 
@@ -71,14 +85,15 @@ cngkit coderoom share
71
85
  Join a room:
72
86
 
73
87
  ```bash
74
- cngkit coderoom join <room-code>
88
+ cngkit coderoom join <room-code> --acceptance-token <token>
75
89
  ```
76
90
 
77
91
  Coderoom deliberately skips `.git/` and files ignored by `.gitignore`. Room codes,
78
- participants, join requests, and file IDs are created by the backend. The room Durable
79
- Object stores the file tree and hashes, keeps small file bodies directly, and uses R2
80
- for large file bodies. The current conflict rule is simple: the latest received change
81
- wins.
92
+ guest acceptance tokens, participants, join requests, and file IDs are created by the
93
+ backend. The CLI prints every initial snapshot upload, live file upload, delete upload,
94
+ backend storage acknowledgement, and shutdown status. The room Durable Object stores the
95
+ file tree and hashes, keeps small file bodies directly, and uses R2 for large file bodies.
96
+ The current conflict rule is simple: the latest received change wins.
82
97
 
83
98
  ## Harness Knowledges
84
99
 
@@ -405,4 +420,5 @@ The package build uses `tsup` to emit a file-preserving ESM build. The published
405
420
 
406
421
  ## License
407
422
 
408
- Apache-2.0. If this helps you, support the workshop: https://curly.ng/support
423
+ Apache-2.0, with the personal-use and owner-operated backend notice above. If this helps
424
+ you, support the workshop: https://curly.ng/support
@@ -1,5 +1,5 @@
1
1
  // src/features/knowledges/knowledges-input.ts
2
- var storedTopicsRoot = "skills/knowledges/topics";
2
+ var storedTopicsRoot = "topics";
3
3
  function normalizeAudienceId(value) {
4
4
  if (value === void 0) {
5
5
  return void 0;
@@ -26,7 +26,6 @@ function normalizeCatalogPath(value) {
26
26
  if (relativePath === storedTopicsRoot || relativePath.startsWith(`${storedTopicsRoot}/`)) {
27
27
  return relativePath;
28
28
  }
29
- const topicRelativePath = relativePath.startsWith("topics/") ? relativePath.slice("topics/".length) : relativePath;
30
29
  const [firstSegment, ...restSegments] = relativePath.split("/");
31
30
  if (!firstSegment) {
32
31
  return relativePath;
@@ -44,7 +43,7 @@ function normalizeCatalogPath(value) {
44
43
  case "tools":
45
44
  return `${storedTopicsRoot}/${firstSegment}${restSegments.length > 0 ? `/${restSegments.join("/")}` : ""}`;
46
45
  default:
47
- return `${storedTopicsRoot}/${topicRelativePath}`;
46
+ return `${storedTopicsRoot}/${relativePath}`;
48
47
  }
49
48
  }
50
49
  function normalizeFilesystemCatalogPath(value) {
@@ -85,4 +84,4 @@ export {
85
84
  formatCatalogPathForDisplay,
86
85
  normalizeGrepMode
87
86
  };
88
- //# sourceMappingURL=chunk-AS7FIJWP.js.map
87
+ //# sourceMappingURL=chunk-2Y5FMKFS.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/features/knowledges/knowledges-input.ts"],"sourcesContent":["import type { CngApi } from \"@cng/client\";\n\nconst storedTopicsRoot = \"topics\";\n\nexport function normalizeAudienceId(\n value: string | undefined\n): 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 storedTopicsRoot;\n }\n\n const relativePath = trimmed.replace(/^\\/+/, \"\");\n if (relativePath === storedTopicsRoot || relativePath.startsWith(`${storedTopicsRoot}/`)) {\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 `${storedTopicsRoot}/${firstSegment}${restSegments.length > 0 ? `/${restSegments.join(\"/\")}` : \"\"}`;\n default:\n return `${storedTopicsRoot}/${relativePath}`;\n }\n}\n\nexport function normalizeFilesystemCatalogPath(value: string): string {\n const trimmed = value.trim();\n if (trimmed === \"/\" || trimmed === \"\") {\n return storedTopicsRoot;\n }\n\n return normalizeCatalogPath(trimmed);\n}\n\nexport function formatCatalogPathForDisplay(value: string): string {\n const normalized = value.replace(/\\/+$/, \"\");\n if (normalized === storedTopicsRoot) {\n return \"/\";\n }\n\n if (normalized.startsWith(`${storedTopicsRoot}/`)) {\n return `/${normalized.slice(storedTopicsRoot.length + 1)}`;\n }\n\n return value;\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"],"mappings":";AAEA,IAAM,mBAAmB;AAElB,SAAS,oBACd,OACsC;AACtC,MAAI,UAAU,QAAW;AACvB,WAAO;AAAA,EACT;AAEA,UAAQ,OAAO;AAAA,IACb,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AACH,aAAO;AAAA,IACT;AACE,YAAM,IAAI;AAAA,QACR,qBAAqB,KAAK;AAAA,MAC5B;AAAA,EACJ;AACF;AAEO,SAAS,qBAAqB,OAAuB;AAC1D,QAAM,UAAU,MAAM,KAAK;AAC3B,MAAI,YAAY,OAAO,YAAY,IAAI;AACrC,WAAO;AAAA,EACT;AAEA,QAAM,eAAe,QAAQ,QAAQ,QAAQ,EAAE;AAC/C,MAAI,iBAAiB,oBAAoB,aAAa,WAAW,GAAG,gBAAgB,GAAG,GAAG;AACxF,WAAO;AAAA,EACT;AAEA,QAAM,CAAC,cAAc,GAAG,YAAY,IAAI,aAAa,MAAM,GAAG;AAC9D,MAAI,CAAC,cAAc;AACjB,WAAO;AAAA,EACT;AAEA,UAAQ,cAAc;AAAA,IACpB,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AACH,aAAO,GAAG,gBAAgB,IAAI,YAAY,GAAG,aAAa,SAAS,IAAI,IAAI,aAAa,KAAK,GAAG,CAAC,KAAK,EAAE;AAAA,IAC1G;AACE,aAAO,GAAG,gBAAgB,IAAI,YAAY;AAAA,EAC9C;AACF;AAEO,SAAS,+BAA+B,OAAuB;AACpE,QAAM,UAAU,MAAM,KAAK;AAC3B,MAAI,YAAY,OAAO,YAAY,IAAI;AACrC,WAAO;AAAA,EACT;AAEA,SAAO,qBAAqB,OAAO;AACrC;AAEO,SAAS,4BAA4B,OAAuB;AACjE,QAAM,aAAa,MAAM,QAAQ,QAAQ,EAAE;AAC3C,MAAI,eAAe,kBAAkB;AACnC,WAAO;AAAA,EACT;AAEA,MAAI,WAAW,WAAW,GAAG,gBAAgB,GAAG,GAAG;AACjD,WAAO,IAAI,WAAW,MAAM,iBAAiB,SAAS,CAAC,CAAC;AAAA,EAC1D;AAEA,SAAO;AACT;AAEO,SAAS,kBAAkB,OAAyD;AACzF,MAAI,UAAU,QAAW;AACvB,WAAO;AAAA,EACT;AAEA,UAAQ,OAAO;AAAA,IACb,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AACH,aAAO;AAAA,IACT;AACE,YAAM,IAAI,MAAM,oEAAoE;AAAA,EACxF;AACF;","names":[]}
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  formatCatalogPathForDisplay
3
- } from "./chunk-AS7FIJWP.js";
3
+ } from "./chunk-2Y5FMKFS.js";
4
4
  import {
5
5
  singleLine
6
6
  } from "./chunk-XQGLUQFM.js";
@@ -8,7 +8,9 @@ import {
8
8
  // src/features/knowledges/knowledges-output.tsx
9
9
  import { Box, Text } from "ink";
10
10
  import { jsx, jsxs } from "react/jsx-runtime";
11
- function KnowCatalogSummary({ catalog }) {
11
+ function KnowCatalogSummary({
12
+ catalog
13
+ }) {
12
14
  return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
13
15
  /* @__PURE__ */ jsxs(Text, { children: [
14
16
  /* @__PURE__ */ jsx(Text, { bold: true, children: "Catalog: " }),
@@ -31,7 +33,9 @@ function KnowCatalogSummary({ catalog }) {
31
33
  ] })
32
34
  ] });
33
35
  }
34
- function KnowAudienceList({ audiences }) {
36
+ function KnowAudienceList({
37
+ audiences
38
+ }) {
35
39
  if (audiences.length === 0) {
36
40
  return /* @__PURE__ */ jsx(Text, { color: "yellow", children: "No audiences available." });
37
41
  }
@@ -71,7 +75,9 @@ function KnowSearchResults({
71
75
  /* @__PURE__ */ jsx(Text, { children: singleLine(result.description || result.contentPreview) })
72
76
  ] }, result.id)) });
73
77
  }
74
- function KnowTopicList({ topics }) {
78
+ function KnowTopicList({
79
+ topics
80
+ }) {
75
81
  return /* @__PURE__ */ jsx(Box, { flexDirection: "column", children: topics.map((topic) => /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [
76
82
  /* @__PURE__ */ jsxs(Text, { children: [
77
83
  /* @__PURE__ */ jsx(Text, { color: "cyan", children: topic.name }),
@@ -91,7 +97,9 @@ function KnowTopicList({ topics }) {
91
97
  /* @__PURE__ */ jsx(Text, { dimColor: true, children: singleLine(topic.description) })
92
98
  ] }, topic.id)) });
93
99
  }
94
- function KnowTopicFileList({ files }) {
100
+ function KnowTopicFileList({
101
+ files
102
+ }) {
95
103
  return /* @__PURE__ */ jsx(Box, { flexDirection: "column", children: files.map((file) => {
96
104
  const title = file.display_title ?? file.title ?? file.topic_name ?? "Untitled";
97
105
  return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [
@@ -108,4 +116,4 @@ export {
108
116
  KnowTopicList,
109
117
  KnowTopicFileList
110
118
  };
111
- //# sourceMappingURL=chunk-VMTXY4KQ.js.map
119
+ //# sourceMappingURL=chunk-3VDQDFHG.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/features/knowledges/knowledges-output.tsx"],"sourcesContent":["import type { CngApi } from \"@cng/client\";\nimport { Box, Text } from \"ink\";\n\nimport { singleLine } from \"../../shared/command-utils.js\";\nimport { formatCatalogPathForDisplay } from \"./knowledges-input.js\";\n\nexport function KnowCatalogSummary({\n catalog,\n}: {\n readonly catalog: CngApi.HarnessCatalogSummary;\n}) {\n return (\n <Box flexDirection=\"column\">\n <Text>\n <Text bold>Catalog: </Text>\n {catalog.name}\n </Text>\n <Text>\n <Text bold>Files: </Text>\n {catalog.files}\n </Text>\n <Text>\n <Text bold>Blobs: </Text>\n {catalog.blobs}\n </Text>\n <Text>\n <Text bold>Database: </Text>\n {catalog.database.engine} ({catalog.database.binding})\n </Text>\n </Box>\n );\n}\n\nexport function KnowAudienceList({\n audiences,\n}: {\n readonly audiences: readonly CngApi.HarnessAudience[];\n}) {\n if (audiences.length === 0) {\n return <Text color=\"yellow\">No audiences available.</Text>;\n }\n\n return (\n <Box flexDirection=\"column\">\n {audiences.map((audience) => (\n <Box flexDirection=\"column\" key={audience.id} marginBottom={1}>\n <Text>\n <Text color=\"cyan\">{audience.id}</Text>\n <Text> - {audience.label}</Text>\n </Text>\n <Text dimColor>{singleLine(audience.help)}</Text>\n </Box>\n ))}\n </Box>\n );\n}\n\nexport function KnowSearchResults({\n results,\n}: {\n readonly results: readonly CngApi.HarnessSemanticSearchResult[];\n}) {\n return (\n <Box flexDirection=\"column\">\n {results.map((result, index) => (\n <Box flexDirection=\"column\" key={result.id} marginBottom={1}>\n <Text>\n <Text color=\"cyan\">{index + 1}. </Text>\n <Text bold>{result.title}</Text>\n <Text dimColor> ({result.topicName})</Text>\n </Text>\n <Text dimColor>\n score {result.score.toFixed(3)} | {formatCatalogPathForDisplay(result.path)}\n </Text>\n <Text>{singleLine(result.description || result.contentPreview)}</Text>\n </Box>\n ))}\n </Box>\n );\n}\n\nexport function KnowTopicList({\n topics,\n}: {\n readonly topics: readonly CngApi.HarnessTopicSummary[];\n}) {\n return (\n <Box flexDirection=\"column\">\n {topics.map((topic) => (\n <Box flexDirection=\"column\" key={topic.id} marginBottom={1}>\n <Text>\n <Text color=\"cyan\">{topic.name}</Text>\n <Text dimColor> [{topic.type}]</Text>\n </Text>\n <Text>\n {topic.title} | files {topic.fileCount} | rating {topic.rating}\n </Text>\n <Text dimColor>{singleLine(topic.description)}</Text>\n </Box>\n ))}\n </Box>\n );\n}\n\nexport function KnowTopicFileList({\n files,\n}: {\n readonly files: readonly CngApi.HarnessTopicAsset[];\n}) {\n return (\n <Box flexDirection=\"column\">\n {files.map((file) => {\n const title = file.display_title ?? file.title ?? file.topic_name ?? \"Untitled\";\n\n return (\n <Box flexDirection=\"column\" key={`${file.path}-${file.sha256}`} marginBottom={1}>\n <Text color=\"cyan\">{formatCatalogPathForDisplay(file.path)}</Text>\n <Text dimColor>{title}</Text>\n </Box>\n );\n })}\n </Box>\n );\n}\n"],"mappings":"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","names":[]}
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  formatError,
3
3
  resolveOutputFormat
4
- } from "./chunk-DCW4RKLC.js";
4
+ } from "./chunk-H5LPFVPJ.js";
5
5
 
6
6
  // src/cli/command-runner.tsx
7
7
  import { useCallback, useEffect as useEffect2, useRef, useState } from "react";
@@ -154,19 +154,16 @@ function CommandOutputMessages({
154
154
  if (messages.length === 0) {
155
155
  return null;
156
156
  }
157
- return createElement(
158
- Static,
159
- {
160
- items: [...messages],
161
- style: { flexDirection: "column" },
162
- children: (message) => createElement(CommandOutputMessageView, {
163
- key: message.id,
164
- message,
165
- useColor,
166
- width
167
- })
168
- }
169
- );
157
+ return createElement(Static, {
158
+ items: [...messages],
159
+ style: { flexDirection: "column" },
160
+ children: (message) => createElement(CommandOutputMessageView, {
161
+ key: message.id,
162
+ message,
163
+ useColor,
164
+ width
165
+ })
166
+ });
170
167
  }
171
168
  function CommandOutputMessageView({
172
169
  message,
@@ -265,4 +262,4 @@ function CommandRunner({ run }) {
265
262
  export {
266
263
  CommandRunner
267
264
  };
268
- //# sourceMappingURL=chunk-TIY4RTXC.js.map
265
+ //# sourceMappingURL=chunk-4Q2LNYVU.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/cli/command-runner.tsx","../src/shared/output/factory.ts","../src/shared/output/markdown.ts","../src/shared/output/renderer.tsx","../src/shared/theme.ts"],"sourcesContent":["import { useCallback, useEffect, useRef, useState } from \"react\";\nimport { useApp } from \"ink\";\n\nimport { createCommandOutput } from \"../shared/output/factory.js\";\nimport { formatError } from \"../shared/output/errors.js\";\nimport { CommandOutputMessages } from \"../shared/output/renderer.js\";\nimport type {\n CommandOutput,\n CommandOutputMessage,\n CommandOutputMessagePayload,\n} from \"../shared/output/types.js\";\n\ntype CommandRunnerProps = {\n readonly run: (output: CommandOutput) => Promise<void>;\n};\n\nexport function CommandRunner({ run }: CommandRunnerProps) {\n const { exit } = useApp();\n const nextMessageIdRef = useRef(1);\n const [messages, setMessages] = useState<CommandOutputMessage[]>([]);\n const appendMessage = useCallback((message: CommandOutputMessagePayload) => {\n const nextMessage: CommandOutputMessage = {\n ...message,\n id: nextMessageIdRef.current,\n };\n nextMessageIdRef.current += 1;\n setMessages((currentMessages) => [...currentMessages, nextMessage]);\n }, []);\n\n useEffect(() => {\n const output = createCommandOutput({\n appendMessage,\n stdout: process.stdout,\n stderr: process.stderr,\n });\n\n void run(output)\n .catch((error: unknown) => {\n process.exitCode = 1;\n output.error(formatError(error));\n })\n .finally(() => {\n setTimeout(() => exit(), 0);\n });\n }, [appendMessage, exit, run]);\n\n return <CommandOutputMessages messages={messages} />;\n}\n","import process from \"node:process\";\n\nimport { resolveOutputFormat } from \"../config.js\";\nimport { prepareMarkdownForTerminal } from \"./markdown.js\";\nimport type { CommandOutput, CommandOutputSink, OutputStream } from \"./types.js\";\n\nexport function createCommandOutput(sink: CommandOutputSink): CommandOutput {\n const stdout = sink.stdout ?? process.stdout;\n const stderr = sink.stderr ?? process.stderr;\n\n return {\n info(message) {\n appendStyledMessage(sink, stdout, \"stdout\", \"info\", message);\n },\n success(message) {\n appendStyledMessage(sink, stdout, \"stdout\", \"success\", message);\n },\n warning(message) {\n appendStyledMessage(sink, stdout, \"stdout\", \"warning\", message);\n },\n muted(message) {\n appendStyledMessage(sink, stdout, \"stdout\", \"muted\", message);\n },\n markdown(message) {\n if (resolveOutputFormat() === \"markdown\") {\n stdout.write(`${message}\\n`);\n return;\n }\n\n if (sink.appendMessage) {\n sink.appendMessage({ kind: \"markdown\", message: prepareMarkdownForTerminal(message) });\n return;\n }\n\n stdout.write(`${message}\\n`);\n },\n component(element) {\n if (sink.appendMessage) {\n sink.appendMessage({ kind: \"component\", element });\n return;\n }\n\n stdout.write(\"\\n\");\n },\n raw(message) {\n stdout.write(`${message}\\n`);\n },\n error(message) {\n appendStyledMessage(sink, stderr, \"stderr\", \"error\", message);\n },\n };\n}\n\nfunction appendStyledMessage(\n sink: CommandOutputSink,\n stream: OutputStream,\n streamName: \"stdout\" | \"stderr\",\n style: \"info\" | \"success\" | \"warning\" | \"muted\" | \"error\",\n message: string\n): void {\n if (sink.appendMessage) {\n sink.appendMessage({ kind: \"styled\", stream: streamName, style, message });\n return;\n }\n\n stream.write(`${message}\\n`);\n}\n","export function prepareMarkdownForTerminal(markdown: string): string {\n if (!markdown.startsWith(\"---\\n\")) {\n return markdown;\n }\n\n const frontmatterEndIndex = markdown.indexOf(\"\\n---\", 4);\n if (frontmatterEndIndex < 0) {\n return formatFrontmatterForTerminal(markdown.slice(4).trimEnd());\n }\n\n const frontmatter = markdown.slice(4, frontmatterEndIndex).trimEnd();\n const body = markdown.slice(frontmatterEndIndex + \"\\n---\".length).replace(/^\\n+/, \"\");\n\n return `${formatFrontmatterForTerminal(frontmatter)}\\n\\n${body}`;\n}\n\nexport function formatFrontmatterForTerminal(frontmatter: string): string {\n return `## Metadata\\n\\n\\`\\`\\`yaml\\n${frontmatter}\\n\\`\\`\\``;\n}\n","import process from \"node:process\";\nimport { createElement, useEffect, type ReactElement } from \"react\";\nimport { Static, Text, useStderr, useStdout } from \"ink\";\nimport Markdown from \"@inkkit/ink-markdown\";\n\nimport { createMarkdownTheme, statusStylePropsByOutputStyle } from \"../theme.js\";\nimport type { CommandOutputMessage, OutputStream } from \"./types.js\";\n\nexport function CommandOutputMessages({\n messages,\n}: {\n readonly messages: readonly CommandOutputMessage[];\n}): ReactElement | null {\n const { stdout } = useStdout();\n const width = clampMarkdownWidth(stdout.columns);\n const useColor = shouldRenderColor(stdout);\n\n if (messages.length === 0) {\n return null;\n }\n\n return createElement(Static<CommandOutputMessage>, {\n items: [...messages],\n style: { flexDirection: \"column\" },\n children: (message: CommandOutputMessage) =>\n createElement(CommandOutputMessageView, {\n key: message.id,\n message,\n useColor,\n width,\n }),\n });\n}\n\nfunction CommandOutputMessageView({\n message,\n useColor,\n width,\n}: {\n readonly message: CommandOutputMessage;\n readonly useColor: boolean;\n readonly width: number;\n}): ReactElement {\n if (message.kind === \"styled\") {\n if (message.stream === \"stderr\") {\n return createElement(StderrLine, { message: message.message });\n }\n\n return createElement(\n Text,\n {\n ...statusStylePropsByOutputStyle[message.style],\n wrap: \"wrap\",\n },\n message.message\n );\n }\n\n if (message.kind === \"markdown\") {\n return createElement(\n Markdown,\n {\n ...createMarkdownTheme(useColor),\n width,\n },\n message.message\n );\n }\n\n return message.element;\n}\n\nfunction StderrLine({ message }: { readonly message: string }): null {\n const { write } = useStderr();\n\n useEffect(() => {\n write(`${message}\\n`);\n }, [message, write]);\n\n return null;\n}\n\nfunction shouldRenderColor(stream: OutputStream): boolean {\n if (process.env.CNGKIT_NO_COLOR === \"1\") {\n return false;\n }\n\n const colorMode = process.env.CNGKIT_COLOR?.toLowerCase();\n\n if (colorMode === \"never\" || colorMode === \"0\" || colorMode === \"false\") {\n return false;\n }\n\n if (colorMode === \"always\" || colorMode === \"1\" || colorMode === \"true\") {\n return true;\n }\n\n if (process.env.FORCE_COLOR !== undefined && process.env.FORCE_COLOR !== \"0\") {\n return true;\n }\n\n if (process.env.NO_COLOR !== undefined) {\n return false;\n }\n\n return stream.isTTY === true;\n}\n\nfunction clampMarkdownWidth(columns: number | undefined): number {\n if (columns === undefined) {\n return 100;\n }\n\n return Math.max(72, Math.min(columns, 120));\n}\n","import { Chalk } from \"chalk\";\nimport type { TextProps } from \"ink\";\n\nexport type OutputStyle = \"info\" | \"success\" | \"warning\" | \"muted\" | \"error\";\n\nexport const statusStylePropsByOutputStyle = {\n info: {\n color: \"cyan\",\n },\n success: {\n color: \"green\",\n bold: true,\n },\n warning: {\n color: \"yellow\",\n bold: true,\n },\n muted: {\n dimColor: true,\n },\n error: {\n color: \"red\",\n bold: true,\n },\n} satisfies Record<OutputStyle, TextProps>;\n\nexport function createMarkdownTheme(useColor: boolean) {\n const chalk = new Chalk({ level: useColor ? 1 : 0 });\n const identity = (value: string) => value;\n\n return {\n code: chalk.green,\n blockquote: chalk.dim.italic,\n html: chalk.gray,\n heading: chalk.blueBright.bold,\n firstHeading: chalk.magentaBright.bold,\n hr: chalk.gray,\n listitem: identity,\n table: identity,\n paragraph: identity,\n strong: chalk.bold,\n em: chalk.italic,\n codespan: chalk.cyanBright,\n del: chalk.dim.strikethrough,\n link: chalk.blueBright,\n href: chalk.blue.underline,\n text: identity,\n showSectionPrefix: false,\n reflowText: true,\n unescape: true,\n emoji: false,\n tab: 2,\n };\n}\n"],"mappings":"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","names":["useEffect","process","process","process","process","useEffect"]}
@@ -1,13 +1,35 @@
1
1
  import {
2
2
  createCngApiClient,
3
3
  readBackendHealth
4
- } from "./chunk-N255PYL7.js";
4
+ } from "./chunk-SRZRHLRJ.js";
5
5
  import {
6
6
  resolveApiBaseUrl
7
- } from "./chunk-DCW4RKLC.js";
7
+ } from "./chunk-H5LPFVPJ.js";
8
8
 
9
9
  // src/features/coderoom/run-coderoom-command.ts
10
10
  import process3 from "process";
11
+ import { createElement } from "react";
12
+
13
+ // src/features/coderoom/coderoom-output.tsx
14
+ import { Box, Text } from "ink";
15
+ import { jsx, jsxs } from "react/jsx-runtime";
16
+ function CoderoomShareCard({
17
+ roomCode,
18
+ command
19
+ }) {
20
+ return /* @__PURE__ */ jsxs(Box, { borderStyle: "round", borderColor: "cyan", flexDirection: "column", paddingX: 1, marginY: 1, children: [
21
+ /* @__PURE__ */ jsx(Text, { bold: true, color: "cyan", children: "Share this Coderoom" }),
22
+ /* @__PURE__ */ jsxs(Text, { children: [
23
+ "Room code: ",
24
+ roomCode
25
+ ] }),
26
+ /* @__PURE__ */ jsxs(Box, { marginTop: 1, flexDirection: "column", children: [
27
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "Send this command to your partner:" }),
28
+ /* @__PURE__ */ jsx(Text, { color: "green", children: command })
29
+ ] }),
30
+ /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(Text, { dimColor: true, children: "Keep this terminal running while they join." }) })
31
+ ] });
32
+ }
11
33
 
12
34
  // src/features/coderoom/sync/client.ts
13
35
  import WebSocket2 from "ws";
@@ -70,7 +92,7 @@ async function shouldSyncRelativePath(context, relativePath) {
70
92
  return false;
71
93
  } catch (error) {
72
94
  const exitCode = typeof error === "object" && error !== null && "code" in error ? error.code : void 0;
73
- return exitCode === 1;
95
+ return exitCode !== 0;
74
96
  }
75
97
  }
76
98
 
@@ -292,6 +314,9 @@ function createSyncWebSocketUrl(options) {
292
314
  if (options.creatorToken) {
293
315
  url.searchParams.set("creatorToken", options.creatorToken);
294
316
  }
317
+ if (options.acceptanceToken) {
318
+ url.searchParams.set("acceptanceToken", options.acceptanceToken);
319
+ }
295
320
  return url.toString();
296
321
  }
297
322
  function sendMessage(socket, message) {
@@ -303,10 +328,12 @@ function createDisplayName() {
303
328
  const username = os.userInfo().username || "user";
304
329
  return `${username}@${os.hostname()}`;
305
330
  }
306
- async function waitForSessionClose(socket, watcher) {
331
+ async function waitForSessionClose(socket, watcher, output) {
307
332
  await new Promise((resolve, reject) => {
308
333
  let settled = false;
334
+ let shutdownRequested = false;
309
335
  const closeSession = async () => {
336
+ output.info("Closing Coderoom session...");
310
337
  await watcher.close();
311
338
  if (socket.readyState === WebSocket.OPEN || socket.readyState === WebSocket.CONNECTING) {
312
339
  socket.close();
@@ -320,9 +347,14 @@ async function waitForSessionClose(socket, watcher) {
320
347
  process.off("SIGINT", onSignal);
321
348
  process.off("SIGTERM", onSignal);
322
349
  await closeSession();
350
+ if (shutdownRequested) {
351
+ output.success("Coderoom session closed.");
352
+ }
323
353
  resolve();
324
354
  };
325
355
  const onSignal = () => {
356
+ shutdownRequested = true;
357
+ output.warning("Shutdown requested. Closing Coderoom cleanly...");
326
358
  void finish();
327
359
  };
328
360
  socket.on("error", async (error) => {
@@ -336,6 +368,9 @@ async function waitForSessionClose(socket, watcher) {
336
368
  reject(error);
337
369
  });
338
370
  socket.on("close", () => {
371
+ if (!shutdownRequested) {
372
+ output.warning("Coderoom socket closed.");
373
+ }
339
374
  void finish();
340
375
  });
341
376
  process.on("SIGINT", onSignal);
@@ -378,11 +413,19 @@ function createRepoWatcher(context) {
378
413
  }
379
414
  async function sendInitialSnapshot(socket, repoContext, output) {
380
415
  let fileCount = 0;
416
+ let totalBytes = 0;
417
+ output.info("Scanning files for initial Coderoom snapshot...");
381
418
  for await (const message of collectSnapshotMessages(repoContext)) {
419
+ if (message.type !== "file") {
420
+ continue;
421
+ }
422
+ const byteCount = Buffer.byteLength(message.contentBase64, "base64");
423
+ totalBytes += byteCount;
382
424
  sendMessage(socket, message);
383
425
  fileCount += 1;
426
+ output.info(`uploaded snapshot file ${message.path} (${formatByteCount(byteCount)})`);
384
427
  }
385
- output.success(`sent snapshot ${fileCount} files`);
428
+ output.success(`sent snapshot ${fileCount} files (${formatByteCount(totalBytes)})`);
386
429
  }
387
430
  async function sendLocalFileChange(context, absolutePath) {
388
431
  if (!context.state.approved) {
@@ -393,11 +436,13 @@ async function sendLocalFileChange(context, absolutePath) {
393
436
  return;
394
437
  }
395
438
  const message = await buildFileMessage(context.repoContext, relativePath);
396
- if (!message) {
439
+ if (!message || message.type !== "file") {
397
440
  return;
398
441
  }
399
442
  sendMessage(context.socket, message);
400
- context.output.muted(`sent file ${relativePath}`);
443
+ context.output.info(
444
+ `uploaded file ${relativePath} (${formatByteCount(Buffer.byteLength(message.contentBase64, "base64"))})`
445
+ );
401
446
  }
402
447
  async function sendLocalDelete(context, absolutePath) {
403
448
  if (!context.state.approved) {
@@ -415,7 +460,17 @@ async function sendLocalDelete(context, absolutePath) {
415
460
  path: relativePath,
416
461
  mtimeMs: Date.now()
417
462
  });
418
- context.output.warning(`sent delete ${relativePath}`);
463
+ context.output.warning(`uploaded delete ${relativePath}`);
464
+ }
465
+ function formatByteCount(byteCount) {
466
+ if (byteCount < 1024) {
467
+ return `${byteCount} B`;
468
+ }
469
+ const kibibytes = byteCount / 1024;
470
+ if (kibibytes < 1024) {
471
+ return `${kibibytes.toFixed(1)} KiB`;
472
+ }
473
+ return `${(kibibytes / 1024).toFixed(1)} MiB`;
419
474
  }
420
475
 
421
476
  // src/features/coderoom/sync/remote-handler.ts
@@ -459,8 +514,8 @@ async function handleServerMessage(options) {
459
514
  return;
460
515
  }
461
516
  if (decodedMessage.type === "file-ack") {
462
- options.output.muted(
463
- `stored ${decodedMessage.storage} ${decodedMessage.path} ${decodedMessage.sha256}`
517
+ options.output.info(
518
+ `stored ${decodedMessage.storage} ${decodedMessage.path} (${formatByteCount2(decodedMessage.size)}) ${decodedMessage.sha256}`
464
519
  );
465
520
  return;
466
521
  }
@@ -471,6 +526,16 @@ async function handleServerMessage(options) {
471
526
  await applyRemoteMessage(options.repoContext, decodedMessage, options.suppressionTracker);
472
527
  options.output.success(`applied ${decodedMessage.type} ${decodedMessage.path}`);
473
528
  }
529
+ function formatByteCount2(byteCount) {
530
+ if (byteCount < 1024) {
531
+ return `${byteCount} B`;
532
+ }
533
+ const kibibytes = byteCount / 1024;
534
+ if (kibibytes < 1024) {
535
+ return `${kibibytes.toFixed(1)} KiB`;
536
+ }
537
+ return `${(kibibytes / 1024).toFixed(1)} MiB`;
538
+ }
474
539
  async function approveJoinRequest(socket, message, output) {
475
540
  const approved = await askForApproval(message, output);
476
541
  sendMessage(socket, {
@@ -525,6 +590,10 @@ async function startSyncSession(options) {
525
590
  void sendInitialSnapshot(socket, repoContext, options.output);
526
591
  return;
527
592
  }
593
+ if (options.acceptanceToken) {
594
+ options.output.info("Using acceptance token. Waiting for room tree...");
595
+ return;
596
+ }
528
597
  options.output.info("Waiting for host approval...");
529
598
  });
530
599
  socket.on("message", (data) => {
@@ -537,22 +606,23 @@ async function startSyncSession(options) {
537
606
  output: options.output
538
607
  });
539
608
  });
540
- await waitForSessionClose(socket, watcher);
609
+ await waitForSessionClose(socket, watcher, options.output);
541
610
  }
542
611
 
543
612
  // src/features/coderoom/run-coderoom-command.ts
544
613
  async function runShareCommand(options, output) {
545
614
  const room = await createCoderoomRoom(options);
546
615
  output.success(`Share code: ${room.roomCode}`);
616
+ printPartnerJoinBox(room, output);
547
617
  await printBackendStatus(options, output);
548
- await runSyncSession("host", room.roomCode, room.creatorToken, options, output);
618
+ await runSyncSession("host", room.roomCode, room.creatorToken, void 0, options, output);
549
619
  }
550
620
  async function runJoinCommand(roomCode, options, output) {
551
621
  if (!roomCode) {
552
622
  throw new Error("Missing room code. Usage: cngkit coderoom join <room-code>");
553
623
  }
554
624
  await printBackendStatus(options, output);
555
- await runSyncSession("guest", roomCode, void 0, options, output);
625
+ await runSyncSession("guest", roomCode, void 0, options.acceptanceToken, options, output);
556
626
  }
557
627
  async function printBackendStatus(options, output) {
558
628
  const health = await readBackendHealth(options);
@@ -562,11 +632,12 @@ async function printBackendStatus(options, output) {
562
632
  }
563
633
  output.warning(`API: unavailable (${health.message})`);
564
634
  }
565
- async function runSyncSession(role, roomCode, creatorToken, options, output) {
635
+ async function runSyncSession(role, roomCode, creatorToken, acceptanceToken, options, output) {
566
636
  await startSyncSession({
567
637
  apiBaseUrl: resolveApiBaseUrl(options),
568
638
  roomCode,
569
639
  creatorToken,
640
+ acceptanceToken,
570
641
  role,
571
642
  cwd: process3.cwd(),
572
643
  output
@@ -576,9 +647,13 @@ async function createCoderoomRoom(options) {
576
647
  const client = createCngApiClient(options);
577
648
  return client.coderoom.createCoderoomRoom();
578
649
  }
650
+ function printPartnerJoinBox(room, output) {
651
+ const command = `npx --yes cngkit@latest coderoom join ${room.roomCode} --acceptance-token ${room.acceptanceToken}`;
652
+ output.component(createElement(CoderoomShareCard, { roomCode: room.roomCode, command }));
653
+ }
579
654
 
580
655
  export {
581
656
  runShareCommand,
582
657
  runJoinCommand
583
658
  };
584
- //# sourceMappingURL=chunk-KURN5BJ6.js.map
659
+ //# sourceMappingURL=chunk-EG3QD47O.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/features/coderoom/run-coderoom-command.ts","../src/features/coderoom/coderoom-output.tsx","../src/features/coderoom/sync/client.ts","../src/features/coderoom/sync/files.ts","../src/features/coderoom/sync/paths.ts","../src/features/coderoom/sync/local-events.ts","../src/features/coderoom/sync/session.ts","../src/features/coderoom/sync/protocol.ts","../src/features/coderoom/sync/remote-handler.ts"],"sourcesContent":["import process from \"node:process\";\nimport { createElement } from \"react\";\n\nimport { createCngApiClient, readBackendHealth } from \"../../shared/api-client.js\";\nimport { resolveApiBaseUrl, type GlobalCommandOptions } from \"../../shared/config.js\";\nimport type { CommandOutput } from \"../../shared/output/types.js\";\nimport { CoderoomShareCard } from \"./coderoom-output.js\";\nimport { startSyncSession, type SyncSessionRole } from \"./sync/client.js\";\n\nexport type CoderoomCommandOptions = GlobalCommandOptions;\n\nexport type ShareCommandOptions = GlobalCommandOptions;\nexport type JoinCommandOptions = GlobalCommandOptions & {\n readonly acceptanceToken?: string;\n};\n\nexport async function runCoderoomCommand(\n args: string[] | undefined,\n options: CoderoomCommandOptions,\n output: CommandOutput\n): Promise<void> {\n const [subcommand, ...subcommandArgs] = args ?? [];\n\n switch (subcommand) {\n case \"share\":\n return runShareCommand(options, output);\n case \"join\":\n return runJoinCommand(subcommandArgs[0], options, output);\n default:\n throw new Error(\"Missing coderoom command. Usage: cngkit coderoom <share|join>\");\n }\n}\n\nexport async function runShareCommand(\n options: ShareCommandOptions,\n output: CommandOutput\n): Promise<void> {\n const room = await createCoderoomRoom(options);\n\n output.success(`Share code: ${room.roomCode}`);\n printPartnerJoinBox(room, output);\n await printBackendStatus(options, output);\n await runSyncSession(\"host\", room.roomCode, room.creatorToken, undefined, options, output);\n}\n\nexport async function runJoinCommand(\n roomCode: string | undefined,\n options: JoinCommandOptions,\n output: CommandOutput\n): Promise<void> {\n if (!roomCode) {\n throw new Error(\"Missing room code. Usage: cngkit coderoom join <room-code>\");\n }\n\n await printBackendStatus(options, output);\n await runSyncSession(\"guest\", roomCode, undefined, options.acceptanceToken, options, output);\n}\n\nasync function printBackendStatus(\n options: GlobalCommandOptions,\n output: CommandOutput\n): Promise<void> {\n const health = await readBackendHealth(options);\n if (health.ok) {\n output.success(`API: ${health.service} ready`);\n return;\n }\n\n output.warning(`API: unavailable (${health.message})`);\n}\n\nasync function runSyncSession(\n role: SyncSessionRole,\n roomCode: string,\n creatorToken: string | undefined,\n acceptanceToken: string | undefined,\n options: GlobalCommandOptions,\n output: CommandOutput\n): Promise<void> {\n await startSyncSession({\n apiBaseUrl: resolveApiBaseUrl(options),\n roomCode,\n creatorToken,\n acceptanceToken,\n role,\n cwd: process.cwd(),\n output,\n });\n}\n\nasync function createCoderoomRoom(options: GlobalCommandOptions): Promise<{\n roomCode: string;\n creatorToken: string;\n acceptanceToken: string;\n}> {\n const client = createCngApiClient(options);\n return client.coderoom.createCoderoomRoom();\n}\n\nfunction printPartnerJoinBox(\n room: {\n roomCode: string;\n acceptanceToken: string;\n },\n output: CommandOutput\n): void {\n const command = `npx --yes cngkit@latest coderoom join ${room.roomCode} --acceptance-token ${room.acceptanceToken}`;\n output.component(createElement(CoderoomShareCard, { roomCode: room.roomCode, command }));\n}\n","import { Box, Text } from \"ink\";\n\nexport function CoderoomShareCard({\n roomCode,\n command,\n}: {\n readonly roomCode: string;\n readonly command: string;\n}) {\n return (\n <Box borderStyle=\"round\" borderColor=\"cyan\" flexDirection=\"column\" paddingX={1} marginY={1}>\n <Text bold color=\"cyan\">\n Share this Coderoom\n </Text>\n <Text>Room code: {roomCode}</Text>\n <Box marginTop={1} flexDirection=\"column\">\n <Text dimColor>Send this command to your partner:</Text>\n <Text color=\"green\">{command}</Text>\n </Box>\n <Box marginTop={1}>\n <Text dimColor>Keep this terminal running while they join.</Text>\n </Box>\n </Box>\n );\n}\n","// Public API entrypoint for the coderoom sync client. Implementation lives in\n// `./session.ts` (WebSocket lifecycle), `./local-events.ts` (file watcher +\n// outbound events), and `./remote-handler.ts` (inbound message dispatch).\n\nimport WebSocket from \"ws\";\n\nimport { createSuppressionTracker } from \"./files.js\";\nimport { createRepoWatcher, sendInitialSnapshot, type WatcherContext } from \"./local-events.js\";\nimport { resolveRepoContext } from \"./paths.js\";\nimport { handleServerMessage } from \"./remote-handler.js\";\nimport { createSyncWebSocketUrl, waitForSessionClose } from \"./session.js\";\nimport type { CommandOutput } from \"../../../shared/output/types.js\";\n\nexport type SyncSessionRole = \"host\" | \"guest\";\n\nexport type StartSyncSessionOptions = {\n apiBaseUrl: string;\n roomCode: string;\n creatorToken?: string;\n acceptanceToken?: string;\n role: SyncSessionRole;\n cwd: string;\n output: CommandOutput;\n};\n\nexport async function startSyncSession(options: StartSyncSessionOptions): Promise<void> {\n const repoContext = await resolveRepoContext(options.cwd);\n const suppressionTracker = createSuppressionTracker();\n const webSocketUrl = createSyncWebSocketUrl(options);\n const socket = new WebSocket(webSocketUrl);\n const state = {\n approved: options.role === \"host\",\n participantId: undefined as string | undefined,\n };\n\n options.output.success(`Room: ${options.roomCode}`);\n options.output.info(`Repo: ${repoContext.rootDir}`);\n\n const watcherContext: WatcherContext = {\n repoContext,\n socket,\n state,\n suppressionTracker,\n output: options.output,\n };\n const watcher = createRepoWatcher(watcherContext);\n\n socket.on(\"open\", () => {\n if (options.role === \"host\") {\n void sendInitialSnapshot(socket, repoContext, options.output);\n return;\n }\n\n if (options.acceptanceToken) {\n options.output.info(\"Using acceptance token. Waiting for room tree...\");\n return;\n }\n\n options.output.info(\"Waiting for host approval...\");\n });\n\n socket.on(\"message\", (data) => {\n void handleServerMessage({\n data,\n socket,\n repoContext,\n state,\n suppressionTracker,\n output: options.output,\n });\n });\n\n await waitForSessionClose(socket, watcher, options.output);\n}\n","import fs from \"node:fs/promises\";\nimport path from \"node:path\";\n\nimport type { ClientMessage, ServerFileMutationMessage } from \"./protocol.js\";\nimport {\n resolveRepoPath,\n shouldSyncRelativePath,\n toRepoRelativePath,\n type RepoContext,\n} from \"./paths.js\";\n\nexport type SuppressionTracker = {\n suppress(relativePath: string): void;\n isSuppressed(relativePath: string): boolean;\n};\n\nexport function createSuppressionTracker(windowMs = 1500): SuppressionTracker {\n const suppressedUntilByPath = new Map<string, number>();\n\n return {\n suppress(relativePath: string) {\n suppressedUntilByPath.set(relativePath, Date.now() + windowMs);\n },\n isSuppressed(relativePath: string) {\n const suppressedUntil = suppressedUntilByPath.get(relativePath);\n if (!suppressedUntil) {\n return false;\n }\n if (suppressedUntil < Date.now()) {\n suppressedUntilByPath.delete(relativePath);\n return false;\n }\n return true;\n },\n };\n}\n\nexport async function* collectSnapshotMessages(\n context: RepoContext\n): AsyncGenerator<ClientMessage> {\n yield* collectDirectorySnapshot(context, context.rootDir);\n}\n\nasync function* collectDirectorySnapshot(\n context: RepoContext,\n directoryPath: string\n): AsyncGenerator<ClientMessage> {\n const entries = await fs.opendir(directoryPath);\n\n for await (const entry of entries) {\n const absolutePath = path.join(directoryPath, entry.name);\n const relativePath = toRepoRelativePath(context.rootDir, absolutePath);\n\n if (!relativePath || !(await shouldSyncRelativePath(context, relativePath))) {\n continue;\n }\n\n if (entry.isDirectory()) {\n yield* collectDirectorySnapshot(context, absolutePath);\n continue;\n }\n\n if (!entry.isFile()) {\n continue;\n }\n\n const [content, stat] = await Promise.all([fs.readFile(absolutePath), fs.stat(absolutePath)]);\n yield {\n type: \"file\",\n path: relativePath,\n contentBase64: content.toString(\"base64\"),\n mtimeMs: stat.mtimeMs,\n };\n }\n}\n\nexport async function buildFileMessage(\n context: RepoContext,\n relativePath: string\n): Promise<ClientMessage | undefined> {\n if (!(await shouldSyncRelativePath(context, relativePath))) {\n return undefined;\n }\n\n const absolutePath = resolveRepoPath(context.rootDir, relativePath);\n if (!absolutePath) {\n return undefined;\n }\n\n const stat = await fs.stat(absolutePath);\n if (!stat.isFile()) {\n return undefined;\n }\n\n const content = await fs.readFile(absolutePath);\n return {\n type: \"file\",\n path: relativePath,\n contentBase64: content.toString(\"base64\"),\n mtimeMs: stat.mtimeMs,\n };\n}\n\nexport async function applyRemoteMessage(\n context: RepoContext,\n message: ServerFileMutationMessage,\n suppressionTracker: SuppressionTracker\n): Promise<void> {\n const absolutePath = resolveRepoPath(context.rootDir, message.path);\n if (!absolutePath || !(await shouldSyncRelativePath(context, message.path))) {\n return;\n }\n\n suppressionTracker.suppress(message.path);\n\n if (message.type === \"delete\") {\n await fs.rm(absolutePath, { force: true });\n return;\n }\n\n await fs.mkdir(path.dirname(absolutePath), { recursive: true });\n await fs.writeFile(absolutePath, Buffer.from(message.contentBase64, \"base64\"));\n}\n","import { execFile } from \"node:child_process\";\nimport path from \"node:path\";\nimport { promisify } from \"node:util\";\n\nconst execFileAsync = promisify(execFile);\n\nexport type RepoContext = {\n rootDir: string;\n};\n\nexport async function resolveRepoContext(cwd: string): Promise<RepoContext> {\n try {\n const { stdout } = await execFileAsync(\"git\", [\"rev-parse\", \"--show-toplevel\"], {\n cwd,\n });\n return { rootDir: path.resolve(stdout.trim()) };\n } catch {\n return { rootDir: path.resolve(cwd) };\n }\n}\n\nexport function toRepoRelativePath(rootDir: string, absolutePath: string): string | undefined {\n const relativePath = path.relative(rootDir, absolutePath);\n\n if (!relativePath || relativePath.startsWith(\"..\") || path.isAbsolute(relativePath)) {\n return undefined;\n }\n\n return relativePath.split(path.sep).join(\"/\");\n}\n\nexport function resolveRepoPath(rootDir: string, relativePath: string): string | undefined {\n if (!isSafeRelativePath(relativePath)) {\n return undefined;\n }\n\n const absolutePath = path.resolve(rootDir, relativePath);\n const normalizedRoot = `${path.resolve(rootDir)}${path.sep}`;\n\n if (absolutePath !== path.resolve(rootDir) && !absolutePath.startsWith(normalizedRoot)) {\n return undefined;\n }\n\n return absolutePath;\n}\n\nexport function isSafeRelativePath(relativePath: string): boolean {\n if (!relativePath || relativePath.startsWith(\"/\") || relativePath.includes(\"\\0\")) {\n return false;\n }\n\n const normalizedParts = relativePath.split(/[\\\\/]+/).filter(Boolean);\n if (normalizedParts.includes(\"..\")) {\n return false;\n }\n\n return normalizedParts[0] !== \".git\";\n}\n\nexport async function shouldSyncRelativePath(\n context: RepoContext,\n relativePath: string\n): Promise<boolean> {\n if (!isSafeRelativePath(relativePath)) {\n return false;\n }\n\n try {\n await execFileAsync(\"git\", [\"check-ignore\", \"--quiet\", \"--\", relativePath], {\n cwd: context.rootDir,\n });\n return false;\n } catch (error) {\n const exitCode =\n typeof error === \"object\" && error !== null && \"code\" in error ? error.code : undefined;\n return exitCode !== 0;\n }\n}\n","import fs from \"node:fs\";\n\nimport chokidar, { type FSWatcher } from \"chokidar\";\nimport WebSocket from \"ws\";\n\nimport type { CommandOutput } from \"../../../shared/output/types.js\";\nimport { buildFileMessage, collectSnapshotMessages, type SuppressionTracker } from \"./files.js\";\nimport { shouldSyncRelativePath, toRepoRelativePath, type RepoContext } from \"./paths.js\";\nimport { sendMessage } from \"./session.js\";\n\ntype SessionState = {\n approved: boolean;\n participantId?: string;\n};\n\nexport type WatcherContext = {\n repoContext: RepoContext;\n socket: WebSocket;\n state: SessionState;\n suppressionTracker: SuppressionTracker;\n output: CommandOutput;\n};\n\nexport function createRepoWatcher(context: WatcherContext): FSWatcher {\n const watcher = chokidar.watch(context.repoContext.rootDir, {\n ignoreInitial: true,\n ignored: (candidatePath) => {\n const relativePath = toRepoRelativePath(context.repoContext.rootDir, candidatePath);\n if (relativePath?.split(\"/\").includes(\".git\") ?? false) {\n return true;\n }\n try {\n const stat = fs.statSync(candidatePath);\n return !stat.isFile() && !stat.isDirectory();\n } catch {\n return false;\n }\n },\n });\n\n watcher.on(\"add\", (absolutePath) => {\n void sendLocalFileChange(context, absolutePath);\n });\n watcher.on(\"change\", (absolutePath) => {\n void sendLocalFileChange(context, absolutePath);\n });\n watcher.on(\"unlink\", (absolutePath) => {\n void sendLocalDelete(context, absolutePath);\n });\n watcher.on(\"error\", (watcherError) => {\n context.output.warning(\n `watcher error: ${watcherError instanceof Error ? watcherError.message : String(watcherError)}`\n );\n });\n\n return watcher;\n}\n\nexport async function sendInitialSnapshot(\n socket: WebSocket,\n repoContext: RepoContext,\n output: CommandOutput\n): Promise<void> {\n let fileCount = 0;\n let totalBytes = 0;\n\n output.info(\"Scanning files for initial Coderoom snapshot...\");\n for await (const message of collectSnapshotMessages(repoContext)) {\n if (message.type !== \"file\") {\n continue;\n }\n\n const byteCount = Buffer.byteLength(message.contentBase64, \"base64\");\n totalBytes += byteCount;\n sendMessage(socket, message);\n fileCount += 1;\n output.info(`uploaded snapshot file ${message.path} (${formatByteCount(byteCount)})`);\n }\n\n output.success(`sent snapshot ${fileCount} files (${formatByteCount(totalBytes)})`);\n}\n\nasync function sendLocalFileChange(context: WatcherContext, absolutePath: string): Promise<void> {\n if (!context.state.approved) {\n return;\n }\n\n const relativePath = toRepoRelativePath(context.repoContext.rootDir, absolutePath);\n if (!relativePath || context.suppressionTracker.isSuppressed(relativePath)) {\n return;\n }\n\n const message = await buildFileMessage(context.repoContext, relativePath);\n if (!message || message.type !== \"file\") {\n return;\n }\n\n sendMessage(context.socket, message);\n context.output.info(\n `uploaded file ${relativePath} (${formatByteCount(Buffer.byteLength(message.contentBase64, \"base64\"))})`\n );\n}\n\nasync function sendLocalDelete(context: WatcherContext, absolutePath: string): Promise<void> {\n if (!context.state.approved) {\n return;\n }\n\n const relativePath = toRepoRelativePath(context.repoContext.rootDir, absolutePath);\n if (!relativePath || context.suppressionTracker.isSuppressed(relativePath)) {\n return;\n }\n\n if (!(await shouldSyncRelativePath(context.repoContext, relativePath))) {\n return;\n }\n\n sendMessage(context.socket, {\n type: \"delete\",\n path: relativePath,\n mtimeMs: Date.now(),\n });\n context.output.warning(`uploaded delete ${relativePath}`);\n}\n\nfunction formatByteCount(byteCount: number): string {\n if (byteCount < 1024) {\n return `${byteCount} B`;\n }\n\n const kibibytes = byteCount / 1024;\n if (kibibytes < 1024) {\n return `${kibibytes.toFixed(1)} KiB`;\n }\n\n return `${(kibibytes / 1024).toFixed(1)} MiB`;\n}\n","import os from \"node:os\";\nimport process from \"node:process\";\n\nimport { type FSWatcher } from \"chokidar\";\nimport WebSocket from \"ws\";\n\nimport { encodeClientMessage, type ClientMessage } from \"./protocol.js\";\nimport type { StartSyncSessionOptions } from \"./client.js\";\nimport type { CommandOutput } from \"../../../shared/output/types.js\";\n\nexport function createSyncWebSocketUrl(options: StartSyncSessionOptions): string {\n const url = new URL(options.apiBaseUrl);\n url.protocol = url.protocol === \"http:\" ? \"ws:\" : \"wss:\";\n url.pathname = `/api/cng/coderoom/rooms/${encodeURIComponent(options.roomCode)}/ws`;\n url.search = \"\";\n url.hash = \"\";\n url.searchParams.set(\"role\", options.role);\n url.searchParams.set(\"displayName\", createDisplayName());\n if (options.creatorToken) {\n url.searchParams.set(\"creatorToken\", options.creatorToken);\n }\n if (options.acceptanceToken) {\n url.searchParams.set(\"acceptanceToken\", options.acceptanceToken);\n }\n return url.toString();\n}\n\nexport function sendMessage(socket: WebSocket, message: ClientMessage): void {\n if (socket.readyState === WebSocket.OPEN) {\n socket.send(encodeClientMessage(message));\n }\n}\n\nexport function createDisplayName(): string {\n const username = os.userInfo().username || \"user\";\n return `${username}@${os.hostname()}`;\n}\n\nexport async function waitForSessionClose(\n socket: WebSocket,\n watcher: FSWatcher,\n output: CommandOutput\n): Promise<void> {\n await new Promise<void>((resolve, reject) => {\n let settled = false;\n let shutdownRequested = false;\n\n const closeSession = async (): Promise<void> => {\n output.info(\"Closing Coderoom session...\");\n await watcher.close();\n if (socket.readyState === WebSocket.OPEN || socket.readyState === WebSocket.CONNECTING) {\n socket.close();\n }\n };\n\n const finish = async (): Promise<void> => {\n if (settled) {\n return;\n }\n settled = true;\n process.off(\"SIGINT\", onSignal);\n process.off(\"SIGTERM\", onSignal);\n await closeSession();\n if (shutdownRequested) {\n output.success(\"Coderoom session closed.\");\n }\n resolve();\n };\n\n const onSignal = (): void => {\n shutdownRequested = true;\n output.warning(\"Shutdown requested. Closing Coderoom cleanly...\");\n void finish();\n };\n\n socket.on(\"error\", async (error) => {\n if (settled) {\n return;\n }\n settled = true;\n process.off(\"SIGINT\", onSignal);\n process.off(\"SIGTERM\", onSignal);\n await closeSession();\n reject(error);\n });\n\n socket.on(\"close\", () => {\n if (!shutdownRequested) {\n output.warning(\"Coderoom socket closed.\");\n }\n void finish();\n });\n\n process.on(\"SIGINT\", onSignal);\n process.on(\"SIGTERM\", onSignal);\n });\n}\n","import { z } from \"zod\";\n\nexport const ClientFileMessageSchema = z.object({\n type: z.literal(\"file\"),\n path: z.string().min(1),\n contentBase64: z.string(),\n mtimeMs: z.number().finite(),\n});\n\nexport const ClientDeleteMessageSchema = z.object({\n type: z.literal(\"delete\"),\n path: z.string().min(1),\n mtimeMs: z.number().finite(),\n});\n\nexport const ClientJoinApprovalMessageSchema = z.object({\n type: z.literal(\"join-approval\"),\n joinRequestId: z.string().min(1),\n approved: z.boolean(),\n});\n\nexport const ClientMessageSchema = z.discriminatedUnion(\"type\", [\n ClientFileMessageSchema,\n ClientDeleteMessageSchema,\n ClientJoinApprovalMessageSchema,\n]);\n\nexport const ServerConnectedMessageSchema = z.object({\n type: z.literal(\"connected\"),\n roomCode: z.string(),\n participantId: z.string(),\n role: z.union([z.literal(\"host\"), z.literal(\"guest\")]),\n status: z.union([z.literal(\"approved\"), z.literal(\"pending\"), z.literal(\"denied\")]),\n});\n\nexport const ServerJoinPendingMessageSchema = z.object({\n type: z.literal(\"join-pending\"),\n participantId: z.string(),\n joinRequestId: z.string(),\n roomCode: z.string(),\n});\n\nexport const ServerJoinRequestMessageSchema = z.object({\n type: z.literal(\"join-request\"),\n joinRequestId: z.string(),\n participantId: z.string(),\n displayName: z.string(),\n requestedAt: z.number().finite(),\n});\n\nexport const ServerJoinApprovedMessageSchema = z.object({\n type: z.literal(\"join-approved\"),\n participantId: z.string(),\n});\n\nexport const ServerJoinDeniedMessageSchema = z.object({\n type: z.literal(\"join-denied\"),\n participantId: z.string(),\n reason: z.string(),\n});\n\nexport const ServerFileMessageSchema = z.object({\n type: z.literal(\"file\"),\n fileId: z.string(),\n path: z.string().min(1),\n sha256: z.string(),\n size: z.number().int().nonnegative(),\n contentBase64: z.string(),\n mtimeMs: z.number().finite(),\n updatedByParticipantId: z.string(),\n});\n\nexport const ServerDeleteMessageSchema = z.object({\n type: z.literal(\"delete\"),\n fileId: z.string().optional(),\n path: z.string().min(1),\n mtimeMs: z.number().finite(),\n updatedByParticipantId: z.string(),\n});\n\nexport const ServerFileAckMessageSchema = z.object({\n type: z.literal(\"file-ack\"),\n fileId: z.string(),\n path: z.string().min(1),\n sha256: z.string(),\n size: z.number().int().nonnegative(),\n storage: z.union([z.literal(\"durable-object\"), z.literal(\"r2\")]),\n});\n\nexport const ServerTreeStartMessageSchema = z.object({\n type: z.literal(\"tree-start\"),\n fileCount: z.number().int().nonnegative(),\n});\n\nexport const ServerTreeCompleteMessageSchema = z.object({\n type: z.literal(\"tree-complete\"),\n fileCount: z.number().int().nonnegative(),\n});\n\nexport const ServerErrorMessageSchema = z.object({\n type: z.literal(\"error\"),\n error: z.string(),\n});\n\nexport const ServerMessageSchema = z.discriminatedUnion(\"type\", [\n ServerConnectedMessageSchema,\n ServerJoinPendingMessageSchema,\n ServerJoinRequestMessageSchema,\n ServerJoinApprovedMessageSchema,\n ServerJoinDeniedMessageSchema,\n ServerFileMessageSchema,\n ServerDeleteMessageSchema,\n ServerFileAckMessageSchema,\n ServerTreeStartMessageSchema,\n ServerTreeCompleteMessageSchema,\n ServerErrorMessageSchema,\n]);\n\nexport type ClientMessage = z.infer<typeof ClientMessageSchema>;\nexport type ServerMessage = z.infer<typeof ServerMessageSchema>;\nexport type ServerFileMutationMessage = Extract<ServerMessage, { type: \"file\" | \"delete\" }>;\n\nexport function encodeClientMessage(message: ClientMessage): string {\n return JSON.stringify(ClientMessageSchema.parse(message));\n}\n\nexport function decodeServerMessage(value: unknown): ServerMessage | undefined {\n if (typeof value !== \"string\") {\n return undefined;\n }\n\n try {\n return ServerMessageSchema.parse(JSON.parse(value));\n } catch {\n return undefined;\n }\n}\n","import process from \"node:process\";\nimport readline from \"node:readline/promises\";\n\nimport WebSocket, { type RawData } from \"ws\";\n\nimport type { CommandOutput } from \"../../../shared/output/types.js\";\nimport { applyRemoteMessage, type SuppressionTracker } from \"./files.js\";\nimport type { RepoContext } from \"./paths.js\";\nimport { decodeServerMessage, type ServerMessage } from \"./protocol.js\";\nimport { sendMessage } from \"./session.js\";\n\ntype SessionState = {\n approved: boolean;\n participantId?: string;\n};\n\nexport type HandleServerMessageOptions = {\n data: RawData;\n socket: WebSocket;\n repoContext: RepoContext;\n state: SessionState;\n suppressionTracker: SuppressionTracker;\n output: CommandOutput;\n};\n\nexport async function handleServerMessage(options: HandleServerMessageOptions): Promise<void> {\n const decodedMessage = decodeServerMessage(options.data.toString());\n if (!decodedMessage) {\n return;\n }\n\n if (decodedMessage.type === \"connected\") {\n options.state.participantId = decodedMessage.participantId;\n options.state.approved = decodedMessage.status === \"approved\";\n options.output.muted(`Participant: ${decodedMessage.participantId}`);\n return;\n }\n\n if (decodedMessage.type === \"join-pending\") {\n options.output.info(`Join request sent: ${decodedMessage.joinRequestId}`);\n return;\n }\n\n if (decodedMessage.type === \"join-request\") {\n await approveJoinRequest(options.socket, decodedMessage, options.output);\n return;\n }\n\n if (decodedMessage.type === \"join-approved\") {\n options.state.approved = true;\n options.output.success(\"Join approved. Applying room file tree...\");\n return;\n }\n\n if (decodedMessage.type === \"join-denied\") {\n options.output.warning(`Join denied: ${decodedMessage.reason}`);\n options.socket.close();\n return;\n }\n\n if (decodedMessage.type === \"tree-start\") {\n options.output.info(`receiving room tree ${decodedMessage.fileCount} files`);\n return;\n }\n\n if (decodedMessage.type === \"tree-complete\") {\n options.output.success(`room tree complete ${decodedMessage.fileCount} files`);\n return;\n }\n\n if (decodedMessage.type === \"file-ack\") {\n options.output.info(\n `stored ${decodedMessage.storage} ${decodedMessage.path} (${formatByteCount(decodedMessage.size)}) ${decodedMessage.sha256}`\n );\n return;\n }\n\n if (decodedMessage.type === \"error\") {\n options.output.warning(`server error: ${decodedMessage.error}`);\n return;\n }\n\n await applyRemoteMessage(options.repoContext, decodedMessage, options.suppressionTracker);\n options.output.success(`applied ${decodedMessage.type} ${decodedMessage.path}`);\n}\n\nfunction formatByteCount(byteCount: number): string {\n if (byteCount < 1024) {\n return `${byteCount} B`;\n }\n\n const kibibytes = byteCount / 1024;\n if (kibibytes < 1024) {\n return `${kibibytes.toFixed(1)} KiB`;\n }\n\n return `${(kibibytes / 1024).toFixed(1)} MiB`;\n}\n\nasync function approveJoinRequest(\n socket: WebSocket,\n message: Extract<ServerMessage, { type: \"join-request\" }>,\n output: CommandOutput\n): Promise<void> {\n const approved = await askForApproval(message, output);\n sendMessage(socket, {\n type: \"join-approval\",\n joinRequestId: message.joinRequestId,\n approved,\n });\n output[approved ? \"success\" : \"warning\"](\n `${approved ? \"approved\" : \"denied\"} ${message.displayName}`\n );\n}\n\nasync function askForApproval(\n message: Extract<ServerMessage, { type: \"join-request\" }>,\n output: CommandOutput\n): Promise<boolean> {\n output.info(`Join request: ${message.displayName} (${message.joinRequestId})`);\n if (!process.stdin.isTTY) {\n output.warning(\"No interactive terminal available. Denying join request.\");\n return false;\n }\n\n const interfaceReader = readline.createInterface({\n input: process.stdin,\n output: process.stdout,\n });\n\n try {\n const answer = await interfaceReader.question(\"Approve join request? [y/N] \");\n return answer.trim().toLowerCase() === \"y\" || answer.trim().toLowerCase() === \"yes\";\n } finally {\n interfaceReader.close();\n }\n}\n"],"mappings":"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","names":["process","WebSocket","path","path","fs","fs","process","formatByteCount","process","WebSocket","process"]}
@@ -4,7 +4,7 @@ import {
4
4
 
5
5
  // src/shared/config.ts
6
6
  import process2 from "process";
7
- var packageVersion = "1.1.22";
7
+ var packageVersion = "1.1.24";
8
8
  var defaultApiBaseUrl = "https://curly.ng";
9
9
  function resolveApiBaseUrl(options) {
10
10
  void options;
@@ -3872,20 +3872,22 @@ function formatApiError(error) {
3872
3872
  }
3873
3873
  return error.message;
3874
3874
  }
3875
+ function isRecord(value) {
3876
+ return value !== null && typeof value === "object" && !Array.isArray(value);
3877
+ }
3875
3878
  function extractBodyErrorMessage(body) {
3876
- if (body == null || typeof body !== "object") {
3879
+ if (!isRecord(body)) {
3877
3880
  return void 0;
3878
3881
  }
3879
- const record = body;
3880
- const errorField = record.error;
3881
- if (errorField != null && typeof errorField === "object") {
3882
+ const errorField = body.error;
3883
+ if (errorField != null && isRecord(errorField)) {
3882
3884
  const message = errorField.message;
3883
3885
  if (typeof message === "string") {
3884
3886
  return message;
3885
3887
  }
3886
3888
  }
3887
- if (typeof record.message === "string") {
3888
- return record.message;
3889
+ if (typeof body.message === "string") {
3890
+ return body.message;
3889
3891
  }
3890
3892
  return void 0;
3891
3893
  }
@@ -3898,4 +3900,4 @@ export {
3898
3900
  CngApiClient,
3899
3901
  formatError
3900
3902
  };
3901
- //# sourceMappingURL=chunk-DCW4RKLC.js.map
3903
+ //# sourceMappingURL=chunk-H5LPFVPJ.js.map