@intentic/machine 1.233.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 (131) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +72 -0
  3. package/dist/app.d.ts +2 -0
  4. package/dist/app.d.ts.map +1 -0
  5. package/dist/app.js +12 -0
  6. package/dist/app.js.map +1 -0
  7. package/dist/autostart.d.ts +3 -0
  8. package/dist/autostart.d.ts.map +1 -0
  9. package/dist/autostart.js +13 -0
  10. package/dist/autostart.js.map +1 -0
  11. package/dist/cli.d.ts +3 -0
  12. package/dist/cli.d.ts.map +1 -0
  13. package/dist/cli.js +5 -0
  14. package/dist/cli.js.map +1 -0
  15. package/dist/commands.d.ts +11 -0
  16. package/dist/commands.d.ts.map +1 -0
  17. package/dist/commands.js +91 -0
  18. package/dist/commands.js.map +1 -0
  19. package/dist/computer/audit.d.ts +6 -0
  20. package/dist/computer/audit.d.ts.map +1 -0
  21. package/dist/computer/audit.js +12 -0
  22. package/dist/computer/audit.js.map +1 -0
  23. package/dist/computer/commands.d.ts +8 -0
  24. package/dist/computer/commands.d.ts.map +1 -0
  25. package/dist/computer/commands.js +113 -0
  26. package/dist/computer/commands.js.map +1 -0
  27. package/dist/computer/config.d.ts +19 -0
  28. package/dist/computer/config.d.ts.map +1 -0
  29. package/dist/computer/config.js +31 -0
  30. package/dist/computer/config.js.map +1 -0
  31. package/dist/computer/connection.d.ts +8 -0
  32. package/dist/computer/connection.d.ts.map +1 -0
  33. package/dist/computer/connection.js +63 -0
  34. package/dist/computer/connection.js.map +1 -0
  35. package/dist/computer/mcp.d.ts +3 -0
  36. package/dist/computer/mcp.d.ts.map +1 -0
  37. package/dist/computer/mcp.js +312 -0
  38. package/dist/computer/mcp.js.map +1 -0
  39. package/dist/computer/policy.d.ts +8 -0
  40. package/dist/computer/policy.d.ts.map +1 -0
  41. package/dist/computer/policy.js +42 -0
  42. package/dist/computer/policy.js.map +1 -0
  43. package/dist/computer/router.d.ts +93 -0
  44. package/dist/computer/router.d.ts.map +1 -0
  45. package/dist/computer/router.js +79 -0
  46. package/dist/computer/router.js.map +1 -0
  47. package/dist/computer/tools/apps.d.ts +9 -0
  48. package/dist/computer/tools/apps.d.ts.map +1 -0
  49. package/dist/computer/tools/apps.js +41 -0
  50. package/dist/computer/tools/apps.js.map +1 -0
  51. package/dist/computer/tools/browser.d.ts +11 -0
  52. package/dist/computer/tools/browser.d.ts.map +1 -0
  53. package/dist/computer/tools/browser.js +63 -0
  54. package/dist/computer/tools/browser.js.map +1 -0
  55. package/dist/computer/tools/computer.d.ts +16 -0
  56. package/dist/computer/tools/computer.d.ts.map +1 -0
  57. package/dist/computer/tools/computer.js +80 -0
  58. package/dist/computer/tools/computer.js.map +1 -0
  59. package/dist/computer/tools/describe.d.ts +4 -0
  60. package/dist/computer/tools/describe.d.ts.map +1 -0
  61. package/dist/computer/tools/describe.js +37 -0
  62. package/dist/computer/tools/describe.js.map +1 -0
  63. package/dist/computer/tools/files.d.ts +12 -0
  64. package/dist/computer/tools/files.d.ts.map +1 -0
  65. package/dist/computer/tools/files.js +58 -0
  66. package/dist/computer/tools/files.js.map +1 -0
  67. package/dist/computer/tools/sandboxes.d.ts +45 -0
  68. package/dist/computer/tools/sandboxes.d.ts.map +1 -0
  69. package/dist/computer/tools/sandboxes.js +230 -0
  70. package/dist/computer/tools/sandboxes.js.map +1 -0
  71. package/dist/computer/tools/shell.d.ts +22 -0
  72. package/dist/computer/tools/shell.d.ts.map +1 -0
  73. package/dist/computer/tools/shell.js +78 -0
  74. package/dist/computer/tools/shell.js.map +1 -0
  75. package/dist/config.d.ts +4 -0
  76. package/dist/config.d.ts.map +1 -0
  77. package/dist/config.js +7 -0
  78. package/dist/config.js.map +1 -0
  79. package/dist/resident.d.ts +8 -0
  80. package/dist/resident.d.ts.map +1 -0
  81. package/dist/resident.js +92 -0
  82. package/dist/resident.js.map +1 -0
  83. package/dist/status.d.ts +21 -0
  84. package/dist/status.d.ts.map +1 -0
  85. package/dist/status.js +123 -0
  86. package/dist/status.js.map +1 -0
  87. package/dist/sync/commands.d.ts +20 -0
  88. package/dist/sync/commands.d.ts.map +1 -0
  89. package/dist/sync/commands.js +244 -0
  90. package/dist/sync/commands.js.map +1 -0
  91. package/dist/sync/config.d.ts +41 -0
  92. package/dist/sync/config.d.ts.map +1 -0
  93. package/dist/sync/config.js +35 -0
  94. package/dist/sync/config.js.map +1 -0
  95. package/dist/sync/exec.d.ts +10 -0
  96. package/dist/sync/exec.d.ts.map +1 -0
  97. package/dist/sync/exec.js +26 -0
  98. package/dist/sync/exec.js.map +1 -0
  99. package/dist/sync/git-bridge.d.ts +11 -0
  100. package/dist/sync/git-bridge.d.ts.map +1 -0
  101. package/dist/sync/git-bridge.js +122 -0
  102. package/dist/sync/git-bridge.js.map +1 -0
  103. package/dist/sync/mirror.d.ts +19 -0
  104. package/dist/sync/mirror.d.ts.map +1 -0
  105. package/dist/sync/mirror.js +310 -0
  106. package/dist/sync/mirror.js.map +1 -0
  107. package/dist/sync/mutagen.d.ts +68 -0
  108. package/dist/sync/mutagen.d.ts.map +1 -0
  109. package/dist/sync/mutagen.js +289 -0
  110. package/dist/sync/mutagen.js.map +1 -0
  111. package/dist/sync/report.d.ts +6 -0
  112. package/dist/sync/report.d.ts.map +1 -0
  113. package/dist/sync/report.js +66 -0
  114. package/dist/sync/report.js.map +1 -0
  115. package/dist/sync/ssh.d.ts +29 -0
  116. package/dist/sync/ssh.d.ts.map +1 -0
  117. package/dist/sync/ssh.js +165 -0
  118. package/dist/sync/ssh.js.map +1 -0
  119. package/dist/sync/tunnel.d.ts +22 -0
  120. package/dist/sync/tunnel.d.ts.map +1 -0
  121. package/dist/sync/tunnel.js +160 -0
  122. package/dist/sync/tunnel.js.map +1 -0
  123. package/dist/upgrade.d.ts +36 -0
  124. package/dist/upgrade.d.ts.map +1 -0
  125. package/dist/upgrade.js +95 -0
  126. package/dist/upgrade.js.map +1 -0
  127. package/dist/version.d.ts +2 -0
  128. package/dist/version.d.ts.map +1 -0
  129. package/dist/version.js +2 -0
  130. package/dist/version.js.map +1 -0
  131. package/package.json +49 -0
package/dist/status.js ADDED
@@ -0,0 +1,123 @@
1
+ import { buildCommand } from "@stricli/core";
2
+ import { watcherStalled } from "@intentic/sandbox-contract";
3
+ import { auditPath, readLinks } from "./computer/config.js";
4
+ import { runLogPath } from "./config.js";
5
+ import { readResidentPid } from "./resident.js";
6
+ import { ensureMutagen, existingSyncSessions, runMutagen, syncSessionNames } from "./sync/mutagen.js";
7
+ import { machineReport } from "./sync/report.js";
8
+ import { MACHINE_VERSION } from "./version.js";
9
+ export const statusSummary = (running, links, sync, now) => {
10
+ const working = links > 0 || sync.pairings.length > 0;
11
+ if (!working) {
12
+ return "nothing connected";
13
+ }
14
+ const halves = [
15
+ links === 0 ? undefined : `${links} sandbox${links === 1 ? "" : "es"} connected`,
16
+ sync.pairings.length === 0 ? undefined : `syncing ${sync.pairings.length} sandbox${sync.pairings.length === 1 ? "" : "es"}`,
17
+ ].filter((part) => part !== undefined);
18
+ if (running === undefined) {
19
+ return `NOT RUNNING · ${halves.join(" · ")}`;
20
+ }
21
+ if (sync.pairings.length > 0 && watcherStalled(sync.watcher, now)) {
22
+ return `STALLED · ${halves.join(" · ")}`;
23
+ }
24
+ return halves.join(" · ");
25
+ };
26
+ export const machineStatus = async (mutagen) => {
27
+ const [pid, links, sync] = await Promise.all([readResidentPid(), readLinks(), machineReport(mutagen)]);
28
+ return {
29
+ version: MACHINE_VERSION,
30
+ ...(pid === undefined ? {} : { running: pid }),
31
+ summary: statusSummary(pid, links.length, sync, Date.now()),
32
+ computer: { links: links.map((link) => ({ sandboxUrl: link.sandboxUrl, id: link.id, scopes: link.scopes })) },
33
+ sync,
34
+ };
35
+ };
36
+ const portLine = (port) => {
37
+ const what = port.command ?? "unknown process";
38
+ if (port.state === "mirrored") {
39
+ return ` localhost:${port.port} ← ${port.sandboxId} (${what})`;
40
+ }
41
+ const reason = port.heldBy === undefined ? "something else on this machine has the port" : `${port.heldBy} has it`;
42
+ return ` localhost:${port.port}, NOT mirrored from ${port.sandboxId}: ${reason} (${what})`;
43
+ };
44
+ export const pairingLine = (pairing) => {
45
+ const where = pairing.mode === "sync" ? (pairing.localDir ?? "(no folder)") : "(ports only)";
46
+ const state = pairing.mode !== "sync"
47
+ ? []
48
+ : [
49
+ pairing.paused === true ? "paused" : (pairing.mutagenStatus ?? "NO FILE-SYNC SESSION, this folder is not syncing"),
50
+ pairing.conflicts === undefined || pairing.conflicts === 0 ? undefined : `${pairing.conflicts} conflict(s)`,
51
+ pairing.paused === true
52
+ ? undefined
53
+ : `backup ${pairing.backupStatus ?? "NOT RUNNING, this sandbox's own state is not being copied here"}`,
54
+ ].filter((part) => part !== undefined);
55
+ return ` ${pairing.sandboxId} ${where}${state.length === 0 ? "" : ` [${state.join(", ")}]`}`;
56
+ };
57
+ export const watcherLine = (watcher, now) => {
58
+ if (!watcher.running) {
59
+ return "Agent: NOT running, file syncing and port mirroring are both stopped. Run `intentic-machine run` to restart it.";
60
+ }
61
+ const since = watcher.lastTickAt === undefined ? undefined : now - watcher.lastTickAt;
62
+ if (watcherStalled(watcher, now) && since !== undefined) {
63
+ return `Agent: sync STALLED (pid ${watcher.pid}), the process is alive but its last full pass finished ${Math.round(since / 60_000)} minute(s) ago, so port mirroring, the git bridge and any file sync it has not created are stopped. Restart it with \`intentic-machine run --stop\` then \`intentic-machine run\`, and check ${runLogPath}.`;
64
+ }
65
+ return since === undefined
66
+ ? `Agent: running (pid ${watcher.pid}), no completed sync pass reported yet (a pass finishes within seconds of startup; an agent older than this one never reports them).`
67
+ : `Agent: running (pid ${watcher.pid}), last sync pass ${Math.round(since / 1000)}s ago`;
68
+ };
69
+ const printReport = (report, out) => {
70
+ out(`Paired sandboxes (${report.pairings.length}):`);
71
+ for (const pairing of report.pairings) {
72
+ out(pairingLine(pairing));
73
+ }
74
+ out(watcherLine(report.watcher, Date.now()));
75
+ out(`Ports (${report.ports.length}):`);
76
+ for (const port of report.ports) {
77
+ out(portLine(port));
78
+ }
79
+ };
80
+ export const status = buildCommand({
81
+ docs: { brief: "Show what this machine's agent is connected to, syncing, and mirroring, and whether it is alive" },
82
+ parameters: {
83
+ flags: {
84
+ json: { kind: "boolean", brief: "Emit the machine status as JSON (what the desktop app's tray and screen read)" },
85
+ },
86
+ },
87
+ async func(flags) {
88
+ const out = (message) => void this.process.stdout.write(`${message}\n`);
89
+ const mutagen = await ensureMutagen();
90
+ const report = await machineStatus(mutagen);
91
+ if (flags.json) {
92
+ out(JSON.stringify(report));
93
+ return;
94
+ }
95
+ out(`Agent: v${report.version}, ${report.running === undefined ? "NOT running (start it with `intentic-machine run`)" : `running (pid ${report.running})`}`);
96
+ out(`Logs: ${runLogPath}`);
97
+ out(`Audit: ${auditPath}`);
98
+ const links = report.computer.links;
99
+ out("");
100
+ out(`Linked sandboxes (${links.length}):`);
101
+ for (const link of links) {
102
+ out(` ${link.sandboxUrl} connected as ${link.id}`);
103
+ out(` permissions (last pushed by the sandbox): commands ${link.scopes.shell}, writes ${link.scopes.write}, screen ${link.scopes.screen}; folders ${link.scopes.roots ?? "(your home folder)"}`);
104
+ }
105
+ out("");
106
+ printReport(report.sync, out);
107
+ const syncing = report.sync.pairings.filter((pairing) => pairing.mode === "sync");
108
+ if (syncing.length > 0) {
109
+ out("File sync:");
110
+ const wanted = syncing.flatMap((pairing) => syncSessionNames(pairing.sandboxId));
111
+ const live = new Set(existingSyncSessions(mutagen, wanted));
112
+ if (live.size > 0) {
113
+ runMutagen(mutagen, ["sync", "list", ...wanted.filter((name) => live.has(name))]);
114
+ }
115
+ for (const pairing of syncing.filter((held) => !syncSessionNames(held.sandboxId).every((name) => live.has(name)))) {
116
+ out(` ${pairing.sandboxId}: no file-sync session exists on this machine, ${pairing.localDir ?? "its folder"} is NOT syncing. The agent retries every few minutes; if it stays this way the sandbox is unreachable (check ${runLogPath}).`);
117
+ }
118
+ }
119
+ out("Port mirroring:");
120
+ runMutagen(mutagen, ["forward", "list"]);
121
+ },
122
+ });
123
+ //# sourceMappingURL=status.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"status.js","sourceRoot":"","sources":["../src/status.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ import { type Log } from "@intentic/local-agent";
2
+ import { type CommandContext } from "@stricli/core";
3
+ import { type Pairing, type SyncMode, type SyncState } from "./config.js";
4
+ export declare const selectPairings: (state: SyncState, selector: string | undefined) => readonly Pairing[];
5
+ export declare const enrollKey: (sandboxUrl: string, pairToken: string, key: string, { attempts, delayMs, takeover }?: {
6
+ attempts?: number;
7
+ delayMs?: number;
8
+ takeover?: boolean;
9
+ }) => Promise<{
10
+ syncToken: string;
11
+ mode: SyncMode;
12
+ }>;
13
+ export declare const syncUninstall: (out: Log, sandbox?: string) => Promise<void>;
14
+ export declare const syncCommands: {
15
+ setup: import("@stricli/core").Command<CommandContext>;
16
+ pause: import("@stricli/core").Command<CommandContext>;
17
+ resume: import("@stricli/core").Command<CommandContext>;
18
+ uninstall: import("@stricli/core").Command<CommandContext>;
19
+ };
20
+ //# sourceMappingURL=commands.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"commands.d.ts","sourceRoot":"","sources":["../../src/sync/commands.ts"],"names":[],"mappings":"AAKA,OAAO,EAAY,KAAK,GAAG,EAA0B,MAAM,uBAAuB,CAAC;AAEnF,OAAO,EAAgB,KAAK,cAAc,EAAE,MAAM,eAAe,CAAC;AAElE,OAAO,EAAE,KAAK,OAAO,EAA4B,KAAK,QAAQ,EAAE,KAAK,SAAS,EAAiB,MAAM,aAAa,CAAC;AA4BnH,eAAO,MAAM,cAAc,UAAW,SAAS,YAAY,MAAM,GAAG,SAAS,KAAG,SAAS,OAAO,EAkB/F,CAAC;AAUF,eAAO,MAAM,SAAS,eACN,MAAM,aACP,MAAM,OACZ,MAAM,oCAC0C;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,OAAO,CAAA;CAAE,KACjH,OAAO,CAAC;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,QAAQ,CAAA;CAAE,CAsD/C,CAAC;AAiOF,eAAO,MAAM,aAAa,QAAe,GAAG,YAAY,MAAM,KAAG,OAAO,CAAC,IAAI,CAuD5E,CAAC;AAWF,eAAO,MAAM,YAAY;;;;;CAAsC,CAAC"}
@@ -0,0 +1,244 @@
1
+ import { spawnSync } from "node:child_process";
2
+ import { setTimeout as sleep } from "node:timers/promises";
3
+ import { mkdir } from "node:fs/promises";
4
+ import { homedir } from "node:os";
5
+ import { join, resolve } from "node:path";
6
+ import { createUi } from "@intentic/local-agent";
7
+ import { sandboxIdFromUrl } from "@intentic/sandbox-contract";
8
+ import { buildCommand } from "@stricli/core";
9
+ import { machineLauncher, reconcileResidency } from "../resident.js";
10
+ import { readState, removePairing, upsertPairing } from "./config.js";
11
+ import { realBridgeExec, runGitBridge } from "./git-bridge.js";
12
+ import { retirePairingMirror, teardownAllForwards } from "./mirror.js";
13
+ import { ensureMutagen, ensureSyncSession, registerMutagenAutostart, retireOrphanSessions, runMutagen, syncSessionNames, unregisterMutagenAutostart, } from "./mutagen.js";
14
+ import { syncSshPort, tunnelReady } from "./tunnel.js";
15
+ import { assertSshConfigVisible, ensureSshKey, mutagenSshPath, pairingSshConfig, probeSshTransport, removeManagedSshConfig, sanitizeId, sshAlias, writeManagedSshConfig, } from "./ssh.js";
16
+ export const selectPairings = (state, selector) => {
17
+ if (selector === undefined) {
18
+ return state.pairings;
19
+ }
20
+ const exact = state.pairings.filter((pairing) => pairing.sandboxId === sanitizeId(selector));
21
+ if (exact.length === 1) {
22
+ return exact;
23
+ }
24
+ const matched = state.pairings.filter((pairing) => pairing.sandboxId.includes(selector));
25
+ if (matched.length === 0) {
26
+ throw new Error(`no paired sandbox matches "${selector}". This machine pairs: ${state.pairings.map((pairing) => pairing.sandboxId).join(", ") || "none"}`);
27
+ }
28
+ if (matched.length > 1) {
29
+ throw new Error(`"${selector}" matches more than one paired sandbox: ${matched.map((pairing) => pairing.sandboxId).join(", ")}`);
30
+ }
31
+ return matched;
32
+ };
33
+ export const enrollKey = async (sandboxUrl, pairToken, key, { attempts = 10, delayMs = 3000, takeover = false } = {}) => {
34
+ const url = `${sandboxUrl.replace(/\/$/, "")}/system/authorized-key`;
35
+ for (let attempt = 1;; attempt++) {
36
+ let response;
37
+ try {
38
+ response = await fetch(url, {
39
+ method: "POST",
40
+ headers: {
41
+ "content-type": "application/json",
42
+ "x-intentic-pair": pairToken,
43
+ ...(takeover ? { "x-intentic-sync-takeover": "1" } : {}),
44
+ },
45
+ body: JSON.stringify({ key }),
46
+ });
47
+ }
48
+ catch (error) {
49
+ if (attempt >= attempts) {
50
+ throw error;
51
+ }
52
+ process.stderr.write(`enrolling the sync key: sandbox tunnel not reachable yet, retrying (${attempt}/${attempts})…\n`);
53
+ await sleep(delayMs);
54
+ continue;
55
+ }
56
+ if (response.status === 401) {
57
+ throw new Error("pairing expired: click 'Enable desktop sync' again in your browser for a fresh command.");
58
+ }
59
+ if (response.status >= 500 && attempt < attempts) {
60
+ process.stderr.write(`enrolling the sync key: sandbox tunnel warming up (HTTP ${response.status}), retrying (${attempt}/${attempts})…\n`);
61
+ await sleep(delayMs);
62
+ continue;
63
+ }
64
+ if (response.status === 423) {
65
+ const held = (await response.json().catch(() => ({})));
66
+ const from = held.machine !== undefined ? ` from "${held.machine}"` : "";
67
+ throw new Error(`desktop sync is already active on this sandbox${from}. Re-run with --takeover to move it to this machine (this stops syncing on the other one).`);
68
+ }
69
+ if (!response.ok) {
70
+ throw new Error(`enrolling the sync key failed (${response.status}): ${await response.text()}`);
71
+ }
72
+ const body = (await response.json());
73
+ if (body.syncToken === undefined) {
74
+ throw new Error("the sandbox enrolled this machine but returned no sync credential: update the sandbox and enable sync again.");
75
+ }
76
+ return { syncToken: body.syncToken, mode: body.mode ?? "sync" };
77
+ }
78
+ };
79
+ const revokeEnrollment = async (sandboxUrl, syncToken) => {
80
+ await fetch(`${sandboxUrl.replace(/\/$/, "")}/system/authorized-key`, { method: "DELETE", headers: { "x-intentic-sync": syncToken } });
81
+ };
82
+ const setup = buildCommand({
83
+ docs: { brief: "Enroll an SSH key with a pairing token and start a Mutagen sync of the local dir ↔ sandbox /work" },
84
+ parameters: {
85
+ flags: {
86
+ url: { kind: "parsed", parse: String, brief: "The sandbox's public URL (e.g. https://sandbox-xxx.example.dev)" },
87
+ pair: { kind: "parsed", parse: String, brief: "The one-time pairing token from the Desktop sync card" },
88
+ dir: {
89
+ kind: "parsed",
90
+ parse: String,
91
+ optional: true,
92
+ brief: "Local directory to sync (default: ~/intentic/<sandbox id>, the id in the sandbox's own URL)",
93
+ },
94
+ sandboxId: { kind: "parsed", parse: String, optional: true, brief: "Session/alias id (default: the sandbox URL host)" },
95
+ takeover: { kind: "boolean", brief: "Take over sync from another machine already enrolled on this sandbox (revokes its key)" },
96
+ },
97
+ },
98
+ async func(flags) {
99
+ const ui = createUi(this.process);
100
+ const out = ui.note;
101
+ ui.begin("intentic · desktop sync", SETUP_PLAN);
102
+ try {
103
+ await runSetup(ui, out, flags);
104
+ }
105
+ finally {
106
+ ui.close();
107
+ }
108
+ },
109
+ });
110
+ const SETUP_PLAN = [
111
+ { phase: "sync-enrolling", label: "Enrol this machine", weight: 25 },
112
+ { phase: "sync-linking", label: "Link the folder", weight: 5 },
113
+ { phase: "sync-starting", label: "Start syncing", weight: 20 },
114
+ ];
115
+ const runSetup = async (ui, out, flags) => {
116
+ ui.step("sync-enrolling", "enrolling this machine with your sandbox…");
117
+ const publicKey = await ensureSshKey();
118
+ const [{ syncToken, mode }, mutagen] = await Promise.all([
119
+ enrollKey(flags.url, flags.pair, publicKey, { takeover: flags.takeover }),
120
+ ensureMutagen(),
121
+ ]);
122
+ out(`enrolled SSH key with ${flags.url}`);
123
+ const sandboxId = flags.sandboxId ?? sanitizeId(new URL(flags.url).host);
124
+ const alias = sshAlias(sandboxId);
125
+ const localDir = mode === "sync"
126
+ ? resolve(flags.dir === undefined
127
+ ? join(homedir(), "intentic", sandboxIdFromUrl(flags.url) ?? sandboxId)
128
+ : flags.dir.replace(/^~(?=[\\/]|$)/, homedir()))
129
+ : undefined;
130
+ if (localDir !== undefined) {
131
+ await mkdir(localDir, { recursive: true });
132
+ }
133
+ const pairing = {
134
+ sandboxUrl: flags.url,
135
+ sandboxId,
136
+ mode,
137
+ syncToken,
138
+ ...(localDir === undefined ? {} : { localDir }),
139
+ };
140
+ ui.step("sync-linking", "linking the folder to your sandbox…");
141
+ await upsertPairing(pairing);
142
+ const pairings = (await readState()).pairings;
143
+ await writeManagedSshConfig(pairingSshConfig(pairings));
144
+ ui.step("sync-starting", "starting the sync engine…");
145
+ await reconcileResidency(out);
146
+ const port = syncSshPort(sandboxId);
147
+ if (!(await tunnelReady(port, TUNNEL_READY_MS))) {
148
+ out(`note: the sync transport for ${sandboxId} isn't listening on 127.0.0.1:${port} yet, syncing starts as soon as it is.`);
149
+ }
150
+ const ssh = mutagenSshPath(process.platform, process.env["MUTAGEN_SSH_PATH"]);
151
+ assertSshConfigVisible(ssh, alias, port);
152
+ await probeSshTransport(ssh, alias, out);
153
+ ensureSyncSession(mutagen, pairing, out);
154
+ retireOrphanSessions(mutagen, pairings, out);
155
+ runGitBridge(realBridgeExec, pairing, out, undefined);
156
+ registerMutagenAutostart(mutagen, machineLauncher(), out);
157
+ if (pairings.length > 1) {
158
+ ui.note(`This machine now syncs ${pairings.length} sandboxes:`);
159
+ for (const held of pairings) {
160
+ ui.note(` ${held.sandboxId}${held.localDir === undefined ? " (ports only)" : ` → ${held.localDir}`}`);
161
+ }
162
+ }
163
+ ui.finished(mode === "sync" ? "Desktop sync is running." : "Enrolled for port mirroring.", mode === "sync" ? localDir : undefined, mode === "sync"
164
+ ? "That folder and your sandbox's /work are now the same files."
165
+ : `Ports from ${flags.url} now answer on this machine's localhost (mirror-only, no file sync).`, [
166
+ ["check it", "intentic-machine status"],
167
+ ["remove it", "intentic-machine sync uninstall"],
168
+ ]);
169
+ };
170
+ const TUNNEL_READY_MS = 10_000;
171
+ const sandboxFlag = {
172
+ sandbox: {
173
+ kind: "parsed",
174
+ parse: String,
175
+ optional: true,
176
+ brief: "Act on one paired sandbox (its id, or any substring matching exactly one). Default: all of them",
177
+ },
178
+ };
179
+ const fileSyncOnly = (brief, verb) => buildCommand({
180
+ docs: { brief },
181
+ parameters: { flags: sandboxFlag },
182
+ async func(flags) {
183
+ const out = (message) => void this.process.stdout.write(`${message}\n`);
184
+ const selected = selectPairings(await readState(), flags.sandbox);
185
+ if (selected.length === 0) {
186
+ out(`no sandboxes are paired on this machine: nothing to ${verb}. Enable sync from a sandbox's Desktop sync card.`);
187
+ return;
188
+ }
189
+ const syncing = selected.filter((pairing) => pairing.mode === "sync");
190
+ if (syncing.length === 0) {
191
+ out(`mirror-only enrollment${selected.length > 1 ? "s" : ""}, no file sync to ${verb}.`);
192
+ return;
193
+ }
194
+ const mutagen = await ensureMutagen();
195
+ runMutagen(mutagen, ["sync", verb, ...syncing.flatMap((pairing) => syncSessionNames(pairing.sandboxId))]);
196
+ out(`${verb === "pause" ? "Paused" : "Resumed"} file sync for: ${syncing.map((pairing) => pairing.sandboxId).join(", ")}`);
197
+ },
198
+ });
199
+ const pause = fileSyncOnly("Pause file syncing", "pause");
200
+ const resume = fileSyncOnly("Resume file syncing", "resume");
201
+ export const syncUninstall = async (out, sandbox) => {
202
+ const state = await readState();
203
+ const dropped = selectPairings(state, sandbox);
204
+ const mutagen = await ensureMutagen();
205
+ const remaining = state.pairings.filter((held) => !dropped.some((pairing) => pairing.sandboxId === held.sandboxId));
206
+ for (const pairing of dropped) {
207
+ if (pairing.syncToken !== undefined) {
208
+ await revokeEnrollment(pairing.sandboxUrl, pairing.syncToken).catch(() => { });
209
+ }
210
+ if (pairing.mode === "sync") {
211
+ spawnSync(mutagen, ["sync", "terminate", ...syncSessionNames(pairing.sandboxId)], { stdio: "ignore", windowsHide: true });
212
+ }
213
+ await retirePairingMirror(mutagen, pairing.sandboxId);
214
+ await removePairing(pairing.sandboxId);
215
+ out(`unpaired ${pairing.sandboxId}${pairing.localDir === undefined ? "" : ` (${pairing.localDir} is no longer synced)`}.`);
216
+ }
217
+ if (remaining.length > 0) {
218
+ await writeManagedSshConfig(pairingSshConfig(remaining));
219
+ await reconcileResidency(out);
220
+ out(`Still syncing ${remaining.length} sandbox(es): ${remaining.map((pairing) => pairing.sandboxId).join(", ")}`);
221
+ return;
222
+ }
223
+ await reconcileResidency(out);
224
+ await teardownAllForwards(mutagen, out);
225
+ await removeManagedSshConfig();
226
+ const ownCopy = mutagen !== "mutagen";
227
+ if (ownCopy) {
228
+ unregisterMutagenAutostart(mutagen);
229
+ spawnSync(mutagen, ["daemon", "stop"], { stdio: "ignore", windowsHide: true });
230
+ }
231
+ out(ownCopy
232
+ ? "Sync terminated; ssh-config include removed; Mutagen daemon stopped and unregistered."
233
+ : "Sync terminated; ssh-config include removed. (Your own Mutagen install is untouched, `mutagen daemon unregister` if you no longer want its daemon at login.)");
234
+ };
235
+ const uninstall = buildCommand({
236
+ docs: { brief: "Unpair a sandbox (--sandbox), or stop syncing every sandbox on this machine" },
237
+ parameters: { flags: sandboxFlag },
238
+ async func(flags) {
239
+ const out = (message) => void this.process.stdout.write(`${message}\n`);
240
+ await syncUninstall(out, flags.sandbox);
241
+ },
242
+ });
243
+ export const syncCommands = { setup, pause, resume, uninstall };
244
+ //# sourceMappingURL=commands.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"commands.js","sourceRoot":"","sources":["../../src/sync/commands.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,41 @@
1
+ import type { PortSummary } from "@intentic/sandbox-contract";
2
+ export declare const sshKeyPath: string;
3
+ export declare const knownHostsPath: string;
4
+ export declare const binDir: string;
5
+ export declare const sshDir: string;
6
+ export declare const sshConfigName = "intentic-machine.conf";
7
+ export declare const sshConfigPath: string;
8
+ export declare const userSshConfigPath: string;
9
+ export declare const mutagenDaemonLogPath: string;
10
+ export declare const mirrorHeartbeatPath: string;
11
+ export interface MirroredPort {
12
+ readonly port: number;
13
+ readonly host: PortSummary["host"];
14
+ readonly command?: string | undefined;
15
+ }
16
+ export interface SkippedPort {
17
+ readonly port: number;
18
+ readonly host: PortSummary["host"];
19
+ readonly heldBy?: string | undefined;
20
+ readonly command?: string | undefined;
21
+ }
22
+ export type SyncMode = "sync" | "mirror";
23
+ export interface Pairing {
24
+ readonly sandboxUrl: string;
25
+ readonly sandboxId: string;
26
+ readonly mode: SyncMode;
27
+ readonly localDir?: string;
28
+ readonly syncToken?: string;
29
+ readonly mirroredPorts?: readonly MirroredPort[];
30
+ readonly skippedPorts?: readonly SkippedPort[];
31
+ readonly fileSyncAutoPaused?: boolean | undefined;
32
+ }
33
+ export interface SyncState {
34
+ readonly pairings: readonly Pairing[];
35
+ }
36
+ export declare const readState: () => Promise<SyncState>;
37
+ export declare const updateState: (mutate: (state: SyncState) => SyncState) => Promise<void>;
38
+ export declare const upsertPairing: (pairing: Pairing) => Promise<void>;
39
+ export declare const removePairing: (sandboxId: string) => Promise<void>;
40
+ export declare const setFileSyncAutoPaused: (sandboxId: string, paused: boolean) => Promise<void>;
41
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/sync/config.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AAU9D,eAAO,MAAM,UAAU,QAA8B,CAAC;AACtD,eAAO,MAAM,cAAc,QAA+B,CAAC;AAC3D,eAAO,MAAM,MAAM,QAAuB,CAAC;AAK3C,eAAO,MAAM,MAAM,QAA0B,CAAC;AAC9C,eAAO,MAAM,aAAa,0BAA0B,CAAC;AACrD,eAAO,MAAM,aAAa,QAA8B,CAAC;AACzD,eAAO,MAAM,iBAAiB,QAAyB,CAAC;AAOxD,eAAO,MAAM,oBAAoB,QAAsC,CAAC;AAaxE,eAAO,MAAM,mBAAmB,QAA+B,CAAC;AAMhE,MAAM,WAAW,YAAY;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IACnC,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACzC;AAOD,MAAM,WAAW,WAAW;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IACnC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACrC,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACzC;AAID,MAAM,MAAM,QAAQ,GAAG,MAAM,GAAG,QAAQ,CAAC;AAiBzC,MAAM,WAAW,OAAO;IACpB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IACxB,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,aAAa,CAAC,EAAE,SAAS,YAAY,EAAE,CAAC;IACjD,QAAQ,CAAC,YAAY,CAAC,EAAE,SAAS,WAAW,EAAE,CAAC;IAC/C,QAAQ,CAAC,kBAAkB,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;CACrD;AAUD,MAAM,WAAW,SAAS;IACtB,QAAQ,CAAC,QAAQ,EAAE,SAAS,OAAO,EAAE,CAAC;CACzC;AAMD,eAAO,MAAM,SAAS,QAAa,OAAO,CAAC,SAAS,CAYnD,CAAC;AAUF,eAAO,MAAM,WAAW,WAAkB,CAAC,KAAK,EAAE,SAAS,KAAK,SAAS,KAAG,OAAO,CAAC,IAAI,CACe,CAAC;AAIxG,eAAO,MAAM,aAAa,YAAmB,OAAO,KAAG,OAAO,CAAC,IAAI,CACkE,CAAC;AAEtI,eAAO,MAAM,aAAa,cAAqB,MAAM,KAAG,OAAO,CAAC,IAAI,CAC2C,CAAC;AAEhH,eAAO,MAAM,qBAAqB,cAAqB,MAAM,UAAU,OAAO,KAAG,OAAO,CAAC,IAAI,CAGtF,CAAC"}
@@ -0,0 +1,35 @@
1
+ import { readFile } from "node:fs/promises";
2
+ import { homedir } from "node:os";
3
+ import { join } from "node:path";
4
+ import { writeSecretFile } from "@intentic/local-agent";
5
+ import { baseDir } from "../config.js";
6
+ const configPath = join(baseDir, "sync.json");
7
+ export const sshKeyPath = join(baseDir, "id_ed25519");
8
+ export const knownHostsPath = join(baseDir, "known_hosts");
9
+ export const binDir = join(baseDir, "bin");
10
+ export const sshDir = join(homedir(), ".ssh");
11
+ export const sshConfigName = "intentic-machine.conf";
12
+ export const sshConfigPath = join(sshDir, sshConfigName);
13
+ export const userSshConfigPath = join(sshDir, "config");
14
+ export const mutagenDaemonLogPath = join(baseDir, "mutagen-daemon.log");
15
+ export const mirrorHeartbeatPath = join(baseDir, "mirror.tick");
16
+ export const readState = async () => {
17
+ const raw = await readFile(configPath, "utf8").catch((error) => {
18
+ if (error.code === "ENOENT") {
19
+ return undefined;
20
+ }
21
+ throw error;
22
+ });
23
+ if (raw === undefined) {
24
+ return { pairings: [] };
25
+ }
26
+ const parsed = JSON.parse(raw);
27
+ return { pairings: Array.isArray(parsed?.pairings) ? parsed.pairings : [] };
28
+ };
29
+ export const updateState = async (mutate) => await writeSecretFile(configPath, baseDir, JSON.stringify(mutate(await readState()), undefined, 2));
30
+ export const upsertPairing = async (pairing) => await updateState((state) => ({ pairings: [...state.pairings.filter((held) => held.sandboxId !== pairing.sandboxId), pairing] }));
31
+ export const removePairing = async (sandboxId) => await updateState((state) => ({ pairings: state.pairings.filter((held) => held.sandboxId !== sandboxId) }));
32
+ export const setFileSyncAutoPaused = async (sandboxId, paused) => await updateState((state) => ({
33
+ pairings: state.pairings.map((held) => (held.sandboxId === sandboxId ? { ...held, fileSyncAutoPaused: paused ? true : undefined } : held)),
34
+ }));
35
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/sync/config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ export interface ExecResult {
2
+ readonly status: number | null;
3
+ readonly stdout: string;
4
+ readonly stderr: string;
5
+ }
6
+ export declare const runProcess: (command: string, args: readonly string[], options?: {
7
+ readonly cwd?: string | undefined;
8
+ readonly timeoutMs?: number | undefined;
9
+ }) => Promise<ExecResult>;
10
+ //# sourceMappingURL=exec.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"exec.d.ts","sourceRoot":"","sources":["../../src/sync/exec.ts"],"names":[],"mappings":"AAyBA,MAAM,WAAW,UAAU;IAEvB,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CAC3B;AAED,eAAO,MAAM,UAAU,YACV,MAAM,QACT,SAAS,MAAM,EAAE,YACd;IAAE,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;CAAE,KACxF,OAAO,CAAC,UAAU,CAgCf,CAAC"}
@@ -0,0 +1,26 @@
1
+ import { spawn } from "node:child_process";
2
+ export const runProcess = async (command, args, options = {}) => await new Promise((resolve) => {
3
+ const child = spawn(command, [...args], {
4
+ ...(options.cwd === undefined ? {} : { cwd: options.cwd }),
5
+ stdio: ["ignore", "pipe", "pipe"],
6
+ windowsHide: true,
7
+ });
8
+ let stdout = "";
9
+ let stderr = "";
10
+ child.stdout.setEncoding("utf8");
11
+ child.stderr.setEncoding("utf8");
12
+ child.stdout.on("data", (chunk) => (stdout += chunk));
13
+ child.stderr.on("data", (chunk) => (stderr += chunk));
14
+ const timer = options.timeoutMs === undefined
15
+ ? undefined
16
+ : setTimeout(() => {
17
+ child.kill("SIGKILL");
18
+ }, options.timeoutMs);
19
+ const settle = (status, failure) => {
20
+ clearTimeout(timer);
21
+ resolve({ status, stdout, stderr: failure === undefined ? stderr : `${stderr}${failure.message}` });
22
+ };
23
+ child.on("error", (error) => settle(null, error));
24
+ child.on("close", (code) => settle(code));
25
+ });
26
+ //# sourceMappingURL=exec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"exec.js","sourceRoot":"","sources":["../../src/sync/exec.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAgC3C,MAAM,CAAC,MAAM,UAAU,GAAG,KAAK,EAC3B,OAAe,EACf,IAAuB,EACvB,OAAO,GAAmF,EAAE,EACzE,EAAE,CACrB,MAAM,IAAI,OAAO,CAAa,CAAC,OAAO,EAAE,EAAE;IAItC,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,EAAE,CAAC,GAAG,IAAI,CAAC,EAAE;QACpC,GAAG,CAAC,OAAO,CAAC,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE,CAAC;QAC1D,KAAK,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC;QACjC,WAAW,EAAE,IAAI;KACpB,CAAC,CAAC;IACH,IAAI,MAAM,GAAG,EAAE,CAAC;IAChB,IAAI,MAAM,GAAG,EAAE,CAAC;IAChB,KAAK,CAAC,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;IACjC,KAAK,CAAC,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;IACjC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAa,EAAE,EAAE,CAAC,CAAC,MAAM,IAAI,KAAK,CAAC,CAAC,CAAC;IAC9D,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAa,EAAE,EAAE,CAAC,CAAC,MAAM,IAAI,KAAK,CAAC,CAAC,CAAC;IAE9D,MAAM,KAAK,GACP,OAAO,CAAC,SAAS,KAAK,SAAS;QAC3B,CAAC,CAAC,SAAS;QACX,CAAC,CAAC,UAAU,CAAC,GAAG,EAAE;YACZ,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QAC1B,CAAC,EAAE,OAAO,CAAC,SAAS,CAAC,CAAC;IAEhC,MAAM,MAAM,GAAG,CAAC,MAAqB,EAAE,OAAe,EAAQ,EAAE;QAC5D,YAAY,CAAC,KAAK,CAAC,CAAC;QACpB,OAAO,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,MAAM,GAAG,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;IACxG,CAAC,CAAC;IAGF,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,KAAY,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC;IACzD,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC;AAC9C,CAAC,CAAC,CAAC"}
@@ -0,0 +1,11 @@
1
+ import type { Log } from "@intentic/local-agent";
2
+ import type { Pairing } from "./config.js";
3
+ export interface BridgeExec {
4
+ readonly run: (command: string, args: readonly string[], cwd?: string) => Promise<string | undefined>;
5
+ readonly exists: (path: string) => boolean;
6
+ }
7
+ export declare const realBridgeExec: BridgeExec;
8
+ export declare const listSandboxRepos: (exec: BridgeExec, alias: string) => Promise<string[] | undefined>;
9
+ export declare const bridgeRepo: (exec: BridgeExec, alias: string, localDir: string, repo: string, log: Log) => Promise<void>;
10
+ export declare const runGitBridge: (exec: BridgeExec, pairing: Pairing, log: Log, known: readonly string[] | undefined) => Promise<readonly string[] | undefined>;
11
+ //# sourceMappingURL=git-bridge.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git-bridge.d.ts","sourceRoot":"","sources":["../../src/sync/git-bridge.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,uBAAuB,CAAC;AACjD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAgC3C,MAAM,WAAW,UAAU;IAEvB,QAAQ,CAAC,GAAG,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,MAAM,EAAE,EAAE,GAAG,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IACtG,QAAQ,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC;CAC9C;AAKD,eAAO,MAAM,cAAc,EAAE,UAM5B,CAAC;AAcF,eAAO,MAAM,gBAAgB,SAAgB,UAAU,SAAS,MAAM,KAAG,OAAO,CAAC,MAAM,EAAE,GAAG,SAAS,CASpG,CAAC;AAKF,eAAO,MAAM,UAAU,SAAgB,UAAU,SAAS,MAAM,YAAY,MAAM,QAAQ,MAAM,OAAO,GAAG,KAAG,OAAO,CAAC,IAAI,CAgIxH,CAAC;AAQF,eAAO,MAAM,YAAY,SACf,UAAU,WACP,OAAO,OACX,GAAG,SACD,SAAS,MAAM,EAAE,GAAG,SAAS,KACrC,OAAO,CAAC,SAAS,MAAM,EAAE,GAAG,SAAS,CAmBvC,CAAC"}