@miphamai/cli 0.2.4 → 0.4.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/bin/mipham.ts +2 -0
- package/dist/mipham +0 -0
- package/package.json +10 -9
- package/skills/mipham/om-artifact.mipham-skill.md +69 -0
- package/skills/mipham/om-model-optimize.mipham-skill.md +58 -9
- package/skills/mipham/om-security.mipham-skill.md +85 -10
- package/skills/standard/doc-generator.SKILL.md +72 -11
- package/skills/standard/github-ops.SKILL.md +94 -13
- package/skills/standard/memory.SKILL.md +72 -11
- package/skills/standard/self-review.SKILL.md +50 -10
- package/skills/standard/superpower.SKILL.md +46 -8
- package/skills/standard/tdd.SKILL.md +85 -12
- package/skills/standard/web-search.SKILL.md +65 -13
- package/src/agent/sub-agent.ts +0 -1
- package/src/artifacts/manifest.ts +101 -0
- package/src/artifacts/server.ts +343 -0
- package/src/core/context.ts +73 -13
- package/src/core/engine.ts +194 -71
- package/src/core/instructions.ts +1 -1
- package/src/core/permission.ts +35 -4
- package/src/core/session-store.ts +5 -1
- package/src/index.tsx +35 -2
- package/src/mcp/transport.ts +42 -5
- package/src/providers/anthropic.ts +2 -1
- package/src/providers/fetch-utils.ts +101 -0
- package/src/providers/openai-compat.ts +53 -15
- package/src/providers/registry.ts +1 -0
- package/src/shared/constants.ts +8 -1
- package/src/shared/types.ts +21 -1
- package/src/skills/loader.ts +2 -2
- package/src/tools/artifact/artifact.ts +144 -0
- package/src/tools/index.ts +3 -0
- package/src/ui/app.tsx +122 -15
- package/src/ui/chat.tsx +29 -7
- package/src/ui/commands.ts +117 -19
- package/src/ui/input.tsx +117 -35
- package/src/ui/picker.tsx +2 -5
|
@@ -1,19 +1,57 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: superpower
|
|
3
|
-
description:
|
|
4
|
-
version:
|
|
3
|
+
description: Skill discovery and invocation system — find and use skills before any response or action
|
|
4
|
+
version: 2.0.0
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
# Superpowers
|
|
7
|
+
# Superpowers — Using Skills
|
|
8
8
|
|
|
9
|
-
##
|
|
9
|
+
## The Rule
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
**Invoke relevant or requested skills BEFORE any response or action.** Even a 1% chance a skill might apply means you should invoke it to check.
|
|
12
12
|
|
|
13
13
|
## How to Access Skills
|
|
14
14
|
|
|
15
|
-
Use the Skill tool to invoke skills. When you invoke a skill, its content is loaded
|
|
15
|
+
Use the `Skill` tool to invoke skills by name. When you invoke a skill, its content is loaded — follow it directly.
|
|
16
16
|
|
|
17
|
-
##
|
|
17
|
+
## Skill Discovery
|
|
18
|
+
|
|
19
|
+
### Check Available Skills
|
|
20
|
+
|
|
21
|
+
Skills are listed in `<system-reminder>` messages. Scan this list when receiving a task.
|
|
22
|
+
|
|
23
|
+
### Matching Algorithm
|
|
24
|
+
|
|
25
|
+
1. Parse the user's request for intent keywords
|
|
26
|
+
2. Scan skill names and descriptions for matches
|
|
27
|
+
3. If ANY skill matches at ≥1% probability → invoke it
|
|
28
|
+
4. Multiple matches → invoke all that may apply
|
|
29
|
+
5. Invoked skill doesn't fit → that's fine, don't use it
|
|
30
|
+
|
|
31
|
+
### Priority Order
|
|
32
|
+
|
|
33
|
+
1. **Process skills first** — brainstorming, systematic-debugging, tdd. These determine HOW to approach
|
|
34
|
+
2. **Implementation skills second** — frontend-design, mcp-builder. These guide execution
|
|
35
|
+
|
|
36
|
+
## Red Flags
|
|
37
|
+
|
|
38
|
+
These thoughts mean STOP — you're rationalizing:
|
|
39
|
+
|
|
40
|
+
| Thought | Reality |
|
|
41
|
+
| ----------------------------------- | ---------------------------------------------- |
|
|
42
|
+
| "This is just a simple question" | Questions are tasks. Check skills. |
|
|
43
|
+
| "I need more context first" | Skill check comes BEFORE clarifying questions. |
|
|
44
|
+
| "Let me explore the codebase first" | Skills tell you HOW to explore. |
|
|
45
|
+
| "I remember this skill" | Skills evolve. Read current version. |
|
|
46
|
+
| "The skill is overkill" | Simple things become complex. Use it. |
|
|
47
|
+
|
|
48
|
+
## Skill Types
|
|
49
|
+
|
|
50
|
+
- **Rigid** (TDD, systematic-debugging): Follow exactly. Don't adapt away discipline.
|
|
51
|
+
- **Flexible** (patterns): Adapt principles to context.
|
|
52
|
+
|
|
53
|
+
The skill itself tells you which type it is.
|
|
54
|
+
|
|
55
|
+
## User Instructions
|
|
18
56
|
|
|
19
|
-
|
|
57
|
+
Instructions say WHAT, not HOW. "Add X" or "Fix Y" doesn't mean skip workflows.
|
|
@@ -1,20 +1,93 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: tdd
|
|
3
|
-
description: Test-Driven Development
|
|
4
|
-
version:
|
|
3
|
+
description: Test-Driven Development — red-green-refactor cycle with language-specific guidance and test design rules
|
|
4
|
+
version: 2.0.0
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
# TDD
|
|
7
|
+
# Test-Driven Development (TDD)
|
|
8
8
|
|
|
9
|
-
##
|
|
9
|
+
## The Cycle
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
11
|
+
```
|
|
12
|
+
RED → GREEN → REFACTOR → repeat
|
|
13
|
+
```
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
### 1. RED — Write a Failing Test
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
-
|
|
20
|
-
-
|
|
17
|
+
Write the smallest test that captures the behavior you want:
|
|
18
|
+
|
|
19
|
+
- Name the test descriptively: `it('should return 0 for empty string')`
|
|
20
|
+
- Use the AAA pattern: **A**rrange → **A**ct → **A**ssert
|
|
21
|
+
- Run to confirm it **fails** (not errors — fails)
|
|
22
|
+
- If it passes before implementation, your test is wrong
|
|
23
|
+
|
|
24
|
+
### 2. GREEN — Make It Pass
|
|
25
|
+
|
|
26
|
+
Write the **minimum** code to make the test pass:
|
|
27
|
+
|
|
28
|
+
- Don't optimize, don't generalize, don't add features
|
|
29
|
+
- A hardcoded return is fine if it passes the test
|
|
30
|
+
- Run all tests — the new one should pass, old ones should still pass
|
|
31
|
+
|
|
32
|
+
### 3. REFACTOR — Clean Up
|
|
33
|
+
|
|
34
|
+
Improve the code while tests stay green:
|
|
35
|
+
|
|
36
|
+
- Remove duplication (test code and production code)
|
|
37
|
+
- Improve names, extract helpers
|
|
38
|
+
- Simplify logic
|
|
39
|
+
- Run tests after each change
|
|
40
|
+
|
|
41
|
+
## Test Design Rules
|
|
42
|
+
|
|
43
|
+
- **Deterministic**: No `Date.now()`, `Math.random()`, or network calls in test bodies
|
|
44
|
+
- **Isolated**: Each test sets up its own state; no test-order dependency
|
|
45
|
+
- **Fast**: Unit tests should run in milliseconds, not seconds
|
|
46
|
+
- **Readable**: Test output should explain what broke without reading source
|
|
47
|
+
|
|
48
|
+
## Language-Specific Guidance
|
|
49
|
+
|
|
50
|
+
### TypeScript / JavaScript (Vitest)
|
|
51
|
+
|
|
52
|
+
```ts
|
|
53
|
+
import { describe, it, expect } from 'vitest'
|
|
54
|
+
|
|
55
|
+
describe('sum', () => {
|
|
56
|
+
it('should add two positive numbers', () => {
|
|
57
|
+
expect(sum(2, 3)).toBe(5)
|
|
58
|
+
})
|
|
59
|
+
it('should handle zero', () => {
|
|
60
|
+
expect(sum(0, 5)).toBe(5)
|
|
61
|
+
})
|
|
62
|
+
})
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
File naming: `src/foo.ts` → `test/foo.test.ts`
|
|
66
|
+
|
|
67
|
+
### Python (pytest)
|
|
68
|
+
|
|
69
|
+
```python
|
|
70
|
+
def test_sum_positive():
|
|
71
|
+
assert sum(2, 3) == 5
|
|
72
|
+
|
|
73
|
+
def test_sum_zero():
|
|
74
|
+
assert sum(0, 5) == 5
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### Go (testing package)
|
|
78
|
+
|
|
79
|
+
```go
|
|
80
|
+
func TestSumPositive(t *testing.T) {
|
|
81
|
+
got := Sum(2, 3)
|
|
82
|
+
want := 5
|
|
83
|
+
if got != want {
|
|
84
|
+
t.Errorf("Sum(2,3) = %d; want %d", got, want)
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
## When NOT to TDD
|
|
90
|
+
|
|
91
|
+
- Exploratory spikes (throw away after learning)
|
|
92
|
+
- Configuration files and types (compile-time enforced)
|
|
93
|
+
- Generated code
|
|
@@ -1,23 +1,75 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: web-search
|
|
3
|
-
description: Search the web for current information
|
|
4
|
-
version:
|
|
3
|
+
description: Search the web for current information — documentation, news, technical references, and troubleshooting
|
|
4
|
+
version: 2.0.0
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
# Web Search
|
|
7
|
+
# Web Search
|
|
8
8
|
|
|
9
|
-
Use WebSearch tool to find current information.
|
|
9
|
+
Use `WebSearch` tool to find current, accurate information from the web.
|
|
10
10
|
|
|
11
11
|
## When to Use
|
|
12
12
|
|
|
13
|
-
-
|
|
14
|
-
- Current events
|
|
15
|
-
-
|
|
16
|
-
-
|
|
13
|
+
- **Library/framework docs**: API references, migration guides, version-specific features
|
|
14
|
+
- **Current events**: News, releases, incidents (anything after training cutoff)
|
|
15
|
+
- **Troubleshooting**: Error messages, stack traces, known issues
|
|
16
|
+
- **Comparisons**: Technology trade-offs, benchmark data
|
|
17
|
+
- **Code examples**: Real-world usage patterns, configuration snippets
|
|
17
18
|
|
|
18
|
-
## Best Practices
|
|
19
|
+
## Query Best Practices
|
|
19
20
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
21
|
+
### Be Specific
|
|
22
|
+
|
|
23
|
+
```
|
|
24
|
+
❌ "React" → too broad
|
|
25
|
+
❌ "React problems" → ambiguous
|
|
26
|
+
✅ "React 19 useEffect double mount fix" → specific, versioned
|
|
27
|
+
✅ "Next.js 14 App Router caching behavior 2026" → targeted
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
### Use Technical Terms
|
|
31
|
+
|
|
32
|
+
```
|
|
33
|
+
❌ "how to make website fast"
|
|
34
|
+
✅ "Core Web Vitals LCP optimization Next.js 14"
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### Include Version Numbers
|
|
38
|
+
|
|
39
|
+
```
|
|
40
|
+
❌ "prisma query"
|
|
41
|
+
✅ "Prisma 5.0 findMany with nested include filter"
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### Domain Filtering
|
|
45
|
+
|
|
46
|
+
Use `allowed_domains` for authoritative sources:
|
|
47
|
+
|
|
48
|
+
- `docs.github.com` — GitHub documentation
|
|
49
|
+
- `nextjs.org` — Next.js official docs
|
|
50
|
+
- `developer.mozilla.org` — MDN Web Docs
|
|
51
|
+
- `nodejs.org` — Node.js official
|
|
52
|
+
|
|
53
|
+
## Verification
|
|
54
|
+
|
|
55
|
+
- **Cross-reference**: Verify claims across 2+ independent sources
|
|
56
|
+
- **Recency**: Prefer results from the current year; note article dates
|
|
57
|
+
- **Authority**: Official docs > well-known blogs > Stack Overflow > random forums
|
|
58
|
+
- **Cite sources**: Always include source URLs in responses
|
|
59
|
+
|
|
60
|
+
## Source Attribution
|
|
61
|
+
|
|
62
|
+
After answering from search results, end with:
|
|
63
|
+
|
|
64
|
+
```markdown
|
|
65
|
+
Sources:
|
|
66
|
+
|
|
67
|
+
- [Title](URL) — brief note
|
|
68
|
+
- [Title](URL) — brief note
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## When NOT to Search
|
|
72
|
+
|
|
73
|
+
- Pure logic or algorithmic questions (reasoning, not research)
|
|
74
|
+
- Questions answerable from code already in context
|
|
75
|
+
- Opinions and subjective recommendations (search for data, not consensus)
|
package/src/agent/sub-agent.ts
CHANGED
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import {
|
|
2
|
+
readFileSync,
|
|
3
|
+
writeFileSync,
|
|
4
|
+
existsSync,
|
|
5
|
+
mkdirSync,
|
|
6
|
+
renameSync,
|
|
7
|
+
copyFileSync,
|
|
8
|
+
unlinkSync,
|
|
9
|
+
} from 'node:fs'
|
|
10
|
+
import { join } from 'node:path'
|
|
11
|
+
import type { ArtifactManifest, ArtifactEntry } from '../shared/types'
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Read the artifact manifest from disk, or return an empty one if it doesn't exist.
|
|
15
|
+
*/
|
|
16
|
+
export function readManifest(dir: string): ArtifactManifest {
|
|
17
|
+
const path = join(dir, 'index.json')
|
|
18
|
+
if (!existsSync(path)) {
|
|
19
|
+
return { version: 1, artifacts: [] }
|
|
20
|
+
}
|
|
21
|
+
try {
|
|
22
|
+
return JSON.parse(readFileSync(path, 'utf-8'))
|
|
23
|
+
} catch {
|
|
24
|
+
return { version: 1, artifacts: [] }
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Write the manifest to disk, creating parent directories as needed.
|
|
30
|
+
*/
|
|
31
|
+
export function writeManifest(dir: string, manifest: ArtifactManifest): void {
|
|
32
|
+
mkdirSync(dir, { recursive: true })
|
|
33
|
+
writeFileSync(join(dir, 'index.json'), JSON.stringify(manifest, null, 2), 'utf-8')
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Add an entry to the manifest and persist it.
|
|
38
|
+
* If an entry with the same name already exists, it is replaced.
|
|
39
|
+
*/
|
|
40
|
+
export function addToManifest(dir: string, entry: ArtifactEntry, port?: number): ArtifactManifest {
|
|
41
|
+
const manifest = readManifest(dir)
|
|
42
|
+
if (port !== undefined) manifest.port = port
|
|
43
|
+
|
|
44
|
+
const idx = manifest.artifacts.findIndex((a) => a.name === entry.name)
|
|
45
|
+
if (idx >= 0) {
|
|
46
|
+
manifest.artifacts[idx] = entry
|
|
47
|
+
} else {
|
|
48
|
+
manifest.artifacts.push(entry)
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
writeManifest(dir, manifest)
|
|
52
|
+
return manifest
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Get all artifacts for a specific session.
|
|
57
|
+
*/
|
|
58
|
+
export function getSessionArtifacts(dir: string, sessionId: string): ArtifactEntry[] {
|
|
59
|
+
const manifest = readManifest(dir)
|
|
60
|
+
return manifest.artifacts.filter((a) => a.sessionId === sessionId)
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Archive an existing artifact file by renaming it with a version tag.
|
|
65
|
+
* e.g. dashboard.html → dashboard.v1.html, dashboard.v1.html → dashboard.v2.html.
|
|
66
|
+
*
|
|
67
|
+
* Returns the version tag assigned to the archived file.
|
|
68
|
+
*/
|
|
69
|
+
export function archiveVersion(dir: string, entry: ArtifactEntry): string {
|
|
70
|
+
const manifest = readManifest(dir)
|
|
71
|
+
const versionCount = (entry.versionCount || 1) + 1
|
|
72
|
+
const ext = entry.type === 'svg' ? '.svg' : '.html'
|
|
73
|
+
const versionTag = `v${versionCount}`
|
|
74
|
+
|
|
75
|
+
// Rename the current file to a versioned copy
|
|
76
|
+
const baseName = entry.name
|
|
77
|
+
const currentPath = join(dir, entry.sessionId, `${baseName}${ext}`)
|
|
78
|
+
const archivedPath = join(dir, entry.sessionId, `${baseName}.${versionTag}${ext}`)
|
|
79
|
+
|
|
80
|
+
if (existsSync(currentPath)) {
|
|
81
|
+
try {
|
|
82
|
+
renameSync(currentPath, archivedPath)
|
|
83
|
+
} catch {
|
|
84
|
+
// If rename fails (e.g. cross-device), copy instead
|
|
85
|
+
copyFileSync(currentPath, archivedPath)
|
|
86
|
+
unlinkSync(currentPath)
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Update manifest entry
|
|
91
|
+
const artifact = manifest.artifacts.find((a) => a.name === entry.name)
|
|
92
|
+
if (artifact) {
|
|
93
|
+
const versions = artifact.versions || ['v1']
|
|
94
|
+
versions.push(versionTag)
|
|
95
|
+
artifact.versions = versions
|
|
96
|
+
artifact.versionCount = versionCount
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
writeManifest(dir, manifest)
|
|
100
|
+
return versionTag
|
|
101
|
+
}
|