volute 0.27.0 → 0.29.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (81) hide show
  1. package/README.md +20 -10
  2. package/dist/accept-666DIZX2.js +41 -0
  3. package/dist/api.d.ts +342 -143
  4. package/dist/{chat-MHJ3L6JQ.js → chat-KTPOR2JT.js} +18 -8
  5. package/dist/chunk-A6TUJJ3L.js +19 -0
  6. package/dist/{chunk-OQZH4PBB.js → chunk-CMILSHZD.js} +199 -277
  7. package/dist/{chunk-K5NAC55T.js → chunk-CQ7SNKNI.js} +1 -1
  8. package/dist/{chunk-PHSAT7YL.js → chunk-EHZKEMMV.js} +5 -5
  9. package/dist/{chunk-IAYBDWVG.js → chunk-FLZGS4QH.js} +145 -0
  10. package/dist/{chunk-USUXRNVD.js → chunk-J4IBNXGJ.js} +0 -2
  11. package/dist/chunk-MD4C26II.js +128 -0
  12. package/dist/{chunk-4WXYUOAK.js → chunk-NI5FFCCS.js} +8 -1
  13. package/dist/{chunk-JKOWNZ4P.js → chunk-P72MVS4R.js} +1 -40
  14. package/dist/chunk-THUUIU3E.js +232 -0
  15. package/dist/cli.js +21 -30
  16. package/dist/clock-DGCBVGYA.js +259 -0
  17. package/dist/{cloud-sync-T7M3ESC3.js → cloud-sync-KILFGV5Q.js} +7 -7
  18. package/dist/connectors/discord-bridge.js +1 -1
  19. package/dist/connectors/slack-bridge.js +1 -1
  20. package/dist/connectors/telegram-bridge.js +1 -1
  21. package/dist/{conversations-M2K4253F.js → conversations-P5BL7RMX.js} +7 -1
  22. package/dist/create-DFCAGEE5.js +70 -0
  23. package/dist/{daemon-restart-M2QTYMEG.js → daemon-restart-UHOMICXT.js} +1 -1
  24. package/dist/daemon.js +715 -661
  25. package/dist/files-M546TKVN.js +46 -0
  26. package/dist/{login-XX37I52P.js → login-BKP3AFWN.js} +7 -17
  27. package/dist/logout-IQK7FNEK.js +20 -0
  28. package/dist/{message-delivery-LDXLGERA.js → message-delivery-Q7VUMIEI.js} +11 -9
  29. package/dist/{mind-DI33C74K.js → mind-S5V6CK5W.js} +8 -13
  30. package/dist/{mind-activity-tracker-EN6XNXPF.js → mind-activity-tracker-WRHFI3YW.js} +1 -1
  31. package/dist/mind-list-UPJ75GPI.js +29 -0
  32. package/dist/{mind-manager-M6EMUW5I.js → mind-manager-P66HQDNE.js} +2 -2
  33. package/dist/mind-status-TK5AETEM.js +55 -0
  34. package/dist/{package-7WY6VKU3.js → package-OFKXNKJF.js} +1 -1
  35. package/dist/{pages-6EBS6CBR.js → pages-EUJR52AH.js} +5 -5
  36. package/dist/pages-watcher-P7QECRE2.js +21 -0
  37. package/dist/{publish-66UB2ZFY.js → publish-ZZB33WP4.js} +6 -17
  38. package/dist/{register-6B2CXTYM.js → register-CHREOMJ3.js} +5 -24
  39. package/dist/reject-LXIZFJ4Q.js +39 -0
  40. package/dist/{sandbox-TGBX22DS.js → sandbox-5BW5HPXM.js} +1 -1
  41. package/dist/{send-ZNCJDSRP.js → send-TAOEZ4NH.js} +64 -6
  42. package/dist/skills/dreaming/references/INSTALL.md +3 -17
  43. package/dist/skills/shared-files/SKILL.md +44 -0
  44. package/dist/skills/shared-files/scripts/merge.ts +72 -0
  45. package/dist/skills/shared-files/scripts/pull.ts +52 -0
  46. package/dist/skills/volute-mind/SKILL.md +48 -22
  47. package/dist/{sleep-manager-MWYHM5HV.js → sleep-manager-G4B5GW5P.js} +7 -7
  48. package/dist/{sprout-IJVVKSJ2.js → sprout-UNT7LKKE.js} +1 -1
  49. package/dist/{status-77YEPHMW.js → status-NQJYR4BG.js} +45 -1
  50. package/dist/{status-THLOBLWG.js → status-S7UUPNRW.js} +3 -13
  51. package/dist/systems-SMEFSHTA.js +60 -0
  52. package/dist/{up-NKSMXBWR.js → up-W6VAK2XE.js} +1 -1
  53. package/dist/{version-notify-5Z4MNR6M.js → version-notify-WDHRO3XD.js} +11 -11
  54. package/dist/web-assets/assets/index-BmKDnWDB.css +1 -0
  55. package/dist/web-assets/assets/index-CLJMx-GA.js +71 -0
  56. package/dist/web-assets/index.html +2 -2
  57. package/package.json +1 -1
  58. package/templates/_base/src/lib/logger.ts +10 -53
  59. package/templates/_base/src/lib/router.ts +1 -9
  60. package/templates/claude/src/lib/stream-consumer.ts +1 -4
  61. package/templates/pi/src/lib/event-handler.ts +1 -14
  62. package/dist/auth-D3OT2ARB.js +0 -37
  63. package/dist/chunk-KDGS53OS.js +0 -50
  64. package/dist/chunk-RWKVSSLY.js +0 -26
  65. package/dist/chunk-T6HKBWXZ.js +0 -23
  66. package/dist/create-D7J73A6H.js +0 -45
  67. package/dist/file-CR36YUPD.js +0 -204
  68. package/dist/log-ABYNVYJ3.js +0 -39
  69. package/dist/logout-W4KOOBIT.js +0 -18
  70. package/dist/logs-U35JR2KE.js +0 -77
  71. package/dist/merge-LNSMSAOF.js +0 -46
  72. package/dist/pull-XCHJTM5M.js +0 -39
  73. package/dist/schedule-QTJMFATP.js +0 -154
  74. package/dist/service-6LIN3F3K.js +0 -122
  75. package/dist/shared-ML5I4Q2A.js +0 -39
  76. package/dist/status-7GA4SM4Y.js +0 -35
  77. package/dist/web-assets/assets/index-CI5wgghI.css +0 -1
  78. package/dist/web-assets/assets/index-is5CvJWH.js +0 -75
  79. package/dist/{chunk-GIE6CSN5.js → chunk-DUAUMCEE.js} +0 -0
  80. package/dist/{history-XKRTAFS2.js → history-ALPTNB3I.js} +0 -0
  81. package/dist/{setup-JG4QAEBV.js → setup-RXYVGGT7.js} +3 -3
@@ -8,8 +8,8 @@
8
8
  <link rel="preconnect" href="https://fonts.googleapis.com" />
9
9
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
10
10
  <link href="https://fonts.googleapis.com/css2?family=Averia+Serif+Libre:wght@300;400;700&family=Fira+Code:wght@300;400;500;600&family=Averia+Sans+Libre:ital,wght@0,300;0,400;0,500;0,600;1,400&display=swap" rel="stylesheet" />
11
- <script type="module" crossorigin src="/assets/index-is5CvJWH.js"></script>
12
- <link rel="stylesheet" crossorigin href="/assets/index-CI5wgghI.css">
11
+ <script type="module" crossorigin src="/assets/index-CLJMx-GA.js"></script>
12
+ <link rel="stylesheet" crossorigin href="/assets/index-BmKDnWDB.css">
13
13
  </head>
14
14
  <body>
15
15
  <div id="root"></div>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "volute",
3
- "version": "0.27.0",
3
+ "version": "0.29.0",
4
4
  "description": "CLI for creating and managing self-modifying AI minds powered by the Claude Agent SDK",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -14,34 +14,7 @@ if (process.env.VOLUTE_DEBUG === "1") {
14
14
  // Loaded once at startup — mind restarts on config changes
15
15
  const preset = loadTransparencyPreset();
16
16
 
17
- /** Categories whose log() calls are also emitted as daemon events. */
18
- const EMIT_CATEGORIES = new Set(["mind", "server", "auto-commit"]);
19
-
20
- function truncate(str: string, maxLen = 200): string {
21
- return str.length > maxLen ? `${str.slice(0, maxLen)}...` : str;
22
- }
23
-
24
- /** Whether debug-level output is active (disables truncation). */
25
- export function isDebug(): boolean {
26
- return minLevel <= LEVELS.debug;
27
- }
28
-
29
- /** Set the minimum log level. */
30
- export function setLevel(level: LogLevel): void {
31
- if (!(level in LEVELS)) {
32
- console.error(`[logger] unknown log level "${level}", defaulting to info`);
33
- minLevel = LEVELS.info;
34
- return;
35
- }
36
- minLevel = LEVELS[level];
37
- }
38
-
39
- function shouldTruncate(): boolean {
40
- return minLevel > LEVELS.debug;
41
- }
42
-
43
17
  function emit(category: string, args: unknown[]): void {
44
- if (!EMIT_CATEGORIES.has(category)) return;
45
18
  const message = args
46
19
  .map((a) => (a instanceof Error ? a.message : typeof a === "string" ? a : JSON.stringify(a)))
47
20
  .join(" ");
@@ -53,6 +26,16 @@ function emit(category: string, args: unknown[]): void {
53
26
  if (filtered) daemonEmit(filtered).catch(() => {});
54
27
  }
55
28
 
29
+ /** Set the minimum log level. */
30
+ export function setLevel(level: LogLevel): void {
31
+ if (!(level in LEVELS)) {
32
+ console.error(`[logger] unknown log level "${level}", defaulting to info`);
33
+ minLevel = LEVELS.info;
34
+ return;
35
+ }
36
+ minLevel = LEVELS[level];
37
+ }
38
+
56
39
  function write(level: LogLevel, category: string, ...args: unknown[]): void {
57
40
  if (LEVELS[level] < minLevel) return;
58
41
  const ts = new Date().toLocaleString();
@@ -80,32 +63,6 @@ export function error(category: string, ...args: unknown[]) {
80
63
  write("error", category, ...args);
81
64
  }
82
65
 
83
- export function logThinking(thinking: string) {
84
- log("thinking", shouldTruncate() ? truncate(thinking) : thinking);
85
- }
86
-
87
- export function logToolUse(name: string, input: unknown) {
88
- const inputStr = shouldTruncate()
89
- ? truncate(JSON.stringify(input), 100)
90
- : JSON.stringify(input, null, 2);
91
- log("tool", `${name}: ${inputStr}`);
92
- }
93
-
94
- export function logToolResult(name: string, output: string, isError?: boolean) {
95
- const prefix = isError ? "error" : "result";
96
- log("tool", `${name} ${prefix}: ${shouldTruncate() ? truncate(output) : output}`);
97
- }
98
-
99
- export function logText(text: string) {
100
- log("text", shouldTruncate() ? truncate(text) : text);
101
- }
102
-
103
- export function logMessage(direction: "in" | "out", content: string, channel?: string) {
104
- const arrow = direction === "in" ? "<<" : ">>";
105
- const channelStr = channel ? ` [${channel}]` : "";
106
- log("msg", `${arrow}${channelStr}`, shouldTruncate() ? truncate(content) : content);
107
- }
108
-
109
66
  // Prevent EPIPE on stderr from crashing the process (detached variant mode)
110
67
  process.stderr?.on?.("error", () => {});
111
68
  process.stdout?.on?.("error", () => {});
@@ -1,5 +1,5 @@
1
1
  import { formatPrefix, formatTypingSuffix } from "./format-prefix.js";
2
- import { log, logMessage } from "./logger.js";
2
+ import { log } from "./logger.js";
3
3
  import {
4
4
  type BatchConfig,
5
5
  loadRoutingConfig,
@@ -269,12 +269,6 @@ export function createRouter(options: {
269
269
  meta: ChannelMeta,
270
270
  listener?: Listener,
271
271
  ): { messageId: string; unsubscribe: () => void } {
272
- const text = content
273
- .filter((p): p is { type: "text"; text: string } => p.type === "text")
274
- .map((p) => p.text)
275
- .join(" ");
276
- logMessage("in", text, meta.channel);
277
-
278
272
  const messageId = generateMessageId();
279
273
  const noop = () => {};
280
274
  const safeListener = listener ?? noop;
@@ -303,12 +297,10 @@ export function createRouter(options: {
303
297
  meta: ChannelMeta,
304
298
  listener?: Listener,
305
299
  ): { messageId: string; unsubscribe: () => void } {
306
- // Log incoming message
307
300
  const text = content
308
301
  .filter((p): p is { type: "text"; text: string } => p.type === "text")
309
302
  .map((p) => p.text)
310
303
  .join(" ");
311
- logMessage("in", text, meta.channel);
312
304
 
313
305
  // Resolve route from config (re-read on each request for hot-reload)
314
306
  const config = options.configPath ? loadRoutingConfig(options.configPath) : {};
@@ -1,6 +1,6 @@
1
1
  import type { query } from "@anthropic-ai/claude-agent-sdk";
2
2
  import { daemonEmit, type EventType } from "./daemon-client.js";
3
- import { log, logText, logThinking, logToolUse, warn } from "./logger.js";
3
+ import { log, warn } from "./logger.js";
4
4
  import { filterEvent, loadTransparencyPreset } from "./transparency.js";
5
5
  import type { VoluteEvent } from "./types.js";
6
6
 
@@ -60,15 +60,12 @@ export async function consumeStream(
60
60
  for (const b of msg.message.content) {
61
61
  if (b.type === "thinking" && "thinking" in b && b.thinking) {
62
62
  const text = b.thinking as string;
63
- logThinking(text);
64
63
  emit(session, { type: "thinking", content: text });
65
64
  } else if (b.type === "text") {
66
65
  const text = (b as { text: string }).text;
67
- logText(text);
68
66
  emit(session, { type: "text", content: text });
69
67
  } else if (b.type === "tool_use") {
70
68
  const tb = b as { name: string; input: unknown };
71
- logToolUse(tb.name, tb.input);
72
69
  emit(session, {
73
70
  type: "tool_use",
74
71
  content: JSON.stringify(tb.input),
@@ -1,6 +1,6 @@
1
1
  import { commitFileChange } from "./auto-commit.js";
2
2
  import { daemonEmit, type EventType } from "./daemon-client.js";
3
- import { log, logText, logThinking, logToolResult, logToolUse, warn } from "./logger.js";
3
+ import { log, warn } from "./logger.js";
4
4
  import { filterEvent, loadTransparencyPreset } from "./transparency.js";
5
5
  import type { VoluteEvent } from "./types.js";
6
6
 
@@ -44,7 +44,6 @@ export function createEventHandler(session: EventSession, options: EventHandlerO
44
44
 
45
45
  function flushText() {
46
46
  if (textBuf) {
47
- logText(textBuf);
48
47
  emit(session, { type: "text", content: textBuf });
49
48
  textBuf = "";
50
49
  }
@@ -52,7 +51,6 @@ export function createEventHandler(session: EventSession, options: EventHandlerO
52
51
 
53
52
  function flushThinking() {
54
53
  if (thinkingBuf) {
55
- logThinking(thinkingBuf);
56
54
  emit(session, { type: "thinking", content: thinkingBuf });
57
55
  thinkingBuf = "";
58
56
  }
@@ -82,25 +80,15 @@ export function createEventHandler(session: EventSession, options: EventHandlerO
82
80
  if (ae.type === "text_delta") {
83
81
  if (thinkingBuf) flushThinking();
84
82
  textBuf += ae.delta;
85
- // Log complete lines as they arrive
86
- for (let nl = textBuf.indexOf("\n"); nl !== -1; nl = textBuf.indexOf("\n")) {
87
- logText(textBuf.slice(0, nl + 1));
88
- textBuf = textBuf.slice(nl + 1);
89
- }
90
83
  } else if (ae.type === "thinking_delta") {
91
84
  if (textBuf) flushText();
92
85
  thinkingBuf += ae.delta;
93
- for (let nl = thinkingBuf.indexOf("\n"); nl !== -1; nl = thinkingBuf.indexOf("\n")) {
94
- logThinking(thinkingBuf.slice(0, nl + 1));
95
- thinkingBuf = thinkingBuf.slice(nl + 1);
96
- }
97
86
  }
98
87
  }
99
88
 
100
89
  if (event.type === "tool_execution_start") {
101
90
  flushBuffers();
102
91
  toolArgs.set(event.toolCallId, event.args);
103
- logToolUse(event.toolName, event.args);
104
92
  emit(session, {
105
93
  type: "tool_use",
106
94
  content: JSON.stringify(event.args),
@@ -111,7 +99,6 @@ export function createEventHandler(session: EventSession, options: EventHandlerO
111
99
  if (event.type === "tool_execution_end") {
112
100
  const output =
113
101
  typeof event.result === "string" ? event.result : JSON.stringify(event.result);
114
- logToolResult(event.toolName, output, event.isError);
115
102
  emit(session, {
116
103
  type: "tool_result",
117
104
  content: output,
@@ -1,37 +0,0 @@
1
- #!/usr/bin/env node
2
- import "./chunk-K3NQKI34.js";
3
-
4
- // src/commands/auth.ts
5
- async function run(args) {
6
- const subcommand = args[0];
7
- switch (subcommand) {
8
- case "register":
9
- await import("./register-6B2CXTYM.js").then((m) => m.run(args.slice(1)));
10
- break;
11
- case "login":
12
- await import("./login-XX37I52P.js").then((m) => m.run(args.slice(1)));
13
- break;
14
- case "logout":
15
- await import("./logout-W4KOOBIT.js").then((m) => m.run());
16
- break;
17
- case "--help":
18
- case "-h":
19
- case void 0:
20
- printUsage();
21
- break;
22
- default:
23
- printUsage();
24
- console.error(`
25
- Unknown subcommand: ${subcommand}`);
26
- process.exit(1);
27
- }
28
- }
29
- function printUsage() {
30
- console.log(`Usage:
31
- volute auth register [--name <name>] Register a system on volute.systems
32
- volute auth login [--key <key>] Log in with an existing API key
33
- volute auth logout Remove stored credentials`);
34
- }
35
- export {
36
- run
37
- };
@@ -1,50 +0,0 @@
1
- #!/usr/bin/env node
2
- import {
3
- voluteUserHome
4
- } from "./chunk-H7OZRFJB.js";
5
-
6
- // src/lib/systems-config.ts
7
- import { existsSync, mkdirSync, readFileSync, unlinkSync, writeFileSync } from "fs";
8
- import { resolve } from "path";
9
- var DEFAULT_API_URL = "https://volute.systems";
10
- function configPath() {
11
- return resolve(voluteUserHome(), "systems.json");
12
- }
13
- function readSystemsConfig() {
14
- const path = configPath();
15
- if (!existsSync(path)) return null;
16
- const raw = readFileSync(path, "utf-8");
17
- let data;
18
- try {
19
- data = JSON.parse(raw);
20
- } catch {
21
- console.error(`Warning: ${path} contains invalid JSON. Run "volute auth logout" and re-login.`);
22
- return null;
23
- }
24
- if (!data.apiKey || !data.system) return null;
25
- return {
26
- apiKey: data.apiKey,
27
- system: data.system,
28
- apiUrl: data.apiUrl || DEFAULT_API_URL
29
- };
30
- }
31
- function writeSystemsConfig(config) {
32
- mkdirSync(voluteUserHome(), { recursive: true });
33
- writeFileSync(configPath(), `${JSON.stringify(config, null, 2)}
34
- `, { mode: 384 });
35
- }
36
- function deleteSystemsConfig() {
37
- try {
38
- unlinkSync(configPath());
39
- return true;
40
- } catch (err) {
41
- if (err.code === "ENOENT") return false;
42
- throw err;
43
- }
44
- }
45
-
46
- export {
47
- readSystemsConfig,
48
- writeSystemsConfig,
49
- deleteSystemsConfig
50
- };
@@ -1,26 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- // src/lib/systems-fetch.ts
4
- async function systemsFetch(url, init) {
5
- try {
6
- return await fetch(url, init);
7
- } catch (err) {
8
- const cause = err.cause;
9
- const code = cause?.code;
10
- const host = new URL(url).host;
11
- if (code === "ENOTFOUND") {
12
- console.error(`Could not resolve ${host}. Check your internet connection.`);
13
- } else if (code === "ECONNREFUSED") {
14
- console.error(`Connection refused by ${host}. The service may be down.`);
15
- } else {
16
- console.error(
17
- `Network error connecting to ${host}: ${cause?.message ?? err.message}`
18
- );
19
- }
20
- process.exit(1);
21
- }
22
- }
23
-
24
- export {
25
- systemsFetch
26
- };
@@ -1,23 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- // src/lib/slugify.ts
4
- function slugify(text) {
5
- return text.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "");
6
- }
7
- function buildVoluteSlug(opts) {
8
- if (opts.convType === "channel" && opts.convName) {
9
- return `volute:#${opts.convName}`;
10
- }
11
- const isDM = opts.participants.length === 2;
12
- if (isDM) {
13
- const other = opts.participants.find((p) => p.username !== opts.mindUsername);
14
- const otherSlug = other ? slugify(other.username) : "";
15
- return otherSlug ? `volute:@${otherSlug}` : `volute:${opts.conversationId}`;
16
- }
17
- return opts.convTitle ? `volute:${slugify(opts.convTitle)}` : `volute:${opts.conversationId}`;
18
- }
19
-
20
- export {
21
- slugify,
22
- buildVoluteSlug
23
- };
@@ -1,45 +0,0 @@
1
- #!/usr/bin/env node
2
- import {
3
- resolveMindName
4
- } from "./chunk-NAOW2CLO.js";
5
- import {
6
- daemonFetch
7
- } from "./chunk-JGFVMROS.js";
8
- import {
9
- parseArgs
10
- } from "./chunk-D424ZQGI.js";
11
- import "./chunk-H7OZRFJB.js";
12
- import "./chunk-K3NQKI34.js";
13
-
14
- // src/commands/chat/create.ts
15
- async function run(args) {
16
- const { flags } = parseArgs(args, {
17
- mind: { type: "string" },
18
- participants: { type: "string" },
19
- name: { type: "string" }
20
- });
21
- if (!flags.participants) {
22
- console.error('Usage: volute chat create --participants u1,u2 [--name "..."] [--mind <name>]');
23
- process.exit(1);
24
- }
25
- const mindName = resolveMindName(flags);
26
- const participants = flags.participants.split(",").map((p) => p.trim());
27
- const res = await daemonFetch(`/api/minds/${encodeURIComponent(mindName)}/conversations`, {
28
- method: "POST",
29
- headers: { "Content-Type": "application/json" },
30
- body: JSON.stringify({
31
- participantNames: participants,
32
- title: flags.name
33
- })
34
- });
35
- if (!res.ok) {
36
- const data = await res.json().catch(() => ({}));
37
- console.error(data.error ?? `Failed to create conversation: ${res.status}`);
38
- process.exit(1);
39
- }
40
- const conv = await res.json();
41
- console.log(`Created conversation: ${conv.id}`);
42
- }
43
- export {
44
- run
45
- };
@@ -1,204 +0,0 @@
1
- #!/usr/bin/env node
2
- import {
3
- resolveMindName
4
- } from "./chunk-NAOW2CLO.js";
5
- import {
6
- daemonFetch
7
- } from "./chunk-JGFVMROS.js";
8
- import {
9
- parseArgs
10
- } from "./chunk-D424ZQGI.js";
11
- import "./chunk-H7OZRFJB.js";
12
- import "./chunk-K3NQKI34.js";
13
-
14
- // src/commands/file.ts
15
- async function run(args) {
16
- const subcommand = args[0];
17
- switch (subcommand) {
18
- case "send":
19
- await sendFile(args.slice(1));
20
- break;
21
- case "list":
22
- await listPending(args.slice(1));
23
- break;
24
- case "accept":
25
- await acceptFile(args.slice(1));
26
- break;
27
- case "reject":
28
- await rejectFile(args.slice(1));
29
- break;
30
- case "trust":
31
- await trustSender(args.slice(1));
32
- break;
33
- case "untrust":
34
- await untrustSender(args.slice(1));
35
- break;
36
- case "--help":
37
- case "-h":
38
- case void 0:
39
- printUsage();
40
- break;
41
- default:
42
- printUsage();
43
- process.exit(1);
44
- }
45
- }
46
- function printUsage() {
47
- console.log(`Usage:
48
- volute file send <path> <target-mind> [--mind <name>] Send a file to another mind
49
- volute file list [--mind <name>] List pending incoming files
50
- volute file accept <id> [--mind <name>] Accept a pending file
51
- volute file reject <id> [--mind <name>] Reject a pending file
52
- volute file trust <sender> [--mind <name>] Trust a sender (auto-deliver)
53
- volute file untrust <sender> [--mind <name>] Remove sender trust`);
54
- }
55
- async function sendFile(args) {
56
- const { positional, flags } = parseArgs(args, {
57
- mind: { type: "string" }
58
- });
59
- const mind = resolveMindName(flags);
60
- const filePath = positional[0];
61
- const targetMind = positional[1];
62
- if (!filePath || !targetMind) {
63
- console.error("Usage: volute file send <path> <target-mind> [--mind <name>]");
64
- process.exit(1);
65
- }
66
- const res = await daemonFetch(`/api/minds/${encodeURIComponent(mind)}/files/send`, {
67
- method: "POST",
68
- headers: { "Content-Type": "application/json" },
69
- body: JSON.stringify({ targetMind, filePath })
70
- });
71
- if (!res.ok) {
72
- const data2 = await res.json();
73
- console.error(data2.error ?? `Failed to send file: ${res.status}`);
74
- process.exit(1);
75
- }
76
- const data = await res.json();
77
- if (data.status === "delivered") {
78
- console.log(`File delivered to ${targetMind}: ${data.destPath}`);
79
- } else {
80
- console.log(`File pending approval from ${targetMind} (id: ${data.id})`);
81
- }
82
- }
83
- async function listPending(args) {
84
- const { flags } = parseArgs(args, {
85
- mind: { type: "string" }
86
- });
87
- const mind = resolveMindName(flags);
88
- const res = await daemonFetch(`/api/minds/${encodeURIComponent(mind)}/files/pending`);
89
- if (!res.ok) {
90
- const data = await res.json();
91
- console.error(data.error ?? `Failed to list pending files: ${res.status}`);
92
- process.exit(1);
93
- }
94
- const pending = await res.json();
95
- if (pending.length === 0) {
96
- console.log("No pending files.");
97
- return;
98
- }
99
- const idW = Math.max(2, ...pending.map((p) => p.id.length));
100
- const senderW = Math.max(6, ...pending.map((p) => p.sender.length));
101
- const fileW = Math.max(4, ...pending.map((p) => p.filename.length));
102
- console.log(`${"ID".padEnd(idW)} ${"SENDER".padEnd(senderW)} ${"FILE".padEnd(fileW)} SIZE`);
103
- for (const p of pending) {
104
- console.log(
105
- `${p.id.padEnd(idW)} ${p.sender.padEnd(senderW)} ${p.filename.padEnd(fileW)} ${formatSize(p.size)}`
106
- );
107
- }
108
- }
109
- async function acceptFile(args) {
110
- const { positional, flags } = parseArgs(args, {
111
- mind: { type: "string" }
112
- });
113
- const mind = resolveMindName(flags);
114
- const id = positional[0];
115
- if (!id) {
116
- console.error("Usage: volute file accept <id> [--mind <name>]");
117
- process.exit(1);
118
- }
119
- const res = await daemonFetch(`/api/minds/${encodeURIComponent(mind)}/files/accept`, {
120
- method: "POST",
121
- headers: { "Content-Type": "application/json" },
122
- body: JSON.stringify({ id })
123
- });
124
- if (!res.ok) {
125
- const data2 = await res.json();
126
- console.error(data2.error ?? `Failed to accept file: ${res.status}`);
127
- process.exit(1);
128
- }
129
- const data = await res.json();
130
- console.log(`File accepted: ${data.destPath}`);
131
- }
132
- async function rejectFile(args) {
133
- const { positional, flags } = parseArgs(args, {
134
- mind: { type: "string" }
135
- });
136
- const mind = resolveMindName(flags);
137
- const id = positional[0];
138
- if (!id) {
139
- console.error("Usage: volute file reject <id> [--mind <name>]");
140
- process.exit(1);
141
- }
142
- const res = await daemonFetch(`/api/minds/${encodeURIComponent(mind)}/files/reject`, {
143
- method: "POST",
144
- headers: { "Content-Type": "application/json" },
145
- body: JSON.stringify({ id })
146
- });
147
- if (!res.ok) {
148
- const data = await res.json();
149
- console.error(data.error ?? `Failed to reject file: ${res.status}`);
150
- process.exit(1);
151
- }
152
- console.log(`File rejected: ${id}`);
153
- }
154
- async function trustSender(args) {
155
- const { positional, flags } = parseArgs(args, {
156
- mind: { type: "string" }
157
- });
158
- const mind = resolveMindName(flags);
159
- const sender = positional[0];
160
- if (!sender) {
161
- console.error("Usage: volute file trust <sender> [--mind <name>]");
162
- process.exit(1);
163
- }
164
- const res = await daemonFetch(`/api/minds/${encodeURIComponent(mind)}/files/trust`, {
165
- method: "POST",
166
- headers: { "Content-Type": "application/json" },
167
- body: JSON.stringify({ sender })
168
- });
169
- if (!res.ok) {
170
- const data = await res.json();
171
- console.error(data.error ?? `Failed to trust sender: ${res.status}`);
172
- process.exit(1);
173
- }
174
- console.log(`Trusted sender: ${sender}`);
175
- }
176
- async function untrustSender(args) {
177
- const { positional, flags } = parseArgs(args, {
178
- mind: { type: "string" }
179
- });
180
- const mind = resolveMindName(flags);
181
- const sender = positional[0];
182
- if (!sender) {
183
- console.error("Usage: volute file untrust <sender> [--mind <name>]");
184
- process.exit(1);
185
- }
186
- const res = await daemonFetch(
187
- `/api/minds/${encodeURIComponent(mind)}/files/trust/${encodeURIComponent(sender)}`,
188
- { method: "DELETE" }
189
- );
190
- if (!res.ok) {
191
- const data = await res.json();
192
- console.error(data.error ?? `Failed to untrust sender: ${res.status}`);
193
- process.exit(1);
194
- }
195
- console.log(`Untrusted sender: ${sender}`);
196
- }
197
- function formatSize(bytes) {
198
- if (bytes < 1024) return `${bytes} B`;
199
- if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
200
- return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
201
- }
202
- export {
203
- run
204
- };
@@ -1,39 +0,0 @@
1
- #!/usr/bin/env node
2
- import {
3
- resolveMindName
4
- } from "./chunk-NAOW2CLO.js";
5
- import {
6
- daemonFetch
7
- } from "./chunk-JGFVMROS.js";
8
- import {
9
- parseArgs
10
- } from "./chunk-D424ZQGI.js";
11
- import "./chunk-H7OZRFJB.js";
12
- import "./chunk-K3NQKI34.js";
13
-
14
- // src/commands/shared/log.ts
15
- async function run(args) {
16
- const { flags } = parseArgs(args, {
17
- mind: { type: "string" },
18
- limit: { type: "number" }
19
- });
20
- const mindName = resolveMindName(flags);
21
- const limit = flags.limit ?? 20;
22
- const res = await daemonFetch(
23
- `/api/minds/${encodeURIComponent(mindName)}/shared/log?limit=${limit}`
24
- );
25
- if (!res.ok) {
26
- const body = await res.json().catch(() => ({}));
27
- console.error(body.error ?? `Server responded with ${res.status}`);
28
- process.exit(1);
29
- }
30
- const output = await res.text();
31
- if (output.trim()) {
32
- console.log(output.trimEnd());
33
- } else {
34
- console.log("No shared history yet.");
35
- }
36
- }
37
- export {
38
- run
39
- };
@@ -1,18 +0,0 @@
1
- #!/usr/bin/env node
2
- import {
3
- deleteSystemsConfig
4
- } from "./chunk-KDGS53OS.js";
5
- import "./chunk-H7OZRFJB.js";
6
- import "./chunk-K3NQKI34.js";
7
-
8
- // src/commands/pages/logout.ts
9
- async function run() {
10
- if (deleteSystemsConfig()) {
11
- console.log("Logged out. Credentials removed.");
12
- } else {
13
- console.log("Not logged in.");
14
- }
15
- }
16
- export {
17
- run
18
- };