agileflow 2.91.0 → 2.92.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/CHANGELOG.md +5 -0
- package/README.md +3 -3
- package/lib/README.md +178 -0
- package/lib/codebase-indexer.js +31 -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 +435 -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 +43 -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 +122 -14
- package/scripts/ralph-loop.js +5 -5
- package/scripts/session-manager.js +220 -42
- package/scripts/spawn-parallel.js +651 -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 +113 -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 +86 -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/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 +114 -1
- package/tools/cli/lib/ui.js +14 -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,73 @@ 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(`find ${projectRoot} -type f | grep -E "${tagPatterns[queryValue] || queryValue}"`);
|
|
127
|
+
lines.push('');
|
|
128
|
+
lines.push('# This tool uses pre-indexed tags for instant lookup.');
|
|
129
|
+
break;
|
|
130
|
+
|
|
131
|
+
case 'export':
|
|
132
|
+
lines.push('# Equivalent to grep for export statements:');
|
|
133
|
+
lines.push(`grep -rn "export.*${queryValue}" ${projectRoot}/src/ --include="*.{js,ts,tsx}"`);
|
|
134
|
+
lines.push('');
|
|
135
|
+
lines.push('# This tool tracks exports in index for instant symbol lookup.');
|
|
136
|
+
break;
|
|
137
|
+
|
|
138
|
+
case 'deps':
|
|
139
|
+
lines.push('# Equivalent to grep for imports:');
|
|
140
|
+
lines.push(`grep -n "import.*from" ${queryValue}`);
|
|
141
|
+
lines.push('');
|
|
142
|
+
lines.push('# Plus reverse search for files importing this one:');
|
|
143
|
+
lines.push(`grep -rl "${path.basename(queryValue, path.extname(queryValue))}" ${projectRoot}/src/`);
|
|
144
|
+
lines.push('');
|
|
145
|
+
lines.push('# This tool tracks bidirectional dependencies in index.');
|
|
146
|
+
break;
|
|
147
|
+
|
|
148
|
+
default:
|
|
149
|
+
lines.push('# Generic file system exploration:');
|
|
150
|
+
lines.push(`ls -la ${projectRoot}/`);
|
|
151
|
+
lines.push(`find ${projectRoot} -type f -name "*.ts" | head -20`);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
lines.push('');
|
|
155
|
+
lines.push('─'.repeat(50));
|
|
156
|
+
return lines.join('\n');
|
|
157
|
+
}
|
|
158
|
+
|
|
88
159
|
// Search file content using grep-style regex
|
|
89
160
|
function queryContent(projectRoot, pattern, budget) {
|
|
90
161
|
const results = [];
|
|
@@ -135,7 +206,14 @@ function queryContent(projectRoot, pattern, budget) {
|
|
|
135
206
|
if (totalChars + resultChars > budget) {
|
|
136
207
|
results.push({
|
|
137
208
|
file: '...',
|
|
138
|
-
matches: [
|
|
209
|
+
matches: [
|
|
210
|
+
{
|
|
211
|
+
line: 0,
|
|
212
|
+
context: [
|
|
213
|
+
{ lineNumber: 0, content: `[Truncated: budget exceeded]`, isMatch: false },
|
|
214
|
+
],
|
|
215
|
+
},
|
|
216
|
+
],
|
|
139
217
|
});
|
|
140
218
|
break;
|
|
141
219
|
}
|
|
@@ -258,14 +336,21 @@ async function main() {
|
|
|
258
336
|
|
|
259
337
|
// Handle --query (glob pattern search)
|
|
260
338
|
if (args.query) {
|
|
261
|
-
if (args.verbose)
|
|
339
|
+
if (args.verbose) {
|
|
340
|
+
console.error(`\n🔍 Step 1: Querying for "${args.query}"`);
|
|
341
|
+
console.error(` Project: ${args.project}`);
|
|
342
|
+
}
|
|
262
343
|
|
|
263
344
|
// First try to get/update index
|
|
345
|
+
if (args.verbose) console.error(`📂 Step 2: Checking/updating index...`);
|
|
264
346
|
const indexResult = updateIndex(args.project);
|
|
265
347
|
if (!indexResult.ok) {
|
|
266
348
|
console.error(`Error: ${indexResult.error}`);
|
|
267
349
|
process.exit(1);
|
|
268
350
|
}
|
|
351
|
+
if (args.verbose) {
|
|
352
|
+
console.error(` Index has ${Object.keys(indexResult.data.files).length} files`);
|
|
353
|
+
}
|
|
269
354
|
|
|
270
355
|
// Interpret query
|
|
271
356
|
const query = args.query.toLowerCase();
|
|
@@ -273,29 +358,41 @@ async function main() {
|
|
|
273
358
|
|
|
274
359
|
// If query looks like a glob, use it directly
|
|
275
360
|
if (query.includes('*') || query.includes('/')) {
|
|
361
|
+
if (args.verbose) console.error(`🔎 Step 3: Glob pattern search: ${args.query}`);
|
|
276
362
|
files = queryFiles(indexResult.data, args.query);
|
|
277
363
|
} else {
|
|
278
364
|
// Otherwise, search multiple ways:
|
|
365
|
+
if (args.verbose) console.error(`🔎 Step 3: Multi-strategy search...`);
|
|
366
|
+
|
|
279
367
|
// 1. Files containing query in name
|
|
368
|
+
if (args.verbose) console.error(` 3a. Filename match: **/*${args.query}*`);
|
|
280
369
|
files = queryFiles(indexResult.data, `**/*${args.query}*`);
|
|
370
|
+
if (args.verbose) console.error(` Found ${files.length} files by name`);
|
|
281
371
|
|
|
282
372
|
// 2. Files with matching tag
|
|
373
|
+
if (args.verbose) console.error(` 3b. Tag search: ${query}`);
|
|
283
374
|
const tagFiles = queryByTag(indexResult.data, query);
|
|
375
|
+
if (args.verbose) console.error(` Found ${tagFiles.length} files by tag`);
|
|
284
376
|
files = [...new Set([...files, ...tagFiles])];
|
|
285
377
|
|
|
286
378
|
// 3. Files exporting symbol
|
|
379
|
+
if (args.verbose) console.error(` 3c. Export search: ${args.query}`);
|
|
287
380
|
const exportFiles = queryByExport(indexResult.data, args.query);
|
|
381
|
+
if (args.verbose) console.error(` Found ${exportFiles.length} files by export`);
|
|
288
382
|
files = [...new Set([...files, ...exportFiles])];
|
|
289
383
|
}
|
|
384
|
+
if (args.verbose) console.error(`✅ Step 4: Total unique results: ${files.length}\n`);
|
|
290
385
|
|
|
291
386
|
if (files.length === 0) {
|
|
292
387
|
console.error(`No files found matching: ${args.query}`);
|
|
293
388
|
process.exit(2);
|
|
294
389
|
}
|
|
295
390
|
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
391
|
+
if (args.explain) {
|
|
392
|
+
console.log(explainWorkflow('query', args.query, args.project));
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
const output = args.json ? JSON.stringify(files, null, 2) : formatResults(files, 'files');
|
|
299
396
|
console.log(truncateOutput(output, args.budget));
|
|
300
397
|
process.exit(0);
|
|
301
398
|
}
|
|
@@ -316,6 +413,10 @@ async function main() {
|
|
|
316
413
|
process.exit(2);
|
|
317
414
|
}
|
|
318
415
|
|
|
416
|
+
if (args.explain) {
|
|
417
|
+
console.log(explainWorkflow('content', args.content, args.project));
|
|
418
|
+
}
|
|
419
|
+
|
|
319
420
|
const output = args.json
|
|
320
421
|
? JSON.stringify(result.data, null, 2)
|
|
321
422
|
: formatResults(result.data, 'content');
|
|
@@ -340,9 +441,11 @@ async function main() {
|
|
|
340
441
|
process.exit(2);
|
|
341
442
|
}
|
|
342
443
|
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
444
|
+
if (args.explain) {
|
|
445
|
+
console.log(explainWorkflow('tag', args.tag, args.project));
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
const output = args.json ? JSON.stringify(files, null, 2) : formatResults(files, 'files');
|
|
346
449
|
console.log(truncateOutput(output, args.budget));
|
|
347
450
|
process.exit(0);
|
|
348
451
|
}
|
|
@@ -364,9 +467,11 @@ async function main() {
|
|
|
364
467
|
process.exit(2);
|
|
365
468
|
}
|
|
366
469
|
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
470
|
+
if (args.explain) {
|
|
471
|
+
console.log(explainWorkflow('export', args.export, args.project));
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
const output = args.json ? JSON.stringify(files, null, 2) : formatResults(files, 'files');
|
|
370
475
|
console.log(truncateOutput(output, args.budget));
|
|
371
476
|
process.exit(0);
|
|
372
477
|
}
|
|
@@ -388,9 +493,11 @@ async function main() {
|
|
|
388
493
|
process.exit(2);
|
|
389
494
|
}
|
|
390
495
|
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
496
|
+
if (args.explain) {
|
|
497
|
+
console.log(explainWorkflow('deps', args.deps, args.project));
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
const output = args.json ? JSON.stringify(deps, null, 2) : formatResults(deps, 'deps');
|
|
394
501
|
console.log(truncateOutput(output, args.budget));
|
|
395
502
|
process.exit(0);
|
|
396
503
|
}
|
|
@@ -411,6 +518,7 @@ Options:
|
|
|
411
518
|
--budget=<chars> Output budget in characters (default: 15000)
|
|
412
519
|
--json Output as JSON
|
|
413
520
|
--verbose Show debug info
|
|
521
|
+
--explain Show equivalent bash workflow (ls/find/grep/cat)
|
|
414
522
|
|
|
415
523
|
Exit codes:
|
|
416
524
|
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
|
|