toolcraft 0.0.135 → 0.0.137

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 (58) hide show
  1. package/composition.json +7 -2
  2. package/dist/cli.js +55 -34
  3. package/dist/composition.json +7 -2
  4. package/dist/human-in-loop/approvals-commands.js +18 -28
  5. package/dist/index.d.ts +3 -2
  6. package/dist/index.js +3 -2
  7. package/dist/renderer.js +4 -1
  8. package/dist/user-error.d.ts +8 -0
  9. package/dist/user-error.js +10 -0
  10. package/node_modules/@poe-code/agent-defs/README.md +14 -1
  11. package/node_modules/@poe-code/agent-defs/dist/agents/claude-code.js +1 -0
  12. package/node_modules/@poe-code/agent-defs/dist/agents/claude-desktop.js +1 -0
  13. package/node_modules/@poe-code/agent-defs/dist/agents/codex.js +1 -0
  14. package/node_modules/@poe-code/agent-defs/dist/agents/cursor.js +1 -0
  15. package/node_modules/@poe-code/agent-defs/dist/agents/gemini-cli.js +1 -0
  16. package/node_modules/@poe-code/agent-defs/dist/agents/goose.js +1 -0
  17. package/node_modules/@poe-code/agent-defs/dist/agents/kimi.js +1 -0
  18. package/node_modules/@poe-code/agent-defs/dist/agents/opencode.js +1 -0
  19. package/node_modules/@poe-code/agent-defs/dist/agents/pi.js +1 -0
  20. package/node_modules/@poe-code/agent-defs/dist/agents/poe-agent.js +1 -0
  21. package/node_modules/@poe-code/agent-defs/dist/capabilities.d.ts +14 -0
  22. package/node_modules/@poe-code/agent-defs/dist/capabilities.js +63 -0
  23. package/node_modules/@poe-code/agent-defs/dist/index.d.ts +2 -1
  24. package/node_modules/@poe-code/agent-defs/dist/index.js +1 -0
  25. package/node_modules/@poe-code/agent-defs/dist/registry.js +3 -0
  26. package/node_modules/@poe-code/agent-defs/dist/types.d.ts +7 -0
  27. package/node_modules/@poe-code/frontmatter/README.md +3 -0
  28. package/node_modules/@poe-code/frontmatter/dist/index.d.ts +1 -1
  29. package/node_modules/@poe-code/frontmatter/dist/index.js +1 -1
  30. package/node_modules/@poe-code/frontmatter/dist/parse.d.ts +9 -0
  31. package/node_modules/@poe-code/frontmatter/dist/parse.js +16 -0
  32. package/node_modules/@poe-code/process-runner/dist/docker/docker-execution-env.js +20 -8
  33. package/node_modules/@poe-code/process-runner/dist/host/host-execution-env.js +1 -0
  34. package/node_modules/@poe-code/process-runner/dist/types.d.ts +5 -3
  35. package/node_modules/@poe-code/task-list/dist/backends/gh-issues-client.js +4 -0
  36. package/node_modules/@poe-code/user-error/README.md +56 -0
  37. package/node_modules/@poe-code/user-error/dist/index.d.ts +17 -0
  38. package/node_modules/@poe-code/user-error/dist/index.js +21 -0
  39. package/node_modules/@poe-code/user-error/package.json +24 -0
  40. package/node_modules/tiny-stdio-mcp-server/dist/composition.json +1 -1
  41. package/node_modules/toolcraft-design/dist/acp/components.d.ts +8 -1
  42. package/node_modules/toolcraft-design/dist/acp/components.js +11 -6
  43. package/node_modules/toolcraft-design/dist/acp/index.d.ts +1 -0
  44. package/node_modules/toolcraft-design/dist/components/command-errors.d.ts +2 -0
  45. package/node_modules/toolcraft-design/dist/components/command-errors.js +8 -2
  46. package/node_modules/toolcraft-design/dist/components/index.d.ts +1 -1
  47. package/node_modules/toolcraft-design/dist/components/index.js +1 -1
  48. package/node_modules/toolcraft-design/dist/components/table.d.ts +1 -0
  49. package/node_modules/toolcraft-design/dist/components/table.js +52 -5
  50. package/node_modules/toolcraft-design/dist/components/template.d.ts +9 -0
  51. package/node_modules/toolcraft-design/dist/components/template.js +27 -2
  52. package/node_modules/toolcraft-design/dist/index.d.ts +2 -2
  53. package/node_modules/toolcraft-design/dist/index.js +2 -2
  54. package/node_modules/toolcraft-design/dist/prompts/interactive/core.d.ts +5 -0
  55. package/node_modules/toolcraft-design/dist/prompts/interactive/core.js +15 -1
  56. package/node_modules/toolcraft-design/dist/prompts/primitives/spinner.js +1 -1
  57. package/node_modules/toolcraft-schema/package.json +1 -1
  58. package/package.json +6 -4
@@ -3,6 +3,7 @@ import { resolveOutputFormat } from "../internal/output-format.js";
3
3
  import { stripAnsi } from "../internal/strip-ansi.js";
4
4
  const reset = "\x1b[0m";
5
5
  const ellipsis = "…";
6
+ const minCellWidth = 4;
6
7
  const graphemeSegmenter = new Intl.Segmenter(undefined, { granularity: "grapheme" });
7
8
  function getCell(row, name) {
8
9
  return Object.prototype.hasOwnProperty.call(row, name) ? row[name] ?? "" : "";
@@ -161,6 +162,51 @@ function computeColumns(columns) {
161
162
  width: getColumnWidth(column)
162
163
  }));
163
164
  }
165
+ // Each column is framed as "│ cell ", plus the closing "│".
166
+ function frameWidth(columnCount) {
167
+ return columnCount * 3 + 1;
168
+ }
169
+ // Log output indents every line with a "│ " guide, so a table emitted through the
170
+ // logger has that much less room than the terminal. Undefined without a terminal:
171
+ // piped output has no width to fit.
172
+ export function loggerTableWidth() {
173
+ const columns = process.stdout.columns;
174
+ return columns === undefined ? undefined : columns - 3;
175
+ }
176
+ // Without an explicit budget or a TTY there is no width to fit: the consumer of the
177
+ // piped output decides, so columns keep their declared widths.
178
+ function budgetColumns(columns, maxWidth) {
179
+ if (maxWidth === undefined) {
180
+ return columns;
181
+ }
182
+ const available = maxWidth - frameWidth(columns.length);
183
+ const contentWidth = (cap) => columns.reduce((total, column) => total + Math.min(column.width, cap), 0);
184
+ if (columns.reduce((total, column) => total + column.width, 0) <= available) {
185
+ return columns;
186
+ }
187
+ // Widest-first: raise a shared cap as far as the budget allows, so narrow columns
188
+ // keep their declared width and only the columns above the cap lose room.
189
+ let cap = minCellWidth;
190
+ while (contentWidth(cap + 1) <= available) {
191
+ cap += 1;
192
+ }
193
+ const budgeted = columns.map((column) => ({ ...column, width: Math.min(column.width, cap) }));
194
+ let slack = available - contentWidth(cap);
195
+ while (slack > 0) {
196
+ const growable = budgeted.filter((column, index) => column.width < columns[index].width);
197
+ if (growable.length === 0) {
198
+ break;
199
+ }
200
+ for (const column of growable) {
201
+ if (slack === 0) {
202
+ break;
203
+ }
204
+ column.width += 1;
205
+ slack -= 1;
206
+ }
207
+ }
208
+ return budgeted;
209
+ }
164
210
  function renderBorder(columns, theme, parts) {
165
211
  const horizontal = theme.muted("─");
166
212
  const segments = columns.map((column) => horizontal.repeat(column.width + 2));
@@ -247,16 +293,17 @@ function renderTableTerminal(options) {
247
293
  }
248
294
  const separatorOptions = options;
249
295
  const includeRowSeparators = separatorOptions.rowSeparator === true || separatorOptions.rowSeparators === true;
250
- const top = renderBorder(computedColumns, theme, { left: "┌", mid: "┬", right: "┐" });
251
- const header = renderTerminalRow(computedColumns.map((column) => theme.header(column.title)), computedColumns, theme);
252
- const headerBottom = renderBorder(computedColumns, theme, { left: "├", mid: "┼", right: "┤" });
253
- const bottom = renderBorder(computedColumns, theme, { left: "└", mid: "┴", right: "┘" });
296
+ const budgetedColumns = budgetColumns(computedColumns, options.maxWidth ?? process.stdout.columns);
297
+ const top = renderBorder(budgetedColumns, theme, { left: "┌", mid: "┬", right: "┐" });
298
+ const header = renderTerminalRow(budgetedColumns.map((column) => theme.header(column.title)), budgetedColumns, theme);
299
+ const headerBottom = renderBorder(budgetedColumns, theme, { left: "├", mid: "┼", right: "┤" });
300
+ const bottom = renderBorder(budgetedColumns, theme, { left: "└", mid: "┴", right: "┘" });
254
301
  const renderedRows = [];
255
302
  for (const [index, row] of rows.entries()) {
256
303
  if (includeRowSeparators && index > 0) {
257
304
  renderedRows.push(headerBottom);
258
305
  }
259
- renderedRows.push(renderTerminalRow(computedColumns.map((column) => getCell(row, column.name)), computedColumns, theme));
306
+ renderedRows.push(renderTerminalRow(budgetedColumns.map((column) => getCell(row, column.name)), budgetedColumns, theme));
260
307
  }
261
308
  return [top, header, headerBottom, ...renderedRows, bottom].join("\n");
262
309
  }
@@ -5,6 +5,15 @@ export interface RenderTemplateOptions {
5
5
  validate?: boolean;
6
6
  yield?: string;
7
7
  }
8
+ export declare class TemplateParseError extends Error {
9
+ readonly description: string;
10
+ readonly line: number;
11
+ readonly column: number;
12
+ constructor(description: string, position: {
13
+ line: number;
14
+ column: number;
15
+ });
16
+ }
8
17
  export declare function renderTemplate(template: string, view: Record<string, unknown>, options?: RenderTemplateOptions): string;
9
18
  export declare function getTemplatePartialNames(template: string): string[];
10
19
  export declare function resolveTemplatePartials(template: string, partials: Record<string, string>): string;
@@ -1,4 +1,17 @@
1
1
  const MAX_PARTIAL_DEPTH = 100;
2
+ const MAX_TAG_EXCERPT_LENGTH = 40;
3
+ export class TemplateParseError extends Error {
4
+ description;
5
+ line;
6
+ column;
7
+ constructor(description, position) {
8
+ super(`${description} at line ${position.line}, column ${position.column}`);
9
+ this.name = "TemplateParseError";
10
+ this.description = description;
11
+ this.line = position.line;
12
+ this.column = position.column;
13
+ }
14
+ }
2
15
  const HTML_ESCAPE = {
3
16
  "&": "&amp;",
4
17
  "<": "&lt;",
@@ -114,13 +127,13 @@ function parseTag(template, open) {
114
127
  if (template.startsWith("{{{", open)) {
115
128
  const close = template.indexOf("}}}", open + 3);
116
129
  if (close === -1) {
117
- throw new Error("Unclosed unescaped tag");
130
+ throw unclosedTagError(template, open, "}}}");
118
131
  }
119
132
  return { kind: "unescaped", name: template.slice(open + 3, close).trim(), end: close + 3 };
120
133
  }
121
134
  const close = template.indexOf("}}", open + 2);
122
135
  if (close === -1) {
123
- throw new Error("Unclosed tag");
136
+ throw unclosedTagError(template, open, "}}");
124
137
  }
125
138
  const raw = template.slice(open + 2, close).trim();
126
139
  const sigil = raw[0];
@@ -142,6 +155,18 @@ function parseTag(template, open) {
142
155
  return { kind: "delimiter", name, end };
143
156
  return { kind: "name", name: raw, end };
144
157
  }
158
+ function unclosedTagError(template, open, expected) {
159
+ const before = template.slice(0, open);
160
+ const lineEnd = template.indexOf("\n", open);
161
+ const opened = template.slice(open, lineEnd === -1 ? template.length : lineEnd).trimEnd();
162
+ const tag = opened.length > MAX_TAG_EXCERPT_LENGTH
163
+ ? `${opened.slice(0, MAX_TAG_EXCERPT_LENGTH)}...`
164
+ : opened;
165
+ return new TemplateParseError(`Unclosed tag "${tag}": expected "${expected}"`, {
166
+ line: before.split("\n").length,
167
+ column: open - (before.lastIndexOf("\n") + 1) + 1
168
+ });
169
+ }
145
170
  function getStandalone(template, tagStart, tagEnd, kind) {
146
171
  if (!["section", "inverted", "close", "comment", "partial", "delimiter"].includes(kind)) {
147
172
  return undefined;
@@ -17,7 +17,7 @@ export * as helpFormatterPlain from "./components/help-formatter-plain.js";
17
17
  export type { CommandInfo, OptionInfo, FormatColumnsOptions, HelpToken, HelpTokenRole } from "./components/help-formatter.js";
18
18
  export { formatCommandNotFound } from "./components/command-errors.js";
19
19
  export { formatCommandNotFoundPanel } from "./components/command-errors.js";
20
- export { renderTable } from "./components/table.js";
20
+ export { loggerTableWidth, renderTable } from "./components/table.js";
21
21
  export type { TableColumn, RenderTableOptions } from "./components/table.js";
22
22
  export { renderFileChanges } from "./components/file-changes.js";
23
23
  export type { FileChange, FileChangeDisplayMode, FileChangeKind, FileChangeOutputFormat, RenderFileChangesOptions } from "./components/file-changes.js";
@@ -29,7 +29,7 @@ export { renderInspectorCard } from "./components/inspector-card.js";
29
29
  export type { InspectorField, InspectorSection, RenderInspectorCardOptions } from "./components/inspector-card.js";
30
30
  export { renderResourceBrowser } from "./components/resource-browser.js";
31
31
  export type { RenderResourceBrowserOptions, ResourceBrowserGroup, ResourceBrowserItem } from "./components/resource-browser.js";
32
- export { getTemplatePartialNames, renderTemplate, resolveTemplatePartials } from "./components/template.js";
32
+ export { TemplateParseError, getTemplatePartialNames, renderTemplate, resolveTemplatePartials } from "./components/template.js";
33
33
  export type { RenderTemplateOptions, TemplateEscape } from "./components/template.js";
34
34
  export { openExternal } from "./components/browser.js";
35
35
  export * as acp from "./acp/index.js";
@@ -14,13 +14,13 @@ export { helpFormatter, formatColumns, formatCommand, formatUsage, formatOption,
14
14
  export * as helpFormatterPlain from "./components/help-formatter-plain.js";
15
15
  export { formatCommandNotFound } from "./components/command-errors.js";
16
16
  export { formatCommandNotFoundPanel } from "./components/command-errors.js";
17
- export { renderTable } from "./components/table.js";
17
+ export { loggerTableWidth, renderTable } from "./components/table.js";
18
18
  export { renderFileChanges } from "./components/file-changes.js";
19
19
  export { renderCatalog } from "./components/catalog.js";
20
20
  export { renderDetailCard } from "./components/detail-card.js";
21
21
  export { renderInspectorCard } from "./components/inspector-card.js";
22
22
  export { renderResourceBrowser } from "./components/resource-browser.js";
23
- export { getTemplatePartialNames, renderTemplate, resolveTemplatePartials } from "./components/template.js";
23
+ export { TemplateParseError, getTemplatePartialNames, renderTemplate, resolveTemplatePartials } from "./components/template.js";
24
24
  export { openExternal } from "./components/browser.js";
25
25
  // ACP rendering
26
26
  export * as acp from "./acp/index.js";
@@ -1,6 +1,11 @@
1
1
  import { EventEmitter } from "node:events";
2
2
  import { CANCEL } from "./cancel-symbol.js";
3
3
  export type PromptStateName = "initial" | "active" | "submit" | "cancel" | "error";
4
+ /**
5
+ * Builds the non-TTY rejection message, naming the documented `--yes` flag for the
6
+ * command being run and keeping `POE_NO_PROMPT=1` as the secondary CI alternative.
7
+ */
8
+ export declare function nonTtyPromptMessage(argv?: string[]): string;
4
9
  export interface PromptState<Value> {
5
10
  state: PromptStateName;
6
11
  value: Value | undefined;
@@ -22,6 +22,20 @@ const cursor = {
22
22
  const erase = {
23
23
  down: "\x1b[J"
24
24
  };
25
+ /**
26
+ * Builds the non-TTY rejection message, naming the documented `--yes` flag for the
27
+ * command being run and keeping `POE_NO_PROMPT=1` as the secondary CI alternative.
28
+ */
29
+ export function nonTtyPromptMessage(argv = process.argv) {
30
+ const tokens = [];
31
+ for (const arg of argv.slice(2)) {
32
+ if (arg.startsWith("-"))
33
+ break;
34
+ tokens.push(arg);
35
+ }
36
+ const retry = [...tokens, "--yes"].join(" ");
37
+ return `Interactive prompt requires a TTY. Re-run with \`${retry}\` to accept defaults non-interactively, or set POE_NO_PROMPT=1 in CI.`;
38
+ }
25
39
  export class Prompt extends EventEmitter {
26
40
  state = "initial";
27
41
  value;
@@ -92,7 +106,7 @@ export class Prompt extends EventEmitter {
92
106
  });
93
107
  }
94
108
  promptNonTty() {
95
- return Promise.reject(new Error("Interactive prompt requires a TTY. Set POE_NO_PROMPT=1 to accept defaults non-interactively."));
109
+ return Promise.reject(new Error(nonTtyPromptMessage()));
96
110
  }
97
111
  readNonTtyLine() {
98
112
  return new Promise((resolve) => {
@@ -33,7 +33,7 @@ export function spinner() {
33
33
  }
34
34
  fallback = process.env.POE_NO_SPINNER === "1" || !process.stdout.isTTY;
35
35
  if (fallback) {
36
- process.stdout.write(`${currentMessage}\n`);
36
+ process.stdout.write(`${color.gray("│")} ${currentMessage}\n`);
37
37
  return;
38
38
  }
39
39
  frameIndex = 0;
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "toolcraft-schema",
3
- "version": "0.0.135",
3
+ "version": "0.0.137",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "toolcraft",
3
- "version": "0.0.135",
3
+ "version": "0.0.137",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -100,8 +100,8 @@
100
100
  "test": "cd ../.. && vitest run packages/toolcraft/src",
101
101
  "test:unit": "cd ../.. && vitest run packages/toolcraft/src",
102
102
  "lint": "cd ../.. && eslint packages/toolcraft/src --ext ts && tsc -p packages/toolcraft/tsconfig.json --noEmit",
103
- "prepack": "node ../../scripts/manage-bundled-workspace-deps.mjs prepare . toolcraft-schema toolcraft-design @poe-code/frontmatter @poe-code/agent-mcp-config @poe-code/agent-human-in-loop @poe-code/task-list @poe-code/agent-defs @poe-code/config-mutations @poe-code/process-runner mcp-oauth-server tiny-http-mcp-server tiny-mcp-client tiny-stdio-mcp-server auth-store jose fast-string-width fast-wrap-ansi ignore jsonc-parser sisteransi smol-toml yaml",
104
- "postpack": "node ../../scripts/manage-bundled-workspace-deps.mjs cleanup . toolcraft-schema toolcraft-design @poe-code/frontmatter @poe-code/agent-mcp-config @poe-code/agent-human-in-loop @poe-code/task-list @poe-code/agent-defs @poe-code/config-mutations @poe-code/process-runner mcp-oauth-server tiny-http-mcp-server tiny-mcp-client tiny-stdio-mcp-server auth-store jose fast-string-width fast-wrap-ansi ignore jsonc-parser sisteransi smol-toml yaml"
103
+ "prepack": "node ../../scripts/manage-bundled-workspace-deps.mjs prepare . toolcraft-schema toolcraft-design @poe-code/frontmatter @poe-code/agent-mcp-config @poe-code/agent-human-in-loop @poe-code/task-list @poe-code/agent-defs @poe-code/config-mutations @poe-code/user-error @poe-code/process-runner mcp-oauth-server tiny-http-mcp-server tiny-mcp-client tiny-stdio-mcp-server auth-store jose fast-string-width fast-wrap-ansi ignore jsonc-parser sisteransi smol-toml yaml",
104
+ "postpack": "node ../../scripts/manage-bundled-workspace-deps.mjs cleanup . toolcraft-schema toolcraft-design @poe-code/frontmatter @poe-code/agent-mcp-config @poe-code/agent-human-in-loop @poe-code/task-list @poe-code/agent-defs @poe-code/config-mutations @poe-code/user-error @poe-code/process-runner mcp-oauth-server tiny-http-mcp-server tiny-mcp-client tiny-stdio-mcp-server auth-store jose fast-string-width fast-wrap-ansi ignore jsonc-parser sisteransi smol-toml yaml"
105
105
  },
106
106
  "dependencies": {
107
107
  "commander": "^13.1.0",
@@ -137,6 +137,7 @@
137
137
  "@poe-code/task-list",
138
138
  "@poe-code/agent-defs",
139
139
  "@poe-code/config-mutations",
140
+ "@poe-code/user-error",
140
141
  "@poe-code/process-runner",
141
142
  "mcp-oauth-server",
142
143
  "tiny-http-mcp-server",
@@ -153,7 +154,7 @@
153
154
  "yaml"
154
155
  ],
155
156
  "optionalDependencies": {
156
- "toolcraft-schema": "0.0.135",
157
+ "toolcraft-schema": "0.0.137",
157
158
  "toolcraft-design": "*",
158
159
  "@poe-code/frontmatter": "*",
159
160
  "@poe-code/agent-mcp-config": "*",
@@ -161,6 +162,7 @@
161
162
  "@poe-code/task-list": "*",
162
163
  "@poe-code/agent-defs": "*",
163
164
  "@poe-code/config-mutations": "*",
165
+ "@poe-code/user-error": "*",
164
166
  "@poe-code/process-runner": "*",
165
167
  "mcp-oauth-server": "*",
166
168
  "tiny-http-mcp-server": "*",