youmd 0.8.0 → 0.8.5
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/chat.d.ts.map +1 -1
- package/dist/commands/chat.js +20 -2
- package/dist/commands/chat.js.map +1 -1
- package/dist/commands/env.d.ts +21 -4
- package/dist/commands/env.d.ts.map +1 -1
- package/dist/commands/env.js +250 -24
- package/dist/commands/env.js.map +1 -1
- package/dist/commands/login.d.ts +1 -0
- package/dist/commands/login.d.ts.map +1 -1
- package/dist/commands/login.js +20 -4
- package/dist/commands/login.js.map +1 -1
- package/dist/commands/machine.d.ts +28 -1
- package/dist/commands/machine.d.ts.map +1 -1
- package/dist/commands/machine.js +529 -4
- package/dist/commands/machine.js.map +1 -1
- package/dist/commands/project.d.ts.map +1 -1
- package/dist/commands/project.js +862 -17
- package/dist/commands/project.js.map +1 -1
- package/dist/commands/prompts.d.ts +19 -0
- package/dist/commands/prompts.d.ts.map +1 -1
- package/dist/commands/prompts.js +304 -1
- package/dist/commands/prompts.js.map +1 -1
- package/dist/commands/pull.d.ts.map +1 -1
- package/dist/commands/pull.js +28 -8
- package/dist/commands/pull.js.map +1 -1
- package/dist/commands/push.d.ts +3 -1
- package/dist/commands/push.d.ts.map +1 -1
- package/dist/commands/push.js +26 -12
- package/dist/commands/push.js.map +1 -1
- package/dist/commands/skill.d.ts.map +1 -1
- package/dist/commands/skill.js +19 -15
- package/dist/commands/skill.js.map +1 -1
- package/dist/commands/stack.d.ts.map +1 -1
- package/dist/commands/stack.js +20 -17
- package/dist/commands/stack.js.map +1 -1
- package/dist/commands/status.d.ts.map +1 -1
- package/dist/commands/status.js +38 -0
- package/dist/commands/status.js.map +1 -1
- package/dist/commands/sync.d.ts +2 -0
- package/dist/commands/sync.d.ts.map +1 -1
- package/dist/commands/sync.js +235 -2
- package/dist/commands/sync.js.map +1 -1
- package/dist/index.js +157 -31
- package/dist/index.js.map +1 -1
- package/dist/lib/api.d.ts +398 -0
- package/dist/lib/api.d.ts.map +1 -1
- package/dist/lib/api.js +104 -0
- package/dist/lib/api.js.map +1 -1
- package/dist/lib/daemon.d.ts +26 -0
- package/dist/lib/daemon.d.ts.map +1 -0
- package/dist/lib/daemon.js +187 -0
- package/dist/lib/daemon.js.map +1 -0
- package/dist/lib/first-run.d.ts +1 -1
- package/dist/lib/first-run.d.ts.map +1 -1
- package/dist/lib/first-run.js +8 -0
- package/dist/lib/first-run.js.map +1 -1
- package/dist/lib/machine-bootstrap-prompt.d.ts +17 -0
- package/dist/lib/machine-bootstrap-prompt.d.ts.map +1 -0
- package/dist/lib/machine-bootstrap-prompt.js +426 -0
- package/dist/lib/machine-bootstrap-prompt.js.map +1 -0
- package/dist/lib/machine-projects.d.ts +71 -0
- package/dist/lib/machine-projects.d.ts.map +1 -0
- package/dist/lib/machine-projects.js +510 -0
- package/dist/lib/machine-projects.js.map +1 -0
- package/dist/lib/machine-verify.d.ts +175 -0
- package/dist/lib/machine-verify.d.ts.map +1 -0
- package/dist/lib/machine-verify.js +684 -0
- package/dist/lib/machine-verify.js.map +1 -0
- package/dist/lib/portfolio-audit.d.ts +34 -0
- package/dist/lib/portfolio-audit.d.ts.map +1 -0
- package/dist/lib/portfolio-audit.js +254 -0
- package/dist/lib/portfolio-audit.js.map +1 -0
- package/dist/lib/portfolio-graph.d.ts +104 -0
- package/dist/lib/portfolio-graph.d.ts.map +1 -0
- package/dist/lib/portfolio-graph.js +281 -0
- package/dist/lib/portfolio-graph.js.map +1 -0
- package/dist/lib/project-strategy.d.ts +45 -0
- package/dist/lib/project-strategy.d.ts.map +1 -0
- package/dist/lib/project-strategy.js +234 -0
- package/dist/lib/project-strategy.js.map +1 -0
- package/dist/lib/realtime-sync.d.ts +128 -0
- package/dist/lib/realtime-sync.d.ts.map +1 -0
- package/dist/lib/realtime-sync.js +215 -0
- package/dist/lib/realtime-sync.js.map +1 -0
- package/dist/lib/reusable-patterns.d.ts +30 -0
- package/dist/lib/reusable-patterns.d.ts.map +1 -0
- package/dist/lib/reusable-patterns.js +375 -0
- package/dist/lib/reusable-patterns.js.map +1 -0
- package/dist/lib/skill-catalog.d.ts.map +1 -1
- package/dist/lib/skill-catalog.js +20 -0
- package/dist/lib/skill-catalog.js.map +1 -1
- package/dist/lib/skills.d.ts +1 -0
- package/dist/lib/skills.d.ts.map +1 -1
- package/dist/lib/skills.js +43 -13
- package/dist/lib/skills.js.map +1 -1
- package/dist/lib/version.d.ts +2 -0
- package/dist/lib/version.d.ts.map +1 -0
- package/dist/lib/version.js +63 -0
- package/dist/lib/version.js.map +1 -0
- package/dist/mcp/registry.d.ts +5 -1
- package/dist/mcp/registry.d.ts.map +1 -1
- package/dist/mcp/registry.js +426 -2
- package/dist/mcp/registry.js.map +1 -1
- package/dist/mcp/server.d.ts +2 -0
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/mcp/server.js +50 -5
- package/dist/mcp/server.js.map +1 -1
- package/package.json +2 -1
- package/scripts/env-vault/README.md +21 -2
- package/scripts/env-vault/backup.sh +24 -1
- package/scripts/env-vault/restore.sh +123 -8
- package/scripts/skillstack-sync/README.md +35 -10
- package/scripts/skillstack-sync/bootstrap-new-mac.sh +31 -0
- package/scripts/skillstack-sync/capture-agent-config.sh +1 -0
- package/scripts/skillstack-sync/com.youmd.context-sync.plist +38 -0
- package/scripts/skillstack-sync/com.youmd.identity-sync.plist +3 -1
- package/scripts/skillstack-sync/com.youmd.realtime-sync.plist +35 -0
- package/scripts/skillstack-sync/com.youmd.skillstack-sync.plist +1 -1
- package/scripts/skillstack-sync/context-sync.sh +69 -1
- package/scripts/skillstack-sync/install-daemons.sh +10 -3
- package/skills/machine-bootstrap.md +312 -0
package/dist/mcp/registry.js
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
*
|
|
13
13
|
* ─── MIGRATION STATUS ───────────────────────────────────────────────────────
|
|
14
14
|
*
|
|
15
|
-
* MIGRATED (
|
|
15
|
+
* MIGRATED (22 tools):
|
|
16
16
|
* whoami — local bundle read, no auth required
|
|
17
17
|
* get_identity — local bundle read, compact/full/json/markdown
|
|
18
18
|
* list_skills — pure local dir scan
|
|
@@ -31,6 +31,10 @@
|
|
|
31
31
|
* get_remote_status — conditional auth branch + ctx.apiRequest
|
|
32
32
|
* use_skill — ctx.getInstalledSkills()
|
|
33
33
|
* get_activity_log — auth-gated fetch via ctx.fetchActivityLog
|
|
34
|
+
* upsert_portfolio_task — authenticated write via ctx.apiRequest
|
|
35
|
+
* update_portfolio_task — authenticated task triage via ctx.apiRequest
|
|
36
|
+
* hydrate_portfolio_graph — authenticated portfolio hydration via ctx.apiRequest
|
|
37
|
+
* record_brain_dump — authenticated write via ctx.apiRequest
|
|
34
38
|
*
|
|
35
39
|
* DEFERRED (4 tools — write-ops and dynamic-import tools):
|
|
36
40
|
* get_agent_brief — >50 lines; delegates to buildAgentBrief() in server.ts
|
|
@@ -84,6 +88,7 @@ const config_1 = require("../lib/config");
|
|
|
84
88
|
const project_1 = require("../lib/project");
|
|
85
89
|
const projectContext_1 = require("../lib/projectContext");
|
|
86
90
|
const youstack_1 = require("../lib/youstack");
|
|
91
|
+
const portfolio_graph_1 = require("../lib/portfolio-graph");
|
|
87
92
|
// ─── Shared config/helpers (duplicated here to avoid circular server.ts dep) ──
|
|
88
93
|
function _getLocalBundleDir2() { return (0, config_1.getLocalBundleDir)(); }
|
|
89
94
|
function _getHomeBundleDir2() { return (0, config_1.getHomeBundleDir)(); }
|
|
@@ -221,6 +226,19 @@ function tryLoadStack(inputPath) {
|
|
|
221
226
|
return null;
|
|
222
227
|
}
|
|
223
228
|
}
|
|
229
|
+
async function getProjectPortfolioSlice(projectName, ctx) {
|
|
230
|
+
if (ctx.authenticated) {
|
|
231
|
+
try {
|
|
232
|
+
const snapshot = await ctx.apiRequest("/api/v1/me/portfolio/graph?includeTasks=1");
|
|
233
|
+
const brief = (0, portfolio_graph_1.portfolioGraphBriefFromSnapshot)(snapshot);
|
|
234
|
+
return (0, portfolio_graph_1.getPortfolioGraphProjectSlice)(projectName, brief);
|
|
235
|
+
}
|
|
236
|
+
catch {
|
|
237
|
+
// Use the bundled fallback when the local agent is offline or unauthenticated.
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
return (0, portfolio_graph_1.getPortfolioGraphProjectSlice)(projectName);
|
|
241
|
+
}
|
|
224
242
|
// ─── Registry ─────────────────────────────────────────────────────────────────
|
|
225
243
|
exports.CLI_MCP_TOOLS = [
|
|
226
244
|
// ── whoami ──────────────────────────────────────────────────────────────────
|
|
@@ -362,11 +380,13 @@ exports.CLI_MCP_TOOLS = [
|
|
|
362
380
|
});
|
|
363
381
|
if (projectName) {
|
|
364
382
|
const ctx2 = readMergedProjectContext({ projectName });
|
|
383
|
+
const portfolioGraph = await getProjectPortfolioSlice(projectName, ctx);
|
|
365
384
|
if (!ctx2) {
|
|
366
385
|
const result = {
|
|
367
386
|
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
387
|
project: { name: projectName, source: "named" },
|
|
369
388
|
projectContext: null,
|
|
389
|
+
portfolioGraph,
|
|
370
390
|
};
|
|
371
391
|
ctx.logActivity("read", "project/" + projectName);
|
|
372
392
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }], isError: true };
|
|
@@ -375,6 +395,7 @@ exports.CLI_MCP_TOOLS = [
|
|
|
375
395
|
readiness: readiness("ready", `Project context for ${projectName} is available.`, "None needed."),
|
|
376
396
|
project: { name: projectName, source: "named" },
|
|
377
397
|
projectContext: ctx2,
|
|
398
|
+
portfolioGraph,
|
|
378
399
|
};
|
|
379
400
|
ctx.logActivity("read", "project/" + projectName);
|
|
380
401
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
@@ -392,16 +413,19 @@ exports.CLI_MCP_TOOLS = [
|
|
|
392
413
|
}
|
|
393
414
|
const finalCtx = merged;
|
|
394
415
|
const name = finalCtx?.meta?.name || current?.name || null;
|
|
416
|
+
const portfolioGraph = await getProjectPortfolioSlice(name, ctx);
|
|
395
417
|
const result = finalCtx
|
|
396
418
|
? {
|
|
397
419
|
readiness: readiness("ready", `Project context for ${name} is available.`, "None needed."),
|
|
398
420
|
project: { name, source: "current" },
|
|
399
421
|
projectContext: finalCtx,
|
|
422
|
+
portfolioGraph,
|
|
400
423
|
}
|
|
401
424
|
: {
|
|
402
425
|
readiness: readiness("not_found", "Project context could not be read.", "Use repo-local instructions and project-context markdown files directly."),
|
|
403
426
|
project: { name, source: "current" },
|
|
404
427
|
projectContext: null,
|
|
428
|
+
portfolioGraph,
|
|
405
429
|
};
|
|
406
430
|
ctx.logActivity("read", "project/current");
|
|
407
431
|
return {
|
|
@@ -642,6 +666,406 @@ exports.CLI_MCP_TOOLS = [
|
|
|
642
666
|
}
|
|
643
667
|
},
|
|
644
668
|
},
|
|
669
|
+
// ── upsert_portfolio_task ───────────────────────────────────────────────────
|
|
670
|
+
{
|
|
671
|
+
name: "upsert_portfolio_task",
|
|
672
|
+
description: "Create a project-associated or personal portfolio task for the user. Use when a local agent needs to assign work to the human or to agents and sync the task into You.md's portfolio graph/repo snapshot. Requires authentication.",
|
|
673
|
+
inputSchema: {
|
|
674
|
+
type: "object",
|
|
675
|
+
properties: {
|
|
676
|
+
title: { type: "string", description: "Task title." },
|
|
677
|
+
project: { type: "string", description: "Optional project slug/name. Omit or use personal for uncategorized personal tasks." },
|
|
678
|
+
description: { type: "string", description: "Optional task details." },
|
|
679
|
+
owner_type: { type: "string", enum: ["human", "agent"], description: "Who owns this task: human or agent." },
|
|
680
|
+
owner_label: { type: "string", description: "Optional owner label, such as Houston, Codex, Claude, or You Agent." },
|
|
681
|
+
status: { type: "string", description: "Task status: proposed, open, in_progress, done, snoozed, cancelled." },
|
|
682
|
+
priority: { type: "string", description: "Priority: low, normal, high, urgent." },
|
|
683
|
+
tags: { type: "array", items: { type: "string" }, description: "Optional searchable tags." },
|
|
684
|
+
sync_repo: { type: "boolean", description: "Whether to publish and sync the GitHub repo snapshot. Defaults true." },
|
|
685
|
+
},
|
|
686
|
+
required: ["title", "owner_type"],
|
|
687
|
+
},
|
|
688
|
+
handler: async (args, ctx) => {
|
|
689
|
+
if (!ctx.authenticated) {
|
|
690
|
+
return { content: [{ type: "text", text: "not authenticated — run youmd login first" }], isError: true };
|
|
691
|
+
}
|
|
692
|
+
const title = typeof args.title === "string" ? args.title.trim() : "";
|
|
693
|
+
if (!title) {
|
|
694
|
+
return { content: [{ type: "text", text: "missing required argument: title" }], isError: true };
|
|
695
|
+
}
|
|
696
|
+
const ownerType = args.owner_type === "human" ? "human" : "agent";
|
|
697
|
+
const body = {
|
|
698
|
+
title,
|
|
699
|
+
projectSlug: typeof args.project === "string" ? args.project : undefined,
|
|
700
|
+
description: typeof args.description === "string" ? args.description : undefined,
|
|
701
|
+
ownerType,
|
|
702
|
+
ownerLabel: typeof args.owner_label === "string" ? args.owner_label : ctx.resolveAgentName(),
|
|
703
|
+
status: typeof args.status === "string" ? args.status : "open",
|
|
704
|
+
priority: typeof args.priority === "string" ? args.priority : "normal",
|
|
705
|
+
tags: Array.isArray(args.tags) ? args.tags.filter((tag) => typeof tag === "string") : [],
|
|
706
|
+
syncRepo: args.sync_repo !== false,
|
|
707
|
+
sourceType: "mcp",
|
|
708
|
+
agentName: ctx.resolveAgentName(),
|
|
709
|
+
};
|
|
710
|
+
try {
|
|
711
|
+
const result = await ctx.apiRequest("/api/v1/me/portfolio/tasks", {
|
|
712
|
+
method: "POST",
|
|
713
|
+
body,
|
|
714
|
+
});
|
|
715
|
+
const ok = result.success === true;
|
|
716
|
+
ctx.logActivity("write", "portfolio/task", { title, project: body.projectSlug ?? "personal" });
|
|
717
|
+
return {
|
|
718
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
|
719
|
+
isError: !ok,
|
|
720
|
+
};
|
|
721
|
+
}
|
|
722
|
+
catch (err) {
|
|
723
|
+
return {
|
|
724
|
+
content: [{ type: "text", text: `failed to save portfolio task: ${err instanceof Error ? err.message : "unknown error"}` }],
|
|
725
|
+
isError: true,
|
|
726
|
+
};
|
|
727
|
+
}
|
|
728
|
+
},
|
|
729
|
+
},
|
|
730
|
+
// ── update_portfolio_task ───────────────────────────────────────────────────
|
|
731
|
+
{
|
|
732
|
+
name: "update_portfolio_task",
|
|
733
|
+
description: "Update an existing portfolio task's triage, owner, project scope, title, details, due date, or tags. Use after an agent starts, finishes, reassigns, routes, or enriches a task in You.md's persisted project graph. Requires authentication.",
|
|
734
|
+
inputSchema: {
|
|
735
|
+
type: "object",
|
|
736
|
+
properties: {
|
|
737
|
+
task_id: { type: "string", description: "Existing portfolio task id." },
|
|
738
|
+
title: { type: "string", description: "Updated task title." },
|
|
739
|
+
project: { type: ["string", "null"], description: "Updated project slug/name. Use null or personal to move to uncategorized personal tasks." },
|
|
740
|
+
description: { type: ["string", "null"], description: "Updated task details. Use null to clear." },
|
|
741
|
+
owner_type: { type: "string", enum: ["human", "agent"], description: "Who owns this task: human or agent." },
|
|
742
|
+
owner_label: { type: ["string", "null"], description: "Optional owner label, such as Houston, Codex, Claude, or You Agent. Use null to clear." },
|
|
743
|
+
status: { type: "string", enum: ["proposed", "open", "in_progress", "done", "snoozed", "cancelled"], description: "New task status." },
|
|
744
|
+
priority: { type: "string", enum: ["low", "normal", "high", "urgent"], description: "New task priority." },
|
|
745
|
+
due_at: { type: ["number", "null"], description: "Due timestamp in milliseconds. Use null to clear." },
|
|
746
|
+
tags: { type: "array", items: { type: "string" }, description: "Replacement tag list." },
|
|
747
|
+
sync_repo: { type: "boolean", description: "Whether to publish and sync the GitHub repo snapshot. Defaults true." },
|
|
748
|
+
},
|
|
749
|
+
required: ["task_id"],
|
|
750
|
+
},
|
|
751
|
+
handler: async (args, ctx) => {
|
|
752
|
+
if (!ctx.authenticated) {
|
|
753
|
+
return { content: [{ type: "text", text: "not authenticated — run youmd login first" }], isError: true };
|
|
754
|
+
}
|
|
755
|
+
const taskId = typeof args.task_id === "string" ? args.task_id.trim() : "";
|
|
756
|
+
if (!taskId) {
|
|
757
|
+
return { content: [{ type: "text", text: "missing required argument: task_id" }], isError: true };
|
|
758
|
+
}
|
|
759
|
+
const status = typeof args.status === "string" ? args.status.trim() : undefined;
|
|
760
|
+
const priority = typeof args.priority === "string" ? args.priority.trim() : undefined;
|
|
761
|
+
const body = {
|
|
762
|
+
taskId,
|
|
763
|
+
syncRepo: args.sync_repo !== false,
|
|
764
|
+
agentName: ctx.resolveAgentName(),
|
|
765
|
+
};
|
|
766
|
+
if (typeof args.title === "string")
|
|
767
|
+
body.title = args.title.trim();
|
|
768
|
+
if ("project" in args)
|
|
769
|
+
body.projectSlug = args.project === null ? null : args.project;
|
|
770
|
+
if ("description" in args)
|
|
771
|
+
body.description = args.description === null ? null : args.description;
|
|
772
|
+
if (args.owner_type === "human" || args.owner_type === "agent")
|
|
773
|
+
body.ownerType = args.owner_type;
|
|
774
|
+
if ("owner_label" in args)
|
|
775
|
+
body.ownerLabel = args.owner_label === null ? null : args.owner_label;
|
|
776
|
+
if (status)
|
|
777
|
+
body.status = status;
|
|
778
|
+
if (priority)
|
|
779
|
+
body.priority = priority;
|
|
780
|
+
if ("due_at" in args)
|
|
781
|
+
body.dueAt = args.due_at === null ? null : args.due_at;
|
|
782
|
+
if (Array.isArray(args.tags))
|
|
783
|
+
body.tags = args.tags.filter((tag) => typeof tag === "string");
|
|
784
|
+
if (Object.keys(body).length <= 3) {
|
|
785
|
+
return { content: [{ type: "text", text: "at least one task field is required" }], isError: true };
|
|
786
|
+
}
|
|
787
|
+
try {
|
|
788
|
+
const result = await ctx.apiRequest("/api/v1/me/portfolio/tasks/update", {
|
|
789
|
+
method: "POST",
|
|
790
|
+
body,
|
|
791
|
+
});
|
|
792
|
+
const ok = result.success === true;
|
|
793
|
+
ctx.logActivity("write", "portfolio/task-update", { taskId, fields: Object.keys(body).filter((field) => !["taskId", "syncRepo", "agentName"].includes(field)) });
|
|
794
|
+
return {
|
|
795
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
|
796
|
+
isError: !ok,
|
|
797
|
+
};
|
|
798
|
+
}
|
|
799
|
+
catch (err) {
|
|
800
|
+
return {
|
|
801
|
+
content: [{ type: "text", text: `failed to update portfolio task: ${err instanceof Error ? err.message : "unknown error"}` }],
|
|
802
|
+
isError: true,
|
|
803
|
+
};
|
|
804
|
+
}
|
|
805
|
+
},
|
|
806
|
+
},
|
|
807
|
+
// ── hydrate_portfolio_graph ────────────────────────────────────────────────
|
|
808
|
+
{
|
|
809
|
+
name: "hydrate_portfolio_graph",
|
|
810
|
+
description: "Hydrate the persisted You.md Portfolio Graph from the authenticated recent GitHub project catalog. Use after refreshing/analyzing active projects so the Portfolio Graph is not stuck on bootstrap seed rows.",
|
|
811
|
+
inputSchema: {
|
|
812
|
+
type: "object",
|
|
813
|
+
properties: {
|
|
814
|
+
days: { type: "number", description: "Recent activity window in days. Defaults to 90." },
|
|
815
|
+
limit: { type: "number", description: "Maximum tracked projects to hydrate. Defaults to 80." },
|
|
816
|
+
include_github: { type: "boolean", description: "Whether to hydrate from tracked GitHub projects. Defaults true." },
|
|
817
|
+
},
|
|
818
|
+
},
|
|
819
|
+
handler: async (args, ctx) => {
|
|
820
|
+
if (!ctx.authenticated) {
|
|
821
|
+
return { content: [{ type: "text", text: "not authenticated — run youmd login first" }], isError: true };
|
|
822
|
+
}
|
|
823
|
+
const days = typeof args.days === "number" && Number.isFinite(args.days) ? args.days : 90;
|
|
824
|
+
const limit = typeof args.limit === "number" && Number.isFinite(args.limit) ? args.limit : 80;
|
|
825
|
+
try {
|
|
826
|
+
const result = await ctx.apiRequest("/api/v1/me/portfolio/projects/hydrate", {
|
|
827
|
+
method: "POST",
|
|
828
|
+
body: {
|
|
829
|
+
includeTracked: args.include_github !== false,
|
|
830
|
+
days,
|
|
831
|
+
limit,
|
|
832
|
+
projects: [],
|
|
833
|
+
source: "mcp-portfolio-hydrate",
|
|
834
|
+
agentName: ctx.resolveAgentName(),
|
|
835
|
+
},
|
|
836
|
+
});
|
|
837
|
+
const ok = result.success === true;
|
|
838
|
+
ctx.logActivity("write", "portfolio/projects", { days, limit });
|
|
839
|
+
return {
|
|
840
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
|
841
|
+
isError: !ok,
|
|
842
|
+
};
|
|
843
|
+
}
|
|
844
|
+
catch (err) {
|
|
845
|
+
return {
|
|
846
|
+
content: [{ type: "text", text: `failed to hydrate portfolio graph: ${err instanceof Error ? err.message : "unknown error"}` }],
|
|
847
|
+
isError: true,
|
|
848
|
+
};
|
|
849
|
+
}
|
|
850
|
+
},
|
|
851
|
+
},
|
|
852
|
+
// ── upsert_portfolio_project ───────────────────────────────────────────────
|
|
853
|
+
{
|
|
854
|
+
name: "upsert_portfolio_project",
|
|
855
|
+
description: "Create or update a project strategy/intelligence record in You.md's persisted Portfolio Graph. Use before adding APIs/MCPs/stacks/tasks so agents share the same goal, vision, pain points, constraints, non-goals, metrics, repo, and docs context.",
|
|
856
|
+
inputSchema: {
|
|
857
|
+
type: "object",
|
|
858
|
+
properties: {
|
|
859
|
+
name: { type: "string", description: "Project display name." },
|
|
860
|
+
slug: { type: "string", description: "Stable project slug." },
|
|
861
|
+
stack_name: { type: "string", description: "Associated stack name, such as YouStack or BAMFStack." },
|
|
862
|
+
status: { type: "string", description: "Project status, such as active, build, research, template, or audit." },
|
|
863
|
+
summary: { type: "string", description: "Short AI/human summary." },
|
|
864
|
+
detailed_description: { type: "string", description: "Longer project description." },
|
|
865
|
+
goal: { type: "string", description: "High-level goal." },
|
|
866
|
+
vision: { type: "string", description: "North-star vision." },
|
|
867
|
+
focus: { type: "string", description: "Current focus." },
|
|
868
|
+
positioning: { type: "string", description: "Positioning/category." },
|
|
869
|
+
audience: { type: "string", description: "Who this is for." },
|
|
870
|
+
pain_points: { type: "array", items: { type: "string" }, description: "Pain points solved." },
|
|
871
|
+
solution: { type: "string", description: "Solution summary." },
|
|
872
|
+
why_this_solution: { type: "string", description: "Why this solution is right." },
|
|
873
|
+
north_star: { type: "string", description: "North-star metric or guiding outcome." },
|
|
874
|
+
metrics: { type: "array", items: { type: "string" }, description: "Metrics to track." },
|
|
875
|
+
constraints: { type: "array", items: { type: "string" }, description: "Constraints/guardrails." },
|
|
876
|
+
not_building: { type: "array", items: { type: "string" }, description: "Explicit non-goals." },
|
|
877
|
+
competitors: {
|
|
878
|
+
type: "array",
|
|
879
|
+
description: "Alternatives or competitors to track.",
|
|
880
|
+
items: {
|
|
881
|
+
type: "object",
|
|
882
|
+
properties: {
|
|
883
|
+
name: { type: "string" },
|
|
884
|
+
url: { type: "string" },
|
|
885
|
+
note: { type: "string" },
|
|
886
|
+
},
|
|
887
|
+
required: ["name"],
|
|
888
|
+
},
|
|
889
|
+
},
|
|
890
|
+
repo_full_name: { type: "string", description: "GitHub repo full name, owner/repo." },
|
|
891
|
+
repo_url: { type: "string", description: "Repository URL." },
|
|
892
|
+
product_url: { type: "string", description: "Product/site URL." },
|
|
893
|
+
docs: { type: "array", items: { type: "string" }, description: "Important docs paths or URLs." },
|
|
894
|
+
environments: { type: "array", items: { type: "string" }, description: "Known environments." },
|
|
895
|
+
tags: { type: "array", items: { type: "string" }, description: "Search/routing tags." },
|
|
896
|
+
repo_path: { type: "string", description: "Local repo path or directory name." },
|
|
897
|
+
},
|
|
898
|
+
required: ["name"],
|
|
899
|
+
},
|
|
900
|
+
handler: async (args, ctx) => {
|
|
901
|
+
if (!ctx.authenticated) {
|
|
902
|
+
return { content: [{ type: "text", text: "not authenticated — run youmd login first" }], isError: true };
|
|
903
|
+
}
|
|
904
|
+
const name = typeof args.name === "string" ? args.name.trim() : "";
|
|
905
|
+
if (!name) {
|
|
906
|
+
return { content: [{ type: "text", text: "missing required argument: name" }], isError: true };
|
|
907
|
+
}
|
|
908
|
+
const stringArray = (value) => Array.isArray(value) ? value.filter((item) => typeof item === "string" && item.trim().length > 0) : [];
|
|
909
|
+
const competitors = Array.isArray(args.competitors)
|
|
910
|
+
? args.competitors.flatMap((item) => {
|
|
911
|
+
if (!item || typeof item !== "object")
|
|
912
|
+
return [];
|
|
913
|
+
const row = item;
|
|
914
|
+
const competitorName = typeof row.name === "string" ? row.name.trim() : "";
|
|
915
|
+
if (!competitorName)
|
|
916
|
+
return [];
|
|
917
|
+
return [{
|
|
918
|
+
name: competitorName,
|
|
919
|
+
url: typeof row.url === "string" ? row.url : undefined,
|
|
920
|
+
note: typeof row.note === "string" ? row.note : undefined,
|
|
921
|
+
}];
|
|
922
|
+
})
|
|
923
|
+
: [];
|
|
924
|
+
const project = {
|
|
925
|
+
name,
|
|
926
|
+
slug: typeof args.slug === "string" ? args.slug : undefined,
|
|
927
|
+
stackName: typeof args.stack_name === "string" ? args.stack_name : undefined,
|
|
928
|
+
status: typeof args.status === "string" ? args.status : "active",
|
|
929
|
+
summary: typeof args.summary === "string" ? args.summary : undefined,
|
|
930
|
+
detailedDescription: typeof args.detailed_description === "string" ? args.detailed_description : undefined,
|
|
931
|
+
goal: typeof args.goal === "string" ? args.goal : undefined,
|
|
932
|
+
vision: typeof args.vision === "string" ? args.vision : undefined,
|
|
933
|
+
focus: typeof args.focus === "string" ? args.focus : undefined,
|
|
934
|
+
positioning: typeof args.positioning === "string" ? args.positioning : undefined,
|
|
935
|
+
audience: typeof args.audience === "string" ? args.audience : undefined,
|
|
936
|
+
painPoints: stringArray(args.pain_points),
|
|
937
|
+
solution: typeof args.solution === "string" ? args.solution : undefined,
|
|
938
|
+
whyThisSolution: typeof args.why_this_solution === "string" ? args.why_this_solution : undefined,
|
|
939
|
+
northStar: typeof args.north_star === "string" ? args.north_star : undefined,
|
|
940
|
+
metrics: stringArray(args.metrics),
|
|
941
|
+
constraints: stringArray(args.constraints),
|
|
942
|
+
notBuilding: stringArray(args.not_building),
|
|
943
|
+
competitors,
|
|
944
|
+
repoFullName: typeof args.repo_full_name === "string" ? args.repo_full_name : undefined,
|
|
945
|
+
repoUrl: typeof args.repo_url === "string" ? args.repo_url : undefined,
|
|
946
|
+
productUrl: typeof args.product_url === "string" ? args.product_url : undefined,
|
|
947
|
+
docs: stringArray(args.docs),
|
|
948
|
+
environments: stringArray(args.environments),
|
|
949
|
+
tags: stringArray(args.tags),
|
|
950
|
+
path: typeof args.repo_path === "string" ? args.repo_path : undefined,
|
|
951
|
+
};
|
|
952
|
+
try {
|
|
953
|
+
const result = await ctx.apiRequest("/api/v1/me/portfolio/projects/hydrate", {
|
|
954
|
+
method: "POST",
|
|
955
|
+
body: {
|
|
956
|
+
includeTracked: false,
|
|
957
|
+
projects: [project],
|
|
958
|
+
source: "mcp-project-enrichment",
|
|
959
|
+
agentName: ctx.resolveAgentName(),
|
|
960
|
+
},
|
|
961
|
+
});
|
|
962
|
+
const ok = result.success === true;
|
|
963
|
+
ctx.logActivity("write", "portfolio/project", { name, slug: project.slug });
|
|
964
|
+
return {
|
|
965
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
|
966
|
+
isError: !ok,
|
|
967
|
+
};
|
|
968
|
+
}
|
|
969
|
+
catch (err) {
|
|
970
|
+
return {
|
|
971
|
+
content: [{ type: "text", text: `failed to upsert portfolio project: ${err instanceof Error ? err.message : "unknown error"}` }],
|
|
972
|
+
isError: true,
|
|
973
|
+
};
|
|
974
|
+
}
|
|
975
|
+
},
|
|
976
|
+
},
|
|
977
|
+
// ── record_brain_dump ───────────────────────────────────────────────────────
|
|
978
|
+
{
|
|
979
|
+
name: "record_brain_dump",
|
|
980
|
+
description: "Save a raw brain dump, route it to projects/tags, and optionally create proposed human/agent tasks. Use for pasted notes, terminal thoughts, SMS/watch transcripts, and local-agent research that should not die in one-off files. Requires authentication.",
|
|
981
|
+
inputSchema: {
|
|
982
|
+
type: "object",
|
|
983
|
+
properties: {
|
|
984
|
+
raw_text: { type: "string", description: "Raw unedited brain dump or transcript text." },
|
|
985
|
+
summary: { type: "string", description: "Short summary. Omit to let the API derive one." },
|
|
986
|
+
projects: { type: "array", items: { type: "string" }, description: "Related project slugs/names." },
|
|
987
|
+
tags: { type: "array", items: { type: "string" }, description: "Topic tags." },
|
|
988
|
+
insights: { type: "array", items: { type: "string" }, description: "Interesting insights or through-lines." },
|
|
989
|
+
source: { type: "string", description: "Capture source: mcp, cli, sms, watch, badapp, shell, manual." },
|
|
990
|
+
tasks: {
|
|
991
|
+
type: "array",
|
|
992
|
+
description: "Optional proposed tasks extracted from the dump.",
|
|
993
|
+
items: {
|
|
994
|
+
type: "object",
|
|
995
|
+
properties: {
|
|
996
|
+
title: { type: "string" },
|
|
997
|
+
projectSlug: { type: "string" },
|
|
998
|
+
description: { type: "string" },
|
|
999
|
+
ownerType: { type: "string", enum: ["human", "agent"] },
|
|
1000
|
+
ownerLabel: { type: "string" },
|
|
1001
|
+
priority: { type: "string" },
|
|
1002
|
+
tags: { type: "array", items: { type: "string" } },
|
|
1003
|
+
},
|
|
1004
|
+
required: ["title", "ownerType"],
|
|
1005
|
+
},
|
|
1006
|
+
},
|
|
1007
|
+
sync_repo: { type: "boolean", description: "Whether to publish and sync the GitHub repo snapshot. Defaults true." },
|
|
1008
|
+
},
|
|
1009
|
+
required: ["raw_text"],
|
|
1010
|
+
},
|
|
1011
|
+
handler: async (args, ctx) => {
|
|
1012
|
+
if (!ctx.authenticated) {
|
|
1013
|
+
return { content: [{ type: "text", text: "not authenticated — run youmd login first" }], isError: true };
|
|
1014
|
+
}
|
|
1015
|
+
const rawText = typeof args.raw_text === "string" ? args.raw_text.trim() : "";
|
|
1016
|
+
if (!rawText) {
|
|
1017
|
+
return { content: [{ type: "text", text: "missing required argument: raw_text" }], isError: true };
|
|
1018
|
+
}
|
|
1019
|
+
const arrayOfStrings = (value) => Array.isArray(value) ? value.filter((item) => typeof item === "string") : [];
|
|
1020
|
+
const tasks = Array.isArray(args.tasks)
|
|
1021
|
+
? args.tasks
|
|
1022
|
+
.map((task) => typeof task === "object" && task !== null ? task : null)
|
|
1023
|
+
.filter((task) => task !== null && typeof task.title === "string")
|
|
1024
|
+
.map((task) => ({
|
|
1025
|
+
title: String(task.title),
|
|
1026
|
+
projectSlug: typeof task.projectSlug === "string" ? task.projectSlug : undefined,
|
|
1027
|
+
description: typeof task.description === "string" ? task.description : undefined,
|
|
1028
|
+
ownerType: task.ownerType === "human" ? "human" : "agent",
|
|
1029
|
+
ownerLabel: typeof task.ownerLabel === "string" ? task.ownerLabel : ctx.resolveAgentName(),
|
|
1030
|
+
priority: typeof task.priority === "string" ? task.priority : "normal",
|
|
1031
|
+
tags: arrayOfStrings(task.tags),
|
|
1032
|
+
}))
|
|
1033
|
+
: [];
|
|
1034
|
+
const body = {
|
|
1035
|
+
rawText,
|
|
1036
|
+
summary: typeof args.summary === "string" ? args.summary : undefined,
|
|
1037
|
+
projectSlugs: arrayOfStrings(args.projects),
|
|
1038
|
+
tags: arrayOfStrings(args.tags),
|
|
1039
|
+
insights: arrayOfStrings(args.insights),
|
|
1040
|
+
source: typeof args.source === "string" ? args.source : "mcp",
|
|
1041
|
+
tasks,
|
|
1042
|
+
syncRepo: args.sync_repo !== false,
|
|
1043
|
+
agentName: ctx.resolveAgentName(),
|
|
1044
|
+
metadata: {
|
|
1045
|
+
command: "record_brain_dump",
|
|
1046
|
+
savedFrom: "cli-mcp",
|
|
1047
|
+
},
|
|
1048
|
+
};
|
|
1049
|
+
try {
|
|
1050
|
+
const result = await ctx.apiRequest("/api/v1/me/portfolio/brain-dumps", {
|
|
1051
|
+
method: "POST",
|
|
1052
|
+
body,
|
|
1053
|
+
});
|
|
1054
|
+
const ok = result.success === true;
|
|
1055
|
+
ctx.logActivity("write", "portfolio/brain-dump", { projects: body.projectSlugs, taskCount: tasks.length });
|
|
1056
|
+
return {
|
|
1057
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
|
1058
|
+
isError: !ok,
|
|
1059
|
+
};
|
|
1060
|
+
}
|
|
1061
|
+
catch (err) {
|
|
1062
|
+
return {
|
|
1063
|
+
content: [{ type: "text", text: `failed to save brain dump: ${err instanceof Error ? err.message : "unknown error"}` }],
|
|
1064
|
+
isError: true,
|
|
1065
|
+
};
|
|
1066
|
+
}
|
|
1067
|
+
},
|
|
1068
|
+
},
|
|
645
1069
|
// ── add_source ───────────────────────────────────────────────────────────────
|
|
646
1070
|
{
|
|
647
1071
|
name: "add_source",
|
|
@@ -760,7 +1184,7 @@ exports.CLI_MCP_TOOLS = [
|
|
|
760
1184
|
properties: {
|
|
761
1185
|
name: {
|
|
762
1186
|
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",
|
|
1187
|
+
description: "Skill name: youstack-start, youstack-maintainer, machine-bootstrap, portfolio-graph-auditor, voice-sync, claude-md-generator, project-context-init, meta-improve, proactive-context-fill, you-logs",
|
|
764
1188
|
},
|
|
765
1189
|
},
|
|
766
1190
|
required: ["name"],
|