svamp-cli 0.2.282 → 0.2.284
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/dist/adminCommands-DPZaByla.mjs +235 -0
- package/dist/{agentCommands-C2SA3m-H.mjs → agentCommands-B23M4vER.mjs} +5 -5
- package/dist/{auth-Ei72rgtQ.mjs → auth-DPZSnISj.mjs} +1 -1
- package/dist/{cli-AqDROKlD.mjs → cli-D8tJd71c.mjs} +74 -67
- package/dist/cli.mjs +2 -2
- package/dist/{commands-CUO72eBO.mjs → commands-BABblJRp.mjs} +1 -1
- package/dist/{commands-CDl7rl3f.mjs → commands-BHO7rzSh.mjs} +1 -1
- package/dist/{commands-C6TKdbzy.mjs → commands-BqaOHWym.mjs} +7 -7
- package/dist/{commands-DJLs9f1R.mjs → commands-CDFhSKgn.mjs} +2 -2
- package/dist/{commands-COekL2o8.mjs → commands-Cp8G-iuw.mjs} +2 -2
- package/dist/{commands-BrWafMO7.mjs → commands-DDf0W30g.mjs} +2 -2
- package/dist/{commands-Cx74j8ot.mjs → commands-DqsoW-S0.mjs} +1 -1
- package/dist/{fleet-Dy9ZJ6vm.mjs → fleet-BxhHefua.mjs} +1 -1
- package/dist/{frpc-DjLzbAcP.mjs → frpc-BsR6aGNJ.mjs} +1 -1
- package/dist/{headlessCli-DttVTkeB.mjs → headlessCli-B-aMhdKx.mjs} +2 -2
- package/dist/index.mjs +1 -1
- package/dist/{notifyCommands-DfQLR_b_.mjs → notifyCommands-CfnthGpX.mjs} +1 -1
- package/dist/package-Br4fCS7J.mjs +64 -0
- package/dist/{rpc-ChQ7ArYi.mjs → rpc-B5BRaVsS.mjs} +1 -1
- package/dist/{rpc-zvlrNata.mjs → rpc-BjrKqEib.mjs} +1 -1
- package/dist/{run-D8PHZBGS.mjs → run-CRTzyKbn.mjs} +30 -99
- package/dist/{run-dVUrVaoC.mjs → run-DWJenrBe.mjs} +1 -1
- package/dist/{scheduler-CntyA8uK.mjs → scheduler-QYMtbUDe.mjs} +1 -1
- package/dist/{serveCommands-DcoJVqwb.mjs → serveCommands-Cj3MLbZb.mjs} +5 -5
- package/dist/{sideband-CpVC-tM4.mjs → sideband-CKmZxwY6.mjs} +1 -1
- package/package.json +2 -2
- package/dist/adminCommands-ChJ_O-_h.mjs +0 -100
- package/dist/package-D2hm0uj4.mjs +0 -64
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
import { c as connectToHypha, K as computeCollectionConfigUpdate, L as SYSTEM_COLLECTION_CONFIG } from './run-CRTzyKbn.mjs';
|
|
2
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import os from 'node:os';
|
|
5
|
+
import 'os';
|
|
6
|
+
import 'fs/promises';
|
|
7
|
+
import 'fs';
|
|
8
|
+
import 'path';
|
|
9
|
+
import 'url';
|
|
10
|
+
import 'child_process';
|
|
11
|
+
import 'crypto';
|
|
12
|
+
import 'node:crypto';
|
|
13
|
+
import 'node:child_process';
|
|
14
|
+
import 'util';
|
|
15
|
+
import 'http';
|
|
16
|
+
import 'net';
|
|
17
|
+
import 'node:events';
|
|
18
|
+
import '@agentclientprotocol/sdk';
|
|
19
|
+
import 'node:readline';
|
|
20
|
+
import 'node:fs/promises';
|
|
21
|
+
import 'node:util';
|
|
22
|
+
import 'yaml';
|
|
23
|
+
|
|
24
|
+
const SYSTEM_COLLECTIONS = [
|
|
25
|
+
{ id: "public/svamp-user-events", alias: "svamp-user-events", name: "Svamp User Events", description: "Cross-workspace user event inbox (bell notifications)" },
|
|
26
|
+
{ id: "public/svamp-shared-sessions", alias: "svamp-shared-sessions", name: "Svamp Shared Sessions", description: "Cross-workspace share notifications for session/machine bookmarks" }
|
|
27
|
+
];
|
|
28
|
+
function loadEnv() {
|
|
29
|
+
const SVAMP_HOME = process.env.SVAMP_HOME || join(os.homedir(), ".svamp");
|
|
30
|
+
for (const f of [join(SVAMP_HOME, ".env"), join(os.homedir(), ".hypha", ".env")]) {
|
|
31
|
+
if (!existsSync(f)) continue;
|
|
32
|
+
try {
|
|
33
|
+
for (const line of readFileSync(f, "utf-8").split("\n")) {
|
|
34
|
+
const m = line.match(/^\s*([A-Za-z0-9_]+)\s*=\s*(.*)\s*$/);
|
|
35
|
+
if (m && process.env[m[1]] === void 0) process.env[m[1]] = m[2].replace(/^["']|["']$/g, "");
|
|
36
|
+
}
|
|
37
|
+
} catch {
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
async function setCollectionConfig(alias, configJson) {
|
|
42
|
+
if (!alias || !configJson) {
|
|
43
|
+
console.error("Usage: svamp admin set-collection-config <alias> --config '<json>'");
|
|
44
|
+
console.error(` e.g. svamp admin set-collection-config svamp-user-events --config '{"private_children":true,"recipient_field":"recipientEmail"}'`);
|
|
45
|
+
process.exit(1);
|
|
46
|
+
}
|
|
47
|
+
let extra;
|
|
48
|
+
try {
|
|
49
|
+
extra = JSON.parse(configJson);
|
|
50
|
+
if (!extra || typeof extra !== "object" || Array.isArray(extra)) throw new Error("config must be a JSON object");
|
|
51
|
+
} catch (e) {
|
|
52
|
+
console.error(`--config must be a JSON object: ${e.message}`);
|
|
53
|
+
process.exit(1);
|
|
54
|
+
}
|
|
55
|
+
loadEnv();
|
|
56
|
+
const serverUrl = process.env.HYPHA_SERVER_URL;
|
|
57
|
+
const token = process.env.HYPHA_TOKEN;
|
|
58
|
+
if (!serverUrl || !token) {
|
|
59
|
+
console.error('Not logged in. Run "svamp login <url>" first.');
|
|
60
|
+
process.exit(1);
|
|
61
|
+
}
|
|
62
|
+
let server;
|
|
63
|
+
try {
|
|
64
|
+
server = await connectToHypha({ serverUrl, token, name: "svamp-admin-cli" });
|
|
65
|
+
} catch (e) {
|
|
66
|
+
console.error(`Failed to connect to Hypha: ${e.message}`);
|
|
67
|
+
process.exit(1);
|
|
68
|
+
}
|
|
69
|
+
try {
|
|
70
|
+
const am = await server.getService("public/artifact-manager");
|
|
71
|
+
if (!am) {
|
|
72
|
+
console.error("Artifact manager not available.");
|
|
73
|
+
process.exit(1);
|
|
74
|
+
}
|
|
75
|
+
let col;
|
|
76
|
+
try {
|
|
77
|
+
col = await am.read({ artifact_id: alias, _rkwargs: true });
|
|
78
|
+
} catch (e) {
|
|
79
|
+
console.error(`Collection "${alias}" not found (or not readable): ${e.message}`);
|
|
80
|
+
process.exit(1);
|
|
81
|
+
}
|
|
82
|
+
const { changed, merged } = computeCollectionConfigUpdate(col.config, extra);
|
|
83
|
+
if (!changed) {
|
|
84
|
+
console.log(`${alias}: config already up to date (no change).`);
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
try {
|
|
88
|
+
await am.edit({ artifact_id: col.id, config: merged, _rkwargs: true });
|
|
89
|
+
await am.commit({ artifact_id: col.id, _rkwargs: true }).catch(() => {
|
|
90
|
+
});
|
|
91
|
+
} catch (e) {
|
|
92
|
+
console.error(`Failed to set config on "${alias}" (need owner/admin/root rights): ${e.message}`);
|
|
93
|
+
process.exit(1);
|
|
94
|
+
}
|
|
95
|
+
console.log(`\u2713 ${alias}: merged {${Object.keys(extra).join(", ")}} into config (existing keys preserved).`);
|
|
96
|
+
} finally {
|
|
97
|
+
try {
|
|
98
|
+
await server.disconnect?.();
|
|
99
|
+
} catch {
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
async function connectAdmin(name = "svamp-admin-cli") {
|
|
104
|
+
loadEnv();
|
|
105
|
+
const serverUrl = process.env.HYPHA_SERVER_URL;
|
|
106
|
+
const token = process.env.HYPHA_TOKEN;
|
|
107
|
+
if (!serverUrl || !token) {
|
|
108
|
+
console.error('Not logged in. Run "svamp login <url>" first.');
|
|
109
|
+
process.exit(1);
|
|
110
|
+
}
|
|
111
|
+
let server;
|
|
112
|
+
try {
|
|
113
|
+
server = await connectToHypha({ serverUrl, token, name });
|
|
114
|
+
} catch (e) {
|
|
115
|
+
console.error(`Failed to connect to Hypha: ${e.message}`);
|
|
116
|
+
process.exit(1);
|
|
117
|
+
}
|
|
118
|
+
const am = await server.getService("public/artifact-manager");
|
|
119
|
+
if (!am) {
|
|
120
|
+
console.error("Artifact manager not available.");
|
|
121
|
+
try {
|
|
122
|
+
await server.disconnect?.();
|
|
123
|
+
} catch {
|
|
124
|
+
}
|
|
125
|
+
process.exit(1);
|
|
126
|
+
}
|
|
127
|
+
return { server, am };
|
|
128
|
+
}
|
|
129
|
+
async function createSystemCollections() {
|
|
130
|
+
const { server, am } = await connectAdmin("svamp-admin-create-collections");
|
|
131
|
+
try {
|
|
132
|
+
for (const c of SYSTEM_COLLECTIONS) {
|
|
133
|
+
try {
|
|
134
|
+
await am.create({
|
|
135
|
+
alias: c.alias,
|
|
136
|
+
workspace: "public",
|
|
137
|
+
type: "collection",
|
|
138
|
+
manifest: { name: c.name, description: c.description },
|
|
139
|
+
config: SYSTEM_COLLECTION_CONFIG,
|
|
140
|
+
_rkwargs: true
|
|
141
|
+
});
|
|
142
|
+
console.log(`\u2713 created ${c.id} (config: @:lf+, private_children, recipient_field, recipient_can_delete)`);
|
|
143
|
+
} catch (e) {
|
|
144
|
+
const msg = String(e?.message || e);
|
|
145
|
+
if (/exist|already/i.test(msg)) {
|
|
146
|
+
console.log(`\u2022 ${c.id}: already exists \u2014 skipped (use 'svamp admin set-collection-config' to update its config)`);
|
|
147
|
+
} else {
|
|
148
|
+
console.error(`\u2717 ${c.id}: ${msg}`);
|
|
149
|
+
console.error(" Needs a PUBLIC-admin token: mint with roles=['admin'], workspace='public' (a ws-user-* token can't create in public).");
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
} finally {
|
|
154
|
+
try {
|
|
155
|
+
await server.disconnect?.();
|
|
156
|
+
} catch {
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
async function migrateChildren(am, fromId, toId) {
|
|
161
|
+
const children = await am.list({ parent_id: fromId, _rkwargs: true });
|
|
162
|
+
if (!Array.isArray(children) || children.length === 0) {
|
|
163
|
+
return { total: 0, copied: 0, alreadyPresent: 0, failed: 0, errors: [] };
|
|
164
|
+
}
|
|
165
|
+
let existing = [];
|
|
166
|
+
try {
|
|
167
|
+
existing = await am.list({ parent_id: toId, _rkwargs: true });
|
|
168
|
+
} catch {
|
|
169
|
+
}
|
|
170
|
+
const keyOf = (c) => String(c?.manifest?.id ?? c?.alias ?? "");
|
|
171
|
+
const existingKeys = new Set((Array.isArray(existing) ? existing : []).map(keyOf).filter(Boolean));
|
|
172
|
+
let copied = 0, alreadyPresent = 0, failed = 0;
|
|
173
|
+
const errors = [];
|
|
174
|
+
const noteErr = (m) => {
|
|
175
|
+
if (errors.length < 5 && !errors.includes(m)) errors.push(m);
|
|
176
|
+
};
|
|
177
|
+
for (const c of children) {
|
|
178
|
+
const manifest = c?.manifest;
|
|
179
|
+
const key = keyOf(c);
|
|
180
|
+
const alias = c?.alias || (manifest?.id ? `mig-${String(manifest.id).slice(0, 12)}` : void 0);
|
|
181
|
+
if (!manifest || !alias) {
|
|
182
|
+
failed++;
|
|
183
|
+
noteErr("child had no manifest/alias");
|
|
184
|
+
continue;
|
|
185
|
+
}
|
|
186
|
+
if (key && existingKeys.has(key)) {
|
|
187
|
+
alreadyPresent++;
|
|
188
|
+
continue;
|
|
189
|
+
}
|
|
190
|
+
try {
|
|
191
|
+
const artifact = await am.create({ alias, parent_id: toId, type: c.type || "user-event", stage: true, manifest, _rkwargs: true });
|
|
192
|
+
await am.commit({ artifact_id: artifact.id, _rkwargs: true });
|
|
193
|
+
if (key) existingKeys.add(key);
|
|
194
|
+
copied++;
|
|
195
|
+
} catch (e) {
|
|
196
|
+
const msg = String(e?.message || e);
|
|
197
|
+
failed++;
|
|
198
|
+
noteErr(msg.slice(0, 160));
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
return { total: children.length, copied, alreadyPresent, failed, errors };
|
|
202
|
+
}
|
|
203
|
+
async function migrateCollectionChildren(fromId, toId) {
|
|
204
|
+
if (!fromId || !toId) {
|
|
205
|
+
console.error("Usage: svamp admin migrate-collection-children <fromId> <toId>");
|
|
206
|
+
console.error(" e.g. svamp admin migrate-collection-children ws-user-root/svamp-user-events public/svamp-user-events");
|
|
207
|
+
process.exit(1);
|
|
208
|
+
}
|
|
209
|
+
const { server, am } = await connectAdmin("svamp-admin-migrate");
|
|
210
|
+
try {
|
|
211
|
+
let result;
|
|
212
|
+
try {
|
|
213
|
+
result = await migrateChildren(am, fromId, toId);
|
|
214
|
+
} catch (e) {
|
|
215
|
+
console.error(`Cannot list source "${fromId}" (need read/list rights on it): ${e.message}`);
|
|
216
|
+
process.exit(1);
|
|
217
|
+
}
|
|
218
|
+
if (result.total === 0) {
|
|
219
|
+
console.log(`${fromId}: no children to migrate.`);
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
222
|
+
console.log(`${fromId} \u2192 ${toId}: ${result.copied} copied, ${result.alreadyPresent} already-present, ${result.failed} failed (of ${result.total}). Source left intact; delete it manually once verified.`);
|
|
223
|
+
if (result.errors.length) {
|
|
224
|
+
console.error(` errors (sample): ${result.errors.join(" | ")}`);
|
|
225
|
+
}
|
|
226
|
+
if (result.failed > 0) process.exit(1);
|
|
227
|
+
} finally {
|
|
228
|
+
try {
|
|
229
|
+
await server.disconnect?.();
|
|
230
|
+
} catch {
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
export { createSystemCollections, migrateChildren, migrateCollectionChildren, setCollectionConfig };
|
|
@@ -2,7 +2,7 @@ import { existsSync, readFileSync, mkdirSync, writeFileSync, renameSync } from '
|
|
|
2
2
|
import { join, dirname } from 'node:path';
|
|
3
3
|
import os from 'node:os';
|
|
4
4
|
import { requireNotSandboxed } from './sandboxDetect-DNTcbgWD.mjs';
|
|
5
|
-
import { i as shortId } from './run-
|
|
5
|
+
import { i as shortId } from './run-CRTzyKbn.mjs';
|
|
6
6
|
import 'os';
|
|
7
7
|
import 'fs/promises';
|
|
8
8
|
import 'fs';
|
|
@@ -96,7 +96,7 @@ async function sessionSetTitle(title) {
|
|
|
96
96
|
}
|
|
97
97
|
async function sessionSetProjectDescription(description) {
|
|
98
98
|
const dir = process.cwd();
|
|
99
|
-
const { projectName, writeProjectInfo, sanitizeDescription, projectInfoPath } = await import('./run-
|
|
99
|
+
const { projectName, writeProjectInfo, sanitizeDescription, projectInfoPath } = await import('./run-CRTzyKbn.mjs').then(function (n) { return n.ap; });
|
|
100
100
|
const desc = sanitizeDescription(description, 240);
|
|
101
101
|
if (!desc) {
|
|
102
102
|
console.error("Project description is empty.");
|
|
@@ -343,7 +343,7 @@ async function sessionBroadcast(action, args) {
|
|
|
343
343
|
console.log(`Broadcast sent: ${action}`);
|
|
344
344
|
}
|
|
345
345
|
async function connectToMachineService() {
|
|
346
|
-
const { connectAndGetMachine } = await import('./commands-
|
|
346
|
+
const { connectAndGetMachine } = await import('./commands-BABblJRp.mjs');
|
|
347
347
|
return connectAndGetMachine();
|
|
348
348
|
}
|
|
349
349
|
function buildInboxMessage(args) {
|
|
@@ -421,7 +421,7 @@ async function inboxSend(targetSessionId, opts) {
|
|
|
421
421
|
console.error("Message body is required.");
|
|
422
422
|
process.exit(1);
|
|
423
423
|
}
|
|
424
|
-
const { connectAndResolveSession } = await import('./commands-
|
|
424
|
+
const { connectAndResolveSession } = await import('./commands-BABblJRp.mjs');
|
|
425
425
|
let server;
|
|
426
426
|
try {
|
|
427
427
|
const { targetId, messageId } = await inboxSendCore(
|
|
@@ -475,7 +475,7 @@ async function inboxReply(messageId, body) {
|
|
|
475
475
|
console.error("SVAMP_SESSION_ID not set. This command must be run inside a Svamp session.");
|
|
476
476
|
process.exit(1);
|
|
477
477
|
}
|
|
478
|
-
const { connectAndResolveSession } = await import('./commands-
|
|
478
|
+
const { connectAndResolveSession } = await import('./commands-BABblJRp.mjs');
|
|
479
479
|
const { server: localServer, machine: localMachine } = await connectToMachineService();
|
|
480
480
|
let localDisconnected = false;
|
|
481
481
|
const disconnectLocal = async () => {
|