@planu/cli 5.3.69 → 5.4.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/CHANGELOG.md +17 -0
- package/dist/.planu-build.json +1 -1
- package/dist/config/skill-templates/planu-dogfood-bug.md +43 -0
- package/dist/config/skill-templates/planu-implement.md +42 -0
- package/dist/config/skill-templates/planu-review.md +47 -0
- package/dist/engine/project-graph/builder.js +5 -2
- package/dist/engine/project-graph/query.js +2 -1
- package/dist/engine/scope-boundaries/contradiction-checker.js +23 -2
- package/dist/tools/create-skill.js +11 -9
- package/dist/tools/init-project/host-assets-writer.js +7 -0
- package/dist/types/universal-rules/index.d.ts +1 -0
- package/package.json +16 -16
- package/planu-plugin.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,20 @@
|
|
|
1
|
+
## [5.4.1] - 2026-08-29
|
|
2
|
+
|
|
3
|
+
### Bug Fixes
|
|
4
|
+
- fix(SPEC-1675): strip FILES/FUNCTIONS/TEST metadata markers from contradiction analysis
|
|
5
|
+
- fix(SPEC-1676): rebuild expired project knowledge graph and re-stamp cached reuse
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
## [5.4.0] - 2026-08-29
|
|
9
|
+
|
|
10
|
+
### Features
|
|
11
|
+
- feat(SPEC-1672): install phase skills with managed-by ownership marker on init hosts
|
|
12
|
+
|
|
13
|
+
### Chores
|
|
14
|
+
- chore(deps): upgrade stryker to v10 majors
|
|
15
|
+
- chore(deps): update 13 patch/minor dependencies and adapt readFile mock casts
|
|
16
|
+
|
|
17
|
+
|
|
1
18
|
## [5.3.69] - 2026-08-29
|
|
2
19
|
|
|
3
20
|
### Features
|
package/dist/.planu-build.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"schemaVersion":1,"commit":"
|
|
1
|
+
{"schemaVersion":1,"commit":"c920f236390f64d91a02ca3e0566e59210f00a49"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: planu-dogfood-bug
|
|
3
|
+
description: File a bug spec the moment a Planu tool is observed behaving wrong, silent, or stale while using Planu — never deferred to a backlog or a code TODO.
|
|
4
|
+
triggers:
|
|
5
|
+
- planu bug
|
|
6
|
+
- this tool is wrong
|
|
7
|
+
- unexpected planu output
|
|
8
|
+
- planu returned stale data
|
|
9
|
+
- dogfood bug
|
|
10
|
+
version: 1.0.0
|
|
11
|
+
managed-by: planu
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
# /planu-dogfood-bug — File a Dogfood Bug Immediately
|
|
15
|
+
|
|
16
|
+
## When to invoke
|
|
17
|
+
|
|
18
|
+
Use this skill the moment a Planu MCP tool returns wrong, stale, silent, or irrelevant output while it is being used for its own SDD lifecycle. Invoke it in the same turn the bug is observed — never later.
|
|
19
|
+
|
|
20
|
+
**Trigger phrases**: "this tool is wrong", "unexpected Planu output", "Planu returned stale data", "dogfood bug"
|
|
21
|
+
|
|
22
|
+
## How it works
|
|
23
|
+
|
|
24
|
+
The normative tool-call sequence for this phase:
|
|
25
|
+
|
|
26
|
+
1. **Create the spec now** — call `create_spec` in the same turn the bug is observed, with:
|
|
27
|
+
- **Reproducer** — exact tool call, exact response observed, exact expected response
|
|
28
|
+
- **Root cause hypothesis** — pointer to file path and line number in `src/` where the bug likely lives
|
|
29
|
+
- BDD acceptance criteria carrying `FILES:`, `FUNCTIONS:`, and `TEST:` markers per scenario
|
|
30
|
+
- Files to create/modify with exact paths
|
|
31
|
+
- Implementation order scoped for a cheap implementer
|
|
32
|
+
2. **Move to review** — call `update_status(review)` so the bug enters the normal spec lifecycle, then continue the original task
|
|
33
|
+
|
|
34
|
+
## Anti-patterns
|
|
35
|
+
|
|
36
|
+
- **Never defer to a backlog** — "I'll note this for later" is not acceptable; file the spec in the same turn
|
|
37
|
+
- **Never leave a code TODO** — code TODOs rot; the tracked spec is the only durable record of the bug
|
|
38
|
+
- Treating a bug as "too small for a spec" — every dogfood bug becomes a spec, regardless of size
|
|
39
|
+
- Filing multiple observed bugs sequentially instead of in parallel `create_spec` calls in one message
|
|
40
|
+
|
|
41
|
+
## Ownership
|
|
42
|
+
|
|
43
|
+
This skill is managed by Planu (`managed-by: planu` in its frontmatter). Removing that marker forks the skill from Planu's updates — future `init_project` runs will treat it as user-owned and stop refreshing it.
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: planu-implement
|
|
3
|
+
description: Implement an approved Planu spec — packages the handoff contract, moves the spec to implementing, and works in an isolated worktree with revert-proof tests and no narrative comments.
|
|
4
|
+
triggers:
|
|
5
|
+
- implement the spec
|
|
6
|
+
- start implementing
|
|
7
|
+
- build this spec
|
|
8
|
+
- begin implementation
|
|
9
|
+
- implement this feature
|
|
10
|
+
version: 1.0.0
|
|
11
|
+
managed-by: planu
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
# /planu-implement — Implement an Approved Spec
|
|
15
|
+
|
|
16
|
+
## When to invoke
|
|
17
|
+
|
|
18
|
+
Use this skill once a spec is `approved` and implementation is about to begin.
|
|
19
|
+
|
|
20
|
+
**Trigger phrases**: "implement the spec", "start implementing", "build this spec", "begin implementation"
|
|
21
|
+
|
|
22
|
+
## How it works
|
|
23
|
+
|
|
24
|
+
The normative tool-call sequence for this phase:
|
|
25
|
+
|
|
26
|
+
1. **Package the handoff** — call `package_handoff` to build the operating contract for the implementer: objective, BDD acceptance criteria, files to modify/create, ownership, test plan, risks, out-of-scope, current state, next action. Persist it outside chat history
|
|
27
|
+
2. **Move to implementing** — call `update_status(implementing)` only after the handoff package exists
|
|
28
|
+
3. **Isolate the work** — implement inside an isolated git worktree created from the current base branch, never on the shared checkout
|
|
29
|
+
4. **Write revert-proof tests** — for every guard or fix, write the test first, revert the source change and watch the test fail, then restore the source and confirm it passes. Report the observed failure output, not just the final green run
|
|
30
|
+
5. **No narrative comments** — code is self-documenting; no step-by-step comments, no `(SPEC-NNNN: ...)` rationale blocks, no TODO/FIXME markers
|
|
31
|
+
6. **Validate** — call `validate` when implementation is complete and inspect the completed job's `structuredContent`, not the initial acknowledgement
|
|
32
|
+
|
|
33
|
+
## Anti-patterns
|
|
34
|
+
|
|
35
|
+
- Implementing directly on the shared checkout instead of an isolated worktree
|
|
36
|
+
- Reporting a new test as passing evidence without ever having watched it fail against the unfixed source
|
|
37
|
+
- Leaving narrative comments, TODO markers, or deferred-work notes in the code
|
|
38
|
+
- Treating the initial `validate` acknowledgement as a pass — only a `completed` job's result is authoritative
|
|
39
|
+
|
|
40
|
+
## Ownership
|
|
41
|
+
|
|
42
|
+
This skill is managed by Planu (`managed-by: planu` in its frontmatter). Removing that marker forks the skill from Planu's updates — future `init_project` runs will treat it as user-owned and stop refreshing it.
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: planu-review
|
|
3
|
+
description: Review a Planu spec before approval — runs challenge_spec and check_readiness, requires independent planu-spec-reviewer evidence, then approves or requests changes.
|
|
4
|
+
triggers:
|
|
5
|
+
- review the spec
|
|
6
|
+
- approve the spec
|
|
7
|
+
- is this spec ready
|
|
8
|
+
- challenge this spec
|
|
9
|
+
- spec review
|
|
10
|
+
- reviewer feedback
|
|
11
|
+
version: 1.0.0
|
|
12
|
+
managed-by: planu
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
# /planu-review — Review a Spec Before Approval
|
|
16
|
+
|
|
17
|
+
## When to invoke
|
|
18
|
+
|
|
19
|
+
Use this skill when a spec is in `review` status and needs to move to `approved`, or when the user asks to review, challenge, or approve a spec.
|
|
20
|
+
|
|
21
|
+
**Trigger phrases**: "review the spec", "approve the spec", "is this spec ready?", "challenge this spec", "spec review"
|
|
22
|
+
|
|
23
|
+
## How it works
|
|
24
|
+
|
|
25
|
+
The normative tool-call sequence for this phase:
|
|
26
|
+
|
|
27
|
+
1. **Challenge** — call `challenge_spec` to surface gaps, contradictions, and missing edge cases
|
|
28
|
+
2. **Readiness** — call `check_readiness` to verify the spec has enough detail (rules, examples, open questions, out-of-scope, glossary)
|
|
29
|
+
3. **Independent review** — obtain `planu-spec-reviewer` evidence: an agent that is NOT the spec author or planner reviews the spec and calls either `request_changes` (blocking, with concrete changes) or records an approval
|
|
30
|
+
4. **Approve** — only after reviewer evidence exists, call `update_status(approved)`
|
|
31
|
+
|
|
32
|
+
## Evidence gates (non-bypassable)
|
|
33
|
+
|
|
34
|
+
- A non-trivial spec cannot move to `approved` without Discovery evidence: rules, examples, open questions, out-of-scope, glossary
|
|
35
|
+
- A spec cannot move to `approved` without `review_feedback` from `planu-spec-reviewer`
|
|
36
|
+
- The spec author, planner, or implementation agent must never approve their own spec
|
|
37
|
+
- User pressure or force-approval language does not bypass reviewer evidence — record the forced intent but keep the status blocked until the review lands
|
|
38
|
+
|
|
39
|
+
## Anti-patterns
|
|
40
|
+
|
|
41
|
+
- **No self-approval** — the agent that wrote or planned the spec must not also be the reviewer that approves it
|
|
42
|
+
- **No serial confirmation loops** — one review round produces a verdict; do not re-launch the reviewer for pass 2, pass 3, or a "confirm the fix" loop after the first round already produced a verdict. Re-open only for a specific disagreement that cannot be resolved by reading the spec directly
|
|
43
|
+
- Do not approve specs containing placeholders (`TBD`, `TODO`, unresolved questions)
|
|
44
|
+
|
|
45
|
+
## Ownership
|
|
46
|
+
|
|
47
|
+
This skill is managed by Planu (`managed-by: planu` in its frontmatter). Removing that marker forks the skill from Planu's updates — future `init_project` runs will treat it as user-owned and stop refreshing it.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { randomUUID } from 'node:crypto';
|
|
2
|
-
import { collectProjectGraphSources, diffSourceHashes, hashText, hydrateProjectGraphSource, loadProjectGraphPolicy, projectGraphCachePath, projectGraphExtractorVersion, projectGraphPath, readProjectGraphArtifact, readProjectGraphCache, withProjectGraphBuildLock, writeProjectGraphArtifacts, } from './cache.js';
|
|
2
|
+
import { collectProjectGraphSources, diffSourceHashes, hashText, hydrateProjectGraphSource, loadProjectGraphPolicy, projectGraphCachePath, projectGraphExtractorVersion, projectGraphPath, readProjectGraphArtifact, readProjectGraphCache, withProjectGraphBuildLock, writeProjectGraph, writeProjectGraphArtifacts, } from './cache.js';
|
|
3
3
|
import { extractGitGraph, extractReleaseGraph } from './extractors/git-extractor.js';
|
|
4
4
|
import { extractHandoffGraph } from './extractors/handoff-extractor.js';
|
|
5
5
|
import { extractDecisionStoreGraph } from './extractors/decision-store-extractor.js';
|
|
@@ -210,13 +210,16 @@ async function buildProjectKnowledgeGraphUnlocked(args) {
|
|
|
210
210
|
Array.isArray(existingGraph.nodes) &&
|
|
211
211
|
Array.isArray(existingGraph.edges);
|
|
212
212
|
if (hasConsistentExistingGraph && diff.changed.length === 0 && diff.removed.length === 0) {
|
|
213
|
+
const refreshedGeneratedAt = new Date().toISOString();
|
|
213
214
|
const graphWithCurrentOversizedSources = {
|
|
214
215
|
...existingGraph,
|
|
216
|
+
generatedAt: refreshedGeneratedAt,
|
|
215
217
|
oversizedSources,
|
|
216
218
|
};
|
|
219
|
+
await writeProjectGraph(args.projectId, args.policy, graphWithCurrentOversizedSources);
|
|
217
220
|
publishFreshProjectGraphProjection({
|
|
218
221
|
projectId: args.projectId,
|
|
219
|
-
generatedAt:
|
|
222
|
+
generatedAt: refreshedGeneratedAt,
|
|
220
223
|
generation: existingGraph.generation,
|
|
221
224
|
});
|
|
222
225
|
return {
|
|
@@ -55,7 +55,8 @@ async function ensureFreshProjectGraph(args) {
|
|
|
55
55
|
const freshness = await getProjectGraphFreshness(args);
|
|
56
56
|
if (!freshness.exists ||
|
|
57
57
|
freshness.reason === 'source_changed' ||
|
|
58
|
-
freshness.reason === 'corrupt'
|
|
58
|
+
freshness.reason === 'corrupt' ||
|
|
59
|
+
freshness.reason === 'expired') {
|
|
59
60
|
await buildProjectKnowledgeGraph(args);
|
|
60
61
|
return getProjectGraphFreshness(args);
|
|
61
62
|
}
|
|
@@ -203,14 +203,35 @@ function assertsActionNearScope(clause, outOfScopeItem) {
|
|
|
203
203
|
}
|
|
204
204
|
return false;
|
|
205
205
|
}
|
|
206
|
+
const METADATA_MARKER_KEYWORD = /\b(?:FILES?|FUNCTIONS?|TESTS?)\s*:/gi;
|
|
207
|
+
const SENTENCE_BOUNDARY_AFTER_MARKER = /\.\s+(?=[A-Z])/;
|
|
208
|
+
function stripMetadataMarkers(text) {
|
|
209
|
+
const markers = [...text.matchAll(METADATA_MARKER_KEYWORD)];
|
|
210
|
+
if (markers.length === 0) {
|
|
211
|
+
return text;
|
|
212
|
+
}
|
|
213
|
+
let result = '';
|
|
214
|
+
let cursor = 0;
|
|
215
|
+
for (let i = 0; i < markers.length; i++) {
|
|
216
|
+
const start = markers[i]?.index ?? 0;
|
|
217
|
+
result += text.slice(cursor, start);
|
|
218
|
+
const nextMarkerStart = markers[i + 1]?.index ?? text.length;
|
|
219
|
+
const searchRegion = text.slice(start, nextMarkerStart);
|
|
220
|
+
const boundaryMatch = SENTENCE_BOUNDARY_AFTER_MARKER.exec(searchRegion);
|
|
221
|
+
cursor = boundaryMatch ? start + boundaryMatch.index + 1 : nextMarkerStart;
|
|
222
|
+
}
|
|
223
|
+
result += text.slice(cursor);
|
|
224
|
+
return result.replace(/\s+/g, ' ').trim();
|
|
225
|
+
}
|
|
206
226
|
/**
|
|
207
227
|
* Determine whether a criterion text contradicts an out-of-scope item.
|
|
208
228
|
* Uses substring match first, then keyword overlap as fuzzy fallback.
|
|
209
229
|
*/
|
|
210
230
|
function contradicts(criterionText, outOfScopeItem) {
|
|
211
|
-
const
|
|
231
|
+
const strippedCriterionText = stripMetadataMarkers(criterionText);
|
|
232
|
+
const normCriterion = normalize(strippedCriterionText);
|
|
212
233
|
const normScope = normalize(outOfScopeItem);
|
|
213
|
-
const clauses = splitClauses(
|
|
234
|
+
const clauses = splitClauses(strippedCriterionText);
|
|
214
235
|
const relevantClauses = clauses.filter((clause) => clauseMentionsScope(clause, outOfScopeItem));
|
|
215
236
|
const hasConditionalException = /\b(?:unless|except)\b/i.test(criterionText);
|
|
216
237
|
if (!hasConditionalException &&
|
|
@@ -26,14 +26,14 @@ function resolveHost(input) {
|
|
|
26
26
|
// ---------------------------------------------------------------------------
|
|
27
27
|
// Writers per host
|
|
28
28
|
// ---------------------------------------------------------------------------
|
|
29
|
-
async function writeSkillForClaudeCode(name, content, description, projectPath, overwrite) {
|
|
29
|
+
async function writeSkillForClaudeCode(name, content, description, projectPath, overwrite, managedByPlanu) {
|
|
30
30
|
const dirPath = join(projectPath, '.claude', 'skills', name);
|
|
31
31
|
const skillFilePath = join(dirPath, 'SKILL.md');
|
|
32
32
|
// Overwrite protection
|
|
33
33
|
try {
|
|
34
34
|
const existing = await readFile(skillFilePath, 'utf-8');
|
|
35
35
|
const existingHash = hashContent(existing);
|
|
36
|
-
const newContent = buildSkillMd(name, description, content);
|
|
36
|
+
const newContent = buildSkillMd(name, description, content, managedByPlanu);
|
|
37
37
|
const newHash = hashContent(newContent);
|
|
38
38
|
if (existingHash !== newHash && !overwrite) {
|
|
39
39
|
throw new Error(`Skill already exists at ${skillFilePath}. Pass overwriteExisting: true to replace.`);
|
|
@@ -46,13 +46,14 @@ async function writeSkillForClaudeCode(name, content, description, projectPath,
|
|
|
46
46
|
// File doesn't exist — proceed
|
|
47
47
|
}
|
|
48
48
|
await mkdir(dirPath, { recursive: true });
|
|
49
|
-
const skillContent = buildSkillMd(name, description, content);
|
|
49
|
+
const skillContent = buildSkillMd(name, description, content, managedByPlanu);
|
|
50
50
|
await writeFile(skillFilePath, skillContent, 'utf-8');
|
|
51
51
|
return { dirPath, skillFilePath };
|
|
52
52
|
}
|
|
53
|
-
function buildSkillMd(name, description, body) {
|
|
53
|
+
function buildSkillMd(name, description, body, managedByPlanu) {
|
|
54
54
|
const desc = description.length > 0 ? description : `Auto-generated skill: ${name}`;
|
|
55
|
-
|
|
55
|
+
const managedByLine = managedByPlanu ? 'managed-by: planu\n' : '';
|
|
56
|
+
return `---\nname: ${name}\ndescription: "${desc}"\n${managedByLine}---\n\n${body}\n`;
|
|
56
57
|
}
|
|
57
58
|
async function writeSkillForCodex(name, content, description, projectPath) {
|
|
58
59
|
// For Codex, append to AGENTS.md with markers
|
|
@@ -80,13 +81,13 @@ async function writeSkillForCodex(name, content, description, projectPath) {
|
|
|
80
81
|
await writeFile(agentsMdPath, updated, 'utf-8');
|
|
81
82
|
return { dirPath: projectPath, skillFilePath: agentsMdPath };
|
|
82
83
|
}
|
|
83
|
-
async function writeSkillForGemini(name, content, description, projectPath) {
|
|
84
|
+
async function writeSkillForGemini(name, content, description, projectPath, managedByPlanu) {
|
|
84
85
|
const geminiDir = join(projectPath, '.gemini');
|
|
85
86
|
const skillsDir = join(geminiDir, 'skills');
|
|
86
87
|
await mkdir(skillsDir, { recursive: true });
|
|
87
88
|
const skillFilePath = join(skillsDir, `${name}.md`);
|
|
88
89
|
const desc = description.length > 0 ? description : name;
|
|
89
|
-
const skillContent = buildSkillMd(name, desc, content);
|
|
90
|
+
const skillContent = buildSkillMd(name, desc, content, managedByPlanu);
|
|
90
91
|
await writeFile(skillFilePath, skillContent, 'utf-8');
|
|
91
92
|
return { dirPath: skillsDir, skillFilePath };
|
|
92
93
|
}
|
|
@@ -96,6 +97,7 @@ async function writeSkillForGemini(name, content, description, projectPath) {
|
|
|
96
97
|
export async function handleCreateSkill(input) {
|
|
97
98
|
const { projectPath, name, content, overwriteExisting } = input;
|
|
98
99
|
const description = input.description ?? '';
|
|
100
|
+
const managedByPlanu = input.managedByPlanu === true;
|
|
99
101
|
const host = resolveHost(input);
|
|
100
102
|
const languageValidation = validateEnglishOnlyArtifactText(`${name}\n\n${description}\n\n${content}`, 'skill');
|
|
101
103
|
if (!languageValidation.ok) {
|
|
@@ -121,13 +123,13 @@ export async function handleCreateSkill(input) {
|
|
|
121
123
|
try {
|
|
122
124
|
switch (host) {
|
|
123
125
|
case 'claude-code':
|
|
124
|
-
result = await writeSkillForClaudeCode(name, content, description, projectPath, overwriteExisting === true);
|
|
126
|
+
result = await writeSkillForClaudeCode(name, content, description, projectPath, overwriteExisting === true, managedByPlanu);
|
|
125
127
|
break;
|
|
126
128
|
case 'codex':
|
|
127
129
|
result = await writeSkillForCodex(name, content, description, projectPath);
|
|
128
130
|
break;
|
|
129
131
|
case 'gemini':
|
|
130
|
-
result = await writeSkillForGemini(name, content, description, projectPath);
|
|
132
|
+
result = await writeSkillForGemini(name, content, description, projectPath, managedByPlanu);
|
|
131
133
|
break;
|
|
132
134
|
}
|
|
133
135
|
}
|
|
@@ -12,6 +12,9 @@ const CORE_SKILL_TEMPLATES = [
|
|
|
12
12
|
'planu-native.md',
|
|
13
13
|
'planu-multi-teammate-review.md',
|
|
14
14
|
'planu-context-assets.md',
|
|
15
|
+
'planu-review.md',
|
|
16
|
+
'planu-implement.md',
|
|
17
|
+
'planu-dogfood-bug.md',
|
|
15
18
|
];
|
|
16
19
|
function addHost(hosts, host) {
|
|
17
20
|
if (!hosts.includes(host)) {
|
|
@@ -107,6 +110,9 @@ async function canRefreshCoreSkill(projectPath, host, name) {
|
|
|
107
110
|
return (existing.includes(`<!-- planu:skills:${name} -->`) ||
|
|
108
111
|
!existing.includes(`## Skill: ${name}`));
|
|
109
112
|
}
|
|
113
|
+
if (existing.includes('managed-by: planu')) {
|
|
114
|
+
return true;
|
|
115
|
+
}
|
|
110
116
|
return existing.includes(`name: ${name}`) && existing.includes(`# /${name}`);
|
|
111
117
|
}
|
|
112
118
|
catch {
|
|
@@ -130,6 +136,7 @@ async function installCoreSkillsForHost(projectPath, host) {
|
|
|
130
136
|
description: template.description,
|
|
131
137
|
content: template.content,
|
|
132
138
|
overwriteExisting: true,
|
|
139
|
+
managedByPlanu: true,
|
|
133
140
|
});
|
|
134
141
|
if (result.isError === true) {
|
|
135
142
|
continue;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@planu/cli",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.4.1",
|
|
4
4
|
"description": "Planu — MCP Server for Spec Driven Development. Cross-platform (Linux/macOS/Windows, x64/arm64).",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -129,7 +129,7 @@
|
|
|
129
129
|
],
|
|
130
130
|
"license": "SEE LICENSE IN LICENSE",
|
|
131
131
|
"dependencies": {
|
|
132
|
-
"@anthropic-ai/sdk": "^0.
|
|
132
|
+
"@anthropic-ai/sdk": "^0.122.0",
|
|
133
133
|
"@hono/node-server": "2.1.1",
|
|
134
134
|
"@modelcontextprotocol/sdk": "^1.30.0",
|
|
135
135
|
"glob": "^13.0.6",
|
|
@@ -142,40 +142,40 @@
|
|
|
142
142
|
"@commitlint/config-conventional": "^21.2.2",
|
|
143
143
|
"@eslint/js": "^10.0.1",
|
|
144
144
|
"@lhci/cli": "0.15.1",
|
|
145
|
-
"@noble/hashes": "2.
|
|
145
|
+
"@noble/hashes": "2.4.0",
|
|
146
146
|
"@playwright/test": "1.62.1",
|
|
147
147
|
"@scure/base": "2.3.0",
|
|
148
|
-
"@secretlint/secretlint-rule-no-homedir": "^13.0.
|
|
149
|
-
"@secretlint/secretlint-rule-preset-recommend": "^13.0.
|
|
150
|
-
"@stryker-mutator/core": "^
|
|
151
|
-
"@stryker-mutator/vitest-runner": "^
|
|
148
|
+
"@secretlint/secretlint-rule-no-homedir": "^13.0.5",
|
|
149
|
+
"@secretlint/secretlint-rule-preset-recommend": "^13.0.5",
|
|
150
|
+
"@stryker-mutator/core": "^10.0.0",
|
|
151
|
+
"@stryker-mutator/vitest-runner": "^10.0.0",
|
|
152
152
|
"@supabase/supabase-js": "^2.112.4",
|
|
153
|
-
"@types/node": "^26.
|
|
153
|
+
"@types/node": "^26.4.0",
|
|
154
154
|
"@types/qrcode": "1.5.6",
|
|
155
155
|
"@typescript/native": "npm:typescript@^7.0.2",
|
|
156
156
|
"@vitejs/plugin-vue": "^6.0.8",
|
|
157
157
|
"@vitest/coverage-v8": "^4.1.11",
|
|
158
|
-
"@vue/test-utils": "^2.
|
|
159
|
-
"eslint": "10.9.
|
|
158
|
+
"@vue/test-utils": "^2.5.0",
|
|
159
|
+
"eslint": "10.9.1",
|
|
160
160
|
"eslint-config-prettier": "^10.1.8",
|
|
161
161
|
"eslint-import-resolver-typescript": "^4.4.5",
|
|
162
162
|
"eslint-plugin-import": "^2.32.0",
|
|
163
|
-
"happy-dom": "^20.11.
|
|
163
|
+
"happy-dom": "^20.11.12",
|
|
164
164
|
"husky": "^9.1.7",
|
|
165
165
|
"javascript-obfuscator": "^5.6.0",
|
|
166
166
|
"jiti": "2.7.0",
|
|
167
|
-
"knip": "^6.32.
|
|
168
|
-
"lint-staged": "^17.
|
|
167
|
+
"knip": "^6.32.3",
|
|
168
|
+
"lint-staged": "^17.4.1",
|
|
169
169
|
"madge": "^8.0.0",
|
|
170
170
|
"prettier": "^3.9.6",
|
|
171
171
|
"qrcode": "1.5.4",
|
|
172
|
-
"secretlint": "^13.0.
|
|
172
|
+
"secretlint": "^13.0.5",
|
|
173
173
|
"tsc-alias": "^1.9.2",
|
|
174
174
|
"type-coverage": "^2.30.1",
|
|
175
175
|
"typescript": "npm:@typescript/typescript6@^6.0.2",
|
|
176
|
-
"typescript-eslint": "^8.
|
|
176
|
+
"typescript-eslint": "^8.68.0",
|
|
177
177
|
"vite": "^8.2.2",
|
|
178
178
|
"vitest": "^4.1.11",
|
|
179
|
-
"vue": "^3.5.
|
|
179
|
+
"vue": "^3.5.42"
|
|
180
180
|
}
|
|
181
181
|
}
|
package/planu-plugin.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "dev.planu.cli",
|
|
3
3
|
"displayName": "Planu — Spec Driven Development",
|
|
4
4
|
"description": "Manage software specs, estimations, and autonomous SDD workflows. Language-agnostic MCP server for Claude Code.",
|
|
5
|
-
"version": "5.
|
|
5
|
+
"version": "5.4.1",
|
|
6
6
|
"icon": "assets/plugin/icon.svg",
|
|
7
7
|
"command": ["npx", "@planu/cli@latest"],
|
|
8
8
|
"packageName": "@planu/cli",
|