poly-agent 1.0.4 → 1.0.6
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/cli.js +18 -11
- package/dist/lib/prompt-loader.js +77 -14
- package/package.json +1 -1
- package/prompts/_shared/context-hook.md +103 -0
- package/prompts/context-recall.md +82 -0
package/dist/cli.js
CHANGED
|
@@ -90,7 +90,7 @@ async function runInit() {
|
|
|
90
90
|
cancel('Operation cancelled.');
|
|
91
91
|
process.exit(0);
|
|
92
92
|
}
|
|
93
|
-
// Step 4:
|
|
93
|
+
// Step 4: Install prompts with shared instructions
|
|
94
94
|
const targetDir = IDE_DIRECTORIES[selectedIDE];
|
|
95
95
|
const fullTargetPath = path.join(process.cwd(), targetDir);
|
|
96
96
|
const s = spinner();
|
|
@@ -98,9 +98,16 @@ async function runInit() {
|
|
|
98
98
|
try {
|
|
99
99
|
// Create target directory if it doesn't exist
|
|
100
100
|
await fs.mkdir(fullTargetPath, { recursive: true });
|
|
101
|
-
//
|
|
102
|
-
const
|
|
103
|
-
|
|
101
|
+
// Install each selected prompt with shared instructions injected
|
|
102
|
+
const installPromises = selectedPrompts.map(async (filename) => {
|
|
103
|
+
// Load prompt with shared instructions injected
|
|
104
|
+
const prompt = await loader.loadPrompt(filename);
|
|
105
|
+
// Reconstruct the full file content with frontmatter
|
|
106
|
+
const fullContent = `---
|
|
107
|
+
name: ${prompt.name}
|
|
108
|
+
description: ${prompt.description}
|
|
109
|
+
---
|
|
110
|
+
${prompt.content}`;
|
|
104
111
|
if (selectedIDE === 'Claude') {
|
|
105
112
|
// For Claude, create a folder with the prompt name and SKILL.md inside
|
|
106
113
|
const promptName = path.basename(filename, '.md');
|
|
@@ -108,23 +115,23 @@ async function runInit() {
|
|
|
108
115
|
const skillFilePath = path.join(skillFolderPath, 'SKILL.md');
|
|
109
116
|
// Create the skill folder
|
|
110
117
|
await fs.mkdir(skillFolderPath, { recursive: true });
|
|
111
|
-
//
|
|
112
|
-
await fs.
|
|
118
|
+
// Write the processed content to SKILL.md
|
|
119
|
+
await fs.writeFile(skillFilePath, fullContent, 'utf-8');
|
|
113
120
|
return `${promptName}/SKILL.md`;
|
|
114
121
|
}
|
|
115
122
|
else {
|
|
116
|
-
// For other IDEs,
|
|
123
|
+
// For other IDEs, write directly
|
|
117
124
|
const targetPath = path.join(fullTargetPath, filename);
|
|
118
|
-
await fs.
|
|
125
|
+
await fs.writeFile(targetPath, fullContent, 'utf-8');
|
|
119
126
|
return filename;
|
|
120
127
|
}
|
|
121
128
|
});
|
|
122
|
-
const
|
|
123
|
-
s.stop(`✓ Installed ${
|
|
129
|
+
const installedFiles = await Promise.all(installPromises);
|
|
130
|
+
s.stop(`✓ Installed ${installedFiles.length} prompt(s) successfully`);
|
|
124
131
|
// Success message
|
|
125
132
|
log.success(`Prompts installed to: ${targetDir}`);
|
|
126
133
|
log.info(`Installed files:`);
|
|
127
|
-
|
|
134
|
+
installedFiles.forEach(file => {
|
|
128
135
|
log.info(` - ${file}`);
|
|
129
136
|
});
|
|
130
137
|
outro('Installation complete! 🎉');
|
|
@@ -2,9 +2,60 @@ import fs from 'fs/promises';
|
|
|
2
2
|
import path from 'path';
|
|
3
3
|
export class PromptLoader {
|
|
4
4
|
promptsDir;
|
|
5
|
+
sharedInstructionsCache = null;
|
|
5
6
|
constructor(promptsDir) {
|
|
6
7
|
this.promptsDir = promptsDir;
|
|
7
8
|
}
|
|
9
|
+
/**
|
|
10
|
+
* Load all shared instructions from the _shared directory.
|
|
11
|
+
* These will be appended to every prompt.
|
|
12
|
+
*/
|
|
13
|
+
async loadSharedInstructions() {
|
|
14
|
+
// Return cached instructions if available
|
|
15
|
+
if (this.sharedInstructionsCache !== null) {
|
|
16
|
+
return this.sharedInstructionsCache;
|
|
17
|
+
}
|
|
18
|
+
const sharedDir = path.join(this.promptsDir, '_shared');
|
|
19
|
+
const instructions = [];
|
|
20
|
+
try {
|
|
21
|
+
const files = await fs.readdir(sharedDir);
|
|
22
|
+
const mdFiles = files.filter(f => f.endsWith('.md'));
|
|
23
|
+
for (const file of mdFiles) {
|
|
24
|
+
const filePath = path.join(sharedDir, file);
|
|
25
|
+
const fileContent = await fs.readFile(filePath, 'utf-8');
|
|
26
|
+
// Parse frontmatter to get name, extract content
|
|
27
|
+
const frontmatterRegex = /^---\n([\s\S]*?)\n---\n([\s\S]*)$/;
|
|
28
|
+
const match = fileContent.match(frontmatterRegex);
|
|
29
|
+
if (match) {
|
|
30
|
+
const metadata = this.parseFrontmatter(match[1]);
|
|
31
|
+
instructions.push({
|
|
32
|
+
name: metadata.name || path.basename(file, '.md'),
|
|
33
|
+
content: match[2].trim()
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
else {
|
|
37
|
+
// No frontmatter, use entire content
|
|
38
|
+
instructions.push({
|
|
39
|
+
name: path.basename(file, '.md'),
|
|
40
|
+
content: fileContent.trim()
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
catch (error) {
|
|
46
|
+
// _shared directory doesn't exist or is empty - that's okay
|
|
47
|
+
// Return empty array, shared instructions are optional
|
|
48
|
+
}
|
|
49
|
+
this.sharedInstructionsCache = instructions;
|
|
50
|
+
return instructions;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Clear the shared instructions cache.
|
|
54
|
+
* Useful if shared instructions are modified at runtime.
|
|
55
|
+
*/
|
|
56
|
+
clearCache() {
|
|
57
|
+
this.sharedInstructionsCache = null;
|
|
58
|
+
}
|
|
8
59
|
async loadPrompt(filename, variables = {}) {
|
|
9
60
|
const filePath = path.join(this.promptsDir, filename);
|
|
10
61
|
try {
|
|
@@ -12,22 +63,33 @@ export class PromptLoader {
|
|
|
12
63
|
// Basic Frontmatter parsing
|
|
13
64
|
const frontmatterRegex = /^---\n([\s\S]*?)\n---\n([\s\S]*)$/;
|
|
14
65
|
const match = fileContent.match(frontmatterRegex);
|
|
66
|
+
let name;
|
|
67
|
+
let description;
|
|
68
|
+
let content;
|
|
15
69
|
if (!match) {
|
|
16
70
|
// Fallback if no frontmatter
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
71
|
+
name = path.basename(filename, '.md');
|
|
72
|
+
description = 'No description provided.';
|
|
73
|
+
content = fileContent;
|
|
74
|
+
}
|
|
75
|
+
else {
|
|
76
|
+
const rawFrontmatter = match[1];
|
|
77
|
+
const metadata = this.parseFrontmatter(rawFrontmatter);
|
|
78
|
+
name = metadata.name || path.basename(filename, '.md');
|
|
79
|
+
description = metadata.description || '';
|
|
80
|
+
content = match[2];
|
|
81
|
+
}
|
|
82
|
+
// Inject variables
|
|
83
|
+
content = this.injectVariables(content, variables);
|
|
84
|
+
// Append shared instructions
|
|
85
|
+
const sharedInstructions = await this.loadSharedInstructions();
|
|
86
|
+
if (sharedInstructions.length > 0) {
|
|
87
|
+
const sharedContent = sharedInstructions
|
|
88
|
+
.map(inst => `\n---\n\n${inst.content}`)
|
|
89
|
+
.join('\n');
|
|
90
|
+
content = content + sharedContent;
|
|
22
91
|
}
|
|
23
|
-
|
|
24
|
-
const content = match[2];
|
|
25
|
-
const metadata = this.parseFrontmatter(rawFrontmatter);
|
|
26
|
-
return {
|
|
27
|
-
name: metadata.name || path.basename(filename, '.md'),
|
|
28
|
-
description: metadata.description || '',
|
|
29
|
-
content: this.injectVariables(content, variables)
|
|
30
|
-
};
|
|
92
|
+
return { name, description, content };
|
|
31
93
|
}
|
|
32
94
|
catch (error) {
|
|
33
95
|
throw new Error(`Failed to load prompt ${filename}: ${error}`);
|
|
@@ -55,7 +117,8 @@ export class PromptLoader {
|
|
|
55
117
|
async listPrompts() {
|
|
56
118
|
try {
|
|
57
119
|
const files = await fs.readdir(this.promptsDir);
|
|
58
|
-
|
|
120
|
+
// Filter out _shared directory and only return .md files
|
|
121
|
+
return files.filter(f => f.endsWith('.md') && !f.startsWith('_'));
|
|
59
122
|
}
|
|
60
123
|
catch (error) {
|
|
61
124
|
return [];
|
package/package.json
CHANGED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: Context Hook
|
|
3
|
+
description: Shared instructions for automatic context dumping after file edits.
|
|
4
|
+
type: shared
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Context Management Hook
|
|
8
|
+
|
|
9
|
+
## Behavior
|
|
10
|
+
|
|
11
|
+
After **every file edit** you make, you MUST update the project context file. This ensures continuity across conversations and helps maintain a clear record of progress.
|
|
12
|
+
|
|
13
|
+
## When to Update Context
|
|
14
|
+
|
|
15
|
+
1. **After any file edit** - Immediately after modifying, creating, or deleting a file
|
|
16
|
+
2. **When the task context changes** - New goals, pivots, or scope changes
|
|
17
|
+
3. **When explicitly mentioned** - If the user references `.context/` or asks about context
|
|
18
|
+
4. **At conversation milestones** - Completing a feature, fixing a bug, reaching a checkpoint
|
|
19
|
+
|
|
20
|
+
## Context File Location & Naming
|
|
21
|
+
|
|
22
|
+
- **Directory**: `.context/`
|
|
23
|
+
- **Filename**: Generate a short, descriptive kebab-case name based on the current task
|
|
24
|
+
- Examples: `feature-auth.md`, `bugfix-api-timeout.md`, `refactor-database-layer.md`, `setup-ci-pipeline.md`
|
|
25
|
+
- **Persistence**: Use the SAME context file throughout a conversation/task. Only create a new one if the task fundamentally changes.
|
|
26
|
+
|
|
27
|
+
## Context File Format
|
|
28
|
+
|
|
29
|
+
Use this exact structure:
|
|
30
|
+
|
|
31
|
+
```markdown
|
|
32
|
+
---
|
|
33
|
+
created: [ISO timestamp when first created]
|
|
34
|
+
updated: [ISO timestamp of last update]
|
|
35
|
+
task: [One-line task description]
|
|
36
|
+
status: [in-progress | completed | blocked | paused]
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
# Context: [short-name]
|
|
40
|
+
|
|
41
|
+
## Summary
|
|
42
|
+
[2-3 sentence AI-generated summary of what this task is about and current state]
|
|
43
|
+
|
|
44
|
+
## Files Changed
|
|
45
|
+
- `path/to/file.ts` - [Brief description of change]
|
|
46
|
+
- `path/to/another.ts` - [Brief description of change]
|
|
47
|
+
|
|
48
|
+
## Current Goals
|
|
49
|
+
1. [Primary goal]
|
|
50
|
+
2. [Secondary goal]
|
|
51
|
+
3. [etc.]
|
|
52
|
+
|
|
53
|
+
## Progress
|
|
54
|
+
- [x] [Completed item]
|
|
55
|
+
- [x] [Completed item]
|
|
56
|
+
- [ ] [Pending item]
|
|
57
|
+
- [ ] [Pending item]
|
|
58
|
+
|
|
59
|
+
## Next Steps
|
|
60
|
+
- [Immediate next action]
|
|
61
|
+
- [Following action]
|
|
62
|
+
|
|
63
|
+
## Notes
|
|
64
|
+
[Any important context, decisions made, blockers, or things to remember]
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## Rules
|
|
68
|
+
|
|
69
|
+
1. **Always update, never skip** - Even small edits warrant a context update
|
|
70
|
+
2. **Be concise but complete** - Capture essential information without verbosity
|
|
71
|
+
3. **Track ALL file changes** - Every file you touch should be listed
|
|
72
|
+
4. **Maintain history** - Don't remove completed items from Progress, mark them done
|
|
73
|
+
5. **Update timestamps** - Always update the `updated` field in frontmatter
|
|
74
|
+
6. **Create directory if needed** - If `.context/` doesn't exist, create it
|
|
75
|
+
|
|
76
|
+
## Example Workflow
|
|
77
|
+
|
|
78
|
+
1. User asks: "Add authentication to the API"
|
|
79
|
+
2. You create/update `.context/feature-api-auth.md` with initial goals
|
|
80
|
+
3. You edit `src/auth/middleware.ts`
|
|
81
|
+
4. You immediately update `.context/feature-api-auth.md` with the file change
|
|
82
|
+
5. You edit `src/routes/login.ts`
|
|
83
|
+
6. You update `.context/feature-api-auth.md` again
|
|
84
|
+
7. Continue until task complete, then set status to `completed`
|
|
85
|
+
|
|
86
|
+
## Recalling Context
|
|
87
|
+
|
|
88
|
+
When a user asks to recall or resume a context (e.g., "recall feature-auth", "continue from context X", "load context"):
|
|
89
|
+
|
|
90
|
+
1. **Read ONLY the specified context file** from `.context/` - Do NOT scan the entire project
|
|
91
|
+
2. **Trust the context file** - It contains all the information you need
|
|
92
|
+
3. **Summarize the current state** - What was done, what remains
|
|
93
|
+
4. **Confirm understanding** with the user before proceeding
|
|
94
|
+
5. **Only read files listed in "Files Changed"** if you need to check current state
|
|
95
|
+
6. **Continue updating** the same context file as you work
|
|
96
|
+
|
|
97
|
+
**IMPORTANT**: When recalling context, do NOT:
|
|
98
|
+
- Search or scan the entire codebase
|
|
99
|
+
- Read files not mentioned in the context
|
|
100
|
+
- Run broad exploratory searches
|
|
101
|
+
- Assume information beyond what's in the context file
|
|
102
|
+
|
|
103
|
+
If asked to **list contexts**, read the `.context/` directory and show available files with their status.
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: Context Recall
|
|
3
|
+
description: Load and resume work from a saved context file.
|
|
4
|
+
---
|
|
5
|
+
# Context Recall
|
|
6
|
+
|
|
7
|
+
You are being asked to **resume work** from a previously saved context.
|
|
8
|
+
|
|
9
|
+
## Instructions
|
|
10
|
+
|
|
11
|
+
1. **Read the context file** specified by the user (from `.context/` directory)
|
|
12
|
+
2. **Understand the state** - Review the summary, files changed, goals, and progress
|
|
13
|
+
3. **Identify next steps** - Look at what was marked as pending or in "Next Steps"
|
|
14
|
+
4. **Resume seamlessly** - Continue the work as if you never left
|
|
15
|
+
|
|
16
|
+
## How to Use
|
|
17
|
+
|
|
18
|
+
The user will provide one of:
|
|
19
|
+
- A context file name: `feature-auth` or `feature-auth.md`
|
|
20
|
+
- A full path: `.context/feature-auth.md`
|
|
21
|
+
- Or ask you to list available contexts
|
|
22
|
+
|
|
23
|
+
## If Asked to List Contexts
|
|
24
|
+
|
|
25
|
+
Read the `.context/` directory and present available context files:
|
|
26
|
+
|
|
27
|
+
```
|
|
28
|
+
Available contexts:
|
|
29
|
+
- feature-auth.md (updated: 2026-01-12)
|
|
30
|
+
- bugfix-api-timeout.md (updated: 2026-01-11)
|
|
31
|
+
- refactor-database.md (updated: 2026-01-10)
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## After Loading Context
|
|
35
|
+
|
|
36
|
+
1. **Summarize** what you understand about the task
|
|
37
|
+
2. **Confirm** the current state and what remains to be done
|
|
38
|
+
3. **Ask** if the user wants to continue from where it left off, or modify the approach
|
|
39
|
+
4. **Continue updating** the same context file as you make changes
|
|
40
|
+
|
|
41
|
+
## Example Interaction
|
|
42
|
+
|
|
43
|
+
**User**: "Recall context feature-auth"
|
|
44
|
+
|
|
45
|
+
**You**:
|
|
46
|
+
> I've loaded the context for **feature-auth**:
|
|
47
|
+
>
|
|
48
|
+
> **Summary**: Implementing JWT-based authentication for the API
|
|
49
|
+
>
|
|
50
|
+
> **Progress**:
|
|
51
|
+
> - ✅ Created auth middleware
|
|
52
|
+
> - ✅ Set up login route
|
|
53
|
+
> - ⏳ Token refresh logic (in progress)
|
|
54
|
+
> - ⬜ Rate limiting
|
|
55
|
+
>
|
|
56
|
+
> **Last worked on**: `src/auth/refresh.ts`
|
|
57
|
+
>
|
|
58
|
+
> Would you like me to continue with the token refresh logic, or would you prefer to work on something else?
|
|
59
|
+
|
|
60
|
+
## Critical Rules
|
|
61
|
+
|
|
62
|
+
1. **ONLY read the context file** - Do NOT scan the entire project or codebase
|
|
63
|
+
2. **Trust the context file** - It contains everything you need to understand the task
|
|
64
|
+
3. **Read files listed in "Files Changed"** - Only if you need to understand current state
|
|
65
|
+
4. **Don't guess or make up content** - Only use information from the context file
|
|
66
|
+
5. **If context file doesn't exist** - Inform the user and offer to create one
|
|
67
|
+
6. **Keep the context file updated** - As you continue working
|
|
68
|
+
|
|
69
|
+
## What NOT To Do
|
|
70
|
+
|
|
71
|
+
- ❌ Do NOT search the entire codebase to "understand the project"
|
|
72
|
+
- ❌ Do NOT read files that aren't mentioned in the context
|
|
73
|
+
- ❌ Do NOT run broad searches or scans
|
|
74
|
+
- ❌ Do NOT assume context beyond what's in the file
|
|
75
|
+
|
|
76
|
+
## What TO Do
|
|
77
|
+
|
|
78
|
+
- ✅ Read ONLY `.context/[name].md` first
|
|
79
|
+
- ✅ Use the "Files Changed" section to know which files are relevant
|
|
80
|
+
- ✅ Read specific files from "Files Changed" if needed for current state
|
|
81
|
+
- ✅ Follow "Next Steps" from the context file
|
|
82
|
+
- ✅ Ask the user if anything is unclear
|