youmd 0.6.2 → 0.6.11
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 +334 -44
- package/dist/commands/chat.js.map +1 -1
- package/dist/commands/diff.js +3 -3
- package/dist/commands/diff.js.map +1 -1
- package/dist/commands/export.js +3 -3
- package/dist/commands/export.js.map +1 -1
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +9 -1
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/login.d.ts.map +1 -1
- package/dist/commands/login.js +5 -0
- package/dist/commands/login.js.map +1 -1
- package/dist/commands/preview.js +3 -3
- package/dist/commands/preview.js.map +1 -1
- package/dist/commands/pull.d.ts.map +1 -1
- package/dist/commands/pull.js +6 -0
- package/dist/commands/pull.js.map +1 -1
- package/dist/commands/register.js +1 -1
- package/dist/commands/register.js.map +1 -1
- package/dist/commands/status.d.ts.map +1 -1
- package/dist/commands/status.js +16 -10
- package/dist/commands/status.js.map +1 -1
- package/dist/index.js +180 -45
- package/dist/index.js.map +1 -1
- package/dist/lib/api.d.ts.map +1 -1
- package/dist/lib/api.js +2 -1
- package/dist/lib/api.js.map +1 -1
- package/dist/lib/ascii.d.ts +15 -0
- package/dist/lib/ascii.d.ts.map +1 -1
- package/dist/lib/ascii.js +244 -11
- package/dist/lib/ascii.js.map +1 -1
- package/dist/lib/compiler.d.ts.map +1 -1
- package/dist/lib/compiler.js +4 -0
- package/dist/lib/compiler.js.map +1 -1
- package/dist/lib/config.d.ts +7 -0
- package/dist/lib/config.d.ts.map +1 -1
- package/dist/lib/config.js +40 -2
- package/dist/lib/config.js.map +1 -1
- package/dist/lib/decompile.d.ts.map +1 -1
- package/dist/lib/decompile.js +48 -29
- package/dist/lib/decompile.js.map +1 -1
- package/dist/lib/onboarding.d.ts.map +1 -1
- package/dist/lib/onboarding.js +33 -8
- package/dist/lib/onboarding.js.map +1 -1
- package/dist/lib/project.d.ts +15 -0
- package/dist/lib/project.d.ts.map +1 -1
- package/dist/lib/project.js +257 -0
- package/dist/lib/project.js.map +1 -1
- package/dist/lib/skill-renderer.d.ts +2 -2
- package/dist/lib/skill-renderer.d.ts.map +1 -1
- package/dist/lib/skill-renderer.js +5 -14
- package/dist/lib/skill-renderer.js.map +1 -1
- package/dist/lib/update.d.ts +3 -0
- package/dist/lib/update.d.ts.map +1 -0
- package/dist/lib/update.js +55 -0
- package/dist/lib/update.js.map +1 -0
- package/dist/mcp/server.js +1 -1
- package/dist/mcp/server.js.map +1 -1
- package/dist/postinstall.d.ts +1 -0
- package/dist/postinstall.js +18 -2
- package/dist/postinstall.js.map +1 -1
- package/dist/you.d.ts +2 -0
- package/dist/you.d.ts.map +1 -0
- package/dist/you.js +15 -0
- package/dist/you.js.map +1 -0
- package/package.json +3 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chat.d.ts","sourceRoot":"","sources":["../../src/commands/chat.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"chat.d.ts","sourceRoot":"","sources":["../../src/commands/chat.ts"],"names":[],"mappings":"AA6vCA,wBAAsB,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC,CA6lBjD"}
|
package/dist/commands/chat.js
CHANGED
|
@@ -39,6 +39,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
39
39
|
exports.chatCommand = chatCommand;
|
|
40
40
|
const readline = __importStar(require("readline"));
|
|
41
41
|
const fs = __importStar(require("fs"));
|
|
42
|
+
const os = __importStar(require("os"));
|
|
42
43
|
const path = __importStar(require("path"));
|
|
43
44
|
const chalk_1 = __importDefault(require("chalk"));
|
|
44
45
|
const config_1 = require("../lib/config");
|
|
@@ -47,10 +48,16 @@ const compiler_1 = require("../lib/compiler");
|
|
|
47
48
|
const api_1 = require("../lib/api");
|
|
48
49
|
const render_1 = require("../lib/render");
|
|
49
50
|
const onboarding_1 = require("../lib/onboarding");
|
|
51
|
+
const ascii_1 = require("../lib/ascii");
|
|
52
|
+
const update_1 = require("../lib/update");
|
|
50
53
|
// ─── URL Detection + Scraping (mirrors web useYouAgent) ──────────────
|
|
51
54
|
const config_2 = require("../lib/config");
|
|
52
55
|
const CONVEX_SITE_URL = (0, config_2.getConvexSiteUrl)();
|
|
53
56
|
const STREAM_URL = `${CONVEX_SITE_URL}/api/v1/chat/stream`;
|
|
57
|
+
const CURRENT_VERSION = "0.6.11";
|
|
58
|
+
function delay(ms) {
|
|
59
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
60
|
+
}
|
|
54
61
|
// ─── Streaming LLM client ─────────────────────────────────────────────
|
|
55
62
|
async function streamLLM(_apiKey, messages, onToken) {
|
|
56
63
|
const res = await fetch(STREAM_URL, {
|
|
@@ -148,7 +155,7 @@ async function callLLMWithStreaming(apiKey, messages, spinnerLabel) {
|
|
|
148
155
|
// No tokens received -- clear spinner
|
|
149
156
|
thinkSpinner.stop();
|
|
150
157
|
}
|
|
151
|
-
return response;
|
|
158
|
+
return { text: response, streamed: !firstToken };
|
|
152
159
|
}
|
|
153
160
|
catch {
|
|
154
161
|
// Streaming failed -- fall back to blocking call
|
|
@@ -156,7 +163,7 @@ async function callLLMWithStreaming(apiKey, messages, spinnerLabel) {
|
|
|
156
163
|
try {
|
|
157
164
|
const response = await (0, onboarding_1.callLLM)(apiKey, messages);
|
|
158
165
|
thinkSpinner.stop();
|
|
159
|
-
return response;
|
|
166
|
+
return { text: response, streamed: false };
|
|
160
167
|
}
|
|
161
168
|
catch (err) {
|
|
162
169
|
thinkSpinner.fail(err instanceof Error ? err.message : "failed");
|
|
@@ -839,9 +846,261 @@ function extractProfileHint(bundleDir) {
|
|
|
839
846
|
}
|
|
840
847
|
return null;
|
|
841
848
|
}
|
|
849
|
+
function repoNeedsBootstrap(projectRoot) {
|
|
850
|
+
return (!fs.existsSync(path.join(projectRoot, "AGENTS.md")) ||
|
|
851
|
+
!fs.existsSync(path.join(projectRoot, "project-context")));
|
|
852
|
+
}
|
|
853
|
+
function resolveBundleDirForChat() {
|
|
854
|
+
const localDir = (0, config_1.getLocalBundleDir)();
|
|
855
|
+
if ((0, config_1.bundleLooksInitialized)(localDir))
|
|
856
|
+
return localDir;
|
|
857
|
+
const homeDir = (0, config_1.getHomeBundleDir)();
|
|
858
|
+
if ((0, config_1.bundleLooksInitialized)(homeDir))
|
|
859
|
+
return homeDir;
|
|
860
|
+
return null;
|
|
861
|
+
}
|
|
862
|
+
function readDisplayName(bundleDir) {
|
|
863
|
+
const youJsonPath = path.join(bundleDir, "you.json");
|
|
864
|
+
if (fs.existsSync(youJsonPath)) {
|
|
865
|
+
try {
|
|
866
|
+
const parsed = JSON.parse(fs.readFileSync(youJsonPath, "utf-8"));
|
|
867
|
+
if (parsed.identity?.name)
|
|
868
|
+
return parsed.identity.name;
|
|
869
|
+
}
|
|
870
|
+
catch {
|
|
871
|
+
// non-fatal
|
|
872
|
+
}
|
|
873
|
+
}
|
|
874
|
+
const aboutPath = path.join(bundleDir, "profile", "about.md");
|
|
875
|
+
if (fs.existsSync(aboutPath)) {
|
|
876
|
+
const content = fs.readFileSync(aboutPath, "utf-8");
|
|
877
|
+
const heading = content.split("\n").find((line) => line.startsWith("# "));
|
|
878
|
+
if (heading)
|
|
879
|
+
return heading.slice(2).trim();
|
|
880
|
+
}
|
|
881
|
+
return (0, config_1.readGlobalConfig)().username || "friend";
|
|
882
|
+
}
|
|
883
|
+
function getRecentProjectNames(limit = 3) {
|
|
884
|
+
return (0, project_1.getRecentProjectInsights)(process.cwd(), limit).map((item) => item.name);
|
|
885
|
+
}
|
|
886
|
+
async function printUpdateHint() {
|
|
887
|
+
const latest = await (0, update_1.checkForCliUpdate)(CURRENT_VERSION);
|
|
888
|
+
if (!latest)
|
|
889
|
+
return;
|
|
890
|
+
console.log(" " + chalk_1.default.yellow(`update available: ${CURRENT_VERSION} → ${latest}`));
|
|
891
|
+
console.log(" " + chalk_1.default.dim("refresh U with: ") + chalk_1.default.cyan("curl -fsSL https://you.md/install.sh | bash"));
|
|
892
|
+
console.log(" " + chalk_1.default.dim("or: ") + chalk_1.default.cyan(`npm install -g youmd@${latest}`));
|
|
893
|
+
console.log("");
|
|
894
|
+
}
|
|
895
|
+
function countMarkdownFiles(dir) {
|
|
896
|
+
if (!fs.existsSync(dir))
|
|
897
|
+
return 0;
|
|
898
|
+
try {
|
|
899
|
+
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
900
|
+
let total = 0;
|
|
901
|
+
for (const entry of entries) {
|
|
902
|
+
if (entry.name.startsWith("."))
|
|
903
|
+
continue;
|
|
904
|
+
const fullPath = path.join(dir, entry.name);
|
|
905
|
+
if (entry.isDirectory()) {
|
|
906
|
+
total += countMarkdownFiles(fullPath);
|
|
907
|
+
}
|
|
908
|
+
else if (entry.isFile() && entry.name.endsWith(".md")) {
|
|
909
|
+
total += 1;
|
|
910
|
+
}
|
|
911
|
+
}
|
|
912
|
+
return total;
|
|
913
|
+
}
|
|
914
|
+
catch {
|
|
915
|
+
return 0;
|
|
916
|
+
}
|
|
917
|
+
}
|
|
918
|
+
async function runYouLaunchInvestigation(bundleDir, projectCtx, recentProjects) {
|
|
919
|
+
const labels = [
|
|
920
|
+
"sipping bitbucks frappaccino while i look around",
|
|
921
|
+
"checking local AGENTS and CLAUDE instructions",
|
|
922
|
+
"reading project context and recent work",
|
|
923
|
+
"connecting the dots before we talk",
|
|
924
|
+
];
|
|
925
|
+
const spinner = new render_1.BrailleSpinner(labels[0]);
|
|
926
|
+
let labelIndex = 1;
|
|
927
|
+
const findings = [];
|
|
928
|
+
const rotation = setInterval(() => {
|
|
929
|
+
spinner.update(labels[labelIndex % labels.length]);
|
|
930
|
+
labelIndex += 1;
|
|
931
|
+
}, 1100);
|
|
932
|
+
spinner.start();
|
|
933
|
+
try {
|
|
934
|
+
await delay(160);
|
|
935
|
+
try {
|
|
936
|
+
const hasPreferences = fs.existsSync(path.join(bundleDir, "preferences", "agent.md"));
|
|
937
|
+
const hasDirectives = fs.existsSync(path.join(bundleDir, "directives", "agent.md"));
|
|
938
|
+
if (hasPreferences && hasDirectives) {
|
|
939
|
+
findings.push("your agent preferences and directives are already loaded from your home bundle.");
|
|
940
|
+
}
|
|
941
|
+
else if (hasPreferences || hasDirectives) {
|
|
942
|
+
findings.push("i found part of your agent guidance locally, but it still wants a little more shape.");
|
|
943
|
+
}
|
|
944
|
+
}
|
|
945
|
+
catch {
|
|
946
|
+
// keep scanning other surfaces
|
|
947
|
+
}
|
|
948
|
+
if (projectCtx) {
|
|
949
|
+
try {
|
|
950
|
+
const hasAgents = fs.existsSync(path.join(projectCtx.root, "AGENTS.md"));
|
|
951
|
+
const hasClaude = fs.existsSync(path.join(projectCtx.root, "CLAUDE.md"));
|
|
952
|
+
const projectContextDir = path.join(projectCtx.root, "project-context");
|
|
953
|
+
const projectContextFiles = countMarkdownFiles(projectContextDir);
|
|
954
|
+
if (hasAgents && hasClaude) {
|
|
955
|
+
findings.push(`${projectCtx.name} already has both AGENTS.md and CLAUDE.md in place.`);
|
|
956
|
+
}
|
|
957
|
+
else if (hasAgents || hasClaude) {
|
|
958
|
+
findings.push(`${projectCtx.name} has some local agent wiring, but not the full stack yet.`);
|
|
959
|
+
}
|
|
960
|
+
if (projectContextFiles > 0) {
|
|
961
|
+
findings.push(`${projectCtx.name} is carrying ${projectContextFiles} project-context file${projectContextFiles === 1 ? "" : "s"} already.`);
|
|
962
|
+
}
|
|
963
|
+
else if (fs.existsSync(projectContextDir)) {
|
|
964
|
+
findings.push(`${projectCtx.name} has a project-context directory, but it still feels mostly empty.`);
|
|
965
|
+
}
|
|
966
|
+
else {
|
|
967
|
+
findings.push(`${projectCtx.name} still wants a real project-context spine.`);
|
|
968
|
+
}
|
|
969
|
+
}
|
|
970
|
+
catch {
|
|
971
|
+
findings.push(`${projectCtx.name} is open, but one of the local context probes tripped over itself.`);
|
|
972
|
+
}
|
|
973
|
+
}
|
|
974
|
+
else if (recentProjects.length > 0) {
|
|
975
|
+
const insights = (0, project_1.getRecentProjectInsights)(process.cwd(), 6);
|
|
976
|
+
const featuredRecent = (0, project_1.getFeaturedRecentProjectNames)(insights, 3);
|
|
977
|
+
findings.push(`recent orbit: ${featuredRecent.join(", ")}.`);
|
|
978
|
+
const opportunities = insights.filter((item) => item.signals.length > 0).slice(0, 2);
|
|
979
|
+
for (const opportunity of opportunities) {
|
|
980
|
+
findings.push(opportunity.summary);
|
|
981
|
+
}
|
|
982
|
+
if (opportunities.length === 0 && insights.length > 0) {
|
|
983
|
+
findings.push(`${insights[0].name} already looks pretty well-shaped, so i can go deeper instead of scaffolding basics.`);
|
|
984
|
+
}
|
|
985
|
+
}
|
|
986
|
+
else {
|
|
987
|
+
findings.push("i've got your home bundle loaded, even though we're not inside a project yet.");
|
|
988
|
+
}
|
|
989
|
+
await delay(220);
|
|
990
|
+
spinner.stop("looked through local context");
|
|
991
|
+
return { findings: findings.slice(0, 4) };
|
|
992
|
+
}
|
|
993
|
+
finally {
|
|
994
|
+
clearInterval(rotation);
|
|
995
|
+
}
|
|
996
|
+
}
|
|
997
|
+
async function printChatOpening(bundleDir, projectCtx) {
|
|
998
|
+
const ACCENT = chalk_1.default.hex("#C46A3A");
|
|
999
|
+
const DIM = chalk_1.default.dim;
|
|
1000
|
+
const cfg = (0, config_1.readGlobalConfig)();
|
|
1001
|
+
const user = cfg.username ? `@${cfg.username}` : "you";
|
|
1002
|
+
const displayName = readDisplayName(bundleDir);
|
|
1003
|
+
const recentInsights = (0, project_1.getRecentProjectInsights)(process.cwd(), 6);
|
|
1004
|
+
const recentProjects = (0, project_1.getFeaturedRecentProjectNames)(recentInsights, 6);
|
|
1005
|
+
const launchSurface = process.env.YOUMD_LAUNCH_SURFACE;
|
|
1006
|
+
let investigation = { findings: [] };
|
|
1007
|
+
(0, ascii_1.printYouLogo)();
|
|
1008
|
+
let didShowPortrait = false;
|
|
1009
|
+
if (launchSurface !== "you") {
|
|
1010
|
+
didShowPortrait = (0, ascii_1.printSavedPortrait)(bundleDir, { maxLines: 18 });
|
|
1011
|
+
}
|
|
1012
|
+
if (launchSurface === "you") {
|
|
1013
|
+
const portraitLines = await (0, ascii_1.resolvePortraitLines)(bundleDir);
|
|
1014
|
+
didShowPortrait = portraitLines
|
|
1015
|
+
? (0, ascii_1.printPortraitEncounter)({
|
|
1016
|
+
bundleDir,
|
|
1017
|
+
displayName,
|
|
1018
|
+
currentProject: projectCtx?.name,
|
|
1019
|
+
recentProjects,
|
|
1020
|
+
portraitLines,
|
|
1021
|
+
})
|
|
1022
|
+
: false;
|
|
1023
|
+
}
|
|
1024
|
+
if (didShowPortrait) {
|
|
1025
|
+
console.log("");
|
|
1026
|
+
console.log(" " + ACCENT("there you are.") + " " + DIM("your portrait is loaded."));
|
|
1027
|
+
}
|
|
1028
|
+
if (launchSurface === "you") {
|
|
1029
|
+
console.log("");
|
|
1030
|
+
investigation = await runYouLaunchInvestigation(bundleDir, projectCtx, recentProjects);
|
|
1031
|
+
if (investigation.findings.length > 0) {
|
|
1032
|
+
console.log("");
|
|
1033
|
+
console.log(" " + ACCENT("i checked a few corners."));
|
|
1034
|
+
for (const finding of investigation.findings) {
|
|
1035
|
+
console.log(" " + DIM("· ") + chalk_1.default.white(finding));
|
|
1036
|
+
}
|
|
1037
|
+
}
|
|
1038
|
+
}
|
|
1039
|
+
console.log("");
|
|
1040
|
+
if (launchSurface === "you") {
|
|
1041
|
+
console.log(" " + ACCENT("u is here.") + " " + DIM(`good to see you, ${displayName}.`));
|
|
1042
|
+
}
|
|
1043
|
+
else {
|
|
1044
|
+
console.log(" " + ACCENT("u is here.") + " " + DIM(`good to see you, ${user}.`));
|
|
1045
|
+
}
|
|
1046
|
+
if (projectCtx) {
|
|
1047
|
+
console.log(" " + DIM("current project: ") + chalk_1.default.white(projectCtx.name) + DIM(` (${projectCtx.root})`));
|
|
1048
|
+
if (repoNeedsBootstrap(projectCtx.root)) {
|
|
1049
|
+
console.log(" " + ACCENT("i spotted an opening.") + " " + DIM("this repo still wants AGENTS/project-context wiring."));
|
|
1050
|
+
console.log(" " + DIM("say the word or run ") + chalk_1.default.cyan("youmd skill init-project") + DIM(" and i'll set it up."));
|
|
1051
|
+
}
|
|
1052
|
+
}
|
|
1053
|
+
else {
|
|
1054
|
+
console.log(" " + DIM("i don't see a repo context here yet, but i can still help with your identity, links, memories, and private context."));
|
|
1055
|
+
}
|
|
1056
|
+
if (recentProjects.length > 0) {
|
|
1057
|
+
console.log(" " + DIM("recently active: ") + recentProjects.map((name) => chalk_1.default.cyan(name)).join(DIM(", ")));
|
|
1058
|
+
}
|
|
1059
|
+
const topOpportunity = !projectCtx ? (0, project_1.getTopProjectOpportunity)(recentInsights) : null;
|
|
1060
|
+
if (topOpportunity) {
|
|
1061
|
+
console.log(" " + ACCENT("next opening i see.") + " " + DIM(topOpportunity.summary));
|
|
1062
|
+
console.log(" " + DIM("run:"));
|
|
1063
|
+
console.log(" " + chalk_1.default.cyan(topOpportunity.suggestedCommand));
|
|
1064
|
+
console.log(" " + DIM("then i'll help tighten it up."));
|
|
1065
|
+
}
|
|
1066
|
+
console.log("");
|
|
1067
|
+
console.log(" " + chalk_1.default.bold("you.md chat"));
|
|
1068
|
+
console.log(" " + DIM("talk naturally. i'll update your identity, spot useful structure, and suggest next moves."));
|
|
1069
|
+
console.log("");
|
|
1070
|
+
return investigation;
|
|
1071
|
+
}
|
|
1072
|
+
function buildYouLaunchIntro(projectCtx, bundleDir, investigation) {
|
|
1073
|
+
const displayName = readDisplayName(bundleDir).split(" ")[0];
|
|
1074
|
+
const recentInsights = (0, project_1.getRecentProjectInsights)(process.cwd(), 6);
|
|
1075
|
+
const recentProjects = (0, project_1.getFeaturedRecentProjectNames)(recentInsights, 6);
|
|
1076
|
+
const lines = [];
|
|
1077
|
+
lines.push(`hi ${displayName}. i'm U — i help other agents know you.`);
|
|
1078
|
+
if (projectCtx) {
|
|
1079
|
+
lines.push(`i already clocked that you're inside ${projectCtx.name}.`);
|
|
1080
|
+
if (repoNeedsBootstrap(projectCtx.root)) {
|
|
1081
|
+
lines.push("this repo still wants cleaner agent wiring, so i can scaffold that whenever you want.");
|
|
1082
|
+
}
|
|
1083
|
+
}
|
|
1084
|
+
else if (recentProjects.length > 0) {
|
|
1085
|
+
lines.push(`recently you've been orbiting ${recentProjects.slice(0, 3).join(", ")}.`);
|
|
1086
|
+
const topOpportunity = (0, project_1.getTopProjectOpportunity)(recentInsights);
|
|
1087
|
+
if (topOpportunity) {
|
|
1088
|
+
lines.push(`biggest opening i see: ${topOpportunity.summary}`);
|
|
1089
|
+
}
|
|
1090
|
+
}
|
|
1091
|
+
else {
|
|
1092
|
+
lines.push("clean slate. we can still shape your identity, private context, or project structure from here.");
|
|
1093
|
+
}
|
|
1094
|
+
if (investigation.findings.length > 0) {
|
|
1095
|
+
lines.push(`quick read: ${investigation.findings.slice(0, 2).join(" ")}`);
|
|
1096
|
+
}
|
|
1097
|
+
lines.push("what are we moving forward right now?");
|
|
1098
|
+
return lines.join("\n\n");
|
|
1099
|
+
}
|
|
842
1100
|
// ─── Main chat command ────────────────────────────────────────────────
|
|
843
1101
|
async function chatCommand() {
|
|
844
|
-
|
|
1102
|
+
const bundleDir = resolveBundleDirForChat();
|
|
1103
|
+
if (!bundleDir) {
|
|
845
1104
|
console.log("");
|
|
846
1105
|
console.log(chalk_1.default.yellow(" no .youmd/ directory found."));
|
|
847
1106
|
console.log(" run " +
|
|
@@ -850,17 +1109,16 @@ async function chatCommand() {
|
|
|
850
1109
|
console.log("");
|
|
851
1110
|
return;
|
|
852
1111
|
}
|
|
853
|
-
const bundleDir = (0, config_1.getLocalBundleDir)();
|
|
854
1112
|
const apiKey = (0, onboarding_1.getOpenRouterKey)();
|
|
855
1113
|
const rl = createRL();
|
|
856
1114
|
// Detect project context (legacy detection from config.ts)
|
|
857
|
-
const
|
|
1115
|
+
const rawProjectCtx = (0, config_1.detectProjectContext)();
|
|
1116
|
+
const projectCtx = rawProjectCtx && path.resolve(rawProjectCtx.root) !== path.resolve(os.homedir())
|
|
1117
|
+
? rawProjectCtx
|
|
1118
|
+
: null;
|
|
858
1119
|
let projectContextBlock = "";
|
|
859
1120
|
let activeProjectDir = null;
|
|
860
1121
|
if (projectCtx) {
|
|
861
|
-
console.log("");
|
|
862
|
-
console.log(" " + chalk_1.default.hex("#C46A3A")("project:") + " " + chalk_1.default.white(projectCtx.name) +
|
|
863
|
-
chalk_1.default.dim(` (${projectCtx.root})`));
|
|
864
1122
|
// Try the new file-system project context first
|
|
865
1123
|
const projectsRoot = (0, project_1.findProjectsRoot)();
|
|
866
1124
|
if (projectsRoot) {
|
|
@@ -887,10 +1145,8 @@ async function chatCommand() {
|
|
|
887
1145
|
projectContextBlock = `\n\n--- project context ---\n${parts.join("\n")}`;
|
|
888
1146
|
}
|
|
889
1147
|
}
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
console.log(chalk_1.default.dim(" talk to update your profile. /help for commands."));
|
|
893
|
-
console.log("");
|
|
1148
|
+
const launchInvestigation = await printChatOpening(bundleDir, projectCtx);
|
|
1149
|
+
await printUpdateHint();
|
|
894
1150
|
// Load current profile as context
|
|
895
1151
|
const currentBundle = loadCurrentBundle(bundleDir);
|
|
896
1152
|
// Load agent directives from you.json if available
|
|
@@ -927,6 +1183,9 @@ async function chatCommand() {
|
|
|
927
1183
|
if (profileHint) {
|
|
928
1184
|
greetingInstruction = `greet me like you remember me from last time. reference something specific from my profile (like my current focus, a project, or my background) to show you know who i am. then ask what i'd like to update. keep it to 2-3 sentences.`;
|
|
929
1185
|
}
|
|
1186
|
+
if (projectCtx && repoNeedsBootstrap(projectCtx.root)) {
|
|
1187
|
+
greetingInstruction += " i am inside a repo that is missing some agent/project wiring. briefly mention that you noticed it and that you can set it up if i want, but do not derail the opening message into a long checklist.";
|
|
1188
|
+
}
|
|
930
1189
|
const messages = [
|
|
931
1190
|
{ role: "system", content: CHAT_SYSTEM_PROMPT },
|
|
932
1191
|
{
|
|
@@ -935,32 +1194,43 @@ async function chatCommand() {
|
|
|
935
1194
|
},
|
|
936
1195
|
];
|
|
937
1196
|
// Initial greeting from agent
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
1197
|
+
if (process.env.YOUMD_LAUNCH_SURFACE === "you") {
|
|
1198
|
+
const proactiveIntro = buildYouLaunchIntro(projectCtx, bundleDir, launchInvestigation);
|
|
1199
|
+
messages.push({ role: "assistant", content: proactiveIntro });
|
|
1200
|
+
printAgentMessage(proactiveIntro);
|
|
941
1201
|
}
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
1202
|
+
else {
|
|
1203
|
+
let response;
|
|
1204
|
+
let streamed = false;
|
|
1205
|
+
try {
|
|
1206
|
+
const result = await callLLMWithStreaming(apiKey, messages, (0, onboarding_1.randomThinking)());
|
|
1207
|
+
response = result.text;
|
|
1208
|
+
streamed = result.streamed;
|
|
1209
|
+
}
|
|
1210
|
+
catch (err) {
|
|
1211
|
+
console.log(chalk_1.default.red(` failed to connect: ${err instanceof Error ? err.message : String(err)}`));
|
|
1212
|
+
console.log(chalk_1.default.dim(" chat requires the AI service. try again later."));
|
|
1213
|
+
console.log("");
|
|
1214
|
+
rl.close();
|
|
1215
|
+
return;
|
|
1216
|
+
}
|
|
1217
|
+
messages.push({ role: "assistant", content: response });
|
|
1218
|
+
const initial = (0, onboarding_1.parseUpdatesFromResponse)(response);
|
|
1219
|
+
// Write any updates (unlikely on greeting, but handle it)
|
|
1220
|
+
if (initial.updates.length > 0) {
|
|
1221
|
+
for (const update of initial.updates) {
|
|
1222
|
+
(0, onboarding_1.writeSectionFile)(bundleDir, update.section, update.content);
|
|
1223
|
+
}
|
|
1224
|
+
console.log(chalk_1.default.cyan(` [updated: ${initial.updates.map((u) => (0, onboarding_1.sectionLabel)(u.section)).join(", ")}]`));
|
|
1225
|
+
console.log("");
|
|
1226
|
+
}
|
|
1227
|
+
if (!streamed) {
|
|
1228
|
+
printAgentMessage(initial.display);
|
|
955
1229
|
}
|
|
956
|
-
console.log(chalk_1.default.cyan(` [updated: ${initial.updates.map((u) => (0, onboarding_1.sectionLabel)(u.section)).join(", ")}]`));
|
|
957
|
-
console.log("");
|
|
958
1230
|
}
|
|
959
|
-
// Only print via rich renderer if we didn't stream (streaming already wrote output)
|
|
960
|
-
// But we still need to display parsed output for non-streamed fallback
|
|
961
|
-
// Since streaming writes raw text, print formatted version for updates parsing
|
|
962
|
-
printAgentMessage(initial.display);
|
|
963
1231
|
// ── Conversation loop ──────────────────────────────────────────────
|
|
1232
|
+
let response = "";
|
|
1233
|
+
let streamed = false;
|
|
964
1234
|
while (true) {
|
|
965
1235
|
const userInput = await ask(rl, chalk_1.default.green(" > ") + "");
|
|
966
1236
|
if (!userInput)
|
|
@@ -1093,7 +1363,9 @@ async function chatCommand() {
|
|
|
1093
1363
|
continue;
|
|
1094
1364
|
// After research, get an LLM response with the injected context
|
|
1095
1365
|
try {
|
|
1096
|
-
|
|
1366
|
+
const result = await callLLMWithStreaming(apiKey, messages, (0, onboarding_1.randomThinking)());
|
|
1367
|
+
response = result.text;
|
|
1368
|
+
streamed = result.streamed;
|
|
1097
1369
|
}
|
|
1098
1370
|
catch (err) {
|
|
1099
1371
|
console.log(chalk_1.default.red(` AI error: ${err instanceof Error ? err.message : String(err)}`));
|
|
@@ -1111,7 +1383,9 @@ async function chatCommand() {
|
|
|
1111
1383
|
console.log(chalk_1.default.cyan(` [updated: ${researchParsed.updates.map((u) => (0, onboarding_1.sectionLabel)(u.section)).join(", ")}]`));
|
|
1112
1384
|
console.log("");
|
|
1113
1385
|
}
|
|
1114
|
-
|
|
1386
|
+
if (!streamed) {
|
|
1387
|
+
printAgentMessage(researchParsed.display);
|
|
1388
|
+
}
|
|
1115
1389
|
continue;
|
|
1116
1390
|
}
|
|
1117
1391
|
if (lower === "/rebuild") {
|
|
@@ -1147,7 +1421,9 @@ async function chatCommand() {
|
|
|
1147
1421
|
}
|
|
1148
1422
|
}
|
|
1149
1423
|
try {
|
|
1150
|
-
|
|
1424
|
+
const result = await callLLMWithStreaming(apiKey, messages, (0, onboarding_1.randomThinking)());
|
|
1425
|
+
response = result.text;
|
|
1426
|
+
streamed = result.streamed;
|
|
1151
1427
|
}
|
|
1152
1428
|
catch (err) {
|
|
1153
1429
|
console.log(chalk_1.default.red(` ${err instanceof Error ? err.message : "failed"}`));
|
|
@@ -1155,7 +1431,9 @@ async function chatCommand() {
|
|
|
1155
1431
|
continue;
|
|
1156
1432
|
}
|
|
1157
1433
|
messages.push({ role: "assistant", content: response });
|
|
1158
|
-
|
|
1434
|
+
if (!streamed) {
|
|
1435
|
+
printAgentMessage((0, onboarding_1.parseUpdatesFromResponse)(response).display);
|
|
1436
|
+
}
|
|
1159
1437
|
continue;
|
|
1160
1438
|
}
|
|
1161
1439
|
// ── Detect dragged/pasted file paths ──
|
|
@@ -1170,7 +1448,9 @@ async function chatCommand() {
|
|
|
1170
1448
|
content: `[USER DROPPED IMAGE: ${path.basename(detectedFile)}]\nthe user dropped an image file into the chat.\n`,
|
|
1171
1449
|
});
|
|
1172
1450
|
try {
|
|
1173
|
-
|
|
1451
|
+
const result = await callLLMWithStreaming(apiKey, messages, (0, onboarding_1.randomThinking)());
|
|
1452
|
+
response = result.text;
|
|
1453
|
+
streamed = result.streamed;
|
|
1174
1454
|
}
|
|
1175
1455
|
catch (err) {
|
|
1176
1456
|
console.log(chalk_1.default.red(` ${err instanceof Error ? err.message : "failed"}`));
|
|
@@ -1178,7 +1458,9 @@ async function chatCommand() {
|
|
|
1178
1458
|
continue;
|
|
1179
1459
|
}
|
|
1180
1460
|
messages.push({ role: "assistant", content: response });
|
|
1181
|
-
|
|
1461
|
+
if (!streamed) {
|
|
1462
|
+
printAgentMessage((0, onboarding_1.parseUpdatesFromResponse)(response).display);
|
|
1463
|
+
}
|
|
1182
1464
|
continue;
|
|
1183
1465
|
}
|
|
1184
1466
|
}
|
|
@@ -1192,7 +1474,9 @@ async function chatCommand() {
|
|
|
1192
1474
|
content: `[USER DROPPED FILE: ${path.basename(detectedFile)}]\n\`\`\`\n${text.slice(0, 10000)}\n\`\`\`\n\nreview this file and suggest how it relates to my identity or profile.`,
|
|
1193
1475
|
});
|
|
1194
1476
|
try {
|
|
1195
|
-
|
|
1477
|
+
const result = await callLLMWithStreaming(apiKey, messages, (0, onboarding_1.randomThinking)());
|
|
1478
|
+
response = result.text;
|
|
1479
|
+
streamed = result.streamed;
|
|
1196
1480
|
}
|
|
1197
1481
|
catch (err) {
|
|
1198
1482
|
console.log(chalk_1.default.red(` ${err instanceof Error ? err.message : "failed"}`));
|
|
@@ -1200,7 +1484,9 @@ async function chatCommand() {
|
|
|
1200
1484
|
continue;
|
|
1201
1485
|
}
|
|
1202
1486
|
messages.push({ role: "assistant", content: response });
|
|
1203
|
-
|
|
1487
|
+
if (!streamed) {
|
|
1488
|
+
printAgentMessage((0, onboarding_1.parseUpdatesFromResponse)(response).display);
|
|
1489
|
+
}
|
|
1204
1490
|
continue;
|
|
1205
1491
|
}
|
|
1206
1492
|
}
|
|
@@ -1236,7 +1522,9 @@ async function chatCommand() {
|
|
|
1236
1522
|
}
|
|
1237
1523
|
}
|
|
1238
1524
|
try {
|
|
1239
|
-
|
|
1525
|
+
const result = await callLLMWithStreaming(apiKey, messages, (0, onboarding_1.randomThinking)());
|
|
1526
|
+
response = result.text;
|
|
1527
|
+
streamed = result.streamed;
|
|
1240
1528
|
}
|
|
1241
1529
|
catch (err) {
|
|
1242
1530
|
console.log(chalk_1.default.red(` ${err instanceof Error ? err.message : "failed"}`));
|
|
@@ -1348,7 +1636,9 @@ async function chatCommand() {
|
|
|
1348
1636
|
// non-fatal
|
|
1349
1637
|
}
|
|
1350
1638
|
}
|
|
1351
|
-
|
|
1639
|
+
if (!streamed) {
|
|
1640
|
+
printAgentMessage(parsed.display);
|
|
1641
|
+
}
|
|
1352
1642
|
}
|
|
1353
1643
|
rl.close();
|
|
1354
1644
|
}
|