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
package/dist/commands/chat.js
CHANGED
|
@@ -44,10 +44,12 @@ const path = __importStar(require("path"));
|
|
|
44
44
|
const chalk_1 = __importDefault(require("chalk"));
|
|
45
45
|
const config_1 = require("../lib/config");
|
|
46
46
|
const project_1 = require("../lib/project");
|
|
47
|
+
const projectContext_1 = require("../lib/projectContext");
|
|
47
48
|
const compiler_1 = require("../lib/compiler");
|
|
48
49
|
const api_1 = require("../lib/api");
|
|
49
50
|
const skills_1 = require("../lib/skills");
|
|
50
51
|
const render_1 = require("../lib/render");
|
|
52
|
+
const stream_1 = require("../lib/stream");
|
|
51
53
|
const onboarding_1 = require("../lib/onboarding");
|
|
52
54
|
const ascii_1 = require("../lib/ascii");
|
|
53
55
|
const update_1 = require("../lib/update");
|
|
@@ -55,122 +57,25 @@ const update_1 = require("../lib/update");
|
|
|
55
57
|
const config_2 = require("../lib/config");
|
|
56
58
|
const CONVEX_SITE_URL = (0, config_2.getConvexSiteUrl)();
|
|
57
59
|
const STREAM_URL = `${CONVEX_SITE_URL}/api/v1/chat/stream`;
|
|
58
|
-
const CURRENT_VERSION = "0.6.
|
|
59
|
-
function delay(ms) {
|
|
60
|
-
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
61
|
-
}
|
|
60
|
+
const CURRENT_VERSION = "0.6.23";
|
|
62
61
|
// ─── Streaming LLM client ─────────────────────────────────────────────
|
|
63
|
-
async function streamLLM(_apiKey, messages, onToken) {
|
|
64
|
-
const res = await fetch(STREAM_URL, {
|
|
65
|
-
method: "POST",
|
|
66
|
-
headers: { "Content-Type": "application/json" },
|
|
67
|
-
body: JSON.stringify({ messages }),
|
|
68
|
-
signal: AbortSignal.timeout(120000),
|
|
69
|
-
});
|
|
70
|
-
if (!res.ok) {
|
|
71
|
-
const body = await res.text();
|
|
72
|
-
throw new Error(`Stream error (${res.status}): ${body}`);
|
|
73
|
-
}
|
|
74
|
-
if (!res.body) {
|
|
75
|
-
throw new Error("No response body from stream endpoint");
|
|
76
|
-
}
|
|
77
|
-
const reader = res.body.getReader();
|
|
78
|
-
const decoder = new TextDecoder();
|
|
79
|
-
let fullText = "";
|
|
80
|
-
let buffer = "";
|
|
81
|
-
while (true) {
|
|
82
|
-
const { done, value } = await reader.read();
|
|
83
|
-
if (done)
|
|
84
|
-
break;
|
|
85
|
-
buffer += decoder.decode(value, { stream: true });
|
|
86
|
-
// Process complete SSE lines
|
|
87
|
-
const lines = buffer.split("\n");
|
|
88
|
-
// Keep the last potentially incomplete line in the buffer
|
|
89
|
-
buffer = lines.pop() || "";
|
|
90
|
-
for (const line of lines) {
|
|
91
|
-
const trimmed = line.trim();
|
|
92
|
-
if (!trimmed)
|
|
93
|
-
continue;
|
|
94
|
-
if (trimmed.startsWith("data: ")) {
|
|
95
|
-
const data = trimmed.slice(6);
|
|
96
|
-
if (data === "[DONE]") {
|
|
97
|
-
continue;
|
|
98
|
-
}
|
|
99
|
-
try {
|
|
100
|
-
const parsed = JSON.parse(data);
|
|
101
|
-
if (parsed.text) {
|
|
102
|
-
fullText += parsed.text;
|
|
103
|
-
onToken(parsed.text);
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
catch {
|
|
107
|
-
// Skip malformed JSON chunks
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
// Process any remaining buffer
|
|
113
|
-
if (buffer.trim()) {
|
|
114
|
-
const trimmed = buffer.trim();
|
|
115
|
-
if (trimmed.startsWith("data: ")) {
|
|
116
|
-
const data = trimmed.slice(6);
|
|
117
|
-
if (data !== "[DONE]") {
|
|
118
|
-
try {
|
|
119
|
-
const parsed = JSON.parse(data);
|
|
120
|
-
if (parsed.text) {
|
|
121
|
-
fullText += parsed.text;
|
|
122
|
-
onToken(parsed.text);
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
catch {
|
|
126
|
-
// Skip
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
return fullText;
|
|
132
|
-
}
|
|
133
62
|
/**
|
|
134
|
-
* Call LLM with streaming
|
|
135
|
-
*
|
|
63
|
+
* Call LLM with streaming (shared helper: spinner until first token, then
|
|
64
|
+
* live tokens with ```json directive blocks filtered from the display),
|
|
65
|
+
* falling back to blocking callLLM on failure.
|
|
66
|
+
*
|
|
67
|
+
* Returns the full RAW response text — directive blocks intact — so the
|
|
68
|
+
* post-stream parsers (parseUpdatesFromResponse, parseMemorySaves,
|
|
69
|
+
* parsePrivateUpdates, parseProjectUpdates) keep working unchanged.
|
|
136
70
|
*/
|
|
137
71
|
async function callLLMWithStreaming(apiKey, messages, spinnerLabel) {
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
thinkSpinner.stop();
|
|
146
|
-
process.stdout.write(" ");
|
|
147
|
-
firstToken = false;
|
|
148
|
-
}
|
|
149
|
-
process.stdout.write(token);
|
|
150
|
-
});
|
|
151
|
-
if (!firstToken) {
|
|
152
|
-
// We streamed something -- add trailing newline
|
|
153
|
-
process.stdout.write("\n");
|
|
154
|
-
}
|
|
155
|
-
else {
|
|
156
|
-
// No tokens received -- clear spinner
|
|
157
|
-
thinkSpinner.stop();
|
|
158
|
-
}
|
|
159
|
-
return { text: response, streamed: !firstToken };
|
|
160
|
-
}
|
|
161
|
-
catch {
|
|
162
|
-
// Streaming failed -- fall back to blocking call
|
|
163
|
-
thinkSpinner.update("streaming unavailable, waiting for response");
|
|
164
|
-
try {
|
|
165
|
-
const response = await (0, onboarding_1.callLLM)(apiKey, messages);
|
|
166
|
-
thinkSpinner.stop();
|
|
167
|
-
return { text: response, streamed: false };
|
|
168
|
-
}
|
|
169
|
-
catch (err) {
|
|
170
|
-
thinkSpinner.fail(err instanceof Error ? err.message : "failed");
|
|
171
|
-
throw err;
|
|
172
|
-
}
|
|
173
|
-
}
|
|
72
|
+
return (0, stream_1.streamAssistantTurn)({
|
|
73
|
+
streamUrl: STREAM_URL,
|
|
74
|
+
messages,
|
|
75
|
+
spinnerLabel,
|
|
76
|
+
timeoutMs: 120000,
|
|
77
|
+
fallback: () => (0, onboarding_1.callLLM)(apiKey, messages),
|
|
78
|
+
});
|
|
174
79
|
}
|
|
175
80
|
function detectSourcesInMessage(text) {
|
|
176
81
|
const sources = [];
|
|
@@ -210,7 +115,7 @@ function detectSourcesInMessage(text) {
|
|
|
210
115
|
}
|
|
211
116
|
const bareDomainRegex = /(?<![/\w])([a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?\.(?:com|co|io|ai|dev|org|net|app|xyz|me)(?:\/[^\s<>"']*)?)/gi;
|
|
212
117
|
while ((match = bareDomainRegex.exec(text)) !== null) {
|
|
213
|
-
|
|
118
|
+
const domain = match[1].replace(/[.,;:)\]]+$/, "");
|
|
214
119
|
if (domain.includes("x.com") || domain.includes("github.com") || domain.includes("linkedin.com"))
|
|
215
120
|
continue;
|
|
216
121
|
const url = `https://${domain}`;
|
|
@@ -541,7 +446,7 @@ function loadCurrentBundle(bundleDir) {
|
|
|
541
446
|
{ dir: "profile", label: "Profile" },
|
|
542
447
|
{ dir: "preferences", label: "Preferences" },
|
|
543
448
|
];
|
|
544
|
-
for (const { dir
|
|
449
|
+
for (const { dir } of dirs) {
|
|
545
450
|
const dirPath = path.join(bundleDir, dir);
|
|
546
451
|
if (!fs.existsSync(dirPath))
|
|
547
452
|
continue;
|
|
@@ -605,8 +510,8 @@ function showStatus(bundleDir) {
|
|
|
605
510
|
console.log(chalk_1.default.dim(" authenticated: " + ((0, config_1.isAuthenticated)() ? "yes" : "no")));
|
|
606
511
|
console.log("");
|
|
607
512
|
}
|
|
608
|
-
function showLinkInfo(
|
|
609
|
-
// Try to read username from the
|
|
513
|
+
function showLinkInfo() {
|
|
514
|
+
// Try to read username from the config
|
|
610
515
|
const config = (0, config_1.readGlobalConfig)();
|
|
611
516
|
const username = config.username || "your-username";
|
|
612
517
|
console.log("");
|
|
@@ -881,9 +786,6 @@ function readDisplayName(bundleDir) {
|
|
|
881
786
|
}
|
|
882
787
|
return (0, config_1.readGlobalConfig)().username || "friend";
|
|
883
788
|
}
|
|
884
|
-
function getRecentProjectNames(limit = 3) {
|
|
885
|
-
return (0, project_1.getRecentProjectInsights)(process.cwd(), limit).map((item) => item.name);
|
|
886
|
-
}
|
|
887
789
|
async function printUpdateHint() {
|
|
888
790
|
const latest = await (0, update_1.checkForCliUpdate)(CURRENT_VERSION);
|
|
889
791
|
if (!latest)
|
|
@@ -969,6 +871,34 @@ function collectHomeAgentSignals() {
|
|
|
969
871
|
}
|
|
970
872
|
return findings;
|
|
971
873
|
}
|
|
874
|
+
function scoreProjectActionItem(item) {
|
|
875
|
+
const lower = item.toLowerCase();
|
|
876
|
+
let score = 0;
|
|
877
|
+
if (lower.includes("trusted publishing") || (lower.includes("publish") && lower.includes("blocked")))
|
|
878
|
+
score += 80;
|
|
879
|
+
if (lower.includes("configure") || lower.includes("unblock") || lower.includes("blocker"))
|
|
880
|
+
score += 40;
|
|
881
|
+
if (lower.includes("publish") || lower.includes("npm"))
|
|
882
|
+
score += 25;
|
|
883
|
+
if (lower.includes("verify") || lower.includes("test") || lower.includes("qa"))
|
|
884
|
+
score += 15;
|
|
885
|
+
if (lower.includes("build") || lower.includes("proactive") || lower.includes("first-run"))
|
|
886
|
+
score += 10;
|
|
887
|
+
return score;
|
|
888
|
+
}
|
|
889
|
+
function rankProjectActionItems(items) {
|
|
890
|
+
return items
|
|
891
|
+
.map((item, index) => ({ item, index, score: scoreProjectActionItem(item) }))
|
|
892
|
+
.sort((a, b) => b.score - a.score || a.index - b.index)
|
|
893
|
+
.map((entry) => entry.item);
|
|
894
|
+
}
|
|
895
|
+
function shortenActionItem(item, maxChars = 240) {
|
|
896
|
+
if (item.length <= maxChars)
|
|
897
|
+
return item;
|
|
898
|
+
const boundary = item.lastIndexOf(" ", maxChars - 1);
|
|
899
|
+
const end = boundary > 90 ? boundary : maxChars - 1;
|
|
900
|
+
return `${item.slice(0, end).trim()}...`;
|
|
901
|
+
}
|
|
972
902
|
async function runYouLaunchInvestigation(bundleDir, projectCtx, recentProjects) {
|
|
973
903
|
const labels = [
|
|
974
904
|
"sipping bitbucks frappaccino while i look around",
|
|
@@ -988,7 +918,6 @@ async function runYouLaunchInvestigation(bundleDir, projectCtx, recentProjects)
|
|
|
988
918
|
}, 1100);
|
|
989
919
|
spinner.start();
|
|
990
920
|
try {
|
|
991
|
-
await delay(600);
|
|
992
921
|
try {
|
|
993
922
|
const hasPreferences = fs.existsSync(path.join(bundleDir, "preferences", "agent.md"));
|
|
994
923
|
const hasDirectives = fs.existsSync(path.join(bundleDir, "directives", "agent.md"));
|
|
@@ -1002,8 +931,6 @@ async function runYouLaunchInvestigation(bundleDir, projectCtx, recentProjects)
|
|
|
1002
931
|
catch {
|
|
1003
932
|
// keep scanning other surfaces
|
|
1004
933
|
}
|
|
1005
|
-
const homeSignals = collectHomeAgentSignals();
|
|
1006
|
-
findings.push(...homeSignals.slice(0, 3));
|
|
1007
934
|
if (projectCtx) {
|
|
1008
935
|
try {
|
|
1009
936
|
const hasAgents = fs.existsSync(path.join(projectCtx.root, "AGENTS.md"));
|
|
@@ -1025,18 +952,30 @@ async function runYouLaunchInvestigation(bundleDir, projectCtx, recentProjects)
|
|
|
1025
952
|
else {
|
|
1026
953
|
findings.push(`${projectCtx.name} still wants a real project-context spine.`);
|
|
1027
954
|
}
|
|
955
|
+
const actionItems = extractProjectActionItems(projectCtx.root);
|
|
956
|
+
strongestProject = {
|
|
957
|
+
name: projectCtx.name,
|
|
958
|
+
slug: projectCtx.name,
|
|
959
|
+
projectDir: projectCtx.root,
|
|
960
|
+
updatedAt: Date.now(),
|
|
961
|
+
signals: (0, project_1.getProjectMarkerSignals)(projectCtx.root),
|
|
962
|
+
summary: `${projectCtx.name} is the current working repo.`,
|
|
963
|
+
suggestedCommand: `cd ${projectCtx.root} && you`,
|
|
964
|
+
};
|
|
1028
965
|
if (repoNeedsBootstrap(projectCtx.root)) {
|
|
1029
966
|
strongestMove = `${projectCtx.name} still wants cleaner agent wiring and project-context scaffolding.`;
|
|
1030
967
|
strongestCommand = "youmd skill init-project";
|
|
1031
|
-
strongestProject =
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
968
|
+
strongestProject.signals = ["still wants cleaner agent wiring and project-context scaffolding"];
|
|
969
|
+
strongestProject.summary = `${projectCtx.name} still wants cleaner agent wiring and project-context scaffolding.`;
|
|
970
|
+
strongestProject.suggestedCommand = "youmd skill init-project";
|
|
971
|
+
}
|
|
972
|
+
else if (actionItems.length > 0) {
|
|
973
|
+
strongestMove = actionItems[0];
|
|
974
|
+
strongestProject.signals = actionItems.slice(0, 3);
|
|
975
|
+
strongestProject.summary = actionItems[0];
|
|
976
|
+
}
|
|
977
|
+
else {
|
|
978
|
+
strongestMove = `read ${projectCtx.name}'s project-context and pick the next concrete release-quality fix from actual repo state.`;
|
|
1040
979
|
}
|
|
1041
980
|
}
|
|
1042
981
|
catch {
|
|
@@ -1064,7 +1003,8 @@ async function runYouLaunchInvestigation(bundleDir, projectCtx, recentProjects)
|
|
|
1064
1003
|
else {
|
|
1065
1004
|
findings.push("i've got your home bundle loaded, even though we're not inside a project yet.");
|
|
1066
1005
|
}
|
|
1067
|
-
|
|
1006
|
+
const homeSignals = collectHomeAgentSignals();
|
|
1007
|
+
findings.push(...homeSignals.slice(0, 2));
|
|
1068
1008
|
spinner.stop("looked through local context");
|
|
1069
1009
|
return {
|
|
1070
1010
|
findings: findings.slice(0, 3),
|
|
@@ -1155,6 +1095,9 @@ function buildYouLaunchIntro(projectCtx, bundleDir, investigation) {
|
|
|
1155
1095
|
|| (projectCtx && repoNeedsBootstrap(projectCtx.root)
|
|
1156
1096
|
? `${projectCtx.name} still wants cleaner agent wiring and project-context scaffolding.`
|
|
1157
1097
|
: null)
|
|
1098
|
+
|| (projectCtx
|
|
1099
|
+
? `read ${projectCtx.name}'s project-context and pick the next concrete release-quality fix from actual repo state.`
|
|
1100
|
+
: null)
|
|
1158
1101
|
|| (0, project_1.getTopProjectOpportunity)(recentInsights)?.summary
|
|
1159
1102
|
|| null;
|
|
1160
1103
|
if (strongestMove) {
|
|
@@ -1181,6 +1124,19 @@ function isStartThereIntent(input) {
|
|
|
1181
1124
|
"start",
|
|
1182
1125
|
].includes(lower);
|
|
1183
1126
|
}
|
|
1127
|
+
function isContinueNextMoveIntent(input) {
|
|
1128
|
+
const lower = input.toLowerCase().trim().replace(/[.!?]+$/, "");
|
|
1129
|
+
return [
|
|
1130
|
+
"continue",
|
|
1131
|
+
"keep going",
|
|
1132
|
+
"more",
|
|
1133
|
+
"next",
|
|
1134
|
+
"what next",
|
|
1135
|
+
"what should i do next",
|
|
1136
|
+
"next strongest move",
|
|
1137
|
+
"do the next strongest move",
|
|
1138
|
+
].includes(lower);
|
|
1139
|
+
}
|
|
1184
1140
|
function isLocalRecentProjectsIntent(input) {
|
|
1185
1141
|
const lower = input.toLowerCase();
|
|
1186
1142
|
const mentionsLocalWork = lower.includes("local director") ||
|
|
@@ -1331,7 +1287,7 @@ function formatProjectBootstrapToolResult(project, result) {
|
|
|
1331
1287
|
].join("\n");
|
|
1332
1288
|
}
|
|
1333
1289
|
function isLocalToolLoopCandidate(input) {
|
|
1334
|
-
if (isStartThereIntent(input) || isLocalRecentProjectsIntent(input))
|
|
1290
|
+
if (isStartThereIntent(input) || isContinueNextMoveIntent(input) || isLocalRecentProjectsIntent(input))
|
|
1335
1291
|
return true;
|
|
1336
1292
|
const lower = input.toLowerCase();
|
|
1337
1293
|
return [
|
|
@@ -1355,6 +1311,8 @@ function isLocalToolLoopCandidate(input) {
|
|
|
1355
1311
|
"publish identity",
|
|
1356
1312
|
"publish my identity",
|
|
1357
1313
|
"push my identity",
|
|
1314
|
+
"what next",
|
|
1315
|
+
"next strongest move",
|
|
1358
1316
|
].some((phrase) => lower.includes(phrase));
|
|
1359
1317
|
}
|
|
1360
1318
|
function userAskedForMutation(input) {
|
|
@@ -1415,8 +1373,12 @@ function normalizeLocalHostToolCall(value) {
|
|
|
1415
1373
|
}
|
|
1416
1374
|
function inferLocalHostToolCall(input, launchInvestigation) {
|
|
1417
1375
|
const lower = input.toLowerCase();
|
|
1418
|
-
if (isStartThereIntent(input)) {
|
|
1419
|
-
|
|
1376
|
+
if (isStartThereIntent(input) || isContinueNextMoveIntent(input)) {
|
|
1377
|
+
const project = resolveProjectForTool(launchInvestigation.strongestProject?.name, launchInvestigation);
|
|
1378
|
+
if (project && repoNeedsBootstrap(project.projectDir)) {
|
|
1379
|
+
return { tool: "write_project_context", project: project.name, mode: "bootstrap" };
|
|
1380
|
+
}
|
|
1381
|
+
return { tool: "read_project_context", project: project?.name || launchInvestigation.strongestProject?.name };
|
|
1420
1382
|
}
|
|
1421
1383
|
if (lower.includes("sync") || lower.includes("publish") || lower.includes("push my identity")) {
|
|
1422
1384
|
return { tool: "sync_identity", mode: lower.includes("publish") || lower.includes("push") || lower.includes("sync") ? "publish" : "status" };
|
|
@@ -1473,29 +1435,77 @@ function readSnippet(filePath, maxChars = 1800) {
|
|
|
1473
1435
|
return null;
|
|
1474
1436
|
}
|
|
1475
1437
|
}
|
|
1438
|
+
function extractProjectActionItems(projectDir, maxItems = 5) {
|
|
1439
|
+
// Read paths come from the single project-context engine: repo
|
|
1440
|
+
// project-context/, the generated .you/ layer, then the global overlay.
|
|
1441
|
+
const files = (0, projectContext_1.projectContextReadPaths)(projectDir, [
|
|
1442
|
+
"TODO.md",
|
|
1443
|
+
"CURRENT_STATE.md",
|
|
1444
|
+
"feature-requests-active.md",
|
|
1445
|
+
]);
|
|
1446
|
+
const seen = new Set();
|
|
1447
|
+
const items = [];
|
|
1448
|
+
for (const { path: fullPath } of files) {
|
|
1449
|
+
const content = readSnippet(fullPath, 12000);
|
|
1450
|
+
if (!content)
|
|
1451
|
+
continue;
|
|
1452
|
+
for (const rawLine of content.split("\n")) {
|
|
1453
|
+
const line = rawLine.trim();
|
|
1454
|
+
if (!line)
|
|
1455
|
+
continue;
|
|
1456
|
+
const openTask = line.match(/^[-*]\s+\[[\s?~-]\]\s+(.+)$/);
|
|
1457
|
+
const statusTask = line.match(/^[-*]\s+(?:TODO|P0|P1|BLOCKED|OPEN|NEXT|IN PROGRESS|ACTIVE)[:\s-]+(.+)$/i);
|
|
1458
|
+
const headingTask = line.match(/^#{2,4}\s+(?:P0|P1|Next|Open|Active|Blocked|Known issue|Current focus)[:\s-]+(.+)$/i);
|
|
1459
|
+
const candidate = (openTask?.[1] || statusTask?.[1] || headingTask?.[1] || "")
|
|
1460
|
+
.replace(/\s+/g, " ")
|
|
1461
|
+
.replace(/\s+#.*$/, "")
|
|
1462
|
+
.trim();
|
|
1463
|
+
if (!candidate || candidate.length < 8)
|
|
1464
|
+
continue;
|
|
1465
|
+
const normalized = candidate.toLowerCase();
|
|
1466
|
+
if (seen.has(normalized))
|
|
1467
|
+
continue;
|
|
1468
|
+
seen.add(normalized);
|
|
1469
|
+
items.push(shortenActionItem(candidate));
|
|
1470
|
+
}
|
|
1471
|
+
}
|
|
1472
|
+
return rankProjectActionItems(items).slice(0, maxItems);
|
|
1473
|
+
}
|
|
1476
1474
|
function formatProjectReadToolResult(project) {
|
|
1477
|
-
const
|
|
1475
|
+
const entrypointFiles = [
|
|
1478
1476
|
"AGENTS.md",
|
|
1479
1477
|
"CLAUDE.md",
|
|
1480
1478
|
"package.json",
|
|
1481
1479
|
"pyproject.toml",
|
|
1482
1480
|
"Cargo.toml",
|
|
1483
1481
|
"go.mod",
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1482
|
+
].map((relativePath) => ({
|
|
1483
|
+
label: relativePath,
|
|
1484
|
+
path: path.join(project.projectDir, relativePath),
|
|
1485
|
+
}));
|
|
1486
|
+
// Context reads route through the single project-context engine (repo
|
|
1487
|
+
// project-context/, .you/ layer, then the global overlay union).
|
|
1488
|
+
const files = [
|
|
1489
|
+
...entrypointFiles,
|
|
1490
|
+
...(0, projectContext_1.projectContextReadPaths)(project.projectDir, [
|
|
1491
|
+
"CURRENT_STATE.md",
|
|
1492
|
+
"TODO.md",
|
|
1493
|
+
"PRD.md",
|
|
1494
|
+
"ARCHITECTURE.md",
|
|
1495
|
+
]),
|
|
1490
1496
|
];
|
|
1491
1497
|
const snippets = files
|
|
1492
|
-
.map((
|
|
1493
|
-
const snippet = readSnippet(
|
|
1494
|
-
return snippet ? `file: ${
|
|
1498
|
+
.map(({ label, path: fullPath }) => {
|
|
1499
|
+
const snippet = readSnippet(fullPath);
|
|
1500
|
+
return snippet ? `file: ${label}\n${snippet}` : null;
|
|
1495
1501
|
})
|
|
1496
1502
|
.filter((item) => !!item)
|
|
1497
1503
|
.slice(0, 5);
|
|
1498
1504
|
const managedContext = (0, project_1.readProjectContext)(project.projectDir);
|
|
1505
|
+
const actionItems = extractProjectActionItems(project.projectDir);
|
|
1506
|
+
const recommendedMove = actionItems.length > 0
|
|
1507
|
+
? actionItems[0]
|
|
1508
|
+
: `tighten ${project.name}'s current-state and TODO docs from actual repo context.`;
|
|
1499
1509
|
return [
|
|
1500
1510
|
"tool: read_project_context",
|
|
1501
1511
|
"status: ok",
|
|
@@ -1503,10 +1513,11 @@ function formatProjectReadToolResult(project) {
|
|
|
1503
1513
|
`project_dir: ${project.projectDir}`,
|
|
1504
1514
|
`markers: ${(0, project_1.getProjectMarkerSignals)(project.projectDir).join(", ") || "none"}`,
|
|
1505
1515
|
managedContext ? `managed_project_context: ${managedContext.meta.name}` : "managed_project_context: none",
|
|
1516
|
+
actionItems.length > 0 ? `action_items: ${actionItems.join(" | ")}` : "action_items: none found in TODO/current-state files",
|
|
1506
1517
|
"",
|
|
1507
1518
|
snippets.length > 0 ? snippets.join("\n\n---\n\n") : "no readable project-context or agent entrypoint files found yet.",
|
|
1508
1519
|
"",
|
|
1509
|
-
`recommended_next_move:
|
|
1520
|
+
`recommended_next_move: ${recommendedMove}`,
|
|
1510
1521
|
].join("\n");
|
|
1511
1522
|
}
|
|
1512
1523
|
async function formatIdentitySyncToolResult(bundleDir, publish) {
|
|
@@ -1556,6 +1567,9 @@ async function formatIdentitySyncToolResult(bundleDir, publish) {
|
|
|
1556
1567
|
return lines.join("\n");
|
|
1557
1568
|
}
|
|
1558
1569
|
async function chooseLocalHostTool(args) {
|
|
1570
|
+
if (isStartThereIntent(args.userInput) || isContinueNextMoveIntent(args.userInput)) {
|
|
1571
|
+
return inferLocalHostToolCall(args.userInput, args.launchInvestigation);
|
|
1572
|
+
}
|
|
1559
1573
|
const projects = collectKnownProjects(args.launchInvestigation)
|
|
1560
1574
|
.slice(0, 8)
|
|
1561
1575
|
.map((project) => `${project.name} | ${project.projectDir} | ${project.signals.slice(0, 4).join(", ")}`)
|
|
@@ -1635,7 +1649,78 @@ async function executeLocalHostTool(toolCall, args) {
|
|
|
1635
1649
|
return "tool: respond\nstatus: skipped\nresult: no local host tool needed.";
|
|
1636
1650
|
}
|
|
1637
1651
|
async function handleLocalChatIntent(args) {
|
|
1638
|
-
const
|
|
1652
|
+
const summarizeLocalToolResult = (toolResult) => {
|
|
1653
|
+
const get = (key) => {
|
|
1654
|
+
const match = toolResult.match(new RegExp(`^${key}:\\s*(.+)$`, "m"));
|
|
1655
|
+
return match?.[1]?.trim() || null;
|
|
1656
|
+
};
|
|
1657
|
+
const tool = get("tool") || "local_tool";
|
|
1658
|
+
const status = get("status") || "done";
|
|
1659
|
+
const project = get("project");
|
|
1660
|
+
const projectDir = get("project_dir") || get("recommended_next_project_dir");
|
|
1661
|
+
const recommended = get("recommended_next_move");
|
|
1662
|
+
const markers = get("markers");
|
|
1663
|
+
const changed = get("changed");
|
|
1664
|
+
const filesRead = Array.from(toolResult.matchAll(/^file:\s*(.+)$/gm))
|
|
1665
|
+
.map((match) => match[1].trim())
|
|
1666
|
+
.slice(0, 5);
|
|
1667
|
+
const actionItems = get("action_items");
|
|
1668
|
+
const displayedActionItems = actionItems
|
|
1669
|
+
?.split(" | ")
|
|
1670
|
+
.slice(0, 3)
|
|
1671
|
+
.join(" | ");
|
|
1672
|
+
if (status === "blocked") {
|
|
1673
|
+
const result = get("result") || "local tool blocked";
|
|
1674
|
+
return [
|
|
1675
|
+
result,
|
|
1676
|
+
"",
|
|
1677
|
+
`next strongest move: ${recommended || "run a read-only local scan before attempting a write."}`,
|
|
1678
|
+
].join("\n");
|
|
1679
|
+
}
|
|
1680
|
+
if (tool === "read_project_context") {
|
|
1681
|
+
const lines = [
|
|
1682
|
+
project ? `read ${project}.` : "read the local project.",
|
|
1683
|
+
projectDir ? `path: ${projectDir}` : null,
|
|
1684
|
+
markers ? `markers: ${markers}` : null,
|
|
1685
|
+
filesRead.length > 0 ? `files read: ${filesRead.join(", ")}` : null,
|
|
1686
|
+
displayedActionItems && displayedActionItems !== "none found in TODO/current-state files" ? `found: ${displayedActionItems}` : null,
|
|
1687
|
+
"",
|
|
1688
|
+
`next strongest move: ${recommended || "tighten the current-state and TODO docs from the actual repo context."}`,
|
|
1689
|
+
].filter((line) => !!line);
|
|
1690
|
+
return lines.join("\n");
|
|
1691
|
+
}
|
|
1692
|
+
if (tool === "project_bootstrap") {
|
|
1693
|
+
return [
|
|
1694
|
+
project ? `bootstrapped ${project}.` : "bootstrapped the project context.",
|
|
1695
|
+
changed || "changed: checked existing wiring.",
|
|
1696
|
+
"",
|
|
1697
|
+
`next strongest move: ${recommended || "read the project-context files and sharpen the current-state pass."}`,
|
|
1698
|
+
].join("\n");
|
|
1699
|
+
}
|
|
1700
|
+
if (tool === "workspace_recent_projects") {
|
|
1701
|
+
return [
|
|
1702
|
+
"scanned local workspace projects.",
|
|
1703
|
+
project ? `strongest target: ${project}` : get("recommended_next_project") ? `strongest target: ${get("recommended_next_project")}` : null,
|
|
1704
|
+
projectDir ? `path: ${projectDir}` : null,
|
|
1705
|
+
"",
|
|
1706
|
+
`next strongest move: ${recommended || "say \"start there\" to read the strongest local project from actual files."}`,
|
|
1707
|
+
].filter((line) => !!line).join("\n");
|
|
1708
|
+
}
|
|
1709
|
+
if (tool === "sync_identity") {
|
|
1710
|
+
return [
|
|
1711
|
+
"synced local identity context.",
|
|
1712
|
+
get("remote_sync") || "remote_sync: local compile only.",
|
|
1713
|
+
"",
|
|
1714
|
+
`next strongest move: ${recommended || "test the updated identity from another agent surface."}`,
|
|
1715
|
+
].join("\n");
|
|
1716
|
+
}
|
|
1717
|
+
return [
|
|
1718
|
+
"local tool finished.",
|
|
1719
|
+
"",
|
|
1720
|
+
`next strongest move: ${recommended || "continue from the local result above."}`,
|
|
1721
|
+
].join("\n");
|
|
1722
|
+
};
|
|
1723
|
+
const recordLocalToolResult = (toolResult) => {
|
|
1639
1724
|
args.messages.push({ role: "user", content: args.userInput });
|
|
1640
1725
|
args.messages.push({
|
|
1641
1726
|
role: "user",
|
|
@@ -1654,11 +1739,9 @@ async function handleLocalChatIntent(args) {
|
|
|
1654
1739
|
"Do not end with a question. Keep it under 8 lines. No generic help-desk closer.",
|
|
1655
1740
|
].join("\n"),
|
|
1656
1741
|
});
|
|
1657
|
-
const
|
|
1658
|
-
args.messages.push({ role: "assistant", content:
|
|
1659
|
-
|
|
1660
|
-
printAgentMessage((0, onboarding_1.parseUpdatesFromResponse)(result.text).display);
|
|
1661
|
-
}
|
|
1742
|
+
const summary = summarizeLocalToolResult(toolResult);
|
|
1743
|
+
args.messages.push({ role: "assistant", content: summary });
|
|
1744
|
+
printAgentMessage(summary);
|
|
1662
1745
|
};
|
|
1663
1746
|
if (isLocalToolLoopCandidate(args.userInput)) {
|
|
1664
1747
|
const routeSpinner = new render_1.BrailleSpinner("choosing local tool");
|
|
@@ -1680,7 +1763,7 @@ async function handleLocalChatIntent(args) {
|
|
|
1680
1763
|
const toolResult = await executeLocalHostTool(toolCall, args);
|
|
1681
1764
|
const statusLine = toolResult.match(/^status: (.+)$/m)?.[1] || "done";
|
|
1682
1765
|
spinner.stop(statusLine);
|
|
1683
|
-
|
|
1766
|
+
recordLocalToolResult(toolResult);
|
|
1684
1767
|
}
|
|
1685
1768
|
catch (err) {
|
|
1686
1769
|
const message = err instanceof Error ? err.message : "local tool failed";
|
|
@@ -1700,6 +1783,8 @@ async function handleLocalChatIntent(args) {
|
|
|
1700
1783
|
}
|
|
1701
1784
|
// ─── Main chat command ────────────────────────────────────────────────
|
|
1702
1785
|
async function chatCommand() {
|
|
1786
|
+
// Chat is a readline loop — piped/CI stdin would hang or spin
|
|
1787
|
+
(0, render_1.requireInteractiveTTY)();
|
|
1703
1788
|
const bundleDir = resolveBundleDirForChat();
|
|
1704
1789
|
if (!bundleDir) {
|
|
1705
1790
|
console.log("");
|
|
@@ -1718,23 +1803,24 @@ async function chatCommand() {
|
|
|
1718
1803
|
? rawProjectCtx
|
|
1719
1804
|
: null;
|
|
1720
1805
|
let projectContextBlock = "";
|
|
1721
|
-
let
|
|
1806
|
+
let activeProjectResolution = null;
|
|
1722
1807
|
if (projectCtx) {
|
|
1723
|
-
//
|
|
1808
|
+
// Single project-context engine: managed store + repo project-context/
|
|
1809
|
+
// overlay (repo wins on conflicts; the union feeds the injection).
|
|
1724
1810
|
const projectsRoot = (0, project_1.findProjectsRoot)();
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
}
|
|
1811
|
+
const detected = projectsRoot ? (0, project_1.detectCurrentProject)(projectsRoot) : null;
|
|
1812
|
+
const resolved = (0, projectContext_1.resolveProjectContext)(detected ? { projectName: detected } : {});
|
|
1813
|
+
if (detected || resolved.repoContextDir) {
|
|
1814
|
+
activeProjectResolution = resolved;
|
|
1815
|
+
const merged = (0, projectContext_1.readMergedProjectContext)(detected ? { projectName: detected } : {});
|
|
1816
|
+
const injection = merged ? (0, project_1.buildProjectContextInjectionFromContext)(merged) : null;
|
|
1817
|
+
if (injection) {
|
|
1818
|
+
projectContextBlock = `\n\n--- project context ---\n${injection}`;
|
|
1733
1819
|
}
|
|
1734
1820
|
}
|
|
1735
1821
|
// Fallback to legacy project context if new system didn't produce anything
|
|
1736
1822
|
if (!projectContextBlock) {
|
|
1737
|
-
const projectNotes = (0,
|
|
1823
|
+
const projectNotes = (0, projectContext_1.readProjectPrivateNotes)(projectCtx.name);
|
|
1738
1824
|
const parts = [];
|
|
1739
1825
|
parts.push(`the user is currently working in project: ${projectCtx.name} at ${projectCtx.root}`);
|
|
1740
1826
|
if (projectCtx.youmdProject?.description) {
|
|
@@ -1831,7 +1917,7 @@ async function chatCommand() {
|
|
|
1831
1917
|
continue;
|
|
1832
1918
|
}
|
|
1833
1919
|
if (lower === "/link") {
|
|
1834
|
-
showLinkInfo(
|
|
1920
|
+
showLinkInfo();
|
|
1835
1921
|
continue;
|
|
1836
1922
|
}
|
|
1837
1923
|
if (lower === "/share") {
|
|
@@ -1840,13 +1926,13 @@ async function chatCommand() {
|
|
|
1840
1926
|
}
|
|
1841
1927
|
if (lower === "/memory" || lower === "/memories") {
|
|
1842
1928
|
try {
|
|
1843
|
-
const
|
|
1844
|
-
const
|
|
1845
|
-
if (
|
|
1929
|
+
const res = await (0, api_1.listMemories)({ limit: 20 });
|
|
1930
|
+
const memories = res.ok ? res.data?.memories ?? [] : [];
|
|
1931
|
+
if (memories.length > 0) {
|
|
1846
1932
|
const grouped = new Map();
|
|
1847
|
-
for (const m of
|
|
1933
|
+
for (const m of memories)
|
|
1848
1934
|
grouped.set(m.category, (grouped.get(m.category) || 0) + 1);
|
|
1849
|
-
console.log(chalk_1.default.dim(` memory: ${
|
|
1935
|
+
console.log(chalk_1.default.dim(` memory: ${memories.length} total`));
|
|
1850
1936
|
for (const [cat, count] of grouped) {
|
|
1851
1937
|
console.log(chalk_1.default.dim(` ${cat}s: ${count}`));
|
|
1852
1938
|
}
|
|
@@ -1864,12 +1950,12 @@ async function chatCommand() {
|
|
|
1864
1950
|
if (lower === "/recall" || lower.startsWith("/recall ")) {
|
|
1865
1951
|
const query = lower.startsWith("/recall ") ? lower.slice(8).trim() : "";
|
|
1866
1952
|
try {
|
|
1867
|
-
const
|
|
1868
|
-
|
|
1869
|
-
|
|
1953
|
+
const res = await (0, api_1.listMemories)({ limit: 50 });
|
|
1954
|
+
if (res.ok && res.data?.memories) {
|
|
1955
|
+
const memories = res.data.memories;
|
|
1870
1956
|
const matches = query
|
|
1871
|
-
?
|
|
1872
|
-
:
|
|
1957
|
+
? memories.filter((m) => m.content.toLowerCase().includes(query) || m.category.includes(query))
|
|
1958
|
+
: memories.slice(0, 10);
|
|
1873
1959
|
if (matches.length > 0) {
|
|
1874
1960
|
console.log(chalk_1.default.dim(query ? ` ${matches.length} memories matching "${query}":` : " recent memories:"));
|
|
1875
1961
|
for (const m of matches.slice(0, 10)) {
|
|
@@ -1889,8 +1975,7 @@ async function chatCommand() {
|
|
|
1889
1975
|
}
|
|
1890
1976
|
if (lower === "/private") {
|
|
1891
1977
|
try {
|
|
1892
|
-
const
|
|
1893
|
-
const res = await getPrivateContext();
|
|
1978
|
+
const res = await (0, api_1.getPrivateContext)();
|
|
1894
1979
|
if (res.ok && res.data) {
|
|
1895
1980
|
const p = res.data;
|
|
1896
1981
|
if (p.privateNotes) {
|
|
@@ -2151,8 +2236,21 @@ async function chatCommand() {
|
|
|
2151
2236
|
console.log(chalk_1.default.green(" [saved private note]"));
|
|
2152
2237
|
}
|
|
2153
2238
|
else if (pu.field === "privateProjects" && pu.action === "add" && pu.project) {
|
|
2154
|
-
|
|
2155
|
-
|
|
2239
|
+
const existing = await (0, api_1.getPrivateContext)();
|
|
2240
|
+
const projects = existing.ok ? existing.data?.privateProjects ?? [] : [];
|
|
2241
|
+
const res = await (0, api_1.updatePrivateContext)({
|
|
2242
|
+
privateProjects: [...projects, {
|
|
2243
|
+
name: pu.project.name || "unnamed",
|
|
2244
|
+
description: pu.project.description || "",
|
|
2245
|
+
status: pu.project.status || "active",
|
|
2246
|
+
}],
|
|
2247
|
+
});
|
|
2248
|
+
if (res.ok) {
|
|
2249
|
+
console.log(chalk_1.default.green(` [saved private project: ${pu.project.name || "unnamed"}]`));
|
|
2250
|
+
}
|
|
2251
|
+
else {
|
|
2252
|
+
console.log(chalk_1.default.yellow(" [private context update failed]"));
|
|
2253
|
+
}
|
|
2156
2254
|
}
|
|
2157
2255
|
}
|
|
2158
2256
|
catch {
|
|
@@ -2160,13 +2258,15 @@ async function chatCommand() {
|
|
|
2160
2258
|
}
|
|
2161
2259
|
}
|
|
2162
2260
|
}
|
|
2163
|
-
// Handle project context updates
|
|
2164
|
-
|
|
2261
|
+
// Handle project context updates — the engine routes context/ files to
|
|
2262
|
+
// the repo project-context/ copy when inside the repo, otherwise to the
|
|
2263
|
+
// global ~/.youmd/projects/<name>/ store.
|
|
2264
|
+
if (activeProjectResolution) {
|
|
2165
2265
|
const projUpdates = (0, project_1.parseProjectUpdates)(response);
|
|
2166
2266
|
if (projUpdates.length > 0) {
|
|
2167
2267
|
for (const pu of projUpdates) {
|
|
2168
2268
|
try {
|
|
2169
|
-
(0,
|
|
2269
|
+
(0, projectContext_1.writeProjectUpdate)(activeProjectResolution, pu.file, pu.content);
|
|
2170
2270
|
console.log(chalk_1.default.hex("#C46A3A")(` [updated project context: ${pu.file}]`));
|
|
2171
2271
|
}
|
|
2172
2272
|
catch {
|
|
@@ -2226,8 +2326,7 @@ function printAgentMessage(text) {
|
|
|
2226
2326
|
if (!text)
|
|
2227
2327
|
return;
|
|
2228
2328
|
// Use rich terminal renderer for structured content
|
|
2229
|
-
|
|
2230
|
-
console.log(renderRichResponse(text));
|
|
2329
|
+
console.log((0, render_1.renderRichResponse)(text));
|
|
2231
2330
|
console.log("");
|
|
2232
2331
|
}
|
|
2233
2332
|
//# sourceMappingURL=chat.js.map
|