youmd 0.6.21 → 0.6.27
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/commands/build.d.ts.map +1 -1
- package/dist/commands/build.js +0 -1
- package/dist/commands/build.js.map +1 -1
- package/dist/commands/chat.d.ts.map +1 -1
- package/dist/commands/chat.js +283 -184
- package/dist/commands/chat.js.map +1 -1
- package/dist/commands/export.d.ts +1 -0
- package/dist/commands/export.d.ts.map +1 -1
- package/dist/commands/export.js +5 -0
- package/dist/commands/export.js.map +1 -1
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +21 -1
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/keys.d.ts.map +1 -1
- package/dist/commands/keys.js +3 -3
- package/dist/commands/keys.js.map +1 -1
- package/dist/commands/link.d.ts.map +1 -1
- package/dist/commands/link.js +3 -3
- package/dist/commands/link.js.map +1 -1
- package/dist/commands/login.d.ts +29 -0
- package/dist/commands/login.d.ts.map +1 -1
- package/dist/commands/login.js +256 -127
- package/dist/commands/login.js.map +1 -1
- package/dist/commands/logs.js +0 -1
- package/dist/commands/logs.js.map +1 -1
- package/dist/commands/mcp.d.ts +14 -0
- package/dist/commands/mcp.d.ts.map +1 -1
- package/dist/commands/mcp.js +284 -28
- package/dist/commands/mcp.js.map +1 -1
- package/dist/commands/okf.d.ts +12 -0
- package/dist/commands/okf.d.ts.map +1 -0
- package/dist/commands/okf.js +411 -0
- package/dist/commands/okf.js.map +1 -0
- package/dist/commands/private.d.ts.map +1 -1
- package/dist/commands/private.js +6 -5
- package/dist/commands/private.js.map +1 -1
- package/dist/commands/project.d.ts.map +1 -1
- package/dist/commands/project.js +9 -5
- package/dist/commands/project.js.map +1 -1
- package/dist/commands/publish.d.ts.map +1 -1
- package/dist/commands/publish.js +0 -1
- package/dist/commands/publish.js.map +1 -1
- package/dist/commands/pull.d.ts +24 -1
- package/dist/commands/pull.d.ts.map +1 -1
- package/dist/commands/pull.js +114 -14
- package/dist/commands/pull.js.map +1 -1
- package/dist/commands/push.d.ts +1 -0
- package/dist/commands/push.d.ts.map +1 -1
- package/dist/commands/push.js +33 -13
- package/dist/commands/push.js.map +1 -1
- package/dist/commands/register.d.ts +6 -0
- package/dist/commands/register.d.ts.map +1 -1
- package/dist/commands/register.js +179 -79
- package/dist/commands/register.js.map +1 -1
- package/dist/commands/skill.d.ts.map +1 -1
- package/dist/commands/skill.js +121 -50
- package/dist/commands/skill.js.map +1 -1
- package/dist/commands/stack.d.ts +16 -0
- package/dist/commands/stack.d.ts.map +1 -0
- package/dist/commands/stack.js +863 -0
- package/dist/commands/stack.js.map +1 -0
- package/dist/commands/status.d.ts.map +1 -1
- package/dist/commands/status.js +25 -5
- package/dist/commands/status.js.map +1 -1
- package/dist/commands/sync.d.ts +23 -0
- package/dist/commands/sync.d.ts.map +1 -1
- package/dist/commands/sync.js +193 -12
- package/dist/commands/sync.js.map +1 -1
- package/dist/commands/whoami.d.ts.map +1 -1
- package/dist/commands/whoami.js +21 -16
- package/dist/commands/whoami.js.map +1 -1
- package/dist/create.js +0 -0
- package/dist/index.js +64 -7
- package/dist/index.js.map +1 -1
- package/dist/lib/api.d.ts +127 -5
- package/dist/lib/api.d.ts.map +1 -1
- package/dist/lib/api.js +142 -5
- package/dist/lib/api.js.map +1 -1
- package/dist/lib/ascii.d.ts +1 -0
- package/dist/lib/ascii.d.ts.map +1 -1
- package/dist/lib/ascii.js +9 -26
- package/dist/lib/ascii.js.map +1 -1
- package/dist/lib/canonical-json.d.ts +8 -0
- package/dist/lib/canonical-json.d.ts.map +1 -0
- package/dist/lib/canonical-json.js +29 -0
- package/dist/lib/canonical-json.js.map +1 -0
- package/dist/lib/capability-router.d.ts +58 -0
- package/dist/lib/capability-router.d.ts.map +1 -0
- package/dist/lib/capability-router.js +54 -0
- package/dist/lib/capability-router.js.map +1 -0
- package/dist/lib/compiler.d.ts +32 -0
- package/dist/lib/compiler.d.ts.map +1 -1
- package/dist/lib/compiler.js +150 -0
- package/dist/lib/compiler.js.map +1 -1
- package/dist/lib/config.d.ts +71 -35
- package/dist/lib/config.d.ts.map +1 -1
- package/dist/lib/config.js +334 -124
- package/dist/lib/config.js.map +1 -1
- package/dist/lib/decompile.d.ts +6 -1
- package/dist/lib/decompile.d.ts.map +1 -1
- package/dist/lib/decompile.js +120 -11
- package/dist/lib/decompile.js.map +1 -1
- package/dist/lib/hash.d.ts.map +1 -1
- package/dist/lib/hash.js +2 -19
- package/dist/lib/hash.js.map +1 -1
- package/dist/lib/heartbeat.d.ts +38 -0
- package/dist/lib/heartbeat.d.ts.map +1 -0
- package/dist/lib/heartbeat.js +70 -0
- package/dist/lib/heartbeat.js.map +1 -0
- package/dist/lib/host-link.d.ts +123 -0
- package/dist/lib/host-link.d.ts.map +1 -0
- package/dist/lib/host-link.js +350 -0
- package/dist/lib/host-link.js.map +1 -0
- package/dist/lib/merge.d.ts +50 -0
- package/dist/lib/merge.d.ts.map +1 -0
- package/dist/lib/merge.js +167 -0
- package/dist/lib/merge.js.map +1 -0
- package/dist/lib/okf-bundle.d.ts +104 -0
- package/dist/lib/okf-bundle.d.ts.map +1 -0
- package/dist/lib/okf-bundle.js +473 -0
- package/dist/lib/okf-bundle.js.map +1 -0
- package/dist/lib/okf-health.d.ts +40 -0
- package/dist/lib/okf-health.d.ts.map +1 -0
- package/dist/lib/okf-health.js +152 -0
- package/dist/lib/okf-health.js.map +1 -0
- package/dist/lib/okf-stack.d.ts +47 -0
- package/dist/lib/okf-stack.d.ts.map +1 -0
- package/dist/lib/okf-stack.js +331 -0
- package/dist/lib/okf-stack.js.map +1 -0
- package/dist/lib/okf-view.d.ts +49 -0
- package/dist/lib/okf-view.d.ts.map +1 -0
- package/dist/lib/okf-view.js +197 -0
- package/dist/lib/okf-view.js.map +1 -0
- package/dist/lib/okf.d.ts +130 -0
- package/dist/lib/okf.d.ts.map +1 -0
- package/dist/lib/okf.js +263 -0
- package/dist/lib/okf.js.map +1 -0
- package/dist/lib/onboarding.d.ts +17 -0
- package/dist/lib/onboarding.d.ts.map +1 -1
- package/dist/lib/onboarding.js +224 -207
- package/dist/lib/onboarding.js.map +1 -1
- package/dist/lib/project.d.ts +5 -0
- package/dist/lib/project.d.ts.map +1 -1
- package/dist/lib/project.js +8 -0
- package/dist/lib/project.js.map +1 -1
- package/dist/lib/projectContext.d.ts +201 -0
- package/dist/lib/projectContext.d.ts.map +1 -0
- package/dist/lib/projectContext.js +597 -0
- package/dist/lib/projectContext.js.map +1 -0
- package/dist/lib/render.d.ts +38 -1
- package/dist/lib/render.d.ts.map +1 -1
- package/dist/lib/render.js +83 -18
- package/dist/lib/render.js.map +1 -1
- package/dist/lib/skill-catalog.d.ts.map +1 -1
- package/dist/lib/skill-catalog.js +22 -2
- package/dist/lib/skill-catalog.js.map +1 -1
- package/dist/lib/skills.d.ts +20 -5
- package/dist/lib/skills.d.ts.map +1 -1
- package/dist/lib/skills.js +116 -58
- package/dist/lib/skills.js.map +1 -1
- package/dist/lib/stackEval.d.ts +87 -0
- package/dist/lib/stackEval.d.ts.map +1 -0
- package/dist/lib/stackEval.js +233 -0
- package/dist/lib/stackEval.js.map +1 -0
- package/dist/lib/stackImprove.d.ts +49 -0
- package/dist/lib/stackImprove.d.ts.map +1 -0
- package/dist/lib/stackImprove.js +313 -0
- package/dist/lib/stackImprove.js.map +1 -0
- package/dist/lib/stackInstall.d.ts +59 -0
- package/dist/lib/stackInstall.d.ts.map +1 -0
- package/dist/lib/stackInstall.js +162 -0
- package/dist/lib/stackInstall.js.map +1 -0
- package/dist/lib/stackSafety.d.ts +126 -0
- package/dist/lib/stackSafety.d.ts.map +1 -0
- package/dist/lib/stackSafety.js +486 -0
- package/dist/lib/stackSafety.js.map +1 -0
- package/dist/lib/stackUpdate.d.ts +44 -0
- package/dist/lib/stackUpdate.d.ts.map +1 -0
- package/dist/lib/stackUpdate.js +256 -0
- package/dist/lib/stackUpdate.js.map +1 -0
- package/dist/lib/stream.d.ts +116 -0
- package/dist/lib/stream.d.ts.map +1 -0
- package/dist/lib/stream.js +368 -0
- package/dist/lib/stream.js.map +1 -0
- package/dist/lib/youstack.d.ts +219 -0
- package/dist/lib/youstack.d.ts.map +1 -0
- package/dist/lib/youstack.js +1049 -0
- package/dist/lib/youstack.js.map +1 -0
- package/dist/mcp/registry.d.ts +133 -0
- package/dist/mcp/registry.d.ts.map +1 -0
- package/dist/mcp/registry.js +833 -0
- package/dist/mcp/registry.js.map +1 -0
- package/dist/mcp/server.d.ts +106 -5
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/mcp/server.js +851 -498
- package/dist/mcp/server.js.map +1 -1
- package/dist/postinstall.js +11 -2
- package/dist/postinstall.js.map +1 -1
- package/dist/you.d.ts +1 -0
- package/dist/you.js +40 -4
- package/dist/you.js.map +1 -1
- package/examples/youstack-bamfstack-public/docs/quickstart.md +34 -0
- package/examples/youstack-bamfstack-public/prompts/creator-draft-starter.md +15 -0
- package/examples/youstack-bamfstack-public/skills/bamfstack-start/SKILL.md +36 -0
- package/examples/youstack-bamfstack-public/tests/smoke.md +19 -0
- package/examples/youstack-bamfstack-public/workflows/creator-growth-workflow.md +22 -0
- package/examples/youstack-bamfstack-public/youstack.json +172 -0
- package/examples/youstack-personal/docs/quickstart.md +10 -0
- package/examples/youstack-personal/skills/youstack-start/SKILL.md +9 -0
- package/examples/youstack-personal/tests/smoke.md +9 -0
- package/examples/youstack-personal/workflows/startup.md +7 -0
- package/examples/youstack-personal/youstack.json +123 -0
- package/package.json +3 -3
- package/skills/claude-md-generator.md +1 -1
- package/skills/meta-improve.md +8 -3
- package/skills/proactive-context-fill.md +1 -1
- package/skills/youstack-maintainer.md +128 -0
- package/skills/youstack-start.md +78 -0
|
@@ -0,0 +1,833 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* T14 — CLI stdio MCP tool registry.
|
|
4
|
+
*
|
|
5
|
+
* Mirrors the shape of convex/lib/mcpRegistry.ts for the local stdio server.
|
|
6
|
+
* The CLI is a separate npm package that cannot import Convex modules, so this
|
|
7
|
+
* is an independent definition with the same ergonomics.
|
|
8
|
+
*
|
|
9
|
+
* Adding a tool: add one entry to CLI_MCP_TOOLS. The ListToolsRequestSchema
|
|
10
|
+
* and CallToolRequestSchema handlers in server.ts both drive from this array —
|
|
11
|
+
* no more editing two places.
|
|
12
|
+
*
|
|
13
|
+
* ─── MIGRATION STATUS ───────────────────────────────────────────────────────
|
|
14
|
+
*
|
|
15
|
+
* MIGRATED (17 tools):
|
|
16
|
+
* whoami — local bundle read, no auth required
|
|
17
|
+
* get_identity — local bundle read, compact/full/json/markdown
|
|
18
|
+
* list_skills — pure local dir scan
|
|
19
|
+
* list_projects — pure local dir scan
|
|
20
|
+
* get_section — local bundle file read
|
|
21
|
+
* get_project_context — local project-context engine, no network
|
|
22
|
+
* get_stack_manifest — local youstack.json parse
|
|
23
|
+
* get_stack_capabilities — local youstack.json capability map
|
|
24
|
+
* route_stack_request — local routing algorithm, no network
|
|
25
|
+
* smoke_stack — local manifest validation, no network
|
|
26
|
+
* search_memories — async fetch via ctx.fetchMemoriesEnvelope
|
|
27
|
+
* get_private_context — async fetch via ctx.fetchPrivateContextEnvelope
|
|
28
|
+
* add_memory — async POST via ctx.apiRequest + ctx.memoryCategories
|
|
29
|
+
* add_source — async POST via ctx.apiRequest
|
|
30
|
+
* create_context_link — async POST via ctx.apiRequest
|
|
31
|
+
* get_remote_status — conditional auth branch + ctx.apiRequest
|
|
32
|
+
* use_skill — ctx.getInstalledSkills()
|
|
33
|
+
* get_activity_log — auth-gated fetch via ctx.fetchActivityLog
|
|
34
|
+
*
|
|
35
|
+
* DEFERRED (4 tools — write-ops and dynamic-import tools):
|
|
36
|
+
* get_agent_brief — >50 lines; delegates to buildAgentBrief() in server.ts
|
|
37
|
+
* which has a deep async call-tree; keep in switch.
|
|
38
|
+
* update_section — fs write; intentionally deferred (write-ops last)
|
|
39
|
+
* add_project_memory — fs write via lib/project; intentionally deferred
|
|
40
|
+
* compile_bundle — dynamic import('../lib/compiler'); deferred
|
|
41
|
+
* push_bundle — dynamic imports compiler + api; deferred
|
|
42
|
+
* compile_and_push — dynamic imports compiler + api; deferred
|
|
43
|
+
*
|
|
44
|
+
* ────────────────────────────────────────────────────────────────────────────
|
|
45
|
+
*/
|
|
46
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
47
|
+
if (k2 === undefined) k2 = k;
|
|
48
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
49
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
50
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
51
|
+
}
|
|
52
|
+
Object.defineProperty(o, k2, desc);
|
|
53
|
+
}) : (function(o, m, k, k2) {
|
|
54
|
+
if (k2 === undefined) k2 = k;
|
|
55
|
+
o[k2] = m[k];
|
|
56
|
+
}));
|
|
57
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
58
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
59
|
+
}) : function(o, v) {
|
|
60
|
+
o["default"] = v;
|
|
61
|
+
});
|
|
62
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
63
|
+
var ownKeys = function(o) {
|
|
64
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
65
|
+
var ar = [];
|
|
66
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
67
|
+
return ar;
|
|
68
|
+
};
|
|
69
|
+
return ownKeys(o);
|
|
70
|
+
};
|
|
71
|
+
return function (mod) {
|
|
72
|
+
if (mod && mod.__esModule) return mod;
|
|
73
|
+
var result = {};
|
|
74
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
75
|
+
__setModuleDefault(result, mod);
|
|
76
|
+
return result;
|
|
77
|
+
};
|
|
78
|
+
})();
|
|
79
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
80
|
+
exports.CLI_MCP_TOOLS = void 0;
|
|
81
|
+
const fs = __importStar(require("fs"));
|
|
82
|
+
const path = __importStar(require("path"));
|
|
83
|
+
const config_1 = require("../lib/config");
|
|
84
|
+
const project_1 = require("../lib/project");
|
|
85
|
+
const projectContext_1 = require("../lib/projectContext");
|
|
86
|
+
const youstack_1 = require("../lib/youstack");
|
|
87
|
+
// ─── Shared config/helpers (duplicated here to avoid circular server.ts dep) ──
|
|
88
|
+
function _getLocalBundleDir2() { return (0, config_1.getLocalBundleDir)(); }
|
|
89
|
+
function _getHomeBundleDir2() { return (0, config_1.getHomeBundleDir)(); }
|
|
90
|
+
function getBundleDir() {
|
|
91
|
+
const local = _getLocalBundleDir2();
|
|
92
|
+
if ((0, config_1.bundleLooksInitialized)(local))
|
|
93
|
+
return local;
|
|
94
|
+
const home = _getHomeBundleDir2();
|
|
95
|
+
if ((0, config_1.bundleLooksInitialized)(home))
|
|
96
|
+
return home;
|
|
97
|
+
return local;
|
|
98
|
+
}
|
|
99
|
+
function readFileOr(filePath, fallback) {
|
|
100
|
+
try {
|
|
101
|
+
return fs.readFileSync(filePath, "utf-8");
|
|
102
|
+
}
|
|
103
|
+
catch {
|
|
104
|
+
return fallback;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
function readJsonOr(filePath, fallback) {
|
|
108
|
+
try {
|
|
109
|
+
return JSON.parse(fs.readFileSync(filePath, "utf-8"));
|
|
110
|
+
}
|
|
111
|
+
catch {
|
|
112
|
+
return fallback;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
function getYouJson() {
|
|
116
|
+
return readJsonOr(path.join(getBundleDir(), "you.json"), {});
|
|
117
|
+
}
|
|
118
|
+
function getYouMd() {
|
|
119
|
+
return readFileOr(path.join(getBundleDir(), "you.md"), "");
|
|
120
|
+
}
|
|
121
|
+
function asRecord(v) {
|
|
122
|
+
return typeof v === "object" && v !== null && !Array.isArray(v) ? v : {};
|
|
123
|
+
}
|
|
124
|
+
function getInstalledSkillNames() {
|
|
125
|
+
const skillsDir = path.join((0, config_1.getGlobalConfigDir)(), "skills");
|
|
126
|
+
if (!fs.existsSync(skillsDir))
|
|
127
|
+
return [];
|
|
128
|
+
try {
|
|
129
|
+
return fs.readdirSync(skillsDir, { withFileTypes: true })
|
|
130
|
+
.filter((e) => {
|
|
131
|
+
if (!e.isDirectory() && !e.isSymbolicLink())
|
|
132
|
+
return false;
|
|
133
|
+
const skillDir = path.join(skillsDir, e.name);
|
|
134
|
+
const hasSkill = fs.existsSync(path.join(skillDir, "SKILL.md"));
|
|
135
|
+
const hasRendered = fs.existsSync(path.join(skillDir, "RENDERED.md"));
|
|
136
|
+
return hasSkill || hasRendered;
|
|
137
|
+
})
|
|
138
|
+
.map((e) => e.name);
|
|
139
|
+
}
|
|
140
|
+
catch {
|
|
141
|
+
return [];
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
function buildWhoamiSummary() {
|
|
145
|
+
const youJson = getYouJson();
|
|
146
|
+
const identity = asRecord(youJson.identity);
|
|
147
|
+
const preferences = asRecord(youJson.preferences);
|
|
148
|
+
const agentPrefs = asRecord(preferences.agent);
|
|
149
|
+
const directives = asRecord(youJson.agent_directives);
|
|
150
|
+
const projects = Array.isArray(youJson.projects) ? youJson.projects : [];
|
|
151
|
+
const bio = asRecord(identity.bio);
|
|
152
|
+
const name = typeof identity.name === "string" ? identity.name
|
|
153
|
+
: typeof youJson.username === "string" ? youJson.username : "(unknown)";
|
|
154
|
+
const role = typeof identity.tagline === "string" ? identity.tagline
|
|
155
|
+
: typeof bio.short === "string" ? bio.short : "";
|
|
156
|
+
const stack = typeof directives.default_stack === "string" ? directives.default_stack : "";
|
|
157
|
+
const tone = typeof agentPrefs.tone === "string" ? agentPrefs.tone : "";
|
|
158
|
+
const avoidList = Array.isArray(agentPrefs.avoid)
|
|
159
|
+
? agentPrefs.avoid.filter((item) => typeof item === "string") : [];
|
|
160
|
+
const avoid = avoidList.join(", ");
|
|
161
|
+
const topProjects = projects.slice(0, 3).map((p) => {
|
|
162
|
+
if (typeof p === "string")
|
|
163
|
+
return p;
|
|
164
|
+
const r = asRecord(p);
|
|
165
|
+
return typeof r.name === "string" ? r.name : "";
|
|
166
|
+
}).filter(Boolean).join(", ");
|
|
167
|
+
const goal = typeof directives.current_goal === "string" ? directives.current_goal : "";
|
|
168
|
+
const lines = [];
|
|
169
|
+
lines.push(`Name: ${name}`);
|
|
170
|
+
if (role)
|
|
171
|
+
lines.push(`Role: ${role}`);
|
|
172
|
+
if (stack)
|
|
173
|
+
lines.push(`Stack: ${stack}`);
|
|
174
|
+
if (tone)
|
|
175
|
+
lines.push(`Tone: ${tone}`);
|
|
176
|
+
if (avoid)
|
|
177
|
+
lines.push(`Avoid: ${avoid}`);
|
|
178
|
+
if (topProjects)
|
|
179
|
+
lines.push(`Top projects: ${topProjects}`);
|
|
180
|
+
if (goal)
|
|
181
|
+
lines.push(`Goal: ${goal}`);
|
|
182
|
+
let summary = lines.join("\n");
|
|
183
|
+
if (summary.length > 500)
|
|
184
|
+
summary = summary.slice(0, 497) + "...";
|
|
185
|
+
return summary;
|
|
186
|
+
}
|
|
187
|
+
function buildIdentityMarkdown() {
|
|
188
|
+
const md = getYouMd();
|
|
189
|
+
if (md)
|
|
190
|
+
return md;
|
|
191
|
+
const youJson = getYouJson();
|
|
192
|
+
const identity = asRecord(youJson.identity);
|
|
193
|
+
const bio = asRecord(identity.bio);
|
|
194
|
+
const parts = [];
|
|
195
|
+
const title = typeof identity.name === "string" ? identity.name
|
|
196
|
+
: typeof youJson.username === "string" ? youJson.username : "Identity";
|
|
197
|
+
parts.push(`# ${title}`);
|
|
198
|
+
if (typeof identity.tagline === "string")
|
|
199
|
+
parts.push(identity.tagline);
|
|
200
|
+
const about = typeof bio.long === "string" ? bio.long
|
|
201
|
+
: typeof bio.medium === "string" ? bio.medium
|
|
202
|
+
: typeof bio.short === "string" ? bio.short : "";
|
|
203
|
+
if (about)
|
|
204
|
+
parts.push(`\n## About\n\n${about}`);
|
|
205
|
+
return parts.join("\n") + "\n";
|
|
206
|
+
}
|
|
207
|
+
function getCurrentProject() {
|
|
208
|
+
const root = (0, project_1.findProjectsRoot)();
|
|
209
|
+
if (!root)
|
|
210
|
+
return null;
|
|
211
|
+
const name = (0, project_1.detectCurrentProject)(root);
|
|
212
|
+
if (!name)
|
|
213
|
+
return null;
|
|
214
|
+
return { name, dir: (0, project_1.getProjectDir)(root, name) };
|
|
215
|
+
}
|
|
216
|
+
function tryLoadStack(inputPath) {
|
|
217
|
+
try {
|
|
218
|
+
return (0, youstack_1.loadYouStackManifest)(inputPath);
|
|
219
|
+
}
|
|
220
|
+
catch {
|
|
221
|
+
return null;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
// ─── Registry ─────────────────────────────────────────────────────────────────
|
|
225
|
+
exports.CLI_MCP_TOOLS = [
|
|
226
|
+
// ── whoami ──────────────────────────────────────────────────────────────────
|
|
227
|
+
{
|
|
228
|
+
name: "whoami",
|
|
229
|
+
description: "Return a compact ~500-char identity summary: name, role, stack, tone, things to avoid, top projects, and current goal. This is the FIRST tool you should call when starting a new conversation — it gives you just enough context to orient on the user before deciding whether to pull the full identity bundle. Returns plain text, not JSON.",
|
|
230
|
+
inputSchema: { type: "object", properties: {} },
|
|
231
|
+
handler: async (_args, ctx) => {
|
|
232
|
+
ctx.logActivity("read", "identity:compact");
|
|
233
|
+
return { content: [{ type: "text", text: buildWhoamiSummary() }] };
|
|
234
|
+
},
|
|
235
|
+
},
|
|
236
|
+
// ── get_identity ─────────────────────────────────────────────────────────────
|
|
237
|
+
{
|
|
238
|
+
name: "get_identity",
|
|
239
|
+
description: "Get the user's complete you.md identity bundle. Returns compact (default), full JSON, or human-readable markdown. For the fastest orient, call whoami first; call get_identity when you need full detail (preferences, voice, directives, projects).",
|
|
240
|
+
inputSchema: {
|
|
241
|
+
type: "object",
|
|
242
|
+
properties: {
|
|
243
|
+
format: {
|
|
244
|
+
type: "string",
|
|
245
|
+
enum: ["compact", "full", "json", "markdown"],
|
|
246
|
+
description: "Output format: compact (500-char summary, default — same as whoami), full/json (complete identity bundle as JSON), markdown (human-readable markdown).",
|
|
247
|
+
},
|
|
248
|
+
},
|
|
249
|
+
},
|
|
250
|
+
handler: async (args, ctx) => {
|
|
251
|
+
const format = args.format || "compact";
|
|
252
|
+
ctx.logActivity("read", "identity:" + format);
|
|
253
|
+
if (format === "markdown") {
|
|
254
|
+
return { content: [{ type: "text", text: buildIdentityMarkdown() }] };
|
|
255
|
+
}
|
|
256
|
+
if (format === "full" || format === "json") {
|
|
257
|
+
return { content: [{ type: "text", text: JSON.stringify(getYouJson(), null, 2) }] };
|
|
258
|
+
}
|
|
259
|
+
return { content: [{ type: "text", text: buildWhoamiSummary() }] };
|
|
260
|
+
},
|
|
261
|
+
},
|
|
262
|
+
// ── list_skills ──────────────────────────────────────────────────────────────
|
|
263
|
+
{
|
|
264
|
+
name: "list_skills",
|
|
265
|
+
description: "List all installed identity-aware skills with their names. Use to discover what skills are available before calling use_skill. Returns a simple list of installed skill names.",
|
|
266
|
+
inputSchema: { type: "object", properties: {} },
|
|
267
|
+
handler: async (_args, ctx) => {
|
|
268
|
+
const names = getInstalledSkillNames();
|
|
269
|
+
ctx.logActivity("read", "skills");
|
|
270
|
+
if (names.length === 0) {
|
|
271
|
+
return {
|
|
272
|
+
content: [{ type: "text", text: "no skills installed. run: youmd skill install voice-sync" }],
|
|
273
|
+
};
|
|
274
|
+
}
|
|
275
|
+
return { content: [{ type: "text", text: `installed skills:\n${names.map((n) => `- ${n}`).join("\n")}` }] };
|
|
276
|
+
},
|
|
277
|
+
},
|
|
278
|
+
// ── list_projects ─────────────────────────────────────────────────────────────
|
|
279
|
+
{
|
|
280
|
+
name: "list_projects",
|
|
281
|
+
description: "List all detected projects with their metadata. Returns project names found in the projects root directory. Use to discover available projects before calling get_project_context with a specific project name.",
|
|
282
|
+
inputSchema: { type: "object", properties: {} },
|
|
283
|
+
handler: async (_args, ctx) => {
|
|
284
|
+
try {
|
|
285
|
+
const root = (0, project_1.findProjectsRoot)();
|
|
286
|
+
if (!root) {
|
|
287
|
+
return { content: [{ type: "text", text: "no projects directory found" }], isError: true };
|
|
288
|
+
}
|
|
289
|
+
const projects = (0, project_1.listProjects)(root);
|
|
290
|
+
if (projects.length === 0) {
|
|
291
|
+
return { content: [{ type: "text", text: "no projects detected. create one with: youmd project init <name>" }] };
|
|
292
|
+
}
|
|
293
|
+
const current = getCurrentProject();
|
|
294
|
+
const list = projects
|
|
295
|
+
.map((p) => `- ${p}${current && current.name === p ? " (current)" : ""}`)
|
|
296
|
+
.join("\n");
|
|
297
|
+
ctx.logActivity("read", "projects");
|
|
298
|
+
return { content: [{ type: "text", text: `projects:\n${list}` }] };
|
|
299
|
+
}
|
|
300
|
+
catch (err) {
|
|
301
|
+
return {
|
|
302
|
+
content: [{ type: "text", text: `error listing projects: ${err instanceof Error ? err.message : "unknown"}` }],
|
|
303
|
+
isError: true,
|
|
304
|
+
};
|
|
305
|
+
}
|
|
306
|
+
},
|
|
307
|
+
},
|
|
308
|
+
// ── get_section ──────────────────────────────────────────────────────────────
|
|
309
|
+
{
|
|
310
|
+
name: "get_section",
|
|
311
|
+
description: "Read a specific identity section by path. Use when you need just ONE section rather than the full bundle. Returns markdown content for the requested section. Available paths: profile/about, profile/projects, profile/now, profile/values, profile/links, preferences/agent, preferences/writing, voice/voice, directives/agent.",
|
|
312
|
+
inputSchema: {
|
|
313
|
+
type: "object",
|
|
314
|
+
properties: {
|
|
315
|
+
section: {
|
|
316
|
+
type: "string",
|
|
317
|
+
description: "Section path: profile/about, profile/projects, profile/now, profile/values, profile/links, preferences/agent, preferences/writing, voice/voice, directives/agent",
|
|
318
|
+
},
|
|
319
|
+
},
|
|
320
|
+
required: ["section"],
|
|
321
|
+
},
|
|
322
|
+
handler: async (args, ctx) => {
|
|
323
|
+
const section = args.section;
|
|
324
|
+
const parts = section.split("/");
|
|
325
|
+
if (parts.length !== 2) {
|
|
326
|
+
return {
|
|
327
|
+
content: [{ type: "text", text: "invalid section path — use format: dir/slug (e.g., profile/about)" }],
|
|
328
|
+
isError: true,
|
|
329
|
+
};
|
|
330
|
+
}
|
|
331
|
+
const filePath = path.join(getBundleDir(), parts[0], `${parts[1]}.md`);
|
|
332
|
+
const content = readFileOr(filePath, "");
|
|
333
|
+
if (!content) {
|
|
334
|
+
return { content: [{ type: "text", text: `section not found: ${section}` }], isError: true };
|
|
335
|
+
}
|
|
336
|
+
ctx.logActivity("read_section", section);
|
|
337
|
+
return { content: [{ type: "text", text: content }] };
|
|
338
|
+
},
|
|
339
|
+
},
|
|
340
|
+
// ── get_project_context ──────────────────────────────────────────────────────
|
|
341
|
+
{
|
|
342
|
+
name: "get_project_context",
|
|
343
|
+
description: "Get the full project context for the current or named project — PRD, TODO, features, decisions, changelog, and project memories. Returns a readiness envelope so agents can distinguish missing project context from ready project context without parsing plain-text errors.",
|
|
344
|
+
inputSchema: {
|
|
345
|
+
type: "object",
|
|
346
|
+
properties: {
|
|
347
|
+
project: {
|
|
348
|
+
type: "string",
|
|
349
|
+
description: "Project name. Omit to auto-detect from current directory.",
|
|
350
|
+
},
|
|
351
|
+
},
|
|
352
|
+
},
|
|
353
|
+
handler: async (args, ctx) => {
|
|
354
|
+
// Delegate to server.ts's fetchProjectContextEnvelope via ctx. Since
|
|
355
|
+
// that function has no network calls and is pure local-read, we re-
|
|
356
|
+
// implement it here using the same projectContext engine imports.
|
|
357
|
+
const { readMergedProjectContext, resolveProjectContext: _rpc } = await Promise.resolve().then(() => __importStar(require("../lib/projectContext")));
|
|
358
|
+
const projectName = args.project;
|
|
359
|
+
const repoRoot = (0, projectContext_1.findRepoContextRoot)();
|
|
360
|
+
const readiness = (status, reason, fallback) => ({
|
|
361
|
+
status, ready: status === "ready", reason, fallback,
|
|
362
|
+
});
|
|
363
|
+
if (projectName) {
|
|
364
|
+
const ctx2 = readMergedProjectContext({ projectName });
|
|
365
|
+
if (!ctx2) {
|
|
366
|
+
const result = {
|
|
367
|
+
readiness: readiness("not_found", `Project context for ${projectName} was not found or is incomplete.`, "Use local repo instructions, project-context files, or confirm the named project exists before retrying."),
|
|
368
|
+
project: { name: projectName, source: "named" },
|
|
369
|
+
projectContext: null,
|
|
370
|
+
};
|
|
371
|
+
ctx.logActivity("read", "project/" + projectName);
|
|
372
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }], isError: true };
|
|
373
|
+
}
|
|
374
|
+
const result = {
|
|
375
|
+
readiness: readiness("ready", `Project context for ${projectName} is available.`, "None needed."),
|
|
376
|
+
project: { name: projectName, source: "named" },
|
|
377
|
+
projectContext: ctx2,
|
|
378
|
+
};
|
|
379
|
+
ctx.logActivity("read", "project/" + projectName);
|
|
380
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
381
|
+
}
|
|
382
|
+
const current = getCurrentProject();
|
|
383
|
+
const merged = readMergedProjectContext(current ? { projectName: current.name } : {});
|
|
384
|
+
if (!merged && !repoRoot) {
|
|
385
|
+
const result = {
|
|
386
|
+
readiness: readiness("not_found", "No current project was detected from the working directory.", "Use local project-context files in the current repo, pass an explicit project name, or fall back to public identity and stack files."),
|
|
387
|
+
project: { name: null, source: "current" },
|
|
388
|
+
projectContext: null,
|
|
389
|
+
};
|
|
390
|
+
ctx.logActivity("read", "project/current");
|
|
391
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }], isError: true };
|
|
392
|
+
}
|
|
393
|
+
const finalCtx = merged;
|
|
394
|
+
const name = finalCtx?.meta?.name || current?.name || null;
|
|
395
|
+
const result = finalCtx
|
|
396
|
+
? {
|
|
397
|
+
readiness: readiness("ready", `Project context for ${name} is available.`, "None needed."),
|
|
398
|
+
project: { name, source: "current" },
|
|
399
|
+
projectContext: finalCtx,
|
|
400
|
+
}
|
|
401
|
+
: {
|
|
402
|
+
readiness: readiness("not_found", "Project context could not be read.", "Use repo-local instructions and project-context markdown files directly."),
|
|
403
|
+
project: { name, source: "current" },
|
|
404
|
+
projectContext: null,
|
|
405
|
+
};
|
|
406
|
+
ctx.logActivity("read", "project/current");
|
|
407
|
+
return {
|
|
408
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
|
409
|
+
isError: !result.readiness.ready,
|
|
410
|
+
};
|
|
411
|
+
},
|
|
412
|
+
},
|
|
413
|
+
// ── get_stack_manifest ────────────────────────────────────────────────────────
|
|
414
|
+
{
|
|
415
|
+
name: "get_stack_manifest",
|
|
416
|
+
description: "Return the current local YouStack manifest discovered from cwd, or from a provided manifest/stack path. Use before trusting local stack files.",
|
|
417
|
+
inputSchema: {
|
|
418
|
+
type: "object",
|
|
419
|
+
properties: {
|
|
420
|
+
path: { type: "string", description: "Optional path to a youstack.json file or stack directory." },
|
|
421
|
+
},
|
|
422
|
+
},
|
|
423
|
+
handler: async (args, ctx) => {
|
|
424
|
+
const loaded = tryLoadStack(args.path);
|
|
425
|
+
const readiness = (0, youstack_1.getYouStackReadiness)(loaded);
|
|
426
|
+
if (!loaded) {
|
|
427
|
+
return {
|
|
428
|
+
content: [{ type: "text", text: JSON.stringify({ readiness, manifest: null, validation: null }, null, 2) }],
|
|
429
|
+
isError: true,
|
|
430
|
+
};
|
|
431
|
+
}
|
|
432
|
+
ctx.logActivity("read", "stack/manifest", { stack: loaded.manifest.slug });
|
|
433
|
+
return {
|
|
434
|
+
content: [{
|
|
435
|
+
type: "text",
|
|
436
|
+
text: JSON.stringify({
|
|
437
|
+
readiness,
|
|
438
|
+
manifestPath: loaded.manifestPath,
|
|
439
|
+
rootDir: loaded.rootDir,
|
|
440
|
+
manifest: loaded.manifest,
|
|
441
|
+
validation: loaded.validation,
|
|
442
|
+
}, null, 2),
|
|
443
|
+
}],
|
|
444
|
+
};
|
|
445
|
+
},
|
|
446
|
+
},
|
|
447
|
+
// ── get_stack_capabilities ────────────────────────────────────────────────────
|
|
448
|
+
{
|
|
449
|
+
name: "get_stack_capabilities",
|
|
450
|
+
description: "Return the local YouStack capability map, including local/static capabilities and protected API/MCP capabilities declared by the manifest.",
|
|
451
|
+
inputSchema: {
|
|
452
|
+
type: "object",
|
|
453
|
+
properties: {
|
|
454
|
+
path: { type: "string", description: "Optional path to a youstack.json file or stack directory." },
|
|
455
|
+
},
|
|
456
|
+
},
|
|
457
|
+
handler: async (args, ctx) => {
|
|
458
|
+
const loaded = tryLoadStack(args.path);
|
|
459
|
+
const readiness = (0, youstack_1.getYouStackReadiness)(loaded);
|
|
460
|
+
if (!loaded) {
|
|
461
|
+
return {
|
|
462
|
+
content: [{ type: "text", text: JSON.stringify({ readiness, capabilities: [] }, null, 2) }],
|
|
463
|
+
isError: true,
|
|
464
|
+
};
|
|
465
|
+
}
|
|
466
|
+
ctx.logActivity("read", "stack/capabilities", { stack: loaded.manifest.slug });
|
|
467
|
+
return {
|
|
468
|
+
content: [{
|
|
469
|
+
type: "text",
|
|
470
|
+
text: JSON.stringify({
|
|
471
|
+
readiness,
|
|
472
|
+
stack: loaded.manifest.slug,
|
|
473
|
+
capabilities: (0, youstack_1.getYouStackCapabilities)(loaded.manifest),
|
|
474
|
+
}, null, 2),
|
|
475
|
+
}],
|
|
476
|
+
};
|
|
477
|
+
},
|
|
478
|
+
},
|
|
479
|
+
// ── route_stack_request ──────────────────────────────────────────────────────
|
|
480
|
+
{
|
|
481
|
+
name: "route_stack_request",
|
|
482
|
+
description: "Route a natural-language request to the safest matching local YouStack capability. This is deterministic and read-only.",
|
|
483
|
+
inputSchema: {
|
|
484
|
+
type: "object",
|
|
485
|
+
properties: {
|
|
486
|
+
request: { type: "string", description: "The user's natural-language stack request." },
|
|
487
|
+
path: { type: "string", description: "Optional path to a youstack.json file or stack directory." },
|
|
488
|
+
},
|
|
489
|
+
required: ["request"],
|
|
490
|
+
},
|
|
491
|
+
handler: async (args, ctx) => {
|
|
492
|
+
if (!args.request) {
|
|
493
|
+
return { content: [{ type: "text", text: "missing required argument: request" }], isError: true };
|
|
494
|
+
}
|
|
495
|
+
const loaded = tryLoadStack(args.path);
|
|
496
|
+
const readiness = (0, youstack_1.getYouStackReadiness)(loaded);
|
|
497
|
+
if (!loaded) {
|
|
498
|
+
return {
|
|
499
|
+
content: [{
|
|
500
|
+
type: "text",
|
|
501
|
+
text: JSON.stringify({ readiness, request: args.request, capability: null, alternatives: [] }, null, 2),
|
|
502
|
+
}],
|
|
503
|
+
isError: true,
|
|
504
|
+
};
|
|
505
|
+
}
|
|
506
|
+
const route = (0, youstack_1.routeYouStackRequest)(loaded.manifest, args.request);
|
|
507
|
+
ctx.logActivity("read", "stack/route", { stack: loaded.manifest.slug, capability: route.capability.id });
|
|
508
|
+
return {
|
|
509
|
+
content: [{ type: "text", text: JSON.stringify({ readiness, ...route }, null, 2) }],
|
|
510
|
+
};
|
|
511
|
+
},
|
|
512
|
+
},
|
|
513
|
+
// ── smoke_stack ───────────────────────────────────────────────────────────────
|
|
514
|
+
{
|
|
515
|
+
name: "smoke_stack",
|
|
516
|
+
description: "Run read-only local YouStack smoke validation. It parses the manifest, verifies required files/checksums, checks adapter declarations, and performs no writes.",
|
|
517
|
+
inputSchema: {
|
|
518
|
+
type: "object",
|
|
519
|
+
properties: {
|
|
520
|
+
path: { type: "string", description: "Optional path to a youstack.json file or stack directory." },
|
|
521
|
+
},
|
|
522
|
+
},
|
|
523
|
+
handler: async (args, ctx) => {
|
|
524
|
+
const loaded = tryLoadStack(args.path);
|
|
525
|
+
const readiness = (0, youstack_1.getYouStackReadiness)(loaded);
|
|
526
|
+
if (!loaded) {
|
|
527
|
+
return {
|
|
528
|
+
content: [{
|
|
529
|
+
type: "text",
|
|
530
|
+
text: JSON.stringify({ readiness, ok: false, errors: ["no local YouStack manifest found"], warnings: [], checks: [] }, null, 2),
|
|
531
|
+
}],
|
|
532
|
+
isError: true,
|
|
533
|
+
};
|
|
534
|
+
}
|
|
535
|
+
const smoke = (0, youstack_1.runYouStackSmoke)(loaded);
|
|
536
|
+
ctx.logActivity("read", "stack/smoke", { stack: loaded.manifest.slug, ok: smoke.ok });
|
|
537
|
+
return {
|
|
538
|
+
content: [{ type: "text", text: JSON.stringify({ readiness, ...smoke }, null, 2) }],
|
|
539
|
+
isError: !smoke.ok,
|
|
540
|
+
};
|
|
541
|
+
},
|
|
542
|
+
},
|
|
543
|
+
// ── search_memories ──────────────────────────────────────────────────────────
|
|
544
|
+
{
|
|
545
|
+
name: "search_memories",
|
|
546
|
+
description: "Search the user's memories by category or list all active memories. Returns a readiness envelope plus memory objects so agents can distinguish auth-required, unavailable, and ready-but-empty retrieval states.",
|
|
547
|
+
inputSchema: {
|
|
548
|
+
type: "object",
|
|
549
|
+
properties: {
|
|
550
|
+
category: {
|
|
551
|
+
type: "string",
|
|
552
|
+
description: "Filter by category (optional): fact, preference, decision, project, goal, insight, context",
|
|
553
|
+
},
|
|
554
|
+
limit: { type: "number", description: "Max results (default 30)" },
|
|
555
|
+
},
|
|
556
|
+
},
|
|
557
|
+
handler: async (args, ctx) => {
|
|
558
|
+
const { category, limit } = args;
|
|
559
|
+
const result = await ctx.fetchMemoriesEnvelope(category, limit ?? 30);
|
|
560
|
+
ctx.logActivity("read", "memories");
|
|
561
|
+
return {
|
|
562
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
|
563
|
+
isError: !result.readiness.ready,
|
|
564
|
+
};
|
|
565
|
+
},
|
|
566
|
+
},
|
|
567
|
+
// ── get_private_context ──────────────────────────────────────────────────────
|
|
568
|
+
{
|
|
569
|
+
name: "get_private_context",
|
|
570
|
+
description: "Read protected private context — notes, internal links, and private projects. Returns a readiness envelope so agents can distinguish auth-required, unavailable, and ready-but-empty retrieval states before asking the user to restate private context.",
|
|
571
|
+
inputSchema: { type: "object", properties: {} },
|
|
572
|
+
handler: async (_args, ctx) => {
|
|
573
|
+
const result = await ctx.fetchPrivateContextEnvelope();
|
|
574
|
+
ctx.logActivity("read", "private-context");
|
|
575
|
+
return {
|
|
576
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
|
577
|
+
isError: !result.readiness.ready,
|
|
578
|
+
};
|
|
579
|
+
},
|
|
580
|
+
},
|
|
581
|
+
// ── add_memory ───────────────────────────────────────────────────────────────
|
|
582
|
+
{
|
|
583
|
+
name: "add_memory",
|
|
584
|
+
description: "Save a memory about the user — facts, preferences, decisions, or context learned during this conversation. Memories persist across sessions and inform ALL future agent interactions. Use proactively when you learn something important about the user (a preference, a decision, a project detail). Requires authentication.",
|
|
585
|
+
inputSchema: {
|
|
586
|
+
type: "object",
|
|
587
|
+
properties: {
|
|
588
|
+
category: {
|
|
589
|
+
type: "string",
|
|
590
|
+
enum: ["fact", "preference", "decision", "project", "goal", "insight", "context", "relationship"],
|
|
591
|
+
description: "Memory category. Must be one of: fact, preference, decision, project, goal, insight, context, relationship.",
|
|
592
|
+
},
|
|
593
|
+
content: { type: "string", description: "The memory content — be specific and actionable" },
|
|
594
|
+
tags: {
|
|
595
|
+
type: "array",
|
|
596
|
+
items: { type: "string" },
|
|
597
|
+
description: "Optional tags for searchability",
|
|
598
|
+
},
|
|
599
|
+
},
|
|
600
|
+
required: ["category", "content"],
|
|
601
|
+
},
|
|
602
|
+
handler: async (args, ctx) => {
|
|
603
|
+
const { category, content: memContent, tags } = args;
|
|
604
|
+
if (!ctx.authenticated) {
|
|
605
|
+
return { content: [{ type: "text", text: "not authenticated — run youmd login first" }], isError: true };
|
|
606
|
+
}
|
|
607
|
+
if (!category || !ctx.memoryCategories.includes(category)) {
|
|
608
|
+
return {
|
|
609
|
+
content: [{
|
|
610
|
+
type: "text",
|
|
611
|
+
text: `invalid category: ${category || "(missing)"}. valid categories: ${ctx.memoryCategories.join(", ")}`,
|
|
612
|
+
}],
|
|
613
|
+
isError: true,
|
|
614
|
+
};
|
|
615
|
+
}
|
|
616
|
+
try {
|
|
617
|
+
await ctx.apiRequest("/api/v1/me/memories", {
|
|
618
|
+
method: "POST",
|
|
619
|
+
body: {
|
|
620
|
+
memories: [{
|
|
621
|
+
category,
|
|
622
|
+
content: memContent,
|
|
623
|
+
source: "mcp",
|
|
624
|
+
sourceAgent: ctx.resolveAgentName(),
|
|
625
|
+
tags,
|
|
626
|
+
}],
|
|
627
|
+
},
|
|
628
|
+
});
|
|
629
|
+
ctx.logActivity("memory_add", category);
|
|
630
|
+
return {
|
|
631
|
+
content: [{
|
|
632
|
+
type: "text",
|
|
633
|
+
text: `memory saved: [${category}] ${memContent.slice(0, 80)}${memContent.length > 80 ? "..." : ""}`,
|
|
634
|
+
}],
|
|
635
|
+
};
|
|
636
|
+
}
|
|
637
|
+
catch (err) {
|
|
638
|
+
return {
|
|
639
|
+
content: [{ type: "text", text: `failed to save memory: ${err instanceof Error ? err.message : "unknown error"}` }],
|
|
640
|
+
isError: true,
|
|
641
|
+
};
|
|
642
|
+
}
|
|
643
|
+
},
|
|
644
|
+
},
|
|
645
|
+
// ── add_source ───────────────────────────────────────────────────────────────
|
|
646
|
+
{
|
|
647
|
+
name: "add_source",
|
|
648
|
+
description: "Register an identity data source (LinkedIn, GitHub, X, website, blog, YouTube). Links an external profile to the user's identity so it can be scraped and indexed. Requires authentication. Use when the user wants to connect a new social profile or website to their identity.",
|
|
649
|
+
inputSchema: {
|
|
650
|
+
type: "object",
|
|
651
|
+
properties: {
|
|
652
|
+
sourceType: {
|
|
653
|
+
type: "string",
|
|
654
|
+
enum: ["website", "linkedin", "x", "github", "blog", "youtube"],
|
|
655
|
+
description: "Type of source to register",
|
|
656
|
+
},
|
|
657
|
+
sourceUrl: {
|
|
658
|
+
type: "string",
|
|
659
|
+
description: "Full URL to the source (e.g., https://github.com/username)",
|
|
660
|
+
},
|
|
661
|
+
},
|
|
662
|
+
required: ["sourceType", "sourceUrl"],
|
|
663
|
+
},
|
|
664
|
+
handler: async (args, ctx) => {
|
|
665
|
+
if (!ctx.authenticated) {
|
|
666
|
+
return { content: [{ type: "text", text: "not authenticated — run youmd login first" }], isError: true };
|
|
667
|
+
}
|
|
668
|
+
const { sourceType, sourceUrl } = args;
|
|
669
|
+
try {
|
|
670
|
+
await ctx.apiRequest("/api/v1/me/sources", {
|
|
671
|
+
method: "POST",
|
|
672
|
+
body: { sourceType, sourceUrl },
|
|
673
|
+
});
|
|
674
|
+
ctx.logActivity("write", "source/" + sourceType);
|
|
675
|
+
return { content: [{ type: "text", text: `source registered: [${sourceType}] ${sourceUrl}` }] };
|
|
676
|
+
}
|
|
677
|
+
catch (err) {
|
|
678
|
+
return {
|
|
679
|
+
content: [{ type: "text", text: `failed to add source: ${err instanceof Error ? err.message : "unknown error"}` }],
|
|
680
|
+
isError: true,
|
|
681
|
+
};
|
|
682
|
+
}
|
|
683
|
+
},
|
|
684
|
+
},
|
|
685
|
+
// ── create_context_link ──────────────────────────────────────────────────────
|
|
686
|
+
{
|
|
687
|
+
name: "create_context_link",
|
|
688
|
+
description: "Generate a shareable context link for agents. The link gives any agent temporary or permanent read access to the user's identity context. Use when the user wants to share their identity with a third-party agent or service. Returns a URL that can be passed to any agent.",
|
|
689
|
+
inputSchema: {
|
|
690
|
+
type: "object",
|
|
691
|
+
properties: {
|
|
692
|
+
scope: {
|
|
693
|
+
type: "string",
|
|
694
|
+
enum: ["public", "full"],
|
|
695
|
+
description: "Access scope: public (profile only) or full (includes memories, preferences, directives). Default: public",
|
|
696
|
+
},
|
|
697
|
+
ttl: {
|
|
698
|
+
type: "string",
|
|
699
|
+
enum: ["1h", "24h", "7d", "30d", "never"],
|
|
700
|
+
description: "Time-to-live for the link. Default: 24h",
|
|
701
|
+
},
|
|
702
|
+
},
|
|
703
|
+
},
|
|
704
|
+
handler: async (args, ctx) => {
|
|
705
|
+
if (!ctx.authenticated) {
|
|
706
|
+
return { content: [{ type: "text", text: "not authenticated — run youmd login first" }], isError: true };
|
|
707
|
+
}
|
|
708
|
+
const { scope, ttl } = args;
|
|
709
|
+
try {
|
|
710
|
+
const result = await ctx.apiRequest("/api/v1/me/context-links", {
|
|
711
|
+
method: "POST",
|
|
712
|
+
body: { scope: scope || "public", ttl: ttl || "24h" },
|
|
713
|
+
});
|
|
714
|
+
const link = result.url || result.link || JSON.stringify(result);
|
|
715
|
+
ctx.logActivity("write", "context-link", { scope: scope || "public" });
|
|
716
|
+
return {
|
|
717
|
+
content: [{ type: "text", text: `context link created: ${link}\nscope: ${scope || "public"}, ttl: ${ttl || "24h"}` }],
|
|
718
|
+
};
|
|
719
|
+
}
|
|
720
|
+
catch (err) {
|
|
721
|
+
return {
|
|
722
|
+
content: [{ type: "text", text: `failed to create context link: ${err instanceof Error ? err.message : "unknown error"}` }],
|
|
723
|
+
isError: true,
|
|
724
|
+
};
|
|
725
|
+
}
|
|
726
|
+
},
|
|
727
|
+
},
|
|
728
|
+
// ── get_remote_status ────────────────────────────────────────────────────────
|
|
729
|
+
{
|
|
730
|
+
name: "get_remote_status",
|
|
731
|
+
description: "Check sync status between local identity bundle and the remote you.md server. Returns whether the user is authenticated, whether the local bundle exists, and the current version info. Use to diagnose sync issues or confirm a push was successful.",
|
|
732
|
+
inputSchema: { type: "object", properties: {} },
|
|
733
|
+
handler: async (_args, ctx) => {
|
|
734
|
+
const youJson = ctx.getYouJson();
|
|
735
|
+
const version = youJson?.version || "unknown";
|
|
736
|
+
const status = {
|
|
737
|
+
authenticated: ctx.authenticated,
|
|
738
|
+
localBundleExists: ctx.activeBundleExists(),
|
|
739
|
+
localVersion: version,
|
|
740
|
+
};
|
|
741
|
+
if (ctx.authenticated) {
|
|
742
|
+
try {
|
|
743
|
+
const remote = await ctx.apiRequest("/api/v1/me/status");
|
|
744
|
+
status.remote = remote;
|
|
745
|
+
}
|
|
746
|
+
catch {
|
|
747
|
+
status.remote = "unreachable";
|
|
748
|
+
}
|
|
749
|
+
}
|
|
750
|
+
ctx.logActivity("read", "status");
|
|
751
|
+
return { content: [{ type: "text", text: JSON.stringify(status, null, 2) }] };
|
|
752
|
+
},
|
|
753
|
+
},
|
|
754
|
+
// ── use_skill ────────────────────────────────────────────────────────────────
|
|
755
|
+
{
|
|
756
|
+
name: "use_skill",
|
|
757
|
+
description: "Render an identity-aware skill — returns the skill content with the user's identity interpolated into {{var}} placeholders. Returns rendered markdown with instructions the agent should follow. Use when the user asks to generate a CLAUDE.md, sync voice, scaffold a project, or run a self-improvement review.",
|
|
758
|
+
inputSchema: {
|
|
759
|
+
type: "object",
|
|
760
|
+
properties: {
|
|
761
|
+
name: {
|
|
762
|
+
type: "string",
|
|
763
|
+
description: "Skill name: youstack-start, youstack-maintainer, voice-sync, claude-md-generator, project-context-init, meta-improve, proactive-context-fill, you-logs",
|
|
764
|
+
},
|
|
765
|
+
},
|
|
766
|
+
required: ["name"],
|
|
767
|
+
},
|
|
768
|
+
handler: async (args, ctx) => {
|
|
769
|
+
const skillName = args.name;
|
|
770
|
+
const skills = ctx.getInstalledSkills();
|
|
771
|
+
const skill = skills.find((s) => s.name === skillName);
|
|
772
|
+
if (!skill) {
|
|
773
|
+
const available = skills.map((s) => s.name).join(", ") || "none installed";
|
|
774
|
+
return { content: [{ type: "text", text: `skill not found: ${skillName}. available: ${available}` }], isError: true };
|
|
775
|
+
}
|
|
776
|
+
ctx.logActivity("skill_use", "skill/" + skillName);
|
|
777
|
+
return { content: [{ type: "text", text: skill.rendered || skill.raw }] };
|
|
778
|
+
},
|
|
779
|
+
},
|
|
780
|
+
// ── get_activity_log ─────────────────────────────────────────────────────────
|
|
781
|
+
{
|
|
782
|
+
name: "get_activity_log",
|
|
783
|
+
description: "Get the user's recent agent activity log. Use this to see which agents have connected to their you.md identity and what they did. Returns an array of activity events with agent name, action, resource, timestamp. Useful for: showing the user proof their identity context is being used by other agents, debugging integration issues, auditing access.",
|
|
784
|
+
inputSchema: {
|
|
785
|
+
type: "object",
|
|
786
|
+
properties: {
|
|
787
|
+
limit: { type: "number", description: "Max events (default 30)" },
|
|
788
|
+
agentName: { type: "string", description: "Filter by agent name (e.g. 'Claude Code')" },
|
|
789
|
+
action: { type: "string", description: "Filter by action (read|write|push|memory_add)" },
|
|
790
|
+
},
|
|
791
|
+
},
|
|
792
|
+
handler: async (args, ctx) => {
|
|
793
|
+
if (!ctx.authenticated) {
|
|
794
|
+
return { content: [{ type: "text", text: "not authenticated — run youmd login first" }], isError: true };
|
|
795
|
+
}
|
|
796
|
+
const params = new URLSearchParams();
|
|
797
|
+
const activityArgs = args;
|
|
798
|
+
if (activityArgs.limit)
|
|
799
|
+
params.set("limit", String(activityArgs.limit));
|
|
800
|
+
if (activityArgs.agentName)
|
|
801
|
+
params.set("agent", String(activityArgs.agentName));
|
|
802
|
+
if (activityArgs.action)
|
|
803
|
+
params.set("action", String(activityArgs.action));
|
|
804
|
+
const res = await ctx.fetchActivityLog(params);
|
|
805
|
+
if (!res.ok) {
|
|
806
|
+
return {
|
|
807
|
+
content: [{ type: "text", text: `failed to fetch activity log: ${res.status}` }],
|
|
808
|
+
isError: true,
|
|
809
|
+
};
|
|
810
|
+
}
|
|
811
|
+
const data = await res.json();
|
|
812
|
+
const events = data.activity || [];
|
|
813
|
+
if (events.length === 0) {
|
|
814
|
+
return { content: [{ type: "text", text: "No activity yet. Agents will appear here when they connect to your you.md identity." }] };
|
|
815
|
+
}
|
|
816
|
+
const formatted = events.slice(0, 30).reverse().map((e) => {
|
|
817
|
+
const time = new Date(e.createdAt || Date.now()).toTimeString().slice(0, 5);
|
|
818
|
+
const versions = e.bundleVersionBefore && e.bundleVersionAfter
|
|
819
|
+
? ` v${e.bundleVersionBefore}→v${e.bundleVersionAfter}` : "";
|
|
820
|
+
const agentName = (e.agentName || "unknown").padEnd(16);
|
|
821
|
+
const action = (e.action || "read").padEnd(12);
|
|
822
|
+
return `${time} ${agentName} ${action} ${e.resource || ""}${versions}`;
|
|
823
|
+
}).join("\n");
|
|
824
|
+
return {
|
|
825
|
+
content: [{
|
|
826
|
+
type: "text",
|
|
827
|
+
text: `── recent agent activity (${events.length} events) ──\n\n${formatted}`,
|
|
828
|
+
}],
|
|
829
|
+
};
|
|
830
|
+
},
|
|
831
|
+
},
|
|
832
|
+
];
|
|
833
|
+
//# sourceMappingURL=registry.js.map
|