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.
Files changed (218) hide show
  1. package/dist/commands/build.d.ts.map +1 -1
  2. package/dist/commands/build.js +0 -1
  3. package/dist/commands/build.js.map +1 -1
  4. package/dist/commands/chat.d.ts.map +1 -1
  5. package/dist/commands/chat.js +283 -184
  6. package/dist/commands/chat.js.map +1 -1
  7. package/dist/commands/export.d.ts +1 -0
  8. package/dist/commands/export.d.ts.map +1 -1
  9. package/dist/commands/export.js +5 -0
  10. package/dist/commands/export.js.map +1 -1
  11. package/dist/commands/init.d.ts.map +1 -1
  12. package/dist/commands/init.js +21 -1
  13. package/dist/commands/init.js.map +1 -1
  14. package/dist/commands/keys.d.ts.map +1 -1
  15. package/dist/commands/keys.js +3 -3
  16. package/dist/commands/keys.js.map +1 -1
  17. package/dist/commands/link.d.ts.map +1 -1
  18. package/dist/commands/link.js +3 -3
  19. package/dist/commands/link.js.map +1 -1
  20. package/dist/commands/login.d.ts +29 -0
  21. package/dist/commands/login.d.ts.map +1 -1
  22. package/dist/commands/login.js +256 -127
  23. package/dist/commands/login.js.map +1 -1
  24. package/dist/commands/logs.js +0 -1
  25. package/dist/commands/logs.js.map +1 -1
  26. package/dist/commands/mcp.d.ts +14 -0
  27. package/dist/commands/mcp.d.ts.map +1 -1
  28. package/dist/commands/mcp.js +284 -28
  29. package/dist/commands/mcp.js.map +1 -1
  30. package/dist/commands/okf.d.ts +12 -0
  31. package/dist/commands/okf.d.ts.map +1 -0
  32. package/dist/commands/okf.js +411 -0
  33. package/dist/commands/okf.js.map +1 -0
  34. package/dist/commands/private.d.ts.map +1 -1
  35. package/dist/commands/private.js +6 -5
  36. package/dist/commands/private.js.map +1 -1
  37. package/dist/commands/project.d.ts.map +1 -1
  38. package/dist/commands/project.js +9 -5
  39. package/dist/commands/project.js.map +1 -1
  40. package/dist/commands/publish.d.ts.map +1 -1
  41. package/dist/commands/publish.js +0 -1
  42. package/dist/commands/publish.js.map +1 -1
  43. package/dist/commands/pull.d.ts +24 -1
  44. package/dist/commands/pull.d.ts.map +1 -1
  45. package/dist/commands/pull.js +114 -14
  46. package/dist/commands/pull.js.map +1 -1
  47. package/dist/commands/push.d.ts +1 -0
  48. package/dist/commands/push.d.ts.map +1 -1
  49. package/dist/commands/push.js +33 -13
  50. package/dist/commands/push.js.map +1 -1
  51. package/dist/commands/register.d.ts +6 -0
  52. package/dist/commands/register.d.ts.map +1 -1
  53. package/dist/commands/register.js +179 -79
  54. package/dist/commands/register.js.map +1 -1
  55. package/dist/commands/skill.d.ts.map +1 -1
  56. package/dist/commands/skill.js +121 -50
  57. package/dist/commands/skill.js.map +1 -1
  58. package/dist/commands/stack.d.ts +16 -0
  59. package/dist/commands/stack.d.ts.map +1 -0
  60. package/dist/commands/stack.js +863 -0
  61. package/dist/commands/stack.js.map +1 -0
  62. package/dist/commands/status.d.ts.map +1 -1
  63. package/dist/commands/status.js +25 -5
  64. package/dist/commands/status.js.map +1 -1
  65. package/dist/commands/sync.d.ts +23 -0
  66. package/dist/commands/sync.d.ts.map +1 -1
  67. package/dist/commands/sync.js +193 -12
  68. package/dist/commands/sync.js.map +1 -1
  69. package/dist/commands/whoami.d.ts.map +1 -1
  70. package/dist/commands/whoami.js +21 -16
  71. package/dist/commands/whoami.js.map +1 -1
  72. package/dist/create.js +0 -0
  73. package/dist/index.js +64 -7
  74. package/dist/index.js.map +1 -1
  75. package/dist/lib/api.d.ts +127 -5
  76. package/dist/lib/api.d.ts.map +1 -1
  77. package/dist/lib/api.js +142 -5
  78. package/dist/lib/api.js.map +1 -1
  79. package/dist/lib/ascii.d.ts +1 -0
  80. package/dist/lib/ascii.d.ts.map +1 -1
  81. package/dist/lib/ascii.js +9 -26
  82. package/dist/lib/ascii.js.map +1 -1
  83. package/dist/lib/canonical-json.d.ts +8 -0
  84. package/dist/lib/canonical-json.d.ts.map +1 -0
  85. package/dist/lib/canonical-json.js +29 -0
  86. package/dist/lib/canonical-json.js.map +1 -0
  87. package/dist/lib/capability-router.d.ts +58 -0
  88. package/dist/lib/capability-router.d.ts.map +1 -0
  89. package/dist/lib/capability-router.js +54 -0
  90. package/dist/lib/capability-router.js.map +1 -0
  91. package/dist/lib/compiler.d.ts +32 -0
  92. package/dist/lib/compiler.d.ts.map +1 -1
  93. package/dist/lib/compiler.js +150 -0
  94. package/dist/lib/compiler.js.map +1 -1
  95. package/dist/lib/config.d.ts +71 -35
  96. package/dist/lib/config.d.ts.map +1 -1
  97. package/dist/lib/config.js +334 -124
  98. package/dist/lib/config.js.map +1 -1
  99. package/dist/lib/decompile.d.ts +6 -1
  100. package/dist/lib/decompile.d.ts.map +1 -1
  101. package/dist/lib/decompile.js +120 -11
  102. package/dist/lib/decompile.js.map +1 -1
  103. package/dist/lib/hash.d.ts.map +1 -1
  104. package/dist/lib/hash.js +2 -19
  105. package/dist/lib/hash.js.map +1 -1
  106. package/dist/lib/heartbeat.d.ts +38 -0
  107. package/dist/lib/heartbeat.d.ts.map +1 -0
  108. package/dist/lib/heartbeat.js +70 -0
  109. package/dist/lib/heartbeat.js.map +1 -0
  110. package/dist/lib/host-link.d.ts +123 -0
  111. package/dist/lib/host-link.d.ts.map +1 -0
  112. package/dist/lib/host-link.js +350 -0
  113. package/dist/lib/host-link.js.map +1 -0
  114. package/dist/lib/merge.d.ts +50 -0
  115. package/dist/lib/merge.d.ts.map +1 -0
  116. package/dist/lib/merge.js +167 -0
  117. package/dist/lib/merge.js.map +1 -0
  118. package/dist/lib/okf-bundle.d.ts +104 -0
  119. package/dist/lib/okf-bundle.d.ts.map +1 -0
  120. package/dist/lib/okf-bundle.js +473 -0
  121. package/dist/lib/okf-bundle.js.map +1 -0
  122. package/dist/lib/okf-health.d.ts +40 -0
  123. package/dist/lib/okf-health.d.ts.map +1 -0
  124. package/dist/lib/okf-health.js +152 -0
  125. package/dist/lib/okf-health.js.map +1 -0
  126. package/dist/lib/okf-stack.d.ts +47 -0
  127. package/dist/lib/okf-stack.d.ts.map +1 -0
  128. package/dist/lib/okf-stack.js +331 -0
  129. package/dist/lib/okf-stack.js.map +1 -0
  130. package/dist/lib/okf-view.d.ts +49 -0
  131. package/dist/lib/okf-view.d.ts.map +1 -0
  132. package/dist/lib/okf-view.js +197 -0
  133. package/dist/lib/okf-view.js.map +1 -0
  134. package/dist/lib/okf.d.ts +130 -0
  135. package/dist/lib/okf.d.ts.map +1 -0
  136. package/dist/lib/okf.js +263 -0
  137. package/dist/lib/okf.js.map +1 -0
  138. package/dist/lib/onboarding.d.ts +17 -0
  139. package/dist/lib/onboarding.d.ts.map +1 -1
  140. package/dist/lib/onboarding.js +224 -207
  141. package/dist/lib/onboarding.js.map +1 -1
  142. package/dist/lib/project.d.ts +5 -0
  143. package/dist/lib/project.d.ts.map +1 -1
  144. package/dist/lib/project.js +8 -0
  145. package/dist/lib/project.js.map +1 -1
  146. package/dist/lib/projectContext.d.ts +201 -0
  147. package/dist/lib/projectContext.d.ts.map +1 -0
  148. package/dist/lib/projectContext.js +597 -0
  149. package/dist/lib/projectContext.js.map +1 -0
  150. package/dist/lib/render.d.ts +38 -1
  151. package/dist/lib/render.d.ts.map +1 -1
  152. package/dist/lib/render.js +83 -18
  153. package/dist/lib/render.js.map +1 -1
  154. package/dist/lib/skill-catalog.d.ts.map +1 -1
  155. package/dist/lib/skill-catalog.js +22 -2
  156. package/dist/lib/skill-catalog.js.map +1 -1
  157. package/dist/lib/skills.d.ts +20 -5
  158. package/dist/lib/skills.d.ts.map +1 -1
  159. package/dist/lib/skills.js +116 -58
  160. package/dist/lib/skills.js.map +1 -1
  161. package/dist/lib/stackEval.d.ts +87 -0
  162. package/dist/lib/stackEval.d.ts.map +1 -0
  163. package/dist/lib/stackEval.js +233 -0
  164. package/dist/lib/stackEval.js.map +1 -0
  165. package/dist/lib/stackImprove.d.ts +49 -0
  166. package/dist/lib/stackImprove.d.ts.map +1 -0
  167. package/dist/lib/stackImprove.js +313 -0
  168. package/dist/lib/stackImprove.js.map +1 -0
  169. package/dist/lib/stackInstall.d.ts +59 -0
  170. package/dist/lib/stackInstall.d.ts.map +1 -0
  171. package/dist/lib/stackInstall.js +162 -0
  172. package/dist/lib/stackInstall.js.map +1 -0
  173. package/dist/lib/stackSafety.d.ts +126 -0
  174. package/dist/lib/stackSafety.d.ts.map +1 -0
  175. package/dist/lib/stackSafety.js +486 -0
  176. package/dist/lib/stackSafety.js.map +1 -0
  177. package/dist/lib/stackUpdate.d.ts +44 -0
  178. package/dist/lib/stackUpdate.d.ts.map +1 -0
  179. package/dist/lib/stackUpdate.js +256 -0
  180. package/dist/lib/stackUpdate.js.map +1 -0
  181. package/dist/lib/stream.d.ts +116 -0
  182. package/dist/lib/stream.d.ts.map +1 -0
  183. package/dist/lib/stream.js +368 -0
  184. package/dist/lib/stream.js.map +1 -0
  185. package/dist/lib/youstack.d.ts +219 -0
  186. package/dist/lib/youstack.d.ts.map +1 -0
  187. package/dist/lib/youstack.js +1049 -0
  188. package/dist/lib/youstack.js.map +1 -0
  189. package/dist/mcp/registry.d.ts +133 -0
  190. package/dist/mcp/registry.d.ts.map +1 -0
  191. package/dist/mcp/registry.js +833 -0
  192. package/dist/mcp/registry.js.map +1 -0
  193. package/dist/mcp/server.d.ts +106 -5
  194. package/dist/mcp/server.d.ts.map +1 -1
  195. package/dist/mcp/server.js +851 -498
  196. package/dist/mcp/server.js.map +1 -1
  197. package/dist/postinstall.js +11 -2
  198. package/dist/postinstall.js.map +1 -1
  199. package/dist/you.d.ts +1 -0
  200. package/dist/you.js +40 -4
  201. package/dist/you.js.map +1 -1
  202. package/examples/youstack-bamfstack-public/docs/quickstart.md +34 -0
  203. package/examples/youstack-bamfstack-public/prompts/creator-draft-starter.md +15 -0
  204. package/examples/youstack-bamfstack-public/skills/bamfstack-start/SKILL.md +36 -0
  205. package/examples/youstack-bamfstack-public/tests/smoke.md +19 -0
  206. package/examples/youstack-bamfstack-public/workflows/creator-growth-workflow.md +22 -0
  207. package/examples/youstack-bamfstack-public/youstack.json +172 -0
  208. package/examples/youstack-personal/docs/quickstart.md +10 -0
  209. package/examples/youstack-personal/skills/youstack-start/SKILL.md +9 -0
  210. package/examples/youstack-personal/tests/smoke.md +9 -0
  211. package/examples/youstack-personal/workflows/startup.md +7 -0
  212. package/examples/youstack-personal/youstack.json +123 -0
  213. package/package.json +3 -3
  214. package/skills/claude-md-generator.md +1 -1
  215. package/skills/meta-improve.md +8 -3
  216. package/skills/proactive-context-fill.md +1 -1
  217. package/skills/youstack-maintainer.md +128 -0
  218. package/skills/youstack-start.md +78 -0
@@ -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.21";
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, falling back to blocking callLLM on failure.
135
- * Returns the full response text.
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
- const thinkSpinner = new render_1.BrailleSpinner(spinnerLabel);
139
- thinkSpinner.start();
140
- try {
141
- let firstToken = true;
142
- const response = await streamLLM(apiKey, messages, (token) => {
143
- if (firstToken) {
144
- // Clear the spinner line before writing streamed text
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
- let domain = match[1].replace(/[.,;:)\]]+$/, "");
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, label } of dirs) {
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(bundleDir) {
609
- // Try to read username from the about.md or config
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
- name: projectCtx.name,
1033
- slug: projectCtx.name,
1034
- projectDir: projectCtx.root,
1035
- updatedAt: Date.now(),
1036
- signals: ["still wants cleaner agent wiring and project-context scaffolding"],
1037
- summary: `${projectCtx.name} still wants cleaner agent wiring and project-context scaffolding.`,
1038
- suggestedCommand: "youmd skill init-project",
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
- await delay(900);
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
- return { tool: "write_project_context", project: launchInvestigation.strongestProject?.name, mode: "bootstrap" };
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 files = [
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
- "project-context/CURRENT_STATE.md",
1485
- "project-context/TODO.md",
1486
- "project-context/PRD.md",
1487
- "project-context/ARCHITECTURE.md",
1488
- ".you/project-context/CURRENT_STATE.md",
1489
- ".you/project-context/TODO.md",
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((relativePath) => {
1493
- const snippet = readSnippet(path.join(project.projectDir, relativePath));
1494
- return snippet ? `file: ${relativePath}\n${snippet}` : null;
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: write a sharper current-state + TODO pass for ${project.name} if the user wants this project tightened.`,
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 runToolResultThroughModel = async (toolResult, spinnerLabel) => {
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 result = await callLLMWithStreaming(args.apiKey, args.messages, spinnerLabel);
1658
- args.messages.push({ role: "assistant", content: result.text });
1659
- if (!result.streamed) {
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
- await runToolResultThroughModel(toolResult, `summarizing ${toolCall.tool}`);
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 activeProjectDir = null;
1806
+ let activeProjectResolution = null;
1722
1807
  if (projectCtx) {
1723
- // Try the new file-system project context first
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
- if (projectsRoot) {
1726
- const detected = (0, project_1.detectCurrentProject)(projectsRoot);
1727
- if (detected) {
1728
- activeProjectDir = (0, project_1.getProjectDir)(projectsRoot, detected);
1729
- const injection = (0, project_1.buildProjectContextInjection)(activeProjectDir);
1730
- if (injection) {
1731
- projectContextBlock = `\n\n--- project context ---\n${injection}`;
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, config_1.readProjectPrivateNotes)(projectCtx.name);
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(bundleDir);
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 { listMemories } = require("../lib/api");
1844
- const res = await listMemories({ limit: 20 });
1845
- if (res.ok && Array.isArray(res.data) && res.data.length > 0) {
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 res.data)
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: ${res.data.length} total`));
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 { listMemories } = require("../lib/api");
1868
- const res = await listMemories({ limit: 50 });
1869
- if (res.ok && Array.isArray(res.data)) {
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
- ? res.data.filter((m) => m.content.toLowerCase().includes(query) || m.category.includes(query))
1872
- : res.data.slice(0, 10);
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 { getPrivateContext } = require("../lib/api");
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
- // For projects, we'd need to fetch existing + append simplified for now
2155
- console.log(chalk_1.default.green(` [saved private project: ${pu.project.name || "unnamed"}]`));
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
- if (activeProjectDir) {
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, project_1.updateProjectFile)(activeProjectDir, pu.file, pu.content);
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
- const { renderRichResponse } = require("../lib/render");
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