@pcircle/memesh 4.7.2 → 4.8.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.
- 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 +330 -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 +24 -19
- 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 +1 -1
- package/dist/transports/cli/cli.d.ts.map +1 -1
- package/dist/transports/cli/cli.js +376 -12
- 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/post-commit.js +13 -1
- package/scripts/hooks/session-start.js +12 -2
- package/scripts/hooks/session-summary.js +20 -8
- 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();
|
|
@@ -152,9 +155,11 @@ program
|
|
|
152
155
|
console.error('Error: --obs needs some text. An empty or whitespace-only observation is not a memory.');
|
|
153
156
|
process.exit(1);
|
|
154
157
|
}
|
|
158
|
+
const supersedes = Array.isArray(opts.supersedes) ? opts.supersedes : [];
|
|
159
|
+
const contradicts = Array.isArray(opts.contradicts) ? opts.contradicts : [];
|
|
155
160
|
const relations = [
|
|
156
|
-
...
|
|
157
|
-
...
|
|
161
|
+
...supersedes.map(to => ({ to, type: 'supersedes' })),
|
|
162
|
+
...contradicts.map(to => ({ to, type: 'contradicts' })),
|
|
158
163
|
];
|
|
159
164
|
await withDatabase(async () => {
|
|
160
165
|
const result = remember({
|
|
@@ -178,13 +183,15 @@ program
|
|
|
178
183
|
if (result.superseded?.length) {
|
|
179
184
|
console.log(` archived as superseded: ${result.superseded.join(', ')}`);
|
|
180
185
|
}
|
|
181
|
-
const
|
|
186
|
+
const relationsCreated = Array.isArray(result.relationsCreated) ? result.relationsCreated : [];
|
|
187
|
+
const contradicted = relationsCreated
|
|
182
188
|
.filter(r => r.type === 'contradicts')
|
|
183
189
|
.map(r => r.to);
|
|
184
190
|
if (contradicted.length > 0) {
|
|
185
191
|
console.log(` conflicts stated: ${contradicted.join(', ')}`);
|
|
186
192
|
}
|
|
187
|
-
|
|
193
|
+
const relationErrors = Array.isArray(result.relationErrors) ? result.relationErrors : [];
|
|
194
|
+
for (const err of relationErrors)
|
|
188
195
|
console.error(` ⚠️ ${err}`);
|
|
189
196
|
}
|
|
190
197
|
if (result.relationErrors?.length)
|
|
@@ -492,6 +499,334 @@ program
|
|
|
492
499
|
}
|
|
493
500
|
});
|
|
494
501
|
});
|
|
502
|
+
const messageCmd = program
|
|
503
|
+
.command('message')
|
|
504
|
+
.description('Send, wait for, fetch, and explicitly receipt durable local agent messages');
|
|
505
|
+
function parseCliMessagePayload(raw, contentType) {
|
|
506
|
+
if (contentType !== 'application/json')
|
|
507
|
+
return raw;
|
|
508
|
+
try {
|
|
509
|
+
return JSON.parse(raw);
|
|
510
|
+
}
|
|
511
|
+
catch {
|
|
512
|
+
throw new Error('stdin must contain valid JSON when --content-type is application/json.');
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
const MAX_CLI_MESSAGE_STDIN_BYTES = 65_536;
|
|
516
|
+
async function readCliMessagePayloadFromStdin(contentType) {
|
|
517
|
+
let raw = '';
|
|
518
|
+
let bytes = 0;
|
|
519
|
+
for await (const chunk of process.stdin) {
|
|
520
|
+
const text = typeof chunk === 'string' ? chunk : Buffer.from(chunk).toString('utf8');
|
|
521
|
+
bytes += Buffer.byteLength(text, 'utf8');
|
|
522
|
+
if (bytes > MAX_CLI_MESSAGE_STDIN_BYTES) {
|
|
523
|
+
throw new Error(`stdin payload exceeds ${MAX_CLI_MESSAGE_STDIN_BYTES} UTF-8 bytes.`);
|
|
524
|
+
}
|
|
525
|
+
raw += text;
|
|
526
|
+
}
|
|
527
|
+
if (bytes === 0) {
|
|
528
|
+
throw new Error('stdin payload is empty.');
|
|
529
|
+
}
|
|
530
|
+
return parseCliMessagePayload(raw, contentType);
|
|
531
|
+
}
|
|
532
|
+
async function runCliMessage(input) {
|
|
533
|
+
await withDatabase(async () => {
|
|
534
|
+
try {
|
|
535
|
+
const result = await executeAgentMessageAction(getDatabase(), input, {
|
|
536
|
+
transport: 'cli',
|
|
537
|
+
sourceHost: 'cli',
|
|
538
|
+
});
|
|
539
|
+
console.log(JSON.stringify(result));
|
|
540
|
+
}
|
|
541
|
+
catch (error) {
|
|
542
|
+
console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);
|
|
543
|
+
process.exitCode = 1;
|
|
544
|
+
}
|
|
545
|
+
});
|
|
546
|
+
}
|
|
547
|
+
function isAgentPollResult(value) {
|
|
548
|
+
if (typeof value !== 'object' || value === null)
|
|
549
|
+
return false;
|
|
550
|
+
const candidate = value;
|
|
551
|
+
return Array.isArray(candidate.events) && typeof candidate.next_cursor === 'string';
|
|
552
|
+
}
|
|
553
|
+
messageCmd
|
|
554
|
+
.command('send')
|
|
555
|
+
.description('Durably send one exact-recipient local message (idempotent)')
|
|
556
|
+
.requiredOption('--project <name>', 'Project scope')
|
|
557
|
+
.requiredOption('--sender <id>', 'Stable sender agent/host ID')
|
|
558
|
+
.requiredOption('--recipient <id>', 'Stable recipient agent/host ID')
|
|
559
|
+
.option('--target-kind <kind>', 'principal | session', 'principal')
|
|
560
|
+
.requiredOption('--idempotency-key <key>', 'Stable retry key')
|
|
561
|
+
.requiredOption('--payload-stdin', 'Read the complete text or JSON payload from stdin (never argv)')
|
|
562
|
+
.option('--content-type <type>', 'text/plain | application/json', 'text/plain')
|
|
563
|
+
.option('--privacy <scope>', 'private | team', 'private')
|
|
564
|
+
.option('--correlation-id <id>', 'Conversation or task correlation ID')
|
|
565
|
+
.option('--reply-to <message-id>', 'Message ID this replies to')
|
|
566
|
+
.action(async (opts) => {
|
|
567
|
+
requireOneOf(opts.contentType, ['text/plain', 'application/json'], '--content-type');
|
|
568
|
+
requireOneOf(opts.privacy, ['private', 'team'], '--privacy');
|
|
569
|
+
requireOneOf(opts.targetKind, ['principal', 'session'], '--target-kind');
|
|
570
|
+
try {
|
|
571
|
+
await runCliMessage({
|
|
572
|
+
action: 'send',
|
|
573
|
+
project: opts.project,
|
|
574
|
+
sender: opts.sender,
|
|
575
|
+
recipient: opts.recipient,
|
|
576
|
+
target_kind: opts.targetKind,
|
|
577
|
+
idempotency_key: opts.idempotencyKey,
|
|
578
|
+
payload: await readCliMessagePayloadFromStdin(opts.contentType),
|
|
579
|
+
content_type: opts.contentType,
|
|
580
|
+
privacy: opts.privacy,
|
|
581
|
+
correlation_id: opts.correlationId,
|
|
582
|
+
reply_to: opts.replyTo,
|
|
583
|
+
});
|
|
584
|
+
}
|
|
585
|
+
catch (error) {
|
|
586
|
+
console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);
|
|
587
|
+
process.exitCode = 1;
|
|
588
|
+
}
|
|
589
|
+
});
|
|
590
|
+
messageCmd
|
|
591
|
+
.command('watch')
|
|
592
|
+
.description('Wait once for an exact-recipient event batch and emit privacy-minimized JSONL')
|
|
593
|
+
.requiredOption('--project <name>', 'Project scope')
|
|
594
|
+
.requiredOption('--recipient <id>', 'Stable recipient agent/host ID')
|
|
595
|
+
.option('--cursor <token>', 'Opaque cursor returned by an earlier watch/poll')
|
|
596
|
+
.option('--wait-ms <ms>', 'Bounded wait, 0-30000 milliseconds', wholeNumber('--wait-ms', 0), 30_000)
|
|
597
|
+
.option('--limit <n>', 'Maximum events, 1-100', wholeNumber('--limit'), 20)
|
|
598
|
+
.action(async (opts) => {
|
|
599
|
+
await withDatabase(async () => {
|
|
600
|
+
console.log(JSON.stringify({
|
|
601
|
+
type: 'ready',
|
|
602
|
+
project: opts.project,
|
|
603
|
+
recipient: opts.recipient,
|
|
604
|
+
cursor: opts.cursor ?? null,
|
|
605
|
+
}));
|
|
606
|
+
try {
|
|
607
|
+
const result = await executeAgentMessageAction(getDatabase(), {
|
|
608
|
+
action: 'poll',
|
|
609
|
+
project: opts.project,
|
|
610
|
+
recipient: opts.recipient,
|
|
611
|
+
cursor: opts.cursor,
|
|
612
|
+
wait_ms: opts.waitMs,
|
|
613
|
+
limit: opts.limit,
|
|
614
|
+
}, {
|
|
615
|
+
transport: 'cli',
|
|
616
|
+
sourceHost: 'cli',
|
|
617
|
+
});
|
|
618
|
+
if (!isAgentPollResult(result)) {
|
|
619
|
+
throw new Error('Message watch returned an invalid poll result.');
|
|
620
|
+
}
|
|
621
|
+
console.log(JSON.stringify({
|
|
622
|
+
type: result.events.length > 0 ? 'events' : 'timeout',
|
|
623
|
+
...result,
|
|
624
|
+
}));
|
|
625
|
+
}
|
|
626
|
+
catch (error) {
|
|
627
|
+
console.error(JSON.stringify({
|
|
628
|
+
type: 'error',
|
|
629
|
+
error: error instanceof Error ? error.message : String(error),
|
|
630
|
+
}));
|
|
631
|
+
process.exitCode = 1;
|
|
632
|
+
}
|
|
633
|
+
});
|
|
634
|
+
});
|
|
635
|
+
messageCmd
|
|
636
|
+
.command('fetch')
|
|
637
|
+
.description('Fetch one payload routed to the exact principal or session without acknowledging it')
|
|
638
|
+
.requiredOption('--project <name>', 'Project scope')
|
|
639
|
+
.requiredOption('--recipient <id>', 'Stable recipient agent/host ID')
|
|
640
|
+
.option('--target-kind <kind>', 'principal | session', 'principal')
|
|
641
|
+
.requiredOption('--message-id <id>', 'Message ID')
|
|
642
|
+
.action((opts) => {
|
|
643
|
+
requireOneOf(opts.targetKind, ['principal', 'session'], '--target-kind');
|
|
644
|
+
return runCliMessage({
|
|
645
|
+
action: 'fetch', project: opts.project, recipient: opts.recipient,
|
|
646
|
+
target_kind: opts.targetKind, message_id: opts.messageId,
|
|
647
|
+
});
|
|
648
|
+
});
|
|
649
|
+
messageCmd
|
|
650
|
+
.command('intake')
|
|
651
|
+
.description('Record fetched/ingested state without implying ACK')
|
|
652
|
+
.requiredOption('--project <name>', 'Project scope')
|
|
653
|
+
.requiredOption('--recipient <id>', 'Stable recipient agent/host ID')
|
|
654
|
+
.requiredOption('--message-id <id>', 'Message ID')
|
|
655
|
+
.requiredOption('--idempotency-key <key>', 'Stable retry key')
|
|
656
|
+
.requiredOption('--state <state>', 'fetched | ingested')
|
|
657
|
+
.action(async (opts) => {
|
|
658
|
+
requireOneOf(opts.state, ['fetched', 'ingested'], '--state');
|
|
659
|
+
await runCliMessage({
|
|
660
|
+
action: 'intake', project: opts.project, recipient: opts.recipient,
|
|
661
|
+
message_id: opts.messageId, idempotency_key: opts.idempotencyKey, intake_state: opts.state,
|
|
662
|
+
});
|
|
663
|
+
});
|
|
664
|
+
messageCmd
|
|
665
|
+
.command('ack')
|
|
666
|
+
.description('Record explicit recipient acknowledgement')
|
|
667
|
+
.requiredOption('--project <name>', 'Project scope')
|
|
668
|
+
.requiredOption('--recipient <id>', 'Stable recipient agent/host ID')
|
|
669
|
+
.requiredOption('--message-id <id>', 'Message ID')
|
|
670
|
+
.requiredOption('--idempotency-key <key>', 'Stable retry key')
|
|
671
|
+
.action((opts) => runCliMessage({
|
|
672
|
+
action: 'ack', project: opts.project, recipient: opts.recipient,
|
|
673
|
+
message_id: opts.messageId, idempotency_key: opts.idempotencyKey,
|
|
674
|
+
}));
|
|
675
|
+
messageCmd
|
|
676
|
+
.command('disposition')
|
|
677
|
+
.description('Record a workflow disposition independently from ACK')
|
|
678
|
+
.requiredOption('--project <name>', 'Project scope')
|
|
679
|
+
.requiredOption('--recipient <id>', 'Stable recipient agent/host ID')
|
|
680
|
+
.requiredOption('--message-id <id>', 'Message ID')
|
|
681
|
+
.requiredOption('--idempotency-key <key>', 'Stable retry key')
|
|
682
|
+
.requiredOption('--value <state>', 'accepted | rejected | completed | cancelled | deferred')
|
|
683
|
+
.option('--detail <text>', 'Optional bounded explanation')
|
|
684
|
+
.action(async (opts) => {
|
|
685
|
+
requireOneOf(opts.value, ['accepted', 'rejected', 'completed', 'cancelled', 'deferred'], '--value');
|
|
686
|
+
await runCliMessage({
|
|
687
|
+
action: 'disposition', project: opts.project, recipient: opts.recipient,
|
|
688
|
+
message_id: opts.messageId, idempotency_key: opts.idempotencyKey,
|
|
689
|
+
disposition: opts.value, detail: opts.detail,
|
|
690
|
+
});
|
|
691
|
+
});
|
|
692
|
+
messageCmd
|
|
693
|
+
.command('activation')
|
|
694
|
+
.description('Record host activation outcome independently from ACK/disposition')
|
|
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>', 'woken | manual_resume_required | unsupported | failed')
|
|
700
|
+
.option('--detail <text>', 'Optional bounded explanation')
|
|
701
|
+
.action(async (opts) => {
|
|
702
|
+
requireOneOf(opts.value, ['woken', 'manual_resume_required', 'unsupported', 'failed'], '--value');
|
|
703
|
+
await runCliMessage({
|
|
704
|
+
action: 'activation', project: opts.project, recipient: opts.recipient,
|
|
705
|
+
message_id: opts.messageId, idempotency_key: opts.idempotencyKey,
|
|
706
|
+
activation: opts.value, detail: opts.detail,
|
|
707
|
+
});
|
|
708
|
+
});
|
|
709
|
+
messageCmd
|
|
710
|
+
.command('receipts')
|
|
711
|
+
.description('Read receipt facts for one message routed to the logical recipient')
|
|
712
|
+
.requiredOption('--project <name>', 'Project scope')
|
|
713
|
+
.requiredOption('--recipient <id>', 'Stable recipient agent/host ID')
|
|
714
|
+
.requiredOption('--message-id <id>', 'Message ID')
|
|
715
|
+
.action((opts) => runCliMessage({
|
|
716
|
+
action: 'receipts', project: opts.project, recipient: opts.recipient, message_id: opts.messageId,
|
|
717
|
+
}));
|
|
718
|
+
const messageStorageCmd = messageCmd
|
|
719
|
+
.command('storage')
|
|
720
|
+
.description('Inspect or bound durable agent-message payload storage without deleting lifecycle audit facts');
|
|
721
|
+
messageStorageCmd
|
|
722
|
+
.command('report')
|
|
723
|
+
.description('Report logical payload, unresolved protection, reusable pages, and SQLite/WAL size')
|
|
724
|
+
.requiredOption('--cutoff <iso-time>', 'Terminal workflows strictly older than this ISO timestamp are prunable')
|
|
725
|
+
.action(async (opts) => {
|
|
726
|
+
await withDatabase(() => {
|
|
727
|
+
const report = getAgentMessageStorageReport(getDatabase(), {
|
|
728
|
+
cutoff: opts.cutoff,
|
|
729
|
+
databasePath: getDbPath(),
|
|
730
|
+
});
|
|
731
|
+
console.log(JSON.stringify({
|
|
732
|
+
policy: {
|
|
733
|
+
cutoff: new Date(opts.cutoff).toISOString(),
|
|
734
|
+
quota_bytes: process.env.MEMESH_AGENT_MESSAGE_STORAGE_QUOTA_BYTES ?? null,
|
|
735
|
+
automatic_pruning: false,
|
|
736
|
+
},
|
|
737
|
+
...report,
|
|
738
|
+
}));
|
|
739
|
+
});
|
|
740
|
+
});
|
|
741
|
+
messageStorageCmd
|
|
742
|
+
.command('prune')
|
|
743
|
+
.description('Dry-run one bounded terminal-payload tombstone batch; --apply performs it')
|
|
744
|
+
.requiredOption('--cutoff <iso-time>', 'Terminal workflows strictly older than this ISO timestamp are eligible')
|
|
745
|
+
.option('--batch-size <n>', 'Maximum payloads in this transaction, 1-1000', wholeNumber('--batch-size'), 100)
|
|
746
|
+
.option('--apply', 'Write hash-bound tombstones; without this flag nothing is changed')
|
|
747
|
+
.option('--actor <id>', 'Bounded audit actor', 'local-owner-cli')
|
|
748
|
+
.action(async (opts) => {
|
|
749
|
+
await withDatabase(() => {
|
|
750
|
+
const result = pruneTerminalAgentMessagePayloads(getDatabase(), {
|
|
751
|
+
cutoff: opts.cutoff,
|
|
752
|
+
databasePath: getDbPath(),
|
|
753
|
+
batchSize: opts.batchSize,
|
|
754
|
+
dryRun: !opts.apply,
|
|
755
|
+
actor: opts.actor,
|
|
756
|
+
});
|
|
757
|
+
console.log(JSON.stringify(result));
|
|
758
|
+
});
|
|
759
|
+
});
|
|
760
|
+
const agentCmd = program
|
|
761
|
+
.command('agent')
|
|
762
|
+
.description('Set up reusable owner-private local host configuration');
|
|
763
|
+
agentCmd
|
|
764
|
+
.command('setup')
|
|
765
|
+
.argument('<host>', 'codex-session | codex | claude | gemini')
|
|
766
|
+
.requiredOption('--project <name>', 'Project scope used for exact routing')
|
|
767
|
+
.requiredOption('--principal <id>', 'Stable logical recipient ID')
|
|
768
|
+
.option('--workspace <path>', 'Managed Codex/Gemini workspace', process.cwd())
|
|
769
|
+
.option('--json', 'Output machine-readable setup result')
|
|
770
|
+
.action((host, opts) => {
|
|
771
|
+
requireOneOf(host, ['codex-session', 'codex', 'claude', 'gemini'], '<host>');
|
|
772
|
+
assertSecureLocalHostRuntimeSupported();
|
|
773
|
+
const messageDir = path.dirname(getDbPath());
|
|
774
|
+
const hostsDir = path.join(messageDir, 'hosts');
|
|
775
|
+
fs.mkdirSync(hostsDir, { recursive: true, mode: 0o700 });
|
|
776
|
+
const hostsStat = fs.lstatSync(hostsDir);
|
|
777
|
+
if (!hostsStat.isDirectory() || hostsStat.isSymbolicLink() || (hostsStat.mode & 0o077) !== 0) {
|
|
778
|
+
throw new Error('The managed host config directory must be a real owner-private directory.');
|
|
779
|
+
}
|
|
780
|
+
const filename = host === 'gemini' ? 'gemini-acp.json' : `${host}.json`;
|
|
781
|
+
const configPath = path.join(hostsDir, filename);
|
|
782
|
+
if (fs.existsSync(configPath)) {
|
|
783
|
+
throw new Error(`Managed ${host} config already exists at ${configPath}; it was not overwritten.`);
|
|
784
|
+
}
|
|
785
|
+
const routerTokenFile = path.join(messageDir, 'agent-router.token');
|
|
786
|
+
ensureRouterTokenFile(routerTokenFile);
|
|
787
|
+
const common = {
|
|
788
|
+
router_socket: path.join(messageDir, 'agent-router.sock'),
|
|
789
|
+
token_file: routerTokenFile,
|
|
790
|
+
project: opts.project,
|
|
791
|
+
principal_id: opts.principal,
|
|
792
|
+
};
|
|
793
|
+
const config = host === 'codex-session'
|
|
794
|
+
? { ...common, workspace: fs.realpathSync(path.resolve(opts.workspace)) }
|
|
795
|
+
: host === 'codex'
|
|
796
|
+
? { ...common, control_socket: path.join(hostsDir, 'codex-app-server.sock'), workspace: path.resolve(opts.workspace) }
|
|
797
|
+
: host === 'claude'
|
|
798
|
+
? { ...common, server_name: 'memesh-channel' }
|
|
799
|
+
: { ...common, workspace: path.resolve(opts.workspace), command: 'gemini', args: [] };
|
|
800
|
+
fs.writeFileSync(configPath, `${JSON.stringify(config, null, 2)}\n`, { flag: 'wx', mode: 0o600 });
|
|
801
|
+
const launchCommand = host === 'codex-session'
|
|
802
|
+
? null
|
|
803
|
+
: host === 'codex'
|
|
804
|
+
? `memesh-host-codex --config ${JSON.stringify(configPath)}`
|
|
805
|
+
: host === 'claude'
|
|
806
|
+
? 'claude --dangerously-load-development-channels server:memesh-channel'
|
|
807
|
+
: `memesh-host-acp --config ${JSON.stringify(configPath)}`;
|
|
808
|
+
const registrationCommand = host === 'claude'
|
|
809
|
+
? `claude mcp add --transport stdio --scope user memesh-channel -- memesh-host-claude --config ${JSON.stringify(configPath)}`
|
|
810
|
+
: null;
|
|
811
|
+
const result = {
|
|
812
|
+
host,
|
|
813
|
+
config_path: configPath,
|
|
814
|
+
mode: host === 'codex-session'
|
|
815
|
+
? 'ordinary-session-native-queue'
|
|
816
|
+
: host === 'claude' ? 'session-owned-channel' : 'memesh-managed-session',
|
|
817
|
+
session_identity: host === 'codex-session' ? 'codex-thread-id-at-session-start' : 'generated-per-process',
|
|
818
|
+
ordinary_sessions: host === 'codex-session' ? 'explicit-workspace-opt-in' : 'presence-only/inbound-unavailable',
|
|
819
|
+
registration_command: registrationCommand,
|
|
820
|
+
launch_command: launchCommand,
|
|
821
|
+
next_command: registrationCommand ?? launchCommand ?? 'Restart Codex in the configured workspace',
|
|
822
|
+
};
|
|
823
|
+
console.log(opts.json ? JSON.stringify(result) : [
|
|
824
|
+
`Created owner-private ${host} config: ${configPath}`,
|
|
825
|
+
'No active or stopped ordinary session was attached.',
|
|
826
|
+
...(registrationCommand ? [`Register once: ${registrationCommand}`] : []),
|
|
827
|
+
...(launchCommand ? [`Launch: ${launchCommand}`] : ['Restart Codex in the configured workspace.']),
|
|
828
|
+
].join('\n'));
|
|
829
|
+
});
|
|
495
830
|
program
|
|
496
831
|
.command('briefing')
|
|
497
832
|
.description('The assembled work topology for a project — task state, decisions, lessons, knowledge, recent activity')
|
|
@@ -639,7 +974,8 @@ program
|
|
|
639
974
|
console.log('\nPlanned actions:');
|
|
640
975
|
for (const st of pending)
|
|
641
976
|
for (const a of st.actions) {
|
|
642
|
-
|
|
977
|
+
const actionArgs = Array.isArray(a.args) ? a.args : [];
|
|
978
|
+
console.log(` • [${st.title}] ${a.label}${a.cmd ? `\n ${a.cmd} ${actionArgs.join(' ')}` : ''}`);
|
|
643
979
|
}
|
|
644
980
|
if (!opts.yes && !process.stdin.isTTY) {
|
|
645
981
|
console.error('\nNot a terminal and --yes not given — nothing was changed. Re-run with: memesh setup --yes');
|
|
@@ -665,9 +1001,10 @@ program
|
|
|
665
1001
|
console.log(` ✅ ${wireUserHooks()}`);
|
|
666
1002
|
}
|
|
667
1003
|
else if (action.cmd) {
|
|
668
|
-
const
|
|
1004
|
+
const actionArgs = Array.isArray(action.args) ? action.args : [];
|
|
1005
|
+
const r = runSeam(action.cmd, actionArgs);
|
|
669
1006
|
if (r.status === 0)
|
|
670
|
-
console.log(` ✅ done (${action.cmd} ${
|
|
1007
|
+
console.log(` ✅ done (${action.cmd} ${actionArgs.join(' ')})`);
|
|
671
1008
|
else {
|
|
672
1009
|
console.error(` ❌ ${action.cmd} exited ${r.status ?? 'without running'}${r.stderr ? `: ${r.stderr.trim()}` : ''}`);
|
|
673
1010
|
failed = true;
|
|
@@ -1598,7 +1935,8 @@ dreamCmd
|
|
|
1598
1935
|
console.log('');
|
|
1599
1936
|
for (const p of proposals) {
|
|
1600
1937
|
const srcLabel = p.kind === 'relation' ? ' (conflict)'
|
|
1601
|
-
: p.
|
|
1938
|
+
: p.kind === 'product_improvement' ? ' (product improvement)'
|
|
1939
|
+
: p.source_kind === 'transcript' ? ' (transcript)' : '';
|
|
1602
1940
|
console.log(` #${p.id} [${p.project}/${p.cluster_key}]${srcLabel} ${p.source_count} source(s) → "${p.digest_name}"`);
|
|
1603
1941
|
if (p.digest_observations_preview !== null) {
|
|
1604
1942
|
console.log(` ${p.digest_observations_preview}`);
|
|
@@ -1698,6 +2036,11 @@ dreamCmd
|
|
|
1698
2036
|
console.log(`Accept: memesh dream accept ${detail.id} | Reject: memesh dream reject ${detail.id}`);
|
|
1699
2037
|
return;
|
|
1700
2038
|
}
|
|
2039
|
+
if (detail.kind === 'product_improvement') {
|
|
2040
|
+
const improvement = detail.digest;
|
|
2041
|
+
console.log(`title: ${improvement.title ?? detail.digest.name}`);
|
|
2042
|
+
console.log('authority: human review required; acceptance does not mean implemented or effective');
|
|
2043
|
+
}
|
|
1701
2044
|
console.log(`name: ${detail.digest.name}`);
|
|
1702
2045
|
console.log(`type: ${detail.digest.type}`);
|
|
1703
2046
|
console.log(`observations (${detail.digest.observations.length}):`);
|
|
@@ -1712,7 +2055,7 @@ dreamCmd
|
|
|
1712
2055
|
});
|
|
1713
2056
|
dreamCmd
|
|
1714
2057
|
.command('accept <id>')
|
|
1715
|
-
.description('
|
|
2058
|
+
.description('Apply a reviewed pending proposal (behaviour depends on proposal kind)')
|
|
1716
2059
|
.action(async (id) => {
|
|
1717
2060
|
await withDatabase(async () => {
|
|
1718
2061
|
const { applyProposal } = await import('../../core/dreamer.js');
|
|
@@ -1729,8 +2072,15 @@ dreamCmd
|
|
|
1729
2072
|
process.exit(1);
|
|
1730
2073
|
}
|
|
1731
2074
|
console.log(`Applied proposal #${result.proposalId}`);
|
|
1732
|
-
|
|
1733
|
-
|
|
2075
|
+
if (result.kind === 'product_improvement') {
|
|
2076
|
+
console.log(` product improvement: ${result.digestEntityName}`);
|
|
2077
|
+
console.log(` source memories preserved: ${result.sourcesLinked ?? 0}`);
|
|
2078
|
+
console.log(' state: accepted for product work; implementation and outcome remain unverified');
|
|
2079
|
+
}
|
|
2080
|
+
else {
|
|
2081
|
+
console.log(` digest entity: ${result.digestEntityName}`);
|
|
2082
|
+
console.log(` sources archived: ${result.sourcesArchived}`);
|
|
2083
|
+
}
|
|
1734
2084
|
});
|
|
1735
2085
|
});
|
|
1736
2086
|
dreamCmd
|
|
@@ -2110,5 +2460,19 @@ program.action(async () => {
|
|
|
2110
2460
|
program.outputHelp();
|
|
2111
2461
|
process.exitCode = 0;
|
|
2112
2462
|
});
|
|
2113
|
-
|
|
2463
|
+
export async function runCli(argv = process.argv) {
|
|
2464
|
+
await program.parseAsync([...argv]);
|
|
2465
|
+
}
|
|
2466
|
+
const cliEntryPath = process.argv[1];
|
|
2467
|
+
if (cliEntryPath && isExecutedModule(cliEntryPath, import.meta.url)) {
|
|
2468
|
+
await runCli();
|
|
2469
|
+
}
|
|
2470
|
+
function isExecutedModule(entryPath, moduleUrl) {
|
|
2471
|
+
try {
|
|
2472
|
+
return fs.realpathSync(entryPath) === fs.realpathSync(fileURLToPath(moduleUrl));
|
|
2473
|
+
}
|
|
2474
|
+
catch {
|
|
2475
|
+
return false;
|
|
2476
|
+
}
|
|
2477
|
+
}
|
|
2114
2478
|
//# sourceMappingURL=cli.js.map
|