wyrm-mcp 7.2.0 → 7.2.2
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/LICENSE +26 -667
- package/NOTICE +14 -33
- package/dist/activation.d.ts.map +1 -1
- package/dist/activation.js +1 -44
- package/dist/activation.js.map +1 -1
- package/dist/agent-daemon.js +4 -281
- package/dist/agent-loop.js +7 -332
- package/dist/analytics.js +13 -236
- package/dist/attribution.js +1 -49
- package/dist/audit.js +2 -457
- package/dist/auto-capture.js +3 -138
- package/dist/auto-orchestrator.js +1 -325
- package/dist/autoconfig.js +39 -840
- package/dist/buddy-runner.js +1 -109
- package/dist/buddy.js +14 -564
- package/dist/build-flags.js +1 -17
- package/dist/capabilities.js +3 -183
- package/dist/capture.js +1 -56
- package/dist/causality.js +6 -107
- package/dist/cli.js +20 -281
- package/dist/cloud/cli.js +5 -541
- package/dist/cloud/client.js +1 -221
- package/dist/cloud/crypto.js +1 -85
- package/dist/cloud/machine-id.js +2 -113
- package/dist/cloud/recovery.js +1 -60
- package/dist/cloud/sync-engine.js +7 -543
- package/dist/cloud-backup.js +5 -579
- package/dist/cloud-profile.js +1 -138
- package/dist/cloud-sync-entrypoint.js +1 -47
- package/dist/cloud-sync.js +2 -309
- package/dist/constellation.js +12 -168
- package/dist/context-build-budgeted.js +4 -144
- package/dist/context-ranking.js +1 -69
- package/dist/crypto.js +1 -179
- package/dist/daemon-write-endpoint.js +1 -290
- package/dist/daemon-writer.js +2 -406
- package/dist/database.js +43 -1110
- package/dist/deprecations.js +2 -162
- package/dist/design.js +13 -141
- package/dist/event-replication.js +1 -112
- package/dist/events-sse.js +7 -43
- package/dist/events.js +6 -238
- package/dist/failure-patterns.js +42 -659
- package/dist/federation.js +12 -236
- package/dist/goals.js +13 -101
- package/dist/golden.js +3 -355
- package/dist/handlers/agent.js +4 -165
- package/dist/handlers/alias-adapters.js +1 -129
- package/dist/handlers/aliases.js +1 -171
- package/dist/handlers/audit.js +1 -87
- package/dist/handlers/boundary.js +1 -221
- package/dist/handlers/capture.js +73 -1109
- package/dist/handlers/causality.js +7 -114
- package/dist/handlers/cloud.js +85 -382
- package/dist/handlers/companion.js +28 -459
- package/dist/handlers/datalake.js +7 -187
- package/dist/handlers/dispatch-context.js +0 -22
- package/dist/handlers/entity.js +25 -256
- package/dist/handlers/events.js +16 -335
- package/dist/handlers/failure.js +13 -340
- package/dist/handlers/goals.js +4 -296
- package/dist/handlers/intelligence.js +126 -674
- package/dist/handlers/invoicing.js +1 -70
- package/dist/handlers/mcpclient.js +6 -137
- package/dist/handlers/orchestration.js +40 -125
- package/dist/handlers/output-schemas.js +1 -24
- package/dist/handlers/presence.js +3 -99
- package/dist/handlers/project.js +28 -182
- package/dist/handlers/prompts.js +6 -157
- package/dist/handlers/quest.js +4 -224
- package/dist/handlers/recall.js +11 -218
- package/dist/handlers/registry.js +1 -167
- package/dist/handlers/resources.js +1 -288
- package/dist/handlers/review.js +11 -74
- package/dist/handlers/run.js +17 -487
- package/dist/handlers/search.js +15 -326
- package/dist/handlers/session.js +28 -615
- package/dist/handlers/share.js +8 -184
- package/dist/handlers/shims.js +1 -464
- package/dist/handlers/skill.js +67 -449
- package/dist/handlers/survivors.js +1 -120
- package/dist/handlers/symbols.js +8 -109
- package/dist/handlers/syncops.js +4 -302
- package/dist/handlers/types.js +1 -27
- package/dist/harvest.js +5 -191
- package/dist/hours.js +7 -156
- package/dist/http-auth.js +3 -321
- package/dist/http-fast.js +21 -1137
- package/dist/icons.js +1 -47
- package/dist/index.js +2 -924
- package/dist/indexer.js +4 -145
- package/dist/intelligence.js +31 -261
- package/dist/internal-dispatch.js +3 -212
- package/dist/keyset.js +1 -110
- package/dist/knowledge-graph.js +12 -176
- package/dist/license.d.ts +11 -0
- package/dist/license.d.ts.map +1 -1
- package/dist/license.js +2 -414
- package/dist/license.js.map +1 -1
- package/dist/logger.js +2 -199
- package/dist/maintenance.js +2 -148
- package/dist/mcp-client.js +6 -262
- package/dist/memory-artifacts.js +30 -449
- package/dist/migrate-prompt.js +2 -124
- package/dist/migrations.js +40 -655
- package/dist/performance.js +1 -228
- package/dist/presence.js +11 -140
- package/dist/priority-embed.js +5 -164
- package/dist/providers/embedding-provider.js +1 -196
- package/dist/readonly-gate.js +1 -29
- package/dist/rehydration.js +9 -157
- package/dist/reindex.js +1 -88
- package/dist/render-target.js +21 -514
- package/dist/render.js +4 -280
- package/dist/repl-guard.js +1 -173
- package/dist/replication-daemon-entrypoint.js +1 -31
- package/dist/replication-daemon.js +2 -262
- package/dist/resilience.js +1 -591
- package/dist/reverse-bridge.js +5 -360
- package/dist/security.js +1 -244
- package/dist/session-seen.js +3 -51
- package/dist/setup.js +1 -260
- package/dist/skill-author.js +5 -168
- package/dist/spec-kit.js +1 -191
- package/dist/sqlite-busy.js +1 -154
- package/dist/statusline.js +11 -315
- package/dist/sub-agent.js +13 -262
- package/dist/summarizer.js +13 -139
- package/dist/symbols.js +7 -283
- package/dist/sync.js +5 -359
- package/dist/tasks-dispatch.js +1 -84
- package/dist/tasks.js +1 -282
- package/dist/token-budget.js +1 -143
- package/dist/tool-analytics.js +7 -129
- package/dist/tool-annotations.js +1 -365
- package/dist/tool-manifest-v2.json +1 -1
- package/dist/tool-manifest.json +1 -1
- package/dist/tool-profiles.js +1 -75
- package/dist/trace-harvest.js +6 -244
- package/dist/types.js +1 -30
- package/dist/ui-dashboard.js +41 -50
- package/dist/ulid.js +1 -81
- package/dist/validate.js +1 -129
- package/dist/vault.js +1 -534
- package/dist/vectors.js +3 -184
- package/dist/version-check.js +4 -136
- package/dist/visibility.js +19 -155
- package/dist/wyrm-cli.js +98 -2451
- package/dist/wyrm-cli.js.map +1 -1
- package/dist/wyrm-guard.js +14 -424
- package/dist/wyrm-loop.js +3 -150
- package/dist/wyrm-manifest.json +1 -1
- package/dist/wyrm-statusline-daemon.js +1 -11
- package/dist/wyrm-statusline.js +4 -56
- package/dist/wyrm-ui.js +9 -77
- package/package.json +4 -2
|
@@ -1,114 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
name: "wyrm_decided_because",
|
|
9
|
-
description: "Use to link a choice or decision to the assumption or evidence it was based on - records a causal edge (truth/quest/artifact/session) so stale foundations invalidate downstream.",
|
|
10
|
-
inputSchema: {
|
|
11
|
-
type: "object",
|
|
12
|
-
properties: {
|
|
13
|
-
projectPath: { type: "string" },
|
|
14
|
-
from_kind: { type: "string", enum: ["truth", "artifact", "quest", "session", "data"] },
|
|
15
|
-
from_id: { type: "number" },
|
|
16
|
-
to_kind: { type: "string", enum: ["truth", "artifact", "quest", "session", "data"] },
|
|
17
|
-
to_id: { type: "number" },
|
|
18
|
-
relation: { type: "string", enum: ["because_of", "supersedes", "refutes", "verifies"], description: "Default because_of" },
|
|
19
|
-
rationale: { type: "string", description: "Why" },
|
|
20
|
-
confidence: { type: "number", description: "0-1, default 1.0" },
|
|
21
|
-
},
|
|
22
|
-
required: ["projectPath", "from_kind", "from_id", "to_kind", "to_id"],
|
|
23
|
-
},
|
|
24
|
-
annotations: TOOL_ANNOTATIONS["wyrm_decided_because"],
|
|
25
|
-
aliases: [],
|
|
26
|
-
handler: async (args, ctx) => {
|
|
27
|
-
const { causality, db } = ctx;
|
|
28
|
-
const { projectPath, from_kind, from_id, to_kind, to_id, relation, rationale, confidence, } = args;
|
|
29
|
-
const project = db.getProject(projectPath);
|
|
30
|
-
if (!project)
|
|
31
|
-
return { content: [{ type: "text", text: "Project not found" }], isError: true };
|
|
32
|
-
const edge = causality.link({
|
|
33
|
-
project_id: project.id,
|
|
34
|
-
from_kind, from_id, to_kind, to_id, relation, rationale, confidence,
|
|
35
|
-
});
|
|
36
|
-
return { content: [{ type: "text", text: ` Edge #${edge.id} — ${from_kind}#${from_id} ${edge.relation} ${to_kind}#${to_id}` }] };
|
|
37
|
-
},
|
|
38
|
-
},
|
|
39
|
-
{
|
|
40
|
-
name: "wyrm_decision_downstream",
|
|
41
|
-
description: "List all decisions that depend on the given source. Use before invalidating a truth to see the blast radius.",
|
|
42
|
-
inputSchema: {
|
|
43
|
-
type: "object",
|
|
44
|
-
properties: {
|
|
45
|
-
kind: { type: "string", enum: ["truth", "artifact", "quest", "session", "data"] },
|
|
46
|
-
id: { type: "number" },
|
|
47
|
-
},
|
|
48
|
-
required: ["kind", "id"],
|
|
49
|
-
},
|
|
50
|
-
annotations: TOOL_ANNOTATIONS["wyrm_decision_downstream"],
|
|
51
|
-
aliases: [],
|
|
52
|
-
handler: async (args, ctx) => {
|
|
53
|
-
const { causality } = ctx;
|
|
54
|
-
const { kind, id } = args;
|
|
55
|
-
const edges = causality.downstreamOf(kind, id);
|
|
56
|
-
if (edges.length === 0) {
|
|
57
|
-
return { content: [{ type: "text", text: ` No active dependents on ${kind}#${id}.` }] };
|
|
58
|
-
}
|
|
59
|
-
const text = edges.map(e => `• ${e.from_kind}#${e.from_id} (${e.relation}, conf ${e.confidence})${e.rationale ? ` — ${e.rationale}` : ''}`).join('\n');
|
|
60
|
-
return { content: [{ type: "text", text: ` ${edges.length} dependent(s):\n${text}` }] };
|
|
61
|
-
},
|
|
62
|
-
},
|
|
63
|
-
{
|
|
64
|
-
name: "wyrm_decision_upstream",
|
|
65
|
-
description: "List all sources a decision was based on (incoming edges). Walks the 'why did we choose this?' chain.",
|
|
66
|
-
inputSchema: {
|
|
67
|
-
type: "object",
|
|
68
|
-
properties: {
|
|
69
|
-
kind: { type: "string", enum: ["truth", "artifact", "quest", "session", "data"] },
|
|
70
|
-
id: { type: "number" },
|
|
71
|
-
},
|
|
72
|
-
required: ["kind", "id"],
|
|
73
|
-
},
|
|
74
|
-
annotations: TOOL_ANNOTATIONS["wyrm_decision_upstream"],
|
|
75
|
-
aliases: [],
|
|
76
|
-
handler: async (args, ctx) => {
|
|
77
|
-
const { causality } = ctx;
|
|
78
|
-
const { kind, id } = args;
|
|
79
|
-
const edges = causality.upstreamOf(kind, id);
|
|
80
|
-
if (edges.length === 0) {
|
|
81
|
-
return { content: [{ type: "text", text: ` No recorded basis for ${kind}#${id}.` }] };
|
|
82
|
-
}
|
|
83
|
-
const text = edges.map(e => `• ${e.to_kind}#${e.to_id} (${e.relation}, conf ${e.confidence})${e.rationale ? ` — ${e.rationale}` : ''}`).join('\n');
|
|
84
|
-
return { content: [{ type: "text", text: ` ${edges.length} basis edge(s):\n${text}` }] };
|
|
85
|
-
},
|
|
86
|
-
},
|
|
87
|
-
{
|
|
88
|
-
name: "wyrm_decision_invalidate",
|
|
89
|
-
description: "Cascade-invalidate all decisions downstream of a source (recursive). Use when a foundational truth turns out to be wrong. Returns the set of affected (kind, id) pairs.",
|
|
90
|
-
inputSchema: {
|
|
91
|
-
type: "object",
|
|
92
|
-
properties: {
|
|
93
|
-
kind: { type: "string", enum: ["truth", "artifact", "quest", "session", "data"] },
|
|
94
|
-
id: { type: "number" },
|
|
95
|
-
reason: { type: "string", description: "Why the source was invalidated" },
|
|
96
|
-
},
|
|
97
|
-
required: ["kind", "id"],
|
|
98
|
-
},
|
|
99
|
-
annotations: TOOL_ANNOTATIONS["wyrm_decision_invalidate"],
|
|
100
|
-
aliases: [],
|
|
101
|
-
handler: async (args, ctx) => {
|
|
102
|
-
const { causality } = ctx;
|
|
103
|
-
const a = args || {};
|
|
104
|
-
const { kind, id, reason } = args;
|
|
105
|
-
const result = causality.invalidateDownstream(kind, id, reason);
|
|
106
|
-
if (result.invalidated === 0) {
|
|
107
|
-
return { content: [{ type: "text", text: ` No dependents to invalidate from ${kind}#${id}.` }] };
|
|
108
|
-
}
|
|
109
|
-
const text = result.affected.map(a => `• ${a.kind}#${a.id} (edge #${a.edge_id})`).join('\n');
|
|
110
|
-
return { content: [{ type: "text", text: ` Invalidated ${result.invalidated} downstream decision(s):\n${text}` }] };
|
|
111
|
-
},
|
|
112
|
-
},
|
|
113
|
-
];
|
|
114
|
-
//# sourceMappingURL=causality.js.map
|
|
1
|
+
import{TOOL_ANNOTATIONS as u}from"../tool-annotations.js";const h=[{name:"wyrm_decided_because",description:"Use to link a choice or decision to the assumption or evidence it was based on - records a causal edge (truth/quest/artifact/session) so stale foundations invalidate downstream.",inputSchema:{type:"object",properties:{projectPath:{type:"string"},from_kind:{type:"string",enum:["truth","artifact","quest","session","data"]},from_id:{type:"number"},to_kind:{type:"string",enum:["truth","artifact","quest","session","data"]},to_id:{type:"number"},relation:{type:"string",enum:["because_of","supersedes","refutes","verifies"],description:"Default because_of"},rationale:{type:"string",description:"Why"},confidence:{type:"number",description:"0-1, default 1.0"}},required:["projectPath","from_kind","from_id","to_kind","to_id"]},annotations:u.wyrm_decided_because,aliases:[],handler:async(i,a)=>{const{causality:r,db:o}=a,{projectPath:n,from_kind:e,from_id:s,to_kind:t,to_id:c,relation:d,rationale:m,confidence:y}=i,p=o.getProject(n);if(!p)return{content:[{type:"text",text:"Project not found"}],isError:!0};const l=r.link({project_id:p.id,from_kind:e,from_id:s,to_kind:t,to_id:c,relation:d,rationale:m,confidence:y});return{content:[{type:"text",text:`\u{F115D} Edge #${l.id} \u2014 ${e}#${s} ${l.relation} ${t}#${c}`}]}}},{name:"wyrm_decision_downstream",description:"List all decisions that depend on the given source. Use before invalidating a truth to see the blast radius.",inputSchema:{type:"object",properties:{kind:{type:"string",enum:["truth","artifact","quest","session","data"]},id:{type:"number"}},required:["kind","id"]},annotations:u.wyrm_decision_downstream,aliases:[],handler:async(i,a)=>{const{causality:r}=a,{kind:o,id:n}=i,e=r.downstreamOf(o,n);if(e.length===0)return{content:[{type:"text",text:`\u{F115D} No active dependents on ${o}#${n}.`}]};const s=e.map(t=>`\u2022 ${t.from_kind}#${t.from_id} (${t.relation}, conf ${t.confidence})${t.rationale?` \u2014 ${t.rationale}`:""}`).join(`
|
|
2
|
+
`);return{content:[{type:"text",text:`\u{F115D} ${e.length} dependent(s):
|
|
3
|
+
${s}`}]}}},{name:"wyrm_decision_upstream",description:"List all sources a decision was based on (incoming edges). Walks the 'why did we choose this?' chain.",inputSchema:{type:"object",properties:{kind:{type:"string",enum:["truth","artifact","quest","session","data"]},id:{type:"number"}},required:["kind","id"]},annotations:u.wyrm_decision_upstream,aliases:[],handler:async(i,a)=>{const{causality:r}=a,{kind:o,id:n}=i,e=r.upstreamOf(o,n);if(e.length===0)return{content:[{type:"text",text:`\u{F115D} No recorded basis for ${o}#${n}.`}]};const s=e.map(t=>`\u2022 ${t.to_kind}#${t.to_id} (${t.relation}, conf ${t.confidence})${t.rationale?` \u2014 ${t.rationale}`:""}`).join(`
|
|
4
|
+
`);return{content:[{type:"text",text:`\u{F115D} ${e.length} basis edge(s):
|
|
5
|
+
${s}`}]}}},{name:"wyrm_decision_invalidate",description:"Cascade-invalidate all decisions downstream of a source (recursive). Use when a foundational truth turns out to be wrong. Returns the set of affected (kind, id) pairs.",inputSchema:{type:"object",properties:{kind:{type:"string",enum:["truth","artifact","quest","session","data"]},id:{type:"number"},reason:{type:"string",description:"Why the source was invalidated"}},required:["kind","id"]},annotations:u.wyrm_decision_invalidate,aliases:[],handler:async(i,a)=>{const{causality:r}=a,o=i||{},{kind:n,id:e,reason:s}=i,t=r.invalidateDownstream(n,e,s);if(t.invalidated===0)return{content:[{type:"text",text:`\u{F115D} No dependents to invalidate from ${n}#${e}.`}]};const c=t.affected.map(d=>`\u2022 ${d.kind}#${d.id} (edge #${d.edge_id})`).join(`
|
|
6
|
+
`);return{content:[{type:"text",text:`\u{F115D} Invalidated ${t.invalidated} downstream decision(s):
|
|
7
|
+
${c}`}]}}}];export{h as causalityToolSpecs};
|
package/dist/handlers/cloud.js
CHANGED
|
@@ -1,382 +1,85 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
return {
|
|
87
|
-
content: [{ type: "text", text: ` ✗ Invalid license format. Please verify your license key.` }],
|
|
88
|
-
isError: true,
|
|
89
|
-
};
|
|
90
|
-
}
|
|
91
|
-
},
|
|
92
|
-
},
|
|
93
|
-
{
|
|
94
|
-
name: "wyrm_analytics_dashboard",
|
|
95
|
-
description: "View usage analytics dashboard — tool calls, tokens, costs, cache efficiency (Pro+)",
|
|
96
|
-
inputSchema: {
|
|
97
|
-
type: "object",
|
|
98
|
-
properties: {
|
|
99
|
-
days: { type: "number", description: "Number of days to analyze (default: 30)" },
|
|
100
|
-
},
|
|
101
|
-
},
|
|
102
|
-
annotations: TOOL_ANNOTATIONS["wyrm_analytics_dashboard"],
|
|
103
|
-
aliases: [],
|
|
104
|
-
handler: async (args, ctx) => {
|
|
105
|
-
const { analytics } = ctx;
|
|
106
|
-
const a = args || {};
|
|
107
|
-
if (!hasFeature('analytics')) {
|
|
108
|
-
return {
|
|
109
|
-
content: [{ type: "text", text: ` Analytics requires a Pro license or higher.\nVisit https://ghosts.lk/wyrm to upgrade.` }],
|
|
110
|
-
};
|
|
111
|
-
}
|
|
112
|
-
const days = args?.days || 30;
|
|
113
|
-
const dashboard = analytics.dashboard(days);
|
|
114
|
-
let text = ` **Usage Analytics** (last ${days} days)\n\n`;
|
|
115
|
-
text += `### Overview\n`;
|
|
116
|
-
text += `- **Total Tool Calls:** ${dashboard.summary.total_calls.toLocaleString()}\n`;
|
|
117
|
-
text += `- **Unique Tools Used:** ${dashboard.summary.unique_tools}\n`;
|
|
118
|
-
text += `- **Total Tokens (In):** ${dashboard.summary.total_tokens_in.toLocaleString()}\n`;
|
|
119
|
-
text += `- **Total Tokens (Out):** ${dashboard.summary.total_tokens_out.toLocaleString()}\n`;
|
|
120
|
-
text += `- **Cache Hit Rate:** ${(dashboard.summary.cache_hit_rate * 100).toFixed(1)}%\n`;
|
|
121
|
-
text += `- **Estimated Cost:** $${dashboard.summary.estimated_cost_usd.toFixed(4)}\n\n`;
|
|
122
|
-
if (dashboard.top_tools.length > 0) {
|
|
123
|
-
text += `### Top Tools\n`;
|
|
124
|
-
for (const t of dashboard.top_tools.slice(0, 10)) {
|
|
125
|
-
text += `- **${t.tool}** — ${t.calls} calls, ${t.tokens.toLocaleString()} tokens\n`;
|
|
126
|
-
}
|
|
127
|
-
text += `\n`;
|
|
128
|
-
}
|
|
129
|
-
if (dashboard.daily.length > 0) {
|
|
130
|
-
text += `### Recent Activity\n`;
|
|
131
|
-
for (const d of dashboard.daily.slice(-7)) {
|
|
132
|
-
text += `- ${d.date}: ${d.calls} calls, ${d.tokens.toLocaleString()} tokens\n`;
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
return { content: [{ type: "text", text }] };
|
|
136
|
-
},
|
|
137
|
-
},
|
|
138
|
-
{
|
|
139
|
-
name: "wyrm_cost_report",
|
|
140
|
-
description: "View estimated API cost report for current billing period (Pro+)",
|
|
141
|
-
inputSchema: {
|
|
142
|
-
type: "object",
|
|
143
|
-
properties: {
|
|
144
|
-
period: { type: "string", description: "Period in YYYY-MM format (default: current month)" },
|
|
145
|
-
},
|
|
146
|
-
},
|
|
147
|
-
annotations: TOOL_ANNOTATIONS["wyrm_cost_report"],
|
|
148
|
-
aliases: [],
|
|
149
|
-
handler: async (args, ctx) => {
|
|
150
|
-
const { analytics } = ctx;
|
|
151
|
-
const a = args || {};
|
|
152
|
-
if (!hasFeature('analytics')) {
|
|
153
|
-
return {
|
|
154
|
-
content: [{ type: "text", text: ` Cost reports require a Pro license or higher.\nVisit https://ghosts.lk/wyrm to upgrade.` }],
|
|
155
|
-
};
|
|
156
|
-
}
|
|
157
|
-
const period = args?.period;
|
|
158
|
-
const report = analytics.costReport(period);
|
|
159
|
-
let text = ` **Cost Report** — ${report.period}\n\n`;
|
|
160
|
-
text += `- **Total Cost:** $${report.total_cost_usd.toFixed(4)}\n`;
|
|
161
|
-
text += `- **Projected Monthly:** $${report.projected_monthly_usd.toFixed(2)}\n\n`;
|
|
162
|
-
if (report.tools.length > 0) {
|
|
163
|
-
text += `### By Tool\n`;
|
|
164
|
-
for (const t of report.tools.slice(0, 10)) {
|
|
165
|
-
text += `- **${t.tool}** — ${t.calls} calls, $${t.cost_usd.toFixed(4)}\n`;
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
return { content: [{ type: "text", text }] };
|
|
169
|
-
},
|
|
170
|
-
},
|
|
171
|
-
{
|
|
172
|
-
name: "wyrm_cloud_backup",
|
|
173
|
-
description: "Backup Wyrm database to encrypted cloud storage (Pro+)",
|
|
174
|
-
inputSchema: {
|
|
175
|
-
type: "object",
|
|
176
|
-
properties: {
|
|
177
|
-
action: { type: "string", description: "Action: backup, restore, list, prune", enum: ["backup", "restore", "list", "prune"] },
|
|
178
|
-
backupKey: { type: "string", description: "Backup key for restore (from list)" },
|
|
179
|
-
keepCount: { type: "number", description: "Number of backups to keep when pruning (default: 10)" },
|
|
180
|
-
},
|
|
181
|
-
required: ["action"],
|
|
182
|
-
},
|
|
183
|
-
annotations: TOOL_ANNOTATIONS["wyrm_cloud_backup"],
|
|
184
|
-
aliases: [],
|
|
185
|
-
handler: async (args, ctx) => {
|
|
186
|
-
const { cloudBackup, db } = ctx;
|
|
187
|
-
const a = args || {};
|
|
188
|
-
if (!hasFeature('cloud_backup')) {
|
|
189
|
-
return {
|
|
190
|
-
content: [{ type: "text", text: ` Cloud backup requires a Pro license or higher.\nVisit https://ghosts.lk/wyrm to upgrade.` }],
|
|
191
|
-
};
|
|
192
|
-
}
|
|
193
|
-
const action = args?.action;
|
|
194
|
-
switch (action) {
|
|
195
|
-
case "backup": {
|
|
196
|
-
const result = await cloudBackup.backup(db.getDatabasePath());
|
|
197
|
-
const meta = result.metadata;
|
|
198
|
-
return {
|
|
199
|
-
content: [{ type: "text", text: ` ✓ Backup complete!\n\n- **Key:** ${result.key}\n- **Size:** ${(meta.db_size / 1024).toFixed(1)} KB → ${(meta.compressed_size / 1024).toFixed(1)} KB compressed\n- **Encrypted:** ${meta.encrypted ? 'Yes' : 'No'}\n- **Checksum:** ${meta.checksum.slice(0, 16)}...` }],
|
|
200
|
-
};
|
|
201
|
-
}
|
|
202
|
-
case "restore": {
|
|
203
|
-
const backupKey = args?.backupKey;
|
|
204
|
-
if (!backupKey)
|
|
205
|
-
throw new Error("backupKey required for restore");
|
|
206
|
-
const result = await cloudBackup.restore(backupKey, db.getDatabasePath());
|
|
207
|
-
return {
|
|
208
|
-
content: [{ type: "text", text: ` ✓ Restore complete!\n\n- **Restored:** ${result.restored ? 'Yes' : 'No'}\n- **Size:** ${(result.size / 1024).toFixed(1)} KB\n- **Previous DB backed up to:** ${db.getDatabasePath()}.bak\n\n⚠️ Restart Wyrm to use the restored database.` }],
|
|
209
|
-
};
|
|
210
|
-
}
|
|
211
|
-
case "list": {
|
|
212
|
-
const backups = await cloudBackup.listBackups();
|
|
213
|
-
if (backups.length === 0) {
|
|
214
|
-
return { content: [{ type: "text", text: ` No backups found.` }] };
|
|
215
|
-
}
|
|
216
|
-
let text = ` **Cloud Backups** (${backups.length} found)\n\n`;
|
|
217
|
-
for (const b of backups) {
|
|
218
|
-
text += `- **${b.timestamp}** — ${(b.db_size / 1024).toFixed(1)} KB, encrypted: ${b.encrypted}, machine: ${b.machine_id.slice(0, 8)}...\n`;
|
|
219
|
-
}
|
|
220
|
-
return { content: [{ type: "text", text }] };
|
|
221
|
-
}
|
|
222
|
-
case "prune": {
|
|
223
|
-
const keepCount = args?.keepCount || 10;
|
|
224
|
-
const result = await cloudBackup.pruneBackups(keepCount);
|
|
225
|
-
return {
|
|
226
|
-
content: [{ type: "text", text: ` ✓ Pruned ${result.deleted} old backup(s). Kept ${keepCount} most recent.` }],
|
|
227
|
-
};
|
|
228
|
-
}
|
|
229
|
-
default:
|
|
230
|
-
return { content: [{ type: "text", text: `Unknown backup action: ${action}. Use: backup, restore, list, prune` }], isError: true };
|
|
231
|
-
}
|
|
232
|
-
},
|
|
233
|
-
},
|
|
234
|
-
{
|
|
235
|
-
name: "wyrm_cloud_sync",
|
|
236
|
-
description: "Start, stop, or check the cloud-sync daemon — Phase 2 multi-device sync. Periodically backs up the DB to R2 and restores on startup if a newer snapshot exists. Last-write-wins by mtime.",
|
|
237
|
-
inputSchema: {
|
|
238
|
-
type: "object",
|
|
239
|
-
properties: {
|
|
240
|
-
action: { type: "string", description: "Action: start, stop, restart, status, force-sync", enum: ["start", "stop", "restart", "status", "force-sync"] },
|
|
241
|
-
interval_minutes: { type: "number", description: "Sync interval (default: 10)" },
|
|
242
|
-
keep_count: { type: "number", description: "Snapshots to retain after pruning (default: 20)" },
|
|
243
|
-
},
|
|
244
|
-
required: ["action"],
|
|
245
|
-
},
|
|
246
|
-
annotations: TOOL_ANNOTATIONS["wyrm_cloud_sync"],
|
|
247
|
-
aliases: [],
|
|
248
|
-
handler: async (args, ctx) => {
|
|
249
|
-
const { cloudBackup, cloudSyncManager, db, sync } = ctx;
|
|
250
|
-
const a = args || {};
|
|
251
|
-
if (!hasFeature('cloud_backup')) {
|
|
252
|
-
return {
|
|
253
|
-
content: [{ type: "text", text: ` Cloud sync requires a Pro license or higher.\nVisit https://ghosts.lk/wyrm to upgrade.` }],
|
|
254
|
-
};
|
|
255
|
-
}
|
|
256
|
-
const action = args?.action;
|
|
257
|
-
const interval_minutes = args?.interval_minutes;
|
|
258
|
-
const keep_count = args?.keep_count;
|
|
259
|
-
switch (action) {
|
|
260
|
-
case "start": {
|
|
261
|
-
const r = cloudSyncManager.start({ interval_minutes, keep_count });
|
|
262
|
-
if (!r.ok) {
|
|
263
|
-
return { content: [{ type: "text", text: ` cloud-sync: ${r.reason ?? 'failed to start'}${r.pid ? ` (pid ${r.pid})` : ''}` }], isError: !r.pid };
|
|
264
|
-
}
|
|
265
|
-
return { content: [{ type: "text", text: ` ✓ cloud-sync daemon started (pid ${r.pid}). Logs: ~/.wyrm/wyrm-cloud-sync.log` }] };
|
|
266
|
-
}
|
|
267
|
-
case "stop": {
|
|
268
|
-
const r = cloudSyncManager.stop();
|
|
269
|
-
return {
|
|
270
|
-
content: [{ type: "text", text: r.ok
|
|
271
|
-
? ` ✓ cloud-sync daemon stopped`
|
|
272
|
-
: ` cloud-sync: ${r.reason ?? 'failed to stop'}` }],
|
|
273
|
-
isError: !r.ok,
|
|
274
|
-
};
|
|
275
|
-
}
|
|
276
|
-
case "restart": {
|
|
277
|
-
cloudSyncManager.stop();
|
|
278
|
-
// Brief grace period for the daemon's final tick before re-spawning
|
|
279
|
-
await new Promise((res) => { setTimeout(res, 500); });
|
|
280
|
-
const r = cloudSyncManager.start({ interval_minutes, keep_count });
|
|
281
|
-
return {
|
|
282
|
-
content: [{ type: "text", text: r.ok
|
|
283
|
-
? ` ✓ cloud-sync daemon restarted (pid ${r.pid})`
|
|
284
|
-
: ` cloud-sync restart failed: ${r.reason ?? 'unknown'}` }],
|
|
285
|
-
isError: !r.ok,
|
|
286
|
-
};
|
|
287
|
-
}
|
|
288
|
-
case "status": {
|
|
289
|
-
const s = cloudSyncManager.status();
|
|
290
|
-
const lines = [` **Cloud Sync Status**`];
|
|
291
|
-
lines.push(`- Running: ${s.running ? '✓ yes' : '✗ no'}`);
|
|
292
|
-
if (s.pid)
|
|
293
|
-
lines.push(`- PID: ${s.pid}`);
|
|
294
|
-
if (s.state) {
|
|
295
|
-
if (s.state.last_uploaded_ts) {
|
|
296
|
-
lines.push(`- Last upload: ${new Date(s.state.last_uploaded_ts).toISOString()}${s.state.last_uploaded_key ? ` (${s.state.last_uploaded_key})` : ''}`);
|
|
297
|
-
}
|
|
298
|
-
if (s.state.last_restored_key)
|
|
299
|
-
lines.push(`- Last restore: ${s.state.last_restored_key}`);
|
|
300
|
-
if (s.state.last_check_ts)
|
|
301
|
-
lines.push(`- Last check: ${new Date(s.state.last_check_ts).toISOString()}`);
|
|
302
|
-
lines.push(`- Machine: ${s.state.machine}`);
|
|
303
|
-
}
|
|
304
|
-
return { content: [{ type: "text", text: lines.join('\n') }] };
|
|
305
|
-
}
|
|
306
|
-
case "force-sync": {
|
|
307
|
-
// One-shot tick without the long-running daemon. Uses the in-process
|
|
308
|
-
// cloudBackup client, so works even when the daemon is stopped.
|
|
309
|
-
const daemon = new CloudSyncDaemon(cloudBackup, db.getDatabasePath());
|
|
310
|
-
const result = await daemon.tick();
|
|
311
|
-
return { content: [{ type: "text", text: ` force-sync: ${JSON.stringify(result, null, 2)}` }] };
|
|
312
|
-
}
|
|
313
|
-
default:
|
|
314
|
-
return { content: [{ type: "text", text: `Unknown cloud-sync action: ${action}. Use: start, stop, restart, status, force-sync` }], isError: true };
|
|
315
|
-
}
|
|
316
|
-
},
|
|
317
|
-
},
|
|
318
|
-
{
|
|
319
|
-
name: "wyrm_encrypt_setup",
|
|
320
|
-
description: "Set up or check encryption status for sensitive data (Pro+)",
|
|
321
|
-
inputSchema: {
|
|
322
|
-
type: "object",
|
|
323
|
-
properties: {
|
|
324
|
-
action: { type: "string", description: "Action: status, enable, test", enum: ["status", "enable", "test"] },
|
|
325
|
-
password: { type: "string", description: "Encryption password (min 8 chars, required for enable)" },
|
|
326
|
-
},
|
|
327
|
-
required: ["action"],
|
|
328
|
-
},
|
|
329
|
-
annotations: TOOL_ANNOTATIONS["wyrm_encrypt_setup"],
|
|
330
|
-
aliases: [],
|
|
331
|
-
handler: async (args, ctx) => {
|
|
332
|
-
const a = args || {};
|
|
333
|
-
if (!hasFeature('encryption')) {
|
|
334
|
-
return {
|
|
335
|
-
content: [{ type: "text", text: ` Encryption setup requires a Pro license or higher.\nVisit https://ghosts.lk/wyrm to upgrade.` }],
|
|
336
|
-
};
|
|
337
|
-
}
|
|
338
|
-
const encAction = args?.action;
|
|
339
|
-
const cryptoInstance = getCrypto();
|
|
340
|
-
switch (encAction) {
|
|
341
|
-
case "status": {
|
|
342
|
-
const enabled = cryptoInstance.isEnabled();
|
|
343
|
-
let text = ` **Encryption Status**\n\n`;
|
|
344
|
-
text += `- **Enabled:** ${enabled ? '✓ Yes' : '✗ No'}\n`;
|
|
345
|
-
text += `- **Algorithm:** AES-256-GCM\n`;
|
|
346
|
-
if (enabled) {
|
|
347
|
-
text += `- **Status:** Active — new data is encrypted at rest\n`;
|
|
348
|
-
}
|
|
349
|
-
else {
|
|
350
|
-
text += `\nTo enable, run: \`wyrm_encrypt_setup\` with action "enable" and a strong password.\n`;
|
|
351
|
-
}
|
|
352
|
-
return { content: [{ type: "text", text }] };
|
|
353
|
-
}
|
|
354
|
-
case "enable": {
|
|
355
|
-
const password = args?.password;
|
|
356
|
-
if (!password || password.length < 8) {
|
|
357
|
-
return { content: [{ type: "text", text: ` Password must be at least 8 characters.` }], isError: true };
|
|
358
|
-
}
|
|
359
|
-
initializeCrypto(password);
|
|
360
|
-
return {
|
|
361
|
-
content: [{ type: "text", text: ` ✓ Encryption enabled!\n\n- **Algorithm:** AES-256-GCM\n- **Key derived from:** your password (PBKDF2)\n\n⚠️ **Store your password safely.** Lost passwords cannot be recovered.\nNew data lake entries will be encrypted at rest.` }],
|
|
362
|
-
};
|
|
363
|
-
}
|
|
364
|
-
case "test": {
|
|
365
|
-
if (!cryptoInstance.isEnabled()) {
|
|
366
|
-
return { content: [{ type: "text", text: ` Encryption not enabled. Run with action "enable" first.` }] };
|
|
367
|
-
}
|
|
368
|
-
const testData = "Wyrm encryption test " + Date.now();
|
|
369
|
-
const encrypted = cryptoInstance.encrypt(testData);
|
|
370
|
-
const decrypted = cryptoInstance.decrypt(encrypted);
|
|
371
|
-
const ok = decrypted === testData;
|
|
372
|
-
return {
|
|
373
|
-
content: [{ type: "text", text: ` Encryption test: ${ok ? '✓ PASSED' : '✗ FAILED'}\n- Encrypted ${testData.length} chars → decrypted back to ${decrypted.length} chars` }],
|
|
374
|
-
};
|
|
375
|
-
}
|
|
376
|
-
default:
|
|
377
|
-
return { content: [{ type: "text", text: `Unknown encrypt action: ${encAction}. Use: status, enable, test` }], isError: true };
|
|
378
|
-
}
|
|
379
|
-
},
|
|
380
|
-
},
|
|
381
|
-
];
|
|
382
|
-
//# sourceMappingURL=cloud.js.map
|
|
1
|
+
import{TOOL_ANNOTATIONS as u}from"../tool-annotations.js";import{CloudSyncDaemon as m}from"../cloud-sync.js";import{getCrypto as h,initializeCrypto as k}from"../crypto.js";import{activateLicense as f,getLicenseInfo as b,getTier as x,hasFeature as d}from"../license.js";const S=[{name:"wyrm_license",description:"View current license status, tier, and available features",inputSchema:{type:"object",properties:{}},annotations:u.wyrm_license,aliases:[],handler:async(o,i)=>{const{cachedResponse:a,sync:r}=i,c=o||{},n=b(),e=x();let t=`\u{F115D} **Wyrm License Status**
|
|
2
|
+
|
|
3
|
+
`;if(t+=`- **Tier:** ${e.charAt(0).toUpperCase()+e.slice(1)}
|
|
4
|
+
`,n.valid&&n.key){t+=`- **Key:** ${n.key}
|
|
5
|
+
`,t+=`- **Issued To:** ${n.issuedTo||"Unknown"}
|
|
6
|
+
`,t+=`- **Expires:** ${n.expiresAt?new Date(n.expiresAt).toLocaleDateString():"Never"}
|
|
7
|
+
`,t+=`- **Status:** \u2713 Valid
|
|
8
|
+
|
|
9
|
+
`,t+=`### Features
|
|
10
|
+
`;for(const l of n.features)t+=`- \u2713 ${l}
|
|
11
|
+
`}else t+=`- **Status:** Free tier (no license key)
|
|
12
|
+
|
|
13
|
+
`,t+=`### Free Features
|
|
14
|
+
`,t+=`- \u2713 Local SQLite storage
|
|
15
|
+
`,t+=`- \u2713 32 MCP tools
|
|
16
|
+
`,t+=`- \u2713 FTS5 search
|
|
17
|
+
`,t+=`- \u2713 File-based sync
|
|
18
|
+
|
|
19
|
+
`,t+=`### Upgrade to Pro
|
|
20
|
+
`,t+=`- Analytics dashboard & cost tracking
|
|
21
|
+
`,t+=`- Cloud backup to R2
|
|
22
|
+
`,t+=`- Encryption at rest
|
|
23
|
+
`,t+=`- Priority support
|
|
24
|
+
|
|
25
|
+
`,t+=`### Already have a license?
|
|
26
|
+
`,t+="Activate it \u2014 paste the license JSON into the `wyrm_activate` tool, or save it to `~/.wyrm/license.json` and restart Wyrm.\n",t+="Manage or download your license at https://account.ghosts.lk \xB7 buy one at https://ghosts.lk/wyrm.";return a(t)}},{name:"wyrm_activate",description:"Activate a license key to unlock Pro/Team/Enterprise features",inputSchema:{type:"object",properties:{license:{type:"string",description:"License JSON string (signed license from Ghost Protocol)"}},required:["license"]},annotations:u.wyrm_activate,aliases:[],handler:async(o,i)=>{const a=o?.license;if(!a)throw new Error("License JSON string required");try{const r=f(a);return r.valid?{content:[{type:"text",text:`\u{F115D} \u2713 License activated!
|
|
27
|
+
|
|
28
|
+
- **Tier:** ${r.tier}
|
|
29
|
+
- **Features:** ${r.features.join(", ")}
|
|
30
|
+
|
|
31
|
+
Restart Wyrm to apply all features.`}]}:{content:[{type:"text",text:`\u{F115D} \u2717 License activation failed: ${r.error||"unknown error"}`}],isError:!0}}catch{return{content:[{type:"text",text:"\u{F115D} \u2717 Invalid license format. Please verify your license key."}],isError:!0}}}},{name:"wyrm_analytics_dashboard",description:"View usage analytics dashboard \u2014 tool calls, tokens, costs, cache efficiency (Pro+)",inputSchema:{type:"object",properties:{days:{type:"number",description:"Number of days to analyze (default: 30)"}}},annotations:u.wyrm_analytics_dashboard,aliases:[],handler:async(o,i)=>{const{analytics:a}=i,r=o||{};if(!d("analytics"))return{content:[{type:"text",text:`\u{F115D} Analytics requires a Pro license or higher.
|
|
32
|
+
Visit https://ghosts.lk/wyrm to upgrade.`}]};const c=o?.days||30,n=a.dashboard(c);let e=`\u{F115D} **Usage Analytics** (last ${c} days)
|
|
33
|
+
|
|
34
|
+
`;if(e+=`### Overview
|
|
35
|
+
`,e+=`- **Total Tool Calls:** ${n.summary.total_calls.toLocaleString()}
|
|
36
|
+
`,e+=`- **Unique Tools Used:** ${n.summary.unique_tools}
|
|
37
|
+
`,e+=`- **Total Tokens (In):** ${n.summary.total_tokens_in.toLocaleString()}
|
|
38
|
+
`,e+=`- **Total Tokens (Out):** ${n.summary.total_tokens_out.toLocaleString()}
|
|
39
|
+
`,e+=`- **Cache Hit Rate:** ${(n.summary.cache_hit_rate*100).toFixed(1)}%
|
|
40
|
+
`,e+=`- **Estimated Cost:** $${n.summary.estimated_cost_usd.toFixed(4)}
|
|
41
|
+
|
|
42
|
+
`,n.top_tools.length>0){e+=`### Top Tools
|
|
43
|
+
`;for(const t of n.top_tools.slice(0,10))e+=`- **${t.tool}** \u2014 ${t.calls} calls, ${t.tokens.toLocaleString()} tokens
|
|
44
|
+
`;e+=`
|
|
45
|
+
`}if(n.daily.length>0){e+=`### Recent Activity
|
|
46
|
+
`;for(const t of n.daily.slice(-7))e+=`- ${t.date}: ${t.calls} calls, ${t.tokens.toLocaleString()} tokens
|
|
47
|
+
`}return{content:[{type:"text",text:e}]}}},{name:"wyrm_cost_report",description:"View estimated API cost report for current billing period (Pro+)",inputSchema:{type:"object",properties:{period:{type:"string",description:"Period in YYYY-MM format (default: current month)"}}},annotations:u.wyrm_cost_report,aliases:[],handler:async(o,i)=>{const{analytics:a}=i,r=o||{};if(!d("analytics"))return{content:[{type:"text",text:`\u{F115D} Cost reports require a Pro license or higher.
|
|
48
|
+
Visit https://ghosts.lk/wyrm to upgrade.`}]};const c=o?.period,n=a.costReport(c);let e=`\u{F115D} **Cost Report** \u2014 ${n.period}
|
|
49
|
+
|
|
50
|
+
`;if(e+=`- **Total Cost:** $${n.total_cost_usd.toFixed(4)}
|
|
51
|
+
`,e+=`- **Projected Monthly:** $${n.projected_monthly_usd.toFixed(2)}
|
|
52
|
+
|
|
53
|
+
`,n.tools.length>0){e+=`### By Tool
|
|
54
|
+
`;for(const t of n.tools.slice(0,10))e+=`- **${t.tool}** \u2014 ${t.calls} calls, $${t.cost_usd.toFixed(4)}
|
|
55
|
+
`}return{content:[{type:"text",text:e}]}}},{name:"wyrm_cloud_backup",description:"Backup Wyrm database to encrypted cloud storage (Pro+)",inputSchema:{type:"object",properties:{action:{type:"string",description:"Action: backup, restore, list, prune",enum:["backup","restore","list","prune"]},backupKey:{type:"string",description:"Backup key for restore (from list)"},keepCount:{type:"number",description:"Number of backups to keep when pruning (default: 10)"}},required:["action"]},annotations:u.wyrm_cloud_backup,aliases:[],handler:async(o,i)=>{const{cloudBackup:a,db:r}=i,c=o||{};if(!d("cloud_backup"))return{content:[{type:"text",text:`\u{F115D} Cloud backup requires a Pro license or higher.
|
|
56
|
+
Visit https://ghosts.lk/wyrm to upgrade.`}]};const n=o?.action;switch(n){case"backup":{const e=await a.backup(r.getDatabasePath()),t=e.metadata;return{content:[{type:"text",text:`\u{F115D} \u2713 Backup complete!
|
|
57
|
+
|
|
58
|
+
- **Key:** ${e.key}
|
|
59
|
+
- **Size:** ${(t.db_size/1024).toFixed(1)} KB \u2192 ${(t.compressed_size/1024).toFixed(1)} KB compressed
|
|
60
|
+
- **Encrypted:** ${t.encrypted?"Yes":"No"}
|
|
61
|
+
- **Checksum:** ${t.checksum.slice(0,16)}...`}]}}case"restore":{const e=o?.backupKey;if(!e)throw new Error("backupKey required for restore");const t=await a.restore(e,r.getDatabasePath());return{content:[{type:"text",text:`\u{F115D} \u2713 Restore complete!
|
|
62
|
+
|
|
63
|
+
- **Restored:** ${t.restored?"Yes":"No"}
|
|
64
|
+
- **Size:** ${(t.size/1024).toFixed(1)} KB
|
|
65
|
+
- **Previous DB backed up to:** ${r.getDatabasePath()}.bak
|
|
66
|
+
|
|
67
|
+
\u26A0\uFE0F Restart Wyrm to use the restored database.`}]}}case"list":{const e=await a.listBackups();if(e.length===0)return{content:[{type:"text",text:"\u{F115D} No backups found."}]};let t=`\u{F115D} **Cloud Backups** (${e.length} found)
|
|
68
|
+
|
|
69
|
+
`;for(const l of e)t+=`- **${l.timestamp}** \u2014 ${(l.db_size/1024).toFixed(1)} KB, encrypted: ${l.encrypted}, machine: ${l.machine_id.slice(0,8)}...
|
|
70
|
+
`;return{content:[{type:"text",text:t}]}}case"prune":{const e=o?.keepCount||10;return{content:[{type:"text",text:`\u{F115D} \u2713 Pruned ${(await a.pruneBackups(e)).deleted} old backup(s). Kept ${e} most recent.`}]}}default:return{content:[{type:"text",text:`Unknown backup action: ${n}. Use: backup, restore, list, prune`}],isError:!0}}}},{name:"wyrm_cloud_sync",description:"Start, stop, or check the cloud-sync daemon \u2014 Phase 2 multi-device sync. Periodically backs up the DB to R2 and restores on startup if a newer snapshot exists. Last-write-wins by mtime.",inputSchema:{type:"object",properties:{action:{type:"string",description:"Action: start, stop, restart, status, force-sync",enum:["start","stop","restart","status","force-sync"]},interval_minutes:{type:"number",description:"Sync interval (default: 10)"},keep_count:{type:"number",description:"Snapshots to retain after pruning (default: 20)"}},required:["action"]},annotations:u.wyrm_cloud_sync,aliases:[],handler:async(o,i)=>{const{cloudBackup:a,cloudSyncManager:r,db:c,sync:n}=i,e=o||{};if(!d("cloud_backup"))return{content:[{type:"text",text:`\u{F115D} Cloud sync requires a Pro license or higher.
|
|
71
|
+
Visit https://ghosts.lk/wyrm to upgrade.`}]};const t=o?.action,l=o?.interval_minutes,y=o?.keep_count;switch(t){case"start":{const s=r.start({interval_minutes:l,keep_count:y});return s.ok?{content:[{type:"text",text:`\u{F115D} \u2713 cloud-sync daemon started (pid ${s.pid}). Logs: ~/.wyrm/wyrm-cloud-sync.log`}]}:{content:[{type:"text",text:`\u{F115D} cloud-sync: ${s.reason??"failed to start"}${s.pid?` (pid ${s.pid})`:""}`}],isError:!s.pid}}case"stop":{const s=r.stop();return{content:[{type:"text",text:s.ok?"\u{F115D} \u2713 cloud-sync daemon stopped":`\u{F115D} cloud-sync: ${s.reason??"failed to stop"}`}],isError:!s.ok}}case"restart":{r.stop(),await new Promise(p=>{setTimeout(p,500)});const s=r.start({interval_minutes:l,keep_count:y});return{content:[{type:"text",text:s.ok?`\u{F115D} \u2713 cloud-sync daemon restarted (pid ${s.pid})`:`\u{F115D} cloud-sync restart failed: ${s.reason??"unknown"}`}],isError:!s.ok}}case"status":{const s=r.status(),p=["\u{F115D} **Cloud Sync Status**"];return p.push(`- Running: ${s.running?"\u2713 yes":"\u2717 no"}`),s.pid&&p.push(`- PID: ${s.pid}`),s.state&&(s.state.last_uploaded_ts&&p.push(`- Last upload: ${new Date(s.state.last_uploaded_ts).toISOString()}${s.state.last_uploaded_key?` (${s.state.last_uploaded_key})`:""}`),s.state.last_restored_key&&p.push(`- Last restore: ${s.state.last_restored_key}`),s.state.last_check_ts&&p.push(`- Last check: ${new Date(s.state.last_check_ts).toISOString()}`),p.push(`- Machine: ${s.state.machine}`)),{content:[{type:"text",text:p.join(`
|
|
72
|
+
`)}]}}case"force-sync":{const p=await new m(a,c.getDatabasePath()).tick();return{content:[{type:"text",text:`\u{F115D} force-sync: ${JSON.stringify(p,null,2)}`}]}}default:return{content:[{type:"text",text:`Unknown cloud-sync action: ${t}. Use: start, stop, restart, status, force-sync`}],isError:!0}}}},{name:"wyrm_encrypt_setup",description:"Set up or check encryption status for sensitive data (Pro+)",inputSchema:{type:"object",properties:{action:{type:"string",description:"Action: status, enable, test",enum:["status","enable","test"]},password:{type:"string",description:"Encryption password (min 8 chars, required for enable)"}},required:["action"]},annotations:u.wyrm_encrypt_setup,aliases:[],handler:async(o,i)=>{const a=o||{};if(!d("encryption"))return{content:[{type:"text",text:`\u{F115D} Encryption setup requires a Pro license or higher.
|
|
73
|
+
Visit https://ghosts.lk/wyrm to upgrade.`}]};const r=o?.action,c=h();switch(r){case"status":{const n=c.isEnabled();let e=`\u{F115D} **Encryption Status**
|
|
74
|
+
|
|
75
|
+
`;return e+=`- **Enabled:** ${n?"\u2713 Yes":"\u2717 No"}
|
|
76
|
+
`,e+=`- **Algorithm:** AES-256-GCM
|
|
77
|
+
`,n?e+=`- **Status:** Active \u2014 new data is encrypted at rest
|
|
78
|
+
`:e+='\nTo enable, run: `wyrm_encrypt_setup` with action "enable" and a strong password.\n',{content:[{type:"text",text:e}]}}case"enable":{const n=o?.password;return!n||n.length<8?{content:[{type:"text",text:"\u{F115D} Password must be at least 8 characters."}],isError:!0}:(k(n),{content:[{type:"text",text:`\u{F115D} \u2713 Encryption enabled!
|
|
79
|
+
|
|
80
|
+
- **Algorithm:** AES-256-GCM
|
|
81
|
+
- **Key derived from:** your password (PBKDF2)
|
|
82
|
+
|
|
83
|
+
\u26A0\uFE0F **Store your password safely.** Lost passwords cannot be recovered.
|
|
84
|
+
New data lake entries will be encrypted at rest.`}]})}case"test":{if(!c.isEnabled())return{content:[{type:"text",text:'\u{F115D} Encryption not enabled. Run with action "enable" first.'}]};const n="Wyrm encryption test "+Date.now(),e=c.encrypt(n),t=c.decrypt(e);return{content:[{type:"text",text:`\u{F115D} Encryption test: ${t===n?"\u2713 PASSED":"\u2717 FAILED"}
|
|
85
|
+
- Encrypted ${n.length} chars \u2192 decrypted back to ${t.length} chars`}]}}default:return{content:[{type:"text",text:`Unknown encrypt action: ${r}. Use: status, enable, test`}],isError:!0}}}}];export{S as cloudToolSpecs};
|