agileflow 4.0.0-alpha.15 → 4.0.0-alpha.17

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agileflow",
3
- "version": "4.0.0-alpha.15",
3
+ "version": "4.0.0-alpha.17",
4
4
  "description": "AI-driven agile development toolkit for Claude Code — skills-first architecture with opt-in plugins (v4)",
5
5
  "keywords": [
6
6
  "agile",
@@ -1182,11 +1182,28 @@ async function maybeOfferAutoRestore(prefs) {
1182
1182
  if (ap !== bp) return bp - ap;
1183
1183
  return 0;
1184
1184
  });
1185
- const options = sorted.map((s) => ({
1185
+ // Synthetic toggles at the top of the picker for users with many
1186
+ // saved sessions — checking one of them rewrites the selection in
1187
+ // bulk after submit (clack's multiselect doesn't natively support
1188
+ // a "select all" shortcut, but synthetic entries are the lightest
1189
+ // path and stay accessible via keyboard).
1190
+ const SELECT_ALL = "__select_all__";
1191
+ const DESELECT_ALL = "__deselect_all__";
1192
+ const allNames = sorted.map((s) => s.name);
1193
+ const sessionOptions = sorted.map((s) => ({
1186
1194
  value: s.name,
1187
1195
  label: `${s.pinned ? "★ " : " "}${s.name}`,
1188
1196
  hint: `${s.cli} — ${s.cwd}${s.worktree && s.worktree.branch ? ` [wt ${s.worktree.branch}]` : ""}`,
1189
1197
  }));
1198
+ const options = [
1199
+ { value: SELECT_ALL, label: "✅ Select all", hint: "check every session" },
1200
+ {
1201
+ value: DESELECT_ALL,
1202
+ label: "⬜ Deselect all",
1203
+ hint: "uncheck every session",
1204
+ },
1205
+ ...sessionOptions,
1206
+ ];
1190
1207
  const anyPinned = sorted.some((s) => s.pinned === true);
1191
1208
  const initial = anyPinned
1192
1209
  ? sorted.filter((s) => s.pinned === true).map((s) => s.name)
@@ -1210,7 +1227,15 @@ async function maybeOfferAutoRestore(prefs) {
1210
1227
  process.exit(0);
1211
1228
  }
1212
1229
  /** @type {string[]} */
1213
- const chosen = Array.isArray(selection) ? selection : [];
1230
+ let chosen = Array.isArray(selection) ? selection : [];
1231
+ // Resolve the synthetic select-all / deselect-all toggles. If both
1232
+ // were checked, select-all wins (the safer "do more" interpretation);
1233
+ // either way, strip the synthetic entries from the final list.
1234
+ const wantSelectAll = chosen.includes(SELECT_ALL);
1235
+ const wantDeselectAll = chosen.includes(DESELECT_ALL);
1236
+ chosen = chosen.filter((v) => v !== SELECT_ALL && v !== DESELECT_ALL);
1237
+ if (wantSelectAll) chosen = [...allNames];
1238
+ else if (wantDeselectAll) chosen = [];
1214
1239
  if (chosen.length === 0) {
1215
1240
  prompts.outro(
1216
1241
  "Skipped. Run `agileflow launch restore` later to bring them back.",
@@ -19,6 +19,8 @@ const {
19
19
  sessionExists,
20
20
  createSession,
21
21
  applyKeybindPreset,
22
+ applyTabFormat,
23
+ detectTmuxVersion,
22
24
  } = require("./tmux.js");
23
25
  const { loadRegistry } = require("./session-registry.js");
24
26
  const { resolveAgileflowBin } = require("./alias-installer.js");
@@ -117,6 +119,14 @@ function runRestore(opts) {
117
119
  log(`agileflow launch: failed to restore ${entry.name} — ${stderr}`);
118
120
  continue;
119
121
  }
122
+ // Apply the same per-session styling launchInTmux does for fresh
123
+ // sessions so the tab strip looks consistent on restore. Without
124
+ // this, restored sessions show tmux's default green status bar
125
+ // instead of the AgileFlow dark strip.
126
+ runner.runSync(["set-option", "-t", entry.name, "status", "1"]);
127
+ applyTabFormat(entry.name, runner, {
128
+ tmuxVersion: detectTmuxVersion(runner),
129
+ });
120
130
  result.restored++;
121
131
  log(`agileflow launch: restored session ${entry.name} (${entry.cwd})`);
122
132
  }
@@ -273,17 +273,15 @@ const TAB_KEYBINDS = [
273
273
  hint: "Alt+, → rename current tab",
274
274
  },
275
275
  {
276
- // Direct close — no confirm-before. The earlier confirm-before
277
- // path was brittle under tmux's bind-key parsing (deferred-command
278
- // quoting issues caused the keybind to silently no-op on some
279
- // tmux builds). Alt+Shift+T (Alt+T) restores the last closed
280
- // tab in the same cwd, so the close is effectively reversible —
281
- // matches Chrome's instant-close + Ctrl+Shift+T undo.
276
+ // Direct kill-window — no CLI roundtrip. The previous
277
+ // run-shell-to-agileflow approach added Node-startup latency
278
+ // (150ms+) and could no-op silently if the binary path resolution
279
+ // returned stale state (e.g. after npx cache cleanup). Killing
280
+ // via tmux directly is instant and bulletproof. Undo is provided
281
+ // by Alt+Shift+T (which reads the closed-windows log populated by
282
+ // the window-unlinked hook installed in applyTabFormat).
282
283
  key: "M-w",
283
- action: [
284
- "run-shell",
285
- "%AGILEFLOW% launch __close-window #{session_name} #{window_index}",
286
- ],
284
+ action: ["kill-window"],
287
285
  hint: "Alt+w → close current tab (Alt+Shift+T to undo)",
288
286
  },
289
287
  {
@@ -223,11 +223,15 @@ function applyTabFormat(sessionName, runner, opts = {}) {
223
223
  const ACCENT = theme.activeBg;
224
224
  const FG = theme.activeNameFg;
225
225
 
226
- const inactiveFormat = ` #I#[fg=${ACCENT}]:#[fg=default]#W `;
226
+ // Active tab uses the BRAND ACCENT (orange) as its pill background
227
+ // with the strip's dark color as text — maximum contrast against
228
+ // the muted inactive tabs so the user always knows which tab is
229
+ // focused after Alt+1..9 / Alt+Tab.
230
+ const inactiveFormat = ` #I:#W `;
227
231
  const activeFormat =
228
- `#[fg=${PILL_BG},bg=${BG}]${HALF_ROUND_OPEN}` +
229
- `#[bg=${PILL_BG},fg=${FG},bold]#I#[fg=${ACCENT}]:#[fg=${FG},nobold]#W` +
230
- `#[fg=${PILL_BG},bg=${BG}]${HALF_ROUND_CLOSE}`;
232
+ `#[fg=${ACCENT},bg=${BG}]${HALF_ROUND_OPEN}` +
233
+ `#[bg=${ACCENT},fg=${theme.activeFg},bold] #I:#W ` +
234
+ `#[fg=${ACCENT},bg=${BG}]${HALF_ROUND_CLOSE}`;
231
235
  const statusLeft =
232
236
  `#[fg=${PILL_BG},bg=${BG}]${HALF_ROUND_OPEN}` +
233
237
  `#[bg=${PILL_BG},fg=${ACCENT}] #S ` +