wyrm-mcp 7.2.1 → 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.
Files changed (150) hide show
  1. package/LICENSE +26 -667
  2. package/NOTICE +14 -33
  3. package/dist/activation.js +1 -60
  4. package/dist/agent-daemon.js +4 -281
  5. package/dist/agent-loop.js +7 -332
  6. package/dist/analytics.js +13 -236
  7. package/dist/attribution.js +1 -49
  8. package/dist/audit.js +2 -457
  9. package/dist/auto-capture.js +3 -138
  10. package/dist/auto-orchestrator.js +1 -325
  11. package/dist/autoconfig.js +39 -840
  12. package/dist/buddy-runner.js +1 -109
  13. package/dist/buddy.js +14 -564
  14. package/dist/build-flags.js +1 -17
  15. package/dist/capabilities.js +3 -183
  16. package/dist/capture.js +1 -56
  17. package/dist/causality.js +6 -107
  18. package/dist/cli.js +20 -281
  19. package/dist/cloud/cli.js +5 -541
  20. package/dist/cloud/client.js +1 -221
  21. package/dist/cloud/crypto.js +1 -85
  22. package/dist/cloud/machine-id.js +2 -113
  23. package/dist/cloud/recovery.js +1 -60
  24. package/dist/cloud/sync-engine.js +7 -543
  25. package/dist/cloud-backup.js +5 -579
  26. package/dist/cloud-profile.js +1 -138
  27. package/dist/cloud-sync-entrypoint.js +1 -47
  28. package/dist/cloud-sync.js +2 -309
  29. package/dist/constellation.js +12 -168
  30. package/dist/context-build-budgeted.js +4 -144
  31. package/dist/context-ranking.js +1 -69
  32. package/dist/crypto.js +1 -179
  33. package/dist/daemon-write-endpoint.js +1 -290
  34. package/dist/daemon-writer.js +2 -406
  35. package/dist/database.js +43 -1110
  36. package/dist/deprecations.js +2 -162
  37. package/dist/design.js +13 -141
  38. package/dist/event-replication.js +1 -112
  39. package/dist/events-sse.js +7 -43
  40. package/dist/events.js +6 -238
  41. package/dist/failure-patterns.js +42 -659
  42. package/dist/federation.js +12 -236
  43. package/dist/goals.js +13 -101
  44. package/dist/golden.js +3 -355
  45. package/dist/handlers/agent.js +4 -165
  46. package/dist/handlers/alias-adapters.js +1 -129
  47. package/dist/handlers/aliases.js +1 -171
  48. package/dist/handlers/audit.js +1 -87
  49. package/dist/handlers/boundary.js +1 -221
  50. package/dist/handlers/capture.js +73 -1109
  51. package/dist/handlers/causality.js +7 -114
  52. package/dist/handlers/cloud.js +85 -382
  53. package/dist/handlers/companion.js +28 -459
  54. package/dist/handlers/datalake.js +7 -187
  55. package/dist/handlers/dispatch-context.js +0 -22
  56. package/dist/handlers/entity.js +25 -256
  57. package/dist/handlers/events.js +16 -335
  58. package/dist/handlers/failure.js +13 -340
  59. package/dist/handlers/goals.js +4 -296
  60. package/dist/handlers/intelligence.js +126 -674
  61. package/dist/handlers/invoicing.js +1 -70
  62. package/dist/handlers/mcpclient.js +6 -137
  63. package/dist/handlers/orchestration.js +40 -125
  64. package/dist/handlers/output-schemas.js +1 -24
  65. package/dist/handlers/presence.js +3 -99
  66. package/dist/handlers/project.js +28 -182
  67. package/dist/handlers/prompts.js +6 -157
  68. package/dist/handlers/quest.js +4 -224
  69. package/dist/handlers/recall.js +11 -218
  70. package/dist/handlers/registry.js +1 -167
  71. package/dist/handlers/resources.js +1 -288
  72. package/dist/handlers/review.js +11 -74
  73. package/dist/handlers/run.js +17 -487
  74. package/dist/handlers/search.js +15 -326
  75. package/dist/handlers/session.js +28 -615
  76. package/dist/handlers/share.js +8 -184
  77. package/dist/handlers/shims.js +1 -464
  78. package/dist/handlers/skill.js +67 -449
  79. package/dist/handlers/survivors.js +1 -120
  80. package/dist/handlers/symbols.js +8 -109
  81. package/dist/handlers/syncops.js +4 -302
  82. package/dist/handlers/types.js +1 -27
  83. package/dist/harvest.js +5 -191
  84. package/dist/hours.js +7 -156
  85. package/dist/http-auth.js +3 -321
  86. package/dist/http-fast.js +21 -1137
  87. package/dist/icons.js +1 -47
  88. package/dist/index.js +2 -924
  89. package/dist/indexer.js +4 -145
  90. package/dist/intelligence.js +31 -261
  91. package/dist/internal-dispatch.js +3 -212
  92. package/dist/keyset.js +1 -110
  93. package/dist/knowledge-graph.js +12 -176
  94. package/dist/license.js +2 -441
  95. package/dist/logger.js +2 -199
  96. package/dist/maintenance.js +2 -148
  97. package/dist/mcp-client.js +6 -262
  98. package/dist/memory-artifacts.js +30 -449
  99. package/dist/migrate-prompt.js +2 -124
  100. package/dist/migrations.js +40 -655
  101. package/dist/performance.js +1 -228
  102. package/dist/presence.js +11 -140
  103. package/dist/priority-embed.js +5 -164
  104. package/dist/providers/embedding-provider.js +1 -196
  105. package/dist/readonly-gate.js +1 -29
  106. package/dist/rehydration.js +9 -157
  107. package/dist/reindex.js +1 -88
  108. package/dist/render-target.js +21 -514
  109. package/dist/render.js +4 -280
  110. package/dist/repl-guard.js +1 -173
  111. package/dist/replication-daemon-entrypoint.js +1 -31
  112. package/dist/replication-daemon.js +2 -262
  113. package/dist/resilience.js +1 -591
  114. package/dist/reverse-bridge.js +5 -360
  115. package/dist/security.js +1 -244
  116. package/dist/session-seen.js +3 -51
  117. package/dist/setup.js +1 -260
  118. package/dist/skill-author.js +5 -168
  119. package/dist/spec-kit.js +1 -191
  120. package/dist/sqlite-busy.js +1 -154
  121. package/dist/statusline.js +11 -315
  122. package/dist/sub-agent.js +13 -262
  123. package/dist/summarizer.js +13 -139
  124. package/dist/symbols.js +7 -283
  125. package/dist/sync.js +5 -359
  126. package/dist/tasks-dispatch.js +1 -84
  127. package/dist/tasks.js +1 -282
  128. package/dist/token-budget.js +1 -143
  129. package/dist/tool-analytics.js +7 -129
  130. package/dist/tool-annotations.js +1 -365
  131. package/dist/tool-manifest-v2.json +1 -1
  132. package/dist/tool-manifest.json +1 -1
  133. package/dist/tool-profiles.js +1 -75
  134. package/dist/trace-harvest.js +6 -244
  135. package/dist/types.js +1 -30
  136. package/dist/ui-dashboard.js +41 -50
  137. package/dist/ulid.js +1 -81
  138. package/dist/validate.js +1 -129
  139. package/dist/vault.js +1 -534
  140. package/dist/vectors.js +3 -184
  141. package/dist/version-check.js +4 -136
  142. package/dist/visibility.js +19 -155
  143. package/dist/wyrm-cli.js +98 -2464
  144. package/dist/wyrm-guard.js +14 -424
  145. package/dist/wyrm-loop.js +3 -150
  146. package/dist/wyrm-manifest.json +1 -1
  147. package/dist/wyrm-statusline-daemon.js +1 -11
  148. package/dist/wyrm-statusline.js +4 -56
  149. package/dist/wyrm-ui.js +9 -77
  150. package/package.json +4 -2
@@ -1,114 +1,7 @@
1
- /**
2
- * @copyright 2026 Ghost Protocol (Pvt) Ltd.
3
- * @license AGPL-3.0-or-later
4
- */
5
- import { TOOL_ANNOTATIONS } from "../tool-annotations.js";
6
- export const causalityToolSpecs = [
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};
@@ -1,382 +1,85 @@
1
- /**
2
- * @copyright 2026 Ghost Protocol (Pvt) Ltd.
3
- * @license AGPL-3.0-or-later
4
- */
5
- import { TOOL_ANNOTATIONS } from "../tool-annotations.js";
6
- import { CloudSyncDaemon } from "../cloud-sync.js";
7
- import { getCrypto, initializeCrypto } from "../crypto.js";
8
- import { activateLicense, getLicenseInfo, getTier, hasFeature } from "../license.js";
9
- export const cloudToolSpecs = [
10
- {
11
- name: "wyrm_license",
12
- description: "View current license status, tier, and available features",
13
- inputSchema: {
14
- type: "object",
15
- properties: {},
16
- },
17
- annotations: TOOL_ANNOTATIONS["wyrm_license"],
18
- aliases: [],
19
- handler: async (args, ctx) => {
20
- const { cachedResponse, sync } = ctx;
21
- const a = args || {};
22
- const license = getLicenseInfo();
23
- const tier = getTier();
24
- let text = `󱅝 **Wyrm License Status**\n\n`;
25
- text += `- **Tier:** ${tier.charAt(0).toUpperCase() + tier.slice(1)}\n`;
26
- if (license.valid && license.key) {
27
- text += `- **Key:** ${license.key}\n`;
28
- text += `- **Issued To:** ${license.issuedTo || 'Unknown'}\n`;
29
- text += `- **Expires:** ${license.expiresAt ? new Date(license.expiresAt).toLocaleDateString() : 'Never'}\n`;
30
- text += `- **Status:** ✓ Valid\n\n`;
31
- text += `### Features\n`;
32
- for (const f of license.features) {
33
- text += `- ✓ ${f}\n`;
34
- }
35
- }
36
- else {
37
- text += `- **Status:** Free tier (no license key)\n\n`;
38
- text += `### Free Features\n`;
39
- text += `- Local SQLite storage\n`;
40
- text += `- ✓ 32 MCP tools\n`;
41
- text += `- ✓ FTS5 search\n`;
42
- text += `- ✓ File-based sync\n\n`;
43
- text += `### Upgrade to Pro\n`;
44
- text += `- Analytics dashboard & cost tracking\n`;
45
- text += `- Cloud backup to R2\n`;
46
- text += `- Encryption at rest\n`;
47
- text += `- Priority support\n\n`;
48
- text += `### Already have a license?\n`;
49
- text += `Activate it — paste the license JSON into the \`wyrm_activate\` tool, or save it to \`~/.wyrm/license.json\` and restart Wyrm.\n`;
50
- text += `Manage or download your license at https://account.ghosts.lk · buy one at https://ghosts.lk/wyrm.`;
51
- }
52
- return cachedResponse(text);
53
- },
54
- },
55
- {
56
- name: "wyrm_activate",
57
- description: "Activate a license key to unlock Pro/Team/Enterprise features",
58
- inputSchema: {
59
- type: "object",
60
- properties: {
61
- license: { type: "string", description: "License JSON string (signed license from Ghost Protocol)" },
62
- },
63
- required: ["license"],
64
- },
65
- annotations: TOOL_ANNOTATIONS["wyrm_activate"],
66
- aliases: [],
67
- handler: async (args, ctx) => {
68
- const licenseStr = args?.license;
69
- if (!licenseStr)
70
- throw new Error("License JSON string required");
71
- try {
72
- const result = activateLicense(licenseStr);
73
- if (result.valid) {
74
- return {
75
- content: [{ type: "text", text: `󱅝 ✓ License activated!\n\n- **Tier:** ${result.tier}\n- **Features:** ${result.features.join(', ')}\n\nRestart Wyrm to apply all features.` }],
76
- };
77
- }
78
- else {
79
- return {
80
- content: [{ type: "text", text: `󱅝 ✗ License activation failed: ${result.error || 'unknown error'}` }],
81
- isError: true,
82
- };
83
- }
84
- }
85
- catch (e) {
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};