@xulthekl/team-flow 0.22.4 → 0.24.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.
Files changed (72) hide show
  1. package/.claude/always/phase-guard.md +1 -1
  2. package/.claude-plugin/marketplace.json +1 -1
  3. package/.claude-plugin/plugin.json +1 -1
  4. package/.codex-plugin/plugin.json +1 -1
  5. package/.cursor-plugin/marketplace.json +1 -1
  6. package/.cursor-plugin/plugin.json +1 -1
  7. package/.github/plugin/marketplace.json +2 -2
  8. package/AGENTS.md +3 -2
  9. package/CHANGELOG.md +103 -0
  10. package/GEMINI.md +1 -1
  11. package/HANDOFF.md +123 -98
  12. package/INSTALL.md +1 -1
  13. package/README.md +1 -1
  14. package/docs/README_en.md +1 -1
  15. package/docs/solutions/INDEX.md +5 -0
  16. package/docs/solutions/cross-phase/2026-07-28-no-summary.md +17 -0
  17. package/gemini-extension.json +1 -1
  18. package/hooks/pre-tool-use-guard +9 -9
  19. package/hooks/session-start +2 -2
  20. package/llms.txt +1 -1
  21. package/package.json +1 -1
  22. package/plugin.json +1 -1
  23. package/scripts/guard/checks/arch-design.mjs +79 -0
  24. package/scripts/guard/checks/compound-captured.mjs +70 -0
  25. package/scripts/guard/guard.mjs +6 -2
  26. package/scripts/lib/arch-merge.mjs +459 -0
  27. package/scripts/lib/cmd-state.mjs +5 -0
  28. package/scripts/lib/hash.mjs +18 -0
  29. package/scripts/lib/solutions-promote.mjs +1 -1
  30. package/scripts/lib/state-loader.mjs +16 -0
  31. package/scripts/team-flow.mjs +3 -0
  32. package/skills/architecture-design/SKILL.md +42 -3
  33. package/skills/architecture-design/templates/api.md +71 -0
  34. package/skills/architecture-design/templates/architecture.md +82 -0
  35. package/skills/architecture-design/templates/change-brief.md +29 -0
  36. package/skills/architecture-design/templates/database.md +69 -0
  37. package/skills/architecture-design/templates/index.md +33 -0
  38. package/skills/architecture-design/templates/physical-model.md +93 -0
  39. package/skills/bug-investigator/SKILL.md +1 -1
  40. package/skills/build-executor/SKILL.md +23 -19
  41. package/skills/build-executor/implementer-prompt.md +1 -1
  42. package/skills/build-executor/references/execution-modes.md +6 -6
  43. package/skills/build-executor/task-reviewer-prompt.md +1 -1
  44. package/skills/ce-brainstorm/SKILL.md +6 -0
  45. package/skills/code-reviewer/SKILL.md +6 -2
  46. package/skills/code-reviewer/code-reviewer-prompt.md +1 -1
  47. package/skills/contract-builder/SKILL.md +6 -6
  48. package/skills/need-explorer/SKILL.md +2 -2
  49. package/skills/release-archivist/SKILL.md +25 -12
  50. package/skills/release-archivist/references/closing-procedures.md +8 -8
  51. package/skills/spec-merger/SKILL.md +2 -2
  52. package/skills/spec-writer/SKILL.md +11 -9
  53. package/skills/workflow-bootstrap/SKILL.md +39 -5
  54. package/skills/workflow-bootstrap/references/b1-reconnaissance.md +22 -1
  55. package/skills/workflow-bootstrap/scripts/recon-probe.sh +122 -1
  56. package/skills/workflow-orchestrator/references/s2-prd-prototype-loop.md +1 -1
  57. package/skills/workflow-orchestrator/references/s4-split-validate.md +1 -1
  58. package/skills/workflow-orchestrator/references/s5-monitoring.md +1 -1
  59. package/skills/workflow-start/SKILL.md +44 -16
  60. package/skills/workflow-start/references/routing-rules.md +17 -17
  61. package/templates/api.md +177 -0
  62. package/templates/architecture.md +122 -0
  63. package/templates/change-brief.md +24 -0
  64. package/templates/database.md +114 -0
  65. package/tests/lib/guard-compound-captured.test.mjs +92 -0
  66. package/tests/lib/guard-specs-merged.test.mjs +2 -0
  67. package/tests/lib/guard-tests-passing.test.mjs +2 -0
  68. package/tests/lib/guard.test.mjs +2 -0
  69. package/tests/lib/solutions-capture.test.mjs +108 -0
  70. package/tests/lib/solutions-index-gen.test.mjs +147 -0
  71. package/tests/lib/solutions-inject.test.mjs +115 -0
  72. package/tests/lib/solutions-promote.test.mjs +200 -0
@@ -0,0 +1,200 @@
1
+ // tests/lib/solutions-promote.test.mjs
2
+ // Tests for scripts/lib/solutions-promote.mjs — change→product promotion
3
+
4
+ import { describe, it, before, after, beforeEach } from 'node:test';
5
+ import assert from 'node:assert/strict';
6
+ import { mkdtempSync, writeFileSync, existsSync, rmSync, mkdirSync, readFileSync } from 'node:fs';
7
+ import { join } from 'node:path';
8
+ import { tmpdir } from 'node:os';
9
+ import { fileURLToPath } from 'node:url';
10
+ import { dirname } from 'node:path';
11
+
12
+ const __dirname = dirname(fileURLToPath(import.meta.url));
13
+ const ROOT = join(__dirname, '..', '..');
14
+
15
+ // NODE_ENV=test is set below before import — promote's CLI guard skips when test.
16
+ process.env.NODE_ENV = 'test';
17
+ const { run: promoteRun } = await import(join(ROOT, 'scripts', 'lib', 'solutions-promote.mjs'));
18
+
19
+ function makeDir(prefix = '') {
20
+ return mkdtempSync(join(tmpdir(), `tf-sol-promote-${prefix}-`));
21
+ }
22
+
23
+ function cleanup(dir) {
24
+ if (existsSync(dir)) rmSync(dir, { recursive: true, force: true });
25
+ }
26
+
27
+ function writeLearnings(dir, content) {
28
+ writeFileSync(join(dir, 'learnings.md'), content, 'utf-8');
29
+ }
30
+
31
+ const INDEX_HEADER = `# Solutions Index
32
+ | date | phase | domain | type | severity | summary | file |
33
+ |------|-------|--------|------|----------|---------|------|
34
+ `;
35
+
36
+ function writeGlobalIndex(solDir, rows = []) {
37
+ mkdirSync(solDir, { recursive: true });
38
+ writeFileSync(join(solDir, 'INDEX.md'), INDEX_HEADER + rows.join('\n') + '\n', 'utf-8');
39
+ }
40
+
41
+ describe('solutions-promote', () => {
42
+ let changeDir, solDir;
43
+
44
+ beforeEach(() => {
45
+ changeDir = makeDir('change');
46
+ solDir = makeDir('solutions');
47
+ });
48
+
49
+ after(() => {
50
+ cleanup(changeDir);
51
+ cleanup(solDir);
52
+ });
53
+
54
+ it('returns zero when no learnings.md exists', () => {
55
+ const result = promoteRun({ changeDir, dir: solDir });
56
+ assert.equal(result.promoted, 0);
57
+ assert.equal(result.updated, 0);
58
+ });
59
+
60
+ it('promotes entry with severity=high and type=pitfall', () => {
61
+ writeLearnings(changeDir, `## Auth token refresh failure
62
+ ---
63
+ phase: build
64
+ domain: auth
65
+ type: pitfall
66
+ severity: high
67
+ date: 2026-07-15
68
+ ---
69
+
70
+ When OAuth token refresh fails, the system silently swallows the error.
71
+ `);
72
+ const result = promoteRun({ changeDir, dir: solDir });
73
+ assert.equal(result.promoted, 1);
74
+ assert.ok(existsSync(join(solDir, 'build')), 'build phase dir should exist');
75
+ });
76
+
77
+ it('promotes entry with severity=medium and type=pattern', () => {
78
+ writeLearnings(changeDir, `## Retry with backoff pattern
79
+ ---
80
+ phase: build
81
+ domain: networking
82
+ type: pattern
83
+ severity: medium
84
+ date: 2026-07-15
85
+ ---
86
+
87
+ Use exponential backoff for API retry logic.
88
+ `);
89
+ const result = promoteRun({ changeDir, dir: solDir });
90
+ assert.equal(result.promoted, 1);
91
+ });
92
+
93
+ it('skips entry with severity=low', () => {
94
+ writeLearnings(changeDir, `## Minor formatting issue
95
+ ---
96
+ phase: build
97
+ domain: style
98
+ type: pitfall
99
+ severity: low
100
+ date: 2026-07-15
101
+ ---
102
+
103
+ Some low severity issue.
104
+ `);
105
+ const result = promoteRun({ changeDir, dir: solDir });
106
+ assert.equal(result.promoted, 0);
107
+ });
108
+
109
+ it('skips entry with type=insight (not pitfall/pattern)', () => {
110
+ writeLearnings(changeDir, `## Interesting observation
111
+ ---
112
+ phase: build
113
+ domain: auth
114
+ type: insight
115
+ severity: high
116
+ date: 2026-07-15
117
+ ---
118
+
119
+ An insight that should not be promoted.
120
+ `);
121
+ const result = promoteRun({ changeDir, dir: solDir });
122
+ assert.equal(result.promoted, 0);
123
+ });
124
+
125
+ it('detects duplicate domain+type and marks as confirmed', () => {
126
+ writeGlobalIndex(solDir, [
127
+ '| 2026-07-01 | build | auth | pitfall | medium | Existing auth pitfall | build/existing.md |',
128
+ ]);
129
+ writeLearnings(changeDir, `## Another auth pitfall
130
+ ---
131
+ phase: build
132
+ domain: auth
133
+ type: pitfall
134
+ severity: high
135
+ date: 2026-07-15
136
+ ---
137
+
138
+ Duplicate domain+type with existing index entry.
139
+ `);
140
+ const result = promoteRun({ changeDir, dir: solDir });
141
+ assert.equal(result.updated, 1, 'should detect duplicate and mark as confirmed');
142
+ assert.equal(result.promoted, 0, 'should not create new file for duplicate');
143
+ });
144
+
145
+ it('promotes multiple entries from single learnings.md', () => {
146
+ writeLearnings(changeDir, `## Issue one
147
+ ---
148
+ phase: spec
149
+ domain: api
150
+ type: pitfall
151
+ severity: high
152
+ date: 2026-07-15
153
+ ---
154
+
155
+ First pitfall.
156
+
157
+ ## Issue two
158
+ ---
159
+ phase: spec
160
+ domain: db
161
+ type: pattern
162
+ severity: medium
163
+ date: 2026-07-15
164
+ ---
165
+
166
+ Second pattern.
167
+
168
+ ## Issue three (low sev, skipped)
169
+ ---
170
+ phase: spec
171
+ domain: style
172
+ type: pitfall
173
+ severity: low
174
+ date: 2026-07-15
175
+ ---
176
+
177
+ Skipped due to low severity.
178
+ `);
179
+ const result = promoteRun({ changeDir, dir: solDir });
180
+ assert.equal(result.promoted, 2, 'should promote 2 entries (high+medium, skip low)');
181
+ });
182
+
183
+ it('appends promoted entry to global INDEX.md', () => {
184
+ writeGlobalIndex(solDir);
185
+ writeLearnings(changeDir, `## DB migration ordering
186
+ ---
187
+ phase: build
188
+ domain: db
189
+ type: pitfall
190
+ severity: high
191
+ date: 2026-07-15
192
+ ---
193
+
194
+ Migration files must be ordered by timestamp.
195
+ `);
196
+ promoteRun({ changeDir, dir: solDir });
197
+ const indexContent = readFileSync(join(solDir, 'INDEX.md'), 'utf-8');
198
+ assert.match(indexContent, /DB migration ordering/);
199
+ });
200
+ });