@assistkick/create 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/dist/bin/create.d.ts +2 -0
- package/dist/bin/create.js +25 -0
- package/dist/bin/create.js.map +1 -0
- package/dist/src/scaffolder.d.ts +22 -0
- package/dist/src/scaffolder.js +120 -0
- package/dist/src/scaffolder.js.map +1 -0
- package/package.json +24 -0
- package/templates/product-system/.env.example +8 -0
- package/templates/product-system/CLAUDE.md +45 -0
- package/templates/product-system/package.json +32 -0
- package/templates/product-system/packages/backend/package.json +37 -0
- package/templates/product-system/packages/backend/src/middleware/auth_middleware.test.ts +86 -0
- package/templates/product-system/packages/backend/src/middleware/auth_middleware.ts +35 -0
- package/templates/product-system/packages/backend/src/routes/auth.ts +463 -0
- package/templates/product-system/packages/backend/src/routes/coherence.ts +187 -0
- package/templates/product-system/packages/backend/src/routes/graph.ts +67 -0
- package/templates/product-system/packages/backend/src/routes/kanban.ts +201 -0
- package/templates/product-system/packages/backend/src/routes/pipeline.ts +41 -0
- package/templates/product-system/packages/backend/src/routes/projects.ts +122 -0
- package/templates/product-system/packages/backend/src/routes/users.ts +97 -0
- package/templates/product-system/packages/backend/src/server.ts +159 -0
- package/templates/product-system/packages/backend/src/services/auth_service.test.ts +115 -0
- package/templates/product-system/packages/backend/src/services/auth_service.ts +82 -0
- package/templates/product-system/packages/backend/src/services/coherence-review.ts +339 -0
- package/templates/product-system/packages/backend/src/services/email_service.ts +75 -0
- package/templates/product-system/packages/backend/src/services/init.ts +80 -0
- package/templates/product-system/packages/backend/src/services/invitation_service.test.ts +235 -0
- package/templates/product-system/packages/backend/src/services/invitation_service.ts +193 -0
- package/templates/product-system/packages/backend/src/services/password_reset_service.test.ts +151 -0
- package/templates/product-system/packages/backend/src/services/password_reset_service.ts +135 -0
- package/templates/product-system/packages/backend/src/services/project_service.test.ts +215 -0
- package/templates/product-system/packages/backend/src/services/project_service.ts +171 -0
- package/templates/product-system/packages/backend/src/services/pty_session_manager.test.ts +88 -0
- package/templates/product-system/packages/backend/src/services/pty_session_manager.ts +279 -0
- package/templates/product-system/packages/backend/src/services/terminal_ws_handler.ts +133 -0
- package/templates/product-system/packages/backend/src/services/user_management_service.test.ts +158 -0
- package/templates/product-system/packages/backend/src/services/user_management_service.ts +128 -0
- package/templates/product-system/packages/backend/tsconfig.json +22 -0
- package/templates/product-system/packages/frontend/index.html +13 -0
- package/templates/product-system/packages/frontend/package-lock.json +2666 -0
- package/templates/product-system/packages/frontend/package.json +30 -0
- package/templates/product-system/packages/frontend/public/favicon.svg +16 -0
- package/templates/product-system/packages/frontend/src/App.tsx +29 -0
- package/templates/product-system/packages/frontend/src/api/client.ts +386 -0
- package/templates/product-system/packages/frontend/src/api/client_projects.test.ts +104 -0
- package/templates/product-system/packages/frontend/src/api/client_refresh.test.ts +145 -0
- package/templates/product-system/packages/frontend/src/components/CoherenceView.tsx +414 -0
- package/templates/product-system/packages/frontend/src/components/GraphLegend.tsx +124 -0
- package/templates/product-system/packages/frontend/src/components/GraphSettings.tsx +112 -0
- package/templates/product-system/packages/frontend/src/components/GraphView.tsx +370 -0
- package/templates/product-system/packages/frontend/src/components/InviteUserDialog.tsx +85 -0
- package/templates/product-system/packages/frontend/src/components/KanbanView.tsx +470 -0
- package/templates/product-system/packages/frontend/src/components/LoginPage.tsx +116 -0
- package/templates/product-system/packages/frontend/src/components/ProjectSelector.tsx +187 -0
- package/templates/product-system/packages/frontend/src/components/QaIssueSheet.tsx +192 -0
- package/templates/product-system/packages/frontend/src/components/SidePanel.tsx +231 -0
- package/templates/product-system/packages/frontend/src/components/TerminalView.tsx +200 -0
- package/templates/product-system/packages/frontend/src/components/Toolbar.tsx +84 -0
- package/templates/product-system/packages/frontend/src/components/UsersView.tsx +249 -0
- package/templates/product-system/packages/frontend/src/constants/graph.ts +191 -0
- package/templates/product-system/packages/frontend/src/hooks/useAuth.tsx +54 -0
- package/templates/product-system/packages/frontend/src/hooks/useGraph.ts +27 -0
- package/templates/product-system/packages/frontend/src/hooks/useKanban.ts +21 -0
- package/templates/product-system/packages/frontend/src/hooks/useProjects.ts +86 -0
- package/templates/product-system/packages/frontend/src/hooks/useTheme.ts +26 -0
- package/templates/product-system/packages/frontend/src/hooks/useToast.tsx +62 -0
- package/templates/product-system/packages/frontend/src/hooks/use_projects_logic.test.ts +61 -0
- package/templates/product-system/packages/frontend/src/main.tsx +12 -0
- package/templates/product-system/packages/frontend/src/pages/accept_invitation_page.tsx +167 -0
- package/templates/product-system/packages/frontend/src/pages/forgot_password_page.tsx +100 -0
- package/templates/product-system/packages/frontend/src/pages/register_page.tsx +137 -0
- package/templates/product-system/packages/frontend/src/pages/reset_password_page.tsx +146 -0
- package/templates/product-system/packages/frontend/src/routes/ProtectedRoute.tsx +12 -0
- package/templates/product-system/packages/frontend/src/routes/accept_invitation.tsx +14 -0
- package/templates/product-system/packages/frontend/src/routes/dashboard.tsx +221 -0
- package/templates/product-system/packages/frontend/src/routes/forgot_password.tsx +13 -0
- package/templates/product-system/packages/frontend/src/routes/login.tsx +14 -0
- package/templates/product-system/packages/frontend/src/routes/register.tsx +14 -0
- package/templates/product-system/packages/frontend/src/routes/reset_password.tsx +13 -0
- package/templates/product-system/packages/frontend/src/styles/index.css +3358 -0
- package/templates/product-system/packages/frontend/src/utils/auth_validation.test.ts +51 -0
- package/templates/product-system/packages/frontend/src/utils/auth_validation.ts +19 -0
- package/templates/product-system/packages/frontend/src/utils/login_validation.test.ts +61 -0
- package/templates/product-system/packages/frontend/src/utils/login_validation.ts +24 -0
- package/templates/product-system/packages/frontend/src/utils/logout.test.ts +63 -0
- package/templates/product-system/packages/frontend/src/utils/node_sizing.test.ts +62 -0
- package/templates/product-system/packages/frontend/src/utils/node_sizing.ts +24 -0
- package/templates/product-system/packages/frontend/src/utils/task_status.test.ts +53 -0
- package/templates/product-system/packages/frontend/src/utils/task_status.ts +14 -0
- package/templates/product-system/packages/frontend/tsconfig.json +21 -0
- package/templates/product-system/packages/frontend/vite.config.ts +20 -0
- package/templates/product-system/packages/shared/.env.example +3 -0
- package/templates/product-system/packages/shared/README.md +1 -0
- package/templates/product-system/packages/shared/db/migrate.ts +32 -0
- package/templates/product-system/packages/shared/db/migrations/0000_dashing_gorgon.sql +128 -0
- package/templates/product-system/packages/shared/db/migrations/meta/0000_snapshot.json +819 -0
- package/templates/product-system/packages/shared/db/migrations/meta/_journal.json +13 -0
- package/templates/product-system/packages/shared/db/schema.ts +137 -0
- package/templates/product-system/packages/shared/drizzle.config.js +14 -0
- package/templates/product-system/packages/shared/lib/claude-service.ts +215 -0
- package/templates/product-system/packages/shared/lib/coherence.ts +278 -0
- package/templates/product-system/packages/shared/lib/completeness.ts +30 -0
- package/templates/product-system/packages/shared/lib/constants.ts +327 -0
- package/templates/product-system/packages/shared/lib/db.ts +81 -0
- package/templates/product-system/packages/shared/lib/git_workflow.ts +110 -0
- package/templates/product-system/packages/shared/lib/graph.ts +186 -0
- package/templates/product-system/packages/shared/lib/kanban.ts +161 -0
- package/templates/product-system/packages/shared/lib/markdown.ts +205 -0
- package/templates/product-system/packages/shared/lib/pipeline-state-store.ts +124 -0
- package/templates/product-system/packages/shared/lib/pipeline.ts +489 -0
- package/templates/product-system/packages/shared/lib/prompt_builder.ts +170 -0
- package/templates/product-system/packages/shared/lib/relevance_search.ts +159 -0
- package/templates/product-system/packages/shared/lib/session.ts +152 -0
- package/templates/product-system/packages/shared/lib/validator.ts +117 -0
- package/templates/product-system/packages/shared/lib/work_summary_parser.ts +130 -0
- package/templates/product-system/packages/shared/package.json +30 -0
- package/templates/product-system/packages/shared/scripts/assign-project.ts +52 -0
- package/templates/product-system/packages/shared/tools/add_edge.ts +61 -0
- package/templates/product-system/packages/shared/tools/add_node.ts +101 -0
- package/templates/product-system/packages/shared/tools/end_session.ts +87 -0
- package/templates/product-system/packages/shared/tools/get_gaps.ts +87 -0
- package/templates/product-system/packages/shared/tools/get_kanban.ts +125 -0
- package/templates/product-system/packages/shared/tools/get_node.ts +78 -0
- package/templates/product-system/packages/shared/tools/get_status.ts +98 -0
- package/templates/product-system/packages/shared/tools/migrate_to_turso.ts +385 -0
- package/templates/product-system/packages/shared/tools/move_card.ts +143 -0
- package/templates/product-system/packages/shared/tools/rebuild_index.ts +77 -0
- package/templates/product-system/packages/shared/tools/remove_edge.ts +59 -0
- package/templates/product-system/packages/shared/tools/remove_node.ts +96 -0
- package/templates/product-system/packages/shared/tools/resolve_question.ts +75 -0
- package/templates/product-system/packages/shared/tools/search_nodes.ts +106 -0
- package/templates/product-system/packages/shared/tools/start_session.ts +144 -0
- package/templates/product-system/packages/shared/tools/update_node.ts +133 -0
- package/templates/product-system/packages/shared/tsconfig.json +24 -0
- package/templates/product-system/pnpm-workspace.yaml +2 -0
- package/templates/product-system/smoke_test.ts +219 -0
- package/templates/product-system/tests/coherence_review.test.ts +562 -0
- package/templates/product-system/tests/db_sqlite_fallback.test.ts +75 -0
- package/templates/product-system/tests/edge_type_color_coding.test.ts +147 -0
- package/templates/product-system/tests/emit-tool-use-events.test.ts +85 -0
- package/templates/product-system/tests/feature_kind.test.ts +139 -0
- package/templates/product-system/tests/gap_indicators.test.ts +199 -0
- package/templates/product-system/tests/graceful_init.test.ts +142 -0
- package/templates/product-system/tests/graph_legend.test.ts +314 -0
- package/templates/product-system/tests/graph_settings_sheet.test.ts +804 -0
- package/templates/product-system/tests/hide_defined_filter.test.ts +205 -0
- package/templates/product-system/tests/kanban.test.ts +529 -0
- package/templates/product-system/tests/neighborhood_focus.test.ts +132 -0
- package/templates/product-system/tests/node_search.test.ts +340 -0
- package/templates/product-system/tests/node_sizing.test.ts +170 -0
- package/templates/product-system/tests/node_type_toggle_filters.test.ts +285 -0
- package/templates/product-system/tests/node_type_visual_encoding.test.ts +103 -0
- package/templates/product-system/tests/pipeline-state-store.test.ts +268 -0
- package/templates/product-system/tests/pipeline-unit.test.ts +593 -0
- package/templates/product-system/tests/pipeline.test.ts +195 -0
- package/templates/product-system/tests/pipeline_stats_all_cards.test.ts +193 -0
- package/templates/product-system/tests/play_all.test.ts +296 -0
- package/templates/product-system/tests/qa_issue_sheet.test.ts +464 -0
- package/templates/product-system/tests/relevance_search.test.ts +186 -0
- package/templates/product-system/tests/search_reorder.test.ts +88 -0
- package/templates/product-system/tests/serve_ui.test.ts +281 -0
- package/templates/product-system/tests/serve_ui_drizzle.test.ts +114 -0
- package/templates/product-system/tests/session_context_recall.test.ts +135 -0
- package/templates/product-system/tests/side_panel.test.ts +345 -0
- package/templates/product-system/tests/spec_completeness_label.test.ts +69 -0
- package/templates/product-system/tests/url_routing_test.ts +122 -0
- package/templates/product-system/tests/user_login.test.ts +150 -0
- package/templates/product-system/tests/user_registration.test.ts +205 -0
- package/templates/product-system/tests/web_terminal.test.ts +572 -0
- package/templates/product-system/tests/work_summary.test.ts +211 -0
- package/templates/product-system/tests/zoom_pan.test.ts +43 -0
- package/templates/product-system/tsconfig.json +24 -0
- package/templates/skills/product-bootstrap/SKILL.md +312 -0
- package/templates/skills/product-code-reviewer/SKILL.md +147 -0
- package/templates/skills/product-debugger/SKILL.md +206 -0
- package/templates/skills/product-debugger/references/agent-browser.md +1156 -0
- package/templates/skills/product-developer/SKILL.md +182 -0
- package/templates/skills/product-interview/SKILL.md +220 -0
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for WorkSummaryParser — parsing structured work summaries from
|
|
3
|
+
* developer Claude output and git diff --name-status.
|
|
4
|
+
* Uses node:test built-in runner per nfr_001.
|
|
5
|
+
*/
|
|
6
|
+
import { describe, it } from 'node:test';
|
|
7
|
+
import assert from 'node:assert/strict';
|
|
8
|
+
import { WorkSummaryParser } from '../packages/shared/lib/work_summary_parser.js';
|
|
9
|
+
|
|
10
|
+
describe('WorkSummaryParser', () => {
|
|
11
|
+
describe('parseFromOutput', () => {
|
|
12
|
+
it('extracts approach and decisions from well-formed output', () => {
|
|
13
|
+
const parser = new WorkSummaryParser();
|
|
14
|
+
const output = `
|
|
15
|
+
Some implementation text here...
|
|
16
|
+
|
|
17
|
+
## Work Summary
|
|
18
|
+
### Approach
|
|
19
|
+
I added a new column to the database and updated the pipeline to capture developer output after each cycle. The work summary is parsed from a structured block in the Claude output.
|
|
20
|
+
### Decisions
|
|
21
|
+
- Used a JSON column instead of a separate table for simplicity
|
|
22
|
+
- Chose to capture git diff --name-status rather than full diff to keep data small
|
|
23
|
+
- Made the work summary section collapsible in the UI
|
|
24
|
+
`;
|
|
25
|
+
|
|
26
|
+
const result = parser.parseFromOutput(output);
|
|
27
|
+
|
|
28
|
+
assert.ok(result.approach.includes('added a new column'));
|
|
29
|
+
assert.equal(result.decisions.length, 3);
|
|
30
|
+
assert.ok(result.decisions[0].includes('JSON column'));
|
|
31
|
+
assert.ok(result.decisions[1].includes('git diff'));
|
|
32
|
+
assert.ok(result.decisions[2].includes('collapsible'));
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it('returns empty values when no work summary block exists', () => {
|
|
36
|
+
const parser = new WorkSummaryParser();
|
|
37
|
+
const output = 'Just some regular output without a work summary.';
|
|
38
|
+
|
|
39
|
+
const result = parser.parseFromOutput(output);
|
|
40
|
+
|
|
41
|
+
assert.equal(result.approach, '');
|
|
42
|
+
assert.deepEqual(result.decisions, []);
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
it('handles approach without decisions', () => {
|
|
46
|
+
const parser = new WorkSummaryParser();
|
|
47
|
+
const output = `
|
|
48
|
+
## Work Summary
|
|
49
|
+
### Approach
|
|
50
|
+
Simple implementation with minimal changes.
|
|
51
|
+
`;
|
|
52
|
+
|
|
53
|
+
const result = parser.parseFromOutput(output);
|
|
54
|
+
|
|
55
|
+
assert.ok(result.approach.includes('Simple implementation'));
|
|
56
|
+
assert.deepEqual(result.decisions, []);
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it('handles decisions with asterisk bullets', () => {
|
|
60
|
+
const parser = new WorkSummaryParser();
|
|
61
|
+
const output = `
|
|
62
|
+
## Work Summary
|
|
63
|
+
### Approach
|
|
64
|
+
Did the thing.
|
|
65
|
+
### Decisions
|
|
66
|
+
* Decision one
|
|
67
|
+
* Decision two
|
|
68
|
+
`;
|
|
69
|
+
|
|
70
|
+
const result = parser.parseFromOutput(output);
|
|
71
|
+
|
|
72
|
+
assert.equal(result.decisions.length, 2);
|
|
73
|
+
assert.equal(result.decisions[0], 'Decision one');
|
|
74
|
+
assert.equal(result.decisions[1], 'Decision two');
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
it('stops parsing decisions at next heading', () => {
|
|
78
|
+
const parser = new WorkSummaryParser();
|
|
79
|
+
const output = `
|
|
80
|
+
## Work Summary
|
|
81
|
+
### Approach
|
|
82
|
+
Did it.
|
|
83
|
+
### Decisions
|
|
84
|
+
- Decision A
|
|
85
|
+
|
|
86
|
+
## Some Other Section
|
|
87
|
+
This should not be parsed as decisions.
|
|
88
|
+
`;
|
|
89
|
+
|
|
90
|
+
const result = parser.parseFromOutput(output);
|
|
91
|
+
|
|
92
|
+
assert.equal(result.decisions.length, 1);
|
|
93
|
+
assert.equal(result.decisions[0], 'Decision A');
|
|
94
|
+
});
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
describe('parseDiffNameStatus', () => {
|
|
98
|
+
it('categorizes files by A/M/D status markers', () => {
|
|
99
|
+
const parser = new WorkSummaryParser();
|
|
100
|
+
const diffOutput = `A\tpackages/shared/lib/new_file.ts
|
|
101
|
+
M\tpackages/shared/lib/pipeline.ts
|
|
102
|
+
M\tpackages/shared/db/schema.ts
|
|
103
|
+
D\tpackages/frontend/src/old_component.tsx
|
|
104
|
+
A\tpackages/frontend/src/KanbanView.tsx`;
|
|
105
|
+
|
|
106
|
+
const result = parser.parseDiffNameStatus(diffOutput);
|
|
107
|
+
|
|
108
|
+
assert.deepEqual(result.filesCreated, [
|
|
109
|
+
'packages/shared/lib/new_file.ts',
|
|
110
|
+
'packages/frontend/src/KanbanView.tsx',
|
|
111
|
+
]);
|
|
112
|
+
assert.deepEqual(result.filesUpdated, [
|
|
113
|
+
'packages/shared/lib/pipeline.ts',
|
|
114
|
+
'packages/shared/db/schema.ts',
|
|
115
|
+
]);
|
|
116
|
+
assert.deepEqual(result.filesDeleted, [
|
|
117
|
+
'packages/frontend/src/old_component.tsx',
|
|
118
|
+
]);
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
it('returns empty arrays for empty diff', () => {
|
|
122
|
+
const parser = new WorkSummaryParser();
|
|
123
|
+
const result = parser.parseDiffNameStatus('');
|
|
124
|
+
|
|
125
|
+
assert.deepEqual(result.filesCreated, []);
|
|
126
|
+
assert.deepEqual(result.filesUpdated, []);
|
|
127
|
+
assert.deepEqual(result.filesDeleted, []);
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
it('handles single added file', () => {
|
|
131
|
+
const parser = new WorkSummaryParser();
|
|
132
|
+
const diffOutput = `A\tsrc/index.ts`;
|
|
133
|
+
|
|
134
|
+
const result = parser.parseDiffNameStatus(diffOutput);
|
|
135
|
+
|
|
136
|
+
assert.deepEqual(result.filesCreated, ['src/index.ts']);
|
|
137
|
+
assert.deepEqual(result.filesUpdated, []);
|
|
138
|
+
assert.deepEqual(result.filesDeleted, []);
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
it('handles single modified file', () => {
|
|
142
|
+
const parser = new WorkSummaryParser();
|
|
143
|
+
const diffOutput = `M\tsrc/index.ts`;
|
|
144
|
+
|
|
145
|
+
const result = parser.parseDiffNameStatus(diffOutput);
|
|
146
|
+
|
|
147
|
+
assert.deepEqual(result.filesCreated, []);
|
|
148
|
+
assert.deepEqual(result.filesUpdated, ['src/index.ts']);
|
|
149
|
+
assert.deepEqual(result.filesDeleted, []);
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
it('handles single deleted file', () => {
|
|
153
|
+
const parser = new WorkSummaryParser();
|
|
154
|
+
const diffOutput = `D\tsrc/removed.ts`;
|
|
155
|
+
|
|
156
|
+
const result = parser.parseDiffNameStatus(diffOutput);
|
|
157
|
+
|
|
158
|
+
assert.deepEqual(result.filesCreated, []);
|
|
159
|
+
assert.deepEqual(result.filesUpdated, []);
|
|
160
|
+
assert.deepEqual(result.filesDeleted, ['src/removed.ts']);
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
it('treats unknown status markers as updated', () => {
|
|
164
|
+
const parser = new WorkSummaryParser();
|
|
165
|
+
const diffOutput = `R\tsrc/renamed.ts`;
|
|
166
|
+
|
|
167
|
+
const result = parser.parseDiffNameStatus(diffOutput);
|
|
168
|
+
|
|
169
|
+
assert.deepEqual(result.filesCreated, []);
|
|
170
|
+
assert.deepEqual(result.filesUpdated, ['src/renamed.ts']);
|
|
171
|
+
assert.deepEqual(result.filesDeleted, []);
|
|
172
|
+
});
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
describe('buildSummary', () => {
|
|
176
|
+
it('combines cycle, diff name-status, and Claude output into a WorkSummary', () => {
|
|
177
|
+
const parser = new WorkSummaryParser();
|
|
178
|
+
const diffOutput = `A\tsrc/new.ts
|
|
179
|
+
M\tsrc/foo.ts`;
|
|
180
|
+
const claudeOutput = `
|
|
181
|
+
## Work Summary
|
|
182
|
+
### Approach
|
|
183
|
+
Implemented the feature by adding a new module.
|
|
184
|
+
### Decisions
|
|
185
|
+
- Chose class-based approach per nfr_001
|
|
186
|
+
`;
|
|
187
|
+
|
|
188
|
+
const summary = parser.buildSummary(1, diffOutput, claudeOutput);
|
|
189
|
+
|
|
190
|
+
assert.equal(summary.cycle, 1);
|
|
191
|
+
assert.deepEqual(summary.filesCreated, ['src/new.ts']);
|
|
192
|
+
assert.deepEqual(summary.filesUpdated, ['src/foo.ts']);
|
|
193
|
+
assert.deepEqual(summary.filesDeleted, []);
|
|
194
|
+
assert.ok(summary.approach.includes('new module'));
|
|
195
|
+
assert.equal(summary.decisions.length, 1);
|
|
196
|
+
assert.ok(summary.timestamp);
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
it('provides default approach when none in output', () => {
|
|
200
|
+
const parser = new WorkSummaryParser();
|
|
201
|
+
const summary = parser.buildSummary(2, '', 'No summary block here');
|
|
202
|
+
|
|
203
|
+
assert.equal(summary.cycle, 2);
|
|
204
|
+
assert.deepEqual(summary.filesCreated, []);
|
|
205
|
+
assert.deepEqual(summary.filesUpdated, []);
|
|
206
|
+
assert.deepEqual(summary.filesDeleted, []);
|
|
207
|
+
assert.equal(summary.approach, 'No approach narrative provided.');
|
|
208
|
+
assert.deepEqual(summary.decisions, []);
|
|
209
|
+
});
|
|
210
|
+
});
|
|
211
|
+
});
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for Zoom and Pan logic (feat_019).
|
|
3
|
+
* Tests pure computation functions extracted from GraphView.
|
|
4
|
+
*/
|
|
5
|
+
import { describe, it } from 'node:test';
|
|
6
|
+
import assert from 'node:assert/strict';
|
|
7
|
+
|
|
8
|
+
// Pure function extracted from GraphView
|
|
9
|
+
const nodeRadius = (d: { edgeCount: number }) => {
|
|
10
|
+
const base = 8;
|
|
11
|
+
const scale = Math.min(d.edgeCount * 1.5, 20);
|
|
12
|
+
return base + scale;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
describe('Zoom and Pan', () => {
|
|
16
|
+
|
|
17
|
+
describe('nodeRadius (affects zoom bounds)', () => {
|
|
18
|
+
it('returns base radius of 8 for zero-edge node', () => {
|
|
19
|
+
assert.equal(nodeRadius({ edgeCount: 0 }), 8);
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it('increases radius with edge count', () => {
|
|
23
|
+
const r0 = nodeRadius({ edgeCount: 0 });
|
|
24
|
+
const r5 = nodeRadius({ edgeCount: 5 });
|
|
25
|
+
assert.ok(r5 > r0, 'more edges should yield larger radius');
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it('caps radius at 28 (8 base + 20 max scale)', () => {
|
|
29
|
+
assert.equal(nodeRadius({ edgeCount: 100 }), 28);
|
|
30
|
+
assert.equal(nodeRadius({ edgeCount: 200 }), 28);
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
describe('nodeRadius consistency', () => {
|
|
35
|
+
it('nodeRadius returns consistent values for force simulation', () => {
|
|
36
|
+
const node = { edgeCount: 5 };
|
|
37
|
+
const r1 = nodeRadius(node);
|
|
38
|
+
const r2 = nodeRadius(node);
|
|
39
|
+
assert.equal(r1, r2);
|
|
40
|
+
assert.equal(r1, 8 + Math.min(5 * 1.5, 20)); // 15.5
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
});
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"strict": false,
|
|
4
|
+
"allowJs": true,
|
|
5
|
+
"module": "NodeNext",
|
|
6
|
+
"moduleResolution": "NodeNext",
|
|
7
|
+
"target": "ESNext",
|
|
8
|
+
"esModuleInterop": true,
|
|
9
|
+
"skipLibCheck": true,
|
|
10
|
+
"forceConsistentCasingInFileNames": true,
|
|
11
|
+
"outDir": "build",
|
|
12
|
+
"rootDir": ".",
|
|
13
|
+
"sourceMap": true,
|
|
14
|
+
"declaration": true
|
|
15
|
+
},
|
|
16
|
+
"include": [
|
|
17
|
+
"tests/**/*.ts",
|
|
18
|
+
"smoke_test.ts"
|
|
19
|
+
],
|
|
20
|
+
"exclude": [
|
|
21
|
+
"node_modules",
|
|
22
|
+
"packages"
|
|
23
|
+
]
|
|
24
|
+
}
|
|
@@ -0,0 +1,312 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: product-bootstrap
|
|
3
|
+
description: Bootstrap the product knowledge graph for an existing project by scanning the codebase and interviewing the user. Use when the user wants to onboard a project, bootstrap the graph, initialize the product system, or bring the knowledge graph up to speed for an existing codebase.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Product Bootstrap Skill
|
|
7
|
+
|
|
8
|
+
## Your Role
|
|
9
|
+
You are bootstrapping the product knowledge graph for an existing project.
|
|
10
|
+
Your goal is to rapidly build a well-connected specification graph by
|
|
11
|
+
**scanning the codebase first** and **asking the user only about intent,
|
|
12
|
+
priorities, and preferences**. You interact with the graph exclusively
|
|
13
|
+
through the tools below.
|
|
14
|
+
|
|
15
|
+
All tools live in `product-system/packages/shared/tools/` and
|
|
16
|
+
are run with `npx tsx`.
|
|
17
|
+
|
|
18
|
+
## Bootstrap Philosophy
|
|
19
|
+
Unlike a greenfield interview, the project already exists. The codebase is
|
|
20
|
+
the primary source of truth for **what exists**. The user is the source of
|
|
21
|
+
truth for **what matters, what's next, and why**.
|
|
22
|
+
|
|
23
|
+
- **Read code first, ask questions second**
|
|
24
|
+
- **Populate aggressively** — create nodes for everything you discover
|
|
25
|
+
- **Ask the user to confirm and prioritize**, not to describe what you can see
|
|
26
|
+
- **Wire edges densely** — a bootstrap graph with sparse edges is useless
|
|
27
|
+
|
|
28
|
+
## Session Start Protocol
|
|
29
|
+
1. Call `start_session`
|
|
30
|
+
2. Call `get_status` — check if this is a cold start or a continuation
|
|
31
|
+
3. If cold start (empty graph): begin with **Phase 1**
|
|
32
|
+
4. If continuing: call `get_gaps --blocking-only` and resume at the
|
|
33
|
+
appropriate phase
|
|
34
|
+
|
|
35
|
+
## Phase 1 — Project Survey (Codebase Scan)
|
|
36
|
+
|
|
37
|
+
**Goal:** Understand the project structure, tech stack, and domain without
|
|
38
|
+
asking the user a single question yet.
|
|
39
|
+
|
|
40
|
+
1. **Explore the project root** — read `package.json`, `Cargo.toml`,
|
|
41
|
+
`pyproject.toml`, `go.mod`, `Gemfile`, or equivalent to identify:
|
|
42
|
+
- Language and framework
|
|
43
|
+
- Key dependencies
|
|
44
|
+
- Build system and scripts
|
|
45
|
+
2. **Scan directory structure** — use Glob to map top-level directories and
|
|
46
|
+
understand the layout (e.g. `src/`, `lib/`, `api/`, `components/`,
|
|
47
|
+
`models/`, `migrations/`)
|
|
48
|
+
3. **Read configuration files** — `.env.example`, CI configs, Docker files,
|
|
49
|
+
`tsconfig.json`, etc. to identify infrastructure and deployment patterns
|
|
50
|
+
4. **Identify data models** — look for ORM models, database schemas,
|
|
51
|
+
migration files, type definitions, or GraphQL schemas
|
|
52
|
+
5. **Identify API surface** — look for route definitions, controllers,
|
|
53
|
+
resolvers, or API handlers
|
|
54
|
+
6. **Identify UI structure** (if applicable) — look for pages, components,
|
|
55
|
+
layouts
|
|
56
|
+
|
|
57
|
+
**Output of Phase 1:** A mental map of the project. Do NOT create nodes yet.
|
|
58
|
+
Present a summary to the user:
|
|
59
|
+
- "Here's what I found in your codebase: [tech stack], [main modules],
|
|
60
|
+
[data entities], [API shape]. Does this look right? Anything I missed?"
|
|
61
|
+
|
|
62
|
+
## Phase 2 — Foundation Nodes
|
|
63
|
+
|
|
64
|
+
**Goal:** Create the structural backbone of the graph. Create nodes in this
|
|
65
|
+
order, using what you learned in Phase 1.
|
|
66
|
+
|
|
67
|
+
### 2a. Tech Choices
|
|
68
|
+
For each technology identified (language, framework, database, hosting,
|
|
69
|
+
key libraries), create a `tech_choice` node:
|
|
70
|
+
```
|
|
71
|
+
add_node --type tech_choice --name "TypeScript" --description "Primary language..."
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### 2b. User Roles
|
|
75
|
+
Scan for auth logic, role enums, middleware, or permission checks. Create a
|
|
76
|
+
`user_role` node for each role discovered. Ask the user: "I found these
|
|
77
|
+
roles: [list]. Are there others? Which is the primary user?"
|
|
78
|
+
|
|
79
|
+
### 2c. Design Patterns
|
|
80
|
+
Identify architectural patterns in use (e.g. MVC, event-driven, repository
|
|
81
|
+
pattern, component composition, state management approach). Create a
|
|
82
|
+
`design_pattern` node for each.
|
|
83
|
+
|
|
84
|
+
### 2d. Decisions
|
|
85
|
+
For patterns that reflect deliberate architectural choices (e.g. "monorepo",
|
|
86
|
+
"REST over GraphQL", "server-side rendering"), create `decision` nodes.
|
|
87
|
+
Ask the user: "I see these architectural decisions. Any context on why, or
|
|
88
|
+
any you'd revisit?"
|
|
89
|
+
|
|
90
|
+
### 2e. Data Entities
|
|
91
|
+
For each model/schema/table discovered, create a `data_entity` node with
|
|
92
|
+
fields listed in the description. Wire `reads_writes` edges as you discover
|
|
93
|
+
which modules touch which entities.
|
|
94
|
+
|
|
95
|
+
### Edge Pass after Phase 2:
|
|
96
|
+
- `tech_choice` → `governed_by` → relevant `decision` nodes
|
|
97
|
+
- `design_pattern` → `governed_by` → relevant `decision` nodes
|
|
98
|
+
- `data_entity` → `reads_writes` edges to each other where foreign keys exist
|
|
99
|
+
|
|
100
|
+
Present all created nodes and edges to the user for confirmation.
|
|
101
|
+
|
|
102
|
+
## Phase 3 — Feature Discovery
|
|
103
|
+
|
|
104
|
+
**Goal:** Map the project's capabilities as features in the graph.
|
|
105
|
+
|
|
106
|
+
1. **Scan for feature boundaries** — look at:
|
|
107
|
+
- Route/page definitions (each route often = a feature)
|
|
108
|
+
- Major UI components or pages
|
|
109
|
+
- API endpoint groups
|
|
110
|
+
- Background jobs, workers, or cron tasks
|
|
111
|
+
- CLI commands (if applicable)
|
|
112
|
+
2. **Create top-level features** — one `feature` node per major capability.
|
|
113
|
+
Set status to `defined` for features that are clearly implemented.
|
|
114
|
+
3. **Decompose large features** — if a feature has sub-routes, tabs, or
|
|
115
|
+
distinct modes, create sub-features and wire `contains` edges.
|
|
116
|
+
4. **Wire edges:**
|
|
117
|
+
- `feature` → `implemented_with` → `tech_choice` or `component`
|
|
118
|
+
- `feature` → `depends_on` → other features it requires
|
|
119
|
+
- `feature` → `reads_writes` → `data_entity`
|
|
120
|
+
- `feature` → `performed_by` → `user_role`
|
|
121
|
+
- `feature` → `governed_by` → `decision` or `design_pattern`
|
|
122
|
+
|
|
123
|
+
Ask the user: "Here are the features I identified: [list]. Any missing?
|
|
124
|
+
Which are most important to you right now?"
|
|
125
|
+
|
|
126
|
+
## Phase 4 — Component Mapping
|
|
127
|
+
|
|
128
|
+
**Goal:** Map internal components and modules that implement features.
|
|
129
|
+
|
|
130
|
+
1. **Identify reusable components** — shared UI components, service classes,
|
|
131
|
+
utility modules, middleware, hooks
|
|
132
|
+
2. **Create `component` nodes** for significant reusable pieces
|
|
133
|
+
3. **Wire edges:**
|
|
134
|
+
- `component` → `implemented_with` → `tech_choice`
|
|
135
|
+
- `feature` → `implemented_with` → `component`
|
|
136
|
+
- `component` → `reads_writes` → `data_entity`
|
|
137
|
+
- `component` → `depends_on` → other components
|
|
138
|
+
|
|
139
|
+
## Phase 5 — Non-Functional Requirements & Constraints
|
|
140
|
+
|
|
141
|
+
**Goal:** Capture the quality attributes and constraints.
|
|
142
|
+
|
|
143
|
+
Ask the user about (only what's relevant):
|
|
144
|
+
- Performance targets (response times, throughput)
|
|
145
|
+
- Security requirements (auth method, data sensitivity, compliance)
|
|
146
|
+
- Scalability expectations
|
|
147
|
+
- Accessibility requirements
|
|
148
|
+
- Browser/device support
|
|
149
|
+
- Uptime/availability targets
|
|
150
|
+
|
|
151
|
+
Create `non_functional_requirement` nodes and wire `constrained_by` edges
|
|
152
|
+
from the features they apply to.
|
|
153
|
+
|
|
154
|
+
## Phase 6 — Flows & Integration Points
|
|
155
|
+
|
|
156
|
+
**Goal:** Capture key user journeys and external integrations.
|
|
157
|
+
|
|
158
|
+
1. **Identify critical flows** — onboarding, checkout, CRUD cycles, admin
|
|
159
|
+
workflows. Create `flow` nodes with step-by-step descriptions.
|
|
160
|
+
2. **Identify external integrations** — third-party APIs, webhooks, OAuth
|
|
161
|
+
providers, payment processors. Create nodes and wire appropriately.
|
|
162
|
+
3. **Wire edges:**
|
|
163
|
+
- `flow` → `contains` → features involved in the flow
|
|
164
|
+
- `flow` → `performed_by` → `user_role`
|
|
165
|
+
|
|
166
|
+
## Phase 7 — Gap Analysis & Prioritization
|
|
167
|
+
|
|
168
|
+
**Goal:** Identify what's missing and let the user prioritize.
|
|
169
|
+
|
|
170
|
+
1. Call `get_gaps` — present the full gap report
|
|
171
|
+
2. Call `get_status` — show completeness metrics
|
|
172
|
+
3. Ask the user:
|
|
173
|
+
- "Which areas should I dig deeper into?"
|
|
174
|
+
- "Are there planned features not yet in the codebase?"
|
|
175
|
+
- "Any known technical debt or areas you want to redesign?"
|
|
176
|
+
4. Create nodes for planned/future work with status `draft`
|
|
177
|
+
|
|
178
|
+
## Session End Protocol
|
|
179
|
+
1. Call `get_gaps` — report remaining gaps
|
|
180
|
+
2. Call `get_status` — show overall progress
|
|
181
|
+
3. Call `end_session` with a summary
|
|
182
|
+
4. Tell the user which phase to resume at next session
|
|
183
|
+
|
|
184
|
+
## Tool Reference
|
|
185
|
+
|
|
186
|
+
### start_session
|
|
187
|
+
```
|
|
188
|
+
npx tsx packages/shared/tools/start_session.ts
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
### end_session
|
|
192
|
+
```
|
|
193
|
+
npx tsx packages/shared/tools/end_session.ts --summary "..." --nodes-touched "feat_001,dec_001" --questions-resolved 3
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
### search_nodes
|
|
197
|
+
```
|
|
198
|
+
npx tsx packages/shared/tools/search_nodes.ts --query "keyword"
|
|
199
|
+
npx tsx packages/shared/tools/search_nodes.ts --type feature
|
|
200
|
+
npx tsx packages/shared/tools/search_nodes.ts --has-open-questions
|
|
201
|
+
npx tsx packages/shared/tools/search_nodes.ts --completeness-below 0.5
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
### get_node
|
|
205
|
+
```
|
|
206
|
+
npx tsx packages/shared/tools/get_node.ts <node_id>
|
|
207
|
+
npx tsx packages/shared/tools/get_node.ts --name "Node Name"
|
|
208
|
+
```
|
|
209
|
+
Returns full .md content plus a Relations section listing all connected nodes
|
|
210
|
+
with direction, relation type, name, type, and status.
|
|
211
|
+
|
|
212
|
+
### add_node
|
|
213
|
+
```
|
|
214
|
+
npx tsx packages/shared/tools/add_node.ts --type <type> --name "Name" --description "..."
|
|
215
|
+
```
|
|
216
|
+
Valid types: feature, component, data_entity, decision, tech_choice,
|
|
217
|
+
non_functional_requirement, design_token, design_pattern, user_role,
|
|
218
|
+
flow, assumption, open_question
|
|
219
|
+
|
|
220
|
+
### update_node
|
|
221
|
+
```
|
|
222
|
+
npx tsx packages/shared/tools/update_node.ts <id> --add-acceptance-criteria "..."
|
|
223
|
+
npx tsx packages/shared/tools/update_node.ts <id> --add-open-question "..."
|
|
224
|
+
npx tsx packages/shared/tools/update_node.ts <id> --add-note "Session N: ..."
|
|
225
|
+
npx tsx packages/shared/tools/update_node.ts <id> --set-status <draft|partially_defined|defined>
|
|
226
|
+
npx tsx packages/shared/tools/update_node.ts <id> --set-priority <low|medium|high|blocking>
|
|
227
|
+
npx tsx packages/shared/tools/update_node.ts <id> --set-description "..."
|
|
228
|
+
npx tsx packages/shared/tools/update_node.ts <id> --set-section "SectionName=content"
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
### resolve_question
|
|
232
|
+
```
|
|
233
|
+
npx tsx packages/shared/tools/resolve_question.ts <id> --question "..." --answer "..."
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
### add_edge
|
|
237
|
+
```
|
|
238
|
+
npx tsx packages/shared/tools/add_edge.ts <from_id> <relation> <to_id>
|
|
239
|
+
```
|
|
240
|
+
Valid relations: contains, depends_on, governed_by, constrained_by,
|
|
241
|
+
implemented_with, reads_writes, exposes, consumes, performed_by,
|
|
242
|
+
escalates_to, relates_to
|
|
243
|
+
|
|
244
|
+
### remove_edge
|
|
245
|
+
```
|
|
246
|
+
npx tsx packages/shared/tools/remove_edge.ts <from_id> <relation> <to_id>
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
### get_gaps
|
|
250
|
+
```
|
|
251
|
+
npx tsx packages/shared/tools/get_gaps.ts
|
|
252
|
+
npx tsx packages/shared/tools/get_gaps.ts --blocking-only
|
|
253
|
+
npx tsx packages/shared/tools/get_gaps.ts --type feature
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
### get_status
|
|
257
|
+
```
|
|
258
|
+
npx tsx packages/shared/tools/get_status.ts
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
### rebuild_index
|
|
262
|
+
```
|
|
263
|
+
npx tsx packages/shared/tools/rebuild_index.ts
|
|
264
|
+
npx tsx packages/shared/tools/rebuild_index.ts --dry-run
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
## Search Strategy
|
|
268
|
+
The `search_nodes --query` tool returns graph-aware relevance-ranked results.
|
|
269
|
+
|
|
270
|
+
1. **Start with specific keywords** — direct matches appear first with
|
|
271
|
+
`relevance: "direct"`.
|
|
272
|
+
2. **Read expansion results** — each direct match surfaces its 1-hop graph
|
|
273
|
+
neighbors. Use them to discover related nodes without manual edge walking.
|
|
274
|
+
3. **Fall back to structural overview** — on zero matches, the tool returns
|
|
275
|
+
the top-5 most-connected nodes per type (the project backbone).
|
|
276
|
+
4. **Use `--type` filters to drill in** — narrow with `--type feature`,
|
|
277
|
+
`--type decision`, etc.
|
|
278
|
+
5. **Trust strong-edge neighbors** — `depends_on`, `implemented_with`,
|
|
279
|
+
`governed_by`, `contains` are architecturally significant. `relates_to`
|
|
280
|
+
is a weak signal.
|
|
281
|
+
|
|
282
|
+
## Edge Type Semantics
|
|
283
|
+
|
|
284
|
+
- **depends_on** — prerequisite chain
|
|
285
|
+
- **implemented_with** — technical realization
|
|
286
|
+
- **governed_by** — architectural constraints
|
|
287
|
+
- **constrained_by** — non-functional limits
|
|
288
|
+
- **contains** — parent-child composition
|
|
289
|
+
- **reads_writes** — data access
|
|
290
|
+
- **exposes** — API surface
|
|
291
|
+
- **consumes** — data intake
|
|
292
|
+
- **performed_by** — actor
|
|
293
|
+
- **escalates_to** — delegation
|
|
294
|
+
- **relates_to** — loose association (weakest)
|
|
295
|
+
|
|
296
|
+
## Rules
|
|
297
|
+
1. Never read or write graph.tson or .md files directly — always use the tools
|
|
298
|
+
2. Always call get_node before update_node — never update blind
|
|
299
|
+
3. Always record answers via resolve_question — don't just add a note
|
|
300
|
+
4. Nodes should reflect reality (codebase + user statements), not inferences —
|
|
301
|
+
use `assumption` node type for inferences
|
|
302
|
+
5. If the user contradicts something in the graph, update it and add a note
|
|
303
|
+
6. All tool commands must be run from the `product-system/`
|
|
304
|
+
directory
|
|
305
|
+
7. Set status to `defined` for features clearly implemented in the codebase;
|
|
306
|
+
use `draft` for planned/future work
|
|
307
|
+
8. **Scan code before asking** — only ask the user about intent, priorities,
|
|
308
|
+
and preferences. Never ask "how does X work?" when you can read the code.
|
|
309
|
+
9. **Batch node creation** — create multiple related nodes before running
|
|
310
|
+
edge discovery, to maximize edge connections found in a single pass
|
|
311
|
+
10. **Present and confirm** — after each phase, show the user what you created
|
|
312
|
+
and get confirmation before moving on
|