@pcircle/memesh 4.7.3 → 4.8.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/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/AGENTS.md +3 -1
- package/README.de.md +42 -16
- package/README.md +46 -19
- package/README.zh-TW.md +42 -17
- package/dashboard/dist/index.html +1 -1
- package/dist/core/agent-message-storage.d.ts +76 -0
- package/dist/core/agent-message-storage.d.ts.map +1 -0
- package/dist/core/agent-message-storage.js +359 -0
- package/dist/core/agent-message-storage.js.map +1 -0
- package/dist/core/agent-messaging.d.ts +224 -0
- package/dist/core/agent-messaging.d.ts.map +1 -0
- package/dist/core/agent-messaging.js +881 -0
- package/dist/core/agent-messaging.js.map +1 -0
- package/dist/core/agent-router.d.ts +194 -0
- package/dist/core/agent-router.d.ts.map +1 -0
- package/dist/core/agent-router.js +1138 -0
- package/dist/core/agent-router.js.map +1 -0
- package/dist/core/briefing.d.ts.map +1 -1
- package/dist/core/briefing.js +8 -1
- package/dist/core/briefing.js.map +1 -1
- package/dist/core/config.d.ts.map +1 -1
- package/dist/core/config.js.map +1 -1
- package/dist/core/doctor.d.ts +19 -0
- package/dist/core/doctor.d.ts.map +1 -1
- package/dist/core/doctor.js +176 -2
- package/dist/core/doctor.js.map +1 -1
- package/dist/core/dreamer.d.ts +8 -5
- package/dist/core/dreamer.d.ts.map +1 -1
- package/dist/core/dreamer.js +88 -3
- package/dist/core/dreamer.js.map +1 -1
- package/dist/core/product-improvements.d.ts +61 -0
- package/dist/core/product-improvements.d.ts.map +1 -0
- package/dist/core/product-improvements.js +216 -0
- package/dist/core/product-improvements.js.map +1 -0
- package/dist/core/repo-state.d.ts +11 -0
- package/dist/core/repo-state.d.ts.map +1 -0
- package/dist/core/repo-state.js +70 -0
- package/dist/core/repo-state.js.map +1 -0
- package/dist/core/schema-export.d.ts.map +1 -1
- package/dist/core/schema-export.js +70 -0
- package/dist/core/schema-export.js.map +1 -1
- package/dist/core/task-state.d.ts.map +1 -1
- package/dist/core/task-state.js +3 -3
- package/dist/core/task-state.js.map +1 -1
- package/dist/core/updater.d.ts +2 -0
- package/dist/core/updater.d.ts.map +1 -1
- package/dist/core/updater.js +11 -5
- package/dist/core/updater.js.map +1 -1
- package/dist/core/work-topology.d.ts.map +1 -1
- package/dist/core/work-topology.js +1 -0
- package/dist/core/work-topology.js.map +1 -1
- package/dist/host-adapters/acp-client.d.ts +147 -0
- package/dist/host-adapters/acp-client.d.ts.map +1 -0
- package/dist/host-adapters/acp-client.js +793 -0
- package/dist/host-adapters/acp-client.js.map +1 -0
- package/dist/host-adapters/claude-channel.d.ts +75 -0
- package/dist/host-adapters/claude-channel.d.ts.map +1 -0
- package/dist/host-adapters/claude-channel.js +255 -0
- package/dist/host-adapters/claude-channel.js.map +1 -0
- package/dist/host-adapters/codex-app-server.d.ts +83 -0
- package/dist/host-adapters/codex-app-server.d.ts.map +1 -0
- package/dist/host-adapters/codex-app-server.js +360 -0
- package/dist/host-adapters/codex-app-server.js.map +1 -0
- package/dist/host-adapters/codex-cli-queue.d.ts +17 -0
- package/dist/host-adapters/codex-cli-queue.d.ts.map +1 -0
- package/dist/host-adapters/codex-cli-queue.js +85 -0
- package/dist/host-adapters/codex-cli-queue.js.map +1 -0
- package/dist/host-runtime/acp.d.ts +57 -0
- package/dist/host-runtime/acp.d.ts.map +1 -0
- package/dist/host-runtime/acp.js +338 -0
- package/dist/host-runtime/acp.js.map +1 -0
- package/dist/host-runtime/claude.d.ts +41 -0
- package/dist/host-runtime/claude.d.ts.map +1 -0
- package/dist/host-runtime/claude.js +213 -0
- package/dist/host-runtime/claude.js.map +1 -0
- package/dist/host-runtime/codex-session.d.ts +24 -0
- package/dist/host-runtime/codex-session.d.ts.map +1 -0
- package/dist/host-runtime/codex-session.js +98 -0
- package/dist/host-runtime/codex-session.js.map +1 -0
- package/dist/host-runtime/codex.d.ts +33 -0
- package/dist/host-runtime/codex.d.ts.map +1 -0
- package/dist/host-runtime/codex.js +215 -0
- package/dist/host-runtime/codex.js.map +1 -0
- package/dist/host-runtime/config.d.ts +9 -0
- package/dist/host-runtime/config.d.ts.map +1 -0
- package/dist/host-runtime/config.js +91 -0
- package/dist/host-runtime/config.js.map +1 -0
- package/dist/host-runtime/router-client.d.ts +38 -0
- package/dist/host-runtime/router-client.d.ts.map +1 -0
- package/dist/host-runtime/router-client.js +463 -0
- package/dist/host-runtime/router-client.js.map +1 -0
- package/dist/host-runtime/router.d.ts +3 -0
- package/dist/host-runtime/router.d.ts.map +1 -0
- package/dist/host-runtime/router.js +43 -0
- package/dist/host-runtime/router.js.map +1 -0
- package/dist/mcp/server.js +2 -2
- package/dist/mcp/server.js.map +1 -1
- package/dist/skills-manifest.json +22 -17
- package/dist/storage/conflicts.d.ts.map +1 -1
- package/dist/storage/conflicts.js +8 -1
- package/dist/storage/conflicts.js.map +1 -1
- package/dist/storage/schema.d.ts +1 -1
- package/dist/storage/schema.d.ts.map +1 -1
- package/dist/storage/schema.js +255 -0
- package/dist/storage/schema.js.map +1 -1
- package/dist/transports/agent-messaging.d.ts +11 -0
- package/dist/transports/agent-messaging.d.ts.map +1 -0
- package/dist/transports/agent-messaging.js +273 -0
- package/dist/transports/agent-messaging.js.map +1 -0
- package/dist/transports/cli/cli.d.ts +6 -1
- package/dist/transports/cli/cli.d.ts.map +1 -1
- package/dist/transports/cli/cli.js +392 -17
- package/dist/transports/cli/cli.js.map +1 -1
- package/dist/transports/http/server.d.ts.map +1 -1
- package/dist/transports/http/server.js +31 -2
- package/dist/transports/http/server.js.map +1 -1
- package/dist/transports/mcp/handlers.d.ts +152 -1
- package/dist/transports/mcp/handlers.d.ts.map +1 -1
- package/dist/transports/mcp/handlers.js +108 -3
- package/dist/transports/mcp/handlers.js.map +1 -1
- package/dist/transports/schemas.d.ts +106 -1
- package/dist/transports/schemas.d.ts.map +1 -1
- package/dist/transports/schemas.js +86 -0
- package/dist/transports/schemas.js.map +1 -1
- package/docs/platforms/README.md +167 -0
- package/docs/platforms/agent-messaging.md +290 -0
- package/hooks/hooks.json +11 -0
- package/llms-install.md +101 -25
- package/package.json +14 -5
- package/scripts/hooks/_generated/repo-state.js +77 -0
- package/scripts/hooks/_generated/schema.js +255 -0
- package/scripts/hooks/_generated/task-state.js +3 -3
- package/scripts/hooks/_generated/work-topology.js +1 -0
- package/scripts/hooks/_shared.js +77 -97
- package/scripts/hooks/auto-update-runner.mjs +243 -0
- package/scripts/hooks/session-start.js +12 -2
- package/scripts/hooks/session-summary.js +7 -6
- package/skills/memesh/SKILL.md +40 -1
|
@@ -16,6 +16,9 @@ import { inspectHosts, allWired } from '../../core/setup.js';
|
|
|
16
16
|
import { installHooks } from '../../core/install-hooks.js';
|
|
17
17
|
import { getTaskState, setTaskState } from '../../core/task-state-store.js';
|
|
18
18
|
import { TASK_STATE_FIELDS, taskStateLines } from '../../core/task-state.js';
|
|
19
|
+
import { executeAgentMessageAction } from '../agent-messaging.js';
|
|
20
|
+
import { getAgentMessageStorageReport, pruneTerminalAgentMessagePayloads, } from '../../core/agent-message-storage.js';
|
|
21
|
+
import { assertSecureLocalHostRuntimeSupported, ensureRouterTokenFile, } from '../../host-runtime/config.js';
|
|
19
22
|
async function withDatabase(fn) {
|
|
20
23
|
try {
|
|
21
24
|
openDatabase();
|
|
@@ -90,6 +93,23 @@ function isOnPath(tool) {
|
|
|
90
93
|
}
|
|
91
94
|
return false;
|
|
92
95
|
}
|
|
96
|
+
export function createHostConfigAtomically(host, configPath, config) {
|
|
97
|
+
try {
|
|
98
|
+
fs.writeFileSync(configPath, `${JSON.stringify(config, null, 2)}\n`, { flag: 'wx', mode: 0o600 });
|
|
99
|
+
}
|
|
100
|
+
catch (error) {
|
|
101
|
+
if (error.code === 'EEXIST') {
|
|
102
|
+
throw new Error(`Managed ${host} config already exists at ${configPath}; it was not overwritten.`, { cause: error });
|
|
103
|
+
}
|
|
104
|
+
throw error;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
export function feedbackBrowserOpenCommand(platform, url) {
|
|
108
|
+
const command = platform === 'darwin' ? 'open'
|
|
109
|
+
: platform === 'win32' ? 'explorer.exe'
|
|
110
|
+
: 'xdg-open';
|
|
111
|
+
return { command, args: [url] };
|
|
112
|
+
}
|
|
93
113
|
function wireUserHooks() {
|
|
94
114
|
const r = installHooks({ pluginRoot: packageRoot, pluginVersion: pkg.version, scope: 'user' });
|
|
95
115
|
return `hooks: added ${r.added}, skipped ${r.skipped} already-installed${r.backupPath ? ` (backup: ${r.backupPath})` : ''}`;
|
|
@@ -152,9 +172,11 @@ program
|
|
|
152
172
|
console.error('Error: --obs needs some text. An empty or whitespace-only observation is not a memory.');
|
|
153
173
|
process.exit(1);
|
|
154
174
|
}
|
|
175
|
+
const supersedes = Array.isArray(opts.supersedes) ? opts.supersedes : [];
|
|
176
|
+
const contradicts = Array.isArray(opts.contradicts) ? opts.contradicts : [];
|
|
155
177
|
const relations = [
|
|
156
|
-
...
|
|
157
|
-
...
|
|
178
|
+
...supersedes.map(to => ({ to, type: 'supersedes' })),
|
|
179
|
+
...contradicts.map(to => ({ to, type: 'contradicts' })),
|
|
158
180
|
];
|
|
159
181
|
await withDatabase(async () => {
|
|
160
182
|
const result = remember({
|
|
@@ -178,13 +200,15 @@ program
|
|
|
178
200
|
if (result.superseded?.length) {
|
|
179
201
|
console.log(` archived as superseded: ${result.superseded.join(', ')}`);
|
|
180
202
|
}
|
|
181
|
-
const
|
|
203
|
+
const relationsCreated = Array.isArray(result.relationsCreated) ? result.relationsCreated : [];
|
|
204
|
+
const contradicted = relationsCreated
|
|
182
205
|
.filter(r => r.type === 'contradicts')
|
|
183
206
|
.map(r => r.to);
|
|
184
207
|
if (contradicted.length > 0) {
|
|
185
208
|
console.log(` conflicts stated: ${contradicted.join(', ')}`);
|
|
186
209
|
}
|
|
187
|
-
|
|
210
|
+
const relationErrors = Array.isArray(result.relationErrors) ? result.relationErrors : [];
|
|
211
|
+
for (const err of relationErrors)
|
|
188
212
|
console.error(` ⚠️ ${err}`);
|
|
189
213
|
}
|
|
190
214
|
if (result.relationErrors?.length)
|
|
@@ -492,6 +516,331 @@ program
|
|
|
492
516
|
}
|
|
493
517
|
});
|
|
494
518
|
});
|
|
519
|
+
const messageCmd = program
|
|
520
|
+
.command('message')
|
|
521
|
+
.description('Send, wait for, fetch, and explicitly receipt durable local agent messages');
|
|
522
|
+
function parseCliMessagePayload(raw, contentType) {
|
|
523
|
+
if (contentType !== 'application/json')
|
|
524
|
+
return raw;
|
|
525
|
+
try {
|
|
526
|
+
return JSON.parse(raw);
|
|
527
|
+
}
|
|
528
|
+
catch {
|
|
529
|
+
throw new Error('stdin must contain valid JSON when --content-type is application/json.');
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
const MAX_CLI_MESSAGE_STDIN_BYTES = 65_536;
|
|
533
|
+
async function readCliMessagePayloadFromStdin(contentType) {
|
|
534
|
+
let raw = '';
|
|
535
|
+
let bytes = 0;
|
|
536
|
+
for await (const chunk of process.stdin) {
|
|
537
|
+
const text = typeof chunk === 'string' ? chunk : Buffer.from(chunk).toString('utf8');
|
|
538
|
+
bytes += Buffer.byteLength(text, 'utf8');
|
|
539
|
+
if (bytes > MAX_CLI_MESSAGE_STDIN_BYTES) {
|
|
540
|
+
throw new Error(`stdin payload exceeds ${MAX_CLI_MESSAGE_STDIN_BYTES} UTF-8 bytes.`);
|
|
541
|
+
}
|
|
542
|
+
raw += text;
|
|
543
|
+
}
|
|
544
|
+
if (bytes === 0) {
|
|
545
|
+
throw new Error('stdin payload is empty.');
|
|
546
|
+
}
|
|
547
|
+
return parseCliMessagePayload(raw, contentType);
|
|
548
|
+
}
|
|
549
|
+
async function runCliMessage(input) {
|
|
550
|
+
await withDatabase(async () => {
|
|
551
|
+
try {
|
|
552
|
+
const result = await executeAgentMessageAction(getDatabase(), input, {
|
|
553
|
+
transport: 'cli',
|
|
554
|
+
sourceHost: 'cli',
|
|
555
|
+
});
|
|
556
|
+
console.log(JSON.stringify(result));
|
|
557
|
+
}
|
|
558
|
+
catch (error) {
|
|
559
|
+
console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);
|
|
560
|
+
process.exitCode = 1;
|
|
561
|
+
}
|
|
562
|
+
});
|
|
563
|
+
}
|
|
564
|
+
function isAgentPollResult(value) {
|
|
565
|
+
if (typeof value !== 'object' || value === null)
|
|
566
|
+
return false;
|
|
567
|
+
const candidate = value;
|
|
568
|
+
return Array.isArray(candidate.events) && typeof candidate.next_cursor === 'string';
|
|
569
|
+
}
|
|
570
|
+
messageCmd
|
|
571
|
+
.command('send')
|
|
572
|
+
.description('Durably send one exact-recipient local message (idempotent)')
|
|
573
|
+
.requiredOption('--project <name>', 'Project scope')
|
|
574
|
+
.requiredOption('--sender <id>', 'Stable sender agent/host ID')
|
|
575
|
+
.requiredOption('--recipient <id>', 'Stable recipient agent/host ID')
|
|
576
|
+
.option('--target-kind <kind>', 'principal | session', 'principal')
|
|
577
|
+
.requiredOption('--idempotency-key <key>', 'Stable retry key')
|
|
578
|
+
.requiredOption('--payload-stdin', 'Read the complete text or JSON payload from stdin (never argv)')
|
|
579
|
+
.option('--content-type <type>', 'text/plain | application/json', 'text/plain')
|
|
580
|
+
.option('--privacy <scope>', 'private | team', 'private')
|
|
581
|
+
.option('--correlation-id <id>', 'Conversation or task correlation ID')
|
|
582
|
+
.option('--reply-to <message-id>', 'Message ID this replies to')
|
|
583
|
+
.action(async (opts) => {
|
|
584
|
+
requireOneOf(opts.contentType, ['text/plain', 'application/json'], '--content-type');
|
|
585
|
+
requireOneOf(opts.privacy, ['private', 'team'], '--privacy');
|
|
586
|
+
requireOneOf(opts.targetKind, ['principal', 'session'], '--target-kind');
|
|
587
|
+
try {
|
|
588
|
+
await runCliMessage({
|
|
589
|
+
action: 'send',
|
|
590
|
+
project: opts.project,
|
|
591
|
+
sender: opts.sender,
|
|
592
|
+
recipient: opts.recipient,
|
|
593
|
+
target_kind: opts.targetKind,
|
|
594
|
+
idempotency_key: opts.idempotencyKey,
|
|
595
|
+
payload: await readCliMessagePayloadFromStdin(opts.contentType),
|
|
596
|
+
content_type: opts.contentType,
|
|
597
|
+
privacy: opts.privacy,
|
|
598
|
+
correlation_id: opts.correlationId,
|
|
599
|
+
reply_to: opts.replyTo,
|
|
600
|
+
});
|
|
601
|
+
}
|
|
602
|
+
catch (error) {
|
|
603
|
+
console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);
|
|
604
|
+
process.exitCode = 1;
|
|
605
|
+
}
|
|
606
|
+
});
|
|
607
|
+
messageCmd
|
|
608
|
+
.command('watch')
|
|
609
|
+
.description('Wait once for an exact-recipient event batch and emit privacy-minimized JSONL')
|
|
610
|
+
.requiredOption('--project <name>', 'Project scope')
|
|
611
|
+
.requiredOption('--recipient <id>', 'Stable recipient agent/host ID')
|
|
612
|
+
.option('--cursor <token>', 'Opaque cursor returned by an earlier watch/poll')
|
|
613
|
+
.option('--wait-ms <ms>', 'Bounded wait, 0-30000 milliseconds', wholeNumber('--wait-ms', 0), 30_000)
|
|
614
|
+
.option('--limit <n>', 'Maximum events, 1-100', wholeNumber('--limit'), 20)
|
|
615
|
+
.action(async (opts) => {
|
|
616
|
+
await withDatabase(async () => {
|
|
617
|
+
console.log(JSON.stringify({
|
|
618
|
+
type: 'ready',
|
|
619
|
+
project: opts.project,
|
|
620
|
+
recipient: opts.recipient,
|
|
621
|
+
cursor: opts.cursor ?? null,
|
|
622
|
+
}));
|
|
623
|
+
try {
|
|
624
|
+
const result = await executeAgentMessageAction(getDatabase(), {
|
|
625
|
+
action: 'poll',
|
|
626
|
+
project: opts.project,
|
|
627
|
+
recipient: opts.recipient,
|
|
628
|
+
cursor: opts.cursor,
|
|
629
|
+
wait_ms: opts.waitMs,
|
|
630
|
+
limit: opts.limit,
|
|
631
|
+
}, {
|
|
632
|
+
transport: 'cli',
|
|
633
|
+
sourceHost: 'cli',
|
|
634
|
+
});
|
|
635
|
+
if (!isAgentPollResult(result)) {
|
|
636
|
+
throw new Error('Message watch returned an invalid poll result.');
|
|
637
|
+
}
|
|
638
|
+
console.log(JSON.stringify({
|
|
639
|
+
type: result.events.length > 0 ? 'events' : 'timeout',
|
|
640
|
+
...result,
|
|
641
|
+
}));
|
|
642
|
+
}
|
|
643
|
+
catch (error) {
|
|
644
|
+
console.error(JSON.stringify({
|
|
645
|
+
type: 'error',
|
|
646
|
+
error: error instanceof Error ? error.message : String(error),
|
|
647
|
+
}));
|
|
648
|
+
process.exitCode = 1;
|
|
649
|
+
}
|
|
650
|
+
});
|
|
651
|
+
});
|
|
652
|
+
messageCmd
|
|
653
|
+
.command('fetch')
|
|
654
|
+
.description('Fetch one payload routed to the exact principal or session without acknowledging it')
|
|
655
|
+
.requiredOption('--project <name>', 'Project scope')
|
|
656
|
+
.requiredOption('--recipient <id>', 'Stable recipient agent/host ID')
|
|
657
|
+
.option('--target-kind <kind>', 'principal | session', 'principal')
|
|
658
|
+
.requiredOption('--message-id <id>', 'Message ID')
|
|
659
|
+
.action((opts) => {
|
|
660
|
+
requireOneOf(opts.targetKind, ['principal', 'session'], '--target-kind');
|
|
661
|
+
return runCliMessage({
|
|
662
|
+
action: 'fetch', project: opts.project, recipient: opts.recipient,
|
|
663
|
+
target_kind: opts.targetKind, message_id: opts.messageId,
|
|
664
|
+
});
|
|
665
|
+
});
|
|
666
|
+
messageCmd
|
|
667
|
+
.command('intake')
|
|
668
|
+
.description('Record fetched/ingested state without implying ACK')
|
|
669
|
+
.requiredOption('--project <name>', 'Project scope')
|
|
670
|
+
.requiredOption('--recipient <id>', 'Stable recipient agent/host ID')
|
|
671
|
+
.requiredOption('--message-id <id>', 'Message ID')
|
|
672
|
+
.requiredOption('--idempotency-key <key>', 'Stable retry key')
|
|
673
|
+
.requiredOption('--state <state>', 'fetched | ingested')
|
|
674
|
+
.action(async (opts) => {
|
|
675
|
+
requireOneOf(opts.state, ['fetched', 'ingested'], '--state');
|
|
676
|
+
await runCliMessage({
|
|
677
|
+
action: 'intake', project: opts.project, recipient: opts.recipient,
|
|
678
|
+
message_id: opts.messageId, idempotency_key: opts.idempotencyKey, intake_state: opts.state,
|
|
679
|
+
});
|
|
680
|
+
});
|
|
681
|
+
messageCmd
|
|
682
|
+
.command('ack')
|
|
683
|
+
.description('Record explicit recipient acknowledgement')
|
|
684
|
+
.requiredOption('--project <name>', 'Project scope')
|
|
685
|
+
.requiredOption('--recipient <id>', 'Stable recipient agent/host ID')
|
|
686
|
+
.requiredOption('--message-id <id>', 'Message ID')
|
|
687
|
+
.requiredOption('--idempotency-key <key>', 'Stable retry key')
|
|
688
|
+
.action((opts) => runCliMessage({
|
|
689
|
+
action: 'ack', project: opts.project, recipient: opts.recipient,
|
|
690
|
+
message_id: opts.messageId, idempotency_key: opts.idempotencyKey,
|
|
691
|
+
}));
|
|
692
|
+
messageCmd
|
|
693
|
+
.command('disposition')
|
|
694
|
+
.description('Record a workflow disposition independently from ACK')
|
|
695
|
+
.requiredOption('--project <name>', 'Project scope')
|
|
696
|
+
.requiredOption('--recipient <id>', 'Stable recipient agent/host ID')
|
|
697
|
+
.requiredOption('--message-id <id>', 'Message ID')
|
|
698
|
+
.requiredOption('--idempotency-key <key>', 'Stable retry key')
|
|
699
|
+
.requiredOption('--value <state>', 'accepted | rejected | completed | cancelled | deferred')
|
|
700
|
+
.option('--detail <text>', 'Optional bounded explanation')
|
|
701
|
+
.action(async (opts) => {
|
|
702
|
+
requireOneOf(opts.value, ['accepted', 'rejected', 'completed', 'cancelled', 'deferred'], '--value');
|
|
703
|
+
await runCliMessage({
|
|
704
|
+
action: 'disposition', project: opts.project, recipient: opts.recipient,
|
|
705
|
+
message_id: opts.messageId, idempotency_key: opts.idempotencyKey,
|
|
706
|
+
disposition: opts.value, detail: opts.detail,
|
|
707
|
+
});
|
|
708
|
+
});
|
|
709
|
+
messageCmd
|
|
710
|
+
.command('activation')
|
|
711
|
+
.description('Record host activation outcome independently from ACK/disposition')
|
|
712
|
+
.requiredOption('--project <name>', 'Project scope')
|
|
713
|
+
.requiredOption('--recipient <id>', 'Stable recipient agent/host ID')
|
|
714
|
+
.requiredOption('--message-id <id>', 'Message ID')
|
|
715
|
+
.requiredOption('--idempotency-key <key>', 'Stable retry key')
|
|
716
|
+
.requiredOption('--value <state>', 'woken | manual_resume_required | unsupported | failed')
|
|
717
|
+
.option('--detail <text>', 'Optional bounded explanation')
|
|
718
|
+
.action(async (opts) => {
|
|
719
|
+
requireOneOf(opts.value, ['woken', 'manual_resume_required', 'unsupported', 'failed'], '--value');
|
|
720
|
+
await runCliMessage({
|
|
721
|
+
action: 'activation', project: opts.project, recipient: opts.recipient,
|
|
722
|
+
message_id: opts.messageId, idempotency_key: opts.idempotencyKey,
|
|
723
|
+
activation: opts.value, detail: opts.detail,
|
|
724
|
+
});
|
|
725
|
+
});
|
|
726
|
+
messageCmd
|
|
727
|
+
.command('receipts')
|
|
728
|
+
.description('Read receipt facts for one message routed to the logical recipient')
|
|
729
|
+
.requiredOption('--project <name>', 'Project scope')
|
|
730
|
+
.requiredOption('--recipient <id>', 'Stable recipient agent/host ID')
|
|
731
|
+
.requiredOption('--message-id <id>', 'Message ID')
|
|
732
|
+
.action((opts) => runCliMessage({
|
|
733
|
+
action: 'receipts', project: opts.project, recipient: opts.recipient, message_id: opts.messageId,
|
|
734
|
+
}));
|
|
735
|
+
const messageStorageCmd = messageCmd
|
|
736
|
+
.command('storage')
|
|
737
|
+
.description('Inspect or bound durable agent-message payload storage without deleting lifecycle audit facts');
|
|
738
|
+
messageStorageCmd
|
|
739
|
+
.command('report')
|
|
740
|
+
.description('Report logical payload, unresolved protection, reusable pages, and SQLite/WAL size')
|
|
741
|
+
.requiredOption('--cutoff <iso-time>', 'Terminal workflows strictly older than this ISO timestamp are prunable')
|
|
742
|
+
.action(async (opts) => {
|
|
743
|
+
await withDatabase(() => {
|
|
744
|
+
const report = getAgentMessageStorageReport(getDatabase(), {
|
|
745
|
+
cutoff: opts.cutoff,
|
|
746
|
+
databasePath: getDbPath(),
|
|
747
|
+
});
|
|
748
|
+
console.log(JSON.stringify({
|
|
749
|
+
policy: {
|
|
750
|
+
cutoff: new Date(opts.cutoff).toISOString(),
|
|
751
|
+
quota_bytes: process.env.MEMESH_AGENT_MESSAGE_STORAGE_QUOTA_BYTES ?? null,
|
|
752
|
+
automatic_pruning: false,
|
|
753
|
+
},
|
|
754
|
+
...report,
|
|
755
|
+
}));
|
|
756
|
+
});
|
|
757
|
+
});
|
|
758
|
+
messageStorageCmd
|
|
759
|
+
.command('prune')
|
|
760
|
+
.description('Dry-run one bounded terminal-payload tombstone batch; --apply performs it')
|
|
761
|
+
.requiredOption('--cutoff <iso-time>', 'Terminal workflows strictly older than this ISO timestamp are eligible')
|
|
762
|
+
.option('--batch-size <n>', 'Maximum payloads in this transaction, 1-1000', wholeNumber('--batch-size'), 100)
|
|
763
|
+
.option('--apply', 'Write hash-bound tombstones; without this flag nothing is changed')
|
|
764
|
+
.option('--actor <id>', 'Bounded audit actor', 'local-owner-cli')
|
|
765
|
+
.action(async (opts) => {
|
|
766
|
+
await withDatabase(() => {
|
|
767
|
+
const result = pruneTerminalAgentMessagePayloads(getDatabase(), {
|
|
768
|
+
cutoff: opts.cutoff,
|
|
769
|
+
databasePath: getDbPath(),
|
|
770
|
+
batchSize: opts.batchSize,
|
|
771
|
+
dryRun: !opts.apply,
|
|
772
|
+
actor: opts.actor,
|
|
773
|
+
});
|
|
774
|
+
console.log(JSON.stringify(result));
|
|
775
|
+
});
|
|
776
|
+
});
|
|
777
|
+
const agentCmd = program
|
|
778
|
+
.command('agent')
|
|
779
|
+
.description('Set up reusable owner-private local host configuration');
|
|
780
|
+
agentCmd
|
|
781
|
+
.command('setup')
|
|
782
|
+
.argument('<host>', 'codex-session | codex | claude | gemini')
|
|
783
|
+
.requiredOption('--project <name>', 'Project scope used for exact routing')
|
|
784
|
+
.requiredOption('--principal <id>', 'Stable logical recipient ID')
|
|
785
|
+
.option('--workspace <path>', 'Managed Codex/Gemini workspace', process.cwd())
|
|
786
|
+
.option('--json', 'Output machine-readable setup result')
|
|
787
|
+
.action((host, opts) => {
|
|
788
|
+
requireOneOf(host, ['codex-session', 'codex', 'claude', 'gemini'], '<host>');
|
|
789
|
+
assertSecureLocalHostRuntimeSupported();
|
|
790
|
+
const messageDir = path.dirname(getDbPath());
|
|
791
|
+
const hostsDir = path.join(messageDir, 'hosts');
|
|
792
|
+
fs.mkdirSync(hostsDir, { recursive: true, mode: 0o700 });
|
|
793
|
+
const hostsStat = fs.lstatSync(hostsDir);
|
|
794
|
+
if (!hostsStat.isDirectory() || hostsStat.isSymbolicLink() || (hostsStat.mode & 0o077) !== 0) {
|
|
795
|
+
throw new Error('The managed host config directory must be a real owner-private directory.');
|
|
796
|
+
}
|
|
797
|
+
const filename = host === 'gemini' ? 'gemini-acp.json' : `${host}.json`;
|
|
798
|
+
const configPath = path.join(hostsDir, filename);
|
|
799
|
+
const routerTokenFile = path.join(messageDir, 'agent-router.token');
|
|
800
|
+
ensureRouterTokenFile(routerTokenFile);
|
|
801
|
+
const common = {
|
|
802
|
+
router_socket: path.join(messageDir, 'agent-router.sock'),
|
|
803
|
+
token_file: routerTokenFile,
|
|
804
|
+
project: opts.project,
|
|
805
|
+
principal_id: opts.principal,
|
|
806
|
+
};
|
|
807
|
+
const config = host === 'codex-session'
|
|
808
|
+
? { ...common, workspace: fs.realpathSync(path.resolve(opts.workspace)) }
|
|
809
|
+
: host === 'codex'
|
|
810
|
+
? { ...common, control_socket: path.join(hostsDir, 'codex-app-server.sock'), workspace: path.resolve(opts.workspace) }
|
|
811
|
+
: host === 'claude'
|
|
812
|
+
? { ...common, server_name: 'memesh-channel' }
|
|
813
|
+
: { ...common, workspace: path.resolve(opts.workspace), command: 'gemini', args: [] };
|
|
814
|
+
createHostConfigAtomically(host, configPath, config);
|
|
815
|
+
const launchCommand = host === 'codex-session'
|
|
816
|
+
? null
|
|
817
|
+
: host === 'codex'
|
|
818
|
+
? `memesh-host-codex --config ${JSON.stringify(configPath)}`
|
|
819
|
+
: host === 'claude'
|
|
820
|
+
? 'claude --dangerously-load-development-channels server:memesh-channel'
|
|
821
|
+
: `memesh-host-acp --config ${JSON.stringify(configPath)}`;
|
|
822
|
+
const registrationCommand = host === 'claude'
|
|
823
|
+
? `claude mcp add --transport stdio --scope user memesh-channel -- memesh-host-claude --config ${JSON.stringify(configPath)}`
|
|
824
|
+
: null;
|
|
825
|
+
const result = {
|
|
826
|
+
host,
|
|
827
|
+
config_path: configPath,
|
|
828
|
+
mode: host === 'codex-session'
|
|
829
|
+
? 'ordinary-session-native-queue'
|
|
830
|
+
: host === 'claude' ? 'session-owned-channel' : 'memesh-managed-session',
|
|
831
|
+
session_identity: host === 'codex-session' ? 'codex-thread-id-at-session-start' : 'generated-per-process',
|
|
832
|
+
ordinary_sessions: host === 'codex-session' ? 'explicit-workspace-opt-in' : 'presence-only/inbound-unavailable',
|
|
833
|
+
registration_command: registrationCommand,
|
|
834
|
+
launch_command: launchCommand,
|
|
835
|
+
next_command: registrationCommand ?? launchCommand ?? 'Restart Codex in the configured workspace',
|
|
836
|
+
};
|
|
837
|
+
console.log(opts.json ? JSON.stringify(result) : [
|
|
838
|
+
`Created owner-private ${host} config: ${configPath}`,
|
|
839
|
+
'No active or stopped ordinary session was attached.',
|
|
840
|
+
...(registrationCommand ? [`Register once: ${registrationCommand}`] : []),
|
|
841
|
+
...(launchCommand ? [`Launch: ${launchCommand}`] : ['Restart Codex in the configured workspace.']),
|
|
842
|
+
].join('\n'));
|
|
843
|
+
});
|
|
495
844
|
program
|
|
496
845
|
.command('briefing')
|
|
497
846
|
.description('The assembled work topology for a project — task state, decisions, lessons, knowledge, recent activity')
|
|
@@ -639,7 +988,8 @@ program
|
|
|
639
988
|
console.log('\nPlanned actions:');
|
|
640
989
|
for (const st of pending)
|
|
641
990
|
for (const a of st.actions) {
|
|
642
|
-
|
|
991
|
+
const actionArgs = Array.isArray(a.args) ? a.args : [];
|
|
992
|
+
console.log(` • [${st.title}] ${a.label}${a.cmd ? `\n ${a.cmd} ${actionArgs.join(' ')}` : ''}`);
|
|
643
993
|
}
|
|
644
994
|
if (!opts.yes && !process.stdin.isTTY) {
|
|
645
995
|
console.error('\nNot a terminal and --yes not given — nothing was changed. Re-run with: memesh setup --yes');
|
|
@@ -665,9 +1015,10 @@ program
|
|
|
665
1015
|
console.log(` ✅ ${wireUserHooks()}`);
|
|
666
1016
|
}
|
|
667
1017
|
else if (action.cmd) {
|
|
668
|
-
const
|
|
1018
|
+
const actionArgs = Array.isArray(action.args) ? action.args : [];
|
|
1019
|
+
const r = runSeam(action.cmd, actionArgs);
|
|
669
1020
|
if (r.status === 0)
|
|
670
|
-
console.log(` ✅ done (${action.cmd} ${
|
|
1021
|
+
console.log(` ✅ done (${action.cmd} ${actionArgs.join(' ')})`);
|
|
671
1022
|
else {
|
|
672
1023
|
console.error(` ❌ ${action.cmd} exited ${r.status ?? 'without running'}${r.stderr ? `: ${r.stderr.trim()}` : ''}`);
|
|
673
1024
|
failed = true;
|
|
@@ -1598,7 +1949,8 @@ dreamCmd
|
|
|
1598
1949
|
console.log('');
|
|
1599
1950
|
for (const p of proposals) {
|
|
1600
1951
|
const srcLabel = p.kind === 'relation' ? ' (conflict)'
|
|
1601
|
-
: p.
|
|
1952
|
+
: p.kind === 'product_improvement' ? ' (product improvement)'
|
|
1953
|
+
: p.source_kind === 'transcript' ? ' (transcript)' : '';
|
|
1602
1954
|
console.log(` #${p.id} [${p.project}/${p.cluster_key}]${srcLabel} ${p.source_count} source(s) → "${p.digest_name}"`);
|
|
1603
1955
|
if (p.digest_observations_preview !== null) {
|
|
1604
1956
|
console.log(` ${p.digest_observations_preview}`);
|
|
@@ -1698,6 +2050,11 @@ dreamCmd
|
|
|
1698
2050
|
console.log(`Accept: memesh dream accept ${detail.id} | Reject: memesh dream reject ${detail.id}`);
|
|
1699
2051
|
return;
|
|
1700
2052
|
}
|
|
2053
|
+
if (detail.kind === 'product_improvement') {
|
|
2054
|
+
const improvement = detail.digest;
|
|
2055
|
+
console.log(`title: ${improvement.title ?? detail.digest.name}`);
|
|
2056
|
+
console.log('authority: human review required; acceptance does not mean implemented or effective');
|
|
2057
|
+
}
|
|
1701
2058
|
console.log(`name: ${detail.digest.name}`);
|
|
1702
2059
|
console.log(`type: ${detail.digest.type}`);
|
|
1703
2060
|
console.log(`observations (${detail.digest.observations.length}):`);
|
|
@@ -1712,7 +2069,7 @@ dreamCmd
|
|
|
1712
2069
|
});
|
|
1713
2070
|
dreamCmd
|
|
1714
2071
|
.command('accept <id>')
|
|
1715
|
-
.description('
|
|
2072
|
+
.description('Apply a reviewed pending proposal (behaviour depends on proposal kind)')
|
|
1716
2073
|
.action(async (id) => {
|
|
1717
2074
|
await withDatabase(async () => {
|
|
1718
2075
|
const { applyProposal } = await import('../../core/dreamer.js');
|
|
@@ -1729,8 +2086,15 @@ dreamCmd
|
|
|
1729
2086
|
process.exit(1);
|
|
1730
2087
|
}
|
|
1731
2088
|
console.log(`Applied proposal #${result.proposalId}`);
|
|
1732
|
-
|
|
1733
|
-
|
|
2089
|
+
if (result.kind === 'product_improvement') {
|
|
2090
|
+
console.log(` product improvement: ${result.digestEntityName}`);
|
|
2091
|
+
console.log(` source memories preserved: ${result.sourcesLinked ?? 0}`);
|
|
2092
|
+
console.log(' state: accepted for product work; implementation and outcome remain unverified');
|
|
2093
|
+
}
|
|
2094
|
+
else {
|
|
2095
|
+
console.log(` digest entity: ${result.digestEntityName}`);
|
|
2096
|
+
console.log(` sources archived: ${result.sourcesArchived}`);
|
|
2097
|
+
}
|
|
1734
2098
|
});
|
|
1735
2099
|
});
|
|
1736
2100
|
dreamCmd
|
|
@@ -1898,12 +2262,9 @@ program
|
|
|
1898
2262
|
console.log('Re-run with --no-diagnostics to leave out the install ID and the doctor report.');
|
|
1899
2263
|
}
|
|
1900
2264
|
const { spawn } = await import('child_process');
|
|
1901
|
-
const
|
|
1902
|
-
: process.platform === 'win32' ? 'cmd'
|
|
1903
|
-
: 'xdg-open';
|
|
1904
|
-
const args = process.platform === 'win32' ? ['/c', 'start', '', url] : [url];
|
|
2265
|
+
const { command, args } = feedbackBrowserOpenCommand(process.platform, url);
|
|
1905
2266
|
try {
|
|
1906
|
-
const child = spawn(
|
|
2267
|
+
const child = spawn(command, args, { stdio: 'ignore', detached: true });
|
|
1907
2268
|
child.unref();
|
|
1908
2269
|
console.log(`Opened browser to file ${fbType} issue.`);
|
|
1909
2270
|
console.log('Edit the title + body before submitting.');
|
|
@@ -2110,5 +2471,19 @@ program.action(async () => {
|
|
|
2110
2471
|
program.outputHelp();
|
|
2111
2472
|
process.exitCode = 0;
|
|
2112
2473
|
});
|
|
2113
|
-
|
|
2474
|
+
export async function runCli(argv = process.argv) {
|
|
2475
|
+
await program.parseAsync([...argv]);
|
|
2476
|
+
}
|
|
2477
|
+
const cliEntryPath = process.argv[1];
|
|
2478
|
+
if (cliEntryPath && isExecutedModule(cliEntryPath, import.meta.url)) {
|
|
2479
|
+
await runCli();
|
|
2480
|
+
}
|
|
2481
|
+
function isExecutedModule(entryPath, moduleUrl) {
|
|
2482
|
+
try {
|
|
2483
|
+
return fs.realpathSync(entryPath) === fs.realpathSync(fileURLToPath(moduleUrl));
|
|
2484
|
+
}
|
|
2485
|
+
catch {
|
|
2486
|
+
return false;
|
|
2487
|
+
}
|
|
2488
|
+
}
|
|
2114
2489
|
//# sourceMappingURL=cli.js.map
|