@tritard/waterbrother 0.12.1 → 0.12.3

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tritard/waterbrother",
3
- "version": "0.12.1",
3
+ "version": "0.12.3",
4
4
  "description": "Waterbrother: Grok-powered coding CLI with local tools, sessions, operator modes, and approval controls",
5
5
  "type": "module",
6
6
  "bin": {
package/src/cli.js CHANGED
@@ -5013,30 +5013,9 @@ async function promptLoop(agent, session, context) {
5013
5013
  if (detectProductRequest(line)) {
5014
5014
  const intent = parseProductIntent(line);
5015
5015
 
5016
- // Multi-turn brief intakeask the right questions
5017
- const questions = [
5018
- { key: "type", prompt: "Web app or mobile? [web]", default: intent.type || "web" },
5019
- { key: "audience", prompt: "Who is this for?", default: "" },
5020
- { key: "taste", prompt: "Visual style? (e.g. clean, bold, minimal, playful) [clean and modern]", default: "clean and modern" },
5021
- { key: "deploy", prompt: "Deploy where? (vercel, netlify, github-pages) [vercel]", default: "vercel" }
5022
- ];
5023
-
5024
- const answers = { type: intent.type || "web", audience: "", taste: "clean and modern", deploy: "vercel" };
5025
-
5026
- console.log(`\n${bold("Let's scope this out.")}`);
5027
-
5028
- for (const q of questions) {
5029
- try {
5030
- const raw = await promptLine(` ${q.prompt} `, { input: process.stdin, output: process.stdout });
5031
- const answer = raw.trim();
5032
- if (answer) answers[q.key] = answer;
5033
- else answers[q.key] = q.default;
5034
- } catch {
5035
- answers[q.key] = q.default;
5036
- }
5037
- }
5038
-
5039
- // Now use the LLM to generate the full brief with user context
5016
+ // Extract everything from the request no interactive prompts (stdin is unreliable on Windows)
5017
+ // Users can be specific: "I want a mobile recipe app, clean style, deploy to vercel"
5018
+ // Or minimal: "I want a recipe app" LLM infers the rest
5040
5019
  const spinner = createProgressSpinner("building your blueprint...");
5041
5020
  try {
5042
5021
  const { createJsonCompletion } = await import("./grok-client.js");
@@ -5046,16 +5025,19 @@ async function promptLoop(agent, session, context) {
5046
5025
  baseUrl: context.runtime.baseUrl,
5047
5026
  model,
5048
5027
  messages: [
5049
- { role: "system", content: `You are a product strategist. Given the user's request and answers, create a product brief. Respond with JSON only:
5028
+ { role: "system", content: `You are a product strategist. Extract a complete product brief from the user's request. Infer anything not stated. Respond with JSON only:
5050
5029
  {
5051
5030
  "name": "short product name",
5052
5031
  "description": "one-sentence description",
5032
+ "audience": "who is this for",
5033
+ "type": "web|mobile|api",
5053
5034
  "surfaces": ["Landing", "Login", "Dashboard"],
5054
5035
  "stack": { "framework": "Next.js", "styling": "Tailwind", "backend": "Supabase", "auth": "email", "deploy": "Vercel" },
5036
+ "taste": "visual style in 3-5 words",
5055
5037
  "features": ["feature 1", "feature 2"]
5056
5038
  }
5057
- Be concrete about surfaces — name actual pages/flows. Infer features from the request.` },
5058
- { role: "user", content: `Request: ${line}\nType: ${answers.type}\nAudience: ${answers.audience}\nStyle: ${answers.taste}\nDeploy: ${answers.deploy}` }
5039
+ Be concrete about surfaces — name actual pages/flows. Choose the best stack for the request. Default to web if not specified.` },
5040
+ { role: "user", content: line }
5059
5041
  ],
5060
5042
  temperature: 0.3
5061
5043
  });
@@ -5068,8 +5050,8 @@ Be concrete about surfaces — name actual pages/flows. Infer features from the
5068
5050
  const product = createProduct({
5069
5051
  name: brief.name || intent.name || "My Product",
5070
5052
  description: brief.description || line,
5071
- audience: answers.audience,
5072
- type: answers.type
5053
+ audience: brief.audience || "",
5054
+ type: brief.type || intent.type
5073
5055
  });
5074
5056
 
5075
5057
  // Apply template if detected
@@ -5082,8 +5064,7 @@ Be concrete about surfaces — name actual pages/flows. Infer features from the
5082
5064
  if (brief.stack) {
5083
5065
  product.stack = { ...product.stack, ...brief.stack };
5084
5066
  }
5085
- product.stack.deploy = answers.deploy;
5086
- product.qualityBar.taste = answers.taste;
5067
+ if (brief.taste) product.qualityBar.taste = brief.taste;
5087
5068
  if (Array.isArray(brief.surfaces)) {
5088
5069
  for (const s of brief.surfaces) {
5089
5070
  addSurface(product, { name: s, type: "page", status: "planned" });
package/src/prompt.js CHANGED
@@ -30,8 +30,7 @@ export async function promptLine(label, { input = process.stdin, output = proces
30
30
  if (settled) return;
31
31
  const str = chunk.toString();
32
32
  for (const ch of str) {
33
- if (ch === "\r") continue;
34
- if (ch === "\n") { output.write("\n"); finish(buf); return; }
33
+ if (ch === "\r" || ch === "\n") { output.write("\n"); finish(buf); return; }
35
34
  if (ch === "\u0003") { finish("", new DOMException("The operation was aborted.", "AbortError")); return; }
36
35
  if (ch === "\u007f" || ch === "\b") {
37
36
  if (buf.length > 0) { buf = buf.slice(0, -1); output.write("\b \b"); }