@crouton-kit/humanloop 0.1.2 → 0.1.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.
@@ -1,4 +1,9 @@
1
- import type { Question, VisualBlock } from '../types.js';
2
- import type { ConversationMessage } from '../conversation/reader.js';
3
- export type VisualUpdateCallback = (questionId: string, block: VisualBlock) => void;
4
- export declare function generateVisuals(questions: Question[], conversation: ConversationMessage[], onUpdate: VisualUpdateCallback, width?: number): Promise<void>;
1
+ import type { Interaction } from '../types.js';
2
+ export declare function defaultGenerateVisual(interaction: Interaction, conversationContext: string): Promise<{
3
+ ok: true;
4
+ ansi: string;
5
+ markdown: string;
6
+ } | {
7
+ ok: false;
8
+ error: string;
9
+ }>;
@@ -14,12 +14,12 @@ If one sentence captures the current state, write one sentence. If they need to
14
14
 
15
15
  # Directives (termrender-flavored markdown)
16
16
 
17
- :::panel{title="T" color="c"} Bordered box (colors: red|green|yellow|blue|magenta|cyan|white|gray)
18
- :::tree{color="c"} Indented hierarchy (2-space indent = nesting)
19
- :::table Markdown table with borders
20
- :::note / :::warning Callouts
17
+ :::panel{title="T" color="c"} Bordered box (colors: red|green|yellow|blue|magenta|cyan|white|gray)
18
+ :::tree{color="c"} Indented hierarchy (2-space indent = nesting)
19
+ :::callout{type="info|warning|error|success"} Status callout with icon
20
+ ::::columns / :::col{width="50%"} Side-by-side layout (use 4 colons on the outer columns)
21
21
 
22
- Each opens with ::: and closes with :::. Standard markdown also works: **bold**, *italic*, \`code\`, bullets.
22
+ Each opens with ::: and closes with :::. GFM tables (\`| col | col |\` with a \`| --- |\` separator) render directly — no directive needed. Standard markdown also works: **bold**, *italic*, \`code\`, bullets.
23
23
 
24
24
  # Critical: ASCII art must live inside a :::panel
25
25
 
@@ -33,7 +33,7 @@ If the conversation doesn't contain enough context to write a grounded briefing,
33
33
 
34
34
  # Hard rules
35
35
 
36
- - Never nest directives (no :::panel containing :::table)
36
+ - When nesting directives, the outer fence needs strictly more colons than the inner — e.g. \`::::columns\` wrapping \`:::col\`. Don't nest a panel inside a panel.
37
37
  - Never wrap output in backtick fences
38
38
  - Never repeat the question/statement text
39
39
  - Never write "tradeoffs to consider" or "here are some options"
@@ -93,37 +93,28 @@ function tryTermrender(markdown, width) {
93
93
  return null;
94
94
  }
95
95
  }
96
- export async function generateVisuals(questions, conversation, onUpdate, width = 72) {
97
- const conversationText = conversation
98
- .map(m => `${m.role}: ${m.content}`)
99
- .join('\n\n');
100
- const tasks = questions.map(async (question) => {
101
- const questionText = question.type === 'validation'
102
- ? `Decision to validate: "${question.statement}"\nRationale: ${question.rationale}`
103
- : `Question: "${question.question}"\nRationale: ${question.rationale}${question.type === 'choice'
104
- ? `\nOptions: ${question.options.join(', ')}`
105
- : ''}`;
106
- const prompt = `Here is the conversation so far:\n\n${conversationText}\n\n---\n\nGenerate a visual context block for this decision point:\n\n${questionText}`;
107
- const result = await callHaiku(prompt, VISUAL_SYSTEM_PROMPT);
108
- if (result) {
109
- const cleaned = result
110
- .replace(/^```[\w]*\n?/gm, '')
111
- .replace(/^```\s*$/gm, '')
112
- .trim();
113
- const rendered = renderWithTermrender(cleaned, width);
114
- onUpdate(question.id, {
115
- questionId: question.id,
116
- content: rendered,
117
- status: 'ready',
118
- });
119
- }
120
- else {
121
- onUpdate(question.id, {
122
- questionId: question.id,
123
- content: '',
124
- status: 'error',
125
- });
126
- }
127
- });
128
- await Promise.all(tasks);
96
+ // defaultGenerateVisual matches the GenerateVisual contract for use with
97
+ // mountPanel. Width is read from process.stdout.columns so callers that
98
+ // embed humanloop in a sub-region should supply their own closure that bakes
99
+ // in the correct width.
100
+ export async function defaultGenerateVisual(interaction, conversationContext) {
101
+ const width = Math.max(40, Math.min((process.stdout.columns || 80) - 4, 76));
102
+ const optionsSummary = interaction.options.length > 0
103
+ ? `\nOptions: ${interaction.options.map((o) => o.label).join(' | ')}`
104
+ : '';
105
+ const subtitleLine = interaction.subtitle ? `\nContext: ${interaction.subtitle}` : '';
106
+ const questionText = `Title: "${interaction.title}"${subtitleLine}${optionsSummary}`;
107
+ const prompt = conversationContext
108
+ ? `Here is the conversation so far:\n\n${conversationContext}\n\n---\n\nGenerate a visual context block for this decision point:\n\n${questionText}`
109
+ : `Generate a visual context block for this decision point:\n\n${questionText}`;
110
+ const result = await callHaiku(prompt, VISUAL_SYSTEM_PROMPT);
111
+ if (result) {
112
+ const markdown = result
113
+ .replace(/^```[\w]*\n?/gm, '')
114
+ .replace(/^```\s*$/gm, '')
115
+ .trim();
116
+ const ansi = renderWithTermrender(markdown, width);
117
+ return { ok: true, ansi, markdown };
118
+ }
119
+ return { ok: false, error: 'haiku returned no output' };
129
120
  }
package/package.json CHANGED
@@ -1,11 +1,22 @@
1
1
  {
2
2
  "name": "@crouton-kit/humanloop",
3
- "version": "0.1.2",
3
+ "version": "0.1.3",
4
4
  "description": "Human-in-the-loop decision TUI — agents write questions, humans answer them",
5
5
  "type": "module",
6
+ "main": "dist/index.js",
7
+ "types": "dist/index.d.ts",
6
8
  "bin": {
7
9
  "hl": "dist/cli.js"
8
10
  },
11
+ "exports": {
12
+ ".": {
13
+ "import": "./dist/index.js",
14
+ "types": "./dist/index.d.ts"
15
+ },
16
+ "./cli": {
17
+ "import": "./dist/cli.js"
18
+ }
19
+ },
9
20
  "files": [
10
21
  "dist",
11
22
  "commands"
@@ -13,7 +24,8 @@
13
24
  "scripts": {
14
25
  "build": "tsc",
15
26
  "dev": "tsx src/cli.ts",
16
- "link": "npm link"
27
+ "link": "npm link",
28
+ "test": "tsx src/__tests__/mount-panel.test.ts"
17
29
  },
18
30
  "dependencies": {
19
31
  "@r-cli/sdk": "^1.3.0",