@a-company/paradigm 3.43.0 → 3.46.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/dist/{chunk-YW5OCVKB.js → chunk-FKJUBQU3.js} +14 -1
- package/dist/chunk-KVDYJLTC.js +121 -0
- package/dist/{symphony-ROEKK7VD.js → chunk-S2HO5MLR.js} +53 -431
- package/dist/{chunk-RGFANZ4Q.js → chunk-ZDHLG5VP.js} +14 -1
- package/dist/{chunk-CZEIK3Y2.js → chunk-ZMQA6SCO.js} +1 -1
- package/dist/{chunk-7WEKMZ46.js → chunk-ZSYVKSY6.js} +1 -1
- package/dist/{commands-LEPFD7S5.js → commands-5N4ILTPH.js} +13 -0
- package/dist/{dist-RVKYUCRU.js → dist-CM3MVWWW.js} +1 -1
- package/dist/{dist-Y7I3CFY5.js → dist-POMVY6WP.js} +2 -2
- package/dist/{habits-O37HTUKE.js → habits-RG5SVKXP.js} +2 -2
- package/dist/index.js +69 -48
- package/dist/mcp.js +89 -9
- package/dist/peers-RFQCWVLV.js +82 -0
- package/dist/{platform-server-KK4OCRTV.js → platform-server-H7Y6Q7O4.js} +10 -1
- package/dist/{reindex-NZQRGKPN.js → reindex-WIJMCJ4A.js} +1 -1
- package/dist/{sentinel-BKYTBT7M.js → sentinel-UOIGJWHH.js} +1 -1
- package/dist/{sentinel-bridge-IZTXYS5M.js → sentinel-bridge-APDXYAZS.js} +1 -1
- package/dist/sentinel-mcp.js +13 -0
- package/dist/sentinel.js +6 -6
- package/dist/{serve-3V2WXLGM.js → serve-KKEHE44G.js} +1 -1
- package/dist/{server-OFEJ2HJP.js → server-JV6UFGWZ.js} +1 -1
- package/dist/symphony-6K3HD7AW.js +791 -0
- package/dist/symphony-YCHBYN3E.js +326 -0
- package/dist/symphony-peers-APOGJPF4.js +120 -0
- package/dist/symphony-peers-HSY3RI3S.js +34 -0
- package/dist/symphony-relay-GTAJRCVF.js +683 -0
- package/dist/{triage-POXJ2TIX.js → triage-IZ4MDYNB.js} +2 -2
- package/dist/university-content/courses/para-501.json +84 -0
- package/package.json +1 -1
- package/platform-ui/dist/assets/{GitSection-DvyJBF_-.js → GitSection-BD3Ze06e.js} +1 -1
- package/platform-ui/dist/assets/{GraphSection-BiQrXqfs.js → GraphSection-SglITfSs.js} +1 -1
- package/platform-ui/dist/assets/{LoreSection-BaH1FaRb.js → LoreSection-bR5Km4Fd.js} +1 -1
- package/platform-ui/dist/assets/{SentinelSection-DemAznjI.js → SentinelSection-QSpAZArG.js} +1 -1
- package/platform-ui/dist/assets/SymphonySection-CobYJgvg.js +1 -0
- package/platform-ui/dist/assets/SymphonySection-zY0C5tFl.css +1 -0
- package/platform-ui/dist/assets/{index-DDKhCt-w.js → index-DbxeSMkV.js} +11 -11
- package/platform-ui/dist/index.html +1 -1
|
@@ -4405,7 +4405,7 @@ function assertStep(step, event) {
|
|
|
4405
4405
|
async function validateAgainstSentinel(persona, options = {}) {
|
|
4406
4406
|
const steps = [];
|
|
4407
4407
|
try {
|
|
4408
|
-
const { SentinelStorage } = await import("./dist-
|
|
4408
|
+
const { SentinelStorage } = await import("./dist-CM3MVWWW.js");
|
|
4409
4409
|
const storage = new SentinelStorage();
|
|
4410
4410
|
const events = storage.queryEvents?.({
|
|
4411
4411
|
schemaId: "paradigm-personas",
|
|
@@ -599,6 +599,19 @@ var SentinelStorage = class {
|
|
|
599
599
|
);
|
|
600
600
|
this.save();
|
|
601
601
|
}
|
|
602
|
+
resolveIncident(id, options) {
|
|
603
|
+
this.updateIncident(id, {
|
|
604
|
+
status: "resolved",
|
|
605
|
+
resolvedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
606
|
+
});
|
|
607
|
+
if (options?.notes) {
|
|
608
|
+
this.addIncidentNote(id, {
|
|
609
|
+
author: "system",
|
|
610
|
+
content: options.notes,
|
|
611
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
612
|
+
});
|
|
613
|
+
}
|
|
614
|
+
}
|
|
602
615
|
addIncidentNote(incidentId, note) {
|
|
603
616
|
this.initializeSync();
|
|
604
617
|
const incident = this.getIncident(incidentId);
|
|
@@ -19,7 +19,7 @@ import {
|
|
|
19
19
|
loadAllSeedPatterns,
|
|
20
20
|
loadParadigmPatterns,
|
|
21
21
|
loadUniversalPatterns
|
|
22
|
-
} from "./chunk-
|
|
22
|
+
} from "./chunk-ZSYVKSY6.js";
|
|
23
23
|
import {
|
|
24
24
|
DEFAULT_AUTH_CONFIG,
|
|
25
25
|
DEFAULT_RATE_LIMIT_CONFIG,
|
|
@@ -30,7 +30,7 @@ import {
|
|
|
30
30
|
loadConfig,
|
|
31
31
|
loadServerConfig,
|
|
32
32
|
writeConfig
|
|
33
|
-
} from "./chunk-
|
|
33
|
+
} from "./chunk-FKJUBQU3.js";
|
|
34
34
|
import "./chunk-ZXMDA7VB.js";
|
|
35
35
|
export {
|
|
36
36
|
ContextEnricher,
|
|
@@ -934,7 +934,7 @@ async function habitsStatusCommand(options) {
|
|
|
934
934
|
const enabled = getEnabledHabits(habits);
|
|
935
935
|
let practiceData = null;
|
|
936
936
|
try {
|
|
937
|
-
const { SentinelStorage } = await import("./dist-
|
|
937
|
+
const { SentinelStorage } = await import("./dist-POMVY6WP.js");
|
|
938
938
|
const sentinelDir = path3.join(rootDir, ".paradigm", "sentinel");
|
|
939
939
|
if (fs2.existsSync(sentinelDir)) {
|
|
940
940
|
const storage = new SentinelStorage(sentinelDir);
|
|
@@ -1302,7 +1302,7 @@ async function habitsCheckCommand(options) {
|
|
|
1302
1302
|
try {
|
|
1303
1303
|
const sentinelDir = path3.join(rootDir, ".paradigm", "sentinel");
|
|
1304
1304
|
if (fs2.existsSync(sentinelDir)) {
|
|
1305
|
-
const { SentinelStorage } = await import("./dist-
|
|
1305
|
+
const { SentinelStorage } = await import("./dist-POMVY6WP.js");
|
|
1306
1306
|
const storage = new SentinelStorage(sentinelDir);
|
|
1307
1307
|
for (const e of evaluation.evaluations) {
|
|
1308
1308
|
storage.recordPracticeEvent({
|
package/dist/index.js
CHANGED
|
@@ -588,76 +588,76 @@ hooksCmd.action(async () => {
|
|
|
588
588
|
});
|
|
589
589
|
var triageCmd = program.command("triage").description("Semantic error triage - incident management and pattern matching");
|
|
590
590
|
triageCmd.command("list").alias("ls").description("List recent incidents with matched patterns").option("-l, --limit <number>", "Maximum incidents to show", "10").option("-s, --status <status>", "Filter by status: open, investigating, resolved, wont-fix, all").option("--symbol <symbol>", "Filter by symbol (e.g., @checkout, ^auth)").option("-e, --env <environment>", "Filter by environment").option("--search <text>", "Search in error messages").option("--from <date>", "Filter from date (ISO format)").option("--to <date>", "Filter to date (ISO format)").option("--json", "Output as JSON").action(async (options) => {
|
|
591
|
-
const { triageListCommand } = await import("./triage-
|
|
591
|
+
const { triageListCommand } = await import("./triage-IZ4MDYNB.js");
|
|
592
592
|
await triageListCommand(options);
|
|
593
593
|
});
|
|
594
594
|
triageCmd.command("show <id>").description("Show full incident details").option("--timeline", "Include flow timeline").option("--json", "Output as JSON").action(async (id, options) => {
|
|
595
|
-
const { triageShowCommand } = await import("./triage-
|
|
595
|
+
const { triageShowCommand } = await import("./triage-IZ4MDYNB.js");
|
|
596
596
|
await triageShowCommand(id, options);
|
|
597
597
|
});
|
|
598
598
|
triageCmd.command("resolve <id>").description("Mark incident as resolved").option("-p, --pattern <patternId>", "Pattern that led to resolution").option("-c, --commit <hash>", "Git commit hash of fix").option("--pr <url>", "Pull request URL").option("-n, --notes <text>", "Resolution notes").option("--wont-fix", "Mark as will not fix").action(async (id, options) => {
|
|
599
|
-
const { triageResolveCommand } = await import("./triage-
|
|
599
|
+
const { triageResolveCommand } = await import("./triage-IZ4MDYNB.js");
|
|
600
600
|
await triageResolveCommand(id, options);
|
|
601
601
|
});
|
|
602
602
|
triageCmd.command("note <id> <note>").description("Add a note to an incident").action(async (id, note) => {
|
|
603
|
-
const { triageNoteCommand } = await import("./triage-
|
|
603
|
+
const { triageNoteCommand } = await import("./triage-IZ4MDYNB.js");
|
|
604
604
|
await triageNoteCommand(id, note);
|
|
605
605
|
});
|
|
606
606
|
triageCmd.command("link <id1> <id2>").description("Link two related incidents").action(async (id1, id2) => {
|
|
607
|
-
const { triageLinkCommand } = await import("./triage-
|
|
607
|
+
const { triageLinkCommand } = await import("./triage-IZ4MDYNB.js");
|
|
608
608
|
await triageLinkCommand(id1, id2);
|
|
609
609
|
});
|
|
610
610
|
var triagePatternsCmd = triageCmd.command("patterns").description("Manage failure patterns");
|
|
611
611
|
triagePatternsCmd.command("list").alias("ls").description("List all patterns").option("--source <source>", "Filter by source: manual, suggested, imported, community").option("--min-confidence <score>", "Minimum confidence score").option("--json", "Output as JSON").action(async (options) => {
|
|
612
|
-
const { triagePatternsListCommand } = await import("./triage-
|
|
612
|
+
const { triagePatternsListCommand } = await import("./triage-IZ4MDYNB.js");
|
|
613
613
|
await triagePatternsListCommand(options);
|
|
614
614
|
});
|
|
615
615
|
triagePatternsCmd.command("show <id>").description("Show pattern details").option("--json", "Output as JSON").action(async (id, options) => {
|
|
616
|
-
const { triagePatternsShowCommand } = await import("./triage-
|
|
616
|
+
const { triagePatternsShowCommand } = await import("./triage-IZ4MDYNB.js");
|
|
617
617
|
await triagePatternsShowCommand(id, options);
|
|
618
618
|
});
|
|
619
619
|
triagePatternsCmd.command("add").description("Create a new pattern").requiredOption("--id <id>", "Pattern ID (kebab-case)").requiredOption("--name <name>", "Human-readable name").option("--description <text>", "Pattern description").option("--symbols <pairs>", 'Symbol criteria (e.g., "feature:@checkout,gate:^auth")').option("--error-contains <keywords>", "Error keywords (comma-separated)").option("--missing-signals <signals>", "Expected missing signals (comma-separated)").option("--strategy <strategy>", "Resolution strategy: retry, fallback, fix-data, fix-code, ignore, escalate", "fix-code").option("--priority <priority>", "Priority: low, medium, high, critical", "medium").option("--code-hint <text>", "Code hint for resolution").option("--tags <tags>", "Tags (comma-separated)").option("--from-incident <id>", "Generate suggestion from incident").action(async (options) => {
|
|
620
|
-
const { triagePatternsAddCommand } = await import("./triage-
|
|
620
|
+
const { triagePatternsAddCommand } = await import("./triage-IZ4MDYNB.js");
|
|
621
621
|
await triagePatternsAddCommand(options);
|
|
622
622
|
});
|
|
623
623
|
triagePatternsCmd.command("delete <id>").alias("rm").description("Delete a pattern").action(async (id) => {
|
|
624
|
-
const { triagePatternsDeleteCommand } = await import("./triage-
|
|
624
|
+
const { triagePatternsDeleteCommand } = await import("./triage-IZ4MDYNB.js");
|
|
625
625
|
await triagePatternsDeleteCommand(id);
|
|
626
626
|
});
|
|
627
627
|
triagePatternsCmd.command("test <id>").description("Test pattern against historical incidents").option("-l, --limit <number>", "Max incidents to test against", "100").option("--json", "Output as JSON").action(async (id, options) => {
|
|
628
|
-
const { triagePatternsTestCommand } = await import("./triage-
|
|
628
|
+
const { triagePatternsTestCommand } = await import("./triage-IZ4MDYNB.js");
|
|
629
629
|
await triagePatternsTestCommand(id, options);
|
|
630
630
|
});
|
|
631
631
|
triagePatternsCmd.command("seed").description("Load built-in seed patterns").action(async () => {
|
|
632
|
-
const { triagePatternsSeedCommand } = await import("./triage-
|
|
632
|
+
const { triagePatternsSeedCommand } = await import("./triage-IZ4MDYNB.js");
|
|
633
633
|
await triagePatternsSeedCommand();
|
|
634
634
|
});
|
|
635
635
|
triagePatternsCmd.action(async () => {
|
|
636
|
-
const { triagePatternsListCommand } = await import("./triage-
|
|
636
|
+
const { triagePatternsListCommand } = await import("./triage-IZ4MDYNB.js");
|
|
637
637
|
await triagePatternsListCommand({});
|
|
638
638
|
});
|
|
639
639
|
triageCmd.command("export <type>").description("Export patterns or full backup (type: patterns, backup)").option("-o, --output <path>", "Output file path").option("--include-private", "Include private patterns").action(async (type, options) => {
|
|
640
|
-
const { triageExportCommand } = await import("./triage-
|
|
640
|
+
const { triageExportCommand } = await import("./triage-IZ4MDYNB.js");
|
|
641
641
|
await triageExportCommand(type, options);
|
|
642
642
|
});
|
|
643
643
|
triageCmd.command("import <file>").description("Import patterns from JSON file").option("--overwrite", "Overwrite existing patterns").action(async (file, options) => {
|
|
644
|
-
const { triageImportCommand } = await import("./triage-
|
|
644
|
+
const { triageImportCommand } = await import("./triage-IZ4MDYNB.js");
|
|
645
645
|
await triageImportCommand(file, options);
|
|
646
646
|
});
|
|
647
647
|
triageCmd.command("restore <file>").description("Restore from full backup").action(async (file) => {
|
|
648
|
-
const { triageRestoreCommand } = await import("./triage-
|
|
648
|
+
const { triageRestoreCommand } = await import("./triage-IZ4MDYNB.js");
|
|
649
649
|
await triageRestoreCommand(file);
|
|
650
650
|
});
|
|
651
651
|
triageCmd.command("stats").description("Show statistics dashboard").option("-p, --period <period>", "Time period: 1d, 7d, 30d, 90d", "7d").option("--symbol <symbol>", "Show health for specific symbol").option("--json", "Output as JSON").action(async (options) => {
|
|
652
|
-
const { triageStatsCommand } = await import("./triage-
|
|
652
|
+
const { triageStatsCommand } = await import("./triage-IZ4MDYNB.js");
|
|
653
653
|
await triageStatsCommand(options);
|
|
654
654
|
});
|
|
655
655
|
triageCmd.command("record").description("Manually record an incident").requiredOption("--error <message>", "Error message").requiredOption("-e, --env <environment>", "Environment").option("--feature <symbol>", "Feature symbol (@...)").option("--component <symbol>", "Component symbol (#...)").option("--flow <symbol>", "Flow symbol ($...)").option("--gate <symbol>", "Gate symbol (^...)").option("--signal <symbol>", "Signal symbol (!...)").option("--state <symbol>", "State symbol (%...)").option("--integration <symbol>", "Integration symbol (&...)").option("--service <name>", "Service name").option("--version <version>", "App version").option("--stack <trace>", "Stack trace").option("--json", "Output as JSON").action(async (options) => {
|
|
656
|
-
const { triageRecordCommand } = await import("./triage-
|
|
656
|
+
const { triageRecordCommand } = await import("./triage-IZ4MDYNB.js");
|
|
657
657
|
await triageRecordCommand(options);
|
|
658
658
|
});
|
|
659
659
|
triageCmd.option("-l, --limit <number>", "Maximum incidents to show", "10").option("-s, --status <status>", "Filter by status").option("--json", "Output as JSON").action(async (options) => {
|
|
660
|
-
const { triageListCommand } = await import("./triage-
|
|
660
|
+
const { triageListCommand } = await import("./triage-IZ4MDYNB.js");
|
|
661
661
|
await triageListCommand(options);
|
|
662
662
|
});
|
|
663
663
|
var loreCmd = program.command("lore").description("Project lore - timeline of everything that happened to this project");
|
|
@@ -710,7 +710,7 @@ loreCmd.option("-p, --port <port>", "Port to run on", "3840").option("--no-open"
|
|
|
710
710
|
await loreServeCommand(void 0, options);
|
|
711
711
|
});
|
|
712
712
|
program.command("serve").description("Launch Paradigm Platform \u2014 unified development management UI").option("-p, --port <port>", "Port to run on", "3850").option("--no-open", "Don't open browser automatically").option("--sections <list>", "Comma-separated sections to enable (e.g., lore,graph,git)").action(async (options) => {
|
|
713
|
-
const { serveCommand } = await import("./serve-
|
|
713
|
+
const { serveCommand } = await import("./serve-KKEHE44G.js");
|
|
714
714
|
await serveCommand(options);
|
|
715
715
|
});
|
|
716
716
|
var graphCmd = program.command("graph").description("Interactive symbol relationship graph").argument("[path]", "Project directory", void 0).option("-p, --port <port>", "Port to run on", "3841").option("--no-open", "Don't open browser automatically").action(async (path2, options) => {
|
|
@@ -723,48 +723,48 @@ graphCmd.command("generate").description("Generate a named graph file in .paradi
|
|
|
723
723
|
});
|
|
724
724
|
var habitsCmd = program.command("habits").description("Behavioral habits - practice tracking and compliance");
|
|
725
725
|
habitsCmd.command("list").alias("ls").description("List all configured habits").option("--trigger <trigger>", "Filter by trigger: preflight, postflight, on-stop, on-commit").option("--category <category>", "Filter by category: discovery, verification, testing, documentation, collaboration, security").option("--json", "Output as JSON").action(async (options) => {
|
|
726
|
-
const { habitsListCommand } = await import("./habits-
|
|
726
|
+
const { habitsListCommand } = await import("./habits-RG5SVKXP.js");
|
|
727
727
|
await habitsListCommand(options);
|
|
728
728
|
});
|
|
729
729
|
habitsCmd.command("status").description("Show practice profile with compliance rates").option("-p, --period <period>", "Time period: 7d, 30d, 90d, all", "30d").option("--json", "Output as JSON").action(async (options) => {
|
|
730
|
-
const { habitsStatusCommand } = await import("./habits-
|
|
730
|
+
const { habitsStatusCommand } = await import("./habits-RG5SVKXP.js");
|
|
731
731
|
await habitsStatusCommand(options);
|
|
732
732
|
});
|
|
733
733
|
habitsCmd.command("init").description("Initialize habits.yaml with seed habits").option("-f, --force", "Overwrite existing file").action(async (options) => {
|
|
734
|
-
const { habitsInitCommand } = await import("./habits-
|
|
734
|
+
const { habitsInitCommand } = await import("./habits-RG5SVKXP.js");
|
|
735
735
|
await habitsInitCommand(options);
|
|
736
736
|
});
|
|
737
737
|
habitsCmd.command("check").description("Evaluate habit compliance for a trigger point").requiredOption("-t, --trigger <trigger>", "Trigger: preflight, postflight, on-stop, on-commit").option("--record", "Record practice events to Sentinel").option("--json", "Output as JSON").option("--files <files>", "Comma-separated files modified (default: git diff)").option("--symbols <symbols>", "Comma-separated symbols touched").action(async (options) => {
|
|
738
|
-
const { habitsCheckCommand } = await import("./habits-
|
|
738
|
+
const { habitsCheckCommand } = await import("./habits-RG5SVKXP.js");
|
|
739
739
|
await habitsCheckCommand(options);
|
|
740
740
|
});
|
|
741
741
|
habitsCmd.command("add").description("Add a custom habit").requiredOption("--id <id>", "Habit ID (kebab-case)").requiredOption("--name <name>", "Human-readable name").requiredOption("--description <desc>", "What this habit enforces").requiredOption("--category <category>", "Category: discovery, verification, testing, documentation, collaboration, security").requiredOption("--trigger <trigger>", "Trigger: preflight, postflight, on-stop, on-commit").option("--severity <severity>", "Severity: advisory, warn, block", "advisory").option("--tools <tools>", "Comma-separated tools to check (for tool-called check type)").option("--check-type <type>", "Check type: tool-called, file-exists, file-modified, lore-recorded, symbols-registered, gates-declared, tests-exist, git-clean", "tool-called").option("--patterns <patterns>", "Comma-separated patterns (for file-exists, file-modified, tests-exist check types)").action(async (options) => {
|
|
742
|
-
const { habitsAddCommand } = await import("./habits-
|
|
742
|
+
const { habitsAddCommand } = await import("./habits-RG5SVKXP.js");
|
|
743
743
|
await habitsAddCommand({ ...options, checkType: options.checkType });
|
|
744
744
|
});
|
|
745
745
|
habitsCmd.command("edit <id>").description("Edit a habit (seed habits: only severity/enabled; custom: all fields)").option("--name <name>", "New name").option("--description <desc>", "New description").option("--category <category>", "New category").option("--trigger <trigger>", "New trigger").option("--severity <severity>", "New severity: advisory, warn, block").option("--enabled <bool>", "Enable or disable: true, false").option("--check-type <type>", "New check type").option("--patterns <patterns>", "Comma-separated patterns").option("--tools <tools>", "Comma-separated tools").action(async (id, options) => {
|
|
746
|
-
const { habitsEditCommand } = await import("./habits-
|
|
746
|
+
const { habitsEditCommand } = await import("./habits-RG5SVKXP.js");
|
|
747
747
|
await habitsEditCommand(id, { ...options, checkType: options.checkType });
|
|
748
748
|
});
|
|
749
749
|
habitsCmd.command("remove <id>").description("Remove a custom habit (seed habits cannot be removed, only disabled)").option("-y, --yes", "Skip confirmation").action(async (id, options) => {
|
|
750
|
-
const { habitsRemoveCommand } = await import("./habits-
|
|
750
|
+
const { habitsRemoveCommand } = await import("./habits-RG5SVKXP.js");
|
|
751
751
|
await habitsRemoveCommand(id, options);
|
|
752
752
|
});
|
|
753
753
|
habitsCmd.command("enable <id>").description("Enable a habit").action(async (id) => {
|
|
754
|
-
const { habitsToggleCommand } = await import("./habits-
|
|
754
|
+
const { habitsToggleCommand } = await import("./habits-RG5SVKXP.js");
|
|
755
755
|
await habitsToggleCommand(id, "enable");
|
|
756
756
|
});
|
|
757
757
|
habitsCmd.command("disable <id>").description("Disable a habit").action(async (id) => {
|
|
758
|
-
const { habitsToggleCommand } = await import("./habits-
|
|
758
|
+
const { habitsToggleCommand } = await import("./habits-RG5SVKXP.js");
|
|
759
759
|
await habitsToggleCommand(id, "disable");
|
|
760
760
|
});
|
|
761
761
|
habitsCmd.action(async () => {
|
|
762
|
-
const { habitsListCommand } = await import("./habits-
|
|
762
|
+
const { habitsListCommand } = await import("./habits-RG5SVKXP.js");
|
|
763
763
|
await habitsListCommand({});
|
|
764
764
|
});
|
|
765
765
|
var sentinelCmd = program.command("sentinel").description("Sentinel \u2014 semantic error monitoring");
|
|
766
766
|
sentinelCmd.command("defend [path]", { isDefault: true }).description("Launch the Sentinel UI - unified codebase intelligence visualizer").option("-p, --port <port>", "Port to run on", "3838").option("--no-open", "Don't open browser automatically").action(async (path2, options) => {
|
|
767
|
-
const { sentinelCommand } = await import("./sentinel-
|
|
767
|
+
const { sentinelCommand } = await import("./sentinel-UOIGJWHH.js");
|
|
768
768
|
await sentinelCommand(path2, options);
|
|
769
769
|
});
|
|
770
770
|
program.command("conductor").description("Launch Paradigm Conductor \u2014 multimodal mission control for Claude Code sessions").option("--build", "Force rebuild the native binary").option("-v, --verbose", "Show build output").action(async (options) => {
|
|
@@ -835,71 +835,92 @@ pipelineCmd.action(async () => {
|
|
|
835
835
|
});
|
|
836
836
|
var symphonyCmd = program.command("symphony").description("Symphony \u2014 agent-to-agent messaging for multi-session collaboration");
|
|
837
837
|
symphonyCmd.command("join").description("Join this session to the Symphony network").option("--remote <ip>", "Connect to remote Symphony server").action(async (options) => {
|
|
838
|
-
const { symphonyJoinCommand } = await import("./symphony-
|
|
838
|
+
const { symphonyJoinCommand } = await import("./symphony-6K3HD7AW.js");
|
|
839
839
|
await symphonyJoinCommand(options);
|
|
840
840
|
});
|
|
841
841
|
symphonyCmd.command("leave").description("Remove this session from the Symphony network").action(async () => {
|
|
842
|
-
const { symphonyLeaveCommand } = await import("./symphony-
|
|
842
|
+
const { symphonyLeaveCommand } = await import("./symphony-6K3HD7AW.js");
|
|
843
843
|
await symphonyLeaveCommand();
|
|
844
844
|
});
|
|
845
845
|
symphonyCmd.command("whoami").description("Show this agent's identity and linked peers").action(async () => {
|
|
846
|
-
const { symphonyWhoamiCommand } = await import("./symphony-
|
|
846
|
+
const { symphonyWhoamiCommand } = await import("./symphony-6K3HD7AW.js");
|
|
847
847
|
await symphonyWhoamiCommand();
|
|
848
848
|
});
|
|
849
849
|
symphonyCmd.command("list").alias("ls").description("List all joined agents").option("--json", "Output as JSON").action(async (options) => {
|
|
850
|
-
const { symphonyListCommand } = await import("./symphony-
|
|
850
|
+
const { symphonyListCommand } = await import("./symphony-6K3HD7AW.js");
|
|
851
851
|
await symphonyListCommand(options);
|
|
852
852
|
});
|
|
853
853
|
symphonyCmd.command("send <message>").description("Send a note to agents").option("--to <agent>", "Send to specific agent (omit for broadcast)").option("--thread <id>", "Reply to existing thread").action(async (message, options) => {
|
|
854
|
-
const { symphonySendCommand } = await import("./symphony-
|
|
854
|
+
const { symphonySendCommand } = await import("./symphony-6K3HD7AW.js");
|
|
855
855
|
await symphonySendCommand(message, options);
|
|
856
856
|
});
|
|
857
857
|
symphonyCmd.command("read").description("Show unread notes").action(async () => {
|
|
858
|
-
const { symphonyReadCommand } = await import("./symphony-
|
|
858
|
+
const { symphonyReadCommand } = await import("./symphony-6K3HD7AW.js");
|
|
859
859
|
await symphonyReadCommand();
|
|
860
860
|
});
|
|
861
861
|
symphonyCmd.command("inbox").description("Show unread notes (alias for read)").action(async () => {
|
|
862
|
-
const { symphonyReadCommand } = await import("./symphony-
|
|
862
|
+
const { symphonyReadCommand } = await import("./symphony-6K3HD7AW.js");
|
|
863
863
|
await symphonyReadCommand();
|
|
864
864
|
});
|
|
865
865
|
symphonyCmd.command("threads").description("List all threads").option("--json", "Output as JSON").action(async (options) => {
|
|
866
|
-
const { symphonyThreadsCommand } = await import("./symphony-
|
|
866
|
+
const { symphonyThreadsCommand } = await import("./symphony-6K3HD7AW.js");
|
|
867
867
|
await symphonyThreadsCommand(options);
|
|
868
868
|
});
|
|
869
869
|
symphonyCmd.command("thread <id>").description("Show full thread conversation").action(async (id) => {
|
|
870
|
-
const { symphonyThreadCommand } = await import("./symphony-
|
|
870
|
+
const { symphonyThreadCommand } = await import("./symphony-6K3HD7AW.js");
|
|
871
871
|
await symphonyThreadCommand(id);
|
|
872
872
|
});
|
|
873
873
|
symphonyCmd.command("resolve <id>").description("Mark a thread as resolved").option("--decision <text>", "Decision text to record").action(async (id, options) => {
|
|
874
|
-
const { symphonyResolveCommand } = await import("./symphony-
|
|
874
|
+
const { symphonyResolveCommand } = await import("./symphony-6K3HD7AW.js");
|
|
875
875
|
await symphonyResolveCommand(id, options);
|
|
876
876
|
});
|
|
877
877
|
symphonyCmd.command("status").description("Show Symphony network status").option("--json", "Output as JSON").action(async (options) => {
|
|
878
|
-
const { symphonyStatusCommand } = await import("./symphony-
|
|
878
|
+
const { symphonyStatusCommand } = await import("./symphony-6K3HD7AW.js");
|
|
879
879
|
await symphonyStatusCommand(options);
|
|
880
880
|
});
|
|
881
|
-
symphonyCmd.command("serve").description("Start
|
|
882
|
-
const { symphonyServeCommand } = await import("./symphony-
|
|
881
|
+
symphonyCmd.command("serve").description("Start Symphony relay server for cross-machine networking").option("--port <port>", "Port to listen on", "3939").option("--public", "Show connection string for internet access").action(async (options) => {
|
|
882
|
+
const { symphonyServeCommand } = await import("./symphony-6K3HD7AW.js");
|
|
883
883
|
await symphonyServeCommand(options);
|
|
884
884
|
});
|
|
885
|
+
var peersCmd = symphonyCmd.command("peers").description("Manage trusted remote peers");
|
|
886
|
+
peersCmd.command("list", { isDefault: true }).description("List trusted peers and their agents").option("--json", "Output as JSON").action(async (options) => {
|
|
887
|
+
const { symphonyPeersCommand } = await import("./peers-RFQCWVLV.js");
|
|
888
|
+
await symphonyPeersCommand(options);
|
|
889
|
+
});
|
|
890
|
+
peersCmd.command("revoke <id>").description("Revoke trust for a peer (disconnects immediately)").action(async (id) => {
|
|
891
|
+
const { symphonyPeersRevokeCommand } = await import("./peers-RFQCWVLV.js");
|
|
892
|
+
await symphonyPeersRevokeCommand(id);
|
|
893
|
+
});
|
|
894
|
+
peersCmd.command("forget").description("Clear all peer trust records").option("--force", "Skip confirmation").action(async (options) => {
|
|
895
|
+
const { symphonyPeersForgetCommand } = await import("./peers-RFQCWVLV.js");
|
|
896
|
+
await symphonyPeersForgetCommand(options);
|
|
897
|
+
});
|
|
898
|
+
peersCmd.action(async () => {
|
|
899
|
+
const { symphonyPeersCommand } = await import("./peers-RFQCWVLV.js");
|
|
900
|
+
await symphonyPeersCommand({});
|
|
901
|
+
});
|
|
885
902
|
symphonyCmd.command("request <file>").description("Request a file from another agent").option("--from <agent>", "Agent to request from").option("--reason <text>", "Why this file is needed").action(async (file, options) => {
|
|
886
|
-
const { symphonyRequestCommand } = await import("./symphony-
|
|
903
|
+
const { symphonyRequestCommand } = await import("./symphony-6K3HD7AW.js");
|
|
887
904
|
await symphonyRequestCommand(file, options);
|
|
888
905
|
});
|
|
889
906
|
symphonyCmd.command("requests").description("List pending file requests").action(async () => {
|
|
890
|
-
const { symphonyRequestsCommand } = await import("./symphony-
|
|
907
|
+
const { symphonyRequestsCommand } = await import("./symphony-6K3HD7AW.js");
|
|
891
908
|
await symphonyRequestsCommand();
|
|
892
909
|
});
|
|
893
910
|
symphonyCmd.command("approve <id>").description("Approve a file request").option("--redact", "Strip sensitive lines before sending").action(async (id, options) => {
|
|
894
|
-
const { symphonyApproveCommand } = await import("./symphony-
|
|
911
|
+
const { symphonyApproveCommand } = await import("./symphony-6K3HD7AW.js");
|
|
895
912
|
await symphonyApproveCommand(id, options);
|
|
896
913
|
});
|
|
897
914
|
symphonyCmd.command("deny <id>").description("Deny a file request").option("--reason <text>", "Reason for denial").action(async (id, options) => {
|
|
898
|
-
const { symphonyDenyCommand } = await import("./symphony-
|
|
915
|
+
const { symphonyDenyCommand } = await import("./symphony-6K3HD7AW.js");
|
|
899
916
|
await symphonyDenyCommand(id, options);
|
|
900
917
|
});
|
|
918
|
+
symphonyCmd.command("watch").description("Watch inbox in real-time \u2014 zero AI tokens, pure file monitoring").option("--interval <ms>", "Poll interval in milliseconds (default: 2000)").option("--thread <id>", "Only show messages from this thread").option("--quiet", "Minimal output \u2014 messages only, no header").action(async (options) => {
|
|
919
|
+
const { symphonyWatchCommand } = await import("./symphony-6K3HD7AW.js");
|
|
920
|
+
await symphonyWatchCommand(options);
|
|
921
|
+
});
|
|
901
922
|
symphonyCmd.action(async () => {
|
|
902
|
-
const { symphonyStatusCommand } = await import("./symphony-
|
|
923
|
+
const { symphonyStatusCommand } = await import("./symphony-6K3HD7AW.js");
|
|
903
924
|
await symphonyStatusCommand({});
|
|
904
925
|
});
|
|
905
926
|
program.parse();
|
package/dist/mcp.js
CHANGED
|
@@ -14,7 +14,7 @@ import {
|
|
|
14
14
|
StatsCalculator,
|
|
15
15
|
TimelineBuilder,
|
|
16
16
|
loadAllSeedPatterns
|
|
17
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-ZDHLG5VP.js";
|
|
18
18
|
import {
|
|
19
19
|
addStep,
|
|
20
20
|
addToolBreadcrumb,
|
|
@@ -90,7 +90,7 @@ import {
|
|
|
90
90
|
validateProtocol,
|
|
91
91
|
validatePurposeFile,
|
|
92
92
|
validateUniversityContent
|
|
93
|
-
} from "./chunk-
|
|
93
|
+
} from "./chunk-ZMQA6SCO.js";
|
|
94
94
|
import {
|
|
95
95
|
addLoreAssessment,
|
|
96
96
|
deleteLoreEntry,
|
|
@@ -12098,7 +12098,7 @@ var PERSONA_SCHEMA = {
|
|
|
12098
12098
|
var sentinelSchemaRegistered = false;
|
|
12099
12099
|
async function emitPersonaEvents(result) {
|
|
12100
12100
|
try {
|
|
12101
|
-
const { SentinelStorage: SentinelStorage2 } = await import("./dist-
|
|
12101
|
+
const { SentinelStorage: SentinelStorage2 } = await import("./dist-CM3MVWWW.js");
|
|
12102
12102
|
const storage2 = new SentinelStorage2();
|
|
12103
12103
|
if (!sentinelSchemaRegistered) {
|
|
12104
12104
|
try {
|
|
@@ -14557,12 +14557,15 @@ function getMyIdentity(projectDir2) {
|
|
|
14557
14557
|
return null;
|
|
14558
14558
|
}
|
|
14559
14559
|
}
|
|
14560
|
-
function markAgentPollTime(agentId) {
|
|
14560
|
+
function markAgentPollTime(agentId, statusBlurb) {
|
|
14561
14561
|
const identityPath = path28.join(getAgentDir(agentId), "identity.json");
|
|
14562
14562
|
if (!fs26.existsSync(identityPath)) return;
|
|
14563
14563
|
try {
|
|
14564
14564
|
const identity = JSON.parse(fs26.readFileSync(identityPath, "utf-8"));
|
|
14565
14565
|
identity.lastPoll = (/* @__PURE__ */ new Date()).toISOString();
|
|
14566
|
+
if (statusBlurb !== void 0) {
|
|
14567
|
+
identity.statusBlurb = statusBlurb || void 0;
|
|
14568
|
+
}
|
|
14566
14569
|
fs26.writeFileSync(identityPath, JSON.stringify(identity, null, 2), "utf-8");
|
|
14567
14570
|
} catch {
|
|
14568
14571
|
}
|
|
@@ -14581,6 +14584,35 @@ function outboxPath(agentId) {
|
|
|
14581
14584
|
function ackPath(agentId) {
|
|
14582
14585
|
return path28.join(getAgentDir(agentId), "ack.json");
|
|
14583
14586
|
}
|
|
14587
|
+
function peekInbox(agentId) {
|
|
14588
|
+
const filePath = inboxPath(agentId);
|
|
14589
|
+
if (!fs26.existsSync(filePath)) return { hasNew: false, inboxSize: 0 };
|
|
14590
|
+
const stat = fs26.statSync(filePath);
|
|
14591
|
+
const inboxSize = stat.size;
|
|
14592
|
+
const ack = readAck(agentId);
|
|
14593
|
+
if (!ack) {
|
|
14594
|
+
return { hasNew: inboxSize > 0, inboxSize };
|
|
14595
|
+
}
|
|
14596
|
+
const ackSizePath = path28.join(getAgentDir(agentId), "ack-size.json");
|
|
14597
|
+
if (fs26.existsSync(ackSizePath)) {
|
|
14598
|
+
try {
|
|
14599
|
+
const ackSize = JSON.parse(fs26.readFileSync(ackSizePath, "utf-8"));
|
|
14600
|
+
return { hasNew: inboxSize > (ackSize.size || 0), inboxSize };
|
|
14601
|
+
} catch {
|
|
14602
|
+
}
|
|
14603
|
+
}
|
|
14604
|
+
return { hasNew: inboxSize > 0, inboxSize };
|
|
14605
|
+
}
|
|
14606
|
+
function recordAckSize(agentId) {
|
|
14607
|
+
const filePath = inboxPath(agentId);
|
|
14608
|
+
const ackSizePath = path28.join(getAgentDir(agentId), "ack-size.json");
|
|
14609
|
+
try {
|
|
14610
|
+
const size = fs26.existsSync(filePath) ? fs26.statSync(filePath).size : 0;
|
|
14611
|
+
ensureAgentDir(agentId);
|
|
14612
|
+
fs26.writeFileSync(ackSizePath, JSON.stringify({ size }), "utf-8");
|
|
14613
|
+
} catch {
|
|
14614
|
+
}
|
|
14615
|
+
}
|
|
14584
14616
|
function appendToInbox(agentId, message) {
|
|
14585
14617
|
ensureAgentDir(agentId);
|
|
14586
14618
|
appendJsonlLine(inboxPath(agentId), message);
|
|
@@ -14939,12 +14971,34 @@ function isProcessAlive2(pid) {
|
|
|
14939
14971
|
// ../paradigm-mcp/src/tools/symphony.ts
|
|
14940
14972
|
function getSymphonyToolsList() {
|
|
14941
14973
|
return [
|
|
14974
|
+
{
|
|
14975
|
+
name: "paradigm_symphony_peek",
|
|
14976
|
+
description: "Ultra-cheap inbox check \u2014 file stat only, no parsing. Returns { hasNew: true/false }. Use with /loop 10s for near-free monitoring. When hasNew is true, call paradigm_symphony_poll to read messages. ~15 tokens.",
|
|
14977
|
+
inputSchema: {
|
|
14978
|
+
type: "object",
|
|
14979
|
+
properties: {
|
|
14980
|
+
status: {
|
|
14981
|
+
type: "string",
|
|
14982
|
+
description: "Short status blurb (same as poll). Updates heartbeat."
|
|
14983
|
+
}
|
|
14984
|
+
}
|
|
14985
|
+
},
|
|
14986
|
+
annotations: {
|
|
14987
|
+
readOnlyHint: true,
|
|
14988
|
+
destructiveHint: false
|
|
14989
|
+
}
|
|
14990
|
+
},
|
|
14942
14991
|
{
|
|
14943
14992
|
name: "paradigm_symphony_poll",
|
|
14944
|
-
description: "
|
|
14993
|
+
description: "Read inbox notes and process them. Call when paradigm_symphony_peek returns hasNew: true, or directly via /loop for continuous messaging. Returns unread notes formatted as markdown with thread context and suggested actions. Updates heartbeat and optional status blurb. ~200 tokens.",
|
|
14945
14994
|
inputSchema: {
|
|
14946
14995
|
type: "object",
|
|
14947
|
-
properties: {
|
|
14996
|
+
properties: {
|
|
14997
|
+
status: {
|
|
14998
|
+
type: "string",
|
|
14999
|
+
description: 'Short status blurb describing what you are currently working on (e.g., "Implementing auth middleware \u2014 3 files modified"). Visible to humans and other agents in the Network view.'
|
|
15000
|
+
}
|
|
15001
|
+
}
|
|
14948
15002
|
},
|
|
14949
15003
|
annotations: {
|
|
14950
15004
|
readOnlyHint: false,
|
|
@@ -15113,14 +15167,26 @@ async function handleSymphonyTool(name, args, ctx) {
|
|
|
15113
15167
|
identity = registerAgent(ctx.rootDir);
|
|
15114
15168
|
}
|
|
15115
15169
|
switch (name) {
|
|
15170
|
+
case "paradigm_symphony_peek": {
|
|
15171
|
+
const peekStatus = args.status;
|
|
15172
|
+
markAgentPollTime(identity.id, peekStatus);
|
|
15173
|
+
const { hasNew } = peekInbox(identity.id);
|
|
15174
|
+
const pendingRequests = hasNew ? listFileRequests("pending").length : 0;
|
|
15175
|
+
return {
|
|
15176
|
+
handled: true,
|
|
15177
|
+
text: JSON.stringify(hasNew ? { hasNew: true, pendingFileRequests: pendingRequests, action: "call paradigm_symphony_poll to read" } : { hasNew: false })
|
|
15178
|
+
};
|
|
15179
|
+
}
|
|
15116
15180
|
case "paradigm_symphony_poll": {
|
|
15117
15181
|
cleanStaleAgents();
|
|
15118
15182
|
expireOldRequests();
|
|
15119
|
-
|
|
15183
|
+
const statusBlurb = args.status;
|
|
15184
|
+
markAgentPollTime(identity.id, statusBlurb);
|
|
15120
15185
|
const messages = readInbox(identity.id);
|
|
15121
15186
|
if (messages.length > 0) {
|
|
15122
15187
|
const lastId = messages[messages.length - 1].id;
|
|
15123
15188
|
acknowledgeMessages(identity.id, lastId);
|
|
15189
|
+
recordAckSize(identity.id);
|
|
15124
15190
|
}
|
|
15125
15191
|
garbageCollect(identity.id);
|
|
15126
15192
|
const pendingRequests = listFileRequests("pending");
|
|
@@ -15227,6 +15293,18 @@ async function handleSymphonyTool(name, args, ctx) {
|
|
|
15227
15293
|
const threads = listThreads("active");
|
|
15228
15294
|
const unread = readInbox(identity.id);
|
|
15229
15295
|
const pendingRequests = listFileRequests("pending");
|
|
15296
|
+
let peers = [];
|
|
15297
|
+
try {
|
|
15298
|
+
const { loadPeers } = await import("./symphony-peers-APOGJPF4.js");
|
|
15299
|
+
const allPeers = loadPeers();
|
|
15300
|
+
peers = allPeers.filter((p) => !p.revoked).map((p) => ({
|
|
15301
|
+
id: p.id,
|
|
15302
|
+
address: p.address,
|
|
15303
|
+
agents: p.agents?.length ?? 0,
|
|
15304
|
+
lastSeen: p.lastSeen
|
|
15305
|
+
}));
|
|
15306
|
+
} catch {
|
|
15307
|
+
}
|
|
15230
15308
|
return {
|
|
15231
15309
|
handled: true,
|
|
15232
15310
|
text: JSON.stringify({
|
|
@@ -15241,8 +15319,10 @@ async function handleSymphonyTool(name, args, ctx) {
|
|
|
15241
15319
|
project: a.project,
|
|
15242
15320
|
role: a.role,
|
|
15243
15321
|
status: isAgentAsleep(a) ? "asleep" : "awake",
|
|
15244
|
-
lastPoll: a.lastPoll
|
|
15322
|
+
lastPoll: a.lastPoll,
|
|
15323
|
+
statusBlurb: a.statusBlurb
|
|
15245
15324
|
})),
|
|
15325
|
+
peers,
|
|
15246
15326
|
activeThreads: threads.map((t) => ({
|
|
15247
15327
|
id: t.id,
|
|
15248
15328
|
topic: t.topic,
|
|
@@ -17440,7 +17520,7 @@ Update command:
|
|
|
17440
17520
|
trackToolCall(noWsText.length, name);
|
|
17441
17521
|
return { content: [{ type: "text", text: noWsText }] };
|
|
17442
17522
|
}
|
|
17443
|
-
const { rebuildStaticFiles: rebuildStaticFiles2 } = await import("./reindex-
|
|
17523
|
+
const { rebuildStaticFiles: rebuildStaticFiles2 } = await import("./reindex-WIJMCJ4A.js");
|
|
17444
17524
|
const memberResults = [];
|
|
17445
17525
|
for (const member of ctx.workspace.config.members) {
|
|
17446
17526
|
const memberAbsPath = path31.resolve(path31.dirname(ctx.workspace.workspacePath), member.path);
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
forgetAllPeers,
|
|
4
|
+
loadPeers,
|
|
5
|
+
revokePeer
|
|
6
|
+
} from "./chunk-KVDYJLTC.js";
|
|
7
|
+
import "./chunk-ZXMDA7VB.js";
|
|
8
|
+
|
|
9
|
+
// src/commands/symphony/peers.ts
|
|
10
|
+
import chalk from "chalk";
|
|
11
|
+
async function symphonyPeersCommand(options) {
|
|
12
|
+
const peers = loadPeers();
|
|
13
|
+
if (options.json) {
|
|
14
|
+
console.log(JSON.stringify(peers, null, 2));
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
if (peers.length === 0) {
|
|
18
|
+
console.log(chalk.yellow('No trusted peers. Run "paradigm symphony serve" to accept connections.'));
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
console.log(chalk.cyan(`
|
|
22
|
+
Trusted Peers (${peers.length})
|
|
23
|
+
`));
|
|
24
|
+
console.log(chalk.gray(` ${"PEER ID".padEnd(20)} ${"ADDRESS".padEnd(22)} ${"STATUS".padEnd(10)} ${"AGENTS".padEnd(8)} LAST SEEN`));
|
|
25
|
+
console.log(chalk.gray(` ${"\u2500".repeat(20)} ${"\u2500".repeat(22)} ${"\u2500".repeat(10)} ${"\u2500".repeat(8)} ${"\u2500".repeat(20)}`));
|
|
26
|
+
for (const peer of peers) {
|
|
27
|
+
const status = peer.revoked ? chalk.red("revoked") : chalk.green("trusted");
|
|
28
|
+
const agentCount = (peer.agents || []).length.toString();
|
|
29
|
+
const lastSeen = peer.lastSeen ? formatRelativeTime(peer.lastSeen) : chalk.gray("never");
|
|
30
|
+
console.log(` ${chalk.white(peer.id.padEnd(20))} ${peer.address.padEnd(22)} ${status.padEnd(10)} ${agentCount.padEnd(8)} ${lastSeen}`);
|
|
31
|
+
if (peer.agents && peer.agents.length > 0) {
|
|
32
|
+
for (const agent of peer.agents) {
|
|
33
|
+
const agentStatus = agent.status === "awake" ? chalk.green("awake") : chalk.yellow("asleep");
|
|
34
|
+
console.log(chalk.gray(` \u2514 ${agent.id} [${agentStatus}]`));
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
console.log();
|
|
39
|
+
}
|
|
40
|
+
async function symphonyPeersRevokeCommand(peerId) {
|
|
41
|
+
const success = revokePeer(peerId);
|
|
42
|
+
if (success) {
|
|
43
|
+
console.log(chalk.green(`\u2713 Revoked peer ${chalk.bold(peerId)}`));
|
|
44
|
+
console.log(chalk.gray(" Peer will be disconnected and cannot reconnect until re-paired."));
|
|
45
|
+
} else {
|
|
46
|
+
console.log(chalk.red(`Peer "${peerId}" not found.`));
|
|
47
|
+
const peers = loadPeers();
|
|
48
|
+
if (peers.length > 0) {
|
|
49
|
+
console.log(chalk.gray("\n Available peers:"));
|
|
50
|
+
for (const p of peers) {
|
|
51
|
+
console.log(chalk.gray(` ${p.id} (${p.address})`));
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
async function symphonyPeersForgetCommand(options) {
|
|
57
|
+
const peers = loadPeers();
|
|
58
|
+
if (peers.length === 0) {
|
|
59
|
+
console.log(chalk.yellow("No peers to forget."));
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
if (!options.force) {
|
|
63
|
+
console.log(chalk.yellow(`This will remove all ${peers.length} trusted peer(s). Use --force to confirm.`));
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
const count = forgetAllPeers();
|
|
67
|
+
console.log(chalk.green(`\u2713 Forgot ${count} peer${count !== 1 ? "s" : ""}`));
|
|
68
|
+
console.log(chalk.gray(" All peer trust records deleted. Re-pairing required for remote connections."));
|
|
69
|
+
}
|
|
70
|
+
function formatRelativeTime(isoDate) {
|
|
71
|
+
const diff = Date.now() - new Date(isoDate).getTime();
|
|
72
|
+
const seconds = Math.floor(diff / 1e3);
|
|
73
|
+
if (seconds < 60) return "just now";
|
|
74
|
+
if (seconds < 3600) return `${Math.floor(seconds / 60)}m ago`;
|
|
75
|
+
if (seconds < 86400) return `${Math.floor(seconds / 3600)}h ago`;
|
|
76
|
+
return `${Math.floor(seconds / 86400)}d ago`;
|
|
77
|
+
}
|
|
78
|
+
export {
|
|
79
|
+
symphonyPeersCommand,
|
|
80
|
+
symphonyPeersForgetCommand,
|
|
81
|
+
symphonyPeersRevokeCommand
|
|
82
|
+
};
|