jumpstart-mode 1.1.12 → 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 +5 -6
- package/.github/agents/jumpstart-challenger.agent.md +2 -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/workflows/quality.yml +19 -2
- package/.jumpstart/agents/analyst.md +38 -0
- package/.jumpstart/agents/architect.md +38 -0
- 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 +4 -0
- package/.jumpstart/config.yaml +24 -0
- package/.jumpstart/schemas/timeline.schema.json +1 -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/state/timeline.json +659 -0
- package/.jumpstart/usage-log.json +74 -3
- package/README.md +62 -1
- 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/semantic-diff.js +335 -0
- package/bin/lib/sla-slo.js +210 -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 +107 -0
- package/bin/lib/tool-guardrails.js +139 -0
- package/bin/lib/tool-schemas.js +172 -3
- package/bin/lib/transcript-ingestion.js +150 -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
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* parallel-agents.js — Multi-Agent Concurrent Execution
|
|
3
|
+
*
|
|
4
|
+
* Orchestrates architect, security, QA, docs, and performance sidecars
|
|
5
|
+
* running in parallel against the same spec set, then reconciles conflicts.
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
* node bin/lib/parallel-agents.js run|status|reconcile [options]
|
|
9
|
+
*
|
|
10
|
+
* State file: .jumpstart/state/parallel-agents.json
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
'use strict';
|
|
14
|
+
|
|
15
|
+
const fs = require('fs');
|
|
16
|
+
const path = require('path');
|
|
17
|
+
|
|
18
|
+
const DEFAULT_STATE_FILE = path.join('.jumpstart', 'state', 'parallel-agents.json');
|
|
19
|
+
|
|
20
|
+
const SIDECAR_AGENTS = ['architect', 'security', 'qa', 'docs', 'performance'];
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Default parallel agents run state.
|
|
24
|
+
* @returns {object}
|
|
25
|
+
*/
|
|
26
|
+
function defaultParallelState() {
|
|
27
|
+
return {
|
|
28
|
+
version: '1.0.0',
|
|
29
|
+
created_at: new Date().toISOString(),
|
|
30
|
+
last_updated: null,
|
|
31
|
+
runs: []
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Load parallel agents state from disk.
|
|
37
|
+
* @param {string} [stateFile]
|
|
38
|
+
* @returns {object}
|
|
39
|
+
*/
|
|
40
|
+
function loadParallelState(stateFile) {
|
|
41
|
+
const filePath = stateFile || DEFAULT_STATE_FILE;
|
|
42
|
+
if (!fs.existsSync(filePath)) {
|
|
43
|
+
return defaultParallelState();
|
|
44
|
+
}
|
|
45
|
+
try {
|
|
46
|
+
return JSON.parse(fs.readFileSync(filePath, 'utf8'));
|
|
47
|
+
} catch {
|
|
48
|
+
return defaultParallelState();
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Save parallel agents state to disk.
|
|
54
|
+
* @param {object} state
|
|
55
|
+
* @param {string} [stateFile]
|
|
56
|
+
*/
|
|
57
|
+
function saveParallelState(state, stateFile) {
|
|
58
|
+
const filePath = stateFile || DEFAULT_STATE_FILE;
|
|
59
|
+
const dir = path.dirname(filePath);
|
|
60
|
+
if (!fs.existsSync(dir)) {
|
|
61
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
62
|
+
}
|
|
63
|
+
state.last_updated = new Date().toISOString();
|
|
64
|
+
fs.writeFileSync(filePath, JSON.stringify(state, null, 2) + '\n', 'utf8');
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Schedule a new parallel agent run.
|
|
69
|
+
*
|
|
70
|
+
* @param {string[]} agents - Subset of SIDECAR_AGENTS to run. Defaults to all.
|
|
71
|
+
* @param {object} context - Shared context (phase, specFiles, root).
|
|
72
|
+
* @param {object} [options]
|
|
73
|
+
* @returns {object}
|
|
74
|
+
*/
|
|
75
|
+
function scheduleRun(agents, context, options = {}) {
|
|
76
|
+
const agentList = (agents && agents.length > 0)
|
|
77
|
+
? agents.filter(a => SIDECAR_AGENTS.includes(a))
|
|
78
|
+
: [...SIDECAR_AGENTS];
|
|
79
|
+
|
|
80
|
+
if (agentList.length === 0) {
|
|
81
|
+
return { success: false, error: `No valid agents specified. Valid: ${SIDECAR_AGENTS.join(', ')}` };
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const stateFile = options.stateFile || DEFAULT_STATE_FILE;
|
|
85
|
+
const state = loadParallelState(stateFile);
|
|
86
|
+
|
|
87
|
+
const runId = `run-${Date.now()}`;
|
|
88
|
+
const run = {
|
|
89
|
+
id: runId,
|
|
90
|
+
scheduled_at: new Date().toISOString(),
|
|
91
|
+
context: context || {},
|
|
92
|
+
agents: agentList.map(name => ({
|
|
93
|
+
name,
|
|
94
|
+
status: 'pending', // pending | running | completed | failed
|
|
95
|
+
started_at: null,
|
|
96
|
+
completed_at: null,
|
|
97
|
+
findings: [],
|
|
98
|
+
errors: []
|
|
99
|
+
})),
|
|
100
|
+
reconciliation: null,
|
|
101
|
+
status: 'pending'
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
state.runs.push(run);
|
|
105
|
+
saveParallelState(state, stateFile);
|
|
106
|
+
|
|
107
|
+
return { success: true, run_id: runId, agents: agentList };
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Record findings from a sidecar agent.
|
|
112
|
+
*
|
|
113
|
+
* @param {string} runId
|
|
114
|
+
* @param {string} agentName
|
|
115
|
+
* @param {object[]} findings - Array of { type, message, severity, file? }.
|
|
116
|
+
* @param {object} [options]
|
|
117
|
+
* @returns {object}
|
|
118
|
+
*/
|
|
119
|
+
function recordAgentFindings(runId, agentName, findings, options = {}) {
|
|
120
|
+
const stateFile = options.stateFile || DEFAULT_STATE_FILE;
|
|
121
|
+
const state = loadParallelState(stateFile);
|
|
122
|
+
|
|
123
|
+
const run = state.runs.find(r => r.id === runId);
|
|
124
|
+
if (!run) {
|
|
125
|
+
return { success: false, error: `Run not found: ${runId}` };
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
const agent = run.agents.find(a => a.name === agentName);
|
|
129
|
+
if (!agent) {
|
|
130
|
+
return { success: false, error: `Agent not found: ${agentName}` };
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
agent.findings = findings || [];
|
|
134
|
+
agent.status = 'completed';
|
|
135
|
+
agent.completed_at = new Date().toISOString();
|
|
136
|
+
|
|
137
|
+
// Update overall run status
|
|
138
|
+
const allDone = run.agents.every(a => a.status === 'completed' || a.status === 'failed');
|
|
139
|
+
if (allDone) {
|
|
140
|
+
run.status = 'completed';
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
saveParallelState(state, stateFile);
|
|
144
|
+
|
|
145
|
+
return { success: true, run_id: runId, agent: agentName, findings_count: findings.length };
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Reconcile findings from all agents in a run — merge and de-duplicate conflicts.
|
|
150
|
+
*
|
|
151
|
+
* @param {string} runId
|
|
152
|
+
* @param {object} [options]
|
|
153
|
+
* @returns {object} Reconciliation result with merged findings and conflicts.
|
|
154
|
+
*/
|
|
155
|
+
function reconcileRun(runId, options = {}) {
|
|
156
|
+
const stateFile = options.stateFile || DEFAULT_STATE_FILE;
|
|
157
|
+
const state = loadParallelState(stateFile);
|
|
158
|
+
|
|
159
|
+
const run = state.runs.find(r => r.id === runId);
|
|
160
|
+
if (!run) {
|
|
161
|
+
return { success: false, error: `Run not found: ${runId}` };
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
const allFindings = [];
|
|
165
|
+
for (const agent of run.agents) {
|
|
166
|
+
for (const finding of agent.findings || []) {
|
|
167
|
+
allFindings.push({ ...finding, agent: agent.name });
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// Detect conflicts: same file+type from different agents with different severities
|
|
172
|
+
const conflicts = [];
|
|
173
|
+
const seen = {};
|
|
174
|
+
for (const f of allFindings) {
|
|
175
|
+
const key = `${f.file || ''}:${f.type || ''}`;
|
|
176
|
+
if (seen[key] && seen[key].severity !== f.severity) {
|
|
177
|
+
conflicts.push({
|
|
178
|
+
key,
|
|
179
|
+
agents: [seen[key].agent, f.agent],
|
|
180
|
+
severities: [seen[key].severity, f.severity],
|
|
181
|
+
message: `Conflict: ${f.type} severity disagrees between ${seen[key].agent} and ${f.agent}`
|
|
182
|
+
});
|
|
183
|
+
} else {
|
|
184
|
+
seen[key] = f;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
const reconciliation = {
|
|
189
|
+
reconciled_at: new Date().toISOString(),
|
|
190
|
+
total_findings: allFindings.length,
|
|
191
|
+
conflicts: conflicts.length,
|
|
192
|
+
conflict_list: conflicts,
|
|
193
|
+
merged_findings: allFindings
|
|
194
|
+
};
|
|
195
|
+
|
|
196
|
+
run.reconciliation = reconciliation;
|
|
197
|
+
saveParallelState(state, stateFile);
|
|
198
|
+
|
|
199
|
+
return { success: true, run_id: runId, reconciliation };
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* Get the status of a run.
|
|
204
|
+
*
|
|
205
|
+
* @param {string} runId
|
|
206
|
+
* @param {object} [options]
|
|
207
|
+
* @returns {object}
|
|
208
|
+
*/
|
|
209
|
+
function getRunStatus(runId, options = {}) {
|
|
210
|
+
const stateFile = options.stateFile || DEFAULT_STATE_FILE;
|
|
211
|
+
const state = loadParallelState(stateFile);
|
|
212
|
+
|
|
213
|
+
const run = state.runs.find(r => r.id === runId);
|
|
214
|
+
if (!run) {
|
|
215
|
+
return { success: false, error: `Run not found: ${runId}` };
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
return {
|
|
219
|
+
success: true,
|
|
220
|
+
run_id: runId,
|
|
221
|
+
status: run.status,
|
|
222
|
+
agents: run.agents.map(a => ({ name: a.name, status: a.status, findings: a.findings.length })),
|
|
223
|
+
reconciliation: run.reconciliation
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* List all runs.
|
|
229
|
+
*
|
|
230
|
+
* @param {object} [options]
|
|
231
|
+
* @returns {object}
|
|
232
|
+
*/
|
|
233
|
+
function listRuns(options = {}) {
|
|
234
|
+
const stateFile = options.stateFile || DEFAULT_STATE_FILE;
|
|
235
|
+
const state = loadParallelState(stateFile);
|
|
236
|
+
|
|
237
|
+
const runs = state.runs.map(r => ({
|
|
238
|
+
id: r.id,
|
|
239
|
+
status: r.status,
|
|
240
|
+
scheduled_at: r.scheduled_at,
|
|
241
|
+
agent_count: r.agents.length
|
|
242
|
+
}));
|
|
243
|
+
|
|
244
|
+
return { success: true, runs, total: runs.length };
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
module.exports = {
|
|
248
|
+
SIDECAR_AGENTS,
|
|
249
|
+
loadParallelState,
|
|
250
|
+
saveParallelState,
|
|
251
|
+
defaultParallelState,
|
|
252
|
+
scheduleRun,
|
|
253
|
+
recordAgentFindings,
|
|
254
|
+
reconcileRun,
|
|
255
|
+
getRunStatus,
|
|
256
|
+
listRuns
|
|
257
|
+
};
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* pattern-library.js — Inner-Source Pattern Library (Item 82)
|
|
3
|
+
*
|
|
4
|
+
* Approved implementation examples that agents can clone, adapt, and cite.
|
|
5
|
+
*
|
|
6
|
+
* Usage:
|
|
7
|
+
* node bin/lib/pattern-library.js register|search|get|list [options]
|
|
8
|
+
*
|
|
9
|
+
* State file: .jumpstart/state/pattern-library.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', 'pattern-library.json');
|
|
18
|
+
|
|
19
|
+
const PATTERN_CATEGORIES = ['api', 'data-access', 'auth', 'messaging', 'testing', 'deployment', 'error-handling', 'logging'];
|
|
20
|
+
|
|
21
|
+
function defaultState() {
|
|
22
|
+
return { version: '1.0.0', patterns: [], 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 registerPattern(name, category, options = {}) {
|
|
41
|
+
if (!name || !category) return { success: false, error: 'name and category are required' };
|
|
42
|
+
if (!PATTERN_CATEGORIES.includes(category)) {
|
|
43
|
+
return { success: false, error: `Unknown category: ${category}. Valid: ${PATTERN_CATEGORIES.join(', ')}` };
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const stateFile = options.stateFile || DEFAULT_STATE_FILE;
|
|
47
|
+
const state = loadState(stateFile);
|
|
48
|
+
|
|
49
|
+
const pattern = {
|
|
50
|
+
id: `PAT-${Date.now()}`,
|
|
51
|
+
name,
|
|
52
|
+
category,
|
|
53
|
+
description: options.description || '',
|
|
54
|
+
language: options.language || 'javascript',
|
|
55
|
+
code: options.code || '',
|
|
56
|
+
tags: options.tags || [],
|
|
57
|
+
approved: options.approved || false,
|
|
58
|
+
created_at: new Date().toISOString()
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
state.patterns.push(pattern);
|
|
62
|
+
saveState(state, stateFile);
|
|
63
|
+
|
|
64
|
+
return { success: true, pattern };
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function searchPatterns(query, options = {}) {
|
|
68
|
+
const stateFile = options.stateFile || DEFAULT_STATE_FILE;
|
|
69
|
+
const state = loadState(stateFile);
|
|
70
|
+
|
|
71
|
+
const q = (query || '').toLowerCase();
|
|
72
|
+
let results = state.patterns;
|
|
73
|
+
|
|
74
|
+
if (q) {
|
|
75
|
+
results = results.filter(p =>
|
|
76
|
+
p.name.toLowerCase().includes(q) ||
|
|
77
|
+
p.description.toLowerCase().includes(q) ||
|
|
78
|
+
p.tags.some(t => t.toLowerCase().includes(q))
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
if (options.category) {
|
|
83
|
+
results = results.filter(p => p.category === options.category);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return { success: true, total: results.length, patterns: results };
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function getPattern(patternId, options = {}) {
|
|
90
|
+
const stateFile = options.stateFile || DEFAULT_STATE_FILE;
|
|
91
|
+
const state = loadState(stateFile);
|
|
92
|
+
|
|
93
|
+
const pattern = state.patterns.find(p => p.id === patternId);
|
|
94
|
+
if (!pattern) return { success: false, error: `Pattern ${patternId} not found` };
|
|
95
|
+
|
|
96
|
+
return { success: true, pattern };
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function listPatterns(options = {}) {
|
|
100
|
+
const stateFile = options.stateFile || DEFAULT_STATE_FILE;
|
|
101
|
+
const state = loadState(stateFile);
|
|
102
|
+
|
|
103
|
+
return {
|
|
104
|
+
success: true,
|
|
105
|
+
total: state.patterns.length,
|
|
106
|
+
categories: PATTERN_CATEGORIES,
|
|
107
|
+
patterns: state.patterns.map(p => ({ id: p.id, name: p.name, category: p.category, approved: p.approved }))
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
module.exports = {
|
|
112
|
+
registerPattern, searchPatterns, getPattern, listPatterns,
|
|
113
|
+
loadState, saveState, defaultState,
|
|
114
|
+
PATTERN_CATEGORIES
|
|
115
|
+
};
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* persona-packs.js — Persona Packs for Enterprise Roles (Item 80)
|
|
3
|
+
*
|
|
4
|
+
* Business analyst, product owner, architect, security lead,
|
|
5
|
+
* platform engineer, SRE, data steward persona definitions.
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
* node bin/lib/persona-packs.js list|get|apply [options]
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
'use strict';
|
|
12
|
+
|
|
13
|
+
const PERSONA_CATALOG = {
|
|
14
|
+
'business-analyst': {
|
|
15
|
+
label: 'Business Analyst',
|
|
16
|
+
focus: ['requirements', 'process-modeling', 'stakeholder-management', 'data-analysis'],
|
|
17
|
+
artifacts: ['product-brief', 'prd', 'process-maps'],
|
|
18
|
+
tools: ['elicitation', 'estimation', 'ambiguity-heatmap']
|
|
19
|
+
},
|
|
20
|
+
'product-owner': {
|
|
21
|
+
label: 'Product Owner',
|
|
22
|
+
focus: ['backlog', 'prioritization', 'user-stories', 'acceptance-criteria'],
|
|
23
|
+
artifacts: ['prd', 'product-brief', 'backlog'],
|
|
24
|
+
tools: ['estimation', 'playback-summaries', 'handoff']
|
|
25
|
+
},
|
|
26
|
+
'architect': {
|
|
27
|
+
label: 'Architect',
|
|
28
|
+
focus: ['system-design', 'tech-stack', 'nfrs', 'data-modeling'],
|
|
29
|
+
artifacts: ['architecture', 'decisions', 'diagrams'],
|
|
30
|
+
tools: ['diagram-studio', 'reference-arch', 'fitness-functions']
|
|
31
|
+
},
|
|
32
|
+
'security-lead': {
|
|
33
|
+
label: 'Security Lead',
|
|
34
|
+
focus: ['threat-modeling', 'compliance', 'access-control', 'data-protection'],
|
|
35
|
+
artifacts: ['security-review', 'compliance-report', 'threat-model'],
|
|
36
|
+
tools: ['credential-boundary', 'data-classification', 'compliance-packs']
|
|
37
|
+
},
|
|
38
|
+
'platform-engineer': {
|
|
39
|
+
label: 'Platform Engineer',
|
|
40
|
+
focus: ['infrastructure', 'ci-cd', 'golden-paths', 'developer-experience'],
|
|
41
|
+
artifacts: ['deployment-guide', 'platform-config', 'runbooks'],
|
|
42
|
+
tools: ['ci-cd-integration', 'env-promotion', 'platform-engineering']
|
|
43
|
+
},
|
|
44
|
+
'sre': {
|
|
45
|
+
label: 'Site Reliability Engineer',
|
|
46
|
+
focus: ['monitoring', 'incident-response', 'sla-slo', 'capacity-planning'],
|
|
47
|
+
artifacts: ['runbooks', 'sla-report', 'incident-log'],
|
|
48
|
+
tools: ['sla-slo', 'incident-feedback', 'ops-ownership']
|
|
49
|
+
},
|
|
50
|
+
'data-steward': {
|
|
51
|
+
label: 'Data Steward',
|
|
52
|
+
focus: ['data-governance', 'data-quality', 'lineage', 'classification'],
|
|
53
|
+
artifacts: ['data-catalog', 'classification-report', 'lineage-map'],
|
|
54
|
+
tools: ['data-classification', 'data-contracts', 'domain-ontology']
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
const PERSONAS = Object.keys(PERSONA_CATALOG);
|
|
59
|
+
|
|
60
|
+
function listPersonas() {
|
|
61
|
+
return {
|
|
62
|
+
success: true,
|
|
63
|
+
personas: PERSONAS.map(p => ({
|
|
64
|
+
id: p,
|
|
65
|
+
label: PERSONA_CATALOG[p].label,
|
|
66
|
+
focus_count: PERSONA_CATALOG[p].focus.length,
|
|
67
|
+
tools_count: PERSONA_CATALOG[p].tools.length
|
|
68
|
+
}))
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function getPersona(personaId) {
|
|
73
|
+
if (!PERSONA_CATALOG[personaId]) {
|
|
74
|
+
return { success: false, error: `Unknown persona: ${personaId}. Valid: ${PERSONAS.join(', ')}` };
|
|
75
|
+
}
|
|
76
|
+
return { success: true, persona: { id: personaId, ...PERSONA_CATALOG[personaId] } };
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function applyPersona(personaId, options = {}) {
|
|
80
|
+
if (!PERSONA_CATALOG[personaId]) {
|
|
81
|
+
return { success: false, error: `Unknown persona: ${personaId}` };
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const persona = PERSONA_CATALOG[personaId];
|
|
85
|
+
return {
|
|
86
|
+
success: true,
|
|
87
|
+
persona_id: personaId,
|
|
88
|
+
label: persona.label,
|
|
89
|
+
recommended_tools: persona.tools,
|
|
90
|
+
relevant_artifacts: persona.artifacts,
|
|
91
|
+
focus_areas: persona.focus,
|
|
92
|
+
applied_at: new Date().toISOString()
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
module.exports = {
|
|
97
|
+
listPersonas, getPersona, applyPersona,
|
|
98
|
+
PERSONAS, PERSONA_CATALOG
|
|
99
|
+
};
|