extend the daemon thin-client surface to two more verb families: state get/set/list now routes through `/v1/state`, and remember/recall/forget through `/v1/memory`. same warm-path pattern as 1.25.0 — try the unix socket first, fall back to the cold ws path when the daemon is absent. multi-mesh aware (aggregates on read, requires `--mesh` for writes when ambiguous). also ships an early `claudemesh workspace <verb>` alias surface — bare teaser for the 1.28.0 mesh→workspace public rename. no-arg falls through to launch. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
99 lines
3.5 KiB
TypeScript
99 lines
3.5 KiB
TypeScript
/**
|
|
* `claudemesh state get <key>` — read a shared state value
|
|
* `claudemesh state set <key> <value>` — write a shared state value
|
|
* `claudemesh state list` — list all state entries
|
|
*/
|
|
|
|
import { withMesh } from "./connect.js";
|
|
import { tryGetStateViaDaemon, tryListStateViaDaemon, trySetStateViaDaemon } from "~/services/bridge/daemon-route.js";
|
|
import { render } from "~/ui/render.js";
|
|
import { bold, dim } from "~/ui/styles.js";
|
|
|
|
export interface StateFlags {
|
|
mesh?: string;
|
|
json?: boolean;
|
|
}
|
|
|
|
export async function runStateGet(flags: StateFlags, key: string): Promise<void> {
|
|
// Daemon path first.
|
|
const daemonEntry = await tryGetStateViaDaemon(key, flags.mesh);
|
|
if (daemonEntry !== null) {
|
|
if (!daemonEntry) { render.info(dim("(not set)")); return; }
|
|
if (flags.json) { console.log(JSON.stringify(daemonEntry, null, 2)); return; }
|
|
const val = typeof daemonEntry.value === "string" ? daemonEntry.value : JSON.stringify(daemonEntry.value);
|
|
render.info(val);
|
|
render.info(dim(` set by ${daemonEntry.updatedBy} at ${new Date(daemonEntry.updatedAt).toLocaleString()}`));
|
|
return;
|
|
}
|
|
await withMesh({ meshSlug: flags.mesh ?? null }, async (client) => {
|
|
const entry = await client.getState(key);
|
|
if (!entry) {
|
|
render.info(dim("(not set)"));
|
|
return;
|
|
}
|
|
if (flags.json) {
|
|
console.log(JSON.stringify(entry, null, 2));
|
|
return;
|
|
}
|
|
const val = typeof entry.value === "string" ? entry.value : JSON.stringify(entry.value);
|
|
render.info(val);
|
|
render.info(dim(` set by ${entry.updatedBy} at ${new Date(entry.updatedAt).toLocaleString()}`));
|
|
});
|
|
}
|
|
|
|
export async function runStateSet(flags: StateFlags, key: string, value: string): Promise<void> {
|
|
let parsed: unknown;
|
|
try {
|
|
parsed = JSON.parse(value);
|
|
} catch {
|
|
parsed = value;
|
|
}
|
|
|
|
// Daemon path first.
|
|
const daemonOk = await trySetStateViaDaemon(key, parsed, flags.mesh);
|
|
if (daemonOk) {
|
|
render.ok(`${bold(key)} = ${JSON.stringify(parsed)}`);
|
|
return;
|
|
}
|
|
await withMesh({ meshSlug: flags.mesh ?? null }, async (client) => {
|
|
await client.setState(key, parsed);
|
|
render.ok(`${bold(key)} = ${JSON.stringify(parsed)}`);
|
|
});
|
|
}
|
|
|
|
export async function runStateList(flags: StateFlags): Promise<void> {
|
|
// Daemon path first.
|
|
const daemonRows = await tryListStateViaDaemon(flags.mesh);
|
|
if (daemonRows !== null) {
|
|
if (flags.json) { console.log(JSON.stringify(daemonRows, null, 2)); return; }
|
|
if (daemonRows.length === 0) { render.info(dim("(no state)")); return; }
|
|
render.section(`state (${daemonRows.length})`);
|
|
for (const e of daemonRows) {
|
|
const val = typeof e.value === "string" ? e.value : JSON.stringify(e.value);
|
|
process.stdout.write(` ${bold(e.key)}: ${val}\n`);
|
|
process.stdout.write(` ${dim(e.updatedBy + " · " + new Date(e.updatedAt).toLocaleString())}\n`);
|
|
}
|
|
return;
|
|
}
|
|
await withMesh({ meshSlug: flags.mesh ?? null }, async (client, mesh) => {
|
|
const entries = await client.listState();
|
|
|
|
if (flags.json) {
|
|
console.log(JSON.stringify(entries, null, 2));
|
|
return;
|
|
}
|
|
|
|
if (entries.length === 0) {
|
|
render.info(dim(`No state on mesh "${mesh.slug}".`));
|
|
return;
|
|
}
|
|
|
|
render.section(`state (${entries.length})`);
|
|
for (const e of entries) {
|
|
const val = typeof e.value === "string" ? e.value : JSON.stringify(e.value);
|
|
process.stdout.write(` ${bold(e.key)}: ${val}\n`);
|
|
process.stdout.write(` ${dim(e.updatedBy + " · " + new Date(e.updatedAt).toLocaleString())}\n`);
|
|
}
|
|
});
|
|
}
|