@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 +603 -59
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
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 (
|
|
143
|
-
const threadId =
|
|
144
|
-
const { messages } = await
|
|
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
|
-
- [
|
|
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,
|
|
752
|
-
| \`prefilter_llm_history\` | \`(state, messages) =>
|
|
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) =>
|
|
756
|
-
| \`after_update_message\` | \`(state, message) => void\` | Run logic after message updated |
|
|
757
|
-
| \`before_store_tool_result\` | \`(state, toolCall, result) =>
|
|
758
|
-
| \`after_tool_call_success\` | \`(state, toolCall, result) =>
|
|
759
|
-
| \`after_tool_call_failure\` | \`(state, toolCall, result) =>
|
|
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
|
|
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
|
|
768
|
-
\u251C\u2500\u2500
|
|
769
|
-
\u251C\u2500\u2500
|
|
770
|
-
\
|
|
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(
|
|
786
|
-
|
|
787
|
-
|
|
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 (
|
|
879
|
+
### Prefilter LLM History (Redact Content)
|
|
792
880
|
|
|
793
881
|
\`\`\`typescript
|
|
794
882
|
import { defineHook } from '@standardagents/builder';
|
|
795
883
|
|
|
796
|
-
export default defineHook(
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
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(
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
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(
|
|
828
|
-
|
|
829
|
-
|
|
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(
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
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
|
-
- **
|
|
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.
|
|
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.
|
|
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
|