@standardagents/cli 0.12.0-next.30cb17a → 0.12.1
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 +884 -276
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { Command } from 'commander';
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
import { fileURLToPath } from 'url';
|
|
3
|
+
import path3 from 'path';
|
|
4
|
+
import fs3 from 'fs';
|
|
6
5
|
import crypto from 'crypto';
|
|
7
6
|
import readline from 'readline';
|
|
8
7
|
import { spawn } from 'child_process';
|
|
@@ -11,6 +10,7 @@ import { parse, modify, applyEdits } from 'jsonc-parser';
|
|
|
11
10
|
import { loadFile, writeFile, generateCode } from 'magicast';
|
|
12
11
|
import { addVitePlugin } from 'magicast/helpers';
|
|
13
12
|
import net from 'net';
|
|
13
|
+
import { fileURLToPath } from 'url';
|
|
14
14
|
|
|
15
15
|
var logger = {
|
|
16
16
|
success: (message) => {
|
|
@@ -116,34 +116,48 @@ agents/
|
|
|
116
116
|
|
|
117
117
|
Files are **auto-discovered** at runtime. No manual registration needed.
|
|
118
118
|
|
|
119
|
-
##
|
|
119
|
+
## ThreadState
|
|
120
120
|
|
|
121
|
-
\`
|
|
121
|
+
\`ThreadState\` is the state object available in tools and hooks:
|
|
122
122
|
|
|
123
123
|
\`\`\`typescript
|
|
124
|
-
interface
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
124
|
+
interface ThreadState {
|
|
125
|
+
// Identity (readonly)
|
|
126
|
+
threadId: string; // Thread identifier
|
|
127
|
+
agentId: string; // Agent identifier
|
|
128
|
+
userId: string | null; // User identifier (if set)
|
|
129
|
+
createdAt: number; // Creation timestamp
|
|
130
|
+
|
|
131
|
+
// Methods
|
|
132
|
+
getMessages(options?): Promise<MessagesResult>; // Get conversation history
|
|
133
|
+
injectMessage(input): Promise<Message>; // Add message to thread
|
|
134
|
+
loadModel(name): Promise<ModelConfig>; // Load model definition
|
|
135
|
+
loadPrompt(name): Promise<PromptConfig>; // Load prompt definition
|
|
136
|
+
loadAgent(name): Promise<AgentConfig>; // Load agent definition
|
|
135
137
|
}
|
|
136
138
|
\`\`\`
|
|
137
139
|
|
|
138
140
|
Access in tools:
|
|
139
141
|
\`\`\`typescript
|
|
140
|
-
export default defineTool('...', schema, async (
|
|
141
|
-
const threadId =
|
|
142
|
-
const messages =
|
|
142
|
+
export default defineTool('...', schema, async (state, args) => {
|
|
143
|
+
const threadId = state.threadId;
|
|
144
|
+
const { messages } = await state.getMessages();
|
|
143
145
|
// ...
|
|
144
146
|
});
|
|
145
147
|
\`\`\`
|
|
146
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
|
+
|
|
147
161
|
## Quick Reference
|
|
148
162
|
|
|
149
163
|
| Function | Purpose | Directory |
|
|
@@ -178,7 +192,7 @@ Full documentation: https://docs.standardagentbuilder.com
|
|
|
178
192
|
- [Agents](https://docs.standardagentbuilder.com/core-concepts/agents)
|
|
179
193
|
- [Tools](https://docs.standardagentbuilder.com/core-concepts/tools)
|
|
180
194
|
- [Hooks](https://docs.standardagentbuilder.com/core-concepts/hooks)
|
|
181
|
-
- [
|
|
195
|
+
- [ThreadState](https://docs.standardagentbuilder.com/core-concepts/threadstate)
|
|
182
196
|
- [Thread API](https://docs.standardagentbuilder.com/core-concepts/api)
|
|
183
197
|
`;
|
|
184
198
|
|
|
@@ -289,6 +303,7 @@ Prompts define system instructions, model selection, and available tools for LLM
|
|
|
289
303
|
| \`parallelToolCalls\` | \`boolean\` | No | Allow multiple concurrent tool calls |
|
|
290
304
|
| \`toolChoice\` | \`'auto' \\| 'none' \\| 'required'\` | No | Tool calling strategy |
|
|
291
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) |
|
|
292
307
|
| \`reasoning\` | \`ReasoningConfig\` | No | Extended thinking configuration |
|
|
293
308
|
|
|
294
309
|
## Basic Example
|
|
@@ -387,6 +402,22 @@ reasoning: {
|
|
|
387
402
|
},
|
|
388
403
|
\`\`\`
|
|
389
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
|
+
|
|
390
421
|
## Best Practices
|
|
391
422
|
|
|
392
423
|
- **Write clear instructions** - Structure with headers and bullet points
|
|
@@ -416,6 +447,7 @@ Agents orchestrate conversations by defining prompts, stop conditions, and turn
|
|
|
416
447
|
| \`maxSessionTurns\` | \`number\` | No | Max total turns across both sides |
|
|
417
448
|
| \`exposeAsTool\` | \`boolean\` | No | Allow other prompts to hand off to this agent |
|
|
418
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) |
|
|
419
451
|
| \`tags\` | \`string[]\` | No | Tags for categorization and filtering |
|
|
420
452
|
|
|
421
453
|
## Side Configuration
|
|
@@ -498,6 +530,23 @@ Other prompts can then include the agent name in their \`tools\` array to enable
|
|
|
498
530
|
4. **stopOnResponse** - Ends turn when LLM returns text
|
|
499
531
|
5. **maxSessionTurns** - Ends conversation (hard limit: 250)
|
|
500
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
|
+
|
|
501
550
|
## Naming Convention
|
|
502
551
|
|
|
503
552
|
Agent names **must** end with the \`_agent\` suffix (e.g., \`support_agent\`, \`research_agent\`).
|
|
@@ -525,12 +574,12 @@ Tools extend agent capabilities beyond text generation. They allow LLMs to fetch
|
|
|
525
574
|
## Function Signature
|
|
526
575
|
|
|
527
576
|
\`\`\`typescript
|
|
528
|
-
defineTool(
|
|
577
|
+
defineTool({
|
|
529
578
|
description: string, // What the tool does (shown to LLM)
|
|
530
|
-
args
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
)
|
|
579
|
+
args?: z.ZodObject, // Input validation schema (optional)
|
|
580
|
+
execute: (state, args) => ToolResult, // Implementation
|
|
581
|
+
tenvs?: z.ZodObject, // Thread environment variables (optional)
|
|
582
|
+
})
|
|
534
583
|
\`\`\`
|
|
535
584
|
|
|
536
585
|
## Basic Example
|
|
@@ -539,20 +588,20 @@ defineTool(
|
|
|
539
588
|
import { defineTool } from '@standardagents/builder';
|
|
540
589
|
import { z } from 'zod';
|
|
541
590
|
|
|
542
|
-
export default defineTool(
|
|
543
|
-
'Search the knowledge base for articles matching a query',
|
|
544
|
-
z.object({
|
|
591
|
+
export default defineTool({
|
|
592
|
+
description: 'Search the knowledge base for articles matching a query',
|
|
593
|
+
args: z.object({
|
|
545
594
|
query: z.string().describe('Search query'),
|
|
546
595
|
limit: z.number().optional().default(10).describe('Max results'),
|
|
547
596
|
}),
|
|
548
|
-
async (
|
|
597
|
+
execute: async (state, args) => {
|
|
549
598
|
const results = await searchKB(args.query, args.limit);
|
|
550
599
|
return {
|
|
551
600
|
status: 'success',
|
|
552
601
|
result: JSON.stringify(results),
|
|
553
602
|
};
|
|
554
|
-
}
|
|
555
|
-
);
|
|
603
|
+
},
|
|
604
|
+
});
|
|
556
605
|
\`\`\`
|
|
557
606
|
|
|
558
607
|
## ToolResult Interface
|
|
@@ -562,44 +611,45 @@ export default defineTool(
|
|
|
562
611
|
| \`status\` | \`'success' \\| 'error'\` | Whether the tool succeeded |
|
|
563
612
|
| \`result\` | \`string\` | Tool output (required for success) |
|
|
564
613
|
| \`error\` | \`string\` | Error message (for error status) |
|
|
614
|
+
| \`attachments\` | \`ToolAttachment[]\` | Files to attach (images, etc.) |
|
|
565
615
|
|
|
566
|
-
##
|
|
616
|
+
## ThreadState Access
|
|
567
617
|
|
|
568
|
-
The \`
|
|
618
|
+
The \`state\` parameter provides access to:
|
|
569
619
|
|
|
570
620
|
\`\`\`typescript
|
|
571
|
-
async (
|
|
621
|
+
execute: async (state, args) => {
|
|
572
622
|
// Thread information
|
|
573
|
-
const threadId =
|
|
574
|
-
const thread =
|
|
623
|
+
const threadId = state.thread.id;
|
|
624
|
+
const thread = state.thread.instance;
|
|
575
625
|
|
|
576
626
|
// Configuration
|
|
577
|
-
const agentName =
|
|
578
|
-
const modelName =
|
|
627
|
+
const agentName = state.agent.name;
|
|
628
|
+
const modelName = state.model.name;
|
|
579
629
|
|
|
580
630
|
// Message history
|
|
581
|
-
const messages =
|
|
631
|
+
const messages = state.messages;
|
|
582
632
|
|
|
583
633
|
// Environment bindings
|
|
584
|
-
const env =
|
|
634
|
+
const env = state.env;
|
|
585
635
|
|
|
586
636
|
// Parent state (for sub-prompts)
|
|
587
|
-
const root =
|
|
637
|
+
const root = state.rootState;
|
|
588
638
|
}
|
|
589
639
|
\`\`\`
|
|
590
640
|
|
|
591
641
|
## Tool Without Arguments
|
|
592
642
|
|
|
593
643
|
\`\`\`typescript
|
|
594
|
-
export default defineTool(
|
|
595
|
-
'Get current server time',
|
|
596
|
-
async (
|
|
644
|
+
export default defineTool({
|
|
645
|
+
description: 'Get current server time',
|
|
646
|
+
execute: async (state) => {
|
|
597
647
|
return {
|
|
598
648
|
status: 'success',
|
|
599
649
|
result: new Date().toISOString(),
|
|
600
650
|
};
|
|
601
|
-
}
|
|
602
|
-
);
|
|
651
|
+
},
|
|
652
|
+
});
|
|
603
653
|
\`\`\`
|
|
604
654
|
|
|
605
655
|
## Error Handling
|
|
@@ -607,10 +657,10 @@ export default defineTool(
|
|
|
607
657
|
Return errors gracefully instead of throwing:
|
|
608
658
|
|
|
609
659
|
\`\`\`typescript
|
|
610
|
-
export default defineTool(
|
|
611
|
-
'Fetch user data',
|
|
612
|
-
z.object({ userId: z.string() }),
|
|
613
|
-
async (
|
|
660
|
+
export default defineTool({
|
|
661
|
+
description: 'Fetch user data',
|
|
662
|
+
args: z.object({ userId: z.string() }),
|
|
663
|
+
execute: async (state, args) => {
|
|
614
664
|
try {
|
|
615
665
|
const user = await fetchUser(args.userId);
|
|
616
666
|
return { status: 'success', result: JSON.stringify(user) };
|
|
@@ -620,8 +670,8 @@ export default defineTool(
|
|
|
620
670
|
error: \`Failed to fetch user: \${error.message}\`,
|
|
621
671
|
};
|
|
622
672
|
}
|
|
623
|
-
}
|
|
624
|
-
);
|
|
673
|
+
},
|
|
674
|
+
});
|
|
625
675
|
\`\`\`
|
|
626
676
|
|
|
627
677
|
## Queueing Additional Tools
|
|
@@ -631,21 +681,21 @@ Queue another tool to run after the current one:
|
|
|
631
681
|
\`\`\`typescript
|
|
632
682
|
import { queueTool } from '@standardagents/builder';
|
|
633
683
|
|
|
634
|
-
export default defineTool(
|
|
635
|
-
'Create order and send confirmation',
|
|
636
|
-
z.object({ items: z.array(z.string()) }),
|
|
637
|
-
async (
|
|
684
|
+
export default defineTool({
|
|
685
|
+
description: 'Create order and send confirmation',
|
|
686
|
+
args: z.object({ items: z.array(z.string()) }),
|
|
687
|
+
execute: async (state, args) => {
|
|
638
688
|
const order = await createOrder(args.items);
|
|
639
689
|
|
|
640
690
|
// Queue email tool to run next
|
|
641
|
-
queueTool(
|
|
691
|
+
queueTool(state, 'send_confirmation_email', {
|
|
642
692
|
orderId: order.id,
|
|
643
|
-
email:
|
|
693
|
+
email: state.thread.metadata.userEmail,
|
|
644
694
|
});
|
|
645
695
|
|
|
646
696
|
return { status: 'success', result: JSON.stringify(order) };
|
|
647
|
-
}
|
|
648
|
-
);
|
|
697
|
+
},
|
|
698
|
+
});
|
|
649
699
|
\`\`\`
|
|
650
700
|
|
|
651
701
|
## Injecting Messages
|
|
@@ -655,17 +705,61 @@ Add messages without triggering re-execution:
|
|
|
655
705
|
\`\`\`typescript
|
|
656
706
|
import { injectMessage } from '@standardagents/builder';
|
|
657
707
|
|
|
658
|
-
export default defineTool(
|
|
659
|
-
'Log audit event',
|
|
660
|
-
z.object({ event: z.string() }),
|
|
661
|
-
async (
|
|
662
|
-
await injectMessage(
|
|
708
|
+
export default defineTool({
|
|
709
|
+
description: 'Log audit event',
|
|
710
|
+
args: z.object({ event: z.string() }),
|
|
711
|
+
execute: async (state, args) => {
|
|
712
|
+
await injectMessage(state, {
|
|
663
713
|
role: 'system',
|
|
664
714
|
content: \`[AUDIT] \${args.event}\`,
|
|
665
715
|
});
|
|
666
716
|
return { status: 'success', result: 'Logged' };
|
|
667
|
-
}
|
|
668
|
-
);
|
|
717
|
+
},
|
|
718
|
+
});
|
|
719
|
+
\`\`\`
|
|
720
|
+
|
|
721
|
+
## Thread Environment Variables (tenvs)
|
|
722
|
+
|
|
723
|
+
Tools can declare required thread environment variables:
|
|
724
|
+
|
|
725
|
+
\`\`\`typescript
|
|
726
|
+
export default defineTool({
|
|
727
|
+
description: 'Search uploaded documents',
|
|
728
|
+
args: z.object({ query: z.string() }),
|
|
729
|
+
execute: async (state, args) => {
|
|
730
|
+
const vectorStoreId = state.tenvs.vectorStoreId;
|
|
731
|
+
const results = await searchVectorStore(vectorStoreId, args.query);
|
|
732
|
+
return { status: 'success', result: JSON.stringify(results) };
|
|
733
|
+
},
|
|
734
|
+
tenvs: z.object({
|
|
735
|
+
vectorStoreId: z.string().describe('OpenAI Vector Store ID'),
|
|
736
|
+
}),
|
|
737
|
+
});
|
|
738
|
+
\`\`\`
|
|
739
|
+
|
|
740
|
+
## Returning Attachments
|
|
741
|
+
|
|
742
|
+
Tools can return file attachments (e.g., generated images):
|
|
743
|
+
|
|
744
|
+
\`\`\`typescript
|
|
745
|
+
export default defineTool({
|
|
746
|
+
description: 'Generate a chart from data',
|
|
747
|
+
args: z.object({ data: z.array(z.number()) }),
|
|
748
|
+
execute: async (state, args) => {
|
|
749
|
+
const chartImage = await generateChart(args.data);
|
|
750
|
+
return {
|
|
751
|
+
status: 'success',
|
|
752
|
+
result: 'Chart generated successfully',
|
|
753
|
+
attachments: [{
|
|
754
|
+
name: 'chart.png',
|
|
755
|
+
mimeType: 'image/png',
|
|
756
|
+
data: chartImage.base64,
|
|
757
|
+
width: 800,
|
|
758
|
+
height: 600,
|
|
759
|
+
}],
|
|
760
|
+
};
|
|
761
|
+
},
|
|
762
|
+
});
|
|
669
763
|
\`\`\`
|
|
670
764
|
|
|
671
765
|
## Best Practices
|
|
@@ -675,7 +769,7 @@ export default defineTool(
|
|
|
675
769
|
- **Handle errors gracefully** - return error status, don't throw
|
|
676
770
|
- **Use snake_case** for file names (\`search_knowledge_base.ts\`)
|
|
677
771
|
- **Keep tools focused** - one task per tool
|
|
678
|
-
- **Use \`
|
|
772
|
+
- **Use \`state.rootState\`** when queueing from sub-prompts
|
|
679
773
|
|
|
680
774
|
## Supported Zod Types
|
|
681
775
|
|
|
@@ -701,31 +795,69 @@ Hooks intercept and modify agent execution at specific lifecycle points.
|
|
|
701
795
|
|
|
702
796
|
| Hook | Signature | Purpose |
|
|
703
797
|
|------|-----------|---------|
|
|
704
|
-
| \`filter_messages\` | \`(state,
|
|
705
|
-
| \`prefilter_llm_history\` | \`(state, messages) =>
|
|
706
|
-
| \`before_create_message\` | \`(state, message) => Message\` | Modify message before database insert |
|
|
707
|
-
| \`after_create_message\` | \`(state, message) => void\` | Run logic after message created |
|
|
708
|
-
| \`before_update_message\` | \`(state, id, updates) =>
|
|
709
|
-
| \`after_update_message\` | \`(state, message) => void\` | Run logic after message updated |
|
|
710
|
-
| \`before_store_tool_result\` | \`(state, toolCall, result) =>
|
|
711
|
-
| \`after_tool_call_success\` | \`(state, toolCall, result) =>
|
|
712
|
-
| \`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
|
|
713
850
|
|
|
714
851
|
## File Naming
|
|
715
852
|
|
|
716
|
-
Hook files
|
|
853
|
+
Hook files can use **any name** \u2014 the hook type and ID are defined inside the file:
|
|
717
854
|
|
|
718
855
|
\`\`\`
|
|
719
856
|
agents/hooks/
|
|
720
|
-
\u251C\u2500\u2500
|
|
721
|
-
\u251C\u2500\u2500
|
|
722
|
-
\u251C\u2500\u2500
|
|
723
|
-
\
|
|
724
|
-
\u251C\u2500\u2500 before_update_message.ts
|
|
725
|
-
\u251C\u2500\u2500 after_update_message.ts
|
|
726
|
-
\u251C\u2500\u2500 before_store_tool_result.ts
|
|
727
|
-
\u251C\u2500\u2500 after_tool_call_success.ts
|
|
728
|
-
\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
|
|
729
861
|
\`\`\`
|
|
730
862
|
|
|
731
863
|
## Examples
|
|
@@ -735,23 +867,31 @@ agents/hooks/
|
|
|
735
867
|
\`\`\`typescript
|
|
736
868
|
import { defineHook } from '@standardagents/builder';
|
|
737
869
|
|
|
738
|
-
export default defineHook(
|
|
739
|
-
|
|
740
|
-
|
|
870
|
+
export default defineHook({
|
|
871
|
+
hook: 'filter_messages',
|
|
872
|
+
id: 'limit_to_20',
|
|
873
|
+
execute: async (state, messages) => {
|
|
874
|
+
return messages.slice(-20);
|
|
875
|
+
}
|
|
741
876
|
});
|
|
742
877
|
\`\`\`
|
|
743
878
|
|
|
744
|
-
### Prefilter LLM History (
|
|
879
|
+
### Prefilter LLM History (Redact Content)
|
|
745
880
|
|
|
746
881
|
\`\`\`typescript
|
|
747
882
|
import { defineHook } from '@standardagents/builder';
|
|
748
883
|
|
|
749
|
-
export default defineHook(
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
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
|
+
}
|
|
755
895
|
});
|
|
756
896
|
\`\`\`
|
|
757
897
|
|
|
@@ -760,15 +900,34 @@ export default defineHook('prefilter_llm_history', async (state, messages) => {
|
|
|
760
900
|
\`\`\`typescript
|
|
761
901
|
import { defineHook } from '@standardagents/builder';
|
|
762
902
|
|
|
763
|
-
export default defineHook(
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
}
|
|
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
|
+
}
|
|
772
931
|
});
|
|
773
932
|
\`\`\`
|
|
774
933
|
|
|
@@ -777,9 +936,13 @@ export default defineHook('before_create_message', async (state, message) => {
|
|
|
777
936
|
\`\`\`typescript
|
|
778
937
|
import { defineHook } from '@standardagents/builder';
|
|
779
938
|
|
|
780
|
-
export default defineHook(
|
|
781
|
-
|
|
782
|
-
|
|
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
|
+
}
|
|
783
946
|
});
|
|
784
947
|
\`\`\`
|
|
785
948
|
|
|
@@ -788,15 +951,18 @@ export default defineHook('after_tool_call_success', async (state, toolCall, res
|
|
|
788
951
|
\`\`\`typescript
|
|
789
952
|
import { defineHook } from '@standardagents/builder';
|
|
790
953
|
|
|
791
|
-
export default defineHook(
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
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
|
|
798
965
|
}
|
|
799
|
-
return result; // Return original error
|
|
800
966
|
});
|
|
801
967
|
\`\`\`
|
|
802
968
|
|
|
@@ -808,8 +974,8 @@ export default defineHook('after_tool_call_failure', async (state, toolCall, res
|
|
|
808
974
|
- \`before_create_message\`
|
|
809
975
|
- \`before_update_message\`
|
|
810
976
|
- \`before_store_tool_result\`
|
|
811
|
-
- \`after_tool_call_success\`
|
|
812
|
-
- \`after_tool_call_failure\`
|
|
977
|
+
- \`after_tool_call_success\` (return modified result or null)
|
|
978
|
+
- \`after_tool_call_failure\` (return modified result or null)
|
|
813
979
|
|
|
814
980
|
**Event hooks** (side effects only):
|
|
815
981
|
- \`after_create_message\`
|
|
@@ -818,8 +984,9 @@ export default defineHook('after_tool_call_failure', async (state, toolCall, res
|
|
|
818
984
|
## Best Practices
|
|
819
985
|
|
|
820
986
|
- **Keep hooks fast** - target <100ms execution
|
|
821
|
-
- **Wrap in try-catch** - hooks continue on error
|
|
822
|
-
- **
|
|
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
|
|
823
990
|
- **Document purpose** with clear comments
|
|
824
991
|
- **Use for cross-cutting concerns** - logging, redaction, enrichment
|
|
825
992
|
|
|
@@ -831,7 +998,7 @@ Full reference: https://docs.standardagentbuilder.com/api-reference/define/hook
|
|
|
831
998
|
// src/templates/api.ts
|
|
832
999
|
var API_CLAUDE_MD = `# Thread-Specific API Endpoints
|
|
833
1000
|
|
|
834
|
-
Define custom API endpoints that operate on specific threads with access to the thread's
|
|
1001
|
+
Define custom API endpoints that operate on specific threads with access to the thread's ThreadState.
|
|
835
1002
|
|
|
836
1003
|
## File-Based Routing
|
|
837
1004
|
|
|
@@ -848,15 +1015,14 @@ Define custom API endpoints that operate on specific threads with access to the
|
|
|
848
1015
|
|
|
849
1016
|
\`\`\`typescript
|
|
850
1017
|
// agents/api/status.get.ts -> GET /api/threads/:id/status
|
|
851
|
-
import { defineThreadEndpoint } from '@standardagents/
|
|
1018
|
+
import { defineThreadEndpoint } from '@standardagents/spec';
|
|
852
1019
|
|
|
853
|
-
export default defineThreadEndpoint(async (
|
|
854
|
-
const messages = await
|
|
855
|
-
return
|
|
856
|
-
|
|
1020
|
+
export default defineThreadEndpoint(async (req, state) => {
|
|
1021
|
+
const { messages, total } = await state.getMessages();
|
|
1022
|
+
return Response.json({
|
|
1023
|
+
threadId: state.threadId,
|
|
1024
|
+
messageCount: total,
|
|
857
1025
|
status: 'active',
|
|
858
|
-
}), {
|
|
859
|
-
headers: { 'Content-Type': 'application/json' },
|
|
860
1026
|
});
|
|
861
1027
|
});
|
|
862
1028
|
\`\`\`
|
|
@@ -865,30 +1031,40 @@ export default defineThreadEndpoint(async (thread, request, env) => {
|
|
|
865
1031
|
|
|
866
1032
|
| Parameter | Type | Description |
|
|
867
1033
|
|-----------|------|-------------|
|
|
868
|
-
| \`
|
|
869
|
-
| \`
|
|
870
|
-
|
|
1034
|
+
| \`req\` | \`Request\` | The incoming HTTP request |
|
|
1035
|
+
| \`state\` | \`ThreadState\` | Thread state with messages, identity, file system, etc. |
|
|
1036
|
+
|
|
1037
|
+
Note: \`state.execution\` is always \`null\` in endpoints since the thread is at rest.
|
|
871
1038
|
|
|
872
|
-
##
|
|
1039
|
+
## ThreadState Methods
|
|
873
1040
|
|
|
874
|
-
Access thread data through the
|
|
1041
|
+
Access thread data through the state object:
|
|
875
1042
|
|
|
876
1043
|
\`\`\`typescript
|
|
877
|
-
|
|
1044
|
+
import { defineThreadEndpoint } from '@standardagents/spec';
|
|
1045
|
+
|
|
1046
|
+
export default defineThreadEndpoint(async (req, state) => {
|
|
1047
|
+
// Thread identity
|
|
1048
|
+
console.log('Thread ID:', state.threadId);
|
|
1049
|
+
console.log('Agent ID:', state.agentId);
|
|
1050
|
+
console.log('User ID:', state.userId);
|
|
1051
|
+
|
|
878
1052
|
// Message operations
|
|
879
|
-
const messages = await
|
|
880
|
-
|
|
1053
|
+
const { messages, total, hasMore } = await state.getMessages({
|
|
1054
|
+
limit: 100,
|
|
1055
|
+
offset: 0,
|
|
1056
|
+
order: 'desc',
|
|
1057
|
+
});
|
|
881
1058
|
|
|
882
|
-
//
|
|
883
|
-
const
|
|
1059
|
+
// File system operations
|
|
1060
|
+
const files = await state.findFiles('**/*.json');
|
|
1061
|
+
const data = await state.readFile('/data/config.json');
|
|
884
1062
|
|
|
885
|
-
//
|
|
886
|
-
await
|
|
1063
|
+
// Resource loading
|
|
1064
|
+
const agent = await state.loadAgent('my-agent');
|
|
1065
|
+
const prompt = await state.loadPrompt('my-prompt');
|
|
887
1066
|
|
|
888
|
-
|
|
889
|
-
const result = thread.ctx.storage.sql.exec(\`
|
|
890
|
-
SELECT * FROM messages WHERE role = 'user'
|
|
891
|
-
\`);
|
|
1067
|
+
return Response.json({ messages, total });
|
|
892
1068
|
});
|
|
893
1069
|
\`\`\`
|
|
894
1070
|
|
|
@@ -896,13 +1072,13 @@ export default defineThreadEndpoint(async (thread, request, env) => {
|
|
|
896
1072
|
|
|
897
1073
|
\`\`\`typescript
|
|
898
1074
|
// agents/api/export.post.ts -> POST /api/threads/:id/export
|
|
899
|
-
import { defineThreadEndpoint } from '@standardagents/
|
|
1075
|
+
import { defineThreadEndpoint } from '@standardagents/spec';
|
|
900
1076
|
|
|
901
|
-
export default defineThreadEndpoint(async (
|
|
902
|
-
const body = await
|
|
1077
|
+
export default defineThreadEndpoint(async (req, state) => {
|
|
1078
|
+
const body = await req.json();
|
|
903
1079
|
const { format = 'json' } = body;
|
|
904
1080
|
|
|
905
|
-
const messages = await
|
|
1081
|
+
const { messages } = await state.getMessages();
|
|
906
1082
|
|
|
907
1083
|
if (format === 'csv') {
|
|
908
1084
|
const csv = messages.map(m => \`\${m.role},\${m.content}\`).join('\\n');
|
|
@@ -911,9 +1087,7 @@ export default defineThreadEndpoint(async (thread, request, env) => {
|
|
|
911
1087
|
});
|
|
912
1088
|
}
|
|
913
1089
|
|
|
914
|
-
return
|
|
915
|
-
headers: { 'Content-Type': 'application/json' },
|
|
916
|
-
});
|
|
1090
|
+
return Response.json(messages);
|
|
917
1091
|
});
|
|
918
1092
|
\`\`\`
|
|
919
1093
|
|
|
@@ -933,35 +1107,38 @@ agents/api/
|
|
|
933
1107
|
## Error Handling
|
|
934
1108
|
|
|
935
1109
|
\`\`\`typescript
|
|
936
|
-
|
|
1110
|
+
import { defineThreadEndpoint } from '@standardagents/spec';
|
|
1111
|
+
|
|
1112
|
+
export default defineThreadEndpoint(async (req, state) => {
|
|
937
1113
|
try {
|
|
938
1114
|
const data = await riskyOperation();
|
|
939
|
-
return
|
|
940
|
-
headers: { 'Content-Type': 'application/json' },
|
|
941
|
-
});
|
|
1115
|
+
return Response.json(data);
|
|
942
1116
|
} catch (error) {
|
|
943
|
-
return
|
|
944
|
-
error: error.message,
|
|
945
|
-
}), {
|
|
946
|
-
status: 500,
|
|
947
|
-
headers: { 'Content-Type': 'application/json' },
|
|
948
|
-
});
|
|
1117
|
+
return Response.json({ error: error.message }, { status: 500 });
|
|
949
1118
|
}
|
|
950
1119
|
});
|
|
951
1120
|
\`\`\`
|
|
952
1121
|
|
|
953
|
-
##
|
|
1122
|
+
## File System Operations
|
|
954
1123
|
|
|
955
1124
|
\`\`\`typescript
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
1125
|
+
import { defineThreadEndpoint } from '@standardagents/spec';
|
|
1126
|
+
|
|
1127
|
+
export default defineThreadEndpoint(async (req, state) => {
|
|
1128
|
+
// Read files
|
|
1129
|
+
const content = await state.readFile('/data/file.txt');
|
|
1130
|
+
|
|
1131
|
+
// Write files
|
|
1132
|
+
await state.writeFile('/output/result.json', JSON.stringify(data), 'application/json');
|
|
960
1133
|
|
|
961
|
-
|
|
962
|
-
|
|
1134
|
+
// List directory
|
|
1135
|
+
const { entries } = await state.readdirFile('/data');
|
|
963
1136
|
|
|
964
|
-
|
|
1137
|
+
// Search files
|
|
1138
|
+
const matches = await state.grepFiles('pattern');
|
|
1139
|
+
const paths = await state.findFiles('**/*.ts');
|
|
1140
|
+
|
|
1141
|
+
return Response.json({ success: true });
|
|
965
1142
|
});
|
|
966
1143
|
\`\`\`
|
|
967
1144
|
|
|
@@ -972,6 +1149,7 @@ export default defineThreadEndpoint(async (thread, request, env) => {
|
|
|
972
1149
|
- **Validate input data** - check request body before processing
|
|
973
1150
|
- **Use descriptive file names** - \`export.post.ts\` not \`ep1.ts\`
|
|
974
1151
|
- **Return proper status codes** - 200, 400, 404, 500
|
|
1152
|
+
- **Import from spec** - use \`@standardagents/spec\` for \`defineThreadEndpoint\`
|
|
975
1153
|
|
|
976
1154
|
## Documentation
|
|
977
1155
|
|
|
@@ -979,17 +1157,19 @@ Full reference: https://docs.standardagentbuilder.com/core-concepts/api
|
|
|
979
1157
|
`;
|
|
980
1158
|
|
|
981
1159
|
// src/commands/scaffold.ts
|
|
982
|
-
var WRANGLER_TEMPLATE = (name) =>
|
|
1160
|
+
var WRANGLER_TEMPLATE = (name) => {
|
|
1161
|
+
const today = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
1162
|
+
return `{
|
|
983
1163
|
"$schema": "node_modules/wrangler/config-schema.json",
|
|
984
1164
|
"name": "${name}",
|
|
985
1165
|
"main": "worker/index.ts",
|
|
986
|
-
"compatibility_date": "
|
|
1166
|
+
"compatibility_date": "${today}",
|
|
987
1167
|
"compatibility_flags": ["nodejs_compat"],
|
|
988
1168
|
"observability": {
|
|
989
1169
|
"enabled": true
|
|
990
1170
|
},
|
|
991
1171
|
"assets": {
|
|
992
|
-
"directory": "dist",
|
|
1172
|
+
"directory": "dist/client",
|
|
993
1173
|
"not_found_handling": "single-page-application",
|
|
994
1174
|
"binding": "ASSETS",
|
|
995
1175
|
"run_worker_first": ["/**"]
|
|
@@ -1018,6 +1198,7 @@ var WRANGLER_TEMPLATE = (name) => `{
|
|
|
1018
1198
|
]
|
|
1019
1199
|
}
|
|
1020
1200
|
`;
|
|
1201
|
+
};
|
|
1021
1202
|
var THREAD_TS = `import { DurableThread } from 'virtual:@standardagents/builder'
|
|
1022
1203
|
|
|
1023
1204
|
export default class Thread extends DurableThread {}
|
|
@@ -1043,9 +1224,9 @@ function getProjectName(cwd) {
|
|
|
1043
1224
|
const packageJsonPath = path3.join(cwd, "package.json");
|
|
1044
1225
|
if (fs3.existsSync(packageJsonPath)) {
|
|
1045
1226
|
try {
|
|
1046
|
-
const
|
|
1047
|
-
if (
|
|
1048
|
-
return
|
|
1227
|
+
const pkg = JSON.parse(fs3.readFileSync(packageJsonPath, "utf-8"));
|
|
1228
|
+
if (pkg.name) {
|
|
1229
|
+
return pkg.name.replace(/^@[^/]+\//, "");
|
|
1049
1230
|
}
|
|
1050
1231
|
} catch {
|
|
1051
1232
|
}
|
|
@@ -1082,14 +1263,6 @@ async function modifyViteConfig(configPath, force) {
|
|
|
1082
1263
|
logger.info("Vite config already includes Standard Agents plugins");
|
|
1083
1264
|
return true;
|
|
1084
1265
|
}
|
|
1085
|
-
if (!hasCloudflare || force) {
|
|
1086
|
-
addVitePlugin(mod, {
|
|
1087
|
-
from: "@cloudflare/vite-plugin",
|
|
1088
|
-
imported: "cloudflare",
|
|
1089
|
-
constructor: "cloudflare"
|
|
1090
|
-
});
|
|
1091
|
-
logger.success("Added cloudflare plugin to vite.config");
|
|
1092
|
-
}
|
|
1093
1266
|
if (!hasAgentBuilder || force) {
|
|
1094
1267
|
addVitePlugin(mod, {
|
|
1095
1268
|
from: "@standardagents/builder",
|
|
@@ -1099,6 +1272,14 @@ async function modifyViteConfig(configPath, force) {
|
|
|
1099
1272
|
});
|
|
1100
1273
|
logger.success("Added agentbuilder plugin to vite.config");
|
|
1101
1274
|
}
|
|
1275
|
+
if (!hasCloudflare || force) {
|
|
1276
|
+
addVitePlugin(mod, {
|
|
1277
|
+
from: "@cloudflare/vite-plugin",
|
|
1278
|
+
imported: "cloudflare",
|
|
1279
|
+
constructor: "cloudflare"
|
|
1280
|
+
});
|
|
1281
|
+
logger.success("Added cloudflare plugin to vite.config");
|
|
1282
|
+
}
|
|
1102
1283
|
await writeFile(mod, configPath);
|
|
1103
1284
|
return true;
|
|
1104
1285
|
} catch (error) {
|
|
@@ -1106,10 +1287,10 @@ async function modifyViteConfig(configPath, force) {
|
|
|
1106
1287
|
logger.log("");
|
|
1107
1288
|
logger.log("Please manually add the following to your vite.config.ts:");
|
|
1108
1289
|
logger.log("");
|
|
1109
|
-
logger.log(` import { cloudflare } from '@cloudflare/vite-plugin'`);
|
|
1110
1290
|
logger.log(` import { agentbuilder } from '@standardagents/builder'`);
|
|
1291
|
+
logger.log(` import { cloudflare } from '@cloudflare/vite-plugin'`);
|
|
1111
1292
|
logger.log("");
|
|
1112
|
-
logger.log(` plugins: [
|
|
1293
|
+
logger.log(` plugins: [agentbuilder({ mountPoint: '/' }), cloudflare()]`);
|
|
1113
1294
|
logger.log("");
|
|
1114
1295
|
return false;
|
|
1115
1296
|
}
|
|
@@ -1158,7 +1339,7 @@ function createOrUpdateWranglerConfig(cwd, projectName, force) {
|
|
|
1158
1339
|
}
|
|
1159
1340
|
if (!config.assets) {
|
|
1160
1341
|
const edits = modify(result, ["assets"], {
|
|
1161
|
-
directory: "dist",
|
|
1342
|
+
directory: "dist/client",
|
|
1162
1343
|
not_found_handling: "single-page-application",
|
|
1163
1344
|
binding: "ASSETS",
|
|
1164
1345
|
run_worker_first: ["/**"]
|
|
@@ -1430,15 +1611,15 @@ async function prompt(question) {
|
|
|
1430
1611
|
input: process.stdin,
|
|
1431
1612
|
output: process.stdout
|
|
1432
1613
|
});
|
|
1433
|
-
return new Promise((
|
|
1614
|
+
return new Promise((resolve) => {
|
|
1434
1615
|
rl.question(question, (answer) => {
|
|
1435
1616
|
rl.close();
|
|
1436
|
-
|
|
1617
|
+
resolve(answer.trim());
|
|
1437
1618
|
});
|
|
1438
1619
|
});
|
|
1439
1620
|
}
|
|
1440
1621
|
async function promptPassword(question) {
|
|
1441
|
-
return new Promise((
|
|
1622
|
+
return new Promise((resolve) => {
|
|
1442
1623
|
const stdin = process.stdin;
|
|
1443
1624
|
const stdout = process.stdout;
|
|
1444
1625
|
stdout.write(question);
|
|
@@ -1459,7 +1640,7 @@ async function promptPassword(question) {
|
|
|
1459
1640
|
stdin.pause();
|
|
1460
1641
|
stdin.removeListener("data", onData);
|
|
1461
1642
|
stdout.write("\n");
|
|
1462
|
-
|
|
1643
|
+
resolve(password);
|
|
1463
1644
|
break;
|
|
1464
1645
|
case "":
|
|
1465
1646
|
stdout.write("\n");
|
|
@@ -1485,7 +1666,7 @@ async function promptPassword(question) {
|
|
|
1485
1666
|
});
|
|
1486
1667
|
}
|
|
1487
1668
|
function runCommand(command, args, cwd) {
|
|
1488
|
-
return new Promise((
|
|
1669
|
+
return new Promise((resolve, reject) => {
|
|
1489
1670
|
const child = spawn(command, args, {
|
|
1490
1671
|
cwd,
|
|
1491
1672
|
stdio: "inherit",
|
|
@@ -1493,7 +1674,7 @@ function runCommand(command, args, cwd) {
|
|
|
1493
1674
|
});
|
|
1494
1675
|
child.on("close", (code) => {
|
|
1495
1676
|
if (code === 0) {
|
|
1496
|
-
|
|
1677
|
+
resolve();
|
|
1497
1678
|
} else {
|
|
1498
1679
|
reject(new Error(`Command failed with exit code ${code}`));
|
|
1499
1680
|
}
|
|
@@ -1517,25 +1698,16 @@ function detectPackageManager() {
|
|
|
1517
1698
|
if (fs3.existsSync("package-lock.json")) return "npm";
|
|
1518
1699
|
return "npm";
|
|
1519
1700
|
}
|
|
1520
|
-
function
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
const pkgPath = path3.resolve(__dirname2, "../../package.json");
|
|
1524
|
-
const pkg2 = JSON.parse(fs3.readFileSync(pkgPath, "utf-8"));
|
|
1525
|
-
const version = pkg2.version;
|
|
1526
|
-
const prereleaseMatch = version.match(/-([a-z]+)\./i);
|
|
1527
|
-
if (prereleaseMatch) {
|
|
1528
|
-
return `@${prereleaseMatch[1]}`;
|
|
1529
|
-
}
|
|
1530
|
-
return `@^${version}`;
|
|
1531
|
-
} catch {
|
|
1532
|
-
return "";
|
|
1701
|
+
function getPackageVersion() {
|
|
1702
|
+
if (process.env.STANDARDAGENTS_WORKSPACE === "1") {
|
|
1703
|
+
return "workspace:*";
|
|
1533
1704
|
}
|
|
1705
|
+
return "0.12.1";
|
|
1534
1706
|
}
|
|
1535
1707
|
async function selectPackageManager(detected) {
|
|
1536
1708
|
const options = ["npm", "pnpm", "yarn", "bun"];
|
|
1537
1709
|
const detectedIndex = options.indexOf(detected);
|
|
1538
|
-
return new Promise((
|
|
1710
|
+
return new Promise((resolve) => {
|
|
1539
1711
|
const stdin = process.stdin;
|
|
1540
1712
|
const stdout = process.stdout;
|
|
1541
1713
|
let selectedIndex = detectedIndex;
|
|
@@ -1581,7 +1753,7 @@ async function selectPackageManager(detected) {
|
|
|
1581
1753
|
renderOptions();
|
|
1582
1754
|
} else if (key === "\r" || key === "\n") {
|
|
1583
1755
|
cleanup();
|
|
1584
|
-
|
|
1756
|
+
resolve(options[selectedIndex]);
|
|
1585
1757
|
} else if (key === "") {
|
|
1586
1758
|
cleanup();
|
|
1587
1759
|
stdout.write("\n");
|
|
@@ -1667,31 +1839,7 @@ export default defineConfig({
|
|
|
1667
1839
|
}
|
|
1668
1840
|
}
|
|
1669
1841
|
logger.log("");
|
|
1670
|
-
logger.info("Step 2:
|
|
1671
|
-
logger.log("");
|
|
1672
|
-
try {
|
|
1673
|
-
const installCmd = pm === "npm" ? "install" : "add";
|
|
1674
|
-
const devFlag = pm === "npm" ? "--save-dev" : "-D";
|
|
1675
|
-
const builderVersion = getBuilderPackageVersion();
|
|
1676
|
-
await runCommand(pm, [
|
|
1677
|
-
installCmd,
|
|
1678
|
-
devFlag,
|
|
1679
|
-
"@cloudflare/vite-plugin",
|
|
1680
|
-
`@standardagents/builder${builderVersion}`,
|
|
1681
|
-
"wrangler",
|
|
1682
|
-
"zod"
|
|
1683
|
-
], projectPath);
|
|
1684
|
-
} catch (error) {
|
|
1685
|
-
logger.error("Failed to install dependencies");
|
|
1686
|
-
process.exit(1);
|
|
1687
|
-
}
|
|
1688
|
-
logger.log("");
|
|
1689
|
-
logger.info("Step 3: Configuring Standard Agents...");
|
|
1690
|
-
logger.log("");
|
|
1691
|
-
process.chdir(projectPath);
|
|
1692
|
-
await scaffold({ force: true });
|
|
1693
|
-
logger.log("");
|
|
1694
|
-
logger.info("Step 4: Configuring environment variables...");
|
|
1842
|
+
logger.info("Step 2: Configuring environment variables...");
|
|
1695
1843
|
logger.log("");
|
|
1696
1844
|
const encryptionKey = crypto.randomBytes(32).toString("hex");
|
|
1697
1845
|
let openrouterKey = "";
|
|
@@ -1726,6 +1874,44 @@ export default defineConfig({
|
|
|
1726
1874
|
if (!adminPassword) {
|
|
1727
1875
|
adminPassword = "admin";
|
|
1728
1876
|
}
|
|
1877
|
+
logger.log("");
|
|
1878
|
+
logger.info("Step 3: Installing Standard Agents dependencies...");
|
|
1879
|
+
logger.log("");
|
|
1880
|
+
try {
|
|
1881
|
+
const installCmd = pm === "npm" ? "install" : "add";
|
|
1882
|
+
const devFlag = pm === "npm" ? "--save-dev" : "-D";
|
|
1883
|
+
const packageVersion = getPackageVersion();
|
|
1884
|
+
await runCommand(pm, [
|
|
1885
|
+
installCmd,
|
|
1886
|
+
devFlag,
|
|
1887
|
+
"@cloudflare/vite-plugin",
|
|
1888
|
+
"wrangler"
|
|
1889
|
+
], projectPath);
|
|
1890
|
+
const deps = [
|
|
1891
|
+
`@standardagents/builder@${packageVersion}`,
|
|
1892
|
+
`@standardagents/spec@${packageVersion}`,
|
|
1893
|
+
`@standardagents/sip@${packageVersion}`,
|
|
1894
|
+
"zod"
|
|
1895
|
+
];
|
|
1896
|
+
if (openaiKey) {
|
|
1897
|
+
deps.push(`@standardagents/openai@${packageVersion}`);
|
|
1898
|
+
}
|
|
1899
|
+
if (openrouterKey) {
|
|
1900
|
+
deps.push(`@standardagents/openrouter@${packageVersion}`);
|
|
1901
|
+
}
|
|
1902
|
+
await runCommand(pm, [installCmd, ...deps], projectPath);
|
|
1903
|
+
} catch (error) {
|
|
1904
|
+
logger.error("Failed to install dependencies");
|
|
1905
|
+
process.exit(1);
|
|
1906
|
+
}
|
|
1907
|
+
logger.log("");
|
|
1908
|
+
logger.info("Step 4: Configuring Standard Agents...");
|
|
1909
|
+
logger.log("");
|
|
1910
|
+
process.chdir(projectPath);
|
|
1911
|
+
await scaffold({ force: true });
|
|
1912
|
+
logger.log("");
|
|
1913
|
+
logger.info("Writing environment configuration...");
|
|
1914
|
+
logger.log("");
|
|
1729
1915
|
const devVarsLines = [
|
|
1730
1916
|
"# Standard Agents Environment Variables",
|
|
1731
1917
|
"# This file contains secrets for local development only",
|
|
@@ -1782,10 +1968,10 @@ export default defineConfig({
|
|
|
1782
1968
|
}
|
|
1783
1969
|
function getReactPackageVersion() {
|
|
1784
1970
|
try {
|
|
1785
|
-
const
|
|
1786
|
-
const pkgPath = path3.resolve(
|
|
1787
|
-
const
|
|
1788
|
-
const version =
|
|
1971
|
+
const __dirname = path3.dirname(fileURLToPath(import.meta.url));
|
|
1972
|
+
const pkgPath = path3.resolve(__dirname, "../package.json");
|
|
1973
|
+
const pkg = JSON.parse(fs3.readFileSync(pkgPath, "utf-8"));
|
|
1974
|
+
const version = pkg.version;
|
|
1789
1975
|
const prereleaseMatch = version.match(/-([a-z]+)\./i);
|
|
1790
1976
|
if (prereleaseMatch) {
|
|
1791
1977
|
return prereleaseMatch[1];
|
|
@@ -1796,23 +1982,23 @@ function getReactPackageVersion() {
|
|
|
1796
1982
|
}
|
|
1797
1983
|
}
|
|
1798
1984
|
function getChatSourceDir() {
|
|
1799
|
-
const
|
|
1800
|
-
return path3.resolve(
|
|
1985
|
+
const __dirname = path3.dirname(fileURLToPath(import.meta.url));
|
|
1986
|
+
return path3.resolve(__dirname, "../chat");
|
|
1801
1987
|
}
|
|
1802
1988
|
async function prompt2(question) {
|
|
1803
1989
|
const rl = readline.createInterface({
|
|
1804
1990
|
input: process.stdin,
|
|
1805
1991
|
output: process.stdout
|
|
1806
1992
|
});
|
|
1807
|
-
return new Promise((
|
|
1993
|
+
return new Promise((resolve) => {
|
|
1808
1994
|
rl.question(question, (answer) => {
|
|
1809
1995
|
rl.close();
|
|
1810
|
-
|
|
1996
|
+
resolve(answer.trim());
|
|
1811
1997
|
});
|
|
1812
1998
|
});
|
|
1813
1999
|
}
|
|
1814
2000
|
function runCommand2(command, args, cwd) {
|
|
1815
|
-
return new Promise((
|
|
2001
|
+
return new Promise((resolve, reject) => {
|
|
1816
2002
|
const child = spawn(command, args, {
|
|
1817
2003
|
cwd,
|
|
1818
2004
|
stdio: "inherit",
|
|
@@ -1820,7 +2006,7 @@ function runCommand2(command, args, cwd) {
|
|
|
1820
2006
|
});
|
|
1821
2007
|
child.on("close", (code) => {
|
|
1822
2008
|
if (code === 0) {
|
|
1823
|
-
|
|
2009
|
+
resolve();
|
|
1824
2010
|
} else {
|
|
1825
2011
|
reject(new Error(`Command failed with exit code ${code}`));
|
|
1826
2012
|
}
|
|
@@ -1844,7 +2030,7 @@ function detectPackageManager2() {
|
|
|
1844
2030
|
async function selectPackageManager2(detected) {
|
|
1845
2031
|
const options = ["npm", "pnpm", "yarn", "bun"];
|
|
1846
2032
|
const detectedIndex = options.indexOf(detected);
|
|
1847
|
-
return new Promise((
|
|
2033
|
+
return new Promise((resolve) => {
|
|
1848
2034
|
const stdin = process.stdin;
|
|
1849
2035
|
const stdout = process.stdout;
|
|
1850
2036
|
let selectedIndex = detectedIndex;
|
|
@@ -1890,7 +2076,7 @@ async function selectPackageManager2(detected) {
|
|
|
1890
2076
|
renderOptions();
|
|
1891
2077
|
} else if (key === "\r" || key === "\n") {
|
|
1892
2078
|
cleanup();
|
|
1893
|
-
|
|
2079
|
+
resolve(options[selectedIndex]);
|
|
1894
2080
|
} else if (key === "") {
|
|
1895
2081
|
cleanup();
|
|
1896
2082
|
stdout.write("\n");
|
|
@@ -1905,7 +2091,7 @@ async function selectFramework() {
|
|
|
1905
2091
|
{ value: "vite", label: "Vite (React + TypeScript)" },
|
|
1906
2092
|
{ value: "nextjs", label: "Next.js (App Router)" }
|
|
1907
2093
|
];
|
|
1908
|
-
return new Promise((
|
|
2094
|
+
return new Promise((resolve) => {
|
|
1909
2095
|
const stdin = process.stdin;
|
|
1910
2096
|
const stdout = process.stdout;
|
|
1911
2097
|
let selectedIndex = 0;
|
|
@@ -1949,7 +2135,7 @@ async function selectFramework() {
|
|
|
1949
2135
|
renderOptions();
|
|
1950
2136
|
} else if (key === "\r" || key === "\n") {
|
|
1951
2137
|
cleanup();
|
|
1952
|
-
|
|
2138
|
+
resolve(options[selectedIndex].value);
|
|
1953
2139
|
} else if (key === "") {
|
|
1954
2140
|
cleanup();
|
|
1955
2141
|
stdout.write("\n");
|
|
@@ -1969,20 +2155,20 @@ function isValidUrl(url) {
|
|
|
1969
2155
|
}
|
|
1970
2156
|
async function isPortOpen(port) {
|
|
1971
2157
|
const tryConnect = (host) => {
|
|
1972
|
-
return new Promise((
|
|
2158
|
+
return new Promise((resolve) => {
|
|
1973
2159
|
const socket = new net.Socket();
|
|
1974
2160
|
socket.setTimeout(200);
|
|
1975
2161
|
socket.on("connect", () => {
|
|
1976
2162
|
socket.destroy();
|
|
1977
|
-
|
|
2163
|
+
resolve(true);
|
|
1978
2164
|
});
|
|
1979
2165
|
socket.on("timeout", () => {
|
|
1980
2166
|
socket.destroy();
|
|
1981
|
-
|
|
2167
|
+
resolve(false);
|
|
1982
2168
|
});
|
|
1983
2169
|
socket.on("error", () => {
|
|
1984
2170
|
socket.destroy();
|
|
1985
|
-
|
|
2171
|
+
resolve(false);
|
|
1986
2172
|
});
|
|
1987
2173
|
socket.connect(port, host);
|
|
1988
2174
|
});
|
|
@@ -2206,21 +2392,21 @@ export default defineConfig({
|
|
|
2206
2392
|
fs3.writeFileSync(path3.join(projectPath, "tsconfig.json"), JSON.stringify(tsconfig, null, 2) + "\n", "utf-8");
|
|
2207
2393
|
logger.success("Created tsconfig.json");
|
|
2208
2394
|
fs3.copyFileSync(path3.join(chatSourceDir, "package.json"), path3.join(projectPath, "package.json"));
|
|
2209
|
-
const
|
|
2210
|
-
|
|
2211
|
-
|
|
2395
|
+
const pkg = JSON.parse(fs3.readFileSync(path3.join(projectPath, "package.json"), "utf-8"));
|
|
2396
|
+
pkg.name = projectName;
|
|
2397
|
+
pkg.scripts = {
|
|
2212
2398
|
dev: "vite",
|
|
2213
2399
|
build: "vite build",
|
|
2214
2400
|
preview: "vite preview"
|
|
2215
2401
|
};
|
|
2216
|
-
delete
|
|
2217
|
-
if (
|
|
2218
|
-
|
|
2219
|
-
}
|
|
2220
|
-
delete
|
|
2221
|
-
delete
|
|
2222
|
-
delete
|
|
2223
|
-
fs3.writeFileSync(path3.join(projectPath, "package.json"), JSON.stringify(
|
|
2402
|
+
delete pkg.private;
|
|
2403
|
+
if (pkg.dependencies?.["@standardagents/react"]) {
|
|
2404
|
+
pkg.dependencies["@standardagents/react"] = reactVersion;
|
|
2405
|
+
}
|
|
2406
|
+
delete pkg.dependencies?.["next"];
|
|
2407
|
+
delete pkg.devDependencies?.["@tailwindcss/postcss"];
|
|
2408
|
+
delete pkg.devDependencies?.["postcss"];
|
|
2409
|
+
fs3.writeFileSync(path3.join(projectPath, "package.json"), JSON.stringify(pkg, null, 2) + "\n", "utf-8");
|
|
2224
2410
|
logger.success("Created package.json");
|
|
2225
2411
|
const envContent = `# Agentbuilder connection
|
|
2226
2412
|
VITE_AGENTBUILDER_URL=${serverUrl}
|
|
@@ -2275,21 +2461,21 @@ async function scaffoldNextjs(projectPath, chatSourceDir, projectName, serverUrl
|
|
|
2275
2461
|
};
|
|
2276
2462
|
fs3.writeFileSync(path3.join(projectPath, "tsconfig.json"), JSON.stringify(tsconfig, null, 2) + "\n", "utf-8");
|
|
2277
2463
|
logger.success("Created tsconfig.json");
|
|
2278
|
-
const
|
|
2279
|
-
|
|
2280
|
-
|
|
2464
|
+
const pkg = JSON.parse(fs3.readFileSync(path3.join(chatSourceDir, "package.json"), "utf-8"));
|
|
2465
|
+
pkg.name = projectName;
|
|
2466
|
+
pkg.scripts = {
|
|
2281
2467
|
dev: "next dev",
|
|
2282
2468
|
build: "next build",
|
|
2283
2469
|
start: "next start"
|
|
2284
2470
|
};
|
|
2285
|
-
delete
|
|
2286
|
-
if (
|
|
2287
|
-
|
|
2288
|
-
}
|
|
2289
|
-
delete
|
|
2290
|
-
delete
|
|
2291
|
-
delete
|
|
2292
|
-
fs3.writeFileSync(path3.join(projectPath, "package.json"), JSON.stringify(
|
|
2471
|
+
delete pkg.private;
|
|
2472
|
+
if (pkg.dependencies?.["@standardagents/react"]) {
|
|
2473
|
+
pkg.dependencies["@standardagents/react"] = reactVersion;
|
|
2474
|
+
}
|
|
2475
|
+
delete pkg.devDependencies?.["@tailwindcss/vite"];
|
|
2476
|
+
delete pkg.devDependencies?.["@vitejs/plugin-react"];
|
|
2477
|
+
delete pkg.devDependencies?.["vite"];
|
|
2478
|
+
fs3.writeFileSync(path3.join(projectPath, "package.json"), JSON.stringify(pkg, null, 2) + "\n", "utf-8");
|
|
2293
2479
|
logger.success("Created package.json");
|
|
2294
2480
|
const envContent = `# Agentbuilder connection
|
|
2295
2481
|
NEXT_PUBLIC_AGENTBUILDER_URL=${serverUrl}
|
|
@@ -2309,15 +2495,437 @@ out
|
|
|
2309
2495
|
pageTsx = pageTsx.replace(/from '\.\.\/\.\.\/src\//g, "from '../src/");
|
|
2310
2496
|
fs3.writeFileSync(path3.join(projectPath, "app", "page.tsx"), pageTsx, "utf-8");
|
|
2311
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
|
+
}
|
|
2312
2919
|
|
|
2313
2920
|
// src/index.ts
|
|
2314
|
-
var __dirname$1 = dirname(fileURLToPath(import.meta.url));
|
|
2315
|
-
var pkg = JSON.parse(readFileSync(resolve(__dirname$1, "../package.json"), "utf-8"));
|
|
2316
2921
|
var program = new Command();
|
|
2317
|
-
program.name("agents").description("CLI tool for Standard Agents / AgentBuilder").version(
|
|
2922
|
+
program.name("agents").description("CLI tool for Standard Agents / AgentBuilder").version("0.12.1");
|
|
2318
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);
|
|
2319
2924
|
program.command("scaffold").description("Add Standard Agents to an existing Vite project").option("--force", "Overwrite existing configuration").action(scaffold);
|
|
2320
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);
|
|
2321
2929
|
program.parse();
|
|
2322
2930
|
//# sourceMappingURL=index.js.map
|
|
2323
2931
|
//# sourceMappingURL=index.js.map
|