@standardagents/cli 0.11.12 → 0.12.0

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/dist/index.js CHANGED
@@ -139,13 +139,25 @@ interface ThreadState {
139
139
 
140
140
  Access in tools:
141
141
  \`\`\`typescript
142
- export default defineTool('...', schema, async (flow, args) => {
143
- const threadId = flow.threadId;
144
- const { messages } = await flow.getMessages();
142
+ export default defineTool('...', schema, async (state, args) => {
143
+ const threadId = state.threadId;
144
+ const { messages } = await state.getMessages();
145
145
  // ...
146
146
  });
147
147
  \`\`\`
148
148
 
149
+ Access in hooks:
150
+ \`\`\`typescript
151
+ export default defineHook({
152
+ hook: 'before_create_message',
153
+ id: 'my_hook',
154
+ execute: async (state, message) => {
155
+ console.log(\`Thread: \${state.threadId}, Agent: \${state.agentId}\`);
156
+ return message;
157
+ }
158
+ });
159
+ \`\`\`
160
+
149
161
  ## Quick Reference
150
162
 
151
163
  | Function | Purpose | Directory |
@@ -180,7 +192,7 @@ Full documentation: https://docs.standardagentbuilder.com
180
192
  - [Agents](https://docs.standardagentbuilder.com/core-concepts/agents)
181
193
  - [Tools](https://docs.standardagentbuilder.com/core-concepts/tools)
182
194
  - [Hooks](https://docs.standardagentbuilder.com/core-concepts/hooks)
183
- - [FlowState](https://docs.standardagentbuilder.com/core-concepts/flowstate)
195
+ - [ThreadState](https://docs.standardagentbuilder.com/core-concepts/threadstate)
184
196
  - [Thread API](https://docs.standardagentbuilder.com/core-concepts/api)
185
197
  `;
186
198
 
@@ -291,6 +303,7 @@ Prompts define system instructions, model selection, and available tools for LLM
291
303
  | \`parallelToolCalls\` | \`boolean\` | No | Allow multiple concurrent tool calls |
292
304
  | \`toolChoice\` | \`'auto' \\| 'none' \\| 'required'\` | No | Tool calling strategy |
293
305
  | \`requiredSchema\` | \`z.ZodObject\` | No | Input validation when called as tool |
306
+ | \`hooks\` | \`string[]\` | No | Hook IDs to run for this prompt (overrides agent hooks) |
294
307
  | \`reasoning\` | \`ReasoningConfig\` | No | Extended thinking configuration |
295
308
 
296
309
  ## Basic Example
@@ -389,6 +402,22 @@ reasoning: {
389
402
  },
390
403
  \`\`\`
391
404
 
405
+ ## Hooks
406
+
407
+ Attach lifecycle hooks to a prompt:
408
+
409
+ \`\`\`typescript
410
+ export default definePrompt({
411
+ name: 'customer_support',
412
+ toolDescription: 'Handle customer support',
413
+ model: 'default',
414
+ prompt: 'You are a support agent...',
415
+ hooks: ['limit_to_20', 'redact_pii'], // Hook IDs from agents/hooks/
416
+ });
417
+ \`\`\`
418
+
419
+ Prompt hooks take precedence over agent hooks. See \`agents/hooks/CLAUDE.md\` for details.
420
+
392
421
  ## Best Practices
393
422
 
394
423
  - **Write clear instructions** - Structure with headers and bullet points
@@ -418,6 +447,7 @@ Agents orchestrate conversations by defining prompts, stop conditions, and turn
418
447
  | \`maxSessionTurns\` | \`number\` | No | Max total turns across both sides |
419
448
  | \`exposeAsTool\` | \`boolean\` | No | Allow other prompts to hand off to this agent |
420
449
  | \`toolDescription\` | \`string\` | No | Description when used as tool (required if exposeAsTool) |
450
+ | \`hooks\` | \`string[]\` | No | Hook IDs to run for this agent (fallback if prompt has no hooks) |
421
451
  | \`tags\` | \`string[]\` | No | Tags for categorization and filtering |
422
452
 
423
453
  ## Side Configuration
@@ -500,6 +530,23 @@ Other prompts can then include the agent name in their \`tools\` array to enable
500
530
  4. **stopOnResponse** - Ends turn when LLM returns text
501
531
  5. **maxSessionTurns** - Ends conversation (hard limit: 250)
502
532
 
533
+ ## Hooks
534
+
535
+ Attach lifecycle hooks at the agent level:
536
+
537
+ \`\`\`typescript
538
+ export default defineAgent({
539
+ name: 'support_agent',
540
+ type: 'ai_human',
541
+ hooks: ['log_all_messages', 'sanitize_results'],
542
+ sideA: {
543
+ prompt: 'customer_support',
544
+ },
545
+ });
546
+ \`\`\`
547
+
548
+ Agent hooks run as a fallback when the active prompt has no hooks defined. Prompt hooks always take precedence. See \`agents/hooks/CLAUDE.md\` for details.
549
+
503
550
  ## Naming Convention
504
551
 
505
552
  Agent names **must** end with the \`_agent\` suffix (e.g., \`support_agent\`, \`research_agent\`).
@@ -748,31 +795,69 @@ Hooks intercept and modify agent execution at specific lifecycle points.
748
795
 
749
796
  | Hook | Signature | Purpose |
750
797
  |------|-----------|---------|
751
- | \`filter_messages\` | \`(state, rows) => Message[]\` | Filter raw message rows before LLM context |
752
- | \`prefilter_llm_history\` | \`(state, messages) => Message[]\` | Modify messages after filtering, before LLM |
753
- | \`before_create_message\` | \`(state, message) => Message\` | Modify message before database insert |
754
- | \`after_create_message\` | \`(state, message) => void\` | Run logic after message created |
755
- | \`before_update_message\` | \`(state, id, updates) => Updates\` | Modify updates before message update |
756
- | \`after_update_message\` | \`(state, message) => void\` | Run logic after message updated |
757
- | \`before_store_tool_result\` | \`(state, toolCall, result) => Result\` | Modify tool result before storage |
758
- | \`after_tool_call_success\` | \`(state, toolCall, result) => Result\` | Process successful tool execution |
759
- | \`after_tool_call_failure\` | \`(state, toolCall, result) => Result\` | Process failed tool execution |
798
+ | \`filter_messages\` | \`(state: ThreadState, messages: Message[]) => Message[]\` | Filter raw messages before LLM context |
799
+ | \`prefilter_llm_history\` | \`(state: ThreadState, messages: LLMMessage[]) => LLMMessage[]\` | Modify chat completion messages before LLM |
800
+ | \`before_create_message\` | \`(state: ThreadState, message: Message) => Message\` | Modify message before database insert |
801
+ | \`after_create_message\` | \`(state: ThreadState, message: Message) => void\` | Run logic after message created |
802
+ | \`before_update_message\` | \`(state: ThreadState, id: string, updates: Record) => Record\` | Modify updates before message update |
803
+ | \`after_update_message\` | \`(state: ThreadState, message: Message) => void\` | Run logic after message updated |
804
+ | \`before_store_tool_result\` | \`(state: ThreadState, toolCall: HookToolCall, result: HookToolResult) => HookToolResult\` | Modify tool result before storage |
805
+ | \`after_tool_call_success\` | \`(state: ThreadState, toolCall: HookToolCall, result: HookToolResult) => HookToolResult \\| null\` | Process successful tool execution |
806
+ | \`after_tool_call_failure\` | \`(state: ThreadState, toolCall: HookToolCall, result: HookToolResult) => HookToolResult \\| null\` | Process failed tool execution |
807
+
808
+ All hooks receive \`ThreadState\` as their first parameter, providing access to thread identity, message history, and resource loading.
809
+
810
+ ## Creating a Hook
811
+
812
+ Each hook file exports a default \`defineHook\` call with three properties:
813
+
814
+ \`\`\`typescript
815
+ import { defineHook } from '@standardagents/builder';
816
+
817
+ export default defineHook({
818
+ hook: 'filter_messages', // Hook type
819
+ id: 'limit_recent_messages', // Unique ID (snake_case)
820
+ execute: async (state, messages) => {
821
+ return messages.slice(-20);
822
+ }
823
+ });
824
+ \`\`\`
825
+
826
+ ## Hook Scoping
827
+
828
+ Hooks are scoped to **prompts** or **agents** via their ID:
829
+
830
+ \`\`\`typescript
831
+ // In a prompt definition
832
+ definePrompt({
833
+ name: 'customer_support',
834
+ hooks: ['limit_recent_messages', 'redact_pii'],
835
+ // ...
836
+ });
837
+
838
+ // In an agent definition
839
+ defineAgent({
840
+ name: 'support_agent',
841
+ hooks: ['log_all_messages'],
842
+ // ...
843
+ });
844
+ \`\`\`
845
+
846
+ - **Prompt hooks** take precedence over agent hooks
847
+ - If a prompt defines hooks, only those run (agent hooks are skipped)
848
+ - If no prompt hooks are defined, agent hooks run as fallback
849
+ - Hooks are filtered by type at runtime
760
850
 
761
851
  ## File Naming
762
852
 
763
- Hook files **must** be named exactly as the hook type:
853
+ Hook files can use **any name** \u2014 the hook type and ID are defined inside the file:
764
854
 
765
855
  \`\`\`
766
856
  agents/hooks/
767
- \u251C\u2500\u2500 filter_messages.ts
768
- \u251C\u2500\u2500 prefilter_llm_history.ts
769
- \u251C\u2500\u2500 before_create_message.ts
770
- \u251C\u2500\u2500 after_create_message.ts
771
- \u251C\u2500\u2500 before_update_message.ts
772
- \u251C\u2500\u2500 after_update_message.ts
773
- \u251C\u2500\u2500 before_store_tool_result.ts
774
- \u251C\u2500\u2500 after_tool_call_success.ts
775
- \u2514\u2500\u2500 after_tool_call_failure.ts
857
+ \u251C\u2500\u2500 my_filter.ts # Could contain any hook type
858
+ \u251C\u2500\u2500 redact_sensitive_data.ts
859
+ \u251C\u2500\u2500 log_tool_usage.ts
860
+ \u2514\u2500\u2500 add_metadata.ts
776
861
  \`\`\`
777
862
 
778
863
  ## Examples
@@ -782,23 +867,31 @@ agents/hooks/
782
867
  \`\`\`typescript
783
868
  import { defineHook } from '@standardagents/builder';
784
869
 
785
- export default defineHook('filter_messages', async (state, rows) => {
786
- // Only include last 20 messages
787
- return rows.slice(-20);
870
+ export default defineHook({
871
+ hook: 'filter_messages',
872
+ id: 'limit_to_20',
873
+ execute: async (state, messages) => {
874
+ return messages.slice(-20);
875
+ }
788
876
  });
789
877
  \`\`\`
790
878
 
791
- ### Prefilter LLM History (Modify Content)
879
+ ### Prefilter LLM History (Redact Content)
792
880
 
793
881
  \`\`\`typescript
794
882
  import { defineHook } from '@standardagents/builder';
795
883
 
796
- export default defineHook('prefilter_llm_history', async (state, messages) => {
797
- // Remove sensitive data from message content
798
- return messages.map(msg => ({
799
- ...msg,
800
- content: msg.content?.replace(/\\b\\d{4}-\\d{4}-\\d{4}-\\d{4}\\b/g, '[REDACTED]'),
801
- }));
884
+ export default defineHook({
885
+ hook: 'prefilter_llm_history',
886
+ id: 'redact_pii',
887
+ execute: async (state, messages) => {
888
+ return messages.map(msg => ({
889
+ ...msg,
890
+ content: typeof msg.content === 'string'
891
+ ? msg.content.replace(/\\b\\d{4}-\\d{4}-\\d{4}-\\d{4}\\b/g, '[REDACTED]')
892
+ : msg.content,
893
+ }));
894
+ }
802
895
  });
803
896
  \`\`\`
804
897
 
@@ -807,15 +900,34 @@ export default defineHook('prefilter_llm_history', async (state, messages) => {
807
900
  \`\`\`typescript
808
901
  import { defineHook } from '@standardagents/builder';
809
902
 
810
- export default defineHook('before_create_message', async (state, message) => {
811
- return {
812
- ...message,
813
- metadata: {
814
- ...message.metadata,
815
- createdAt: Date.now(),
816
- agentVersion: '1.0.0',
817
- },
818
- };
903
+ export default defineHook({
904
+ hook: 'before_create_message',
905
+ id: 'add_version_metadata',
906
+ execute: async (state, message) => {
907
+ if (message.role === 'user' && message.content) {
908
+ return { ...message, content: \`[v1.0] \${message.content}\` };
909
+ }
910
+ return message;
911
+ }
912
+ });
913
+ \`\`\`
914
+
915
+ ### Before Store Tool Result (Sanitize)
916
+
917
+ \`\`\`typescript
918
+ import { defineHook } from '@standardagents/builder';
919
+
920
+ export default defineHook({
921
+ hook: 'before_store_tool_result',
922
+ id: 'sanitize_results',
923
+ execute: async (state, toolCall, toolResult) => {
924
+ // toolCall: { id, type: 'function', function: { name, arguments } }
925
+ // toolResult: { status, result?, error?, stack?, attachments? }
926
+ if (toolResult.result) {
927
+ return { ...toolResult, result: toolResult.result.replace(/secret/gi, '[REDACTED]') };
928
+ }
929
+ return toolResult;
930
+ }
819
931
  });
820
932
  \`\`\`
821
933
 
@@ -824,9 +936,13 @@ export default defineHook('before_create_message', async (state, message) => {
824
936
  \`\`\`typescript
825
937
  import { defineHook } from '@standardagents/builder';
826
938
 
827
- export default defineHook('after_tool_call_success', async (state, toolCall, result) => {
828
- console.log(\`Tool \${toolCall.function.name} succeeded:\`, result);
829
- return result; // Return result unchanged, or modify it
939
+ export default defineHook({
940
+ hook: 'after_tool_call_success',
941
+ id: 'log_tool_success',
942
+ execute: async (state, toolCall, result) => {
943
+ console.log(\`Tool \${toolCall.function.name} succeeded\`);
944
+ return null; // Return null to use original result
945
+ }
830
946
  });
831
947
  \`\`\`
832
948
 
@@ -835,15 +951,18 @@ export default defineHook('after_tool_call_success', async (state, toolCall, res
835
951
  \`\`\`typescript
836
952
  import { defineHook } from '@standardagents/builder';
837
953
 
838
- export default defineHook('after_tool_call_failure', async (state, toolCall, result) => {
839
- // Override error with fallback result
840
- if (toolCall.function.name === 'fetch_weather') {
841
- return {
842
- status: 'success',
843
- result: JSON.stringify({ temp: 'unavailable', fallback: true }),
844
- };
954
+ export default defineHook({
955
+ hook: 'after_tool_call_failure',
956
+ id: 'weather_fallback',
957
+ execute: async (state, toolCall, result) => {
958
+ if (toolCall.function.name === 'fetch_weather') {
959
+ return {
960
+ status: 'success',
961
+ result: JSON.stringify({ temp: 'unavailable', fallback: true }),
962
+ };
963
+ }
964
+ return null; // Use original error for other tools
845
965
  }
846
- return result; // Return original error
847
966
  });
848
967
  \`\`\`
849
968
 
@@ -855,8 +974,8 @@ export default defineHook('after_tool_call_failure', async (state, toolCall, res
855
974
  - \`before_create_message\`
856
975
  - \`before_update_message\`
857
976
  - \`before_store_tool_result\`
858
- - \`after_tool_call_success\`
859
- - \`after_tool_call_failure\`
977
+ - \`after_tool_call_success\` (return modified result or null)
978
+ - \`after_tool_call_failure\` (return modified result or null)
860
979
 
861
980
  **Event hooks** (side effects only):
862
981
  - \`after_create_message\`
@@ -865,8 +984,9 @@ export default defineHook('after_tool_call_failure', async (state, toolCall, res
865
984
  ## Best Practices
866
985
 
867
986
  - **Keep hooks fast** - target <100ms execution
868
- - **Wrap in try-catch** - hooks continue on error
869
- - **Validate input data** before processing
987
+ - **Wrap in try-catch** - hooks continue on error (original data preserved)
988
+ - **Use unique IDs** - hook IDs must be snake_case and unique across the project
989
+ - **Scope appropriately** - assign hooks to prompts or agents that need them
870
990
  - **Document purpose** with clear comments
871
991
  - **Use for cross-cutting concerns** - logging, redaction, enrichment
872
992
 
@@ -1582,7 +1702,7 @@ function getPackageVersion() {
1582
1702
  if (process.env.STANDARDAGENTS_WORKSPACE === "1") {
1583
1703
  return "workspace:*";
1584
1704
  }
1585
- return "0.11.12";
1705
+ return "0.12.0";
1586
1706
  }
1587
1707
  async function selectPackageManager(detected) {
1588
1708
  const options = ["npm", "pnpm", "yarn", "bun"];
@@ -2375,13 +2495,437 @@ out
2375
2495
  pageTsx = pageTsx.replace(/from '\.\.\/\.\.\/src\//g, "from '../src/");
2376
2496
  fs3.writeFileSync(path3.join(projectPath, "app", "page.tsx"), pageTsx, "utf-8");
2377
2497
  }
2498
+ async function selectAgent(agents) {
2499
+ return new Promise((resolve) => {
2500
+ const stdin = process.stdin;
2501
+ const stdout = process.stdout;
2502
+ let selectedIndex = 0;
2503
+ const renderOptions = () => {
2504
+ stdout.write("\x1B[?25l");
2505
+ stdout.write(`\x1B[${agents.length + 1}A`);
2506
+ stdout.write("\x1B[0J");
2507
+ stdout.write("Select an agent to pack (use arrows, enter to confirm):\n");
2508
+ agents.forEach((agent, i) => {
2509
+ const prefix = i === selectedIndex ? "\x1B[36m\u276F\x1B[0m" : " ";
2510
+ const highlight = i === selectedIndex ? "\x1B[36m" : "\x1B[90m";
2511
+ stdout.write(`${prefix} ${highlight}${agent}\x1B[0m
2512
+ `);
2513
+ });
2514
+ };
2515
+ stdout.write("Select an agent to pack (use arrows, enter to confirm):\n");
2516
+ agents.forEach((agent, i) => {
2517
+ const prefix = i === selectedIndex ? "\x1B[36m\u276F\x1B[0m" : " ";
2518
+ const highlight = i === selectedIndex ? "\x1B[36m" : "\x1B[90m";
2519
+ stdout.write(`${prefix} ${highlight}${agent}\x1B[0m
2520
+ `);
2521
+ });
2522
+ const wasRaw = stdin.isRaw;
2523
+ if (stdin.isTTY) {
2524
+ stdin.setRawMode(true);
2525
+ }
2526
+ stdin.resume();
2527
+ stdin.setEncoding("utf8");
2528
+ const cleanup = () => {
2529
+ stdin.setRawMode(wasRaw ?? false);
2530
+ stdin.pause();
2531
+ stdin.removeListener("data", onData);
2532
+ stdout.write("\x1B[?25h");
2533
+ };
2534
+ const onData = (key) => {
2535
+ if (key === "\x1B[A" || key === "k") {
2536
+ selectedIndex = (selectedIndex - 1 + agents.length) % agents.length;
2537
+ renderOptions();
2538
+ } else if (key === "\x1B[B" || key === "j") {
2539
+ selectedIndex = (selectedIndex + 1) % agents.length;
2540
+ renderOptions();
2541
+ } else if (key === "\r" || key === "\n") {
2542
+ cleanup();
2543
+ resolve(agents[selectedIndex]);
2544
+ } else if (key === "") {
2545
+ cleanup();
2546
+ stdout.write("\n");
2547
+ process.exit(1);
2548
+ }
2549
+ };
2550
+ stdin.on("data", onData);
2551
+ });
2552
+ }
2553
+ async function selectItemModes(items, _agentName) {
2554
+ return new Promise((resolve) => {
2555
+ const stdin = process.stdin;
2556
+ const stdout = process.stdout;
2557
+ let selectedIndex = 0;
2558
+ const getDisplayLines = () => {
2559
+ const lines = [];
2560
+ lines.push("");
2561
+ lines.push("Remove originals? (space to toggle, enter to confirm)");
2562
+ lines.push("");
2563
+ for (let i = 0; i < items.length; i++) {
2564
+ const item = items[i];
2565
+ const isSelected = i === selectedIndex;
2566
+ const cursor = isSelected ? "\x1B[36m\u276F\x1B[0m" : " ";
2567
+ const modeText = item.mode === "extract" ? "\x1B[32m(extract)\x1B[0m" : "\x1B[90m(copy)\x1B[0m";
2568
+ lines.push(`${cursor} ${item.name} \x1B[90m(${item.type})\x1B[0m ${modeText}`);
2569
+ }
2570
+ lines.push("");
2571
+ return lines;
2572
+ };
2573
+ const render = (initial = false) => {
2574
+ const lines = getDisplayLines();
2575
+ if (!initial) {
2576
+ stdout.write("\x1B[?25l");
2577
+ stdout.write(`\x1B[${lines.length}A`);
2578
+ stdout.write("\x1B[0J");
2579
+ }
2580
+ stdout.write(lines.join("\n") + "\n");
2581
+ };
2582
+ render(true);
2583
+ const wasRaw = stdin.isRaw;
2584
+ if (stdin.isTTY) {
2585
+ stdin.setRawMode(true);
2586
+ }
2587
+ stdin.resume();
2588
+ stdin.setEncoding("utf8");
2589
+ const cleanup = () => {
2590
+ stdin.setRawMode(wasRaw ?? false);
2591
+ stdin.pause();
2592
+ stdin.removeListener("data", onData);
2593
+ stdout.write("\x1B[?25h");
2594
+ };
2595
+ const onData = (key) => {
2596
+ if (key === "\x1B[A" || key === "k") {
2597
+ selectedIndex = (selectedIndex - 1 + items.length) % items.length;
2598
+ render();
2599
+ } else if (key === "\x1B[B" || key === "j") {
2600
+ selectedIndex = (selectedIndex + 1) % items.length;
2601
+ render();
2602
+ } else if (key === " ") {
2603
+ items[selectedIndex].mode = items[selectedIndex].mode === "extract" ? "copy" : "extract";
2604
+ render();
2605
+ } else if (key === "\r" || key === "\n") {
2606
+ cleanup();
2607
+ resolve(items);
2608
+ } else if (key === "") {
2609
+ cleanup();
2610
+ stdout.write("\n");
2611
+ process.exit(1);
2612
+ }
2613
+ };
2614
+ stdin.on("data", onData);
2615
+ });
2616
+ }
2617
+ function isStandardAgentsProject() {
2618
+ if (!fs3.existsSync("agents")) {
2619
+ return false;
2620
+ }
2621
+ try {
2622
+ const pkgJson = JSON.parse(fs3.readFileSync("package.json", "utf-8"));
2623
+ const deps = { ...pkgJson.dependencies, ...pkgJson.devDependencies };
2624
+ return "@standardagents/builder" in deps;
2625
+ } catch {
2626
+ return false;
2627
+ }
2628
+ }
2629
+ async function pack(agentName, options) {
2630
+ logger.info("Packing agent...\n");
2631
+ if (!isStandardAgentsProject()) {
2632
+ logger.error("This does not appear to be a Standard Agents project.");
2633
+ logger.info("Make sure you have @standardagents/builder installed and an agents/ directory.");
2634
+ process.exit(1);
2635
+ }
2636
+ const rootDir = process.cwd();
2637
+ let PackingService;
2638
+ try {
2639
+ const packing = await import('@standardagents/builder/packing');
2640
+ PackingService = packing.PackingService;
2641
+ } catch (err) {
2642
+ logger.error("Failed to load packing service from @standardagents/builder");
2643
+ logger.info("Make sure @standardagents/builder is installed and built.");
2644
+ if (err instanceof Error) {
2645
+ logger.info(`Error: ${err.message}`);
2646
+ }
2647
+ process.exit(1);
2648
+ }
2649
+ const packingService = new PackingService();
2650
+ if (!agentName) {
2651
+ const agents = packingService.listAgents(rootDir);
2652
+ if (agents.length === 0) {
2653
+ logger.error("No agents found in agents/agents/");
2654
+ process.exit(1);
2655
+ }
2656
+ if (agents.length === 1) {
2657
+ agentName = agents[0];
2658
+ logger.info(`Found one agent: ${agentName}`);
2659
+ } else {
2660
+ console.log("");
2661
+ agentName = await selectAgent(agents);
2662
+ console.log("");
2663
+ }
2664
+ }
2665
+ if (!agentName) {
2666
+ logger.error("No agent selected");
2667
+ process.exit(1);
2668
+ }
2669
+ const selectedAgent = agentName;
2670
+ logger.info(`Analyzing agent: ${selectedAgent}`);
2671
+ const analysis = await packingService.analyzeAgent(selectedAgent, rootDir);
2672
+ if (analysis.errors.length > 0) {
2673
+ logger.error("Analysis failed:");
2674
+ for (const error of analysis.errors) {
2675
+ console.log(` - ${error}`);
2676
+ }
2677
+ process.exit(1);
2678
+ }
2679
+ console.log("");
2680
+ logger.info("Discovered constituents:");
2681
+ console.log(` Agents: ${analysis.constituents.agents.map((a) => a.name).join(", ") || "(none)"}`);
2682
+ console.log(` Prompts: ${analysis.constituents.prompts.map((p) => p.name).join(", ") || "(none)"}`);
2683
+ console.log(` Tools: ${analysis.constituents.tools.map((t) => t.name).join(", ") || "(none)"}`);
2684
+ console.log(` Models: ${analysis.constituents.models.map((m) => m.name).join(", ") || "(none)"}`);
2685
+ console.log(` Hooks: ${analysis.constituents.hooks.map((h) => h.name).join(", ") || "(none)"}`);
2686
+ if (analysis.warnings.length > 0) {
2687
+ console.log("");
2688
+ logger.warning("Warnings:");
2689
+ for (const warning of analysis.warnings) {
2690
+ console.log(` - ${warning}`);
2691
+ }
2692
+ }
2693
+ const selectionItems = [];
2694
+ for (const agent of analysis.constituents.agents) {
2695
+ selectionItems.push({
2696
+ name: agent.name,
2697
+ type: "agent",
2698
+ filePath: agent.filePath,
2699
+ mode: agent.sharedWith.length > 0 ? "copy" : "extract",
2700
+ isShared: agent.sharedWith.length > 0,
2701
+ sharedWith: agent.sharedWith
2702
+ });
2703
+ }
2704
+ for (const prompt3 of analysis.constituents.prompts) {
2705
+ selectionItems.push({
2706
+ name: prompt3.name,
2707
+ type: "prompt",
2708
+ filePath: prompt3.filePath,
2709
+ mode: prompt3.sharedWith.length > 0 ? "copy" : "extract",
2710
+ isShared: prompt3.sharedWith.length > 0,
2711
+ sharedWith: prompt3.sharedWith
2712
+ });
2713
+ }
2714
+ for (const tool of analysis.constituents.tools) {
2715
+ selectionItems.push({
2716
+ name: tool.name,
2717
+ type: "tool",
2718
+ filePath: tool.filePath,
2719
+ mode: tool.sharedWith.length > 0 ? "copy" : "extract",
2720
+ isShared: tool.sharedWith.length > 0,
2721
+ sharedWith: tool.sharedWith
2722
+ });
2723
+ }
2724
+ for (const model of analysis.constituents.models) {
2725
+ selectionItems.push({
2726
+ name: model.name,
2727
+ type: "model",
2728
+ filePath: model.filePath,
2729
+ mode: model.sharedWith.length > 0 ? "copy" : "extract",
2730
+ isShared: model.sharedWith.length > 0,
2731
+ sharedWith: model.sharedWith
2732
+ });
2733
+ }
2734
+ for (const hook of analysis.constituents.hooks) {
2735
+ selectionItems.push({
2736
+ name: hook.name,
2737
+ type: "hook",
2738
+ filePath: hook.filePath,
2739
+ mode: hook.sharedWith.length > 0 ? "copy" : "extract",
2740
+ isShared: hook.sharedWith.length > 0,
2741
+ sharedWith: hook.sharedWith
2742
+ });
2743
+ }
2744
+ let itemSelections;
2745
+ if (!options.noInteractive && process.stdin.isTTY && selectionItems.length > 0) {
2746
+ console.log("");
2747
+ const selections = await selectItemModes(selectionItems);
2748
+ itemSelections = selections.map((s) => ({
2749
+ name: s.name,
2750
+ type: s.type,
2751
+ filePath: s.filePath,
2752
+ mode: s.mode
2753
+ }));
2754
+ console.log("");
2755
+ }
2756
+ const outputDir = options.output || path3.join(rootDir, "agents", "packed");
2757
+ logger.info(`Packing to: ${outputDir}`);
2758
+ const result = await packingService.pack({
2759
+ agentName: selectedAgent,
2760
+ rootDir,
2761
+ outputDir,
2762
+ version: options.version || "1.0.0",
2763
+ npm: options.npm || false,
2764
+ removeOriginals: itemSelections ? false : !options.noRemove,
2765
+ // Let itemSelections handle removal
2766
+ packageId: `standardagent-${selectedAgent.replace(/_/g, "-")}`,
2767
+ itemSelections
2768
+ });
2769
+ if (!result.success) {
2770
+ logger.error(`Packing failed: ${result.error}`);
2771
+ process.exit(1);
2772
+ }
2773
+ console.log("");
2774
+ logger.success("Packing complete!");
2775
+ console.log(` Package ID: ${result.packageId}`);
2776
+ console.log(` Output: ${result.outputPath}`);
2777
+ console.log(` Files: ${result.filesCreated.length} created`);
2778
+ if (result.filesRemoved && result.filesRemoved.length > 0) {
2779
+ console.log(` Removed: ${result.filesRemoved.length} original files`);
2780
+ }
2781
+ if (result.warnings.length > 0) {
2782
+ console.log("");
2783
+ logger.warning("Warnings:");
2784
+ for (const warning of result.warnings) {
2785
+ console.log(` - ${warning}`);
2786
+ }
2787
+ }
2788
+ if (options.npm) {
2789
+ console.log("");
2790
+ logger.info("NPM package structure created. To publish:");
2791
+ console.log(` cd ${result.outputPath}`);
2792
+ console.log(" npm publish");
2793
+ }
2794
+ }
2795
+ function isStandardAgentsProject2() {
2796
+ if (!fs3.existsSync("agents")) {
2797
+ return false;
2798
+ }
2799
+ try {
2800
+ const pkgJson = JSON.parse(fs3.readFileSync("package.json", "utf-8"));
2801
+ const deps = { ...pkgJson.dependencies, ...pkgJson.devDependencies };
2802
+ return "@standardagents/builder" in deps;
2803
+ } catch {
2804
+ return false;
2805
+ }
2806
+ }
2807
+ async function unpack(pkgIdentifier, options) {
2808
+ logger.info("Unpacking agent...\n");
2809
+ if (!isStandardAgentsProject2()) {
2810
+ logger.error("This does not appear to be a Standard Agents project.");
2811
+ logger.info("Make sure you have @standardagents/builder installed and an agents/ directory.");
2812
+ process.exit(1);
2813
+ }
2814
+ const rootDir = process.cwd();
2815
+ let UnpackingService;
2816
+ try {
2817
+ const builder = await import('@standardagents/builder/runtime');
2818
+ UnpackingService = builder.UnpackingService;
2819
+ if (!UnpackingService) {
2820
+ const packing = await import('@standardagents/builder');
2821
+ UnpackingService = packing.UnpackingService;
2822
+ }
2823
+ } catch (err) {
2824
+ logger.error("Failed to load unpacking service from @standardagents/builder");
2825
+ logger.info("Make sure @standardagents/builder is installed.");
2826
+ process.exit(1);
2827
+ }
2828
+ const unpackingService = new UnpackingService();
2829
+ if (!pkgIdentifier) {
2830
+ const packages = await unpackingService.listPackages(rootDir);
2831
+ if (packages.length === 0) {
2832
+ logger.info("No packed agents found.");
2833
+ logger.info("Pack an agent with: agents pack <agent-name>");
2834
+ process.exit(0);
2835
+ }
2836
+ logger.info("Available packed agents:");
2837
+ for (const pkg of packages) {
2838
+ console.log(` - ${pkg.packageId} (${pkg.version}) [${pkg.source}]`);
2839
+ console.log(` Entry: ${pkg.entryAgent}`);
2840
+ console.log(` Path: ${pkg.path}`);
2841
+ console.log("");
2842
+ }
2843
+ logger.info("Run: agents unpack <package-id>");
2844
+ process.exit(0);
2845
+ }
2846
+ logger.info(`Unpacking: ${pkgIdentifier}`);
2847
+ const result = await unpackingService.unpack({
2848
+ package: pkgIdentifier,
2849
+ rootDir,
2850
+ keepSignatures: !options.noSignatures
2851
+ });
2852
+ if (!result.success) {
2853
+ logger.error(`Unpacking failed: ${result.error}`);
2854
+ process.exit(1);
2855
+ }
2856
+ console.log("");
2857
+ logger.success("Unpacking complete!");
2858
+ console.log(` Package: ${result.packageId}`);
2859
+ console.log(` Files: ${result.filesCreated.length} created`);
2860
+ if (result.filesCreated.length > 0) {
2861
+ console.log("");
2862
+ logger.info("Created files:");
2863
+ for (const file of result.filesCreated) {
2864
+ const relPath = path3.relative(rootDir, file);
2865
+ console.log(` - ${relPath}`);
2866
+ }
2867
+ }
2868
+ if (result.warnings.length > 0) {
2869
+ console.log("");
2870
+ logger.warning("Warnings:");
2871
+ for (const warning of result.warnings) {
2872
+ console.log(` - ${warning}`);
2873
+ }
2874
+ }
2875
+ if (options.noSignatures) {
2876
+ console.log("");
2877
+ logger.info("Package signatures removed - files are fully editable.");
2878
+ } else {
2879
+ console.log("");
2880
+ logger.info("Package signatures preserved - files are editable but marked as packed.");
2881
+ }
2882
+ }
2883
+ async function listPacked() {
2884
+ if (!isStandardAgentsProject2()) {
2885
+ logger.error("This does not appear to be a Standard Agents project.");
2886
+ logger.info("Make sure you have @standardagents/builder installed and an agents/ directory.");
2887
+ process.exit(1);
2888
+ }
2889
+ const rootDir = process.cwd();
2890
+ let UnpackingService;
2891
+ try {
2892
+ const builder = await import('@standardagents/builder/runtime');
2893
+ UnpackingService = builder.UnpackingService;
2894
+ if (!UnpackingService) {
2895
+ const packing = await import('@standardagents/builder');
2896
+ UnpackingService = packing.UnpackingService;
2897
+ }
2898
+ } catch (err) {
2899
+ logger.error("Failed to load unpacking service from @standardagents/builder");
2900
+ logger.info("Make sure @standardagents/builder is installed.");
2901
+ process.exit(1);
2902
+ }
2903
+ const unpackingService = new UnpackingService();
2904
+ const packages = await unpackingService.listPackages(rootDir);
2905
+ if (packages.length === 0) {
2906
+ logger.info("No packed agents found.");
2907
+ logger.info("Pack an agent with: agents pack <agent-name>");
2908
+ return;
2909
+ }
2910
+ logger.info("Discovered packed agents:\n");
2911
+ for (const pkg of packages) {
2912
+ console.log(`${pkg.packageId} (${pkg.version})`);
2913
+ console.log(` Source: ${pkg.source}`);
2914
+ console.log(` Entry: ${pkg.entryAgent}`);
2915
+ console.log(` Path: ${pkg.path}`);
2916
+ console.log("");
2917
+ }
2918
+ }
2378
2919
 
2379
2920
  // src/index.ts
2380
2921
  var program = new Command();
2381
- program.name("agents").description("CLI tool for Standard Agents / AgentBuilder").version("0.11.12");
2922
+ program.name("agents").description("CLI tool for Standard Agents / AgentBuilder").version("0.12.0");
2382
2923
  program.command("init [project-name]").description("Create a new Standard Agents project (runs create vite, then scaffold)").option("-y, --yes", "Skip prompts and use defaults").option("--template <template>", "Vite template to use", "vanilla-ts").action(init);
2383
2924
  program.command("scaffold").description("Add Standard Agents to an existing Vite project").option("--force", "Overwrite existing configuration").action(scaffold);
2384
2925
  program.command("init-chat [project-name]").description("Scaffold a frontend chat application").option("-y, --yes", "Skip prompts and use defaults").option("--framework <framework>", "Framework to use (vite or nextjs)").action(initChat);
2926
+ program.command("pack [agent-name]").description("Pack an agent with all its dependencies").option("--output <dir>", "Output directory (default: agents/packed)").option("--npm", "Generate npm-ready package structure").option("--version <version>", "Package version (default: 1.0.0)").option("--no-remove", "Keep original files after packing").option("--no-interactive", "Skip interactive item mode selector").action(pack);
2927
+ program.command("unpack [package]").description("Unpack a packed agent to the local agents directory").option("--no-signatures", "Remove package signatures (fully editable)").action(unpack);
2928
+ program.command("list-packed").description("List all discovered packed agents").action(listPacked);
2385
2929
  program.parse();
2386
2930
  //# sourceMappingURL=index.js.map
2387
2931
  //# sourceMappingURL=index.js.map