jumpstart-mode 1.1.11 → 1.1.13
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/.github/agents/jumpstart-adversary.agent.md +2 -1
- package/.github/agents/jumpstart-architect.agent.md +6 -7
- package/.github/agents/jumpstart-challenger.agent.md +2 -1
- package/.github/agents/jumpstart-developer.agent.md +1 -1
- package/.github/agents/jumpstart-devops.agent.md +2 -2
- package/.github/agents/jumpstart-diagram-verifier.agent.md +2 -1
- package/.github/agents/jumpstart-maintenance.agent.md +1 -0
- package/.github/agents/jumpstart-performance.agent.md +1 -0
- package/.github/agents/jumpstart-pm.agent.md +1 -1
- package/.github/agents/jumpstart-refactor.agent.md +1 -0
- package/.github/agents/jumpstart-requirements-extractor.agent.md +1 -0
- package/.github/agents/jumpstart-researcher.agent.md +1 -0
- package/.github/agents/jumpstart-retrospective.agent.md +1 -0
- package/.github/agents/jumpstart-reviewer.agent.md +2 -0
- package/.github/agents/jumpstart-scout.agent.md +1 -1
- package/.github/agents/jumpstart-scrum-master.agent.md +1 -0
- package/.github/agents/jumpstart-security.agent.md +2 -1
- package/.github/agents/jumpstart-tech-writer.agent.md +1 -0
- package/.github/agents/jumpstart-uiux-designer.agent.md +66 -0
- package/.github/workflows/quality.yml +19 -2
- package/.jumpstart/agents/analyst.md +38 -0
- package/.jumpstart/agents/architect.md +39 -1
- package/.jumpstart/agents/challenger.md +38 -0
- package/.jumpstart/agents/developer.md +41 -0
- package/.jumpstart/agents/pm.md +38 -0
- package/.jumpstart/agents/scout.md +33 -0
- package/.jumpstart/agents/ux-designer.md +29 -9
- package/.jumpstart/commands/commands.md +6 -5
- package/.jumpstart/config.yaml +25 -1
- package/.jumpstart/roadmap.md +1 -1
- package/.jumpstart/schemas/timeline.schema.json +1 -0
- package/.jumpstart/skills/README.md +1 -0
- package/.jumpstart/skills/quality-gates/SKILL.md +126 -0
- package/.jumpstart/skills/skill-creator/SKILL.md +485 -357
- package/.jumpstart/skills/skill-creator/agents/analyzer.md +274 -0
- package/.jumpstart/skills/skill-creator/agents/comparator.md +202 -0
- package/.jumpstart/skills/skill-creator/agents/grader.md +223 -0
- package/.jumpstart/skills/skill-creator/assets/eval_review.html +146 -0
- package/.jumpstart/skills/skill-creator/eval-viewer/generate_review.py +471 -0
- package/.jumpstart/skills/skill-creator/eval-viewer/viewer.html +1325 -0
- package/.jumpstart/skills/skill-creator/references/schemas.md +430 -0
- package/.jumpstart/skills/skill-creator/scripts/__init__.py +0 -0
- package/.jumpstart/skills/skill-creator/scripts/aggregate_benchmark.py +401 -0
- package/.jumpstart/skills/skill-creator/scripts/generate_report.py +326 -0
- package/.jumpstart/skills/skill-creator/scripts/improve_description.py +247 -0
- package/.jumpstart/skills/skill-creator/scripts/package_skill.py +136 -110
- package/.jumpstart/skills/skill-creator/scripts/run_eval.py +310 -0
- package/.jumpstart/skills/skill-creator/scripts/run_loop.py +328 -0
- package/.jumpstart/skills/skill-creator/scripts/utils.py +47 -0
- package/.jumpstart/skills/ui-ux-pro-max/SKILL.md +266 -0
- package/.jumpstart/skills/ui-ux-pro-max/data/charts.csv +26 -0
- package/.jumpstart/skills/ui-ux-pro-max/data/colors.csv +97 -0
- package/.jumpstart/skills/ui-ux-pro-max/data/icons.csv +101 -0
- package/.jumpstart/skills/ui-ux-pro-max/data/landing.csv +31 -0
- package/.jumpstart/skills/ui-ux-pro-max/data/products.csv +97 -0
- package/.jumpstart/skills/ui-ux-pro-max/data/react-performance.csv +45 -0
- package/.jumpstart/skills/ui-ux-pro-max/data/stacks/astro.csv +54 -0
- package/.jumpstart/skills/ui-ux-pro-max/data/stacks/flutter.csv +53 -0
- package/.jumpstart/skills/ui-ux-pro-max/data/stacks/html-tailwind.csv +56 -0
- package/.jumpstart/skills/ui-ux-pro-max/data/stacks/jetpack-compose.csv +53 -0
- package/.jumpstart/skills/ui-ux-pro-max/data/stacks/nextjs.csv +53 -0
- package/.jumpstart/skills/ui-ux-pro-max/data/stacks/nuxt-ui.csv +51 -0
- package/.jumpstart/skills/ui-ux-pro-max/data/stacks/nuxtjs.csv +59 -0
- package/.jumpstart/skills/ui-ux-pro-max/data/stacks/react-native.csv +52 -0
- package/.jumpstart/skills/ui-ux-pro-max/data/stacks/react.csv +54 -0
- package/.jumpstart/skills/ui-ux-pro-max/data/stacks/shadcn.csv +61 -0
- package/.jumpstart/skills/ui-ux-pro-max/data/stacks/svelte.csv +54 -0
- package/.jumpstart/skills/ui-ux-pro-max/data/stacks/swiftui.csv +51 -0
- package/.jumpstart/skills/ui-ux-pro-max/data/stacks/vue.csv +50 -0
- package/.jumpstart/skills/ui-ux-pro-max/data/styles.csv +68 -0
- package/.jumpstart/skills/ui-ux-pro-max/data/typography.csv +58 -0
- package/.jumpstart/skills/ui-ux-pro-max/data/ui-reasoning.csv +101 -0
- package/.jumpstart/skills/ui-ux-pro-max/data/ux-guidelines.csv +100 -0
- package/.jumpstart/skills/ui-ux-pro-max/data/web-interface.csv +31 -0
- package/.jumpstart/skills/ui-ux-pro-max/scripts/core.py +253 -0
- package/.jumpstart/skills/ui-ux-pro-max/scripts/design_system.py +1067 -0
- package/.jumpstart/skills/ui-ux-pro-max/scripts/search.py +114 -0
- package/.jumpstart/state/timeline.json +659 -0
- package/.jumpstart/templates/model-map.md +1 -1
- package/.jumpstart/templates/ux-design.md +3 -3
- package/.jumpstart/usage-log.json +74 -3
- package/AGENTS.md +1 -1
- package/README.md +64 -3
- package/bin/cli.js +3217 -1
- package/bin/headless-runner.js +62 -2
- package/bin/lib/agent-checkpoint.js +168 -0
- package/bin/lib/ai-evaluation.js +104 -0
- package/bin/lib/ai-intake.js +152 -0
- package/bin/lib/ambiguity-heatmap.js +152 -0
- package/bin/lib/artifact-comparison.js +104 -0
- package/bin/lib/ast-edit-engine.js +157 -0
- package/bin/lib/backlog-sync.js +338 -0
- package/bin/lib/bcdr-planning.js +158 -0
- package/bin/lib/bidirectional-trace.js +199 -0
- package/bin/lib/branch-workflow.js +266 -0
- package/bin/lib/cab-output.js +119 -0
- package/bin/lib/chat-integration.js +122 -0
- package/bin/lib/ci-cd-integration.js +208 -0
- package/bin/lib/codebase-retrieval.js +125 -0
- package/bin/lib/collaboration.js +168 -0
- package/bin/lib/compliance-packs.js +213 -0
- package/bin/lib/context-chunker.js +128 -0
- package/bin/lib/context-onboarding.js +122 -0
- package/bin/lib/contract-first.js +124 -0
- package/bin/lib/cost-router.js +148 -0
- package/bin/lib/credential-boundary.js +155 -0
- package/bin/lib/data-classification.js +180 -0
- package/bin/lib/data-contracts.js +129 -0
- package/bin/lib/db-evolution.js +158 -0
- package/bin/lib/decision-conflicts.js +299 -0
- package/bin/lib/delivery-confidence.js +361 -0
- package/bin/lib/dependency-upgrade.js +153 -0
- package/bin/lib/design-system.js +133 -0
- package/bin/lib/deterministic-artifacts.js +151 -0
- package/bin/lib/diagram-studio.js +115 -0
- package/bin/lib/domain-ontology.js +140 -0
- package/bin/lib/ea-review-packet.js +151 -0
- package/bin/lib/enterprise-search.js +123 -0
- package/bin/lib/enterprise-templates.js +140 -0
- package/bin/lib/environment-promotion.js +220 -0
- package/bin/lib/estimation-studio.js +130 -0
- package/bin/lib/event-modeling.js +133 -0
- package/bin/lib/evidence-collector.js +179 -0
- package/bin/lib/finops-planner.js +182 -0
- package/bin/lib/fitness-functions.js +279 -0
- package/bin/lib/focus.js +448 -0
- package/bin/lib/governance-dashboard.js +165 -0
- package/bin/lib/guided-handoff.js +120 -0
- package/bin/lib/impact-analysis.js +190 -0
- package/bin/lib/incident-feedback.js +157 -0
- package/bin/lib/integrate.js +1 -1
- package/bin/lib/knowledge-graph.js +122 -0
- package/bin/lib/legacy-modernizer.js +160 -0
- package/bin/lib/migration-planner.js +144 -0
- package/bin/lib/model-governance.js +185 -0
- package/bin/lib/model-router.js +144 -0
- package/bin/lib/multi-repo.js +272 -0
- package/bin/lib/next-phase.js +53 -8
- package/bin/lib/ops-ownership.js +152 -0
- package/bin/lib/parallel-agents.js +257 -0
- package/bin/lib/pattern-library.js +115 -0
- package/bin/lib/persona-packs.js +99 -0
- package/bin/lib/plan-executor.js +366 -0
- package/bin/lib/platform-engineering.js +119 -0
- package/bin/lib/playback-summaries.js +126 -0
- package/bin/lib/policy-engine.js +240 -0
- package/bin/lib/portfolio-reporting.js +357 -0
- package/bin/lib/pr-package.js +197 -0
- package/bin/lib/project-memory.js +235 -0
- package/bin/lib/prompt-governance.js +130 -0
- package/bin/lib/promptless-mode.js +128 -0
- package/bin/lib/quality-graph.js +193 -0
- package/bin/lib/raci-matrix.js +188 -0
- package/bin/lib/refactor-planner.js +167 -0
- package/bin/lib/reference-architectures.js +304 -0
- package/bin/lib/release-readiness.js +171 -0
- package/bin/lib/repo-graph.js +262 -0
- package/bin/lib/requirements-baseline.js +358 -0
- package/bin/lib/risk-register.js +211 -0
- package/bin/lib/role-approval.js +249 -0
- package/bin/lib/role-views.js +142 -0
- package/bin/lib/root-cause-analysis.js +132 -0
- package/bin/lib/runtime-debugger.js +154 -0
- package/bin/lib/safe-rename.js +135 -0
- package/bin/lib/secret-scanner.js +313 -0
- package/bin/lib/semantic-diff.js +335 -0
- package/bin/lib/sla-slo.js +210 -0
- package/bin/lib/smoke-tester.js +344 -0
- package/bin/lib/spec-comments.js +147 -0
- package/bin/lib/spec-maturity.js +287 -0
- package/bin/lib/sre-integration.js +154 -0
- package/bin/lib/structured-elicitation.js +174 -0
- package/bin/lib/telemetry-feedback.js +118 -0
- package/bin/lib/test-generator.js +146 -0
- package/bin/lib/timeline.js +2 -1
- package/bin/lib/tool-bridge.js +159 -0
- package/bin/lib/tool-guardrails.js +139 -0
- package/bin/lib/tool-schemas.js +281 -3
- package/bin/lib/transcript-ingestion.js +150 -0
- package/bin/lib/type-checker.js +261 -0
- package/bin/lib/uat-coverage.js +411 -0
- package/bin/lib/vendor-risk.js +173 -0
- package/bin/lib/waiver-workflow.js +174 -0
- package/bin/lib/web-dashboard.js +126 -0
- package/bin/lib/workshop-mode.js +165 -0
- package/bin/lib/workstream-ownership.js +104 -0
- package/package.json +1 -1
- package/.github/agents/jumpstart-ux-designer.agent.md +0 -45
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* pr-package.js — PR-Native Execution Mode
|
|
3
|
+
*
|
|
4
|
+
* Creates PR-ready work packages with summary, risk notes, test evidence,
|
|
5
|
+
* and rollback guidance — ready to attach to a pull request.
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
* node bin/lib/pr-package.js create|export [options]
|
|
9
|
+
*
|
|
10
|
+
* Output file: .jumpstart/pr-packages/<id>.md
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
'use strict';
|
|
14
|
+
|
|
15
|
+
const fs = require('fs');
|
|
16
|
+
const path = require('path');
|
|
17
|
+
|
|
18
|
+
const DEFAULT_OUTPUT_DIR = path.join('.jumpstart', 'pr-packages');
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Gather test evidence by scanning test results files.
|
|
22
|
+
*
|
|
23
|
+
* @param {string} root
|
|
24
|
+
* @returns {string[]} Evidence snippets.
|
|
25
|
+
*/
|
|
26
|
+
function gatherTestEvidence(root) {
|
|
27
|
+
const evidence = [];
|
|
28
|
+
const candidatePaths = [
|
|
29
|
+
path.join(root, 'test-results.json'),
|
|
30
|
+
path.join(root, 'coverage', 'summary.json'),
|
|
31
|
+
path.join(root, '.vitest', 'results.json')
|
|
32
|
+
];
|
|
33
|
+
|
|
34
|
+
for (const p of candidatePaths) {
|
|
35
|
+
if (fs.existsSync(p)) {
|
|
36
|
+
try {
|
|
37
|
+
const data = JSON.parse(fs.readFileSync(p, 'utf8'));
|
|
38
|
+
evidence.push(`Test results from ${path.relative(root, p)}: ${JSON.stringify(data).slice(0, 200)}`);
|
|
39
|
+
} catch {
|
|
40
|
+
evidence.push(`Test results found at: ${path.relative(root, p)}`);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return evidence;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Create a PR work package.
|
|
50
|
+
*
|
|
51
|
+
* @param {object} pkg - Work package definition.
|
|
52
|
+
* pkg.title - PR title.
|
|
53
|
+
* pkg.summary - Plain-English summary of changes.
|
|
54
|
+
* pkg.changes - Array of changed files or descriptions.
|
|
55
|
+
* pkg.risk_notes - Risk notes (string or array).
|
|
56
|
+
* pkg.test_evidence - Optional test evidence (string or array).
|
|
57
|
+
* pkg.rollback - Rollback guidance string.
|
|
58
|
+
* pkg.linked_stories - Array of story/task IDs.
|
|
59
|
+
* @param {string} root
|
|
60
|
+
* @param {object} [options]
|
|
61
|
+
* @returns {object}
|
|
62
|
+
*/
|
|
63
|
+
function createPRPackage(pkg, root, options = {}) {
|
|
64
|
+
if (!pkg || !pkg.title || !pkg.summary) {
|
|
65
|
+
return { success: false, error: 'pkg.title and pkg.summary are required' };
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const id = `pr-${Date.now()}-${Math.random().toString(36).slice(2, 7)}`;
|
|
69
|
+
const outputDir = options.outputDir || path.join(root, DEFAULT_OUTPUT_DIR);
|
|
70
|
+
const outputFile = path.join(outputDir, `${id}.md`);
|
|
71
|
+
|
|
72
|
+
// Gather auto-detected test evidence if none provided
|
|
73
|
+
let testEvidence = pkg.test_evidence || [];
|
|
74
|
+
if (typeof testEvidence === 'string') testEvidence = [testEvidence];
|
|
75
|
+
if (testEvidence.length === 0) {
|
|
76
|
+
testEvidence = gatherTestEvidence(root);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const changes = Array.isArray(pkg.changes) ? pkg.changes : [pkg.changes || ''].filter(Boolean);
|
|
80
|
+
const riskNotes = Array.isArray(pkg.risk_notes) ? pkg.risk_notes : [pkg.risk_notes || 'None identified'].filter(Boolean);
|
|
81
|
+
const linkedStories = Array.isArray(pkg.linked_stories) ? pkg.linked_stories : [];
|
|
82
|
+
|
|
83
|
+
const now = new Date().toISOString();
|
|
84
|
+
|
|
85
|
+
const lines = [
|
|
86
|
+
`# PR Work Package: ${pkg.title}`,
|
|
87
|
+
'',
|
|
88
|
+
`**ID:** ${id}`,
|
|
89
|
+
`**Created:** ${now}`,
|
|
90
|
+
'',
|
|
91
|
+
'## Summary',
|
|
92
|
+
'',
|
|
93
|
+
pkg.summary,
|
|
94
|
+
'',
|
|
95
|
+
'## Changes',
|
|
96
|
+
'',
|
|
97
|
+
...changes.map(c => `- ${c}`),
|
|
98
|
+
'',
|
|
99
|
+
'## Linked Stories / Tasks',
|
|
100
|
+
'',
|
|
101
|
+
linkedStories.length > 0 ? linkedStories.map(s => `- ${s}`).join('\n') : '- None specified',
|
|
102
|
+
'',
|
|
103
|
+
'## Risk Notes',
|
|
104
|
+
'',
|
|
105
|
+
...riskNotes.map(r => `- ${r}`),
|
|
106
|
+
'',
|
|
107
|
+
'## Test Evidence',
|
|
108
|
+
'',
|
|
109
|
+
testEvidence.length > 0
|
|
110
|
+
? testEvidence.map(e => `- ${e}`).join('\n')
|
|
111
|
+
: '- No automated test results found. Run tests before merging.',
|
|
112
|
+
'',
|
|
113
|
+
'## Rollback Guidance',
|
|
114
|
+
'',
|
|
115
|
+
pkg.rollback || 'No specific rollback steps documented. Revert the PR commits.',
|
|
116
|
+
'',
|
|
117
|
+
'---',
|
|
118
|
+
'',
|
|
119
|
+
`*Generated by JumpStart PR-Native Execution Mode*`
|
|
120
|
+
];
|
|
121
|
+
|
|
122
|
+
const content = lines.join('\n');
|
|
123
|
+
|
|
124
|
+
if (!fs.existsSync(outputDir)) {
|
|
125
|
+
fs.mkdirSync(outputDir, { recursive: true });
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
fs.writeFileSync(outputFile, content, 'utf8');
|
|
129
|
+
|
|
130
|
+
return {
|
|
131
|
+
success: true,
|
|
132
|
+
id,
|
|
133
|
+
output_file: outputFile,
|
|
134
|
+
title: pkg.title,
|
|
135
|
+
changes_count: changes.length,
|
|
136
|
+
risk_count: riskNotes.length,
|
|
137
|
+
has_test_evidence: testEvidence.length > 0
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* List all existing PR packages.
|
|
143
|
+
*
|
|
144
|
+
* @param {string} root
|
|
145
|
+
* @param {object} [options]
|
|
146
|
+
* @returns {object}
|
|
147
|
+
*/
|
|
148
|
+
function listPRPackages(root, options = {}) {
|
|
149
|
+
const outputDir = options.outputDir || path.join(root, DEFAULT_OUTPUT_DIR);
|
|
150
|
+
|
|
151
|
+
if (!fs.existsSync(outputDir)) {
|
|
152
|
+
return { success: true, packages: [], total: 0 };
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
const files = fs.readdirSync(outputDir)
|
|
156
|
+
.filter(f => f.endsWith('.md'))
|
|
157
|
+
.map(f => {
|
|
158
|
+
const filePath = path.join(outputDir, f);
|
|
159
|
+
const stat = fs.statSync(filePath);
|
|
160
|
+
return {
|
|
161
|
+
id: path.basename(f, '.md'),
|
|
162
|
+
file: path.relative(root, filePath).replace(/\\/g, '/'),
|
|
163
|
+
created_at: stat.birthtime.toISOString(),
|
|
164
|
+
size_bytes: stat.size
|
|
165
|
+
};
|
|
166
|
+
})
|
|
167
|
+
.sort((a, b) => b.created_at.localeCompare(a.created_at));
|
|
168
|
+
|
|
169
|
+
return { success: true, packages: files, total: files.length };
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Export a PR package as a string (for copying into PR description).
|
|
174
|
+
*
|
|
175
|
+
* @param {string} packageId
|
|
176
|
+
* @param {string} root
|
|
177
|
+
* @param {object} [options]
|
|
178
|
+
* @returns {object}
|
|
179
|
+
*/
|
|
180
|
+
function exportPRPackage(packageId, root, options = {}) {
|
|
181
|
+
const outputDir = options.outputDir || path.join(root, DEFAULT_OUTPUT_DIR);
|
|
182
|
+
const filePath = path.join(outputDir, `${packageId}.md`);
|
|
183
|
+
|
|
184
|
+
if (!fs.existsSync(filePath)) {
|
|
185
|
+
return { success: false, error: `PR package not found: ${packageId}` };
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
const content = fs.readFileSync(filePath, 'utf8');
|
|
189
|
+
return { success: true, id: packageId, content };
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
module.exports = {
|
|
193
|
+
createPRPackage,
|
|
194
|
+
listPRPackages,
|
|
195
|
+
exportPRPackage,
|
|
196
|
+
gatherTestEvidence
|
|
197
|
+
};
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* project-memory.js — Persistent Long-Term Project Memory
|
|
3
|
+
*
|
|
4
|
+
* Captures team decisions, rejected options, recurring pitfalls, and
|
|
5
|
+
* tribal knowledge beyond artifact files. Acts as an ever-growing
|
|
6
|
+
* organizational knowledge base for the project.
|
|
7
|
+
*
|
|
8
|
+
* Usage:
|
|
9
|
+
* node bin/lib/project-memory.js add|list|search|recall [options]
|
|
10
|
+
*
|
|
11
|
+
* State file: .jumpstart/state/project-memory.json
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
'use strict';
|
|
15
|
+
|
|
16
|
+
const fs = require('fs');
|
|
17
|
+
const path = require('path');
|
|
18
|
+
|
|
19
|
+
const DEFAULT_MEMORY_FILE = path.join('.jumpstart', 'state', 'project-memory.json');
|
|
20
|
+
|
|
21
|
+
const MEMORY_TYPES = ['decision', 'rejection', 'pitfall', 'tribal', 'insight', 'other'];
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Default memory store structure.
|
|
25
|
+
* @returns {object}
|
|
26
|
+
*/
|
|
27
|
+
function defaultMemoryStore() {
|
|
28
|
+
return {
|
|
29
|
+
version: '1.0.0',
|
|
30
|
+
created_at: new Date().toISOString(),
|
|
31
|
+
last_updated: null,
|
|
32
|
+
entries: []
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Load the memory store from disk.
|
|
38
|
+
* @param {string} [memoryFile]
|
|
39
|
+
* @returns {object}
|
|
40
|
+
*/
|
|
41
|
+
function loadMemoryStore(memoryFile) {
|
|
42
|
+
const filePath = memoryFile || DEFAULT_MEMORY_FILE;
|
|
43
|
+
if (!fs.existsSync(filePath)) {
|
|
44
|
+
return defaultMemoryStore();
|
|
45
|
+
}
|
|
46
|
+
try {
|
|
47
|
+
return JSON.parse(fs.readFileSync(filePath, 'utf8'));
|
|
48
|
+
} catch {
|
|
49
|
+
return defaultMemoryStore();
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Save the memory store to disk.
|
|
55
|
+
* @param {object} store
|
|
56
|
+
* @param {string} [memoryFile]
|
|
57
|
+
*/
|
|
58
|
+
function saveMemoryStore(store, memoryFile) {
|
|
59
|
+
const filePath = memoryFile || DEFAULT_MEMORY_FILE;
|
|
60
|
+
const dir = path.dirname(filePath);
|
|
61
|
+
if (!fs.existsSync(dir)) {
|
|
62
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
63
|
+
}
|
|
64
|
+
store.last_updated = new Date().toISOString();
|
|
65
|
+
fs.writeFileSync(filePath, JSON.stringify(store, null, 2) + '\n', 'utf8');
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Add a new memory entry to the store.
|
|
70
|
+
*
|
|
71
|
+
* @param {object} entry - { type, title, content, tags?, author?, phase? }
|
|
72
|
+
* @param {object} [options]
|
|
73
|
+
* @returns {object}
|
|
74
|
+
*/
|
|
75
|
+
function addMemory(entry, options = {}) {
|
|
76
|
+
if (!entry || !entry.title || !entry.content) {
|
|
77
|
+
return { success: false, error: 'entry.title and entry.content are required' };
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const type = (entry.type || 'other').toLowerCase();
|
|
81
|
+
if (!MEMORY_TYPES.includes(type)) {
|
|
82
|
+
return { success: false, error: `type must be one of: ${MEMORY_TYPES.join(', ')}` };
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const memoryFile = options.memoryFile || DEFAULT_MEMORY_FILE;
|
|
86
|
+
const store = loadMemoryStore(memoryFile);
|
|
87
|
+
|
|
88
|
+
const id = `mem-${Date.now()}-${Math.random().toString(36).slice(2, 7)}`;
|
|
89
|
+
const newEntry = {
|
|
90
|
+
id,
|
|
91
|
+
type,
|
|
92
|
+
title: entry.title.trim(),
|
|
93
|
+
content: entry.content.trim(),
|
|
94
|
+
tags: Array.isArray(entry.tags) ? entry.tags : [],
|
|
95
|
+
author: entry.author || null,
|
|
96
|
+
phase: entry.phase !== undefined ? entry.phase : null,
|
|
97
|
+
created_at: new Date().toISOString(),
|
|
98
|
+
updated_at: new Date().toISOString()
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
store.entries.push(newEntry);
|
|
102
|
+
saveMemoryStore(store, memoryFile);
|
|
103
|
+
|
|
104
|
+
return { success: true, entry: newEntry, total: store.entries.length };
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* List memory entries, optionally filtered.
|
|
109
|
+
*
|
|
110
|
+
* @param {object} [filter] - { type?, tag?, phase? }
|
|
111
|
+
* @param {object} [options]
|
|
112
|
+
* @returns {object}
|
|
113
|
+
*/
|
|
114
|
+
function listMemories(filter = {}, options = {}) {
|
|
115
|
+
const memoryFile = options.memoryFile || DEFAULT_MEMORY_FILE;
|
|
116
|
+
const store = loadMemoryStore(memoryFile);
|
|
117
|
+
|
|
118
|
+
let entries = store.entries;
|
|
119
|
+
|
|
120
|
+
if (filter.type) {
|
|
121
|
+
entries = entries.filter(e => e.type === filter.type);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
if (filter.tag) {
|
|
125
|
+
entries = entries.filter(e => e.tags && e.tags.includes(filter.tag));
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
if (filter.phase !== undefined && filter.phase !== null) {
|
|
129
|
+
entries = entries.filter(e => e.phase === filter.phase);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
return { success: true, entries, total: entries.length };
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Search memory entries by keyword in title or content.
|
|
137
|
+
*
|
|
138
|
+
* @param {string} keyword
|
|
139
|
+
* @param {object} [options]
|
|
140
|
+
* @returns {object}
|
|
141
|
+
*/
|
|
142
|
+
function searchMemories(keyword, options = {}) {
|
|
143
|
+
if (!keyword || typeof keyword !== 'string') {
|
|
144
|
+
return { success: false, error: 'keyword is required' };
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
const memoryFile = options.memoryFile || DEFAULT_MEMORY_FILE;
|
|
148
|
+
const store = loadMemoryStore(memoryFile);
|
|
149
|
+
|
|
150
|
+
const lower = keyword.toLowerCase();
|
|
151
|
+
const entries = store.entries.filter(
|
|
152
|
+
e =>
|
|
153
|
+
e.title.toLowerCase().includes(lower) ||
|
|
154
|
+
e.content.toLowerCase().includes(lower) ||
|
|
155
|
+
(e.tags && e.tags.some(t => t.toLowerCase().includes(lower)))
|
|
156
|
+
);
|
|
157
|
+
|
|
158
|
+
return { success: true, keyword, entries, total: entries.length };
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Recall (get) a specific memory entry by ID.
|
|
163
|
+
*
|
|
164
|
+
* @param {string} id
|
|
165
|
+
* @param {object} [options]
|
|
166
|
+
* @returns {object}
|
|
167
|
+
*/
|
|
168
|
+
function recallMemory(id, options = {}) {
|
|
169
|
+
const memoryFile = options.memoryFile || DEFAULT_MEMORY_FILE;
|
|
170
|
+
const store = loadMemoryStore(memoryFile);
|
|
171
|
+
|
|
172
|
+
const entry = store.entries.find(e => e.id === id);
|
|
173
|
+
if (!entry) {
|
|
174
|
+
return { success: false, error: `Memory entry not found: ${id}` };
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
return { success: true, entry };
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Delete a memory entry by ID.
|
|
182
|
+
*
|
|
183
|
+
* @param {string} id
|
|
184
|
+
* @param {object} [options]
|
|
185
|
+
* @returns {object}
|
|
186
|
+
*/
|
|
187
|
+
function deleteMemory(id, options = {}) {
|
|
188
|
+
const memoryFile = options.memoryFile || DEFAULT_MEMORY_FILE;
|
|
189
|
+
const store = loadMemoryStore(memoryFile);
|
|
190
|
+
|
|
191
|
+
const idx = store.entries.findIndex(e => e.id === id);
|
|
192
|
+
if (idx === -1) {
|
|
193
|
+
return { success: false, error: `Memory entry not found: ${id}` };
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
const [removed] = store.entries.splice(idx, 1);
|
|
197
|
+
saveMemoryStore(store, memoryFile);
|
|
198
|
+
|
|
199
|
+
return { success: true, removed, total: store.entries.length };
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* Get memory statistics grouped by type.
|
|
204
|
+
*
|
|
205
|
+
* @param {object} [options]
|
|
206
|
+
* @returns {object}
|
|
207
|
+
*/
|
|
208
|
+
function getMemoryStats(options = {}) {
|
|
209
|
+
const memoryFile = options.memoryFile || DEFAULT_MEMORY_FILE;
|
|
210
|
+
const store = loadMemoryStore(memoryFile);
|
|
211
|
+
|
|
212
|
+
const byType = {};
|
|
213
|
+
for (const type of MEMORY_TYPES) {
|
|
214
|
+
byType[type] = store.entries.filter(e => e.type === type).length;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
return {
|
|
218
|
+
total: store.entries.length,
|
|
219
|
+
by_type: byType,
|
|
220
|
+
last_updated: store.last_updated
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
module.exports = {
|
|
225
|
+
loadMemoryStore,
|
|
226
|
+
saveMemoryStore,
|
|
227
|
+
defaultMemoryStore,
|
|
228
|
+
addMemory,
|
|
229
|
+
listMemories,
|
|
230
|
+
searchMemories,
|
|
231
|
+
recallMemory,
|
|
232
|
+
deleteMemory,
|
|
233
|
+
getMemoryStats,
|
|
234
|
+
MEMORY_TYPES
|
|
235
|
+
};
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* prompt-governance.js — Prompt and Agent Version Governance (Item 91)
|
|
3
|
+
*
|
|
4
|
+
* Version, diff, test, and approve prompts, personas, tools, and workflows.
|
|
5
|
+
*
|
|
6
|
+
* Usage:
|
|
7
|
+
* node bin/lib/prompt-governance.js register|version|diff|approve|list [options]
|
|
8
|
+
*
|
|
9
|
+
* State file: .jumpstart/state/prompt-governance.json
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
'use strict';
|
|
13
|
+
|
|
14
|
+
const fs = require('fs');
|
|
15
|
+
const path = require('path');
|
|
16
|
+
|
|
17
|
+
const DEFAULT_STATE_FILE = path.join('.jumpstart', 'state', 'prompt-governance.json');
|
|
18
|
+
|
|
19
|
+
const ASSET_TYPES = ['prompt', 'persona', 'tool', 'workflow'];
|
|
20
|
+
|
|
21
|
+
function defaultState() {
|
|
22
|
+
return { version: '1.0.0', assets: [], last_updated: null };
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function loadState(stateFile) {
|
|
26
|
+
const fp = stateFile || DEFAULT_STATE_FILE;
|
|
27
|
+
if (!fs.existsSync(fp)) return defaultState();
|
|
28
|
+
try { return JSON.parse(fs.readFileSync(fp, 'utf8')); }
|
|
29
|
+
catch { return defaultState(); }
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function saveState(state, stateFile) {
|
|
33
|
+
const fp = stateFile || DEFAULT_STATE_FILE;
|
|
34
|
+
const dir = path.dirname(fp);
|
|
35
|
+
if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
|
|
36
|
+
state.last_updated = new Date().toISOString();
|
|
37
|
+
fs.writeFileSync(fp, JSON.stringify(state, null, 2) + '\n', 'utf8');
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function registerAsset(name, type, content, options = {}) {
|
|
41
|
+
if (!name || !type || !content) return { success: false, error: 'name, type, and content are required' };
|
|
42
|
+
if (!ASSET_TYPES.includes(type)) {
|
|
43
|
+
return { success: false, error: `Unknown type: ${type}. Valid: ${ASSET_TYPES.join(', ')}` };
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const stateFile = options.stateFile || DEFAULT_STATE_FILE;
|
|
47
|
+
const state = loadState(stateFile);
|
|
48
|
+
|
|
49
|
+
const asset = {
|
|
50
|
+
id: `PGOV-${Date.now()}`,
|
|
51
|
+
name,
|
|
52
|
+
type,
|
|
53
|
+
versions: [{
|
|
54
|
+
version: '1.0.0',
|
|
55
|
+
content,
|
|
56
|
+
approved: false,
|
|
57
|
+
created_at: new Date().toISOString()
|
|
58
|
+
}],
|
|
59
|
+
current_version: '1.0.0',
|
|
60
|
+
created_at: new Date().toISOString()
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
state.assets.push(asset);
|
|
64
|
+
saveState(state, stateFile);
|
|
65
|
+
|
|
66
|
+
return { success: true, asset: { id: asset.id, name: asset.name, type: asset.type, version: asset.current_version } };
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function addVersion(assetId, content, version, options = {}) {
|
|
70
|
+
if (!assetId || !content || !version) return { success: false, error: 'assetId, content, and version are required' };
|
|
71
|
+
|
|
72
|
+
const stateFile = options.stateFile || DEFAULT_STATE_FILE;
|
|
73
|
+
const state = loadState(stateFile);
|
|
74
|
+
|
|
75
|
+
const asset = state.assets.find(a => a.id === assetId);
|
|
76
|
+
if (!asset) return { success: false, error: `Asset ${assetId} not found` };
|
|
77
|
+
|
|
78
|
+
asset.versions.push({ version, content, approved: false, created_at: new Date().toISOString() });
|
|
79
|
+
asset.current_version = version;
|
|
80
|
+
|
|
81
|
+
saveState(state, stateFile);
|
|
82
|
+
|
|
83
|
+
return { success: true, asset_id: assetId, version };
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function approveVersion(assetId, version, options = {}) {
|
|
87
|
+
if (!assetId || !version) return { success: false, error: 'assetId and version are required' };
|
|
88
|
+
|
|
89
|
+
const stateFile = options.stateFile || DEFAULT_STATE_FILE;
|
|
90
|
+
const state = loadState(stateFile);
|
|
91
|
+
|
|
92
|
+
const asset = state.assets.find(a => a.id === assetId);
|
|
93
|
+
if (!asset) return { success: false, error: `Asset ${assetId} not found` };
|
|
94
|
+
|
|
95
|
+
const ver = asset.versions.find(v => v.version === version);
|
|
96
|
+
if (!ver) return { success: false, error: `Version ${version} not found` };
|
|
97
|
+
|
|
98
|
+
ver.approved = true;
|
|
99
|
+
ver.approved_at = new Date().toISOString();
|
|
100
|
+
ver.approved_by = options.approver || 'system';
|
|
101
|
+
|
|
102
|
+
saveState(state, stateFile);
|
|
103
|
+
|
|
104
|
+
return { success: true, asset_id: assetId, version, approved: true };
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function listAssets(options = {}) {
|
|
108
|
+
const stateFile = options.stateFile || DEFAULT_STATE_FILE;
|
|
109
|
+
const state = loadState(stateFile);
|
|
110
|
+
|
|
111
|
+
let assets = state.assets;
|
|
112
|
+
if (options.type) assets = assets.filter(a => a.type === options.type);
|
|
113
|
+
|
|
114
|
+
return {
|
|
115
|
+
success: true,
|
|
116
|
+
total: assets.length,
|
|
117
|
+
assets: assets.map(a => ({
|
|
118
|
+
id: a.id, name: a.name, type: a.type,
|
|
119
|
+
current_version: a.current_version,
|
|
120
|
+
versions_count: a.versions.length,
|
|
121
|
+
latest_approved: (a.versions.filter(v => v.approved).pop() || {}).version || null
|
|
122
|
+
}))
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
module.exports = {
|
|
127
|
+
registerAsset, addVersion, approveVersion, listAssets,
|
|
128
|
+
loadState, saveState, defaultState,
|
|
129
|
+
ASSET_TYPES
|
|
130
|
+
};
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* promptless-mode.js — Promptless Mode for Less Technical Users (Item 77)
|
|
3
|
+
*
|
|
4
|
+
* Wizard-driven workflows that still produce rigorous outputs.
|
|
5
|
+
*
|
|
6
|
+
* Usage:
|
|
7
|
+
* node bin/lib/promptless-mode.js start|step|status [options]
|
|
8
|
+
*
|
|
9
|
+
* State file: .jumpstart/state/promptless.json
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
'use strict';
|
|
13
|
+
|
|
14
|
+
const fs = require('fs');
|
|
15
|
+
const path = require('path');
|
|
16
|
+
|
|
17
|
+
const DEFAULT_STATE_FILE = path.join('.jumpstart', 'state', 'promptless.json');
|
|
18
|
+
|
|
19
|
+
const WIZARDS = ['new-project', 'add-feature', 'review-spec', 'estimate', 'handoff'];
|
|
20
|
+
|
|
21
|
+
const WIZARD_STEPS = {
|
|
22
|
+
'new-project': [
|
|
23
|
+
{ id: 'name', prompt: 'What is your project name?', type: 'text' },
|
|
24
|
+
{ id: 'domain', prompt: 'What industry is this for?', type: 'select', options: ['healthcare', 'fintech', 'retail', 'manufacturing', 'public-sector', 'general'] },
|
|
25
|
+
{ id: 'type', prompt: 'Is this a new or existing project?', type: 'select', options: ['greenfield', 'brownfield'] },
|
|
26
|
+
{ id: 'team_size', prompt: 'How large is your team?', type: 'select', options: ['1-3', '4-10', '10+'] }
|
|
27
|
+
],
|
|
28
|
+
'add-feature': [
|
|
29
|
+
{ id: 'feature_name', prompt: 'What feature do you want to add?', type: 'text' },
|
|
30
|
+
{ id: 'priority', prompt: 'How urgent is this?', type: 'select', options: ['must-have', 'should-have', 'nice-to-have'] },
|
|
31
|
+
{ id: 'complexity', prompt: 'How complex do you think it is?', type: 'select', options: ['simple', 'moderate', 'complex'] }
|
|
32
|
+
],
|
|
33
|
+
'review-spec': [
|
|
34
|
+
{ id: 'spec_file', prompt: 'Which specification file?', type: 'text' },
|
|
35
|
+
{ id: 'review_type', prompt: 'What kind of review?', type: 'select', options: ['completeness', 'quality', 'ambiguity'] }
|
|
36
|
+
]
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
function defaultState() {
|
|
40
|
+
return { version: '1.0.0', sessions: [], last_updated: null };
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function loadState(stateFile) {
|
|
44
|
+
const fp = stateFile || DEFAULT_STATE_FILE;
|
|
45
|
+
if (!fs.existsSync(fp)) return defaultState();
|
|
46
|
+
try { return JSON.parse(fs.readFileSync(fp, 'utf8')); }
|
|
47
|
+
catch { return defaultState(); }
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function saveState(state, stateFile) {
|
|
51
|
+
const fp = stateFile || DEFAULT_STATE_FILE;
|
|
52
|
+
const dir = path.dirname(fp);
|
|
53
|
+
if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
|
|
54
|
+
state.last_updated = new Date().toISOString();
|
|
55
|
+
fs.writeFileSync(fp, JSON.stringify(state, null, 2) + '\n', 'utf8');
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function startWizard(wizardType, options = {}) {
|
|
59
|
+
if (!WIZARDS.includes(wizardType)) {
|
|
60
|
+
return { success: false, error: `Unknown wizard: ${wizardType}. Valid: ${WIZARDS.join(', ')}` };
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const stateFile = options.stateFile || DEFAULT_STATE_FILE;
|
|
64
|
+
const state = loadState(stateFile);
|
|
65
|
+
|
|
66
|
+
const session = {
|
|
67
|
+
id: `WIZ-${Date.now()}`,
|
|
68
|
+
wizard: wizardType,
|
|
69
|
+
status: 'active',
|
|
70
|
+
current_step: 0,
|
|
71
|
+
steps: (WIZARD_STEPS[wizardType] || []).map(s => ({ ...s, answer: null })),
|
|
72
|
+
created_at: new Date().toISOString()
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
state.sessions.push(session);
|
|
76
|
+
saveState(state, stateFile);
|
|
77
|
+
|
|
78
|
+
return { success: true, session, next_step: session.steps[0] || null };
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function answerStep(sessionId, answer, options = {}) {
|
|
82
|
+
if (!sessionId) return { success: false, error: 'sessionId is required' };
|
|
83
|
+
|
|
84
|
+
const stateFile = options.stateFile || DEFAULT_STATE_FILE;
|
|
85
|
+
const state = loadState(stateFile);
|
|
86
|
+
|
|
87
|
+
const session = state.sessions.find(s => s.id === sessionId);
|
|
88
|
+
if (!session) return { success: false, error: `Session ${sessionId} not found` };
|
|
89
|
+
|
|
90
|
+
if (session.current_step >= session.steps.length) {
|
|
91
|
+
return { success: false, error: 'Wizard is already complete' };
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
session.steps[session.current_step].answer = answer;
|
|
95
|
+
session.current_step++;
|
|
96
|
+
|
|
97
|
+
const complete = session.current_step >= session.steps.length;
|
|
98
|
+
if (complete) session.status = 'complete';
|
|
99
|
+
|
|
100
|
+
saveState(state, stateFile);
|
|
101
|
+
|
|
102
|
+
return {
|
|
103
|
+
success: true,
|
|
104
|
+
complete,
|
|
105
|
+
next_step: complete ? null : session.steps[session.current_step],
|
|
106
|
+
answers: Object.fromEntries(session.steps.filter(s => s.answer !== null).map(s => [s.id, s.answer]))
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function getWizardStatus(options = {}) {
|
|
111
|
+
const stateFile = options.stateFile || DEFAULT_STATE_FILE;
|
|
112
|
+
const state = loadState(stateFile);
|
|
113
|
+
|
|
114
|
+
return {
|
|
115
|
+
success: true,
|
|
116
|
+
available_wizards: WIZARDS,
|
|
117
|
+
sessions: state.sessions.map(s => ({
|
|
118
|
+
id: s.id, wizard: s.wizard, status: s.status,
|
|
119
|
+
progress: `${s.current_step}/${s.steps.length}`
|
|
120
|
+
}))
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
module.exports = {
|
|
125
|
+
startWizard, answerStep, getWizardStatus,
|
|
126
|
+
loadState, saveState, defaultState,
|
|
127
|
+
WIZARDS, WIZARD_STEPS
|
|
128
|
+
};
|