agileflow 2.83.0 → 2.84.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/package.json +1 -1
- package/scripts/agileflow-configure.js +2 -4
- package/scripts/agileflow-statusline.sh +50 -3
- package/scripts/agileflow-welcome.js +84 -11
- package/scripts/check-update.js +12 -63
- package/scripts/lib/file-tracking.js +733 -0
- package/scripts/lib/story-claiming.js +558 -0
- package/scripts/obtain-context.js +117 -1
- package/scripts/session-manager.js +519 -1
- package/src/core/agents/configuration-visual-e2e.md +29 -1
- package/src/core/agents/ui.md +50 -0
- package/src/core/commands/babysit.md +118 -0
- package/src/core/commands/session/end.md +44 -2
package/CHANGELOG.md
CHANGED
package/package.json
CHANGED
|
@@ -788,16 +788,14 @@ function enableFeature(feature, options = {}) {
|
|
|
788
788
|
|
|
789
789
|
// Handle autoupdate (metadata only, no hooks needed)
|
|
790
790
|
if (feature === 'autoupdate') {
|
|
791
|
-
const frequency = options.checkFrequency || 'daily';
|
|
792
791
|
updateMetadata({
|
|
793
792
|
updates: {
|
|
794
793
|
autoUpdate: true,
|
|
795
|
-
checkFrequency: frequency,
|
|
796
794
|
showChangelog: true,
|
|
797
795
|
},
|
|
798
796
|
});
|
|
799
|
-
success(
|
|
800
|
-
info('AgileFlow will
|
|
797
|
+
success('Auto-update enabled');
|
|
798
|
+
info('AgileFlow will check for updates every session and update automatically');
|
|
801
799
|
return true; // Skip settings.json write for this feature
|
|
802
800
|
}
|
|
803
801
|
|
|
@@ -385,11 +385,11 @@ PYTHON
|
|
|
385
385
|
SESSION_COLOR="$SESSION_GREEN" # Light green - plenty of time
|
|
386
386
|
fi
|
|
387
387
|
|
|
388
|
-
# Build compact display: "
|
|
388
|
+
# Build compact display: "~2h15m" or "~45m" (tilde indicates remaining time)
|
|
389
389
|
if [ "$RH" -gt 0 ]; then
|
|
390
|
-
SESSION_DISPLAY="${SESSION_COLOR}
|
|
390
|
+
SESSION_DISPLAY="${SESSION_COLOR}~${RH}h${RM}m${RESET}"
|
|
391
391
|
else
|
|
392
|
-
SESSION_DISPLAY="${SESSION_COLOR}
|
|
392
|
+
SESSION_DISPLAY="${SESSION_COLOR}~${RM}m${RESET}"
|
|
393
393
|
fi
|
|
394
394
|
fi
|
|
395
395
|
fi
|
|
@@ -520,6 +520,47 @@ if git rev-parse --git-dir > /dev/null 2>&1; then
|
|
|
520
520
|
fi
|
|
521
521
|
fi
|
|
522
522
|
|
|
523
|
+
# ============================================================================
|
|
524
|
+
# Session Info (Multi-session awareness)
|
|
525
|
+
# ============================================================================
|
|
526
|
+
# Show current session if in a non-main session
|
|
527
|
+
SESSION_INFO=""
|
|
528
|
+
SHOW_SESSION=true # New component - default enabled
|
|
529
|
+
|
|
530
|
+
# Check component setting
|
|
531
|
+
if [ "$COMPONENTS" != "null" ] && [ -n "$COMPONENTS" ]; then
|
|
532
|
+
SHOW_SESSION=$(echo "$COMPONENTS" | jq -r '.session | if . == null then true else . end')
|
|
533
|
+
fi
|
|
534
|
+
|
|
535
|
+
if [ "$SHOW_SESSION" = "true" ]; then
|
|
536
|
+
REGISTRY_FILE=".agileflow/sessions/registry.json"
|
|
537
|
+
if [ -f "$REGISTRY_FILE" ]; then
|
|
538
|
+
# Get current working directory
|
|
539
|
+
CWD=$(pwd)
|
|
540
|
+
|
|
541
|
+
# Find session matching current directory
|
|
542
|
+
SESSION_DATA=$(jq -r --arg cwd "$CWD" '
|
|
543
|
+
.sessions | to_entries[] | select(.value.path == $cwd) |
|
|
544
|
+
{id: .key, nickname: .value.nickname, is_main: .value.is_main}
|
|
545
|
+
' "$REGISTRY_FILE" 2>/dev/null)
|
|
546
|
+
|
|
547
|
+
if [ -n "$SESSION_DATA" ]; then
|
|
548
|
+
SESSION_NUM=$(echo "$SESSION_DATA" | jq -r '.id')
|
|
549
|
+
SESSION_NICK=$(echo "$SESSION_DATA" | jq -r '.nickname // empty')
|
|
550
|
+
IS_MAIN=$(echo "$SESSION_DATA" | jq -r '.is_main // false')
|
|
551
|
+
|
|
552
|
+
# Only show for non-main sessions
|
|
553
|
+
if [ "$IS_MAIN" != "true" ] && [ -n "$SESSION_NUM" ]; then
|
|
554
|
+
if [ -n "$SESSION_NICK" ] && [ "$SESSION_NICK" != "null" ]; then
|
|
555
|
+
SESSION_INFO="${DIM}[${RESET}${MAGENTA}S${SESSION_NUM}${RESET}${DIM}:${RESET}${SESSION_NICK}${DIM}]${RESET}"
|
|
556
|
+
else
|
|
557
|
+
SESSION_INFO="${DIM}[${RESET}${MAGENTA}S${SESSION_NUM}${RESET}${DIM}]${RESET}"
|
|
558
|
+
fi
|
|
559
|
+
fi
|
|
560
|
+
fi
|
|
561
|
+
fi
|
|
562
|
+
fi
|
|
563
|
+
|
|
523
564
|
# ============================================================================
|
|
524
565
|
# Build Status Line
|
|
525
566
|
# ============================================================================
|
|
@@ -533,6 +574,12 @@ if [ "$SHOW_AGILEFLOW" = "true" ] && [ -n "$AGILEFLOW_DISPLAY" ]; then
|
|
|
533
574
|
OUTPUT="${AGILEFLOW_DISPLAY}"
|
|
534
575
|
fi
|
|
535
576
|
|
|
577
|
+
# Session info (if in a non-main session)
|
|
578
|
+
if [ "$SHOW_SESSION" = "true" ] && [ -n "$SESSION_INFO" ]; then
|
|
579
|
+
[ -n "$OUTPUT" ] && OUTPUT="${OUTPUT}${SEP}"
|
|
580
|
+
OUTPUT="${OUTPUT}${SESSION_INFO}"
|
|
581
|
+
fi
|
|
582
|
+
|
|
536
583
|
# Model with subtle styling (if enabled and available)
|
|
537
584
|
if [ "$SHOW_MODEL" = "true" ] && [ -n "$MODEL_DISPLAY" ]; then
|
|
538
585
|
[ -n "$OUTPUT" ] && OUTPUT="${OUTPUT}${SEP}"
|
|
@@ -22,6 +22,22 @@ const { getProjectRoot } = require('../lib/paths');
|
|
|
22
22
|
// Session manager path (relative to script location)
|
|
23
23
|
const SESSION_MANAGER_PATH = path.join(__dirname, 'session-manager.js');
|
|
24
24
|
|
|
25
|
+
// Story claiming module
|
|
26
|
+
let storyClaiming;
|
|
27
|
+
try {
|
|
28
|
+
storyClaiming = require('./lib/story-claiming.js');
|
|
29
|
+
} catch (e) {
|
|
30
|
+
// Story claiming not available
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// File tracking module
|
|
34
|
+
let fileTracking;
|
|
35
|
+
try {
|
|
36
|
+
fileTracking = require('./lib/file-tracking.js');
|
|
37
|
+
} catch (e) {
|
|
38
|
+
// File tracking not available
|
|
39
|
+
}
|
|
40
|
+
|
|
25
41
|
// Update checker module
|
|
26
42
|
let updateChecker;
|
|
27
43
|
try {
|
|
@@ -481,14 +497,18 @@ function getChangelogEntries(version) {
|
|
|
481
497
|
async function runAutoUpdate(rootDir) {
|
|
482
498
|
try {
|
|
483
499
|
console.log(`${c.skyBlue}Updating AgileFlow...${c.reset}`);
|
|
484
|
-
|
|
500
|
+
// Use --force to skip prompts for non-interactive auto-update
|
|
501
|
+
execSync('npx agileflow@latest update --force', {
|
|
485
502
|
cwd: rootDir,
|
|
486
503
|
encoding: 'utf8',
|
|
487
504
|
stdio: 'inherit',
|
|
505
|
+
timeout: 120000, // 2 minute timeout
|
|
488
506
|
});
|
|
507
|
+
console.log(`${c.mintGreen}Update complete!${c.reset}`);
|
|
489
508
|
return true;
|
|
490
509
|
} catch (e) {
|
|
491
|
-
console.log(`${c.peach}Auto-update failed
|
|
510
|
+
console.log(`${c.peach}Auto-update failed: ${e.message}${c.reset}`);
|
|
511
|
+
console.log(`${c.dim}Run manually: npx agileflow update${c.reset}`);
|
|
492
512
|
return false;
|
|
493
513
|
}
|
|
494
514
|
}
|
|
@@ -722,16 +742,19 @@ function formatTable(
|
|
|
722
742
|
lines.push(fullRow(` Run: ${c.skyBlue}npx agileflow update${c.reset}`, ''));
|
|
723
743
|
}
|
|
724
744
|
|
|
725
|
-
//
|
|
726
|
-
|
|
745
|
+
// Always show "What's new" section with current version changelog
|
|
746
|
+
// Get changelog entries for current version (even if not just updated)
|
|
747
|
+
const changelogEntries = updateInfo.changelog && updateInfo.changelog.length > 0
|
|
748
|
+
? updateInfo.changelog
|
|
749
|
+
: getChangelogEntries(info.version);
|
|
750
|
+
|
|
751
|
+
if (changelogEntries && changelogEntries.length > 0) {
|
|
727
752
|
lines.push(fullDivider());
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
);
|
|
734
|
-
for (const entry of updateInfo.changelog.slice(0, 2)) {
|
|
753
|
+
const headerText = updateInfo.justUpdated
|
|
754
|
+
? `${c.mintGreen}✨${c.reset} Just updated to ${c.softGold}v${info.version}${c.reset}:`
|
|
755
|
+
: `${c.teal}📋${c.reset} What's new in ${c.softGold}v${info.version}${c.reset}:`;
|
|
756
|
+
lines.push(fullRow(headerText, ''));
|
|
757
|
+
for (const entry of changelogEntries.slice(0, 2)) {
|
|
735
758
|
lines.push(fullRow(` ${c.teal}•${c.reset} ${truncate(entry, W - 6)}`, ''));
|
|
736
759
|
}
|
|
737
760
|
lines.push(fullRow(` Run ${c.skyBlue}/agileflow:whats-new${c.reset} for full changelog`, ''));
|
|
@@ -976,6 +999,56 @@ async function main() {
|
|
|
976
999
|
`${c.slate} Run ${c.skyBlue}/agileflow:session:new${c.reset}${c.slate} to create isolated workspace.${c.reset}`
|
|
977
1000
|
);
|
|
978
1001
|
}
|
|
1002
|
+
|
|
1003
|
+
// Story claiming: cleanup stale claims and show warnings
|
|
1004
|
+
if (storyClaiming) {
|
|
1005
|
+
try {
|
|
1006
|
+
// Clean up stale claims (dead PIDs, expired TTL)
|
|
1007
|
+
const cleanupResult = storyClaiming.cleanupStaleClaims({ rootDir });
|
|
1008
|
+
if (cleanupResult.ok && cleanupResult.cleaned > 0) {
|
|
1009
|
+
console.log('');
|
|
1010
|
+
console.log(
|
|
1011
|
+
`${c.dim}Cleaned ${cleanupResult.cleaned} stale story claim(s)${c.reset}`
|
|
1012
|
+
);
|
|
1013
|
+
}
|
|
1014
|
+
|
|
1015
|
+
// Show stories claimed by other sessions
|
|
1016
|
+
const othersResult = storyClaiming.getStoriesClaimedByOthers({ rootDir });
|
|
1017
|
+
if (othersResult.ok && othersResult.stories && othersResult.stories.length > 0) {
|
|
1018
|
+
console.log('');
|
|
1019
|
+
console.log(storyClaiming.formatClaimedStories(othersResult.stories));
|
|
1020
|
+
console.log('');
|
|
1021
|
+
console.log(
|
|
1022
|
+
`${c.slate} These stories are locked - pick a different one to avoid conflicts.${c.reset}`
|
|
1023
|
+
);
|
|
1024
|
+
}
|
|
1025
|
+
} catch (e) {
|
|
1026
|
+
// Silently ignore story claiming errors
|
|
1027
|
+
}
|
|
1028
|
+
}
|
|
1029
|
+
|
|
1030
|
+
// File tracking: cleanup stale touches and show overlap warnings
|
|
1031
|
+
if (fileTracking) {
|
|
1032
|
+
try {
|
|
1033
|
+
// Clean up stale file touches (dead PIDs, expired TTL)
|
|
1034
|
+
const cleanupResult = fileTracking.cleanupStaleTouches({ rootDir });
|
|
1035
|
+
if (cleanupResult.ok && cleanupResult.cleaned > 0) {
|
|
1036
|
+
console.log('');
|
|
1037
|
+
console.log(
|
|
1038
|
+
`${c.dim}Cleaned ${cleanupResult.cleaned} stale file tracking session(s)${c.reset}`
|
|
1039
|
+
);
|
|
1040
|
+
}
|
|
1041
|
+
|
|
1042
|
+
// Show file overlaps with other sessions
|
|
1043
|
+
const overlapsResult = fileTracking.getMyFileOverlaps({ rootDir });
|
|
1044
|
+
if (overlapsResult.ok && overlapsResult.overlaps && overlapsResult.overlaps.length > 0) {
|
|
1045
|
+
console.log('');
|
|
1046
|
+
console.log(fileTracking.formatFileOverlaps(overlapsResult.overlaps));
|
|
1047
|
+
}
|
|
1048
|
+
} catch (e) {
|
|
1049
|
+
// Silently ignore file tracking errors
|
|
1050
|
+
}
|
|
1051
|
+
}
|
|
979
1052
|
}
|
|
980
1053
|
|
|
981
1054
|
main().catch(console.error);
|
package/scripts/check-update.js
CHANGED
|
@@ -1,20 +1,15 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
* check-update.js - Check for AgileFlow updates
|
|
4
|
+
* check-update.js - Check for AgileFlow updates
|
|
5
5
|
*
|
|
6
|
-
*
|
|
7
|
-
* -
|
|
8
|
-
* -
|
|
9
|
-
* -
|
|
10
|
-
* - Returns structured JSON for easy parsing
|
|
6
|
+
* Simple update checker:
|
|
7
|
+
* - Always checks npm registry for latest version
|
|
8
|
+
* - Auto-updates if update is available (enabled by default)
|
|
9
|
+
* - Fast npm metadata lookup (~100-500ms)
|
|
11
10
|
*
|
|
12
11
|
* Usage:
|
|
13
|
-
* node check-update.js [--
|
|
14
|
-
*
|
|
15
|
-
* Options:
|
|
16
|
-
* --force Bypass cache and check npm directly
|
|
17
|
-
* --json Output as JSON (default is human-readable)
|
|
12
|
+
* node check-update.js [--json]
|
|
18
13
|
*
|
|
19
14
|
* Environment:
|
|
20
15
|
* DEBUG_UPDATE=1 Enable debug logging
|
|
@@ -66,12 +61,9 @@ function getInstalledVersion(rootDir) {
|
|
|
66
61
|
// Get update configuration from metadata
|
|
67
62
|
function getUpdateConfig(rootDir) {
|
|
68
63
|
const defaults = {
|
|
69
|
-
autoUpdate:
|
|
70
|
-
checkFrequency: 'daily', // hourly, daily, weekly, never
|
|
64
|
+
autoUpdate: true, // Auto-update enabled by default
|
|
71
65
|
showChangelog: true,
|
|
72
|
-
lastCheck: null,
|
|
73
66
|
lastSeenVersion: null,
|
|
74
|
-
latestVersion: null,
|
|
75
67
|
};
|
|
76
68
|
|
|
77
69
|
const metadataPath = path.join(rootDir, 'docs/00-meta/agileflow-metadata.json');
|
|
@@ -109,34 +101,6 @@ function saveUpdateConfig(rootDir, config) {
|
|
|
109
101
|
return true;
|
|
110
102
|
}
|
|
111
103
|
|
|
112
|
-
// Check if cache is still valid
|
|
113
|
-
function isCacheValid(config) {
|
|
114
|
-
if (!config.lastCheck) return false;
|
|
115
|
-
|
|
116
|
-
const now = Date.now();
|
|
117
|
-
const lastCheck = new Date(config.lastCheck).getTime();
|
|
118
|
-
const age = now - lastCheck;
|
|
119
|
-
|
|
120
|
-
// Convert frequency to milliseconds
|
|
121
|
-
const frequencies = {
|
|
122
|
-
hourly: 60 * 60 * 1000, // 1 hour
|
|
123
|
-
daily: 24 * 60 * 60 * 1000, // 24 hours
|
|
124
|
-
weekly: 7 * 24 * 60 * 60 * 1000, // 7 days
|
|
125
|
-
never: Infinity,
|
|
126
|
-
};
|
|
127
|
-
|
|
128
|
-
const maxAge = frequencies[config.checkFrequency] || frequencies.daily;
|
|
129
|
-
|
|
130
|
-
debugLog('Cache check', {
|
|
131
|
-
lastCheck: config.lastCheck,
|
|
132
|
-
ageMs: age,
|
|
133
|
-
maxAgeMs: maxAge,
|
|
134
|
-
valid: age < maxAge,
|
|
135
|
-
});
|
|
136
|
-
|
|
137
|
-
return age < maxAge;
|
|
138
|
-
}
|
|
139
|
-
|
|
140
104
|
// Fetch latest version from npm
|
|
141
105
|
async function fetchLatestVersion() {
|
|
142
106
|
return new Promise(resolve => {
|
|
@@ -205,8 +169,8 @@ function compareVersions(a, b) {
|
|
|
205
169
|
return 0;
|
|
206
170
|
}
|
|
207
171
|
|
|
208
|
-
// Main check function
|
|
209
|
-
async function checkForUpdates(
|
|
172
|
+
// Main check function - always checks npm
|
|
173
|
+
async function checkForUpdates() {
|
|
210
174
|
const rootDir = getProjectRoot();
|
|
211
175
|
const installedVersion = getInstalledVersion(rootDir);
|
|
212
176
|
const config = getUpdateConfig(rootDir);
|
|
@@ -218,7 +182,6 @@ async function checkForUpdates(options = {}) {
|
|
|
218
182
|
autoUpdate: config.autoUpdate,
|
|
219
183
|
justUpdated: false,
|
|
220
184
|
previousVersion: config.lastSeenVersion,
|
|
221
|
-
fromCache: false,
|
|
222
185
|
error: null,
|
|
223
186
|
};
|
|
224
187
|
|
|
@@ -234,21 +197,8 @@ async function checkForUpdates(options = {}) {
|
|
|
234
197
|
result.previousVersion = config.lastSeenVersion;
|
|
235
198
|
}
|
|
236
199
|
|
|
237
|
-
//
|
|
238
|
-
|
|
239
|
-
result.latest = config.latestVersion;
|
|
240
|
-
result.fromCache = true;
|
|
241
|
-
} else if (config.checkFrequency !== 'never') {
|
|
242
|
-
// Fetch from npm
|
|
243
|
-
result.latest = await fetchLatestVersion();
|
|
244
|
-
|
|
245
|
-
// Update cache
|
|
246
|
-
if (result.latest) {
|
|
247
|
-
config.lastCheck = new Date().toISOString();
|
|
248
|
-
config.latestVersion = result.latest;
|
|
249
|
-
saveUpdateConfig(rootDir, config);
|
|
250
|
-
}
|
|
251
|
-
}
|
|
200
|
+
// Always fetch from npm
|
|
201
|
+
result.latest = await fetchLatestVersion();
|
|
252
202
|
|
|
253
203
|
// Compare versions
|
|
254
204
|
if (result.latest && compareVersions(installedVersion, result.latest) < 0) {
|
|
@@ -269,7 +219,6 @@ function markVersionSeen(version) {
|
|
|
269
219
|
// CLI interface
|
|
270
220
|
async function main() {
|
|
271
221
|
const args = process.argv.slice(2);
|
|
272
|
-
const force = args.includes('--force');
|
|
273
222
|
const jsonOutput = args.includes('--json');
|
|
274
223
|
const markSeen = args.includes('--mark-seen');
|
|
275
224
|
|
|
@@ -286,7 +235,7 @@ async function main() {
|
|
|
286
235
|
return;
|
|
287
236
|
}
|
|
288
237
|
|
|
289
|
-
const result = await checkForUpdates(
|
|
238
|
+
const result = await checkForUpdates();
|
|
290
239
|
|
|
291
240
|
if (jsonOutput) {
|
|
292
241
|
console.log(JSON.stringify(result, null, 2));
|