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.
- package/README.md +24 -8
- package/dist/{chunk-AS7FIJWP.js → chunk-2Y5FMKFS.js} +3 -4
- package/dist/chunk-2Y5FMKFS.js.map +1 -0
- package/dist/{chunk-VMTXY4KQ.js → chunk-3VDQDFHG.js} +14 -6
- package/dist/chunk-3VDQDFHG.js.map +1 -0
- package/dist/{chunk-TIY4RTXC.js → chunk-4Q2LNYVU.js} +12 -15
- package/dist/chunk-4Q2LNYVU.js.map +1 -0
- package/dist/{chunk-KURN5BJ6.js → chunk-EG3QD47O.js} +90 -15
- package/dist/chunk-EG3QD47O.js.map +1 -0
- package/dist/{chunk-DCW4RKLC.js → chunk-H5LPFVPJ.js} +10 -8
- package/dist/{chunk-DCW4RKLC.js.map → chunk-H5LPFVPJ.js.map} +1 -1
- package/dist/{chunk-BRFWVQI4.js → chunk-LC4CYVCT.js} +1 -1
- package/dist/chunk-LC4CYVCT.js.map +1 -0
- package/dist/{chunk-YALWTRIP.js → chunk-LNFZT3R3.js} +2 -2
- package/dist/{chunk-JNHW72SU.js → chunk-QCAHQE7Q.js} +14 -9
- package/dist/chunk-QCAHQE7Q.js.map +1 -0
- package/dist/{chunk-N255PYL7.js → chunk-SRZRHLRJ.js} +2 -2
- package/dist/{chunk-3BATDTKU.js → chunk-YPGDQ6P2.js} +2 -4
- package/dist/chunk-YPGDQ6P2.js.map +1 -0
- package/dist/{chunk-NLAANOBW.js → chunk-ZFBOTEAS.js} +2 -2
- package/dist/cli.js +2 -2
- package/dist/cli.js.map +1 -1
- package/dist/commands/coderoom/index.js +3 -3
- package/dist/commands/coderoom/join.js +14 -5
- package/dist/commands/coderoom/join.js.map +1 -1
- package/dist/commands/coderoom/share.js +4 -4
- package/dist/commands/hookify/index.js +3 -3
- package/dist/commands/hookify/ingest.js +3 -3
- package/dist/commands/hooks/index.js +3 -3
- package/dist/commands/hooks/install.js +3 -3
- package/dist/commands/hooks/uninstall.js +3 -3
- package/dist/commands/index.js +3 -3
- package/dist/commands/knowledges/audiences.js +6 -6
- package/dist/commands/knowledges/cat.js +6 -6
- package/dist/commands/knowledges/files.js +6 -6
- package/dist/commands/knowledges/find.js +6 -6
- package/dist/commands/knowledges/find.js.map +1 -1
- package/dist/commands/knowledges/glob.js +5 -5
- package/dist/commands/knowledges/grep.js +5 -5
- package/dist/commands/knowledges/grep.js.map +1 -1
- package/dist/commands/knowledges/head.js +6 -6
- package/dist/commands/knowledges/index.js +3 -3
- package/dist/commands/knowledges/list.js +6 -6
- package/dist/commands/knowledges/ls.js +6 -6
- package/dist/commands/knowledges/ls.js.map +1 -1
- package/dist/commands/knowledges/read.js +5 -5
- package/dist/commands/knowledges/read.js.map +1 -1
- package/dist/commands/knowledges/realpath.js +3 -3
- package/dist/commands/knowledges/realpath.js.map +1 -1
- package/dist/commands/knowledges/search.js +6 -6
- package/dist/commands/knowledges/stat.js +6 -6
- package/dist/commands/knowledges/status.js +6 -6
- package/dist/commands/knowledges/tail.js +6 -6
- package/dist/commands/knowledges/tree.js +6 -6
- package/dist/commands/login.js +2 -2
- package/dist/commands/scrub.js +17 -14
- package/dist/commands/scrub.js.map +1 -1
- package/dist/commands/transcripts.js +41 -31
- package/dist/commands/transcripts.js.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-3BATDTKU.js.map +0 -1
- package/dist/chunk-AS7FIJWP.js.map +0 -1
- package/dist/chunk-BRFWVQI4.js.map +0 -1
- package/dist/chunk-JNHW72SU.js.map +0 -1
- package/dist/chunk-KURN5BJ6.js.map +0 -1
- package/dist/chunk-TIY4RTXC.js.map +0 -1
- package/dist/chunk-VMTXY4KQ.js.map +0 -1
- /package/dist/{chunk-YALWTRIP.js.map → chunk-LNFZT3R3.js.map} +0 -0
- /package/dist/{chunk-N255PYL7.js.map → chunk-SRZRHLRJ.js.map} +0 -0
- /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
|
|
63
|
-
|
|
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
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
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
|
|
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 = "
|
|
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}/${
|
|
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-
|
|
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-
|
|
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({
|
|
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({
|
|
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({
|
|
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({
|
|
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-
|
|
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-
|
|
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
|
-
|
|
159
|
-
{
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
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-
|
|
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-
|
|
4
|
+
} from "./chunk-SRZRHLRJ.js";
|
|
5
5
|
import {
|
|
6
6
|
resolveApiBaseUrl
|
|
7
|
-
} from "./chunk-
|
|
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
|
|
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.
|
|
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(`
|
|
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.
|
|
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-
|
|
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.
|
|
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
|
|
3879
|
+
if (!isRecord(body)) {
|
|
3877
3880
|
return void 0;
|
|
3878
3881
|
}
|
|
3879
|
-
const
|
|
3880
|
-
|
|
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
|
|
3888
|
-
return
|
|
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-
|
|
3903
|
+
//# sourceMappingURL=chunk-H5LPFVPJ.js.map
|