agileflow 2.91.0 → 2.92.1
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/CHANGELOG.md +10 -0
- package/README.md +6 -6
- package/lib/README.md +178 -0
- package/lib/codebase-indexer.js +32 -23
- package/lib/colors.js +190 -12
- package/lib/consent.js +232 -0
- package/lib/correlation.js +277 -0
- package/lib/error-codes.js +46 -0
- package/lib/errors.js +48 -6
- package/lib/file-cache.js +182 -0
- package/lib/format-error.js +156 -0
- package/lib/path-resolver.js +155 -7
- package/lib/paths.js +212 -20
- package/lib/placeholder-registry.js +205 -0
- package/lib/registry-di.js +358 -0
- package/lib/result-schema.js +363 -0
- package/lib/result.js +210 -0
- package/lib/session-registry.js +13 -0
- package/lib/session-state-machine.js +465 -0
- package/lib/validate-commands.js +308 -0
- package/lib/validate.js +116 -52
- package/package.json +1 -1
- package/scripts/af +34 -0
- package/scripts/agent-loop.js +63 -9
- package/scripts/agileflow-configure.js +2 -2
- package/scripts/agileflow-welcome.js +491 -23
- package/scripts/archive-completed-stories.sh +57 -11
- package/scripts/claude-tmux.sh +102 -0
- package/scripts/damage-control-bash.js +3 -70
- package/scripts/damage-control-edit.js +3 -20
- package/scripts/damage-control-write.js +3 -20
- package/scripts/dependency-check.js +310 -0
- package/scripts/get-env.js +11 -4
- package/scripts/lib/configure-detect.js +23 -1
- package/scripts/lib/configure-features.js +50 -2
- package/scripts/lib/context-formatter.js +771 -0
- package/scripts/lib/context-loader.js +699 -0
- package/scripts/lib/damage-control-utils.js +107 -0
- package/scripts/lib/json-utils.sh +162 -0
- package/scripts/lib/state-migrator.js +353 -0
- package/scripts/lib/story-state-machine.js +437 -0
- package/scripts/obtain-context.js +80 -1248
- package/scripts/pre-push-check.sh +46 -0
- package/scripts/precompact-context.sh +23 -10
- package/scripts/query-codebase.js +127 -14
- package/scripts/ralph-loop.js +5 -5
- package/scripts/session-manager.js +408 -55
- package/scripts/spawn-parallel.js +666 -0
- package/scripts/tui/blessed/data/watcher.js +20 -15
- package/scripts/tui/blessed/index.js +2 -2
- package/scripts/tui/blessed/panels/output.js +14 -8
- package/scripts/tui/blessed/panels/sessions.js +22 -15
- package/scripts/tui/blessed/panels/trace.js +14 -8
- package/scripts/tui/blessed/ui/help.js +3 -3
- package/scripts/tui/blessed/ui/screen.js +4 -4
- package/scripts/tui/blessed/ui/statusbar.js +5 -9
- package/scripts/tui/blessed/ui/tabbar.js +11 -11
- package/scripts/validators/component-validator.js +41 -14
- package/scripts/validators/json-schema-validator.js +11 -4
- package/scripts/validators/markdown-validator.js +1 -2
- package/scripts/validators/migration-validator.js +17 -5
- package/scripts/validators/security-validator.js +137 -33
- package/scripts/validators/story-format-validator.js +31 -10
- package/scripts/validators/test-result-validator.js +19 -4
- package/scripts/validators/workflow-validator.js +12 -5
- package/src/core/agents/codebase-query.md +24 -0
- package/src/core/commands/adr.md +114 -0
- package/src/core/commands/agent.md +120 -0
- package/src/core/commands/assign.md +145 -0
- package/src/core/commands/babysit.md +32 -5
- package/src/core/commands/changelog.md +118 -0
- package/src/core/commands/configure.md +42 -6
- package/src/core/commands/diagnose.md +114 -0
- package/src/core/commands/epic.md +113 -0
- package/src/core/commands/handoff.md +128 -0
- package/src/core/commands/help.md +75 -0
- package/src/core/commands/pr.md +96 -0
- package/src/core/commands/roadmap/analyze.md +400 -0
- package/src/core/commands/session/new.md +132 -6
- package/src/core/commands/session/spawn.md +197 -0
- package/src/core/commands/sprint.md +22 -0
- package/src/core/commands/status.md +74 -0
- package/src/core/commands/story.md +143 -4
- package/src/core/templates/agileflow-metadata.json +55 -2
- package/src/core/templates/plan-template.md +125 -0
- package/src/core/templates/story-lifecycle.md +213 -0
- package/src/core/templates/story-template.md +4 -0
- package/src/core/templates/tdd-test-template.js +241 -0
- package/tools/cli/commands/setup.js +95 -0
- package/tools/cli/installers/core/installer.js +94 -0
- package/tools/cli/installers/ide/_base-ide.js +20 -11
- package/tools/cli/installers/ide/codex.js +29 -47
- package/tools/cli/installers/ide/windsurf.js +1 -1
- package/tools/cli/lib/config-manager.js +17 -2
- package/tools/cli/lib/content-transformer.js +271 -0
- package/tools/cli/lib/error-handler.js +14 -22
- package/tools/cli/lib/ide-error-factory.js +421 -0
- package/tools/cli/lib/ide-health-monitor.js +364 -0
- package/tools/cli/lib/ide-registry.js +113 -2
- package/tools/cli/lib/ui.js +15 -25
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Pre-push validation script
|
|
3
|
+
# Run before pushing to catch CI failures locally
|
|
4
|
+
# Usage: npm run check (quick: lint + tests only, ~30s)
|
|
5
|
+
# npm run check:full (full: lint + tests + docs build, ~5m)
|
|
6
|
+
|
|
7
|
+
set -e
|
|
8
|
+
|
|
9
|
+
echo "🔍 Running pre-push checks..."
|
|
10
|
+
echo ""
|
|
11
|
+
|
|
12
|
+
# Track start time
|
|
13
|
+
START_TIME=$(date +%s)
|
|
14
|
+
|
|
15
|
+
# 1. Lint check (fastest, catches most issues)
|
|
16
|
+
echo "📋 Step 1/2: Linting..."
|
|
17
|
+
cd packages/cli
|
|
18
|
+
npm run lint 2>&1 | tail -30 || {
|
|
19
|
+
echo "❌ Lint failed! Fix errors before pushing."
|
|
20
|
+
exit 1
|
|
21
|
+
}
|
|
22
|
+
cd ../..
|
|
23
|
+
echo "✅ Lint passed"
|
|
24
|
+
echo ""
|
|
25
|
+
|
|
26
|
+
# 2. Run tests (catches logic errors)
|
|
27
|
+
echo "🧪 Step 2/2: Running tests..."
|
|
28
|
+
cd packages/cli
|
|
29
|
+
npm test 2>&1 | tail -20 || {
|
|
30
|
+
echo "❌ Tests failed! Fix errors before pushing."
|
|
31
|
+
exit 1
|
|
32
|
+
}
|
|
33
|
+
cd ../..
|
|
34
|
+
echo "✅ Tests passed"
|
|
35
|
+
echo ""
|
|
36
|
+
|
|
37
|
+
# Calculate elapsed time
|
|
38
|
+
END_TIME=$(date +%s)
|
|
39
|
+
ELAPSED=$((END_TIME - START_TIME))
|
|
40
|
+
|
|
41
|
+
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
42
|
+
echo "✅ Pre-push checks passed! (${ELAPSED}s)"
|
|
43
|
+
echo " Safe to push."
|
|
44
|
+
echo ""
|
|
45
|
+
echo "💡 Tip: Run 'npm run check:full' to include docs build"
|
|
46
|
+
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
@@ -74,16 +74,29 @@ if [ -f "docs/09-agents/session-state.json" ]; then
|
|
|
74
74
|
fi
|
|
75
75
|
|
|
76
76
|
if [ ! -z "$COMMAND_FILE" ]; then
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
77
|
+
# Security: Validate COMMAND_FILE contains only safe characters (alphanumeric, /, -, _, .)
|
|
78
|
+
# and doesn't contain path traversal sequences
|
|
79
|
+
if [[ "$COMMAND_FILE" =~ ^[a-zA-Z0-9/_.-]+$ ]] && [[ ! "$COMMAND_FILE" =~ \.\. ]]; then
|
|
80
|
+
SUMMARY=$(COMMAND_FILE_PATH="$COMMAND_FILE" ACTIVE_CMD="$ACTIVE_COMMAND" node -e "
|
|
81
|
+
const fs = require('fs');
|
|
82
|
+
const filePath = process.env.COMMAND_FILE_PATH;
|
|
83
|
+
const activeCmd = process.env.ACTIVE_CMD;
|
|
84
|
+
// Double-check: only allow paths within expected directories
|
|
85
|
+
const allowedPrefixes = ['packages/cli/src/core/commands/', '.agileflow/commands/', '.claude/commands/agileflow/'];
|
|
86
|
+
if (!allowedPrefixes.some(p => filePath.startsWith(p))) {
|
|
87
|
+
process.exit(1);
|
|
88
|
+
}
|
|
89
|
+
try {
|
|
90
|
+
const content = fs.readFileSync(filePath, 'utf8');
|
|
91
|
+
const match = content.match(/<!-- COMPACT_SUMMARY_START[\\s\\S]*?-->([\\s\\S]*?)<!-- COMPACT_SUMMARY_END -->/);
|
|
92
|
+
if (match) {
|
|
93
|
+
console.log('## ACTIVE COMMAND: /agileflow:' + activeCmd);
|
|
94
|
+
console.log('');
|
|
95
|
+
console.log(match[1].trim());
|
|
96
|
+
}
|
|
97
|
+
} catch (e) {}
|
|
98
|
+
" 2>/dev/null || echo "")
|
|
99
|
+
fi
|
|
87
100
|
|
|
88
101
|
if [ ! -z "$SUMMARY" ]; then
|
|
89
102
|
COMMAND_SUMMARIES="${COMMAND_SUMMARIES}
|
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
* --budget=<chars> Token budget for output (default: 15000)
|
|
22
22
|
* --json Output as JSON
|
|
23
23
|
* --verbose Show debug info
|
|
24
|
+
* --explain Show equivalent bash workflow (ls/find/grep/cat)
|
|
24
25
|
*
|
|
25
26
|
* Exit codes:
|
|
26
27
|
* 0 = Success
|
|
@@ -56,6 +57,7 @@ function parseArgs(argv) {
|
|
|
56
57
|
budget: DEFAULT_BUDGET,
|
|
57
58
|
json: false,
|
|
58
59
|
verbose: false,
|
|
60
|
+
explain: false, // Show equivalent bash workflow
|
|
59
61
|
};
|
|
60
62
|
|
|
61
63
|
for (const arg of argv.slice(2)) {
|
|
@@ -65,6 +67,8 @@ function parseArgs(argv) {
|
|
|
65
67
|
args.json = true;
|
|
66
68
|
} else if (arg === '--verbose') {
|
|
67
69
|
args.verbose = true;
|
|
70
|
+
} else if (arg === '--explain') {
|
|
71
|
+
args.explain = true;
|
|
68
72
|
} else if (arg.startsWith('--query=')) {
|
|
69
73
|
args.query = arg.slice(8);
|
|
70
74
|
} else if (arg.startsWith('--deps=')) {
|
|
@@ -85,6 +89,78 @@ function parseArgs(argv) {
|
|
|
85
89
|
return args;
|
|
86
90
|
}
|
|
87
91
|
|
|
92
|
+
// Generate bash workflow explanation (research: ls → find → grep → cat pattern)
|
|
93
|
+
function explainWorkflow(queryType, queryValue, projectRoot) {
|
|
94
|
+
const lines = ['', '📖 Equivalent Bash Workflow:', ''];
|
|
95
|
+
|
|
96
|
+
switch (queryType) {
|
|
97
|
+
case 'query':
|
|
98
|
+
lines.push('# Step 1: List available directories (ls)');
|
|
99
|
+
lines.push(`ls -la ${projectRoot}/src/`);
|
|
100
|
+
lines.push('');
|
|
101
|
+
lines.push('# Step 2: Find files matching pattern (find)');
|
|
102
|
+
lines.push(`find ${projectRoot} -name "*${queryValue}*" -type f`);
|
|
103
|
+
lines.push('');
|
|
104
|
+
lines.push('# Step 3: Search content within files (grep)');
|
|
105
|
+
lines.push(`grep -rl "${queryValue}" ${projectRoot}/src/`);
|
|
106
|
+
lines.push('');
|
|
107
|
+
lines.push('# This tool combines all three with indexing for speed.');
|
|
108
|
+
break;
|
|
109
|
+
|
|
110
|
+
case 'content':
|
|
111
|
+
lines.push('# Equivalent to grep with context:');
|
|
112
|
+
lines.push(`grep -rn "${queryValue}" ${projectRoot}/src/ --include="*.{js,ts,tsx}"`);
|
|
113
|
+
lines.push('');
|
|
114
|
+
lines.push('# This tool adds: index awareness, budget truncation, structured output.');
|
|
115
|
+
break;
|
|
116
|
+
|
|
117
|
+
case 'tag': {
|
|
118
|
+
const tagPatterns = {
|
|
119
|
+
api: '/api/|/routes/|/controllers/',
|
|
120
|
+
ui: '/components/|/views/|/pages/',
|
|
121
|
+
auth: '/auth/|/login/|/jwt/',
|
|
122
|
+
database: '/db/|/models/|/migrations/',
|
|
123
|
+
test: '/test/|/__tests__/|/spec/',
|
|
124
|
+
};
|
|
125
|
+
lines.push('# Equivalent to find with path patterns:');
|
|
126
|
+
lines.push(
|
|
127
|
+
`find ${projectRoot} -type f | grep -E "${tagPatterns[queryValue] || queryValue}"`
|
|
128
|
+
);
|
|
129
|
+
lines.push('');
|
|
130
|
+
lines.push('# This tool uses pre-indexed tags for instant lookup.');
|
|
131
|
+
break;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
case 'export':
|
|
135
|
+
lines.push('# Equivalent to grep for export statements:');
|
|
136
|
+
lines.push(`grep -rn "export.*${queryValue}" ${projectRoot}/src/ --include="*.{js,ts,tsx}"`);
|
|
137
|
+
lines.push('');
|
|
138
|
+
lines.push('# This tool tracks exports in index for instant symbol lookup.');
|
|
139
|
+
break;
|
|
140
|
+
|
|
141
|
+
case 'deps':
|
|
142
|
+
lines.push('# Equivalent to grep for imports:');
|
|
143
|
+
lines.push(`grep -n "import.*from" ${queryValue}`);
|
|
144
|
+
lines.push('');
|
|
145
|
+
lines.push('# Plus reverse search for files importing this one:');
|
|
146
|
+
lines.push(
|
|
147
|
+
`grep -rl "${path.basename(queryValue, path.extname(queryValue))}" ${projectRoot}/src/`
|
|
148
|
+
);
|
|
149
|
+
lines.push('');
|
|
150
|
+
lines.push('# This tool tracks bidirectional dependencies in index.');
|
|
151
|
+
break;
|
|
152
|
+
|
|
153
|
+
default:
|
|
154
|
+
lines.push('# Generic file system exploration:');
|
|
155
|
+
lines.push(`ls -la ${projectRoot}/`);
|
|
156
|
+
lines.push(`find ${projectRoot} -type f -name "*.ts" | head -20`);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
lines.push('');
|
|
160
|
+
lines.push('─'.repeat(50));
|
|
161
|
+
return lines.join('\n');
|
|
162
|
+
}
|
|
163
|
+
|
|
88
164
|
// Search file content using grep-style regex
|
|
89
165
|
function queryContent(projectRoot, pattern, budget) {
|
|
90
166
|
const results = [];
|
|
@@ -135,7 +211,14 @@ function queryContent(projectRoot, pattern, budget) {
|
|
|
135
211
|
if (totalChars + resultChars > budget) {
|
|
136
212
|
results.push({
|
|
137
213
|
file: '...',
|
|
138
|
-
matches: [
|
|
214
|
+
matches: [
|
|
215
|
+
{
|
|
216
|
+
line: 0,
|
|
217
|
+
context: [
|
|
218
|
+
{ lineNumber: 0, content: `[Truncated: budget exceeded]`, isMatch: false },
|
|
219
|
+
],
|
|
220
|
+
},
|
|
221
|
+
],
|
|
139
222
|
});
|
|
140
223
|
break;
|
|
141
224
|
}
|
|
@@ -258,14 +341,21 @@ async function main() {
|
|
|
258
341
|
|
|
259
342
|
// Handle --query (glob pattern search)
|
|
260
343
|
if (args.query) {
|
|
261
|
-
if (args.verbose)
|
|
344
|
+
if (args.verbose) {
|
|
345
|
+
console.error(`\n🔍 Step 1: Querying for "${args.query}"`);
|
|
346
|
+
console.error(` Project: ${args.project}`);
|
|
347
|
+
}
|
|
262
348
|
|
|
263
349
|
// First try to get/update index
|
|
350
|
+
if (args.verbose) console.error(`📂 Step 2: Checking/updating index...`);
|
|
264
351
|
const indexResult = updateIndex(args.project);
|
|
265
352
|
if (!indexResult.ok) {
|
|
266
353
|
console.error(`Error: ${indexResult.error}`);
|
|
267
354
|
process.exit(1);
|
|
268
355
|
}
|
|
356
|
+
if (args.verbose) {
|
|
357
|
+
console.error(` Index has ${Object.keys(indexResult.data.files).length} files`);
|
|
358
|
+
}
|
|
269
359
|
|
|
270
360
|
// Interpret query
|
|
271
361
|
const query = args.query.toLowerCase();
|
|
@@ -273,29 +363,41 @@ async function main() {
|
|
|
273
363
|
|
|
274
364
|
// If query looks like a glob, use it directly
|
|
275
365
|
if (query.includes('*') || query.includes('/')) {
|
|
366
|
+
if (args.verbose) console.error(`🔎 Step 3: Glob pattern search: ${args.query}`);
|
|
276
367
|
files = queryFiles(indexResult.data, args.query);
|
|
277
368
|
} else {
|
|
278
369
|
// Otherwise, search multiple ways:
|
|
370
|
+
if (args.verbose) console.error(`🔎 Step 3: Multi-strategy search...`);
|
|
371
|
+
|
|
279
372
|
// 1. Files containing query in name
|
|
373
|
+
if (args.verbose) console.error(` 3a. Filename match: **/*${args.query}*`);
|
|
280
374
|
files = queryFiles(indexResult.data, `**/*${args.query}*`);
|
|
375
|
+
if (args.verbose) console.error(` Found ${files.length} files by name`);
|
|
281
376
|
|
|
282
377
|
// 2. Files with matching tag
|
|
378
|
+
if (args.verbose) console.error(` 3b. Tag search: ${query}`);
|
|
283
379
|
const tagFiles = queryByTag(indexResult.data, query);
|
|
380
|
+
if (args.verbose) console.error(` Found ${tagFiles.length} files by tag`);
|
|
284
381
|
files = [...new Set([...files, ...tagFiles])];
|
|
285
382
|
|
|
286
383
|
// 3. Files exporting symbol
|
|
384
|
+
if (args.verbose) console.error(` 3c. Export search: ${args.query}`);
|
|
287
385
|
const exportFiles = queryByExport(indexResult.data, args.query);
|
|
386
|
+
if (args.verbose) console.error(` Found ${exportFiles.length} files by export`);
|
|
288
387
|
files = [...new Set([...files, ...exportFiles])];
|
|
289
388
|
}
|
|
389
|
+
if (args.verbose) console.error(`✅ Step 4: Total unique results: ${files.length}\n`);
|
|
290
390
|
|
|
291
391
|
if (files.length === 0) {
|
|
292
392
|
console.error(`No files found matching: ${args.query}`);
|
|
293
393
|
process.exit(2);
|
|
294
394
|
}
|
|
295
395
|
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
396
|
+
if (args.explain) {
|
|
397
|
+
console.log(explainWorkflow('query', args.query, args.project));
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
const output = args.json ? JSON.stringify(files, null, 2) : formatResults(files, 'files');
|
|
299
401
|
console.log(truncateOutput(output, args.budget));
|
|
300
402
|
process.exit(0);
|
|
301
403
|
}
|
|
@@ -316,6 +418,10 @@ async function main() {
|
|
|
316
418
|
process.exit(2);
|
|
317
419
|
}
|
|
318
420
|
|
|
421
|
+
if (args.explain) {
|
|
422
|
+
console.log(explainWorkflow('content', args.content, args.project));
|
|
423
|
+
}
|
|
424
|
+
|
|
319
425
|
const output = args.json
|
|
320
426
|
? JSON.stringify(result.data, null, 2)
|
|
321
427
|
: formatResults(result.data, 'content');
|
|
@@ -340,9 +446,11 @@ async function main() {
|
|
|
340
446
|
process.exit(2);
|
|
341
447
|
}
|
|
342
448
|
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
449
|
+
if (args.explain) {
|
|
450
|
+
console.log(explainWorkflow('tag', args.tag, args.project));
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
const output = args.json ? JSON.stringify(files, null, 2) : formatResults(files, 'files');
|
|
346
454
|
console.log(truncateOutput(output, args.budget));
|
|
347
455
|
process.exit(0);
|
|
348
456
|
}
|
|
@@ -364,9 +472,11 @@ async function main() {
|
|
|
364
472
|
process.exit(2);
|
|
365
473
|
}
|
|
366
474
|
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
475
|
+
if (args.explain) {
|
|
476
|
+
console.log(explainWorkflow('export', args.export, args.project));
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
const output = args.json ? JSON.stringify(files, null, 2) : formatResults(files, 'files');
|
|
370
480
|
console.log(truncateOutput(output, args.budget));
|
|
371
481
|
process.exit(0);
|
|
372
482
|
}
|
|
@@ -388,9 +498,11 @@ async function main() {
|
|
|
388
498
|
process.exit(2);
|
|
389
499
|
}
|
|
390
500
|
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
501
|
+
if (args.explain) {
|
|
502
|
+
console.log(explainWorkflow('deps', args.deps, args.project));
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
const output = args.json ? JSON.stringify(deps, null, 2) : formatResults(deps, 'deps');
|
|
394
506
|
console.log(truncateOutput(output, args.budget));
|
|
395
507
|
process.exit(0);
|
|
396
508
|
}
|
|
@@ -411,6 +523,7 @@ Options:
|
|
|
411
523
|
--budget=<chars> Output budget in characters (default: 15000)
|
|
412
524
|
--json Output as JSON
|
|
413
525
|
--verbose Show debug info
|
|
526
|
+
--explain Show equivalent bash workflow (ls/find/grep/cat)
|
|
414
527
|
|
|
415
528
|
Exit codes:
|
|
416
529
|
0 = Success
|
package/scripts/ralph-loop.js
CHANGED
|
@@ -34,33 +34,33 @@ const { execSync, spawnSync } = require('child_process');
|
|
|
34
34
|
|
|
35
35
|
// Shared utilities
|
|
36
36
|
const { c } = require('../lib/colors');
|
|
37
|
-
const { getProjectRoot } = require('../lib/paths');
|
|
37
|
+
const { getProjectRoot, getStatusPath, getSessionStatePath } = require('../lib/paths');
|
|
38
38
|
const { safeReadJSON, safeWriteJSON } = require('../lib/errors');
|
|
39
39
|
const { isValidEpicId, parseIntBounded } = require('../lib/validate');
|
|
40
40
|
|
|
41
41
|
// Read session state
|
|
42
42
|
function getSessionState(rootDir) {
|
|
43
|
-
const statePath =
|
|
43
|
+
const statePath = getSessionStatePath(rootDir);
|
|
44
44
|
const result = safeReadJSON(statePath, { defaultValue: {} });
|
|
45
45
|
return result.ok ? result.data : {};
|
|
46
46
|
}
|
|
47
47
|
|
|
48
48
|
// Write session state
|
|
49
49
|
function saveSessionState(rootDir, state) {
|
|
50
|
-
const statePath =
|
|
50
|
+
const statePath = getSessionStatePath(rootDir);
|
|
51
51
|
safeWriteJSON(statePath, state, { createDir: true });
|
|
52
52
|
}
|
|
53
53
|
|
|
54
54
|
// Read status.json for stories
|
|
55
55
|
function getStatus(rootDir) {
|
|
56
|
-
const statusPath =
|
|
56
|
+
const statusPath = getStatusPath(rootDir);
|
|
57
57
|
const result = safeReadJSON(statusPath, { defaultValue: { stories: {}, epics: {} } });
|
|
58
58
|
return result.ok ? result.data : { stories: {}, epics: {} };
|
|
59
59
|
}
|
|
60
60
|
|
|
61
61
|
// Save status.json
|
|
62
62
|
function saveStatus(rootDir, status) {
|
|
63
|
-
const statusPath =
|
|
63
|
+
const statusPath = getStatusPath(rootDir);
|
|
64
64
|
safeWriteJSON(statusPath, status);
|
|
65
65
|
}
|
|
66
66
|
|