cap-pro 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/README.md +26 -0
- package/.claude-plugin/marketplace.json +24 -0
- package/.claude-plugin/plugin.json +24 -0
- package/LICENSE +21 -0
- package/README.ja-JP.md +834 -0
- package/README.ko-KR.md +823 -0
- package/README.md +806 -0
- package/README.pt-BR.md +452 -0
- package/README.zh-CN.md +800 -0
- package/agents/cap-architect.md +269 -0
- package/agents/cap-brainstormer.md +207 -0
- package/agents/cap-curator.md +276 -0
- package/agents/cap-debugger.md +365 -0
- package/agents/cap-designer.md +246 -0
- package/agents/cap-historian.md +464 -0
- package/agents/cap-migrator.md +291 -0
- package/agents/cap-prototyper.md +197 -0
- package/agents/cap-validator.md +308 -0
- package/bin/install.js +5433 -0
- package/cap/bin/cap-tools.cjs +853 -0
- package/cap/bin/lib/arc-scanner.cjs +344 -0
- package/cap/bin/lib/cap-affinity-engine.cjs +862 -0
- package/cap/bin/lib/cap-anchor.cjs +228 -0
- package/cap/bin/lib/cap-annotation-writer.cjs +340 -0
- package/cap/bin/lib/cap-checkpoint.cjs +434 -0
- package/cap/bin/lib/cap-cluster-detect.cjs +945 -0
- package/cap/bin/lib/cap-cluster-display.cjs +52 -0
- package/cap/bin/lib/cap-cluster-format.cjs +245 -0
- package/cap/bin/lib/cap-cluster-helpers.cjs +295 -0
- package/cap/bin/lib/cap-cluster-io.cjs +212 -0
- package/cap/bin/lib/cap-completeness.cjs +540 -0
- package/cap/bin/lib/cap-deps.cjs +583 -0
- package/cap/bin/lib/cap-design-families.cjs +332 -0
- package/cap/bin/lib/cap-design.cjs +966 -0
- package/cap/bin/lib/cap-divergence-detector.cjs +400 -0
- package/cap/bin/lib/cap-doctor.cjs +752 -0
- package/cap/bin/lib/cap-feature-map-internals.cjs +19 -0
- package/cap/bin/lib/cap-feature-map-migrate.cjs +335 -0
- package/cap/bin/lib/cap-feature-map-monorepo.cjs +885 -0
- package/cap/bin/lib/cap-feature-map-shard.cjs +315 -0
- package/cap/bin/lib/cap-feature-map.cjs +1943 -0
- package/cap/bin/lib/cap-fitness-score.cjs +1075 -0
- package/cap/bin/lib/cap-impact-analysis.cjs +652 -0
- package/cap/bin/lib/cap-learn-review.cjs +1072 -0
- package/cap/bin/lib/cap-learning-signals.cjs +627 -0
- package/cap/bin/lib/cap-loader.cjs +227 -0
- package/cap/bin/lib/cap-logger.cjs +57 -0
- package/cap/bin/lib/cap-memory-bridge.cjs +764 -0
- package/cap/bin/lib/cap-memory-confidence.cjs +452 -0
- package/cap/bin/lib/cap-memory-dir.cjs +987 -0
- package/cap/bin/lib/cap-memory-engine.cjs +698 -0
- package/cap/bin/lib/cap-memory-extends.cjs +398 -0
- package/cap/bin/lib/cap-memory-graph.cjs +790 -0
- package/cap/bin/lib/cap-memory-migrate.cjs +2015 -0
- package/cap/bin/lib/cap-memory-pin.cjs +183 -0
- package/cap/bin/lib/cap-memory-platform.cjs +490 -0
- package/cap/bin/lib/cap-memory-prune.cjs +707 -0
- package/cap/bin/lib/cap-memory-schema.cjs +812 -0
- package/cap/bin/lib/cap-migrate-tags.cjs +309 -0
- package/cap/bin/lib/cap-migrate.cjs +540 -0
- package/cap/bin/lib/cap-pattern-apply.cjs +1203 -0
- package/cap/bin/lib/cap-pattern-pipeline.cjs +1034 -0
- package/cap/bin/lib/cap-plugin-manifest.cjs +80 -0
- package/cap/bin/lib/cap-realtime-affinity.cjs +399 -0
- package/cap/bin/lib/cap-reconcile.cjs +570 -0
- package/cap/bin/lib/cap-research-gate.cjs +218 -0
- package/cap/bin/lib/cap-scope-filter.cjs +402 -0
- package/cap/bin/lib/cap-semantic-pipeline.cjs +1038 -0
- package/cap/bin/lib/cap-session-extract.cjs +987 -0
- package/cap/bin/lib/cap-session.cjs +445 -0
- package/cap/bin/lib/cap-snapshot-linkage.cjs +963 -0
- package/cap/bin/lib/cap-stack-docs.cjs +646 -0
- package/cap/bin/lib/cap-tag-observer.cjs +371 -0
- package/cap/bin/lib/cap-tag-scanner.cjs +1766 -0
- package/cap/bin/lib/cap-telemetry.cjs +466 -0
- package/cap/bin/lib/cap-test-audit.cjs +1438 -0
- package/cap/bin/lib/cap-thread-migrator.cjs +307 -0
- package/cap/bin/lib/cap-thread-synthesis.cjs +545 -0
- package/cap/bin/lib/cap-thread-tracker.cjs +519 -0
- package/cap/bin/lib/cap-trace.cjs +399 -0
- package/cap/bin/lib/cap-trust-mode.cjs +336 -0
- package/cap/bin/lib/cap-ui-design-editor.cjs +642 -0
- package/cap/bin/lib/cap-ui-mind-map.cjs +712 -0
- package/cap/bin/lib/cap-ui-thread-nav.cjs +693 -0
- package/cap/bin/lib/cap-ui.cjs +1245 -0
- package/cap/bin/lib/cap-upgrade.cjs +1028 -0
- package/cap/bin/lib/cli/arg-helpers.cjs +49 -0
- package/cap/bin/lib/cli/frontmatter-router.cjs +31 -0
- package/cap/bin/lib/cli/init-router.cjs +68 -0
- package/cap/bin/lib/cli/phase-router.cjs +102 -0
- package/cap/bin/lib/cli/state-router.cjs +61 -0
- package/cap/bin/lib/cli/template-router.cjs +37 -0
- package/cap/bin/lib/cli/uat-router.cjs +29 -0
- package/cap/bin/lib/cli/validation-router.cjs +26 -0
- package/cap/bin/lib/cli/verification-router.cjs +31 -0
- package/cap/bin/lib/cli/workstream-router.cjs +39 -0
- package/cap/bin/lib/commands.cjs +961 -0
- package/cap/bin/lib/config.cjs +467 -0
- package/cap/bin/lib/convention-reader.cjs +258 -0
- package/cap/bin/lib/core.cjs +1241 -0
- package/cap/bin/lib/feature-aggregator.cjs +423 -0
- package/cap/bin/lib/frontmatter.cjs +337 -0
- package/cap/bin/lib/init.cjs +1443 -0
- package/cap/bin/lib/manifest-generator.cjs +383 -0
- package/cap/bin/lib/milestone.cjs +253 -0
- package/cap/bin/lib/model-profiles.cjs +69 -0
- package/cap/bin/lib/monorepo-context.cjs +226 -0
- package/cap/bin/lib/monorepo-migrator.cjs +509 -0
- package/cap/bin/lib/phase.cjs +889 -0
- package/cap/bin/lib/profile-output.cjs +989 -0
- package/cap/bin/lib/profile-pipeline.cjs +540 -0
- package/cap/bin/lib/roadmap.cjs +330 -0
- package/cap/bin/lib/security.cjs +394 -0
- package/cap/bin/lib/session-manager.cjs +292 -0
- package/cap/bin/lib/skeleton-generator.cjs +179 -0
- package/cap/bin/lib/state.cjs +1032 -0
- package/cap/bin/lib/template.cjs +231 -0
- package/cap/bin/lib/test-detector.cjs +62 -0
- package/cap/bin/lib/uat.cjs +283 -0
- package/cap/bin/lib/verify.cjs +889 -0
- package/cap/bin/lib/workspace-detector.cjs +371 -0
- package/cap/bin/lib/workstream.cjs +492 -0
- package/cap/commands/gsd/workstreams.md +63 -0
- package/cap/references/arc-standard.md +315 -0
- package/cap/references/cap-agent-architecture.md +101 -0
- package/cap/references/cap-gitignore-template +9 -0
- package/cap/references/cap-zero-deps.md +158 -0
- package/cap/references/checkpoints.md +778 -0
- package/cap/references/continuation-format.md +249 -0
- package/cap/references/contract-test-templates.md +312 -0
- package/cap/references/feature-map-template.md +25 -0
- package/cap/references/git-integration.md +295 -0
- package/cap/references/git-planning-commit.md +38 -0
- package/cap/references/model-profiles.md +174 -0
- package/cap/references/phase-numbering.md +126 -0
- package/cap/references/planning-config.md +202 -0
- package/cap/references/property-test-templates.md +316 -0
- package/cap/references/security-test-templates.md +347 -0
- package/cap/references/session-template.json +8 -0
- package/cap/references/tdd.md +263 -0
- package/cap/references/user-profiling.md +681 -0
- package/cap/references/verification-patterns.md +612 -0
- package/cap/templates/UAT.md +265 -0
- package/cap/templates/claude-md.md +175 -0
- package/cap/templates/codebase/architecture.md +255 -0
- package/cap/templates/codebase/concerns.md +310 -0
- package/cap/templates/codebase/conventions.md +307 -0
- package/cap/templates/codebase/integrations.md +280 -0
- package/cap/templates/codebase/stack.md +186 -0
- package/cap/templates/codebase/structure.md +285 -0
- package/cap/templates/codebase/testing.md +480 -0
- package/cap/templates/config.json +44 -0
- package/cap/templates/context.md +352 -0
- package/cap/templates/continue-here.md +78 -0
- package/cap/templates/copilot-instructions.md +7 -0
- package/cap/templates/debug-subagent-prompt.md +91 -0
- package/cap/templates/discussion-log.md +63 -0
- package/cap/templates/milestone-archive.md +123 -0
- package/cap/templates/milestone.md +115 -0
- package/cap/templates/phase-prompt.md +610 -0
- package/cap/templates/planner-subagent-prompt.md +117 -0
- package/cap/templates/project.md +186 -0
- package/cap/templates/requirements.md +231 -0
- package/cap/templates/research-project/ARCHITECTURE.md +204 -0
- package/cap/templates/research-project/FEATURES.md +147 -0
- package/cap/templates/research-project/PITFALLS.md +200 -0
- package/cap/templates/research-project/STACK.md +120 -0
- package/cap/templates/research-project/SUMMARY.md +170 -0
- package/cap/templates/research.md +552 -0
- package/cap/templates/roadmap.md +202 -0
- package/cap/templates/state.md +176 -0
- package/cap/templates/summary.md +364 -0
- package/cap/templates/user-preferences.md +498 -0
- package/cap/templates/verification-report.md +322 -0
- package/cap/workflows/add-phase.md +112 -0
- package/cap/workflows/add-tests.md +351 -0
- package/cap/workflows/add-todo.md +158 -0
- package/cap/workflows/audit-milestone.md +340 -0
- package/cap/workflows/audit-uat.md +109 -0
- package/cap/workflows/autonomous.md +891 -0
- package/cap/workflows/check-todos.md +177 -0
- package/cap/workflows/cleanup.md +152 -0
- package/cap/workflows/complete-milestone.md +767 -0
- package/cap/workflows/diagnose-issues.md +231 -0
- package/cap/workflows/discovery-phase.md +289 -0
- package/cap/workflows/discuss-phase-assumptions.md +653 -0
- package/cap/workflows/discuss-phase.md +1049 -0
- package/cap/workflows/do.md +104 -0
- package/cap/workflows/execute-phase.md +846 -0
- package/cap/workflows/execute-plan.md +514 -0
- package/cap/workflows/fast.md +105 -0
- package/cap/workflows/forensics.md +265 -0
- package/cap/workflows/health.md +181 -0
- package/cap/workflows/help.md +660 -0
- package/cap/workflows/insert-phase.md +130 -0
- package/cap/workflows/list-phase-assumptions.md +178 -0
- package/cap/workflows/list-workspaces.md +56 -0
- package/cap/workflows/manager.md +362 -0
- package/cap/workflows/map-codebase.md +377 -0
- package/cap/workflows/milestone-summary.md +223 -0
- package/cap/workflows/new-milestone.md +486 -0
- package/cap/workflows/new-project.md +1250 -0
- package/cap/workflows/new-workspace.md +237 -0
- package/cap/workflows/next.md +97 -0
- package/cap/workflows/node-repair.md +92 -0
- package/cap/workflows/note.md +156 -0
- package/cap/workflows/pause-work.md +176 -0
- package/cap/workflows/plan-milestone-gaps.md +273 -0
- package/cap/workflows/plan-phase.md +857 -0
- package/cap/workflows/plant-seed.md +169 -0
- package/cap/workflows/pr-branch.md +129 -0
- package/cap/workflows/profile-user.md +449 -0
- package/cap/workflows/progress.md +507 -0
- package/cap/workflows/quick.md +757 -0
- package/cap/workflows/remove-phase.md +155 -0
- package/cap/workflows/remove-workspace.md +90 -0
- package/cap/workflows/research-phase.md +82 -0
- package/cap/workflows/resume-project.md +326 -0
- package/cap/workflows/review.md +228 -0
- package/cap/workflows/session-report.md +146 -0
- package/cap/workflows/settings.md +283 -0
- package/cap/workflows/ship.md +228 -0
- package/cap/workflows/stats.md +60 -0
- package/cap/workflows/transition.md +671 -0
- package/cap/workflows/ui-phase.md +298 -0
- package/cap/workflows/ui-review.md +161 -0
- package/cap/workflows/update.md +323 -0
- package/cap/workflows/validate-phase.md +170 -0
- package/cap/workflows/verify-phase.md +254 -0
- package/cap/workflows/verify-work.md +637 -0
- package/commands/cap/annotate.md +165 -0
- package/commands/cap/brainstorm.md +393 -0
- package/commands/cap/checkpoint.md +106 -0
- package/commands/cap/completeness.md +94 -0
- package/commands/cap/continue.md +72 -0
- package/commands/cap/debug.md +588 -0
- package/commands/cap/deps.md +169 -0
- package/commands/cap/design.md +479 -0
- package/commands/cap/init.md +354 -0
- package/commands/cap/iterate.md +249 -0
- package/commands/cap/learn.md +459 -0
- package/commands/cap/memory.md +275 -0
- package/commands/cap/migrate-feature-map.md +91 -0
- package/commands/cap/migrate-memory.md +108 -0
- package/commands/cap/migrate-tags.md +91 -0
- package/commands/cap/migrate.md +131 -0
- package/commands/cap/prototype.md +510 -0
- package/commands/cap/reconcile.md +121 -0
- package/commands/cap/review.md +360 -0
- package/commands/cap/save.md +72 -0
- package/commands/cap/scan.md +404 -0
- package/commands/cap/start.md +356 -0
- package/commands/cap/status.md +118 -0
- package/commands/cap/test-audit.md +262 -0
- package/commands/cap/test.md +394 -0
- package/commands/cap/trace.md +133 -0
- package/commands/cap/ui.md +167 -0
- package/hooks/dist/cap-check-update.js +115 -0
- package/hooks/dist/cap-context-monitor.js +185 -0
- package/hooks/dist/cap-learn-review-hook.js +114 -0
- package/hooks/dist/cap-learning-hook.js +192 -0
- package/hooks/dist/cap-memory.js +299 -0
- package/hooks/dist/cap-prompt-guard.js +97 -0
- package/hooks/dist/cap-statusline.js +157 -0
- package/hooks/dist/cap-tag-observer.js +115 -0
- package/hooks/dist/cap-version-check.js +112 -0
- package/hooks/dist/cap-workflow-guard.js +175 -0
- package/hooks/hooks.json +55 -0
- package/package.json +58 -0
- package/scripts/base64-scan.sh +262 -0
- package/scripts/build-hooks.js +93 -0
- package/scripts/cap-removal-checklist.md +202 -0
- package/scripts/prompt-injection-scan.sh +199 -0
- package/scripts/run-tests.cjs +181 -0
- package/scripts/secret-scan.sh +227 -0
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
// @cap-feature(feature:F-031) Thread migration — extract brainstorm sessions from past JSONL logs and persist as conversation threads
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
const fs = require('node:fs');
|
|
5
|
+
const path = require('node:path');
|
|
6
|
+
|
|
7
|
+
/** Patterns that indicate a decision or conclusion in assistant text. */
|
|
8
|
+
const DECISION_PATTERNS = [
|
|
9
|
+
/(?:entscheid|decided|decision|chose|approach|fazit|ergebnis)/i,
|
|
10
|
+
/(?:empfehl|recommend|suggestion|vorschlag)/i,
|
|
11
|
+
/(?:conclusion|zusammenfassung|summary|erkenntnis)/i,
|
|
12
|
+
/(?:pros?\s*(?:&|und|and)\s*cons?|vorteile.*nachteile)/i,
|
|
13
|
+
/(?:the (?:problem|issue|root cause|fix|solution|workaround))/i,
|
|
14
|
+
/(?:wir (?:haben|sollten|werden|nutzen|verwenden))/i,
|
|
15
|
+
/(?:best(?:er)?\s*(?:approach|ansatz|weg|practice))/i,
|
|
16
|
+
];
|
|
17
|
+
|
|
18
|
+
/** Patterns that indicate a brainstorm-relevant session (not just any session). */
|
|
19
|
+
const BRAINSTORM_MARKERS = [
|
|
20
|
+
'/cap:brainstorm', '/gsd:brainstorm',
|
|
21
|
+
'BRAINSTORM OUTPUT', '=== FEATURE:',
|
|
22
|
+
'Feature Map', 'FEATURE-MAP',
|
|
23
|
+
'acceptance criteria', 'Akzeptanzkriterien',
|
|
24
|
+
];
|
|
25
|
+
|
|
26
|
+
/** Max characters for extracted fields to keep threads compact. */
|
|
27
|
+
const MAX_PROBLEM = 300;
|
|
28
|
+
const MAX_SOLUTION = 500;
|
|
29
|
+
const MAX_DECISION = 200;
|
|
30
|
+
const MAX_DECISIONS = 8;
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Migrate past brainstorm sessions to conversation threads.
|
|
34
|
+
* Extracts problem statements, solution approaches, and key decisions
|
|
35
|
+
* from JSONL session logs. Idempotent — skips if threads already exist.
|
|
36
|
+
*
|
|
37
|
+
* @param {string} cwd - Project root
|
|
38
|
+
* @returns {{ migrated: number, totalSessions: number, reason?: string }}
|
|
39
|
+
*/
|
|
40
|
+
function migrateBrainstormSessions(cwd, options = {}) {
|
|
41
|
+
const tracker = require('./cap-thread-tracker.cjs');
|
|
42
|
+
const extract = require('./cap-session-extract.cjs');
|
|
43
|
+
const force = options.force === true;
|
|
44
|
+
|
|
45
|
+
const index = tracker.loadIndex(cwd);
|
|
46
|
+
|
|
47
|
+
// If threads exist and not forcing, check if they need enrichment
|
|
48
|
+
if (index.threads.length > 0 && !force) {
|
|
49
|
+
// Re-migrate if existing threads have empty solutionShape (old metadata-only migration)
|
|
50
|
+
const needsEnrichment = index.threads.some(t => {
|
|
51
|
+
const full = tracker.loadThread(cwd, t.id);
|
|
52
|
+
return full && !full.solutionShape;
|
|
53
|
+
});
|
|
54
|
+
if (!needsEnrichment) {
|
|
55
|
+
return { migrated: 0, totalSessions: 0, reason: 'threads already enriched' };
|
|
56
|
+
}
|
|
57
|
+
// Clear old metadata-only threads before re-migrating
|
|
58
|
+
for (const t of index.threads) {
|
|
59
|
+
tracker.deleteThread(cwd, t.id);
|
|
60
|
+
}
|
|
61
|
+
} else if (index.threads.length > 0 && force) {
|
|
62
|
+
// Force: clear all existing threads
|
|
63
|
+
for (const t of [...index.threads]) {
|
|
64
|
+
tracker.deleteThread(cwd, t.id);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const projectDir = extract.getProjectDir(cwd);
|
|
69
|
+
if (!projectDir) {
|
|
70
|
+
return { migrated: 0, totalSessions: 0, reason: 'no session directory' };
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const sessionFiles = extract.getSessionFiles(projectDir);
|
|
74
|
+
if (sessionFiles.length === 0) {
|
|
75
|
+
return { migrated: 0, totalSessions: 0, reason: 'no sessions' };
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
let migrated = 0;
|
|
79
|
+
for (const sf of sessionFiles) {
|
|
80
|
+
try {
|
|
81
|
+
const result = _extractSessionContext(sf.path);
|
|
82
|
+
if (!result) continue;
|
|
83
|
+
|
|
84
|
+
const thread = tracker.createThread({
|
|
85
|
+
problemStatement: result.problemStatement,
|
|
86
|
+
solutionShape: result.solutionShape,
|
|
87
|
+
boundaryDecisions: result.boundaryDecisions,
|
|
88
|
+
featureIds: result.featureIds,
|
|
89
|
+
});
|
|
90
|
+
if (sf.date) thread.timestamp = sf.date;
|
|
91
|
+
tracker.persistThread(cwd, thread);
|
|
92
|
+
migrated++;
|
|
93
|
+
} catch { /* skip unparseable sessions */ }
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return { migrated, totalSessions: sessionFiles.length };
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Extract meaningful context from a single session JSONL file.
|
|
101
|
+
* Returns null if the session doesn't contain brainstorm-relevant content.
|
|
102
|
+
*
|
|
103
|
+
* @param {string} filePath - Absolute path to JSONL file
|
|
104
|
+
* @returns {{ problemStatement: string, solutionShape: string, boundaryDecisions: string[], featureIds: string[] } | null}
|
|
105
|
+
*/
|
|
106
|
+
function _extractSessionContext(filePath) {
|
|
107
|
+
const content = fs.readFileSync(filePath, 'utf8');
|
|
108
|
+
const lines = content.split('\n').filter(l => l.trim());
|
|
109
|
+
|
|
110
|
+
// Check if this session has brainstorm-relevant content
|
|
111
|
+
let isBrainstorm = false;
|
|
112
|
+
const messages = [];
|
|
113
|
+
|
|
114
|
+
for (const l of lines) {
|
|
115
|
+
try {
|
|
116
|
+
const msg = JSON.parse(l);
|
|
117
|
+
const text = _extractText(msg);
|
|
118
|
+
if (!text || text.length < 10) continue;
|
|
119
|
+
|
|
120
|
+
if (!isBrainstorm) {
|
|
121
|
+
isBrainstorm = BRAINSTORM_MARKERS.some(m => text.includes(m));
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
messages.push({ type: msg.type, text });
|
|
125
|
+
} catch { /* skip */ }
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
if (!isBrainstorm || messages.length < 3) return null;
|
|
129
|
+
|
|
130
|
+
// Require at least 2 substantive user messages (not just command invocations)
|
|
131
|
+
const substantiveUserMsgs = messages.filter(m =>
|
|
132
|
+
m.type === 'user' && m.text.length > 15 &&
|
|
133
|
+
!m.text.startsWith('/') && !/^<command-message>/.test(m.text.trim())
|
|
134
|
+
);
|
|
135
|
+
if (substantiveUserMsgs.length < 2) return null;
|
|
136
|
+
|
|
137
|
+
// Extract problem statement from first substantive user messages
|
|
138
|
+
const problemStatement = _extractProblemStatement(messages);
|
|
139
|
+
|
|
140
|
+
// Extract feature IDs from all messages
|
|
141
|
+
const featureIds = _extractFeatureIds(messages);
|
|
142
|
+
|
|
143
|
+
// Extract solution shape from assistant conclusions/recommendations
|
|
144
|
+
const solutionShape = _extractSolutionShape(messages);
|
|
145
|
+
|
|
146
|
+
// Extract boundary decisions
|
|
147
|
+
const boundaryDecisions = _extractDecisions(messages);
|
|
148
|
+
|
|
149
|
+
// Skip sessions with no meaningful content
|
|
150
|
+
if (!problemStatement && featureIds.length === 0 && !solutionShape) return null;
|
|
151
|
+
|
|
152
|
+
return {
|
|
153
|
+
problemStatement: problemStatement || 'Brainstorm session',
|
|
154
|
+
solutionShape,
|
|
155
|
+
boundaryDecisions,
|
|
156
|
+
featureIds,
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Extract the core problem statement from early user messages.
|
|
162
|
+
* Skips command invocations and short confirmations.
|
|
163
|
+
*/
|
|
164
|
+
function _extractProblemStatement(messages) {
|
|
165
|
+
const userMessages = messages.filter(m => m.type === 'user');
|
|
166
|
+
const parts = [];
|
|
167
|
+
|
|
168
|
+
for (const msg of userMessages) {
|
|
169
|
+
const trimmed = msg.text.trim();
|
|
170
|
+
// Skip commands, short confirmations, interruptions, XML wrappers, and internal Claude context
|
|
171
|
+
if (trimmed.startsWith('/') || trimmed.length < 15) continue;
|
|
172
|
+
if (/^<(?:command-message|command-name|local-command-caveat|context|objective|system-reminder)>/.test(trimmed)) continue;
|
|
173
|
+
if (/^<!--/.test(trimmed)) continue;
|
|
174
|
+
if (/^#\s*\/(?:cap|gsd):/.test(trimmed)) continue;
|
|
175
|
+
if (/^Unknown skill:/.test(trimmed)) continue;
|
|
176
|
+
if (/^(ja|yes|ok|nein|no|weiter|continue|gut|perfect|danke|mach|schau)\b/i.test(trimmed)) continue;
|
|
177
|
+
if (trimmed.includes('[Request interrupted')) continue;
|
|
178
|
+
|
|
179
|
+
parts.push(msg.text.trim());
|
|
180
|
+
// Take first 2-3 substantive user messages to capture the problem
|
|
181
|
+
if (parts.length >= 3) break;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
if (parts.length === 0) return '';
|
|
185
|
+
|
|
186
|
+
const combined = parts.join(' | ');
|
|
187
|
+
return combined.length > MAX_PROBLEM ? combined.substring(0, MAX_PROBLEM).replace(/\s\S*$/, '...') : combined;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Extract solution shape from assistant messages containing decisions/recommendations.
|
|
192
|
+
* Looks for the most informative assistant message that summarizes the approach.
|
|
193
|
+
*/
|
|
194
|
+
function _extractSolutionShape(messages) {
|
|
195
|
+
const candidates = [];
|
|
196
|
+
|
|
197
|
+
for (const msg of messages) {
|
|
198
|
+
if (msg.type !== 'assistant') continue;
|
|
199
|
+
if (msg.text.length < 80) continue;
|
|
200
|
+
|
|
201
|
+
const hasDecision = DECISION_PATTERNS.some(p => p.test(msg.text));
|
|
202
|
+
if (!hasDecision) continue;
|
|
203
|
+
|
|
204
|
+
// Score by relevance: longer + more decision patterns = better
|
|
205
|
+
const patternCount = DECISION_PATTERNS.filter(p => p.test(msg.text)).length;
|
|
206
|
+
candidates.push({
|
|
207
|
+
text: msg.text,
|
|
208
|
+
score: patternCount * 10 + Math.min(msg.text.length / 100, 5),
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
if (candidates.length === 0) return '';
|
|
213
|
+
|
|
214
|
+
// Take the highest-scoring candidate
|
|
215
|
+
candidates.sort((a, b) => b.score - a.score);
|
|
216
|
+
const best = candidates[0].text;
|
|
217
|
+
|
|
218
|
+
// Extract the most relevant paragraph (first one with a decision pattern)
|
|
219
|
+
const paragraphs = best.split(/\n\n+/);
|
|
220
|
+
for (const p of paragraphs) {
|
|
221
|
+
if (p.length > 40 && DECISION_PATTERNS.some(pat => pat.test(p))) {
|
|
222
|
+
const trimmed = p.replace(/^#+\s*/, '').trim();
|
|
223
|
+
return trimmed.length > MAX_SOLUTION ? trimmed.substring(0, MAX_SOLUTION).replace(/\s\S*$/, '...') : trimmed;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
// Fallback: first 500 chars of best candidate
|
|
228
|
+
return best.length > MAX_SOLUTION ? best.substring(0, MAX_SOLUTION).replace(/\s\S*$/, '...') : best;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* Extract key decisions/conclusions from assistant messages.
|
|
233
|
+
* Returns compact one-line summaries.
|
|
234
|
+
*/
|
|
235
|
+
function _extractDecisions(messages) {
|
|
236
|
+
const decisions = [];
|
|
237
|
+
const seen = new Set();
|
|
238
|
+
|
|
239
|
+
for (const msg of messages) {
|
|
240
|
+
if (msg.type !== 'assistant') continue;
|
|
241
|
+
if (msg.text.length < 50) continue;
|
|
242
|
+
|
|
243
|
+
// Look for bullet points or numbered lists that state decisions
|
|
244
|
+
const bulletMatches = msg.text.match(/^[\s]*[-*]\s+\*\*[^*]+\*\*[^*\n]*/gm) || [];
|
|
245
|
+
for (const bullet of bulletMatches) {
|
|
246
|
+
const clean = bullet.replace(/^[\s]*[-*]\s+/, '').replace(/\*\*/g, '').trim();
|
|
247
|
+
if (clean.length > 20 && clean.length < MAX_DECISION && !seen.has(clean)) {
|
|
248
|
+
seen.add(clean);
|
|
249
|
+
decisions.push(clean);
|
|
250
|
+
}
|
|
251
|
+
if (decisions.length >= MAX_DECISIONS) break;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
// Also look for "Fazit:", "Empfehlung:", "Decision:" lines
|
|
255
|
+
const labelMatches = msg.text.match(/^(?:Fazit|Ergebnis|Empfehlung|Decision|Conclusion|Approach|Ansatz)\s*:\s*.+/gim) || [];
|
|
256
|
+
for (const label of labelMatches) {
|
|
257
|
+
const clean = label.trim();
|
|
258
|
+
if (clean.length > 15 && clean.length < MAX_DECISION && !seen.has(clean)) {
|
|
259
|
+
seen.add(clean);
|
|
260
|
+
decisions.push(clean);
|
|
261
|
+
}
|
|
262
|
+
if (decisions.length >= MAX_DECISIONS) break;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
if (decisions.length >= MAX_DECISIONS) break;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
return decisions;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
/**
|
|
272
|
+
* Extract unique feature IDs from all messages.
|
|
273
|
+
*/
|
|
274
|
+
function _extractFeatureIds(messages) {
|
|
275
|
+
const ids = new Set();
|
|
276
|
+
for (const msg of messages) {
|
|
277
|
+
const matches = msg.text.match(/F-\d{3}/g);
|
|
278
|
+
if (matches) matches.forEach(id => ids.add(id));
|
|
279
|
+
}
|
|
280
|
+
return [...ids];
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
/**
|
|
284
|
+
* Extract text content from a JSONL message object.
|
|
285
|
+
* @param {Object} msg
|
|
286
|
+
* @returns {string}
|
|
287
|
+
*/
|
|
288
|
+
function _extractText(msg) {
|
|
289
|
+
const content = msg.message?.content;
|
|
290
|
+
if (!content) return '';
|
|
291
|
+
if (typeof content === 'string') return content;
|
|
292
|
+
if (Array.isArray(content)) {
|
|
293
|
+
return content.filter(c => c.type === 'text').map(c => c.text || '').join(' ');
|
|
294
|
+
}
|
|
295
|
+
return '';
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
module.exports = {
|
|
299
|
+
migrateBrainstormSessions,
|
|
300
|
+
// Exposed for testing
|
|
301
|
+
_extractSessionContext,
|
|
302
|
+
_extractProblemStatement,
|
|
303
|
+
_extractSolutionShape,
|
|
304
|
+
_extractDecisions,
|
|
305
|
+
_extractFeatureIds,
|
|
306
|
+
_extractText,
|
|
307
|
+
};
|