murmur8 4.1.1 → 4.3.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/.blueprint/agents/AGENT_SPECIFICATION_ALEX.md +33 -3
- package/.blueprint/features/feature_config-factory/FEATURE_SPEC.md +138 -0
- package/.blueprint/features/feature_config-factory/IMPLEMENTATION_PLAN.md +187 -0
- package/.blueprint/features/feature_config-factory/handoff-nigel.md +57 -0
- package/.blueprint/features/feature_export-history/FEATURE_SPEC.md +215 -0
- package/.blueprint/features/feature_export-history/IMPLEMENTATION_PLAN.md +48 -0
- package/.blueprint/features/feature_export-history/story-basic-export.md +48 -0
- package/.blueprint/features/feature_export-history/story-date-filter.md +42 -0
- package/.blueprint/features/feature_export-history/story-feature-filter.md +42 -0
- package/.blueprint/features/feature_export-history/story-file-output.md +48 -0
- package/.blueprint/features/feature_export-history/story-status-filter.md +42 -0
- package/.blueprint/features/feature_extract-prompt-util/FEATURE_SPEC.md +42 -0
- package/.blueprint/features/feature_fix-status-icons/FEATURE_SPEC.md +37 -0
- package/.blueprint/features/feature_murm-subagent/FEATURE_SPEC.md +137 -0
- package/.blueprint/features/feature_murm-subagent/SKILL_CHANGES.md +345 -0
- package/.blueprint/features/feature_split-cli-commands/FEATURE_SPEC.md +125 -0
- package/.blueprint/features/feature_split-cli-commands/IMPLEMENTATION_PLAN.md +119 -0
- package/.blueprint/features/feature_split-cli-commands/handoff-nigel.md +45 -0
- package/.blueprint/features/feature_theme-adoption/FEATURE_SPEC.md +143 -0
- package/.blueprint/features/feature_theme-adoption/IMPLEMENTATION_PLAN.md +68 -0
- package/.blueprint/features/feature_theme-adoption/handoff-nigel.md +35 -0
- package/.blueprint/templates/BACKLOG_TEMPLATE.md +46 -0
- package/README.md +26 -10
- package/SKILL.md +377 -3
- package/bin/cli.js +20 -384
- package/package.json +1 -1
- package/src/commands/feedback-config.js +32 -0
- package/src/commands/help.js +81 -0
- package/src/commands/history.js +42 -0
- package/src/commands/init.js +12 -0
- package/src/commands/insights.js +23 -0
- package/src/commands/murm-config.js +52 -0
- package/src/commands/murm.js +109 -0
- package/src/commands/queue.js +19 -0
- package/src/commands/retry-config.js +28 -0
- package/src/commands/stack-config.js +32 -0
- package/src/commands/update.js +12 -0
- package/src/commands/utils.js +24 -0
- package/src/commands/validate.js +15 -0
- package/src/config-factory.js +190 -0
- package/src/feedback.js +5 -2
- package/src/history.js +92 -1
- package/src/init.js +1 -15
- package/src/insights.js +19 -16
- package/src/retry.js +5 -2
- package/src/stack.js +4 -1
- package/src/theme.js +4 -4
- package/src/update.js +2 -15
- package/src/utils.js +26 -0
- package/src/validate.js +5 -12
|
@@ -8,6 +8,7 @@ inputs:
|
|
|
8
8
|
outputs:
|
|
9
9
|
- feature_spec
|
|
10
10
|
- system_spec
|
|
11
|
+
- feature_backlog
|
|
11
12
|
---
|
|
12
13
|
|
|
13
14
|
# Agent: Alex — System Specification & Chief-of-Staff
|
|
@@ -74,7 +75,36 @@ Once drafted, the feature specification is handed to **Cass** for user story ela
|
|
|
74
75
|
|
|
75
76
|
---
|
|
76
77
|
|
|
77
|
-
### 3.
|
|
78
|
+
### 3. Feature Backlog Ownership
|
|
79
|
+
|
|
80
|
+
Alex owns the **Feature Backlog** at `.blueprint/features/BACKLOG.md` — a prioritised list of features ready for implementation.
|
|
81
|
+
|
|
82
|
+
**Template:** `.blueprint/templates/BACKLOG_TEMPLATE.md`
|
|
83
|
+
|
|
84
|
+
**Format (token-efficient table):**
|
|
85
|
+
```markdown
|
|
86
|
+
| Status | P | E | Slug | Description |
|
|
87
|
+
|--------|---|---|------|-------------|
|
|
88
|
+
| ⏳ | P1 | M | user-auth | Login and registration flow |
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
**When to create/update:**
|
|
92
|
+
- After creating a system spec — propose initial feature breakdown
|
|
93
|
+
- After completing a feature — pipeline removes entry automatically
|
|
94
|
+
- When scope changes — reprioritise and update descriptions
|
|
95
|
+
|
|
96
|
+
**Prioritisation criteria:**
|
|
97
|
+
- Business value and user impact
|
|
98
|
+
- Dependencies (what must come first?)
|
|
99
|
+
- Technical risk (surface unknowns early)
|
|
100
|
+
|
|
101
|
+
**Status icons:** ⏳ ready, 🚧 in progress, ❓ needs clarification
|
|
102
|
+
|
|
103
|
+
Alex keeps the backlog aligned with the system specification. If a proposed feature contradicts the system design, Alex flags it rather than adding it silently.
|
|
104
|
+
|
|
105
|
+
---
|
|
106
|
+
|
|
107
|
+
### 4. Living Collaboration with Cass (BA)
|
|
78
108
|
Alex and Cass operate in a **continuous, collaborative loop**:
|
|
79
109
|
- Cass may query, challenge, or request refinement of a specification before writing stories
|
|
80
110
|
- Alex clarifies intent, resolves ambiguities, or adjusts the specification where appropriate
|
|
@@ -89,7 +119,7 @@ Alex does **not** silently accept spec drift.
|
|
|
89
119
|
|
|
90
120
|
---
|
|
91
121
|
|
|
92
|
-
###
|
|
122
|
+
### 5. Conceptual Coherence Guardian (Hover Mode)
|
|
93
123
|
After initial specification and story creation, Alex remains active as a **conceptual coherence guardian**.
|
|
94
124
|
|
|
95
125
|
Alex reacts to:
|
|
@@ -109,7 +139,7 @@ When meaningful change is detected, Alex:
|
|
|
109
139
|
|
|
110
140
|
---
|
|
111
141
|
|
|
112
|
-
###
|
|
142
|
+
### 6. Managing Evolution & Breaking Change Proposals
|
|
113
143
|
When a feature exposes a flaw or limitation in the system specification:
|
|
114
144
|
- Alex may propose a **breaking or structural change** to the system spec
|
|
115
145
|
- Alex must clearly articulate:
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
# Feature Specification — Config Factory
|
|
2
|
+
|
|
3
|
+
## 1. Feature Intent
|
|
4
|
+
**Why this feature exists.**
|
|
5
|
+
|
|
6
|
+
- Four config modules (retry, feedback, murm, stack) share identical patterns
|
|
7
|
+
- Each implements: `getDefaultConfig()`, `readConfig()`, `writeConfig()`, `displayConfig()`, `setConfigValue()`, `resetConfig()`
|
|
8
|
+
- ~80 lines of boilerplate duplicated 4 times (~320 lines total)
|
|
9
|
+
- Inconsistent validation and error handling across modules
|
|
10
|
+
- Adding a new config module requires copying boilerplate
|
|
11
|
+
|
|
12
|
+
> Technical refactoring feature — consolidate to a factory pattern.
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## 2. Scope
|
|
17
|
+
### In Scope
|
|
18
|
+
- Create `src/config-factory.js` with `createConfigModule(options)` factory
|
|
19
|
+
- Refactor retry.js, feedback.js, stack.js to use the factory
|
|
20
|
+
- Refactor murm.js config functions to use the factory
|
|
21
|
+
- Standardize validation, error messages, and display formatting
|
|
22
|
+
- Preserve all existing config behaviour exactly
|
|
23
|
+
|
|
24
|
+
### Out of Scope
|
|
25
|
+
- Adding new config modules
|
|
26
|
+
- Changing config file locations or formats
|
|
27
|
+
- Modifying default values
|
|
28
|
+
- Adding new config keys
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## 3. Actors Involved
|
|
33
|
+
**Who interacts with this feature.**
|
|
34
|
+
|
|
35
|
+
- **Developer**: Creates new config modules with minimal boilerplate
|
|
36
|
+
- **CLI User**: No change in experience — all config commands work identically
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## 4. Behaviour Overview
|
|
41
|
+
**What the feature does, conceptually.**
|
|
42
|
+
|
|
43
|
+
The factory creates a config module with standard methods:
|
|
44
|
+
|
|
45
|
+
```javascript
|
|
46
|
+
const myConfig = createConfigModule({
|
|
47
|
+
name: 'my-config',
|
|
48
|
+
file: '.claude/my-config.json',
|
|
49
|
+
defaults: { key1: 'value1', key2: 42 },
|
|
50
|
+
validators: {
|
|
51
|
+
key1: (v) => typeof v === 'string',
|
|
52
|
+
key2: (v) => Number.isInteger(v) && v > 0
|
|
53
|
+
},
|
|
54
|
+
formatters: {
|
|
55
|
+
key2: (v) => `${v} items`
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
// Returns: { read, write, reset, display, setValue, getDefault, CONFIG_FILE }
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Each existing config module becomes a thin wrapper calling the factory.
|
|
63
|
+
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
## 5. State & Lifecycle Interactions
|
|
67
|
+
**How this feature touches the system lifecycle.**
|
|
68
|
+
|
|
69
|
+
- No state changes — pure refactoring
|
|
70
|
+
- Config files remain in same locations
|
|
71
|
+
- No runtime behaviour differences
|
|
72
|
+
|
|
73
|
+
---
|
|
74
|
+
|
|
75
|
+
## 6. Rules & Decision Logic
|
|
76
|
+
**New or exercised rules.**
|
|
77
|
+
|
|
78
|
+
| Rule | Description |
|
|
79
|
+
|------|-------------|
|
|
80
|
+
| Default merging | Factory merges missing keys from defaults on read |
|
|
81
|
+
| Validation | Factory validates values before write using validators map |
|
|
82
|
+
| Display format | Factory uses formatters map or falls back to default display |
|
|
83
|
+
| Error messages | Standardized format: `Invalid value for {key}: {value}. {reason}` |
|
|
84
|
+
| Array handling | Arrays validated and displayed consistently (JSON parse for set) |
|
|
85
|
+
|
|
86
|
+
---
|
|
87
|
+
|
|
88
|
+
## 7. Dependencies
|
|
89
|
+
**What this feature relies on.**
|
|
90
|
+
|
|
91
|
+
- Node.js `fs` module (already used)
|
|
92
|
+
- No new external dependencies
|
|
93
|
+
|
|
94
|
+
---
|
|
95
|
+
|
|
96
|
+
## 8. Non-Functional Considerations
|
|
97
|
+
|
|
98
|
+
- **Code reduction**: ~200+ lines removed across 4 modules
|
|
99
|
+
- **Consistency**: Identical error messages and validation across all configs
|
|
100
|
+
- **Extensibility**: New config modules require ~10 lines instead of ~80
|
|
101
|
+
|
|
102
|
+
---
|
|
103
|
+
|
|
104
|
+
## 9. Assumptions & Open Questions
|
|
105
|
+
|
|
106
|
+
**Assumptions:**
|
|
107
|
+
- All four config modules can use the same factory pattern
|
|
108
|
+
- Specialized validation (like feedback's issueMappings) can be handled via validators
|
|
109
|
+
|
|
110
|
+
**Open Questions:**
|
|
111
|
+
- Should murm.js config functions be split to a separate file or remain inline?
|
|
112
|
+
- Should the factory support nested config objects (like retry's `strategies`)?
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
## 10. Impact on System Specification
|
|
117
|
+
|
|
118
|
+
- No impact — internal refactoring only
|
|
119
|
+
- Public APIs of all config modules remain unchanged
|
|
120
|
+
|
|
121
|
+
---
|
|
122
|
+
|
|
123
|
+
## 11. Handover to BA (Cass)
|
|
124
|
+
|
|
125
|
+
**Skip Cass stage** — this is a technical refactoring feature with no user stories needed.
|
|
126
|
+
|
|
127
|
+
Direct handover to Nigel for test creation:
|
|
128
|
+
- Tests should verify all config commands work after refactoring
|
|
129
|
+
- Tests should verify validation errors are consistent
|
|
130
|
+
- Tests should verify display output format is preserved
|
|
131
|
+
- Tests should verify default values are unchanged
|
|
132
|
+
|
|
133
|
+
---
|
|
134
|
+
|
|
135
|
+
## 12. Change Log (Feature-Level)
|
|
136
|
+
| Date | Change | Reason | Raised By |
|
|
137
|
+
|------|--------|--------|-----------|
|
|
138
|
+
| 2026-03-03 | Initial spec | DRY up config modules | Alex |
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
# Implementation Plan: Config Factory
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
Create a factory function to eliminate ~320 lines of duplicated boilerplate across four config modules (retry.js, feedback.js, stack.js, murm.js).
|
|
5
|
+
|
|
6
|
+
## Step 1: Create `src/config-factory.js`
|
|
7
|
+
|
|
8
|
+
Create the factory module with the following structure:
|
|
9
|
+
|
|
10
|
+
```js
|
|
11
|
+
function createConfigModule(options) {
|
|
12
|
+
const { name, file, defaults, validators = {}, formatters = {}, arrayKeys = [] } = options;
|
|
13
|
+
|
|
14
|
+
return {
|
|
15
|
+
CONFIG_FILE: file,
|
|
16
|
+
getDefault: () => ({ ...defaults }),
|
|
17
|
+
read: () => { /* merge defaults, handle errors */ },
|
|
18
|
+
write: (config) => { /* ensure dir, write JSON */ },
|
|
19
|
+
reset: () => { /* write defaults */ },
|
|
20
|
+
setValue: (key, value) => { /* validate, write */ },
|
|
21
|
+
display: () => { /* format and log */ }
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
### Factory Methods Detail
|
|
27
|
+
|
|
28
|
+
| Method | Behavior |
|
|
29
|
+
|--------|----------|
|
|
30
|
+
| `getDefault()` | Return shallow copy of defaults |
|
|
31
|
+
| `read()` | Return defaults if missing/corrupted, merge missing keys |
|
|
32
|
+
| `write(config)` | Create dir if needed, write JSON with 2-space indent |
|
|
33
|
+
| `reset()` | Call write(getDefault()) |
|
|
34
|
+
| `setValue(key, value)` | Validate key exists, parse arrays, run validator, write |
|
|
35
|
+
| `display()` | Log name header, iterate keys with formatters |
|
|
36
|
+
|
|
37
|
+
### Validation Logic
|
|
38
|
+
```js
|
|
39
|
+
setValue(key, value) {
|
|
40
|
+
if (!(key in defaults)) throw Error(`Unknown config key: ${key}. Valid keys: ...`);
|
|
41
|
+
|
|
42
|
+
let parsed = value;
|
|
43
|
+
if (arrayKeys.includes(key)) {
|
|
44
|
+
parsed = JSON.parse(value); // throws on invalid
|
|
45
|
+
if (!Array.isArray(parsed)) throw Error(`${key} must be a JSON array`);
|
|
46
|
+
} else if (typeof defaults[key] === 'number') {
|
|
47
|
+
parsed = parseFloat(value);
|
|
48
|
+
} else if (typeof defaults[key] === 'boolean') {
|
|
49
|
+
parsed = value === 'true';
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
if (validators[key]) {
|
|
53
|
+
const result = validators[key](parsed);
|
|
54
|
+
if (result !== true) {
|
|
55
|
+
throw Error(`Invalid value for ${key}: ${value}. ${result}`);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const config = read();
|
|
60
|
+
config[key] = parsed;
|
|
61
|
+
write(config);
|
|
62
|
+
}
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## Step 2: Refactor retry.js
|
|
66
|
+
|
|
67
|
+
Keep existing business logic functions (calculateFailureRate, recommendStrategy, etc.).
|
|
68
|
+
Replace config boilerplate with factory:
|
|
69
|
+
|
|
70
|
+
```js
|
|
71
|
+
const { createConfigModule } = require('./config-factory');
|
|
72
|
+
|
|
73
|
+
const configModule = createConfigModule({
|
|
74
|
+
name: 'Retry',
|
|
75
|
+
file: '.claude/retry-config.json',
|
|
76
|
+
defaults: {
|
|
77
|
+
maxRetries: 3,
|
|
78
|
+
windowSize: 10,
|
|
79
|
+
highFailureThreshold: 0.2,
|
|
80
|
+
strategies: { /* ... */ }
|
|
81
|
+
},
|
|
82
|
+
validators: {
|
|
83
|
+
maxRetries: (v) => Number.isInteger(v) && v >= 0 ? true : 'must be a non-negative integer',
|
|
84
|
+
windowSize: (v) => Number.isInteger(v) && v >= 1 ? true : 'must be a positive integer',
|
|
85
|
+
highFailureThreshold: (v) => v >= 0 && v <= 1 ? true : 'must be between 0 and 1'
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
// Re-export with same names for backward compatibility
|
|
90
|
+
const {
|
|
91
|
+
CONFIG_FILE,
|
|
92
|
+
getDefault: getDefaultConfig,
|
|
93
|
+
read: readConfig,
|
|
94
|
+
write: writeConfig,
|
|
95
|
+
reset: resetConfig,
|
|
96
|
+
display: displayConfig,
|
|
97
|
+
setValue: setConfigValue
|
|
98
|
+
} = configModule;
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## Step 3: Refactor feedback.js
|
|
102
|
+
|
|
103
|
+
Similar pattern. Keep validateFeedback, shouldPause, parseFeedbackFromOutput, normalizeFeedbackKeys.
|
|
104
|
+
|
|
105
|
+
```js
|
|
106
|
+
const configModule = createConfigModule({
|
|
107
|
+
name: 'Feedback',
|
|
108
|
+
file: '.claude/feedback-config.json',
|
|
109
|
+
defaults: {
|
|
110
|
+
minRatingThreshold: 3.0,
|
|
111
|
+
enabled: true,
|
|
112
|
+
issueMappings: { /* ... */ }
|
|
113
|
+
},
|
|
114
|
+
validators: {
|
|
115
|
+
minRatingThreshold: (v) => v >= 1.0 && v <= 5.0 ? true : 'must be between 1.0 and 5.0',
|
|
116
|
+
enabled: (v) => typeof v === 'boolean' ? true : 'must be true or false'
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
## Step 4: Refactor stack.js
|
|
122
|
+
|
|
123
|
+
Keep detectStackConfig. Note: stack uses `*StackConfig` naming convention.
|
|
124
|
+
|
|
125
|
+
```js
|
|
126
|
+
const configModule = createConfigModule({
|
|
127
|
+
name: 'Stack',
|
|
128
|
+
file: '.claude/stack-config.json',
|
|
129
|
+
defaults: {
|
|
130
|
+
language: '', runtime: '', packageManager: '',
|
|
131
|
+
frameworks: [], testRunner: '', testCommand: '',
|
|
132
|
+
linter: '', tools: []
|
|
133
|
+
},
|
|
134
|
+
arrayKeys: ['frameworks', 'tools']
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
// Alias exports with Stack suffix for backward compatibility
|
|
138
|
+
const getDefaultStackConfig = configModule.getDefault;
|
|
139
|
+
const readStackConfig = configModule.read;
|
|
140
|
+
// etc.
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
## Step 5: Refactor murm.js Config Functions
|
|
144
|
+
|
|
145
|
+
Murm.js has additional complexity (migrations, special merge logic). Keep using factory for core operations but preserve migration logic.
|
|
146
|
+
|
|
147
|
+
```js
|
|
148
|
+
const configModule = createConfigModule({
|
|
149
|
+
name: 'Murmuration',
|
|
150
|
+
file: '.claude/murm-config.json',
|
|
151
|
+
defaults: {
|
|
152
|
+
maxConcurrency: 3, maxFeatures: 10, timeout: 30,
|
|
153
|
+
minDiskSpaceMB: 500, cli: 'npx claude',
|
|
154
|
+
skill: '/implement-feature', skillFlags: '--no-commit',
|
|
155
|
+
worktreeDir: '.claude/worktrees', queueFile: '.claude/murm-queue.json'
|
|
156
|
+
},
|
|
157
|
+
validators: {
|
|
158
|
+
maxConcurrency: (v) => Number.isInteger(v) && v >= 1 ? true : 'must be a positive integer',
|
|
159
|
+
timeout: (v) => Number.isInteger(v) && v >= 1 ? true : 'must be a positive integer'
|
|
160
|
+
},
|
|
161
|
+
formatters: {
|
|
162
|
+
timeout: (v) => `${v} min`
|
|
163
|
+
}
|
|
164
|
+
});
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
Note: readMurmConfig needs to preserve migration logic for legacy files.
|
|
168
|
+
|
|
169
|
+
## Step 6: Run Tests
|
|
170
|
+
|
|
171
|
+
```bash
|
|
172
|
+
node --test test/feature_config-factory.test.js
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
Fix any failures, iterate until all 19 tests pass.
|
|
176
|
+
|
|
177
|
+
## Files Modified
|
|
178
|
+
- `src/config-factory.js` (new)
|
|
179
|
+
- `src/retry.js` (refactored)
|
|
180
|
+
- `src/feedback.js` (refactored)
|
|
181
|
+
- `src/stack.js` (refactored)
|
|
182
|
+
- `src/murm.js` (refactored config functions)
|
|
183
|
+
|
|
184
|
+
## Risk Mitigation
|
|
185
|
+
- All existing exports preserved with same names
|
|
186
|
+
- Business logic functions untouched
|
|
187
|
+
- Tests verify backward compatibility
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# Nigel Handoff: Config Factory
|
|
2
|
+
|
|
3
|
+
## Summary
|
|
4
|
+
Created test suite for the config-factory feature with 19 test cases covering:
|
|
5
|
+
- Factory core functions (7 tests)
|
|
6
|
+
- Validation (5 tests)
|
|
7
|
+
- Display formatting (3 tests)
|
|
8
|
+
- Backward compatibility (4 tests)
|
|
9
|
+
- Error message consistency (2 tests)
|
|
10
|
+
|
|
11
|
+
## Test Files Created
|
|
12
|
+
- `test/artifacts/feature_config-factory/test-spec.md` - Test mapping document
|
|
13
|
+
- `test/feature_config-factory.test.js` - Executable test file
|
|
14
|
+
|
|
15
|
+
## Key Test Coverage
|
|
16
|
+
|
|
17
|
+
### Factory API
|
|
18
|
+
- Factory returns: read, write, reset, display, setValue, getDefault, CONFIG_FILE
|
|
19
|
+
- getDefault returns provided defaults unchanged
|
|
20
|
+
- read handles missing/corrupted files gracefully
|
|
21
|
+
- read merges missing keys from defaults
|
|
22
|
+
- write/reset operations
|
|
23
|
+
|
|
24
|
+
### Validation System
|
|
25
|
+
- Validators map prevents invalid values
|
|
26
|
+
- Array keys parsed from JSON strings
|
|
27
|
+
- Unknown keys rejected with helpful error
|
|
28
|
+
|
|
29
|
+
### Backward Compatibility
|
|
30
|
+
- retry.js exports unchanged
|
|
31
|
+
- feedback.js exports unchanged
|
|
32
|
+
- stack.js (with Stack prefix) exports unchanged
|
|
33
|
+
- murm.js config functions unchanged
|
|
34
|
+
|
|
35
|
+
## Implementation Notes for Codey
|
|
36
|
+
|
|
37
|
+
1. **Create `src/config-factory.js`** with `createConfigModule(options)` factory
|
|
38
|
+
2. **Options object shape**:
|
|
39
|
+
```js
|
|
40
|
+
{
|
|
41
|
+
name: string, // Config name for display
|
|
42
|
+
file: string, // Path like '.claude/foo.json'
|
|
43
|
+
defaults: object, // Default config values
|
|
44
|
+
validators?: object, // Key -> validator function
|
|
45
|
+
formatters?: object, // Key -> display formatter
|
|
46
|
+
arrayKeys?: string[] // Keys that accept JSON array values
|
|
47
|
+
}
|
|
48
|
+
```
|
|
49
|
+
3. **Validator functions** return `true` for valid, or error string for invalid
|
|
50
|
+
4. **Error format**: `Invalid value for {key}: {value}. {reason}`
|
|
51
|
+
5. **Refactor existing modules** to use factory while preserving all exports
|
|
52
|
+
|
|
53
|
+
## Running Tests
|
|
54
|
+
```bash
|
|
55
|
+
cd .claude/worktrees/feat-config-factory
|
|
56
|
+
node --test test/feature_config-factory.test.js
|
|
57
|
+
```
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
# Feature Specification — Export Pipeline History
|
|
2
|
+
|
|
3
|
+
## 1. Feature Intent
|
|
4
|
+
|
|
5
|
+
**Why this feature exists.**
|
|
6
|
+
|
|
7
|
+
Users need to extract pipeline history data for analysis, reporting, and integration with external tools. The existing `history` and `insights` commands provide on-demand viewing, but teams often require:
|
|
8
|
+
|
|
9
|
+
- **Spreadsheet analysis** — CSV export for pivot tables, charts, and ad-hoc queries
|
|
10
|
+
- **Custom dashboards** — JSON export for ingestion into monitoring tools or team portals
|
|
11
|
+
- **Filtered exports** — Ability to slice data by date range, status, or specific features
|
|
12
|
+
|
|
13
|
+
This feature supports the system purpose of **observability** (System Spec Section 8) by making pipeline execution data portable and actionable beyond the CLI.
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## 2. Scope
|
|
18
|
+
|
|
19
|
+
### In Scope
|
|
20
|
+
|
|
21
|
+
- New `export` subcommand under `murmur8 history`
|
|
22
|
+
- Export formats: CSV and JSON
|
|
23
|
+
- Filtering options: `--since`, `--until`, `--status`, `--feature`
|
|
24
|
+
- Output to stdout (default) or file via `--output`
|
|
25
|
+
|
|
26
|
+
### Out of Scope
|
|
27
|
+
|
|
28
|
+
- Export of queue state (`.claude/implement-queue.json`) — separate concern
|
|
29
|
+
- Scheduled/automated exports — users can integrate via shell scripts
|
|
30
|
+
- Direct integration with external services (Slack, email, dashboards)
|
|
31
|
+
- Aggregated statistics export — `--stats` output remains display-only
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## 3. Actors Involved
|
|
36
|
+
|
|
37
|
+
### Human User
|
|
38
|
+
|
|
39
|
+
- **Can:** Export history data in CSV or JSON format, apply filters, redirect to file
|
|
40
|
+
- **Cannot:** Export queue state or insights aggregations through this command
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
## 4. Behaviour Overview
|
|
45
|
+
|
|
46
|
+
**Happy Path:**
|
|
47
|
+
|
|
48
|
+
1. User runs `murmur8 history export --format=csv`
|
|
49
|
+
2. System reads `.claude/pipeline-history.json`
|
|
50
|
+
3. System converts entries to CSV format
|
|
51
|
+
4. System outputs to stdout
|
|
52
|
+
|
|
53
|
+
**With Filters:**
|
|
54
|
+
|
|
55
|
+
1. User runs `murmur8 history export --format=json --since=2024-01-01 --status=failed`
|
|
56
|
+
2. System reads history, filters by date and status
|
|
57
|
+
3. System outputs filtered JSON to stdout
|
|
58
|
+
|
|
59
|
+
**To File:**
|
|
60
|
+
|
|
61
|
+
1. User runs `murmur8 history export --format=csv --output=report.csv`
|
|
62
|
+
2. System writes CSV to specified file
|
|
63
|
+
3. System prints confirmation message
|
|
64
|
+
|
|
65
|
+
**Edge Cases:**
|
|
66
|
+
|
|
67
|
+
- Empty history: Output empty array/CSV header with no data rows
|
|
68
|
+
- Corrupted history file: Warn and exit with non-zero status
|
|
69
|
+
- No matches for filters: Output empty result (not an error)
|
|
70
|
+
- Invalid date format: Error with usage hint
|
|
71
|
+
|
|
72
|
+
---
|
|
73
|
+
|
|
74
|
+
## 5. State & Lifecycle Interactions
|
|
75
|
+
|
|
76
|
+
This feature is **state-reading only**. It does not modify pipeline state.
|
|
77
|
+
|
|
78
|
+
- **Reads:** `.claude/pipeline-history.json`
|
|
79
|
+
- **Does not modify:** Any state files or artifacts
|
|
80
|
+
|
|
81
|
+
---
|
|
82
|
+
|
|
83
|
+
## 6. Rules & Decision Logic
|
|
84
|
+
|
|
85
|
+
### Format Selection Rule
|
|
86
|
+
|
|
87
|
+
| `--format` value | Output |
|
|
88
|
+
|------------------|--------|
|
|
89
|
+
| `csv` (default) | Comma-separated values with header row |
|
|
90
|
+
| `json` | Pretty-printed JSON array |
|
|
91
|
+
|
|
92
|
+
### Date Filtering Rules
|
|
93
|
+
|
|
94
|
+
- `--since=YYYY-MM-DD`: Include entries where `completedAt >= since`
|
|
95
|
+
- `--until=YYYY-MM-DD`: Include entries where `completedAt <= until`
|
|
96
|
+
- Both can be combined for a range
|
|
97
|
+
- Dates are interpreted as start of day (00:00:00) in local timezone
|
|
98
|
+
|
|
99
|
+
### Status Filtering Rule
|
|
100
|
+
|
|
101
|
+
- `--status=success|failed|paused`: Include only entries with matching status
|
|
102
|
+
- Multiple values not supported in v1 (e.g., no `--status=success,failed`)
|
|
103
|
+
|
|
104
|
+
### Feature Filtering Rule
|
|
105
|
+
|
|
106
|
+
- `--feature=<slug>`: Include only entries matching the feature slug
|
|
107
|
+
- Exact match (not substring)
|
|
108
|
+
|
|
109
|
+
### Output Destination Rule
|
|
110
|
+
|
|
111
|
+
- No `--output`: Write to stdout
|
|
112
|
+
- `--output=<path>`: Write to file, creating parent directories if needed
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
## 7. Dependencies
|
|
117
|
+
|
|
118
|
+
### System Components
|
|
119
|
+
|
|
120
|
+
- `src/history.js` — Existing `readHistoryFile()` function for reading history
|
|
121
|
+
- `src/theme.js` — Optional colorization for confirmation messages
|
|
122
|
+
|
|
123
|
+
### Data Format
|
|
124
|
+
|
|
125
|
+
Relies on existing history entry structure:
|
|
126
|
+
|
|
127
|
+
```javascript
|
|
128
|
+
{
|
|
129
|
+
slug: string,
|
|
130
|
+
status: 'success' | 'failed' | 'paused',
|
|
131
|
+
startedAt: ISO8601,
|
|
132
|
+
completedAt: ISO8601,
|
|
133
|
+
totalDurationMs: number,
|
|
134
|
+
stages: { [stage]: { durationMs, feedback? } },
|
|
135
|
+
failedStage?: string,
|
|
136
|
+
pausedAfter?: string
|
|
137
|
+
}
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
---
|
|
141
|
+
|
|
142
|
+
## 8. Non-Functional Considerations
|
|
143
|
+
|
|
144
|
+
### Performance
|
|
145
|
+
|
|
146
|
+
- History files are typically small (<1MB). No streaming required for v1.
|
|
147
|
+
- If performance becomes an issue with large histories, consider streaming JSON output.
|
|
148
|
+
|
|
149
|
+
### Error Handling
|
|
150
|
+
|
|
151
|
+
- Invalid date format: Exit with code 1, print usage hint
|
|
152
|
+
- Missing history file: Treat as empty (not an error)
|
|
153
|
+
- Corrupted history file: Exit with code 1, suggest `history clear`
|
|
154
|
+
- File write error: Exit with code 1 with descriptive message
|
|
155
|
+
|
|
156
|
+
---
|
|
157
|
+
|
|
158
|
+
## 9. Assumptions & Open Questions
|
|
159
|
+
|
|
160
|
+
### Assumptions
|
|
161
|
+
|
|
162
|
+
- History file structure is stable (no migration needed)
|
|
163
|
+
- Users have write permissions for `--output` destination
|
|
164
|
+
- Date parsing uses native JavaScript Date (ISO 8601 format expected)
|
|
165
|
+
|
|
166
|
+
### Open Questions
|
|
167
|
+
|
|
168
|
+
- **Q:** Should we support `--limit` to cap exported rows?
|
|
169
|
+
- **A:** Defer to v2. Users can pipe to `head` for now.
|
|
170
|
+
- **Q:** Should CSV include nested stage data?
|
|
171
|
+
- **A:** v1 exports top-level fields only. Stage details available in JSON.
|
|
172
|
+
|
|
173
|
+
---
|
|
174
|
+
|
|
175
|
+
## 10. Impact on System Specification
|
|
176
|
+
|
|
177
|
+
This feature **reinforces** existing system assumptions:
|
|
178
|
+
|
|
179
|
+
- Aligns with observability cross-cutting concern (System Spec Section 8)
|
|
180
|
+
- Builds on existing history module without modifying its behavior
|
|
181
|
+
- Does not introduce new state, lifecycle, or invariant changes
|
|
182
|
+
|
|
183
|
+
No system spec changes required.
|
|
184
|
+
|
|
185
|
+
---
|
|
186
|
+
|
|
187
|
+
## 11. Handover to BA (Cass)
|
|
188
|
+
|
|
189
|
+
### Story Themes
|
|
190
|
+
|
|
191
|
+
1. **Basic Export** — Export history to CSV or JSON format
|
|
192
|
+
2. **Date Filtering** — Filter exports by date range
|
|
193
|
+
3. **Status Filtering** — Filter exports by pipeline status
|
|
194
|
+
4. **Feature Filtering** — Filter exports by feature slug
|
|
195
|
+
5. **File Output** — Write exports to a file instead of stdout
|
|
196
|
+
|
|
197
|
+
### Expected Story Boundaries
|
|
198
|
+
|
|
199
|
+
- Each filter type should be a separate story for independent testing
|
|
200
|
+
- File output can be combined with basic export
|
|
201
|
+
- Error handling can be implicit in each story's acceptance criteria
|
|
202
|
+
|
|
203
|
+
### Areas Needing Careful Story Framing
|
|
204
|
+
|
|
205
|
+
- CSV field ordering and escaping rules (commas, quotes in slugs)
|
|
206
|
+
- Empty result behavior (should still output valid CSV/JSON structure)
|
|
207
|
+
- Date parsing edge cases (timezone handling, invalid formats)
|
|
208
|
+
|
|
209
|
+
---
|
|
210
|
+
|
|
211
|
+
## 12. Change Log (Feature-Level)
|
|
212
|
+
|
|
213
|
+
| Date | Change | Reason | Raised By |
|
|
214
|
+
|------|--------|--------|-----------|
|
|
215
|
+
| 2026-03-03 | Initial feature specification | Implement export-history from backlog | Alex |
|