@compilr-dev/cli 0.5.1 → 0.5.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.
Files changed (56) hide show
  1. package/LICENSE +108 -0
  2. package/README.md +2 -2
  3. package/dist/.tsbuildinfo.app +1 -1
  4. package/dist/.tsbuildinfo.data +1 -1
  5. package/dist/.tsbuildinfo.domain +1 -1
  6. package/dist/.tsbuildinfo.foundation +1 -1
  7. package/dist/agent.js +8 -6
  8. package/dist/commands-v2/handlers/context.js +20 -0
  9. package/dist/commands-v2/handlers/core.js +26 -1
  10. package/dist/commands-v2/handlers/project.js +88 -12
  11. package/dist/commands-v2/handlers/reset.js +19 -6
  12. package/dist/commands-v2/handlers/session.d.ts +5 -1
  13. package/dist/commands-v2/handlers/session.js +54 -16
  14. package/dist/commands-v2/types.d.ts +5 -0
  15. package/dist/compilr-diff-companion.vsix +0 -0
  16. package/dist/db/repositories/document-repository.js +1 -0
  17. package/dist/db/schema.d.ts +1 -1
  18. package/dist/index.js +99 -30
  19. package/dist/models/providers.d.ts +3 -1
  20. package/dist/models/providers.js +9 -0
  21. package/dist/repl-helpers.js +2 -0
  22. package/dist/repl-v2.d.ts +12 -0
  23. package/dist/repl-v2.js +27 -11
  24. package/dist/tool-names.d.ts +9 -0
  25. package/dist/tool-names.js +36 -0
  26. package/dist/tools/db-tools.d.ts +6 -1
  27. package/dist/tools/db-tools.js +6 -2
  28. package/dist/tools/meta-tools.d.ts +1 -1
  29. package/dist/tools/platform-adapter.d.ts +6 -0
  30. package/dist/tools/platform-adapter.js +10 -0
  31. package/dist/tools.d.ts +14 -4
  32. package/dist/tools.js +60 -20
  33. package/dist/ui/constants/labels.js +1 -0
  34. package/dist/ui/overlay/impl/workflow-overlay-v2.d.ts +1 -0
  35. package/dist/ui/overlay/impl/workflow-overlay-v2.js +5 -3
  36. package/dist/ui/terminal-ui.d.ts +7 -7
  37. package/dist/ui/terminal-ui.js +1 -1
  38. package/dist/ui/tool-formatters.js +190 -6
  39. package/dist/ui/turn-metrics.d.ts +10 -10
  40. package/dist/ui/turn-metrics.js +5 -5
  41. package/dist/ui/types.d.ts +4 -4
  42. package/package.json +6 -5
  43. package/dist/tools/anchor-tools.d.ts +0 -31
  44. package/dist/tools/anchor-tools.js +0 -255
  45. package/dist/tools/artifact-tools.d.ts +0 -42
  46. package/dist/tools/artifact-tools.js +0 -328
  47. package/dist/tools/backlog-wrappers.d.ts +0 -56
  48. package/dist/tools/backlog-wrappers.js +0 -353
  49. package/dist/tools/document-db.d.ts +0 -43
  50. package/dist/tools/document-db.js +0 -220
  51. package/dist/tools/plan-tools.d.ts +0 -54
  52. package/dist/tools/plan-tools.js +0 -338
  53. package/dist/tools/recall-work-tool.d.ts +0 -18
  54. package/dist/tools/recall-work-tool.js +0 -82
  55. package/dist/tools/workitem-db.d.ts +0 -135
  56. package/dist/tools/workitem-db.js +0 -730
@@ -112,6 +112,12 @@ export const TOOL_NAMES = {
112
112
  ARTIFACT_DELETE: 'artifact_delete',
113
113
  // Episode tools (meta-registry)
114
114
  RECALL_WORK: 'recall_work',
115
+ // Factory tools (meta-registry)
116
+ APP_MODEL_GET: 'app_model_get',
117
+ APP_MODEL_UPDATE: 'app_model_update',
118
+ APP_MODEL_VALIDATE: 'app_model_validate',
119
+ FACTORY_SCAFFOLD: 'factory_scaffold',
120
+ FACTORY_LIST_TOOLKITS: 'factory_list_toolkits',
115
121
  };
116
122
  /** Array of all direct tool names (always available) */
117
123
  export const DIRECT_TOOL_NAMES = [
@@ -136,6 +142,30 @@ export const DIRECT_TOOL_NAMES = [
136
142
  TOOL_NAMES.TASK,
137
143
  TOOL_NAMES.SUGGEST,
138
144
  ];
145
+ /** Hot tools — used in >50% of turns, always declared as direct schemas */
146
+ export const HOT_TOOL_NAMES = [
147
+ TOOL_NAMES.READ_FILE,
148
+ TOOL_NAMES.WRITE_FILE,
149
+ TOOL_NAMES.EDIT,
150
+ TOOL_NAMES.BASH,
151
+ TOOL_NAMES.GREP,
152
+ TOOL_NAMES.GLOB,
153
+ TOOL_NAMES.ASK_USER,
154
+ ];
155
+ /** Warm tools — used occasionally, moved to meta-registry in hot-tools mode */
156
+ export const WARM_TOOL_NAMES = [
157
+ TOOL_NAMES.BASH_OUTPUT,
158
+ TOOL_NAMES.KILL_SHELL,
159
+ TOOL_NAMES.TODO_WRITE,
160
+ TOOL_NAMES.TODO_READ,
161
+ TOOL_NAMES.TODO_CLAIM,
162
+ TOOL_NAMES.TODO_HANDOFF,
163
+ TOOL_NAMES.ASK_USER_SIMPLE,
164
+ TOOL_NAMES.DELEGATE,
165
+ TOOL_NAMES.DELEGATE_BACKGROUND,
166
+ TOOL_NAMES.HANDOFF,
167
+ TOOL_NAMES.COMPILR_GUIDE,
168
+ ];
139
169
  /** Array of all meta-tool names (tool discovery) */
140
170
  export const META_TOOL_NAMES = [
141
171
  TOOL_NAMES.LIST_TOOLS,
@@ -217,6 +247,12 @@ export const META_REGISTRY_TOOL_NAMES = [
217
247
  TOOL_NAMES.RECALL_WORK,
218
248
  // Delegation
219
249
  TOOL_NAMES.DELEGATION_STATUS,
250
+ // Factory
251
+ TOOL_NAMES.APP_MODEL_GET,
252
+ TOOL_NAMES.APP_MODEL_UPDATE,
253
+ TOOL_NAMES.APP_MODEL_VALIDATE,
254
+ TOOL_NAMES.FACTORY_SCAFFOLD,
255
+ TOOL_NAMES.FACTORY_LIST_TOOLKITS,
220
256
  ];
221
257
  /**
222
258
  * Get all tool names as an array.
@@ -5,8 +5,13 @@
5
5
  * provided by the SDK via platform-adapter.ts. This file re-exports them
6
6
  * along with state management functions still needed by ~15+ CLI files.
7
7
  */
8
+ import { allFactoryTools } from './platform-adapter.js';
8
9
  export { getActiveProject, setActiveProject } from './project-db.js';
9
10
  /**
10
- * All database tools combined (24 tools from SDK)
11
+ * All database tools combined (32 tools from SDK)
11
12
  */
12
13
  export declare const allDbTools: import("@compilr-dev/agents").Tool<never>[];
14
+ /**
15
+ * All factory tools (5 tools from @compilr-dev/factory)
16
+ */
17
+ export { allFactoryTools };
@@ -5,10 +5,14 @@
5
5
  * provided by the SDK via platform-adapter.ts. This file re-exports them
6
6
  * along with state management functions still needed by ~15+ CLI files.
7
7
  */
8
- import { allPlatformTools } from './platform-adapter.js';
8
+ import { allPlatformTools, allFactoryTools } from './platform-adapter.js';
9
9
  // Re-export state management functions (still needed by many CLI files)
10
10
  export { getActiveProject, setActiveProject } from './project-db.js';
11
11
  /**
12
- * All database tools combined (24 tools from SDK)
12
+ * All database tools combined (32 tools from SDK)
13
13
  */
14
14
  export const allDbTools = allPlatformTools;
15
+ /**
16
+ * All factory tools (5 tools from @compilr-dev/factory)
17
+ */
18
+ export { allFactoryTools };
@@ -23,4 +23,4 @@ export declare const getToolInfoTool: Tool<object>;
23
23
  export declare const useToolTool: Tool<object>;
24
24
  export declare const metaTools: Tool<object>[];
25
25
  export declare function createMetaToolFallback(): (name: string, input: Record<string, unknown>) => Promise<ToolExecutionResult | null>;
26
- export declare const META_TOOLS_SYSTEM_PROMPT_PREFIX = "\n## Tool Index (Specialized Tools)\n\nThese tools are called **exactly like direct tools** \u2014 just use the tool name with parameters. No special syntax or wrapper needed. The system routes them automatically.\n\n**IMPORTANT \u2014 These are CLI system tools, NOT your project's backend. Never use localhost/curl to access them.**\n\n**Parameter Rules:**\n- For **zero-parameter calls**: call the tool directly (e.g., `workitem_query()`, `git_status()`).\n- For **calls WITH parameters**: you MUST call `get_tool_info(\"tool_name\")` first to get the exact JSON schema. The signatures below are summaries only \u2014 do NOT guess parameter structure from them.\n- After a failed tool call, always call `get_tool_info()` before retrying.\n\n";
26
+ export declare const META_TOOLS_SYSTEM_PROMPT_PREFIX = "\n## Tool Index (Specialized Tools)\n\nThese tools are called **exactly like direct tools** \u2014 just use the tool name with parameters. No special syntax or wrapper needed. The system routes them automatically.\n\n**IMPORTANT \u2014 These are CLI system tools, NOT your project's backend. Never use localhost/curl to access them.**\n\n**Parameter Rules:**\n- For **zero-parameter calls**: call the tool directly (e.g., `workitem_query()`, `git_status()`).\n- For **calls WITH parameters**: you MUST call `get_tool_info(\"tool_name\")` first to get parameter details. The signatures below are summaries only \u2014 do NOT guess parameter structure from them.\n- After a failed tool call, always call `get_tool_info()` before retrying.\n\n";
@@ -27,3 +27,9 @@
27
27
  * - 1 episode tool (recall_work)
28
28
  */
29
29
  export declare const allPlatformTools: import("@compilr-dev/sdk").Tool<never>[];
30
+ /**
31
+ * All 5 factory tools from @compilr-dev/factory:
32
+ * - 3 model tools (app_model_get, app_model_update, app_model_validate)
33
+ * - 2 factory tools (factory_scaffold, factory_list_toolkits)
34
+ */
35
+ export declare const allFactoryTools: import("@compilr-dev/sdk").Tool<never>[];
@@ -16,6 +16,7 @@
16
16
  * - recall-work-tool.ts (1 tool)
17
17
  */
18
18
  import { createPlatformTools, } from '@compilr-dev/sdk';
19
+ import { createFactoryTools } from '@compilr-dev/factory';
19
20
  import { projectRepository, workItemRepository, documentRepository, planRepository, } from '../db/repositories/index.js';
20
21
  import { getCurrentProject, setCurrentProject } from './project-db.js';
21
22
  import { awardFirstProject, awardWorkItemCompletion } from '../games/coins.js';
@@ -392,3 +393,12 @@ const config = {
392
393
  * - 1 episode tool (recall_work)
393
394
  */
394
395
  export const allPlatformTools = createPlatformTools(config);
396
+ /**
397
+ * All 5 factory tools from @compilr-dev/factory:
398
+ * - 3 model tools (app_model_get, app_model_update, app_model_validate)
399
+ * - 2 factory tools (factory_scaffold, factory_list_toolkits)
400
+ */
401
+ export const allFactoryTools = createFactoryTools({
402
+ context,
403
+ cwd: process.cwd(),
404
+ });
package/dist/tools.d.ts CHANGED
@@ -14,7 +14,7 @@
14
14
  * Tool names are defined in tool-names.ts (a dependency-free module).
15
15
  * This file re-exports them for convenience. Import from here or tool-names.ts.
16
16
  */
17
- export { TOOL_NAMES, type ToolName, DIRECT_TOOL_NAMES, META_TOOL_NAMES, META_REGISTRY_TOOL_NAMES, getAllToolNames, } from './tool-names.js';
17
+ export { TOOL_NAMES, type ToolName, DIRECT_TOOL_NAMES, HOT_TOOL_NAMES, WARM_TOOL_NAMES, META_TOOL_NAMES, META_REGISTRY_TOOL_NAMES, getAllToolNames, } from './tool-names.js';
18
18
  import { TodoStore, type Tool } from '@compilr-dev/sdk';
19
19
  export declare const todoStore: TodoStore;
20
20
  import { setMetaToolFilter, getRegisteredMetaTools } from './tools/meta-tools.js';
@@ -32,9 +32,10 @@ export declare function createToolRegistry(): unknown[];
32
32
  export declare function createMinimalToolRegistry(): unknown[];
33
33
  /**
34
34
  * Get direct tools that are always available.
35
- * These are declared normally and can be called by name.
35
+ * When hotOnly is true, returns only hot tools (7 tools, ~2.1K tokens).
36
+ * When false/undefined, returns all direct tools (18 tools, ~5.4K tokens).
36
37
  */
37
- export declare function getDirectTools(): Tool[];
38
+ export declare function getDirectTools(hotOnly?: boolean): Tool[];
38
39
  /**
39
40
  * Get meta-tools for agent registration.
40
41
  * Only get_tool_info is kept as a direct tool — use_tool and list_tools
@@ -47,11 +48,18 @@ export declare function getMetaTools(): Tool[];
47
48
  * checks the meta-registry and executes it transparently.
48
49
  */
49
50
  export declare function createToolFallback(): (name: string, input: Record<string, unknown>) => Promise<import('@compilr-dev/sdk').ToolExecutionResult | null>;
51
+ /**
52
+ * Check if hot-tools mode is active.
53
+ * When true, only hot tools are declared as direct schemas; warm tools are in meta-registry.
54
+ */
55
+ export declare function isHotToolsMode(): boolean;
50
56
  /**
51
57
  * Initialize the meta-tool registry with specialized tools.
58
+ * When includeWarmTools is true, warm tools are also added to the meta-registry
59
+ * (enabling hot-tools mode where only 7 core tools are declared directly).
52
60
  * Call this once at startup.
53
61
  */
54
- export declare function initializeMetaTools(): void;
62
+ export declare function initializeMetaTools(includeWarmTools?: boolean): void;
55
63
  /**
56
64
  * Get the tool index for the system prompt.
57
65
  * This lists all meta-registry tools with their signatures.
@@ -71,6 +79,8 @@ export declare function isMetaToolsEnabled(): boolean;
71
79
  */
72
80
  export declare function getToolStats(): {
73
81
  directTools: number;
82
+ hotTools: number;
83
+ warmTools: number;
74
84
  metaRegistryTools: number;
75
85
  totalTools: number;
76
86
  estimatedDirectTokens: number;
package/dist/tools.js CHANGED
@@ -16,7 +16,7 @@
16
16
  */
17
17
  // Re-export tool names from the dependency-free module
18
18
  // This breaks circular dependencies while maintaining a single source of truth
19
- export { TOOL_NAMES, DIRECT_TOOL_NAMES, META_TOOL_NAMES, META_REGISTRY_TOOL_NAMES, getAllToolNames, } from './tool-names.js';
19
+ export { TOOL_NAMES, DIRECT_TOOL_NAMES, HOT_TOOL_NAMES, WARM_TOOL_NAMES, META_TOOL_NAMES, META_REGISTRY_TOOL_NAMES, getAllToolNames, } from './tool-names.js';
20
20
  // =============================================================================
21
21
  // TOOL IMPORTS
22
22
  // =============================================================================
@@ -127,7 +127,7 @@ import { delegationStatusTool } from './tools/delegation-status.js';
127
127
  import { handoffTool } from './tools/handoff.js';
128
128
  import { guideTool } from './tools/guide-tool.js';
129
129
  // DB tools for project, work item, document, plan, backlog, anchor, artifact, and episode management
130
- import { allDbTools } from './tools/db-tools.js';
130
+ import { allDbTools, allFactoryTools } from './tools/db-tools.js';
131
131
  // Meta-tools for dynamic tool loading
132
132
  import { initializeMetaToolRegistry, generateToolIndex, getMetaToolCount, META_TOOLS_SYSTEM_PROMPT_PREFIX, setMetaToolFilter, getRegisteredMetaTools, createMetaToolFallback, getToolInfoTool, } from './tools/meta-tools.js';
133
133
  // Re-export for use in agent.ts
@@ -136,29 +136,36 @@ export { setMetaToolFilter, getRegisteredMetaTools };
136
136
  // DIRECT TOOLS - Always available, called by name
137
137
  // =============================================================================
138
138
  /**
139
- * Direct tools are the most frequently used tools.
140
- * These are always available and can be called directly by name.
141
- * Estimated: ~3,500 tokens for definitions
139
+ * Hot tools used in >50% of turns. Always declared as direct schemas.
140
+ * Estimated: ~2,100 tokens for definitions
142
141
  */
143
- const DIRECT_TOOLS = [
142
+ const HOT_TOOLS = [
144
143
  // File operations (most common)
145
144
  readFileTool,
146
145
  writeFileTool,
147
146
  editTool,
148
147
  // Shell (very common)
149
148
  bashTool,
150
- bashOutputTool,
151
- killShellTool,
152
149
  // Search (very common)
153
150
  globTool,
154
151
  grepTool,
155
- // Task tracking (always needed)
152
+ // User interaction (always needed)
153
+ askUserTool,
154
+ ];
155
+ /**
156
+ * Warm tools — used occasionally. In hot-tools mode these move to meta-registry.
157
+ * Estimated: ~3,300 tokens for definitions
158
+ */
159
+ const WARM_TOOLS = [
160
+ // Shell management
161
+ bashOutputTool,
162
+ killShellTool,
163
+ // Task tracking
156
164
  todoWriteTool,
157
165
  todoReadTool,
158
166
  todoClaimTool,
159
167
  todoHandoffTool,
160
- // User interaction (always needed)
161
- askUserTool,
168
+ // User interaction (simple variant)
162
169
  askUserSimpleTool,
163
170
  // Delegation (coordinator only)
164
171
  delegateTool,
@@ -166,9 +173,14 @@ const DIRECT_TOOLS = [
166
173
  delegateBackgroundTool,
167
174
  // Handoff (specialist-to-specialist)
168
175
  handoffTool,
169
- // CLI documentation (always available)
176
+ // CLI documentation
170
177
  guideTool,
171
178
  ];
179
+ /**
180
+ * All direct tools combined (hot + warm).
181
+ * Used in legacy mode (no meta-tools) and for backwards compatibility.
182
+ */
183
+ const DIRECT_TOOLS = [...HOT_TOOLS, ...WARM_TOOLS];
172
184
  // =============================================================================
173
185
  // META-REGISTRY TOOLS - Available via use_tool()
174
186
  // =============================================================================
@@ -212,6 +224,8 @@ const META_REGISTRY_TOOLS = [
212
224
  getComplexityTool,
213
225
  // DB tools (project, workitem, document, plan, backlog, anchor, artifact, episode)
214
226
  ...allDbTools,
227
+ // Factory tools (app_model_get, app_model_update, app_model_validate, factory_scaffold, factory_list_toolkits)
228
+ ...allFactoryTools,
215
229
  // Delegation status (coordinator query)
216
230
  delegationStatusTool,
217
231
  ];
@@ -246,9 +260,12 @@ export function createMinimalToolRegistry() {
246
260
  // =============================================================================
247
261
  /**
248
262
  * Get direct tools that are always available.
249
- * These are declared normally and can be called by name.
263
+ * When hotOnly is true, returns only hot tools (7 tools, ~2.1K tokens).
264
+ * When false/undefined, returns all direct tools (18 tools, ~5.4K tokens).
250
265
  */
251
- export function getDirectTools() {
266
+ export function getDirectTools(hotOnly) {
267
+ if (hotOnly)
268
+ return HOT_TOOLS;
252
269
  return DIRECT_TOOLS;
253
270
  }
254
271
  /**
@@ -267,12 +284,29 @@ export function getMetaTools() {
267
284
  export function createToolFallback() {
268
285
  return createMetaToolFallback();
269
286
  }
287
+ /** Whether hot-tools mode is active (warm tools in meta-registry) */
288
+ let hotToolsModeActive = false;
289
+ /**
290
+ * Check if hot-tools mode is active.
291
+ * When true, only hot tools are declared as direct schemas; warm tools are in meta-registry.
292
+ */
293
+ export function isHotToolsMode() {
294
+ return hotToolsModeActive;
295
+ }
270
296
  /**
271
297
  * Initialize the meta-tool registry with specialized tools.
298
+ * When includeWarmTools is true, warm tools are also added to the meta-registry
299
+ * (enabling hot-tools mode where only 7 core tools are declared directly).
272
300
  * Call this once at startup.
273
301
  */
274
- export function initializeMetaTools() {
275
- initializeMetaToolRegistry(META_REGISTRY_TOOLS);
302
+ export function initializeMetaTools(includeWarmTools) {
303
+ const tools = includeWarmTools
304
+ ? [...WARM_TOOLS, ...META_REGISTRY_TOOLS]
305
+ : META_REGISTRY_TOOLS;
306
+ initializeMetaToolRegistry(tools);
307
+ if (includeWarmTools) {
308
+ hotToolsModeActive = true;
309
+ }
276
310
  }
277
311
  /**
278
312
  * Get the tool index for the system prompt.
@@ -301,16 +335,22 @@ export function isMetaToolsEnabled() {
301
335
  * Get tool statistics for debugging/display.
302
336
  */
303
337
  export function getToolStats() {
304
- const directCount = DIRECT_TOOLS.length;
305
- const metaCount = META_REGISTRY_TOOLS.length;
306
- const totalCount = directCount + metaCount;
338
+ const hotCount = HOT_TOOLS.length;
339
+ const warmCount = WARM_TOOLS.length;
340
+ const directCount = hotToolsModeActive ? hotCount : hotCount + warmCount;
341
+ const metaCount = hotToolsModeActive
342
+ ? META_REGISTRY_TOOLS.length + warmCount
343
+ : META_REGISTRY_TOOLS.length;
344
+ const totalCount = hotCount + warmCount + META_REGISTRY_TOOLS.length;
307
345
  // Rough estimates: ~300 tokens per tool definition
308
346
  const tokensPerTool = 300;
309
347
  const estimatedDirectTokens = directCount * tokensPerTool;
310
- const estimatedMetaTokens = 800; // Tool index + meta-tool definitions
348
+ const estimatedMetaTokens = 1000; // Tool index + meta-tool definitions
311
349
  const estimatedLegacyTokens = totalCount * tokensPerTool;
312
350
  return {
313
351
  directTools: directCount,
352
+ hotTools: hotCount,
353
+ warmTools: warmCount,
314
354
  metaRegistryTools: metaCount,
315
355
  totalTools: totalCount,
316
356
  estimatedDirectTokens,
@@ -22,6 +22,7 @@ export const DOC_TYPE_LABELS = {
22
22
  'design': 'DESIGN',
23
23
  'notes': 'NOTES',
24
24
  'plan': 'PLAN',
25
+ 'app-model': 'MODEL',
25
26
  };
26
27
  // =============================================================================
27
28
  // Plan Status Labels
@@ -24,6 +24,7 @@ interface ProjectStats {
24
24
  hasPrd: boolean;
25
25
  hasArchDocs: boolean;
26
26
  hasScaffold: boolean;
27
+ hasModel: boolean;
27
28
  }
28
29
  interface ActionItem {
29
30
  label: string;
@@ -53,7 +53,7 @@ const PHASES = [
53
53
  id: 'scaffold',
54
54
  name: 'Scaffold',
55
55
  command: '/scaffold',
56
- description: 'Create project foundation',
56
+ description: 'Create project foundation (auto-generates if model available)',
57
57
  isComplete: (_project, stats) => stats.hasScaffold,
58
58
  isActive: (_project, stats) => stats.totalItems >= 3 && !stats.hasScaffold,
59
59
  },
@@ -82,6 +82,7 @@ function getProjectStats(project) {
82
82
  const docs = documentRepository.listByProject(project.id);
83
83
  const hasPrd = docs.some(d => d.docType === 'prd');
84
84
  const hasArchDocs = docs.some(d => d.docType === 'architecture');
85
+ const hasModel = docs.some(d => d.docType === 'app-model');
85
86
  const hasScaffold = items.some(i => i.title.toLowerCase().includes('scaffold') && i.status === 'completed') || project.metadata?.scaffolded === true;
86
87
  return {
87
88
  totalItems: items.length,
@@ -90,6 +91,7 @@ function getProjectStats(project) {
90
91
  hasPrd,
91
92
  hasArchDocs,
92
93
  hasScaffold,
94
+ hasModel,
93
95
  };
94
96
  }
95
97
  function buildActionsItems(project, stats) {
@@ -130,9 +132,9 @@ function buildActionsItems(project, stats) {
130
132
  }
131
133
  if (stats.totalItems > 0 && !stats.hasScaffold) {
132
134
  actions.push({
133
- label: 'Scaffold Project',
135
+ label: stats.hasModel ? 'Generate from Model' : 'Scaffold Project',
134
136
  command: '/scaffold',
135
- description: 'Create project foundation',
137
+ description: stats.hasModel ? 'Auto-generate from Application Model' : 'Create project foundation',
136
138
  enabled: true,
137
139
  });
138
140
  }
@@ -103,12 +103,12 @@ export declare class TerminalUI extends EventEmitter {
103
103
  * Add input/output tokens for live display
104
104
  * @param thinkingTokens - Optional thinking tokens (Gemini 2.5+ models)
105
105
  * @param cacheReadTokens - Optional cache read tokens (Anthropic/Gemini)
106
- * @param debugPayload - Optional debug payload sizes (char counts)
106
+ * @param debugPayload - Optional debug payload sizes (token estimates)
107
107
  */
108
108
  addTokens(inputTokens: number, outputTokens: number, thinkingTokens?: number, cacheReadTokens?: number, debugPayload?: {
109
- systemChars: number;
110
- contentsChars: number;
111
- toolsChars: number;
109
+ systemTokens: number;
110
+ contentsTokens: number;
111
+ toolsTokens: number;
112
112
  }): void;
113
113
  /**
114
114
  * Increment tool call counter
@@ -134,9 +134,9 @@ export declare class TerminalUI extends EventEmitter {
134
134
  toolCalls: number;
135
135
  apiCalls: number;
136
136
  debugPayload?: {
137
- systemChars: number;
138
- contentsChars: number;
139
- toolsChars: number;
137
+ systemTokens: number;
138
+ contentsTokens: number;
139
+ toolsTokens: number;
140
140
  };
141
141
  };
142
142
  setMode(mode: AgentMode): void;
@@ -339,7 +339,7 @@ export class TerminalUI extends EventEmitter {
339
339
  * Add input/output tokens for live display
340
340
  * @param thinkingTokens - Optional thinking tokens (Gemini 2.5+ models)
341
341
  * @param cacheReadTokens - Optional cache read tokens (Anthropic/Gemini)
342
- * @param debugPayload - Optional debug payload sizes (char counts)
342
+ * @param debugPayload - Optional debug payload sizes (token estimates)
343
343
  */
344
344
  addTokens(inputTokens, outputTokens, thinkingTokens, cacheReadTokens, debugPayload) {
345
345
  this.turnMetrics.addTokens(inputTokens, outputTokens, thinkingTokens, cacheReadTokens, debugPayload);
@@ -130,6 +130,21 @@ export function formatToolResult(toolName, result) {
130
130
  else if (toolLower.startsWith('artifact_')) {
131
131
  ({ content, summary } = formatArtifact(toolLower, innerResult));
132
132
  }
133
+ else if (toolLower === 'app_model_get') {
134
+ ({ content, summary } = formatAppModelGet(innerResult));
135
+ }
136
+ else if (toolLower === 'app_model_update') {
137
+ ({ content, summary } = formatAppModelUpdate(innerResult));
138
+ }
139
+ else if (toolLower === 'app_model_validate') {
140
+ ({ content, summary } = formatAppModelValidate(innerResult));
141
+ }
142
+ else if (toolLower === 'factory_scaffold') {
143
+ ({ content, summary } = formatFactoryScaffold(innerResult));
144
+ }
145
+ else if (toolLower === 'factory_list_toolkits') {
146
+ ({ content, summary } = formatFactoryListToolkits(innerResult));
147
+ }
133
148
  else if (toolLower === 'list_tools') {
134
149
  ({ content, summary } = formatListTools(innerResult));
135
150
  }
@@ -973,14 +988,22 @@ function formatListTools(result) {
973
988
  return { content: '', summary: count ? `${String(count)} tools available` : 'No tools' };
974
989
  }
975
990
  function formatGetToolInfo(result) {
991
+ // Compact schema format (SDK 0.1.15+): result is a string like "tool_name(...)\n description"
992
+ if (typeof result === 'string') {
993
+ // Extract tool name from signature line: "tool_name(params...)"
994
+ const parenIdx = result.indexOf('(');
995
+ const toolName = parenIdx > 0 ? result.slice(0, parenIdx) : null;
996
+ if (toolName) {
997
+ return { content: '', summary: `Schema: ${toolName}` };
998
+ }
999
+ return { content: '', summary: result.split('\n')[0].slice(0, 80) };
1000
+ }
1001
+ // Legacy object format: { name, description, parameters }
976
1002
  const name = result.name;
977
- const description = result.description;
978
- if (name && description) {
979
- // First sentence of description
980
- const firstSentence = description.split('.')[0].slice(0, 60);
981
- return { content: '', summary: `${name}: ${firstSentence}` };
1003
+ if (name) {
1004
+ return { content: '', summary: `Schema: ${name}` };
982
1005
  }
983
- return { content: '', summary: name || 'Tool info' };
1006
+ return { content: '', summary: 'Tool info' };
984
1007
  }
985
1008
  function formatDelegateBackground(result) {
986
1009
  const delegated = result.delegated;
@@ -1002,6 +1025,167 @@ function formatDelegate(result) {
1002
1025
  const message = result.message;
1003
1026
  return { content: '', summary: message || 'Delegated' };
1004
1027
  }
1028
+ // =============================================================================
1029
+ // Factory Tool Formatters
1030
+ // =============================================================================
1031
+ /**
1032
+ * Unwrap the use_tool envelope to get the actual tool result.
1033
+ * use_tool wraps as: { tool, status, message, result: { success, result: actualData } }
1034
+ */
1035
+ function unwrapToolResult(result) {
1036
+ const inner = result.result;
1037
+ if (inner && typeof inner === 'object' && !Array.isArray(inner)) {
1038
+ const innerObj = inner;
1039
+ // If wrapped by use_tool, the actual data is in innerObj.result
1040
+ if (innerObj.result && typeof innerObj.result === 'object' && !Array.isArray(innerObj.result)) {
1041
+ return innerObj.result;
1042
+ }
1043
+ return innerObj;
1044
+ }
1045
+ return result;
1046
+ }
1047
+ function formatAppModelGet(result) {
1048
+ const data = unwrapToolResult(result);
1049
+ // No model exists
1050
+ if (data.exists === false) {
1051
+ const message = data.message;
1052
+ return { content: '', summary: message || 'No Application Model found' };
1053
+ }
1054
+ // Summary scope
1055
+ if (data.entityCount !== undefined) {
1056
+ const name = data.name || '?';
1057
+ const entityCount = data.entityCount;
1058
+ const toolkit = data.toolkit || '?';
1059
+ const revision = data.revision;
1060
+ const entities = data.entities;
1061
+ const summary = `${name} — ${String(entityCount)} entities, toolkit: ${toolkit}${revision !== undefined ? `, rev ${String(revision)}` : ''}`;
1062
+ const lines = [];
1063
+ if (entities?.length) {
1064
+ for (const e of entities) {
1065
+ const rels = e.relationshipCount > 0 ? `, ${String(e.relationshipCount)} rel` : '';
1066
+ lines.push(` ${e.name} (${String(e.fieldCount)} fields, ${e.views.join('/')})${rels}`);
1067
+ }
1068
+ }
1069
+ const features = data.features;
1070
+ if (features) {
1071
+ const enabled = Object.entries(features).filter(([, v]) => v).map(([k]) => k);
1072
+ if (enabled.length)
1073
+ lines.push(`Features: ${enabled.join(', ')}`);
1074
+ }
1075
+ return { content: lines.join('\n'), summary };
1076
+ }
1077
+ // Single entity scope
1078
+ if (data.entity && typeof data.entity === 'object') {
1079
+ const entity = data.entity;
1080
+ const name = entity.name || '?';
1081
+ const fields = entity.fields;
1082
+ const rels = entity.relationships;
1083
+ const summary = `Entity: ${name} (${String(fields?.length ?? 0)} fields)`;
1084
+ const lines = [];
1085
+ if (fields?.length) {
1086
+ lines.push('Fields:');
1087
+ for (const f of fields)
1088
+ lines.push(` ${f.name}: ${f.type}`);
1089
+ }
1090
+ if (rels?.length) {
1091
+ lines.push('Relationships:');
1092
+ for (const r of rels)
1093
+ lines.push(` ${r.type} → ${r.target}`);
1094
+ }
1095
+ return { content: lines.join('\n'), summary };
1096
+ }
1097
+ // Section scopes (identity, features, layout, theme, techStack)
1098
+ const section = data.identity ?? data.features ?? data.layout ?? data.theme ?? data.techStack;
1099
+ if (section && typeof section === 'object') {
1100
+ const entries = Object.entries(section);
1101
+ const summary = entries.map(([k, v]) => `${k}: ${String(v)}`).join(', ');
1102
+ return { content: '', summary: truncate(summary, 80) };
1103
+ }
1104
+ // Full model fallback
1105
+ const message = data.message;
1106
+ return { content: '', summary: message || 'Application Model' };
1107
+ }
1108
+ function formatAppModelUpdate(result) {
1109
+ const data = unwrapToolResult(result);
1110
+ const op = data.op || '';
1111
+ const revision = data.revision;
1112
+ const message = data.message;
1113
+ const revInfo = revision !== undefined ? ` (rev ${String(revision)})` : '';
1114
+ const summary = message || `${op} applied${revInfo}`;
1115
+ return { content: '', summary: truncate(summary, 80) };
1116
+ }
1117
+ function formatAppModelValidate(result) {
1118
+ const data = unwrapToolResult(result);
1119
+ const valid = data.valid;
1120
+ const errors = data.errors;
1121
+ const revision = data.revision;
1122
+ if (valid) {
1123
+ return { content: '', summary: `Model valid${revision !== undefined ? ` (rev ${String(revision)})` : ''}` };
1124
+ }
1125
+ const errorCount = errors?.length ?? 0;
1126
+ const summary = `${String(errorCount)} validation error(s)`;
1127
+ const lines = errors?.slice(0, 10).map((e) => `${e.path || '?'}: ${e.message || 'error'}`) ?? [];
1128
+ if (errorCount > 10)
1129
+ lines.push(`... and ${String(errorCount - 10)} more`);
1130
+ return { content: lines.join('\n'), summary };
1131
+ }
1132
+ function formatFactoryScaffold(result) {
1133
+ const data = unwrapToolResult(result);
1134
+ const toolkit = data.toolkit || '?';
1135
+ const fileCount = data.fileCount;
1136
+ const files = data.files;
1137
+ const dryRun = data.dryRun;
1138
+ const warnings = data.warnings;
1139
+ const message = data.message;
1140
+ const mode = dryRun ? 'Dry run' : 'Generated';
1141
+ const summary = message || `${mode}: ${String(fileCount ?? 0)} files (${toolkit})`;
1142
+ // Build detailed content with file listing
1143
+ const lines = [];
1144
+ if (files?.length) {
1145
+ // Group files by directory
1146
+ const dirs = new Map();
1147
+ for (const f of files) {
1148
+ const parts = f.split('/');
1149
+ const dir = parts.length > 1 ? parts.slice(0, -1).join('/') : '.';
1150
+ const file = parts[parts.length - 1];
1151
+ const existing = dirs.get(dir);
1152
+ if (existing) {
1153
+ existing.push(file);
1154
+ }
1155
+ else {
1156
+ dirs.set(dir, [file]);
1157
+ }
1158
+ }
1159
+ for (const [dir, dirFiles] of dirs) {
1160
+ lines.push(`${dir}/`);
1161
+ for (const f of dirFiles)
1162
+ lines.push(` ${f}`);
1163
+ }
1164
+ }
1165
+ if (warnings?.length) {
1166
+ lines.push('');
1167
+ lines.push('Warnings:');
1168
+ for (const w of warnings)
1169
+ lines.push(` ! ${w}`);
1170
+ }
1171
+ return { content: lines.join('\n'), summary };
1172
+ }
1173
+ function formatFactoryListToolkits(result) {
1174
+ const data = unwrapToolResult(result);
1175
+ const count = data.count;
1176
+ const toolkits = data.toolkits;
1177
+ if (!toolkits?.length) {
1178
+ return { content: '', summary: 'No toolkits available' };
1179
+ }
1180
+ const summary = `${String(count ?? toolkits.length)} toolkit(s)`;
1181
+ const lines = toolkits.map((t) => {
1182
+ const name = t.name || t.id || '?';
1183
+ const desc = t.description ? ` — ${t.description}` : '';
1184
+ const sections = t.requiredSections?.length ? `\n Requires: ${t.requiredSections.join(', ')}` : '';
1185
+ return `${name}${desc}${sections}`;
1186
+ });
1187
+ return { content: lines.join('\n'), summary };
1188
+ }
1005
1189
  function formatGeneric(result) {
1006
1190
  const content = typeof result.content === 'string'
1007
1191
  ? result.content