zooid 0.6.1 → 0.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +1 -1
- package/README.md +36 -444
- package/dist/bin.js +1891 -0
- package/dist/bin.js.map +1 -0
- package/dist/chunk-SUPTPSN3.js +31434 -0
- package/dist/chunk-SUPTPSN3.js.map +1 -0
- package/dist/index.d.ts +64 -0
- package/dist/index.js +4 -3790
- package/dist/index.js.map +1 -0
- package/dist/web/assets/geist-cyrillic-wght-normal-CHSlOQsW.woff2 +0 -0
- package/dist/web/assets/geist-latin-ext-wght-normal-DMtmJ5ZE.woff2 +0 -0
- package/dist/web/assets/geist-latin-wght-normal-Dm3htQBi.woff2 +0 -0
- package/dist/web/assets/index-C2MAIew3.css +1 -0
- package/dist/web/assets/index-CqfWXqvO.js +118066 -0
- package/dist/web/assets/index-Cz5fEZBc.js +295 -0
- package/dist/web/assets/reaction-picker-emoji-cME0vOsX.js +716 -0
- package/dist/web/favicon.svg +1 -0
- package/dist/web/index.html +14 -0
- package/package.json +43 -22
- package/src/bin.ts +115 -0
- package/src/bootstrap/admin.test.ts +69 -0
- package/src/bootstrap/admin.ts +37 -0
- package/src/bootstrap/configs.test.ts +24 -0
- package/src/bootstrap/configs.ts +64 -0
- package/src/bootstrap/data-layout.test.ts +25 -0
- package/src/bootstrap/data-layout.ts +20 -0
- package/src/bootstrap/derive.test.ts +74 -0
- package/src/bootstrap/derive.ts +40 -0
- package/src/bootstrap/paths.test.ts +22 -0
- package/src/bootstrap/paths.ts +27 -0
- package/src/bootstrap/tokens.test.ts +44 -0
- package/src/bootstrap/tokens.ts +43 -0
- package/src/build-registry.context.test.ts +61 -0
- package/src/build-registry.test.ts +59 -0
- package/src/build-registry.ts +343 -0
- package/src/build-registry.zod043.test.ts +64 -0
- package/src/build-registry.zod044.test.ts +261 -0
- package/src/commands/dev-cascade.test.ts +38 -0
- package/src/commands/dev-cascade.ts +35 -0
- package/src/commands/dev-data-layout.test.ts +55 -0
- package/src/commands/dev.ts +316 -0
- package/src/commands/init/generators.test.ts +97 -0
- package/src/commands/init/generators.ts +124 -0
- package/src/commands/init/prompts.ts +123 -0
- package/src/commands/init/registry.test.ts +33 -0
- package/src/commands/init/registry.ts +75 -0
- package/src/commands/init/sniff.test.ts +41 -0
- package/src/commands/init/sniff.ts +30 -0
- package/src/commands/init.test.ts +131 -0
- package/src/commands/init.ts +158 -0
- package/src/commands/logs.test.ts +105 -0
- package/src/commands/logs.ts +108 -0
- package/src/commands/start.ts +28 -0
- package/src/commands/status.test.ts +73 -0
- package/src/commands/status.ts +105 -0
- package/src/daemon/start-daemon.test.ts +67 -0
- package/src/daemon/start-daemon.ts +270 -0
- package/src/index.ts +2 -0
- package/src/observability/capture-agent.ts +58 -0
- package/src/observability/capture-tuwunel.test.ts +57 -0
- package/src/observability/capture-tuwunel.ts +24 -0
- package/src/observability/file-sink.test.ts +68 -0
- package/src/observability/file-sink.ts +78 -0
- package/src/observability/observability.integration.test.ts +162 -0
- package/src/observability/paths.test.ts +104 -0
- package/src/observability/paths.ts +94 -0
- package/src/prepull-images.test.ts +149 -0
- package/src/prepull-images.ts +100 -0
- package/src/services/tuwunel.test.ts +64 -0
- package/src/services/tuwunel.ts +91 -0
- package/src/web/resolve.test.ts +50 -0
- package/src/web/resolve.ts +31 -0
- package/src/web/static.test.ts +51 -0
- package/src/web/static.ts +61 -0
- package/src/web/watch.ts +103 -0
- package/dist/chunk-67ZRMVHO.js +0 -174
- package/dist/chunk-AR456MHY.js +0 -29
- package/dist/chunk-VBGU2NST.js +0 -139
- package/dist/client-4VMFEFDX.js +0 -22
- package/dist/config-2KK5GX42.js +0 -27
- package/dist/template-T5IB4YWC.js +0 -92
package/dist/chunk-67ZRMVHO.js
DELETED
|
@@ -1,174 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
// src/lib/config.ts
|
|
4
|
-
import fs from "fs";
|
|
5
|
-
import os from "os";
|
|
6
|
-
import path from "path";
|
|
7
|
-
|
|
8
|
-
// src/lib/constants.ts
|
|
9
|
-
var STATE_FILENAME = "state.json";
|
|
10
|
-
var LEGACY_STATE_FILENAME = "config.json";
|
|
11
|
-
|
|
12
|
-
// src/lib/config.ts
|
|
13
|
-
function getConfigDir() {
|
|
14
|
-
return process.env.ZOOID_CONFIG_DIR ?? path.join(os.homedir(), ".zooid");
|
|
15
|
-
}
|
|
16
|
-
function getStatePath() {
|
|
17
|
-
const dir = getConfigDir();
|
|
18
|
-
const statePath = path.join(dir, STATE_FILENAME);
|
|
19
|
-
if (!fs.existsSync(statePath)) {
|
|
20
|
-
const legacyPath = path.join(dir, LEGACY_STATE_FILENAME);
|
|
21
|
-
if (fs.existsSync(legacyPath)) {
|
|
22
|
-
fs.renameSync(legacyPath, statePath);
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
return statePath;
|
|
26
|
-
}
|
|
27
|
-
var getConfigPath = getStatePath;
|
|
28
|
-
function loadConfigFile() {
|
|
29
|
-
try {
|
|
30
|
-
const raw = fs.readFileSync(getStatePath(), "utf-8");
|
|
31
|
-
const parsed = JSON.parse(raw);
|
|
32
|
-
if (parsed.server && !parsed.servers) {
|
|
33
|
-
const serverUrl = parsed.server;
|
|
34
|
-
const migrated = {
|
|
35
|
-
current: serverUrl,
|
|
36
|
-
servers: {
|
|
37
|
-
[serverUrl]: {
|
|
38
|
-
worker_url: parsed.worker_url,
|
|
39
|
-
admin_token: parsed.admin_token,
|
|
40
|
-
channels: parsed.channels
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
};
|
|
44
|
-
const dir = getConfigDir();
|
|
45
|
-
fs.mkdirSync(dir, { recursive: true });
|
|
46
|
-
fs.writeFileSync(
|
|
47
|
-
getConfigPath(),
|
|
48
|
-
JSON.stringify(migrated, null, 2) + "\n"
|
|
49
|
-
);
|
|
50
|
-
return migrated;
|
|
51
|
-
}
|
|
52
|
-
return parsed;
|
|
53
|
-
} catch {
|
|
54
|
-
return {};
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
var serverNoteShown = false;
|
|
58
|
-
function resolveServer() {
|
|
59
|
-
const file = loadConfigFile();
|
|
60
|
-
let cwdUrl;
|
|
61
|
-
try {
|
|
62
|
-
const zooidJsonPath = path.join(process.cwd(), "zooid.json");
|
|
63
|
-
if (fs.existsSync(zooidJsonPath)) {
|
|
64
|
-
const raw = fs.readFileSync(zooidJsonPath, "utf-8");
|
|
65
|
-
const parsed = JSON.parse(raw);
|
|
66
|
-
cwdUrl = parsed.url || void 0;
|
|
67
|
-
}
|
|
68
|
-
} catch {
|
|
69
|
-
}
|
|
70
|
-
if (cwdUrl) {
|
|
71
|
-
if (file.current && file.current !== cwdUrl && !serverNoteShown) {
|
|
72
|
-
serverNoteShown = true;
|
|
73
|
-
console.log(
|
|
74
|
-
` Note: using server from zooid.json (${cwdUrl}), current is ${file.current}`
|
|
75
|
-
);
|
|
76
|
-
}
|
|
77
|
-
return cwdUrl;
|
|
78
|
-
}
|
|
79
|
-
return file.current;
|
|
80
|
-
}
|
|
81
|
-
function loadConfig() {
|
|
82
|
-
const file = loadConfigFile();
|
|
83
|
-
const serverUrl = resolveServer();
|
|
84
|
-
const entry = serverUrl ? file.servers?.[serverUrl] : void 0;
|
|
85
|
-
return {
|
|
86
|
-
server: serverUrl,
|
|
87
|
-
worker_url: entry?.worker_url,
|
|
88
|
-
admin_token: entry?.admin_token,
|
|
89
|
-
channels: entry?.channels
|
|
90
|
-
};
|
|
91
|
-
}
|
|
92
|
-
function saveConfig(partial, serverUrl, options) {
|
|
93
|
-
const dir = getConfigDir();
|
|
94
|
-
fs.mkdirSync(dir, { recursive: true });
|
|
95
|
-
const file = loadConfigFile();
|
|
96
|
-
const url = serverUrl ?? resolveServer();
|
|
97
|
-
if (!url) {
|
|
98
|
-
throw new Error(
|
|
99
|
-
"No server URL to save config for. Deploy first or set url in zooid.json."
|
|
100
|
-
);
|
|
101
|
-
}
|
|
102
|
-
if (!file.servers) file.servers = {};
|
|
103
|
-
const existing = file.servers[url] ?? {};
|
|
104
|
-
const merged = { ...existing, ...partial };
|
|
105
|
-
if (partial.channels && existing.channels) {
|
|
106
|
-
merged.channels = { ...existing.channels };
|
|
107
|
-
for (const [chId, chData] of Object.entries(partial.channels)) {
|
|
108
|
-
merged.channels[chId] = { ...existing.channels[chId], ...chData };
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
file.servers[url] = merged;
|
|
112
|
-
if (options?.setCurrent !== false) {
|
|
113
|
-
file.current = url;
|
|
114
|
-
}
|
|
115
|
-
fs.writeFileSync(getConfigPath(), JSON.stringify(file, null, 2) + "\n");
|
|
116
|
-
}
|
|
117
|
-
function loadDirectoryToken() {
|
|
118
|
-
const file = loadConfigFile();
|
|
119
|
-
return file.directory_token;
|
|
120
|
-
}
|
|
121
|
-
function saveDirectoryToken(token) {
|
|
122
|
-
const dir = getConfigDir();
|
|
123
|
-
fs.mkdirSync(dir, { recursive: true });
|
|
124
|
-
const file = loadConfigFile();
|
|
125
|
-
file.directory_token = token;
|
|
126
|
-
fs.writeFileSync(getConfigPath(), JSON.stringify(file, null, 2) + "\n");
|
|
127
|
-
}
|
|
128
|
-
function recordTailHistory(channelId, serverUrl, name, lastEventId) {
|
|
129
|
-
const url = serverUrl ?? resolveServer();
|
|
130
|
-
if (!url) return;
|
|
131
|
-
const file = loadConfigFile();
|
|
132
|
-
if (!file.servers) file.servers = {};
|
|
133
|
-
if (!file.servers[url]) file.servers[url] = {};
|
|
134
|
-
if (!file.servers[url].channels) file.servers[url].channels = {};
|
|
135
|
-
const channel = file.servers[url].channels[channelId] ?? {};
|
|
136
|
-
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
137
|
-
const existing = channel.stats;
|
|
138
|
-
channel.stats = {
|
|
139
|
-
num_tails: (existing?.num_tails ?? 0) + 1,
|
|
140
|
-
last_tailed_at: now,
|
|
141
|
-
first_tailed_at: existing?.first_tailed_at ?? now,
|
|
142
|
-
last_event_id: lastEventId ?? existing?.last_event_id
|
|
143
|
-
};
|
|
144
|
-
if (name) {
|
|
145
|
-
channel.name = name;
|
|
146
|
-
}
|
|
147
|
-
file.servers[url].channels[channelId] = channel;
|
|
148
|
-
const dir = getConfigDir();
|
|
149
|
-
fs.mkdirSync(dir, { recursive: true });
|
|
150
|
-
fs.writeFileSync(getConfigPath(), JSON.stringify(file, null, 2) + "\n");
|
|
151
|
-
}
|
|
152
|
-
function switchServer(url) {
|
|
153
|
-
const dir = getConfigDir();
|
|
154
|
-
fs.mkdirSync(dir, { recursive: true });
|
|
155
|
-
const file = loadConfigFile();
|
|
156
|
-
if (!file.servers) file.servers = {};
|
|
157
|
-
if (!file.servers[url]) file.servers[url] = {};
|
|
158
|
-
file.current = url;
|
|
159
|
-
fs.writeFileSync(getConfigPath(), JSON.stringify(file, null, 2) + "\n");
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
export {
|
|
163
|
-
getConfigDir,
|
|
164
|
-
getStatePath,
|
|
165
|
-
getConfigPath,
|
|
166
|
-
loadConfigFile,
|
|
167
|
-
resolveServer,
|
|
168
|
-
loadConfig,
|
|
169
|
-
saveConfig,
|
|
170
|
-
loadDirectoryToken,
|
|
171
|
-
saveDirectoryToken,
|
|
172
|
-
recordTailHistory,
|
|
173
|
-
switchServer
|
|
174
|
-
};
|
package/dist/chunk-AR456MHY.js
DELETED
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
// src/lib/github.ts
|
|
4
|
-
function parseGitHubUrl(url) {
|
|
5
|
-
try {
|
|
6
|
-
const u = new URL(url);
|
|
7
|
-
if (u.hostname !== "github.com") return null;
|
|
8
|
-
const parts = u.pathname.replace(/^\/|\/$/g, "").split("/");
|
|
9
|
-
if (parts.length < 2) return null;
|
|
10
|
-
const owner = parts[0];
|
|
11
|
-
const repo = parts[1];
|
|
12
|
-
if (!owner || !repo) return null;
|
|
13
|
-
if (parts.length === 2) {
|
|
14
|
-
return { owner, repo, ref: "main", path: "" };
|
|
15
|
-
}
|
|
16
|
-
if (parts[2] === "tree" && parts.length >= 4) {
|
|
17
|
-
const ref = parts[3];
|
|
18
|
-
const subPath = parts.slice(4).join("/");
|
|
19
|
-
return { owner, repo, ref, path: subPath };
|
|
20
|
-
}
|
|
21
|
-
return null;
|
|
22
|
-
} catch {
|
|
23
|
-
return null;
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export {
|
|
28
|
-
parseGitHubUrl
|
|
29
|
-
};
|
package/dist/chunk-VBGU2NST.js
DELETED
|
@@ -1,139 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
loadConfig,
|
|
4
|
-
loadConfigFile,
|
|
5
|
-
saveConfig
|
|
6
|
-
} from "./chunk-67ZRMVHO.js";
|
|
7
|
-
|
|
8
|
-
// src/lib/client.ts
|
|
9
|
-
import { ZooidClient } from "@zooid/sdk";
|
|
10
|
-
function createClient(token) {
|
|
11
|
-
const config = loadConfig();
|
|
12
|
-
const server = config.server;
|
|
13
|
-
if (!server) {
|
|
14
|
-
throw new Error(
|
|
15
|
-
"No server configured. Run: npx zooid config set server <url>"
|
|
16
|
-
);
|
|
17
|
-
}
|
|
18
|
-
return new ZooidClient({ server, token: token ?? config.admin_token });
|
|
19
|
-
}
|
|
20
|
-
function getChannelToken(channelTokens, tokenType) {
|
|
21
|
-
if (!channelTokens) return void 0;
|
|
22
|
-
if (channelTokens.token) return channelTokens.token;
|
|
23
|
-
if (tokenType === "publish") return channelTokens.publish_token;
|
|
24
|
-
if (tokenType === "subscribe") return channelTokens.subscribe_token;
|
|
25
|
-
return channelTokens.publish_token ?? channelTokens.subscribe_token;
|
|
26
|
-
}
|
|
27
|
-
function createChannelClient(channelId, tokenType) {
|
|
28
|
-
const config = loadConfig();
|
|
29
|
-
const server = config.server;
|
|
30
|
-
if (!server) {
|
|
31
|
-
throw new Error(
|
|
32
|
-
"No server configured. Run: npx zooid config set server <url>"
|
|
33
|
-
);
|
|
34
|
-
}
|
|
35
|
-
const channelToken = getChannelToken(config.channels?.[channelId], tokenType);
|
|
36
|
-
return new ZooidClient({ server, token: channelToken ?? config.admin_token });
|
|
37
|
-
}
|
|
38
|
-
var createPublishClient = (channelId) => createChannelClient(channelId, "publish");
|
|
39
|
-
var createSubscribeClient = (channelId) => createChannelClient(channelId, "subscribe");
|
|
40
|
-
var PRIVATE_HOST_RE = /^(localhost|127\.\d+\.\d+\.\d+|10\.\d+\.\d+\.\d+|192\.168\.\d+\.\d+|172\.(1[6-9]|2\d|3[01])\.\d+\.\d+)$/;
|
|
41
|
-
function normalizeServerUrl(url) {
|
|
42
|
-
let normalized = url.replace(/\/+$/, "");
|
|
43
|
-
try {
|
|
44
|
-
const parsed = new URL(normalized);
|
|
45
|
-
if (parsed.protocol === "http:" && !PRIVATE_HOST_RE.test(parsed.hostname)) {
|
|
46
|
-
normalized = normalized.replace(/^http:\/\//, "https://");
|
|
47
|
-
}
|
|
48
|
-
} catch {
|
|
49
|
-
}
|
|
50
|
-
return normalized;
|
|
51
|
-
}
|
|
52
|
-
function parseChannelUrl(channel) {
|
|
53
|
-
let raw = channel;
|
|
54
|
-
if (!raw.startsWith("http") && raw.includes("/")) {
|
|
55
|
-
if (PRIVATE_HOST_RE.test(raw.split(/[:/]/)[0])) {
|
|
56
|
-
raw = `http://${raw}`;
|
|
57
|
-
} else if (raw.includes(".")) {
|
|
58
|
-
raw = `https://${raw}`;
|
|
59
|
-
} else if (/^[^/]+:\d+\//.test(raw)) {
|
|
60
|
-
raw = `http://${raw}`;
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
if (!raw.startsWith("http")) return null;
|
|
64
|
-
try {
|
|
65
|
-
const url = new URL(raw);
|
|
66
|
-
const channelsMatch = url.pathname.match(/^\/channels\/([^/]+)/);
|
|
67
|
-
if (channelsMatch) {
|
|
68
|
-
return { server: url.origin, channelId: channelsMatch[1] };
|
|
69
|
-
}
|
|
70
|
-
const segments = url.pathname.split("/").filter(Boolean);
|
|
71
|
-
if (segments.length === 1) {
|
|
72
|
-
return { server: url.origin, channelId: segments[0] };
|
|
73
|
-
}
|
|
74
|
-
} catch {
|
|
75
|
-
}
|
|
76
|
-
return null;
|
|
77
|
-
}
|
|
78
|
-
function resolveChannel(channel, opts) {
|
|
79
|
-
const parsed = parseChannelUrl(channel);
|
|
80
|
-
if (parsed) {
|
|
81
|
-
const { server: server2, channelId } = parsed;
|
|
82
|
-
let token2 = opts?.token;
|
|
83
|
-
let tokenSaved2 = false;
|
|
84
|
-
if (token2) {
|
|
85
|
-
saveConfig({ channels: { [channelId]: { token: token2 } } }, server2, {
|
|
86
|
-
setCurrent: false
|
|
87
|
-
});
|
|
88
|
-
tokenSaved2 = true;
|
|
89
|
-
}
|
|
90
|
-
if (!token2) {
|
|
91
|
-
const file = loadConfigFile();
|
|
92
|
-
const channelTokens = file.servers?.[server2]?.channels?.[channelId];
|
|
93
|
-
token2 = getChannelToken(channelTokens, opts?.tokenType);
|
|
94
|
-
}
|
|
95
|
-
return {
|
|
96
|
-
client: new ZooidClient({ server: server2, token: token2 }),
|
|
97
|
-
channelId,
|
|
98
|
-
server: server2,
|
|
99
|
-
tokenSaved: tokenSaved2
|
|
100
|
-
};
|
|
101
|
-
}
|
|
102
|
-
const config = loadConfig();
|
|
103
|
-
const server = config.server;
|
|
104
|
-
if (!server) {
|
|
105
|
-
throw new Error(
|
|
106
|
-
"No server configured. Run: npx zooid config set server <url>"
|
|
107
|
-
);
|
|
108
|
-
}
|
|
109
|
-
let token = opts?.token;
|
|
110
|
-
let tokenSaved = false;
|
|
111
|
-
if (token) {
|
|
112
|
-
saveConfig({ channels: { [channel]: { token } } });
|
|
113
|
-
tokenSaved = true;
|
|
114
|
-
}
|
|
115
|
-
if (!token) {
|
|
116
|
-
const channelToken = getChannelToken(
|
|
117
|
-
config.channels?.[channel],
|
|
118
|
-
opts?.tokenType
|
|
119
|
-
);
|
|
120
|
-
token = channelToken ?? config.admin_token;
|
|
121
|
-
}
|
|
122
|
-
return {
|
|
123
|
-
client: new ZooidClient({ server, token }),
|
|
124
|
-
channelId: channel,
|
|
125
|
-
server,
|
|
126
|
-
tokenSaved
|
|
127
|
-
};
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
export {
|
|
131
|
-
createClient,
|
|
132
|
-
createChannelClient,
|
|
133
|
-
createPublishClient,
|
|
134
|
-
createSubscribeClient,
|
|
135
|
-
PRIVATE_HOST_RE,
|
|
136
|
-
normalizeServerUrl,
|
|
137
|
-
parseChannelUrl,
|
|
138
|
-
resolveChannel
|
|
139
|
-
};
|
package/dist/client-4VMFEFDX.js
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
PRIVATE_HOST_RE,
|
|
4
|
-
createChannelClient,
|
|
5
|
-
createClient,
|
|
6
|
-
createPublishClient,
|
|
7
|
-
createSubscribeClient,
|
|
8
|
-
normalizeServerUrl,
|
|
9
|
-
parseChannelUrl,
|
|
10
|
-
resolveChannel
|
|
11
|
-
} from "./chunk-VBGU2NST.js";
|
|
12
|
-
import "./chunk-67ZRMVHO.js";
|
|
13
|
-
export {
|
|
14
|
-
PRIVATE_HOST_RE,
|
|
15
|
-
createChannelClient,
|
|
16
|
-
createClient,
|
|
17
|
-
createPublishClient,
|
|
18
|
-
createSubscribeClient,
|
|
19
|
-
normalizeServerUrl,
|
|
20
|
-
parseChannelUrl,
|
|
21
|
-
resolveChannel
|
|
22
|
-
};
|
package/dist/config-2KK5GX42.js
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
getConfigDir,
|
|
4
|
-
getConfigPath,
|
|
5
|
-
getStatePath,
|
|
6
|
-
loadConfig,
|
|
7
|
-
loadConfigFile,
|
|
8
|
-
loadDirectoryToken,
|
|
9
|
-
recordTailHistory,
|
|
10
|
-
resolveServer,
|
|
11
|
-
saveConfig,
|
|
12
|
-
saveDirectoryToken,
|
|
13
|
-
switchServer
|
|
14
|
-
} from "./chunk-67ZRMVHO.js";
|
|
15
|
-
export {
|
|
16
|
-
getConfigDir,
|
|
17
|
-
getConfigPath,
|
|
18
|
-
getStatePath,
|
|
19
|
-
loadConfig,
|
|
20
|
-
loadConfigFile,
|
|
21
|
-
loadDirectoryToken,
|
|
22
|
-
recordTailHistory,
|
|
23
|
-
resolveServer,
|
|
24
|
-
saveConfig,
|
|
25
|
-
saveDirectoryToken,
|
|
26
|
-
switchServer
|
|
27
|
-
};
|
|
@@ -1,92 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
parseGitHubUrl
|
|
4
|
-
} from "./chunk-AR456MHY.js";
|
|
5
|
-
|
|
6
|
-
// src/lib/template.ts
|
|
7
|
-
import fs from "fs";
|
|
8
|
-
import path from "path";
|
|
9
|
-
import os from "os";
|
|
10
|
-
import { execSync } from "child_process";
|
|
11
|
-
async function fetchTemplate(url, targetDir, options) {
|
|
12
|
-
const parts = parseGitHubUrl(url);
|
|
13
|
-
if (!parts) {
|
|
14
|
-
throw new Error(
|
|
15
|
-
"Only GitHub URLs are supported. Use https://github.com/owner/repo or https://github.com/owner/repo/tree/ref/path"
|
|
16
|
-
);
|
|
17
|
-
}
|
|
18
|
-
const fetchFn = options?.fetch ?? globalThis.fetch;
|
|
19
|
-
const tarballUrl = `https://api.github.com/repos/${parts.owner}/${parts.repo}/tarball/${parts.ref}`;
|
|
20
|
-
const res = await fetchFn(tarballUrl, {
|
|
21
|
-
headers: {
|
|
22
|
-
Accept: "application/vnd.github+json",
|
|
23
|
-
"User-Agent": "zooid-cli"
|
|
24
|
-
},
|
|
25
|
-
redirect: "follow"
|
|
26
|
-
});
|
|
27
|
-
if (!res.ok) {
|
|
28
|
-
throw new Error(`Failed to fetch template from GitHub: HTTP ${res.status}`);
|
|
29
|
-
}
|
|
30
|
-
const tmpTarball = path.join(
|
|
31
|
-
os.tmpdir(),
|
|
32
|
-
`zooid-template-${Date.now()}.tar.gz`
|
|
33
|
-
);
|
|
34
|
-
const arrayBuffer = await res.arrayBuffer();
|
|
35
|
-
const buffer = new Uint8Array(arrayBuffer);
|
|
36
|
-
if (buffer.byteLength === 0) {
|
|
37
|
-
throw new Error(
|
|
38
|
-
"This doesn't look like a Zooid template (no .zooid/workforce.json found)"
|
|
39
|
-
);
|
|
40
|
-
}
|
|
41
|
-
fs.writeFileSync(tmpTarball, new Uint8Array(buffer));
|
|
42
|
-
try {
|
|
43
|
-
const tmpExtract = fs.mkdtempSync(
|
|
44
|
-
path.join(os.tmpdir(), "zooid-template-extract-")
|
|
45
|
-
);
|
|
46
|
-
execSync(`tar xzf "${tmpTarball}" -C "${tmpExtract}"`, {
|
|
47
|
-
stdio: "pipe"
|
|
48
|
-
});
|
|
49
|
-
const entries = fs.readdirSync(tmpExtract);
|
|
50
|
-
const topDir = entries[0];
|
|
51
|
-
if (!topDir) {
|
|
52
|
-
throw new Error("Empty tarball");
|
|
53
|
-
}
|
|
54
|
-
const extractRoot = path.join(tmpExtract, topDir);
|
|
55
|
-
const sourceRoot = parts.path ? path.join(extractRoot, parts.path) : extractRoot;
|
|
56
|
-
if (!fs.existsSync(sourceRoot)) {
|
|
57
|
-
throw new Error(
|
|
58
|
-
`Path "${parts.path}" not found in ${parts.owner}/${parts.repo}`
|
|
59
|
-
);
|
|
60
|
-
}
|
|
61
|
-
const sourceZooid = path.join(sourceRoot, ".zooid");
|
|
62
|
-
const targetZooid = path.join(targetDir, ".zooid");
|
|
63
|
-
let channelCount = 0;
|
|
64
|
-
let roleCount = 0;
|
|
65
|
-
if (fs.existsSync(sourceZooid)) {
|
|
66
|
-
fs.cpSync(sourceZooid, targetZooid, { recursive: true });
|
|
67
|
-
const wfPath = path.join(sourceZooid, "workforce.json");
|
|
68
|
-
if (fs.existsSync(wfPath)) {
|
|
69
|
-
const wf = JSON.parse(fs.readFileSync(wfPath, "utf-8"));
|
|
70
|
-
channelCount = Object.keys(wf.channels ?? {}).length;
|
|
71
|
-
roleCount = Object.keys(wf.roles ?? {}).length + Object.keys(wf.agents ?? {}).length;
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
const sourceConfig = path.join(sourceRoot, "zooid.json");
|
|
75
|
-
const targetConfig = path.join(targetDir, "zooid.json");
|
|
76
|
-
if (fs.existsSync(sourceConfig) && !fs.existsSync(targetConfig)) {
|
|
77
|
-
fs.copyFileSync(sourceConfig, targetConfig);
|
|
78
|
-
}
|
|
79
|
-
fs.rmSync(tmpExtract, { recursive: true, force: true });
|
|
80
|
-
if (channelCount === 0 && roleCount === 0) {
|
|
81
|
-
throw new Error(
|
|
82
|
-
"This doesn't look like a Zooid template (no .zooid/workforce.json found)"
|
|
83
|
-
);
|
|
84
|
-
}
|
|
85
|
-
return { channelCount, roleCount };
|
|
86
|
-
} finally {
|
|
87
|
-
fs.rmSync(tmpTarball, { force: true });
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
export {
|
|
91
|
-
fetchTemplate
|
|
92
|
-
};
|