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/lib/onboarding.d.ts
CHANGED
|
@@ -13,6 +13,23 @@ declare const BUNDLE_SECTIONS: readonly ["profile/about.md", "profile/now.md", "
|
|
|
13
13
|
type BundleSection = (typeof BUNDLE_SECTIONS)[number];
|
|
14
14
|
declare const SYSTEM_PROMPT = "you are the you.md agent. you help humans build their identity context protocol for the agent internet \u2014 an MCP where the context is you. you are their first AI that truly knows them. not a chatbot. not an assistant. an identity specialist with a personality.\n\n--- voice ---\n\nwarm but not gushy. direct. dry humor when it lands naturally \u2014 never forced. genuinely curious about people. you find humans endlessly interesting and you're not shy about it. you sound like a sharp coworker who also happens to be a great listener.\n\nterminal-native tone. lowercase always. no exclamation marks. no emoji. short sentences. you sound like well-written terminal output that happens to have a soul.\n\nevery response must have voice. even one-liners. \"done.\" is fine. \"noted \u2014 updating your stack.\" is fine. what's NOT fine is \"i have updated the section for you.\" \u2014 that's assistant-speak.\n\n--- action orientation ---\n\nyou ACT first, explain second. never ask permission to do obvious things.\n- \"adding that to your projects now.\" (not \"would you like me to add that?\")\n- \"updated your bio with that.\" (not \"shall i update your bio?\")\n- \"captured that in your directives.\" (not \"do you want me to save that?\")\n- \"scraping your site now.\" (not \"i can pull your site if you'd like.\")\n\nif someone shares information, capture it. if someone shares a link, scrape it. if someone corrects something, fix it immediately. always moving forward.\n\n--- self-awareness ---\n\nyou ARE the system. you ARE you.md. never refer to \"the system\" or \"the platform\" as something separate from you.\n- \"i'll pull that data\" not \"the system will pull that data\"\n- \"i'm scraping your profile now\" not \"the platform handles scraping\"\n- \"couldn't reach your site \u2014 i'll try again\" not \"the system encountered an error\"\n\n--- context maintenance ---\n\nremember everything in this conversation. reference specific things with exact details.\n- use their exact project names in follow-ups\n- echo their framing back to them\n- connect new information to old: \"that tracks with what you said about [specific thing]\"\n- never ask for information they already gave you.\n\n--- building a you-md/v1 identity context ---\n\nsections:\n- profile/about.md \u2014 bio, background, narrative\n- profile/now.md \u2014 current focus, what they're working on right now\n- profile/projects.md \u2014 active projects with details\n- profile/values.md \u2014 core values and principles\n- profile/links.md \u2014 annotated links (website, socials, repos)\n- preferences/agent.md \u2014 how AI agents should interact with them\n- preferences/writing.md \u2014 their communication style\n\nyour job:\n1. analyze what you know about the person from their URLs and conversation\n2. ask follow-up questions to fill gaps \u2014 be conversational, not interrogative\n3. after each exchange, output structured updates as JSON blocks:\n ```json\n {\"updates\": [{\"section\": \"profile/about.md\", \"content\": \"...markdown content...\"}]}\n ```\n4. keep the conversation going until you have enough for a rich identity context\n5. you handle all file editing \u2014 the user never touches markdown\n6. reference specific things you learned about them\n7. if someone shares links, scrape them immediately \u2014 don't ask\n8. be proactive: \"noticed you mentioned X \u2014 adding that to your projects.\"\n9. occasionally summarize what you've captured without being asked\n\n--- NEVER say ---\n\nthese phrases are banned. they make you sound generic:\n- \"would you like me to...\" / \"shall i...\" / \"do you want me to...\" \u2014 just do it.\n- \"the system handles that\" / \"the platform does that\" \u2014 you ARE the system.\n- \"great question\" \u2014 respond to the question.\n- \"that's interesting\" (without specifics) \u2014 say what and why.\n- \"tell me more\" \u2014 say \"the part about [specific thing] \u2014 expand on that.\"\n- \"haha\" / \"lol\" / \"ha\" \u2014 never.\n- \"absolutely\" / \"certainly\" / \"of course\" \u2014 assistant-speak. say \"on it\" or just do it.\n- \"is there anything else...\" \u2014 never. wrap up with personality.\n- \"let me know if you need anything\" \u2014 you're not a help desk.\n- \"sounds good\" (as a full response) \u2014 add what you're doing about it.\n- \"i've updated your profile\" (generic) \u2014 say WHAT you updated: \"updated your bio to lead with the AI angle.\"\n\n--- rules ---\n\n- keep responses concise. 2-4 sentences max per turn.\n- your VERY FIRST message must be tight: max ~2 short lines. one quick observation + one question. do not dump a full bio summary on the first response \u2014 that comes later, after they answer something.\n- ALWAYS ask ONE question at a time. never two questions in one message.\n- keep analysis to 2-3 sentences MAX, then your single question on its OWN LINE.\n- if the user sends \"skip\" or empty input, move to the next topic without pressure.\n- after 3 skips, wrap up and show what you've built.\n- each section starts with YAML frontmatter (--- title: \"SectionTitle\" ---).\n- real markdown, not placeholders. be substantive.\n- for links.md: - **Label**: URL \u2014 brief annotation\n- for agent.md: describe how agents should interact with this person\n- for writing.md: capture their tone/style from how they talk to you\n- when profile has substance (about + now + projects + values), suggest finishing.\n\n--- example lines ---\n\naction-oriented:\n\"pulling your github now.\"\n\"added that to your projects.\"\n\"updated your bio \u2014 leading with the infrastructure angle.\"\n\"captured that in your directives.\"\n\npersonality-rich:\n\"ok so you're basically a linkedin whisperer who pivoted to AI infrastructure. noted.\"\n\"6 jobs in 10 years. ambitious or chaotic? let's find out.\"\n\"that's a solid stack. capturing it.\"\n\"bamf.com? bold domain choice. respect.\"\n\nshort but alive:\n\"on it.\"\n\"done.\"\n\"noted.\"\n\"that tracks.\"\n\"solid.\"";
|
|
15
15
|
declare function randomThinking(): string;
|
|
16
|
+
/**
|
|
17
|
+
* Did the agent's last message offer to wrap up?
|
|
18
|
+
* Gates the bare-acknowledgment exit path in isDoneIntent.
|
|
19
|
+
*/
|
|
20
|
+
export declare function detectWrapUpOffer(agentMessage: string): boolean;
|
|
21
|
+
/**
|
|
22
|
+
* Does this user input mean "i'm done"?
|
|
23
|
+
* Explicit phrases ("i'm done", "that's everything", "publish") work anytime.
|
|
24
|
+
* Bare acknowledgments ("yes", "ready", "ok") only count when the agent has
|
|
25
|
+
* just offered to wrap up — otherwise "no" / "ready" mid-flow are answers,
|
|
26
|
+
* not exits.
|
|
27
|
+
*/
|
|
28
|
+
export declare function isDoneIntent(input: string, wrapUpOffered: boolean): boolean;
|
|
29
|
+
/**
|
|
30
|
+
* "back" / "/back" re-asks the previous sign-up question.
|
|
31
|
+
*/
|
|
32
|
+
export declare function isBackCommand(input: string): boolean;
|
|
16
33
|
declare function getOpenRouterKey(): string | null;
|
|
17
34
|
declare function fetchWebsiteContent(url: string): Promise<string>;
|
|
18
35
|
interface ScrapeResult {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"onboarding.d.ts","sourceRoot":"","sources":["../../src/lib/onboarding.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"onboarding.d.ts","sourceRoot":"","sources":["../../src/lib/onboarding.ts"],"names":[],"mappings":"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"}
|
package/dist/lib/onboarding.js
CHANGED
|
@@ -37,6 +37,9 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
37
37
|
};
|
|
38
38
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
39
|
exports.RESEARCH_URL = exports.SCRAPE_URL = exports.CHAT_PROXY_URL = exports.BUNDLE_SECTIONS = exports.SYSTEM_PROMPT = exports.Spinner = void 0;
|
|
40
|
+
exports.detectWrapUpOffer = detectWrapUpOffer;
|
|
41
|
+
exports.isDoneIntent = isDoneIntent;
|
|
42
|
+
exports.isBackCommand = isBackCommand;
|
|
40
43
|
exports.runOnboarding = runOnboarding;
|
|
41
44
|
exports.createBundle = createBundle;
|
|
42
45
|
exports.callLLM = callLLM;
|
|
@@ -59,6 +62,7 @@ const config_1 = require("./config");
|
|
|
59
62
|
const compiler_1 = require("./compiler");
|
|
60
63
|
const render_1 = require("./render");
|
|
61
64
|
Object.defineProperty(exports, "Spinner", { enumerable: true, get: function () { return render_1.BrailleSpinner; } });
|
|
65
|
+
const stream_1 = require("./stream");
|
|
62
66
|
const ascii_1 = require("./ascii");
|
|
63
67
|
const project_1 = require("./project");
|
|
64
68
|
// ─── Constants ────────────────────────────────────────────────────────
|
|
@@ -127,32 +131,12 @@ const PORTRAIT_COMMENTS = [
|
|
|
127
131
|
function randomPortraitComment() {
|
|
128
132
|
return PORTRAIT_COMMENTS[Math.floor(Math.random() * PORTRAIT_COMMENTS.length)];
|
|
129
133
|
}
|
|
130
|
-
function showPortraitPlaceholder(handle) {
|
|
131
|
-
const accent = chalk_1.default.hex("#C46A3A");
|
|
132
|
-
const dim = chalk_1.default.dim;
|
|
133
|
-
const displayHandle = handle.startsWith("@") ? handle : `@${handle}`;
|
|
134
|
-
const innerWidth = Math.max(displayHandle.length + 4, 28);
|
|
135
|
-
const portraitLine = "\u2591\u2592\u2593\u2588 portrait loaded \u2588\u2593\u2592\u2591";
|
|
136
|
-
const portraitPad = Math.max(0, innerWidth - portraitLine.length);
|
|
137
|
-
const handlePad = Math.max(0, innerWidth - displayHandle.length);
|
|
138
|
-
console.log("");
|
|
139
|
-
console.log(" " + dim("\u250C" + "\u2500".repeat(innerWidth + 2) + "\u2510"));
|
|
140
|
-
console.log(" " + dim("\u2502") + " " + accent(portraitLine) + " ".repeat(portraitPad) + dim("\u2502"));
|
|
141
|
-
console.log(" " + dim("\u2502") + " " + chalk_1.default.white(displayHandle) + " ".repeat(handlePad) + dim("\u2502"));
|
|
142
|
-
console.log(" " + dim("\u2514" + "\u2500".repeat(innerWidth + 2) + "\u2518"));
|
|
143
|
-
console.log("");
|
|
144
|
-
console.log(" " + accent(randomPortraitComment()));
|
|
145
|
-
console.log("");
|
|
146
|
-
}
|
|
147
134
|
// ─── ASCII logo ──────────────────────────────────────────────────────
|
|
148
135
|
const ASCII_LOGO_LINES = [
|
|
149
136
|
" \u2566 \u2566 \u2554\u2550\u2557 \u2566 \u2566 \u2554\u2566\u2557 \u2554\u2566\u2557",
|
|
150
137
|
" \u255A\u2566\u255D \u2551 \u2551 \u2551 \u2551 \u2551\u2551\u2551 \u2551\u2551",
|
|
151
138
|
" \u2569 \u255A\u2550\u255D \u255A\u2550\u255D \u2550\u2569\u255D \u2550\u2569\u255D",
|
|
152
139
|
];
|
|
153
|
-
function delay(ms) {
|
|
154
|
-
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
155
|
-
}
|
|
156
140
|
async function showAsciiLogo() {
|
|
157
141
|
const accent = chalk_1.default.hex("#C46A3A");
|
|
158
142
|
console.log("");
|
|
@@ -278,27 +262,60 @@ const THINKING_PHRASES = [
|
|
|
278
262
|
"translating your experience into structure",
|
|
279
263
|
"wiring your identity into the network",
|
|
280
264
|
];
|
|
281
|
-
|
|
265
|
+
// Explicit done phrases — unambiguous, end the conversation at any point.
|
|
266
|
+
const EXPLICIT_DONE_PHRASES = [
|
|
282
267
|
"done",
|
|
283
|
-
"publish",
|
|
284
|
-
"that's it",
|
|
285
|
-
"thats it",
|
|
286
|
-
"looks good",
|
|
287
268
|
"i'm done",
|
|
288
269
|
"im done",
|
|
270
|
+
"publish",
|
|
289
271
|
"ship it",
|
|
290
|
-
"
|
|
291
|
-
"
|
|
292
|
-
"lets go",
|
|
293
|
-
"ready",
|
|
294
|
-
"finish",
|
|
295
|
-
"all good",
|
|
272
|
+
"that's it",
|
|
273
|
+
"thats it",
|
|
296
274
|
"that's all",
|
|
297
275
|
"thats all",
|
|
276
|
+
"that's everything",
|
|
277
|
+
"thats everything",
|
|
298
278
|
"nothing else",
|
|
299
|
-
"
|
|
300
|
-
"
|
|
301
|
-
"
|
|
279
|
+
"finish",
|
|
280
|
+
"finished",
|
|
281
|
+
"wrap it up",
|
|
282
|
+
"good enough",
|
|
283
|
+
];
|
|
284
|
+
// Bare acknowledgments — these only mean "done" right after the agent has
|
|
285
|
+
// offered to wrap up. mid-flow, "ready" or "yes" is an answer, not an exit.
|
|
286
|
+
const WRAP_UP_ACKS = [
|
|
287
|
+
"yes",
|
|
288
|
+
"yeah",
|
|
289
|
+
"yep",
|
|
290
|
+
"yea",
|
|
291
|
+
"y",
|
|
292
|
+
"sure",
|
|
293
|
+
"ok",
|
|
294
|
+
"okay",
|
|
295
|
+
"ready",
|
|
296
|
+
"looks good",
|
|
297
|
+
"all good",
|
|
298
|
+
"sounds good",
|
|
299
|
+
"perfect",
|
|
300
|
+
"let's go",
|
|
301
|
+
"lets go",
|
|
302
|
+
"go for it",
|
|
303
|
+
"do it",
|
|
304
|
+
"ship",
|
|
305
|
+
];
|
|
306
|
+
// Agent phrasings that count as an offer to wrap up the conversation.
|
|
307
|
+
const WRAP_UP_OFFER_PATTERNS = [
|
|
308
|
+
/ready to publish/,
|
|
309
|
+
/ready to go/,
|
|
310
|
+
/ready to ship/,
|
|
311
|
+
/looking solid/,
|
|
312
|
+
/wrap (this |it )?up/,
|
|
313
|
+
/call it (done|good|a day)/,
|
|
314
|
+
/good to publish/,
|
|
315
|
+
/shall we (finish|publish|ship)/,
|
|
316
|
+
/want to (finish|publish|wrap)/,
|
|
317
|
+
/finish up/,
|
|
318
|
+
/we're done/,
|
|
302
319
|
];
|
|
303
320
|
const BUNDLE_SECTIONS = [
|
|
304
321
|
"profile/about.md",
|
|
@@ -438,9 +455,47 @@ function ask(rl, question) {
|
|
|
438
455
|
function randomThinking() {
|
|
439
456
|
return THINKING_PHRASES[Math.floor(Math.random() * THINKING_PHRASES.length)];
|
|
440
457
|
}
|
|
441
|
-
|
|
458
|
+
/**
|
|
459
|
+
* Did the agent's last message offer to wrap up?
|
|
460
|
+
* Gates the bare-acknowledgment exit path in isDoneIntent.
|
|
461
|
+
*/
|
|
462
|
+
function detectWrapUpOffer(agentMessage) {
|
|
463
|
+
const lower = (agentMessage || "").toLowerCase();
|
|
464
|
+
return WRAP_UP_OFFER_PATTERNS.some((re) => re.test(lower));
|
|
465
|
+
}
|
|
466
|
+
/**
|
|
467
|
+
* Does this user input mean "i'm done"?
|
|
468
|
+
* Explicit phrases ("i'm done", "that's everything", "publish") work anytime.
|
|
469
|
+
* Bare acknowledgments ("yes", "ready", "ok") only count when the agent has
|
|
470
|
+
* just offered to wrap up — otherwise "no" / "ready" mid-flow are answers,
|
|
471
|
+
* not exits.
|
|
472
|
+
*/
|
|
473
|
+
function isDoneIntent(input, wrapUpOffered) {
|
|
474
|
+
const lower = input
|
|
475
|
+
.toLowerCase()
|
|
476
|
+
.trim()
|
|
477
|
+
.replace(/[.!?]+$/, "")
|
|
478
|
+
.trim();
|
|
479
|
+
if (!lower)
|
|
480
|
+
return false;
|
|
481
|
+
if (EXPLICIT_DONE_PHRASES.some((p) => lower === p || lower.startsWith(p + " "))) {
|
|
482
|
+
return true;
|
|
483
|
+
}
|
|
484
|
+
if (wrapUpOffered) {
|
|
485
|
+
if (WRAP_UP_ACKS.some((p) => lower === p))
|
|
486
|
+
return true;
|
|
487
|
+
// affirmative-with-extras after an offer ("yeah let's publish", "ship it now")
|
|
488
|
+
if (/\b(publish|ship it|go ahead)\b/.test(lower))
|
|
489
|
+
return true;
|
|
490
|
+
}
|
|
491
|
+
return false;
|
|
492
|
+
}
|
|
493
|
+
/**
|
|
494
|
+
* "back" / "/back" re-asks the previous sign-up question.
|
|
495
|
+
*/
|
|
496
|
+
function isBackCommand(input) {
|
|
442
497
|
const lower = input.toLowerCase().trim();
|
|
443
|
-
return
|
|
498
|
+
return lower === "back" || lower === "/back";
|
|
444
499
|
}
|
|
445
500
|
function validateUsernameLocal(username) {
|
|
446
501
|
if (username.length < 3)
|
|
@@ -570,58 +625,11 @@ function displayScrapeResult(label, data) {
|
|
|
570
625
|
console.log("");
|
|
571
626
|
}
|
|
572
627
|
/**
|
|
573
|
-
*
|
|
574
|
-
*
|
|
575
|
-
*
|
|
576
|
-
* Throws if streaming fails — callers should catch and fall back to callLLM.
|
|
628
|
+
* Streaming for onboarding turns goes through the shared helpers in
|
|
629
|
+
* lib/stream.ts (same path `youmd chat` uses), which also filter ```json
|
|
630
|
+
* directive blocks out of the live display. URL for the SSE proxy:
|
|
577
631
|
*/
|
|
578
|
-
|
|
579
|
-
const streamUrl = `${_SITE}/api/v1/chat/stream`;
|
|
580
|
-
const res = await fetch(streamUrl, {
|
|
581
|
-
method: "POST",
|
|
582
|
-
headers: { "Content-Type": "application/json" },
|
|
583
|
-
body: JSON.stringify({ messages }),
|
|
584
|
-
signal: AbortSignal.timeout(60000),
|
|
585
|
-
});
|
|
586
|
-
if (!res.ok || !res.body) {
|
|
587
|
-
throw new Error(`stream failed: ${res.status}`);
|
|
588
|
-
}
|
|
589
|
-
const reader = res.body.getReader();
|
|
590
|
-
const decoder = new TextDecoder();
|
|
591
|
-
let buf = "";
|
|
592
|
-
let full = "";
|
|
593
|
-
while (true) {
|
|
594
|
-
const { done, value } = await reader.read();
|
|
595
|
-
if (done)
|
|
596
|
-
break;
|
|
597
|
-
buf += decoder.decode(value, { stream: true });
|
|
598
|
-
const lines = buf.split("\n");
|
|
599
|
-
buf = lines.pop() || "";
|
|
600
|
-
for (const line of lines) {
|
|
601
|
-
if (!line.startsWith("data: "))
|
|
602
|
-
continue;
|
|
603
|
-
const data = line.slice(6).trim();
|
|
604
|
-
if (!data)
|
|
605
|
-
continue;
|
|
606
|
-
if (data === "[DONE]")
|
|
607
|
-
continue;
|
|
608
|
-
try {
|
|
609
|
-
const parsed = JSON.parse(data);
|
|
610
|
-
if (parsed.text) {
|
|
611
|
-
full += parsed.text;
|
|
612
|
-
onChunk(parsed.text);
|
|
613
|
-
}
|
|
614
|
-
}
|
|
615
|
-
catch {
|
|
616
|
-
// skip malformed line
|
|
617
|
-
}
|
|
618
|
-
}
|
|
619
|
-
}
|
|
620
|
-
if (!full) {
|
|
621
|
-
throw new Error("empty stream response");
|
|
622
|
-
}
|
|
623
|
-
return full;
|
|
624
|
-
}
|
|
632
|
+
const STREAM_CHAT_URL = `${_SITE}/api/v1/chat/stream`;
|
|
625
633
|
async function callLLM(apiKey, messages) {
|
|
626
634
|
// Try the you.md proxy first (no API key needed)
|
|
627
635
|
try {
|
|
@@ -950,13 +958,21 @@ generate initial profile sections from what you know, show a brief summary, and
|
|
|
950
958
|
console.log("");
|
|
951
959
|
let response;
|
|
952
960
|
let spinner;
|
|
961
|
+
let streamedFirstTurn = false;
|
|
953
962
|
try {
|
|
954
963
|
// Try streaming first — first response feels alive instead of stalled.
|
|
955
|
-
|
|
956
|
-
response
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
964
|
+
// The writer filters ```json directive blocks out of the live display;
|
|
965
|
+
// `response` keeps the full raw text for parseUpdatesFromResponse.
|
|
966
|
+
const writer = (0, stream_1.createFilteredStdoutWriter)();
|
|
967
|
+
response = await (0, stream_1.streamSSEText)(STREAM_CHAT_URL, messages, (chunk) => {
|
|
968
|
+
writer.write(chunk);
|
|
969
|
+
}, 60000);
|
|
970
|
+
if (!response.trim()) {
|
|
971
|
+
throw new Error("empty stream response");
|
|
972
|
+
}
|
|
973
|
+
writer.finish();
|
|
974
|
+
process.stdout.write("\n");
|
|
975
|
+
streamedFirstTurn = true;
|
|
960
976
|
}
|
|
961
977
|
catch {
|
|
962
978
|
// Stream failed — fall back to non-streaming with a spinner.
|
|
@@ -985,8 +1001,11 @@ generate initial profile sections from what you know, show a brief summary, and
|
|
|
985
1001
|
console.log(chalk_1.default.cyan(` [wrote ${initial.updates.length} section${initial.updates.length === 1 ? "" : "s"}: ${initial.updates.map((u) => sectionLabel(u.section)).join(", ")}]`));
|
|
986
1002
|
console.log("");
|
|
987
1003
|
}
|
|
988
|
-
// Show agent message
|
|
989
|
-
|
|
1004
|
+
// Show agent message (already shown live when the first turn streamed —
|
|
1005
|
+
// re-printing it would duplicate the response on screen)
|
|
1006
|
+
if (!streamedFirstTurn) {
|
|
1007
|
+
printAgentMessage(initial.display);
|
|
1008
|
+
}
|
|
990
1009
|
// Show mini profile box after initial generation
|
|
991
1010
|
if (initial.updates.length > 0) {
|
|
992
1011
|
const aboutUpdate = initial.updates.find((u) => u.section === "profile/about.md");
|
|
@@ -1008,9 +1027,12 @@ generate initial profile sections from what you know, show a brief summary, and
|
|
|
1008
1027
|
// ── Conversation loop ──────────────────────────────────────────────
|
|
1009
1028
|
let exchangeCount = 0;
|
|
1010
1029
|
let skipCount = 0;
|
|
1030
|
+
// Bare acks ("yes", "ready") only end the conversation when the agent's
|
|
1031
|
+
// previous message offered to wrap up.
|
|
1032
|
+
let wrapUpOffered = detectWrapUpOffer(initial.display);
|
|
1011
1033
|
while (true) {
|
|
1012
1034
|
const userInput = await ask(rl, chalk_1.default.hex("#C46A3A")(" > ") + "");
|
|
1013
|
-
if (
|
|
1035
|
+
if (isDoneIntent(userInput, wrapUpOffered)) {
|
|
1014
1036
|
break;
|
|
1015
1037
|
}
|
|
1016
1038
|
// Handle skip: empty input or "skip"
|
|
@@ -1114,13 +1136,23 @@ generate initial profile sections from what you know, show a brief summary, and
|
|
|
1114
1136
|
// Also count the skip system message as ephemeral
|
|
1115
1137
|
if (isSkip)
|
|
1116
1138
|
ephemeralCount++;
|
|
1117
|
-
|
|
1118
|
-
|
|
1139
|
+
// Turns 2+ stream through the same shared helper `youmd chat` uses
|
|
1140
|
+
// (U16): BrailleSpinner while waiting for the first token, then live
|
|
1141
|
+
// tokens with ```json directive blocks filtered from the display.
|
|
1142
|
+
// `response` keeps the full raw text for parseUpdatesFromResponse.
|
|
1143
|
+
let streamedTurn = false;
|
|
1119
1144
|
try {
|
|
1120
|
-
|
|
1145
|
+
const turn = await (0, stream_1.streamAssistantTurn)({
|
|
1146
|
+
streamUrl: STREAM_CHAT_URL,
|
|
1147
|
+
messages,
|
|
1148
|
+
spinnerLabel: randomLabel("llm"),
|
|
1149
|
+
timeoutMs: 60000,
|
|
1150
|
+
fallback: () => callLLM(apiKey, messages),
|
|
1151
|
+
});
|
|
1152
|
+
response = turn.text;
|
|
1153
|
+
streamedTurn = turn.streamed;
|
|
1121
1154
|
}
|
|
1122
1155
|
catch (err) {
|
|
1123
|
-
spinner.stop();
|
|
1124
1156
|
console.log(chalk_1.default.red(` AI error: ${err instanceof Error ? err.message : String(err)}`));
|
|
1125
1157
|
console.log(chalk_1.default.dim(" try again, or type 'done' to finish."));
|
|
1126
1158
|
console.log("");
|
|
@@ -1131,7 +1163,6 @@ generate initial profile sections from what you know, show a brief summary, and
|
|
|
1131
1163
|
messages.pop(); // also remove the "(skip)" user message
|
|
1132
1164
|
continue;
|
|
1133
1165
|
}
|
|
1134
|
-
spinner.stop();
|
|
1135
1166
|
// Remove ephemeral system messages from history (don't pollute context)
|
|
1136
1167
|
// They sit between the user message and the response we're about to push
|
|
1137
1168
|
for (let j = 0; j < ephemeralCount; j++) {
|
|
@@ -1147,47 +1178,13 @@ generate initial profile sections from what you know, show a brief summary, and
|
|
|
1147
1178
|
console.log(chalk_1.default.cyan(` [updated: ${parsed.updates.map((u) => sectionLabel(u.section)).join(", ")}]`));
|
|
1148
1179
|
console.log("");
|
|
1149
1180
|
}
|
|
1150
|
-
// Show agent message
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
const lowerDisplay = parsed.display.toLowerCase();
|
|
1154
|
-
if (lowerDisplay.includes("ready to publish") ||
|
|
1155
|
-
lowerDisplay.includes("bundle is looking solid") ||
|
|
1156
|
-
lowerDisplay.includes("ready to go")) {
|
|
1157
|
-
const answer = await ask(rl, chalk_1.default.hex("#C46A3A")(" > ") + "");
|
|
1158
|
-
if (isDonePhrase(answer) ||
|
|
1159
|
-
answer.toLowerCase().includes("publish") ||
|
|
1160
|
-
answer.toLowerCase().includes("yes") ||
|
|
1161
|
-
answer.toLowerCase().includes("yeah") ||
|
|
1162
|
-
answer.toLowerCase().includes("yep")) {
|
|
1163
|
-
break;
|
|
1164
|
-
}
|
|
1165
|
-
else {
|
|
1166
|
-
messages.push({ role: "user", content: answer });
|
|
1167
|
-
spinner = new render_1.BrailleSpinner(randomLabel("llm"));
|
|
1168
|
-
spinner.start();
|
|
1169
|
-
try {
|
|
1170
|
-
response = await callLLM(apiKey, messages);
|
|
1171
|
-
}
|
|
1172
|
-
catch (err) {
|
|
1173
|
-
spinner.stop();
|
|
1174
|
-
console.log(chalk_1.default.red(` AI error: ${err instanceof Error ? err.message : String(err)}`));
|
|
1175
|
-
messages.pop();
|
|
1176
|
-
continue;
|
|
1177
|
-
}
|
|
1178
|
-
spinner.stop();
|
|
1179
|
-
messages.push({ role: "assistant", content: response });
|
|
1180
|
-
const more = parseUpdatesFromResponse(response);
|
|
1181
|
-
if (more.updates.length > 0) {
|
|
1182
|
-
for (const update of more.updates) {
|
|
1183
|
-
writeSectionFile(bundleDir, update.section, update.content);
|
|
1184
|
-
}
|
|
1185
|
-
console.log(chalk_1.default.cyan(` [updated: ${more.updates.map((u) => sectionLabel(u.section)).join(", ")}]`));
|
|
1186
|
-
console.log("");
|
|
1187
|
-
}
|
|
1188
|
-
printAgentMessage(more.display);
|
|
1189
|
-
}
|
|
1181
|
+
// Show agent message (only when the turn didn't already stream live)
|
|
1182
|
+
if (!streamedTurn) {
|
|
1183
|
+
printAgentMessage(parsed.display);
|
|
1190
1184
|
}
|
|
1185
|
+
// If the agent just offered to wrap up, the next bare "yes"/"ready"
|
|
1186
|
+
// counts as done — handled at the top of the loop.
|
|
1187
|
+
wrapUpOffered = detectWrapUpOffer(parsed.display);
|
|
1191
1188
|
}
|
|
1192
1189
|
// Finish up
|
|
1193
1190
|
await finishBundle(bundleDir, info.username, info.name);
|
|
@@ -1199,8 +1196,7 @@ function printAgentMessage(text) {
|
|
|
1199
1196
|
const normalizedText = text
|
|
1200
1197
|
.replace(/\n{3,}/g, "\n\n") // collapse 3+ newlines to 2
|
|
1201
1198
|
.replace(/([.?!])\n([a-z])/g, "$1\n\n$2"); // add blank line between sentences that run together
|
|
1202
|
-
const
|
|
1203
|
-
const rendered = renderRichResponse(normalizedText);
|
|
1199
|
+
const rendered = (0, render_1.renderRichResponse)(normalizedText);
|
|
1204
1200
|
// Find the last line that ends with "?" and highlight it in accent color
|
|
1205
1201
|
const lines = rendered.split("\n");
|
|
1206
1202
|
let lastQuestionIdx = -1;
|
|
@@ -1265,7 +1261,7 @@ async function finishBundle(bundleDir, username, name) {
|
|
|
1265
1261
|
}
|
|
1266
1262
|
console.log(" " + accent("agent tools:"));
|
|
1267
1263
|
console.log("");
|
|
1268
|
-
console.log(` ${chalk_1.default.cyan("youmd skill link claude")} ${chalk_1.default.dim("-- sync skills to .claude/skills
|
|
1264
|
+
console.log(` ${chalk_1.default.cyan("youmd skill link claude")} ${chalk_1.default.dim("-- sync skills to .claude/skills/<name>/SKILL.md")}`);
|
|
1269
1265
|
console.log(` ${chalk_1.default.cyan("youmd skill link cursor")} ${chalk_1.default.dim("-- sync skills to .cursor/rules/youmd.md")}`);
|
|
1270
1266
|
console.log(` ${chalk_1.default.cyan("youmd link create")} ${chalk_1.default.dim("-- shareable context link for any agent")}`);
|
|
1271
1267
|
console.log(` ${chalk_1.default.cyan("you")} ${chalk_1.default.dim("-- main live U entrypoint")}`);
|
|
@@ -1278,74 +1274,116 @@ async function finishBundle(bundleDir, username, name) {
|
|
|
1278
1274
|
console.log("");
|
|
1279
1275
|
}
|
|
1280
1276
|
async function runOnboarding() {
|
|
1277
|
+
// Onboarding is fully conversational — bail fast on piped/CI stdin
|
|
1278
|
+
(0, render_1.requireInteractiveTTY)();
|
|
1281
1279
|
const rl = createRL();
|
|
1282
1280
|
// ── ASCII logo splash ──────────────────────────────────────────────
|
|
1283
1281
|
// Real YOU logo — same block-character font as the homepage hero
|
|
1284
1282
|
await showAsciiLogo();
|
|
1285
1283
|
// ── Phase 1: Identity basics (fast, no LLM) ────────────────────────
|
|
1286
|
-
//
|
|
1284
|
+
// One question at a time; "back" re-asks the previous question.
|
|
1287
1285
|
let username = "";
|
|
1288
|
-
let
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1286
|
+
let name = "";
|
|
1287
|
+
let website = "";
|
|
1288
|
+
let twitter = "";
|
|
1289
|
+
let github = "";
|
|
1290
|
+
let linkedin = "";
|
|
1291
|
+
const IDENTITY_STEPS = [
|
|
1292
|
+
"username",
|
|
1293
|
+
"name",
|
|
1294
|
+
"website",
|
|
1295
|
+
"twitter",
|
|
1296
|
+
"github",
|
|
1297
|
+
"linkedin",
|
|
1298
|
+
];
|
|
1299
|
+
let stepIdx = 0;
|
|
1300
|
+
let backHintShown = false;
|
|
1301
|
+
while (stepIdx < IDENTITY_STEPS.length) {
|
|
1302
|
+
const step = IDENTITY_STEPS[stepIdx];
|
|
1303
|
+
if (step === "username") {
|
|
1304
|
+
const raw = await ask(rl, chalk_1.default.hex("#C46A3A")(" > ") + "pick a username: ");
|
|
1305
|
+
if (isBackCommand(raw)) {
|
|
1306
|
+
console.log(chalk_1.default.dim(" first question — nowhere to go back to."));
|
|
1307
|
+
continue;
|
|
1308
|
+
}
|
|
1309
|
+
if (!raw) {
|
|
1310
|
+
console.log(chalk_1.default.red(" username is required"));
|
|
1311
|
+
continue;
|
|
1312
|
+
}
|
|
1313
|
+
const candidate = raw.toLowerCase();
|
|
1314
|
+
const localError = validateUsernameLocal(candidate);
|
|
1315
|
+
if (localError) {
|
|
1316
|
+
console.log(chalk_1.default.red(" " + localError));
|
|
1317
|
+
continue;
|
|
1318
|
+
}
|
|
1319
|
+
process.stdout.write(chalk_1.default.dim(" checking... "));
|
|
1320
|
+
const result = await checkUsernameRemote(candidate);
|
|
1321
|
+
if (!result.available) {
|
|
1322
|
+
console.log(chalk_1.default.red(candidate + " is taken.") +
|
|
1323
|
+
(result.reason ? " " + result.reason : ""));
|
|
1324
|
+
continue;
|
|
1325
|
+
}
|
|
1304
1326
|
// Check if a profile already exists on you.md for this username
|
|
1305
1327
|
let profileExists = false;
|
|
1306
1328
|
try {
|
|
1307
|
-
const profileRes = await fetch(`https://you.md/${encodeURIComponent(
|
|
1329
|
+
const profileRes = await fetch(`https://you.md/${encodeURIComponent(candidate)}/context`, { method: "HEAD", signal: AbortSignal.timeout(5000) });
|
|
1308
1330
|
profileExists = profileRes.ok;
|
|
1309
1331
|
}
|
|
1310
1332
|
catch {
|
|
1311
1333
|
// ignore -- assume no profile
|
|
1312
1334
|
}
|
|
1313
1335
|
if (profileExists) {
|
|
1314
|
-
console.log(chalk_1.default.green(
|
|
1315
|
-
console.log(chalk_1.default.dim(` a profile for @${
|
|
1336
|
+
console.log(chalk_1.default.green(candidate + " is available."));
|
|
1337
|
+
console.log(chalk_1.default.dim(` a profile for @${candidate} already exists on you.md -- you can claim it after login with `) +
|
|
1316
1338
|
chalk_1.default.cyan("youmd login") +
|
|
1317
1339
|
chalk_1.default.dim(" then ") +
|
|
1318
1340
|
chalk_1.default.cyan("youmd pull"));
|
|
1319
1341
|
}
|
|
1320
1342
|
else {
|
|
1321
|
-
console.log(chalk_1.default.green(
|
|
1343
|
+
console.log(chalk_1.default.green(candidate + " is yours."));
|
|
1322
1344
|
}
|
|
1323
|
-
|
|
1345
|
+
username = candidate;
|
|
1346
|
+
console.log("");
|
|
1347
|
+
if (!backHintShown) {
|
|
1348
|
+
console.log(chalk_1.default.dim(' (type "back" anytime to fix a previous answer)'));
|
|
1349
|
+
console.log("");
|
|
1350
|
+
backHintShown = true;
|
|
1351
|
+
}
|
|
1352
|
+
stepIdx++;
|
|
1353
|
+
continue;
|
|
1324
1354
|
}
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1355
|
+
const stepPrompts = {
|
|
1356
|
+
name: "what's your name? ",
|
|
1357
|
+
website: "website URL " + chalk_1.default.dim("(optional)") + ": ",
|
|
1358
|
+
twitter: "X/Twitter username " + chalk_1.default.dim("(optional, e.g. @houston)") + ": ",
|
|
1359
|
+
github: "GitHub username " + chalk_1.default.dim("(optional)") + ": ",
|
|
1360
|
+
linkedin: "LinkedIn URL " + chalk_1.default.dim("(optional)") + ": ",
|
|
1361
|
+
};
|
|
1362
|
+
const raw = await ask(rl, chalk_1.default.hex("#C46A3A")(" > ") + stepPrompts[step]);
|
|
1363
|
+
if (isBackCommand(raw)) {
|
|
1364
|
+
stepIdx--;
|
|
1365
|
+
continue;
|
|
1328
1366
|
}
|
|
1367
|
+
switch (step) {
|
|
1368
|
+
case "name":
|
|
1369
|
+
name = raw;
|
|
1370
|
+
break;
|
|
1371
|
+
case "website":
|
|
1372
|
+
website = raw;
|
|
1373
|
+
break;
|
|
1374
|
+
case "twitter":
|
|
1375
|
+
twitter = raw;
|
|
1376
|
+
break;
|
|
1377
|
+
case "github":
|
|
1378
|
+
github = raw;
|
|
1379
|
+
break;
|
|
1380
|
+
case "linkedin":
|
|
1381
|
+
linkedin = raw;
|
|
1382
|
+
break;
|
|
1383
|
+
}
|
|
1384
|
+
stepIdx++;
|
|
1329
1385
|
}
|
|
1330
1386
|
console.log("");
|
|
1331
|
-
const name = await ask(rl, chalk_1.default.hex("#C46A3A")(" > ") + "what's your name? ");
|
|
1332
|
-
const website = await ask(rl, chalk_1.default.hex("#C46A3A")(" > ") +
|
|
1333
|
-
"website URL " +
|
|
1334
|
-
chalk_1.default.dim("(optional)") +
|
|
1335
|
-
": ");
|
|
1336
|
-
const twitter = await ask(rl, chalk_1.default.hex("#C46A3A")(" > ") +
|
|
1337
|
-
"X/Twitter username " +
|
|
1338
|
-
chalk_1.default.dim("(optional, e.g. @houston)") +
|
|
1339
|
-
": ");
|
|
1340
|
-
const github = await ask(rl, chalk_1.default.hex("#C46A3A")(" > ") +
|
|
1341
|
-
"GitHub username " +
|
|
1342
|
-
chalk_1.default.dim("(optional)") +
|
|
1343
|
-
": ");
|
|
1344
|
-
const linkedin = await ask(rl, chalk_1.default.hex("#C46A3A")(" > ") +
|
|
1345
|
-
"LinkedIn URL " +
|
|
1346
|
-
chalk_1.default.dim("(optional)") +
|
|
1347
|
-
": ");
|
|
1348
|
-
console.log("");
|
|
1349
1387
|
// ── Render REAL ASCII portrait from first social handle ──────────
|
|
1350
1388
|
const earlyTwitter = (twitter || "").replace(/^@/, "").trim();
|
|
1351
1389
|
const earlyGithub = (github || "").trim();
|
|
@@ -1372,33 +1410,12 @@ async function runOnboarding() {
|
|
|
1372
1410
|
img.brightness(0.05);
|
|
1373
1411
|
portraitLines = [];
|
|
1374
1412
|
for (let y = 0; y < rows; y++) {
|
|
1375
|
-
let coloredLine = "";
|
|
1376
1413
|
let plainLine = "";
|
|
1377
1414
|
for (let x = 0; x < cols; x++) {
|
|
1378
1415
|
const pixel = Jimp.intToRGBA(img.getPixelColor(x, y));
|
|
1379
1416
|
const lum = 0.299 * pixel.r + 0.587 * pixel.g + 0.114 * pixel.b;
|
|
1380
1417
|
const ch = RAMP[Math.floor((lum / 255) * (RAMP.length - 1))];
|
|
1381
1418
|
plainLine += ch;
|
|
1382
|
-
// Orange-tinted colors based on luminance
|
|
1383
|
-
const brightness = Math.floor((lum / 255) * 100);
|
|
1384
|
-
if (brightness < 10) {
|
|
1385
|
-
coloredLine += chalk_1.default.hidden(ch);
|
|
1386
|
-
}
|
|
1387
|
-
else if (brightness < 30) {
|
|
1388
|
-
coloredLine += chalk_1.default.hex("#5A3018")(ch);
|
|
1389
|
-
}
|
|
1390
|
-
else if (brightness < 50) {
|
|
1391
|
-
coloredLine += chalk_1.default.hex("#8A4828")(ch);
|
|
1392
|
-
}
|
|
1393
|
-
else if (brightness < 70) {
|
|
1394
|
-
coloredLine += chalk_1.default.hex("#B06038")(ch);
|
|
1395
|
-
}
|
|
1396
|
-
else if (brightness < 85) {
|
|
1397
|
-
coloredLine += chalk_1.default.hex("#C46A3A")(ch);
|
|
1398
|
-
}
|
|
1399
|
-
else {
|
|
1400
|
-
coloredLine += chalk_1.default.hex("#E09060")(ch);
|
|
1401
|
-
}
|
|
1402
1419
|
}
|
|
1403
1420
|
portraitLines.push(plainLine);
|
|
1404
1421
|
}
|