@planu/cli 4.11.1 → 4.11.3
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 +16 -0
- package/dist/config/elicitation-questions.json +5 -17
- package/dist/engine/cascade-hooks/registry.js +0 -2
- package/dist/engine/challenge-scenarios-loader.d.ts +3 -3
- package/dist/engine/compliance-injector.d.ts +3 -3
- package/dist/engine/dashboard/kanban-logic.d.ts +1 -1
- package/dist/engine/doc-generator/portal/risk-matrix-svg.d.ts +1 -1
- package/dist/engine/doc-generator/proposal/proposal-generator.d.ts +1 -1
- package/dist/engine/elicitation/answer-extractor.d.ts +1 -4
- package/dist/engine/elicitation/answer-extractor.js +197 -68
- package/dist/engine/elicitation/decision-gap-detector.js +59 -79
- package/dist/engine/elicitation/index.d.ts +0 -1
- package/dist/engine/elicitation/index.js +0 -1
- package/dist/engine/elicitation/question-generator.js +10 -3
- package/dist/engine/elicitation/question-grounding-gate.js +83 -34
- package/dist/engine/evidence-gates/lifecycle-gate.js +27 -14
- package/dist/engine/evidence-index/index-builder.js +7 -2
- package/dist/engine/frontmatter-sha/frozen-fields.d.ts +1 -1
- package/dist/engine/handoff-artifacts/schemas/red-tests-handoff.d.ts +2 -2
- package/dist/engine/handoff-artifacts/schemas.d.ts +22 -22
- package/dist/engine/human-summary.js +3 -3
- package/dist/engine/implementation-contract/common.d.ts +1 -1
- package/dist/engine/implementation-contract/renderer.js +17 -39
- package/dist/engine/keyword-matcher/stopwords.d.ts +2 -2
- package/dist/engine/lifecycle-hints.d.ts +1 -1
- package/dist/engine/lifecycle-hints.js +13 -29
- package/dist/engine/provider-adapters/adapters/claude.d.ts +1 -1
- package/dist/engine/provider-adapters/adapters/gemini.d.ts +1 -1
- package/dist/engine/provider-adapters/adapters/gpt4.d.ts +1 -1
- package/dist/engine/provider-adapters/adapters/markdown.d.ts +1 -1
- package/dist/engine/safety/atomic-write-file.d.ts +1 -1
- package/dist/engine/safety/cross-process-lock.d.ts +1 -1
- package/dist/engine/safety/path-sanitizer.d.ts +1 -1
- package/dist/engine/security-analyzer/profile-detector.js +48 -16
- package/dist/engine/spec-format/copula-blacklist.d.ts +2 -2
- package/dist/engine/spec-format/lean-spec-generator.d.ts +2 -2
- package/dist/engine/spec-format/lean-spec-generator.js +9 -10
- package/dist/engine/spec-format/metadata-value-policy.d.ts +20 -20
- package/dist/engine/spec-generator/fallback-generator.js +13 -20
- package/dist/engine/spec-grounding/contract.d.ts +5 -0
- package/dist/engine/spec-grounding/contract.js +10 -6
- package/dist/engine/spec-migrator/lean-migration.js +9 -16
- package/dist/engine/text-signal-boundaries.js +45 -12
- package/dist/engine/universal-rules/rules/planu-modes.js +0 -2
- package/dist/engine/web-fetcher/stack-advisor.d.ts +2 -2
- package/dist/engine/web-fetcher/stack-advisor.js +78 -17
- package/dist/engine/well-known/manifest-schema.d.ts +33 -33
- package/dist/engine/workers/schema.d.ts +3 -3
- package/dist/hosts/claude-code/ux/mcp-resources.d.ts +4 -4
- package/dist/hosts/codex/rest-shim.d.ts +1 -1
- package/dist/native/lightweight-command-catalog.d.ts +30 -30
- package/dist/server/openapi-spec.d.ts +132 -132
- package/dist/tools/challenge-spec/challenge-report.d.ts +13 -0
- package/dist/tools/challenge-spec/challenge-report.js +55 -0
- package/dist/tools/challenge-spec/event-challenge-scenarios.js +8 -27
- package/dist/tools/challenge-spec/resilience-challenge-scenarios-a.js +16 -32
- package/dist/tools/challenge-spec/resilience-challenge-scenarios-b.js +15 -20
- package/dist/tools/challenge-spec/scenario-collector.d.ts +13 -0
- package/dist/tools/challenge-spec/scenario-collector.js +86 -0
- package/dist/tools/challenge-spec/scenarios-data.js +10 -9
- package/dist/tools/challenge-spec/scenarios-failure.js +38 -54
- package/dist/tools/challenge-spec/scenarios-scale.js +14 -15
- package/dist/tools/challenge-spec/scenarios-security.d.ts +1 -1
- package/dist/tools/challenge-spec/scenarios-security.js +18 -11
- package/dist/tools/challenge-spec/scenarios-utils.d.ts +31 -5
- package/dist/tools/challenge-spec/scenarios-utils.js +102 -6
- package/dist/tools/challenge-spec/security-challenge-scenarios.d.ts +1 -1
- package/dist/tools/challenge-spec/security-challenge-scenarios.js +20 -25
- package/dist/tools/challenge-spec.js +46 -124
- package/dist/tools/clarify-requirements/multiple-choice.js +1 -1
- package/dist/tools/clarify-requirements/questions-context.js +11 -11
- package/dist/tools/clarify-requirements/questions.js +3 -23
- package/dist/tools/clarify-requirements.js +38 -0
- package/dist/tools/compliance-gate-handler.d.ts +1 -1
- package/dist/tools/create-spec/autopilot-analyzer.d.ts +1 -1
- package/dist/tools/create-spec/autopilot-analyzer.js +29 -54
- package/dist/tools/create-spec/post-creation.js +23 -4
- package/dist/tools/create-spec.js +51 -168
- package/dist/tools/delete-first/suggest-deletions.d.ts +1 -1
- package/dist/tools/elicit-requirements-handler.js +20 -12
- package/dist/tools/generate-batch-script.d.ts +2 -2
- package/dist/tools/init-project/rules-generator.js +0 -1
- package/dist/tools/oauth-handler.d.ts +1 -1
- package/dist/tools/register-sdd-tools.d.ts +1 -1
- package/dist/tools/register-spec-tools/core-spec-tools.js +11 -2
- package/dist/tools/render-spec-for-provider.d.ts +2 -2
- package/dist/tools/scan-orphan-spec-refs.d.ts +6 -6
- package/dist/tools/schemas/agents.d.ts +7 -7
- package/dist/tools/schemas/analysis.d.ts +11 -11
- package/dist/tools/schemas/delete.d.ts +5 -5
- package/dist/tools/schemas/github.d.ts +4 -4
- package/dist/tools/schemas/ide-config.d.ts +12 -12
- package/dist/tools/schemas/infra.d.ts +9 -9
- package/dist/tools/schemas/lifecycle.d.ts +50 -50
- package/dist/tools/schemas/llm-provider-schemas.d.ts +7 -7
- package/dist/tools/schemas/plugins-schemas.d.ts +12 -12
- package/dist/tools/schemas/project-graph.d.ts +6 -6
- package/dist/tools/schemas/rbac.d.ts +2 -2
- package/dist/tools/schemas/registry.d.ts +3 -3
- package/dist/tools/schemas/runtime-security.d.ts +2 -2
- package/dist/tools/schemas/session.d.ts +2 -2
- package/dist/tools/schemas/spec.d.ts +15 -15
- package/dist/tools/schemas/token-intelligence.d.ts +6 -6
- package/dist/tools/schemas/token-optimization.d.ts +2 -2
- package/dist/tools/schemas/workers-schema.d.ts +4 -4
- package/dist/tools/skill-bootstrap-handler.d.ts +7 -7
- package/dist/tools/suggest-stack.js +49 -13
- package/dist/tools/tool-registry/deprecated-stubs.d.ts +1 -1
- package/dist/tools/triage-request.d.ts +3 -3
- package/dist/tools/update-status/dod-gates.d.ts +8 -0
- package/dist/tools/update-status/dod-gates.js +68 -43
- package/dist/tools/update-status/file-sync.d.ts +1 -1
- package/dist/tools/update-status/file-sync.js +10 -45
- package/dist/tools/update-status/index.js +133 -97
- package/dist/tools/update-status/qa-gate.js +26 -0
- package/dist/tools/update-status/response-builder.d.ts +1 -1
- package/dist/tools/update-status/response-builder.js +11 -19
- package/dist/tools/update-status/transition-guard.d.ts +2 -2
- package/dist/tools/update-status/transition-guard.js +11 -8
- package/dist/tools/update-status-actions.d.ts +0 -1
- package/dist/tools/update-status-actions.js +10 -26
- package/dist/tools/update-status-convention-gate.d.ts +1 -6
- package/dist/tools/update-status-convention-gate.js +9 -33
- package/dist/tools/validate-lint.d.ts +1 -1
- package/dist/tools/validate-lint.js +39 -1
- package/dist/types/docs.d.ts +0 -4
- package/dist/types/env.d.ts +0 -4
- package/dist/types/estimation.d.ts +0 -2
- package/dist/types/multi-teammate-review.d.ts +4 -4
- package/dist/types/plugin-install.d.ts +7 -7
- package/dist/types/spec/core.d.ts +20 -0
- package/dist/types/spec/inputs.d.ts +1 -1
- package/dist/types/stack/index.d.ts +1 -1
- package/dist/types/stack/recommend.d.ts +10 -0
- package/package.json +21 -18
- package/planu-native.json +1 -1
- package/planu-plugin.json +1 -1
- package/src/i18n/messages/en.json +0 -72
- package/src/i18n/messages/es.json +0 -72
- package/src/i18n/messages/pt.json +0 -72
- package/dist/config/elicitation-dimensions.json +0 -51
- package/dist/engine/actuals-estimator.d.ts +0 -14
- package/dist/engine/actuals-estimator.js +0 -64
- package/dist/engine/cascade-hooks/hooks/living-specs.hook.d.ts +0 -3
- package/dist/engine/cascade-hooks/hooks/living-specs.hook.js +0 -19
- package/dist/engine/elicitation/non-interactive-defaults.d.ts +0 -9
- package/dist/engine/elicitation/non-interactive-defaults.js +0 -28
- package/dist/engine/elicitation/option-builder.d.ts +0 -9
- package/dist/engine/elicitation/option-builder.js +0 -85
- package/dist/engine/progress-writer.d.ts +0 -10
- package/dist/engine/progress-writer.js +0 -63
- package/dist/tools/clarify-requirements/interview-mode.d.ts +0 -42
- package/dist/tools/clarify-requirements/interview-mode.js +0 -342
- package/dist/tools/update-status/mode-hints.d.ts +0 -4
- package/dist/tools/update-status/mode-hints.js +0 -24
|
@@ -133,10 +133,7 @@ export async function runImplementingActions(projectId, specId) {
|
|
|
133
133
|
return {
|
|
134
134
|
autoBranch,
|
|
135
135
|
protectedBranchWarning,
|
|
136
|
-
suggestions: [
|
|
137
|
-
'Run generate_execution_plan for a step-by-step implementation guide',
|
|
138
|
-
'Run generate_tests to scaffold test files',
|
|
139
|
-
],
|
|
136
|
+
suggestions: [],
|
|
140
137
|
autopilotSummary,
|
|
141
138
|
};
|
|
142
139
|
}
|
|
@@ -145,23 +142,7 @@ export async function runDoneActions(projectId, specId, gitBranch) {
|
|
|
145
142
|
// SPEC-628: Group A — fast synchronous checks only (< 100ms each)
|
|
146
143
|
// Validation removed: already done by runValidateGate in index.ts (BATCH B)
|
|
147
144
|
// -------------------------------------------------------------------------
|
|
148
|
-
const [
|
|
149
|
-
// SPEC-287: Suggest recording actual hours when spec has an estimation
|
|
150
|
-
(async () => {
|
|
151
|
-
try {
|
|
152
|
-
const spec = await specStore.getSpec(projectId, specId);
|
|
153
|
-
if (spec?.estimation) {
|
|
154
|
-
const estHours = spec.estimation.devHours + spec.estimation.reviewHours;
|
|
155
|
-
if (estHours > 0) {
|
|
156
|
-
return `Don't forget to record actual hours: record_actual({ specId: "${specId}", actualHours: <N> }) — estimated: ${String(estHours)}h`;
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
catch {
|
|
161
|
-
// best-effort — never blocks transition
|
|
162
|
-
}
|
|
163
|
-
return null;
|
|
164
|
-
})(),
|
|
145
|
+
const [uncommittedResult] = await Promise.allSettled([
|
|
165
146
|
// Warn if non-planu changes remain. Planu autocommit/staging is opt-in only.
|
|
166
147
|
(async () => {
|
|
167
148
|
try {
|
|
@@ -189,7 +170,6 @@ export async function runDoneActions(projectId, specId, gitBranch) {
|
|
|
189
170
|
return null;
|
|
190
171
|
})(),
|
|
191
172
|
]);
|
|
192
|
-
const recordActualHint = recordActualResult.status === 'fulfilled' ? recordActualResult.value : null;
|
|
193
173
|
const uncommittedWarning = uncommittedResult.status === 'fulfilled' ? uncommittedResult.value : null;
|
|
194
174
|
// -------------------------------------------------------------------------
|
|
195
175
|
// SPEC-628: Group B — merge-check only (PR generation moved to Group C)
|
|
@@ -198,12 +178,17 @@ export async function runDoneActions(projectId, specId, gitBranch) {
|
|
|
198
178
|
if (gitBranch) {
|
|
199
179
|
const mergeResult = await Promise.resolve((async () => {
|
|
200
180
|
try {
|
|
201
|
-
const { resolveProjectPath, git: gitCmd } = await import('./git/git-helpers.js');
|
|
181
|
+
const { resolveProjectPath, resolveBaseBranch, git: gitCmd, } = await import('./git/git-helpers.js');
|
|
202
182
|
const projectPath = await resolveProjectPath(projectId);
|
|
203
|
-
|
|
183
|
+
await gitCmd(projectPath, ['rev-parse', '--verify', gitBranch]);
|
|
184
|
+
const baseBranch = await resolveBaseBranch(projectPath);
|
|
185
|
+
if (!baseBranch) {
|
|
186
|
+
return null;
|
|
187
|
+
}
|
|
188
|
+
const { stdout } = await gitCmd(projectPath, ['branch', '--merged', baseBranch]);
|
|
204
189
|
const mergedBranches = stdout.split('\n').map((b) => b.trim().replace('* ', ''));
|
|
205
190
|
if (!mergedBranches.includes(gitBranch)) {
|
|
206
|
-
return `Branch '${gitBranch}' has not been merged to
|
|
191
|
+
return `Branch '${gitBranch}' has not been merged to '${baseBranch}' yet.`;
|
|
207
192
|
}
|
|
208
193
|
}
|
|
209
194
|
catch {
|
|
@@ -325,7 +310,6 @@ export async function runDoneActions(projectId, specId, gitBranch) {
|
|
|
325
310
|
prSuggestion: null,
|
|
326
311
|
validationWarning: null,
|
|
327
312
|
uncommittedWarning,
|
|
328
|
-
recordActualHint,
|
|
329
313
|
autopilotSummary,
|
|
330
314
|
};
|
|
331
315
|
}
|
|
@@ -1,11 +1,6 @@
|
|
|
1
1
|
import type { SpecStatus, ComplianceGateResult } from '../types/index.js';
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
4
|
-
* Returns warning messages for critical violations (non-blocking, best-effort).
|
|
5
|
-
*/
|
|
6
|
-
export declare function checkConventionGate(projectId: string): Promise<string[]>;
|
|
7
|
-
/**
|
|
8
|
-
* Runs all non-blocking compliance gates (convention + constitution + compile + lint + test)
|
|
3
|
+
* Runs non-blocking transition checks not already covered by the authoritative validate report.
|
|
9
4
|
* in parallel. Extracts complexity from handleUpdateStatus.
|
|
10
5
|
*/
|
|
11
6
|
export declare function runComplianceGates(projectId: string, specTitle: string, specTags: string[], newStatus: SpecStatus): Promise<ComplianceGateResult>;
|
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
import { execFile as execFileCb } from 'node:child_process';
|
|
4
4
|
import { promisify } from 'node:util';
|
|
5
5
|
import { knowledgeStore } from '../storage/index.js';
|
|
6
|
-
import { parseConventions, scanConventions } from '../engine/convention-scanner/index.js';
|
|
7
6
|
import { checkConstitutionOnTransition } from './update-status-actions.js';
|
|
8
7
|
const execFile = promisify(execFileCb);
|
|
9
8
|
// ---------------------------------------------------------------------------
|
|
@@ -121,38 +120,10 @@ function isFailureSummaryLine(line) {
|
|
|
121
120
|
return /\b(?:FAIL|failed|failing|error|errored)\b/i.test(trimmed);
|
|
122
121
|
}
|
|
123
122
|
// ---------------------------------------------------------------------------
|
|
124
|
-
// Convention gate (existing logic, unchanged)
|
|
125
|
-
// ---------------------------------------------------------------------------
|
|
126
|
-
/**
|
|
127
|
-
* Checks for critical convention violations before allowing a spec to be marked as done.
|
|
128
|
-
* Returns warning messages for critical violations (non-blocking, best-effort).
|
|
129
|
-
*/
|
|
130
|
-
export async function checkConventionGate(projectId) {
|
|
131
|
-
try {
|
|
132
|
-
const knowledge = await knowledgeStore.getKnowledge(projectId);
|
|
133
|
-
if (!knowledge?.projectPath) {
|
|
134
|
-
return [];
|
|
135
|
-
}
|
|
136
|
-
const rules = parseConventions(knowledge.projectPath);
|
|
137
|
-
if (rules.length === 0) {
|
|
138
|
-
return [];
|
|
139
|
-
}
|
|
140
|
-
const violations = scanConventions(knowledge.projectPath, rules);
|
|
141
|
-
const critical = violations.filter((v) => v.severity === 'critical');
|
|
142
|
-
if (critical.length === 0) {
|
|
143
|
-
return [];
|
|
144
|
-
}
|
|
145
|
-
return critical.slice(0, 5).map((v) => `${v.category}: ${v.message} (${v.file})`);
|
|
146
|
-
}
|
|
147
|
-
catch {
|
|
148
|
-
return [];
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
// ---------------------------------------------------------------------------
|
|
152
123
|
// Main gate runner
|
|
153
124
|
// ---------------------------------------------------------------------------
|
|
154
125
|
/**
|
|
155
|
-
* Runs
|
|
126
|
+
* Runs non-blocking transition checks not already covered by the authoritative validate report.
|
|
156
127
|
* in parallel. Extracts complexity from handleUpdateStatus.
|
|
157
128
|
*/
|
|
158
129
|
export async function runComplianceGates(projectId, specTitle, specTags, newStatus) {
|
|
@@ -161,8 +132,7 @@ export async function runComplianceGates(projectId, specTitle, specTags, newStat
|
|
|
161
132
|
// Load knowledge once — needed for project path and commands
|
|
162
133
|
const knowledge = isDone ? await knowledgeStore.getKnowledge(projectId) : null;
|
|
163
134
|
const projectPath = knowledge?.projectPath ?? null;
|
|
164
|
-
const [
|
|
165
|
-
isDone ? checkConventionGate(projectId) : Promise.resolve([]),
|
|
135
|
+
const [constitutionWarnings, compileWarnings, lintWarnings, testWarnings] = await Promise.all([
|
|
166
136
|
isApprovedOrDone
|
|
167
137
|
? checkConstitutionOnTransition(projectId, specTitle, specTags)
|
|
168
138
|
: Promise.resolve([]),
|
|
@@ -176,6 +146,12 @@ export async function runComplianceGates(projectId, specTitle, specTags, newStat
|
|
|
176
146
|
? checkTestGate(projectPath, knowledge?.testCommand ?? null)
|
|
177
147
|
: Promise.resolve([]),
|
|
178
148
|
]);
|
|
179
|
-
return {
|
|
149
|
+
return {
|
|
150
|
+
conventionWarnings: [],
|
|
151
|
+
constitutionWarnings,
|
|
152
|
+
compileWarnings,
|
|
153
|
+
lintWarnings,
|
|
154
|
+
testWarnings,
|
|
155
|
+
};
|
|
180
156
|
}
|
|
181
157
|
//# sourceMappingURL=update-status-convention-gate.js.map
|
|
@@ -3,6 +3,6 @@ interface LintCheckContext {
|
|
|
3
3
|
projectId?: string;
|
|
4
4
|
specId?: string;
|
|
5
5
|
}
|
|
6
|
-
export declare function runLintCheck(projectPath: string, lintCommand: string | null,
|
|
6
|
+
export declare function runLintCheck(projectPath: string, lintCommand: string | null, context?: LintCheckContext): LintCheckResult;
|
|
7
7
|
export {};
|
|
8
8
|
//# sourceMappingURL=validate-lint.d.ts.map
|
|
@@ -3,6 +3,7 @@ import { execFileSync } from 'node:child_process';
|
|
|
3
3
|
import { createHash } from 'node:crypto';
|
|
4
4
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
5
5
|
import { dirname, join } from 'node:path';
|
|
6
|
+
import { projectDataDir } from '../storage/base-store.js';
|
|
6
7
|
import { formatLintFailureDiagnostics, resolveProjectCommandPlan, runProjectCommandPlan, } from './validate-runtime.js';
|
|
7
8
|
/** Allowlist: alphanumerics, spaces, and safe shell chars. Rejects ; | $ ` & < > */
|
|
8
9
|
const SAFE_COMMAND_RE = /^[\w\s./:@~=-]+$/;
|
|
@@ -39,7 +40,7 @@ function parseLintIssueCount(output) {
|
|
|
39
40
|
}
|
|
40
41
|
return output.split('\n').filter((l) => l.trim().length > 0).length;
|
|
41
42
|
}
|
|
42
|
-
export function runLintCheck(projectPath, lintCommand,
|
|
43
|
+
export function runLintCheck(projectPath, lintCommand, context = {}) {
|
|
43
44
|
if (lintCommand !== null && !isSafeCommand(lintCommand)) {
|
|
44
45
|
console.warn(`[Planu] validate: lintCommand contains unsafe characters — skipping execution`);
|
|
45
46
|
return {
|
|
@@ -50,6 +51,10 @@ export function runLintCheck(projectPath, lintCommand, _context = {}) {
|
|
|
50
51
|
};
|
|
51
52
|
}
|
|
52
53
|
const command = lintCommand ?? 'pnpm lint';
|
|
54
|
+
const externalEvidence = readExternalPassedLintEvidence(context, command);
|
|
55
|
+
if (externalEvidence !== null) {
|
|
56
|
+
return externalEvidence;
|
|
57
|
+
}
|
|
53
58
|
const plan = resolveProjectCommandPlan(projectPath, command);
|
|
54
59
|
const fingerprint = calculateLintFingerprint(projectPath);
|
|
55
60
|
const cached = readPassedLintCache(projectPath, command, fingerprint);
|
|
@@ -77,6 +82,39 @@ export function runLintCheck(projectPath, lintCommand, _context = {}) {
|
|
|
77
82
|
return { passed: false, command, issueCount, output };
|
|
78
83
|
}
|
|
79
84
|
}
|
|
85
|
+
function readExternalPassedLintEvidence(context, command) {
|
|
86
|
+
if (!context.projectId || !context.specId) {
|
|
87
|
+
return null;
|
|
88
|
+
}
|
|
89
|
+
try {
|
|
90
|
+
const path = join(projectDataDir(context.projectId), 'handoffs', context.specId, 'traceability-matrix.json');
|
|
91
|
+
if (!existsSync(path)) {
|
|
92
|
+
return null;
|
|
93
|
+
}
|
|
94
|
+
const parsed = JSON.parse(readFileSync(path, 'utf-8'));
|
|
95
|
+
const rows = Array.isArray(parsed.rows) ? parsed.rows : [];
|
|
96
|
+
if (rows.length === 0 ||
|
|
97
|
+
!rows.every((row) => isPassedFullValidationEvidence(row.validationEvidence))) {
|
|
98
|
+
return null;
|
|
99
|
+
}
|
|
100
|
+
return {
|
|
101
|
+
passed: true,
|
|
102
|
+
command,
|
|
103
|
+
issueCount: 0,
|
|
104
|
+
output: `(reused external validation evidence from handoffs/${context.specId}/traceability-matrix.json)`,
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
catch {
|
|
108
|
+
return null;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
function isPassedFullValidationEvidence(value) {
|
|
112
|
+
if (typeof value !== 'string') {
|
|
113
|
+
return false;
|
|
114
|
+
}
|
|
115
|
+
return (/\bpnpm\s+validate\b[\s\S]{0,160}\bpass(?:ed|ing)?\b/i.test(value) ||
|
|
116
|
+
/\bpass(?:ed|ing)?\b[\s\S]{0,160}\bpnpm\s+validate\b/i.test(value));
|
|
117
|
+
}
|
|
80
118
|
function lintCheckTimeoutMs() {
|
|
81
119
|
const raw = process.env.PLANU_VALIDATE_LINT_TIMEOUT_MS;
|
|
82
120
|
if (raw === undefined || raw.trim() === '') {
|
package/dist/types/docs.d.ts
CHANGED
|
@@ -165,10 +165,6 @@ export interface PerSpecReportData {
|
|
|
165
165
|
estimationReasoning?: string;
|
|
166
166
|
similarSpecs?: string[];
|
|
167
167
|
}
|
|
168
|
-
export interface ProgressSection {
|
|
169
|
-
title: string;
|
|
170
|
-
content: string;
|
|
171
|
-
}
|
|
172
168
|
export interface NavItem {
|
|
173
169
|
path: string;
|
|
174
170
|
title: string;
|
package/dist/types/env.d.ts
CHANGED
|
@@ -27,8 +27,6 @@ export interface Actuals {
|
|
|
27
27
|
totalCostUsd: number;
|
|
28
28
|
completedAt: string;
|
|
29
29
|
notes: string;
|
|
30
|
-
/** True when token/cost fields were auto-estimated (agent did not provide them) */
|
|
31
|
-
estimated?: boolean;
|
|
32
30
|
}
|
|
33
31
|
export interface ImpactAnalysis {
|
|
34
32
|
affectedModules: string[];
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
export declare const SeveritySchema: z.ZodEnum<{
|
|
3
3
|
critical: "critical";
|
|
4
|
-
suggestion: "suggestion";
|
|
5
|
-
nit: "nit";
|
|
6
4
|
"false-positive": "false-positive";
|
|
5
|
+
nit: "nit";
|
|
6
|
+
suggestion: "suggestion";
|
|
7
7
|
}>;
|
|
8
8
|
export type Severity = z.infer<typeof SeveritySchema>;
|
|
9
9
|
export declare const SpecialistRoleSchema: z.ZodEnum<{
|
|
10
10
|
architecture: "architecture";
|
|
11
|
-
security: "security";
|
|
12
|
-
performance: "performance";
|
|
13
11
|
correctness: "correctness";
|
|
14
12
|
maintainability: "maintainability";
|
|
13
|
+
performance: "performance";
|
|
14
|
+
security: "security";
|
|
15
15
|
}>;
|
|
16
16
|
export type SpecialistRole = z.infer<typeof SpecialistRoleSchema>;
|
|
17
17
|
export interface SpecialistFinding {
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import type { PluginErrorType, PluginInstallError } from './plugins.js';
|
|
3
3
|
export declare const PluginInstallModeSchema: z.ZodEnum<{
|
|
4
|
-
recommended: "recommended";
|
|
5
4
|
full: "full";
|
|
6
5
|
minimal: "minimal";
|
|
6
|
+
recommended: "recommended";
|
|
7
7
|
}>;
|
|
8
8
|
export declare const StackSignalSchema: z.ZodObject<{
|
|
9
9
|
name: z.ZodString;
|
|
10
10
|
confidence: z.ZodEnum<{
|
|
11
|
+
high: "high";
|
|
11
12
|
low: "low";
|
|
12
13
|
medium: "medium";
|
|
13
|
-
high: "high";
|
|
14
14
|
}>;
|
|
15
15
|
source: z.ZodString;
|
|
16
16
|
}, z.core.$strip>;
|
|
@@ -19,8 +19,8 @@ export declare const PluginRecommendationSchema: z.ZodObject<{
|
|
|
19
19
|
displayName: z.ZodString;
|
|
20
20
|
tier: z.ZodEnum<{
|
|
21
21
|
always: "always";
|
|
22
|
-
"stack-matched": "stack-matched";
|
|
23
22
|
optional: "optional";
|
|
23
|
+
"stack-matched": "stack-matched";
|
|
24
24
|
}>;
|
|
25
25
|
stacks: z.ZodArray<z.ZodString>;
|
|
26
26
|
description: z.ZodString;
|
|
@@ -33,8 +33,8 @@ export declare const PluginInstallPlanSchema: z.ZodObject<{
|
|
|
33
33
|
displayName: z.ZodString;
|
|
34
34
|
tier: z.ZodEnum<{
|
|
35
35
|
always: "always";
|
|
36
|
-
"stack-matched": "stack-matched";
|
|
37
36
|
optional: "optional";
|
|
37
|
+
"stack-matched": "stack-matched";
|
|
38
38
|
}>;
|
|
39
39
|
stacks: z.ZodArray<z.ZodString>;
|
|
40
40
|
description: z.ZodString;
|
|
@@ -44,25 +44,25 @@ export declare const PluginInstallPlanSchema: z.ZodObject<{
|
|
|
44
44
|
displayName: z.ZodString;
|
|
45
45
|
tier: z.ZodEnum<{
|
|
46
46
|
always: "always";
|
|
47
|
-
"stack-matched": "stack-matched";
|
|
48
47
|
optional: "optional";
|
|
48
|
+
"stack-matched": "stack-matched";
|
|
49
49
|
}>;
|
|
50
50
|
stacks: z.ZodArray<z.ZodString>;
|
|
51
51
|
description: z.ZodString;
|
|
52
52
|
}, z.core.$strip>>;
|
|
53
53
|
detectedStacks: z.ZodArray<z.ZodString>;
|
|
54
54
|
mode: z.ZodEnum<{
|
|
55
|
-
recommended: "recommended";
|
|
56
55
|
full: "full";
|
|
57
56
|
minimal: "minimal";
|
|
57
|
+
recommended: "recommended";
|
|
58
58
|
}>;
|
|
59
59
|
}, z.core.$strip>;
|
|
60
60
|
export declare const PluginInstallResultSchema: z.ZodObject<{
|
|
61
61
|
projectPath: z.ZodString;
|
|
62
62
|
mode: z.ZodEnum<{
|
|
63
|
-
recommended: "recommended";
|
|
64
63
|
full: "full";
|
|
65
64
|
minimal: "minimal";
|
|
65
|
+
recommended: "recommended";
|
|
66
66
|
}>;
|
|
67
67
|
dryRun: z.ZodBoolean;
|
|
68
68
|
marketplaceAdded: z.ZodBoolean;
|
|
@@ -112,6 +112,26 @@ export interface ChallengeReport {
|
|
|
112
112
|
overallRisk: 'low' | 'medium' | 'high' | 'critical';
|
|
113
113
|
/** Whether the challenge passed the mandatory gate. */
|
|
114
114
|
passed: boolean;
|
|
115
|
+
/** Findings discovered by the challenge run and their evidence-derived state. */
|
|
116
|
+
findings?: ChallengeFinding[];
|
|
117
|
+
/** Explicit mitigation or risk-acceptance evidence for resolved findings. */
|
|
118
|
+
resolutionEvidence?: ChallengeResolutionEvidence[];
|
|
119
|
+
}
|
|
120
|
+
export interface ChallengeFinding {
|
|
121
|
+
/** Exact scenario text emitted by challenge_spec. */
|
|
122
|
+
scenario: string;
|
|
123
|
+
/** Derived from matching explicit resolution evidence; discovery alone is never resolution. */
|
|
124
|
+
resolved: boolean;
|
|
125
|
+
}
|
|
126
|
+
export interface ChallengeResolutionEvidence {
|
|
127
|
+
/** Exact scenario text being resolved. */
|
|
128
|
+
scenario: string;
|
|
129
|
+
/** Whether the scenario was mitigated or explicitly accepted as a known risk. */
|
|
130
|
+
resolution: 'mitigated' | 'accepted';
|
|
131
|
+
/** Concrete proof or rationale supporting the resolution. */
|
|
132
|
+
evidence: string;
|
|
133
|
+
/** When the resolution was recorded. */
|
|
134
|
+
resolvedAt: string;
|
|
115
135
|
}
|
|
116
136
|
/** SPEC-630: Model and token budget derived from spec difficulty and devHours. */
|
|
117
137
|
export interface ModelBudget {
|
|
@@ -21,7 +21,7 @@ export interface CreateSpecInput {
|
|
|
21
21
|
* Required when the previous response contained interactiveQuestions[].
|
|
22
22
|
*/
|
|
23
23
|
clarificationAnswers?: Record<string, string>;
|
|
24
|
-
/**
|
|
24
|
+
/** Explicit user-confirmed out-of-scope items. Omitted values are not inferred. */
|
|
25
25
|
outOfScope?: string[];
|
|
26
26
|
/** SPEC-697: Spec ID for agent team findings synthesis path. Required with agentTeamFindings. */
|
|
27
27
|
specId?: string;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export type { StackRecommendation, SuggestStackResult, PackageRegistry, DependencyStatus, CheckVersionsResult, SkillFile, GenerateSkillResult, AgentConfig, SubAgentDefinition, GenerateSubAgentResult, GenerateRulesResult, SuggestStackInput, CheckVersionsInput, GenerateSkillInput, GenerateSubAgentInput, GenerateRulesInput, DetectAgentInput, DetectAgentResult, GenerateOrchestrationScriptInput, PlatformConfig, PlatformsConfig, RuleSection, LanguageSignature, FrameworkSignature, PackageManagerSignature, DatabaseSignature, StackSignatures, ArchPatternConfig, ArchPatternsFile, FrameworkConfig, AgentPlatformsConfig, } from './recommend.js';
|
|
1
|
+
export type { StackRecommendation, StackAdviceGrounding, SuggestStackResult, PackageRegistry, DependencyStatus, CheckVersionsResult, SkillFile, GenerateSkillResult, AgentConfig, SubAgentDefinition, GenerateSubAgentResult, GenerateRulesResult, SuggestStackInput, CheckVersionsInput, GenerateSkillInput, GenerateSubAgentInput, GenerateRulesInput, DetectAgentInput, DetectAgentResult, GenerateOrchestrationScriptInput, PlatformConfig, PlatformsConfig, RuleSection, LanguageSignature, FrameworkSignature, PackageManagerSignature, DatabaseSignature, StackSignatures, ArchPatternConfig, ArchPatternsFile, FrameworkConfig, AgentPlatformsConfig, } from './recommend.js';
|
|
2
2
|
export type { DependencyStatusCode, DepSeverity, AuditedDependency, StackHealthScore, StackAuditResult, RuntimeVersionStatus, StackAuditDelta, UpgradeRiskLevel, UpgradeBreakingChange, UpgradePlan, StackAuditConfig, ManifestData, AuditStackOptions, AuditStackInput, PlanUpgradeInput, VulnerableRange, KnownVulnerablePackage, } from './audit.js';
|
|
3
3
|
export type { DeprecationSeverity, DeprecationFinding, DeprecationReport, DeprecationPattern, DetectDeprecationsInput, } from './deprecation.js';
|
|
4
4
|
export type { HypermediaFramework, RenderingMode, TurboSubtype, HypermediaDetectionResult, TemplateEngineSignal, } from './hypermedia.js';
|
|
@@ -26,6 +26,16 @@ export interface SuggestStackResult {
|
|
|
26
26
|
lastChecked: string;
|
|
27
27
|
confidence?: 'high' | 'medium' | 'low';
|
|
28
28
|
}
|
|
29
|
+
export interface StackAdviceGrounding {
|
|
30
|
+
selectionStatus: 'unconfirmed' | 'partially-confirmed';
|
|
31
|
+
detectedEvidence: string[];
|
|
32
|
+
confirmedChoices: {
|
|
33
|
+
field: string;
|
|
34
|
+
value: string;
|
|
35
|
+
source: 'user_confirmation';
|
|
36
|
+
}[];
|
|
37
|
+
candidateNotice: string;
|
|
38
|
+
}
|
|
29
39
|
export type PackageRegistry = 'npm' | 'pypi' | 'crates' | 'go' | 'packagist' | 'pub' | 'nuget' | 'rubygems';
|
|
30
40
|
export interface DependencyStatus {
|
|
31
41
|
name: string;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@planu/cli",
|
|
3
|
-
"version": "4.11.
|
|
3
|
+
"version": "4.11.3",
|
|
4
4
|
"description": "Planu — MCP Server for Spec Driven Development with native Rust acceleration for hot paths. Cross-platform (Linux/macOS/Windows, x64/arm64, glibc/musl).",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -34,14 +34,14 @@
|
|
|
34
34
|
"packageName": "@planu/core"
|
|
35
35
|
},
|
|
36
36
|
"optionalDependencies": {
|
|
37
|
-
"@planu/core-darwin-arm64": "4.11.
|
|
38
|
-
"@planu/core-darwin-x64": "4.11.
|
|
39
|
-
"@planu/core-linux-arm64-gnu": "4.11.
|
|
40
|
-
"@planu/core-linux-arm64-musl": "4.11.
|
|
41
|
-
"@planu/core-linux-x64-gnu": "4.11.
|
|
42
|
-
"@planu/core-linux-x64-musl": "4.11.
|
|
43
|
-
"@planu/core-win32-arm64-msvc": "4.11.
|
|
44
|
-
"@planu/core-win32-x64-msvc": "4.11.
|
|
37
|
+
"@planu/core-darwin-arm64": "4.11.3",
|
|
38
|
+
"@planu/core-darwin-x64": "4.11.3",
|
|
39
|
+
"@planu/core-linux-arm64-gnu": "4.11.3",
|
|
40
|
+
"@planu/core-linux-arm64-musl": "4.11.3",
|
|
41
|
+
"@planu/core-linux-x64-gnu": "4.11.3",
|
|
42
|
+
"@planu/core-linux-x64-musl": "4.11.3",
|
|
43
|
+
"@planu/core-win32-arm64-msvc": "4.11.3",
|
|
44
|
+
"@planu/core-win32-x64-msvc": "4.11.3"
|
|
45
45
|
},
|
|
46
46
|
"engines": {
|
|
47
47
|
"node": ">=24.0.0"
|
|
@@ -55,7 +55,7 @@
|
|
|
55
55
|
"release:local:all": "bash scripts/release-local.sh --all",
|
|
56
56
|
"release:publish": "bash scripts/release-local.sh --all --publish",
|
|
57
57
|
"build": "pnpm clean && pnpm build:rust && pnpm build:ts",
|
|
58
|
-
"build:ts": "tsc -p tsconfig.build.json && tsc-alias -p tsconfig.build.json && node scripts/copy-runtime-assets.mjs",
|
|
58
|
+
"build:ts": "pnpm clean && tsc -p tsconfig.build.json && tsc-alias -p tsconfig.build.json && node scripts/copy-runtime-assets.mjs",
|
|
59
59
|
"build:obfuscated": "pnpm build && node scripts/obfuscate.mjs",
|
|
60
60
|
"dev": "tsc --watch",
|
|
61
61
|
"start": "node dist/index.js",
|
|
@@ -66,6 +66,8 @@
|
|
|
66
66
|
"format": "prettier --write 'src/**/*.ts' 'tests/**/*.test.ts'",
|
|
67
67
|
"format:check": "prettier --check 'src/**/*.ts' 'tests/**/*.test.ts'",
|
|
68
68
|
"typecheck": "tsc --noEmit",
|
|
69
|
+
"typecheck:compat": "tsc6 --noEmit",
|
|
70
|
+
"verify:typescript-migration": "node scripts/verify-typescript-migration.mjs",
|
|
69
71
|
"test": "vitest run",
|
|
70
72
|
"test:watch": "vitest",
|
|
71
73
|
"test:coverage": "vitest run --coverage --exclude 'tests/integration/**'",
|
|
@@ -87,9 +89,9 @@
|
|
|
87
89
|
"setup:protection": "bash scripts/setup-branch-protection.sh",
|
|
88
90
|
"prepare": "husky || true",
|
|
89
91
|
"prepublishOnly": "bash scripts/prepublish-guard.sh",
|
|
90
|
-
"prepack": "pnpm
|
|
92
|
+
"prepack": "pnpm build:ts && pnpm package:size",
|
|
91
93
|
"test:debug": "vitest run --inspect-brk --single-thread",
|
|
92
|
-
"validate": "pnpm typecheck && pnpm lint && pnpm format:check && pnpm test",
|
|
94
|
+
"validate": "pnpm typecheck && pnpm verify:typescript-migration && pnpm lint && pnpm format:check && pnpm test",
|
|
93
95
|
"docker:build": "docker build -t planu .",
|
|
94
96
|
"docker:run": "docker compose up",
|
|
95
97
|
"publish:blog": "node scripts/publish-blog.mjs",
|
|
@@ -138,7 +140,7 @@
|
|
|
138
140
|
"zod": "^4.4.3"
|
|
139
141
|
},
|
|
140
142
|
"devDependencies": {
|
|
141
|
-
"@commitlint/cli": "^21.2.
|
|
143
|
+
"@commitlint/cli": "^21.2.1",
|
|
142
144
|
"@commitlint/config-conventional": "^21.2.0",
|
|
143
145
|
"@eslint/js": "^10.0.1",
|
|
144
146
|
"@napi-rs/cli": "^3.7.2",
|
|
@@ -146,8 +148,9 @@
|
|
|
146
148
|
"@secretlint/secretlint-rule-preset-recommend": "^13.0.2",
|
|
147
149
|
"@stryker-mutator/core": "^9.6.1",
|
|
148
150
|
"@stryker-mutator/vitest-runner": "^9.6.1",
|
|
149
|
-
"@supabase/supabase-js": "^2.110.
|
|
150
|
-
"@types/node": "^26.1.
|
|
151
|
+
"@supabase/supabase-js": "^2.110.2",
|
|
152
|
+
"@types/node": "^26.1.1",
|
|
153
|
+
"@typescript/native": "npm:typescript@^7.0.2",
|
|
151
154
|
"@vitejs/plugin-vue": "^6.0.7",
|
|
152
155
|
"@vitest/coverage-v8": "^4.1.10",
|
|
153
156
|
"@vue/test-utils": "^2.4.11",
|
|
@@ -157,7 +160,7 @@
|
|
|
157
160
|
"eslint-plugin-import": "^2.32.0",
|
|
158
161
|
"happy-dom": "^20.10.6",
|
|
159
162
|
"husky": "^9.1.7",
|
|
160
|
-
"javascript-obfuscator": "^5.4.
|
|
163
|
+
"javascript-obfuscator": "^5.4.5",
|
|
161
164
|
"knip": "^6.25.0",
|
|
162
165
|
"lint-staged": "^17.0.8",
|
|
163
166
|
"madge": "^8.0.0",
|
|
@@ -165,9 +168,9 @@
|
|
|
165
168
|
"secretlint": "^13.0.2",
|
|
166
169
|
"tsc-alias": "^1.9.0",
|
|
167
170
|
"type-coverage": "^2.29.7",
|
|
168
|
-
"typescript": "
|
|
171
|
+
"typescript": "npm:@typescript/typescript6@^6.0.2",
|
|
169
172
|
"typescript-eslint": "^8.63.0",
|
|
170
|
-
"vite": "^8.1.
|
|
173
|
+
"vite": "^8.1.4",
|
|
171
174
|
"vitest": "^4.1.10",
|
|
172
175
|
"vue": "^3.5.39"
|
|
173
176
|
}
|
package/planu-native.json
CHANGED
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": "4.11.
|
|
5
|
+
"version": "4.11.3",
|
|
6
6
|
"icon": "assets/plugin/icon.svg",
|
|
7
7
|
"command": [
|
|
8
8
|
"npx",
|
|
@@ -558,77 +558,5 @@
|
|
|
558
558
|
"description": "Get a complete overview of a project — specs, progress, and health metrics",
|
|
559
559
|
"message": "Give me a complete status overview for project {projectId}.\n\nPlease:\n1. List all specs grouped by status (draft, review, approved, implementing, done)\n2. Show overall progress (how many specs are done vs total)\n3. Highlight any specs that might need attention:\n - Specs stuck in 'implementing' for a long time\n - Specs in 'draft' that haven't been reviewed\n - Any specs with drift detected\n4. Summarize the project health in plain language"
|
|
560
560
|
}
|
|
561
|
-
},
|
|
562
|
-
"questions": {
|
|
563
|
-
"target": {
|
|
564
|
-
"question": "What area does this feature target?",
|
|
565
|
-
"header": "Target",
|
|
566
|
-
"frontend": "Frontend",
|
|
567
|
-
"frontendDesc": "UI components, pages, styling",
|
|
568
|
-
"backend": "Backend",
|
|
569
|
-
"backendDesc": "API, server logic, database",
|
|
570
|
-
"fullstack": "Fullstack (Recommended)",
|
|
571
|
-
"fullstackDesc": "Both frontend and backend changes",
|
|
572
|
-
"infra": "Infrastructure",
|
|
573
|
-
"infraDesc": "CI/CD, deployment, config"
|
|
574
|
-
},
|
|
575
|
-
"payment": {
|
|
576
|
-
"providerQuestion": "Which payment provider will this integrate with?",
|
|
577
|
-
"providerHeader": "Payment Provider",
|
|
578
|
-
"stripe": "Stripe (Recommended)",
|
|
579
|
-
"stripeDesc": "Cards, subscriptions, invoicing",
|
|
580
|
-
"paypal": "PayPal",
|
|
581
|
-
"paypalDesc": "PayPal checkout and subscriptions",
|
|
582
|
-
"paddle": "Paddle",
|
|
583
|
-
"paddleDesc": "SaaS-focused, handles taxes",
|
|
584
|
-
"other": "Other / custom",
|
|
585
|
-
"otherDesc": "Specify in the description",
|
|
586
|
-
"modelQuestion": "What subscription / billing model does this need?",
|
|
587
|
-
"modelHeader": "Billing Model",
|
|
588
|
-
"oneTime": "One-time payment",
|
|
589
|
-
"oneTimeDesc": "Single charge per purchase",
|
|
590
|
-
"recurring": "Recurring subscription (Recommended)",
|
|
591
|
-
"recurringDesc": "Monthly or annual plans",
|
|
592
|
-
"usageBased": "Usage-based",
|
|
593
|
-
"usageBasedDesc": "Charged per unit consumed",
|
|
594
|
-
"freemium": "Freemium + paid tiers",
|
|
595
|
-
"freemiumDesc": "Free tier with upgrades"
|
|
596
|
-
},
|
|
597
|
-
"scope": {
|
|
598
|
-
"question": "What is the scope of this change?",
|
|
599
|
-
"header": "Scope",
|
|
600
|
-
"feature": "Feature (Recommended)",
|
|
601
|
-
"featureDesc": "New functionality in a single module",
|
|
602
|
-
"crossModule": "Cross-module",
|
|
603
|
-
"crossModuleDesc": "Changes spanning multiple modules",
|
|
604
|
-
"trivial": "Trivial",
|
|
605
|
-
"trivialDesc": "Small fix or config change",
|
|
606
|
-
"architectural": "Architectural",
|
|
607
|
-
"architecturalDesc": "Structural change affecting the whole system"
|
|
608
|
-
},
|
|
609
|
-
"database": {
|
|
610
|
-
"question": "Does this feature involve database changes?",
|
|
611
|
-
"header": "Database",
|
|
612
|
-
"none": "No database changes",
|
|
613
|
-
"noneDesc": "Pure frontend or logic change",
|
|
614
|
-
"schema": "New table/columns (Recommended)",
|
|
615
|
-
"schemaDesc": "Schema migration needed",
|
|
616
|
-
"rls": "RLS policies",
|
|
617
|
-
"rlsDesc": "Row Level Security changes",
|
|
618
|
-
"rpc": "RPC functions",
|
|
619
|
-
"rpcDesc": "New or modified database functions"
|
|
620
|
-
},
|
|
621
|
-
"uiType": {
|
|
622
|
-
"question": "What type of UI work is involved?",
|
|
623
|
-
"header": "UI Type",
|
|
624
|
-
"newComponent": "New component (Recommended)",
|
|
625
|
-
"newComponentDesc": "Build from scratch",
|
|
626
|
-
"modify": "Modify existing",
|
|
627
|
-
"modifyDesc": "Change an existing component",
|
|
628
|
-
"serverAction": "Server Action",
|
|
629
|
-
"serverActionDesc": "Backend logic triggered from UI",
|
|
630
|
-
"noUi": "No UI changes",
|
|
631
|
-
"noUiDesc": "Backend only"
|
|
632
|
-
}
|
|
633
561
|
}
|
|
634
562
|
}
|