deepflow 0.1.55 → 0.1.57

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.
@@ -28,11 +28,30 @@ INTERRUPTED=false
28
28
  # restarted with --resume to get a fresh context window.
29
29
  CONTEXT_THRESHOLD_PCT=50
30
30
 
31
- # Associative array for per-spec status tracking
32
- # Values: "converged", "halted", "in-progress"
33
- declare -A SPEC_STATUS
34
- # Associative array for per-spec winner slugs
35
- declare -A SPEC_WINNER
31
+ # Per-spec status/winner tracking (bash 3.2 compatible, no associative arrays)
32
+ # Uses a temp directory with one file per key.
33
+ _SPEC_MAP_DIR=""
34
+ _spec_map_init() {
35
+ if [[ -z "$_SPEC_MAP_DIR" ]]; then
36
+ _SPEC_MAP_DIR="$(mktemp -d "${TMPDIR:-/tmp}/deepflow-spec-map.XXXXXX")"
37
+ fi
38
+ }
39
+ _spec_set() { # usage: _spec_set STATUS myspec converged
40
+ _spec_map_init
41
+ printf '%s' "$3" > "${_SPEC_MAP_DIR}/${1}__${2}"
42
+ }
43
+ _spec_get() { # usage: _spec_get STATUS myspec [default]
44
+ _spec_map_init
45
+ local f="${_SPEC_MAP_DIR}/${1}__${2}"
46
+ if [[ -f "$f" ]]; then cat "$f"; else printf '%s' "${3:-}"; fi
47
+ }
48
+ _spec_isset() { # usage: _spec_isset STATUS myspec
49
+ _spec_map_init
50
+ [[ -f "${_SPEC_MAP_DIR}/${1}__${2}" ]]
51
+ }
52
+ _spec_map_cleanup() {
53
+ [[ -n "$_SPEC_MAP_DIR" && -d "$_SPEC_MAP_DIR" ]] && rm -rf "$_SPEC_MAP_DIR"
54
+ }
36
55
 
37
56
  # ---------------------------------------------------------------------------
38
57
  # Logging
@@ -1050,18 +1069,18 @@ generate_report() {
1050
1069
  all_spec_names+=("$sname")
1051
1070
 
1052
1071
  # If status was not set by the main loop, determine it now
1053
- if [[ -z "${SPEC_STATUS[$sname]+x}" ]]; then
1072
+ if ! _spec_isset STATUS "$sname"; then
1054
1073
  # Check if winner file exists
1055
1074
  if [[ -f "${PROJECT_ROOT}/.deepflow/selection/${sname}-winner.json" ]]; then
1056
- SPEC_STATUS[$sname]="converged"
1075
+ _spec_set STATUS "$sname" "converged"
1057
1076
  # Extract winner slug
1058
1077
  local w_slug
1059
1078
  w_slug="$(grep -o '"winner"[[:space:]]*:[[:space:]]*"[^"]*"' "${PROJECT_ROOT}/.deepflow/selection/${sname}-winner.json" | sed 's/.*"winner"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/')" || w_slug=""
1060
- SPEC_WINNER[$sname]="$w_slug"
1079
+ _spec_set WINNER "$sname" "$w_slug"
1061
1080
  elif [[ "$INTERRUPTED" == "true" ]]; then
1062
- SPEC_STATUS[$sname]="in-progress"
1081
+ _spec_set STATUS "$sname" "in-progress"
1063
1082
  else
1064
- SPEC_STATUS[$sname]="halted"
1083
+ _spec_set STATUS "$sname" "halted"
1065
1084
  fi
1066
1085
  fi
1067
1086
  done
@@ -1070,15 +1089,15 @@ generate_report() {
1070
1089
  # If interrupted, override any unfinished specs
1071
1090
  if [[ "$INTERRUPTED" == "true" ]]; then
1072
1091
  for sname in "${all_spec_names[@]}"; do
1073
- if [[ "${SPEC_STATUS[$sname]}" != "converged" ]]; then
1074
- SPEC_STATUS[$sname]="in-progress"
1092
+ if [[ "$(_spec_get STATUS "$sname")" != "converged" ]]; then
1093
+ _spec_set STATUS "$sname" "in-progress"
1075
1094
  fi
1076
1095
  done
1077
1096
  overall_status="in-progress"
1078
1097
  else
1079
1098
  # Determine overall status from per-spec statuses
1080
1099
  for sname in "${all_spec_names[@]}"; do
1081
- local s="${SPEC_STATUS[$sname]}"
1100
+ local s="$(_spec_get STATUS "$sname")"
1082
1101
  if [[ "$s" == "halted" ]]; then
1083
1102
  overall_status="halted"
1084
1103
  elif [[ "$s" == "in-progress" ]]; then
@@ -1100,7 +1119,7 @@ generate_report() {
1100
1119
  # Winner info (if converged)
1101
1120
  if [[ "$overall_status" == "converged" ]]; then
1102
1121
  for sname in "${all_spec_names[@]}"; do
1103
- local w="${SPEC_WINNER[$sname]:-}"
1122
+ local w="$(_spec_get WINNER "$sname")"
1104
1123
  if [[ -n "$w" ]]; then
1105
1124
  local summary=""
1106
1125
  local winner_file="${PROJECT_ROOT}/.deepflow/selection/${sname}-winner.json"
@@ -1117,8 +1136,8 @@ generate_report() {
1117
1136
  echo "| Spec | Status | Winner |"
1118
1137
  echo "|------|--------|--------|"
1119
1138
  for sname in "${all_spec_names[@]}"; do
1120
- local s="${SPEC_STATUS[$sname]:-unknown}"
1121
- local w="${SPEC_WINNER[$sname]:--}"
1139
+ local s="$(_spec_get STATUS "$sname" "unknown")"
1140
+ local w="$(_spec_get WINNER "$sname" "-")"
1122
1141
  echo "| ${sname} | ${s} | ${w} |"
1123
1142
  done
1124
1143
  echo ""
@@ -1129,7 +1148,7 @@ generate_report() {
1129
1148
 
1130
1149
  local has_changes=false
1131
1150
  for sname in "${all_spec_names[@]}"; do
1132
- local w="${SPEC_WINNER[$sname]:-}"
1151
+ local w="$(_spec_get WINNER "$sname")"
1133
1152
  if [[ -n "$w" ]]; then
1134
1153
  has_changes=true
1135
1154
  local branch_name="df/${sname}-${w}"
@@ -1196,10 +1215,10 @@ run_spec_cycle() {
1196
1215
  auto_log "Selection accepted for ${spec_file} at cycle ${cycle}"
1197
1216
  echo "Selection accepted for $(basename "$spec_file") at cycle ${cycle}"
1198
1217
  # Track convergence
1199
- SPEC_STATUS[$spec_name]="converged"
1218
+ _spec_set STATUS "$spec_name" "converged"
1200
1219
  local w_slug
1201
1220
  w_slug="$(grep -o '"winner"[[:space:]]*:[[:space:]]*"[^"]*"' "${PROJECT_ROOT}/.deepflow/selection/${spec_name}-winner.json" | sed 's/.*"winner"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/')" || w_slug=""
1202
- SPEC_WINNER[$spec_name]="$w_slug"
1221
+ _spec_set WINNER "$spec_name" "$w_slug"
1203
1222
  break
1204
1223
  fi
1205
1224
 
@@ -1208,8 +1227,8 @@ run_spec_cycle() {
1208
1227
  done
1209
1228
 
1210
1229
  # If we exited the loop without converging, mark as halted
1211
- if [[ "${SPEC_STATUS[$spec_name]:-}" != "converged" ]]; then
1212
- SPEC_STATUS[$spec_name]="halted"
1230
+ if [[ "$(_spec_get STATUS "$spec_name")" != "converged" ]]; then
1231
+ _spec_set STATUS "$spec_name" "halted"
1213
1232
  fi
1214
1233
  }
1215
1234
 
@@ -1282,6 +1301,7 @@ handle_signal() {
1282
1301
  }
1283
1302
 
1284
1303
  trap handle_signal SIGINT SIGTERM
1304
+ trap _spec_map_cleanup EXIT
1285
1305
 
1286
1306
  # Safety assertions: this script must never modify spec files or push to remotes.
1287
1307
  # These constraints are enforced by design — no write/push commands exist in this script.
package/bin/install.js CHANGED
@@ -35,6 +35,23 @@ const GLOBAL_DIR = path.join(os.homedir(), '.claude');
35
35
  const PROJECT_DIR = path.join(process.cwd(), '.claude');
36
36
  const PACKAGE_DIR = path.resolve(__dirname, '..');
37
37
 
38
+ function updateGlobalPackage() {
39
+ const currentVersion = require(path.join(PACKAGE_DIR, 'package.json')).version;
40
+ try {
41
+ const globalPkgPath = execFileSync('node', ['-e',
42
+ "try{console.log(require(require('path').join(require('child_process').execFileSync('npm',['root','-g'],{encoding:'utf8'}).trim(),'deepflow','package.json')).version)}catch(e){console.log('')}"
43
+ ], { encoding: 'utf8' }).trim();
44
+
45
+ if (globalPkgPath && globalPkgPath !== currentVersion) {
46
+ console.log(`Updating global npm package (${globalPkgPath} → ${currentVersion})...`);
47
+ execFileSync('npm', ['install', '-g', `deepflow@${currentVersion}`], { stdio: 'inherit' });
48
+ console.log('');
49
+ }
50
+ } catch (e) {
51
+ // No global installation or npm not available - skip silently
52
+ }
53
+ }
54
+
38
55
  async function main() {
39
56
  // Handle --uninstall flag
40
57
  if (process.argv.includes('--uninstall')) {
@@ -45,6 +62,9 @@ async function main() {
45
62
  console.log(`${c.cyan}deepflow installer${c.reset}`);
46
63
  console.log('');
47
64
 
65
+ // Update global npm package if stale
66
+ updateGlobalPackage();
67
+
48
68
  // Detect existing installations
49
69
  const globalInstalled = isInstalled(GLOBAL_DIR);
50
70
  const projectInstalled = isInstalled(PROJECT_DIR);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "deepflow",
3
- "version": "0.1.55",
3
+ "version": "0.1.57",
4
4
  "description": "Stay in flow state - lightweight spec-driven task orchestration for Claude Code",
5
5
  "keywords": [
6
6
  "claude",