aid-installer 1.1.1 → 2.0.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/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  # aid-installer
2
2
 
3
- Install [AID](https://github.com/AndreVianna/aid-methodology) (Agentic Iterative Development)
4
- into your repository. Current release: **v1.1.0**.
3
+ Install [AID](https://github.com/AndreVianna/aid-methodology) (AI Integrated Development)
4
+ into your repository. This package always installs the matching AID release.
5
5
 
6
6
  `npm i -g aid-installer` (or `npx aid-installer ...`) puts an `aid` command on your PATH.
7
7
  Then, inside a project:
package/VERSION CHANGED
@@ -1 +1 @@
1
- 1.1.1
1
+ 2.0.1
package/bin/aid CHANGED
@@ -13,7 +13,7 @@
13
13
  # aid version Print the CLI version
14
14
  # aid status Show AID state of the current project
15
15
  # aid add <tool>[,...] Add tool(s) to the current project
16
- # aid update [<tool>... | self] Update to latest; no arg = all tools; 'self' = the aid CLI
16
+ # aid update [self] Update to latest; inside repo = CLI + all tools; 'self' = CLI only
17
17
  # aid remove [<tool>... | self] Remove; no arg = ALL AID from project; 'self' = the aid CLI
18
18
  # aid projects [list|add|remove|help] [path] [--local|--shared] [--verbose]
19
19
  # List, register, or unregister AID projects
@@ -95,6 +95,10 @@ _aid_is_project_dir() {
95
95
  # C1: Per-repo format stamp constant.
96
96
  # The current .aid/ layout version. Bumped ONLY on a breaking layout change,
97
97
  # never on every CLI release. Defined exactly once; all comparisons read this.
98
+ # NOTE (work-007 C6): the install-time settings seed also stamps this value.
99
+ # On a bump, update ALL carriers together: this line, bin/aid.ps1
100
+ # AidSupportedFormat, and lib/AidInstallCore.psm1 $script:_AidSupportedFormat.
101
+ # (lib/aid-install-core.sh reads THIS var via ${AID_SUPPORTED_FORMAT:-1}.)
98
102
  # ---------------------------------------------------------------------------
99
103
  readonly AID_SUPPORTED_FORMAT=1
100
104
 
@@ -144,15 +148,19 @@ _aid_usage() {
144
148
  printf ' --dry-run: print the exact command(s) it would run, then exit (no changes).\n'
145
149
  ;;
146
150
  update)
147
- printf 'aid update [<tool>...] [--version <v>] [--from-bundle <path>] [--force] [--target <dir>]\n'
151
+ printf 'aid update [--version <v>] [--from-bundle <path>] [--force] [--dry-run] [--target <dir>]\n'
148
152
  printf 'aid update self [--from-bundle <path>] [--dry-run]\n'
149
- printf ' Update to latest. No args: update all installed tools.\n'
153
+ printf ' Update to latest.\n'
154
+ printf ' Outside an AID repo: updates the CLI only (no-op if already latest).\n'
155
+ printf ' Inside an AID repo: updates the CLI first, then ALL installed tools to one version.\n'
156
+ printf ' No per-tool selection -- any tool positional is an error (use "self" only).\n'
150
157
  printf ' self: COMPLETELY update the aid CLI, channel-aware:\n'
151
158
  printf ' npm -> npm i -g | pypi -> pipx upgrade | curl -> re-bootstrap install.sh.\n'
152
159
  printf ' Auto-elevates with sudo only when the install location needs root.\n'
153
- printf ' --from-bundle <path>: install the CLI from a local artifact instead of @latest\n'
160
+ printf ' --version <v>: pin ALL tools (and CLI) to version v.\n'
161
+ printf ' --from-bundle <path>: install from a local artifact instead of @latest\n'
154
162
  printf ' (npm .tgz | pypi .whl | curl release-staging dir with install.sh).\n'
155
- printf ' --dry-run: print the exact command(s) it would run, then exit (no changes).\n'
163
+ printf ' --dry-run: print the full plan (tools updated, files copied, paths pruned) and exit.\n'
156
164
  ;;
157
165
  version)
158
166
  printf 'aid version\n'
@@ -194,7 +202,7 @@ _aid_usage() {
194
202
  printf ' aid version Print the CLI version\n'
195
203
  printf ' aid status Show AID state of the current project\n'
196
204
  printf ' aid add <tool>[,...] Add tool(s) to the current project\n'
197
- printf ' aid update [<tool>... | self] Update to latest; no arg = all tools\n'
205
+ printf ' aid update [self] Update to latest; inside repo = all tools\n'
198
206
  printf ' aid remove [<tool>... | self] Remove; no arg = ALL AID from project\n'
199
207
  printf ' aid dashboard start|stop ... Start/stop the local dashboard\n'
200
208
  printf ' aid projects [list|add|remove] List/register/unregister AID projects\n'
@@ -2579,7 +2587,7 @@ _cmd_dashboard() {
2579
2587
  if [[ -f "$ver_file" ]]; then
2580
2588
  cli_version="$(tr -d '[:space:]' < "$ver_file")"
2581
2589
  fi
2582
- printf 'AID v%s - Agentic Iterative Development\n' "$cli_version"
2590
+ printf 'AID v%s - AI Integrated Development\n' "$cli_version"
2583
2591
  printf 'Install, update, and manage AID across your projects.\n'
2584
2592
 
2585
2593
  # C6: format gate for cwd repo (.aid/ is guaranteed present here -- the
@@ -2855,6 +2863,7 @@ esac
2855
2863
  # Collect positional tool args (comma-separated or space-separated before flags).
2856
2864
  _AID_POSITIONAL_TOOLS=""
2857
2865
  _AID_REMOVE_FORCE=0
2866
+ _AID_DRY_RUN=0
2858
2867
 
2859
2868
  while [[ $# -gt 0 ]]; do
2860
2869
  case "$1" in
@@ -2870,6 +2879,7 @@ while [[ $# -gt 0 ]]; do
2870
2879
  [[ $# -lt 2 ]] && _aid_die "--target requires a value" 2
2871
2880
  _AID_TARGET="$2"; shift 2 ;;
2872
2881
  --no-path) _AID_NO_PATH=1; shift ;;
2882
+ --dry-run) _AID_DRY_RUN=1; shift ;;
2873
2883
  -h|--help) _aid_usage "$SUBCMD"; exit 0 ;;
2874
2884
  -*) _aid_die "unknown flag: $1" 2 ;;
2875
2885
  *)
@@ -2895,6 +2905,16 @@ if [[ "$_AID_FORCE" -eq 0 && ( "${AID_FORCE:-0}" == "1" || "${AID_FORCE:-0}" ==
2895
2905
  fi
2896
2906
  export AID_VERBOSE="$_AID_VERBOSE"
2897
2907
 
2908
+ # FR10: 'update' no longer accepts a per-tool positional (other than 'self' which
2909
+ # was already consumed above). Any non-flag positional on 'aid update' is a usage error.
2910
+ if [[ "$SUBCMD" == "update" && -n "$_AID_TOOL_ARG" ]]; then
2911
+ echo "ERROR: aid update: unexpected argument: '${_AID_TOOL_ARG}'" >&2
2912
+ echo " 'aid update' updates all installed tools -- no per-tool selection." >&2
2913
+ echo " Use 'aid update self' to update the CLI only." >&2
2914
+ echo " See 'aid update -h' for usage." >&2
2915
+ exit 2
2916
+ fi
2917
+
2898
2918
  _AID_TARGET="${_AID_TARGET:-.}"
2899
2919
  # Validate target dir.
2900
2920
  if [[ ! -d "$_AID_TARGET" ]]; then
@@ -2902,20 +2922,32 @@ if [[ ! -d "$_AID_TARGET" ]]; then
2902
2922
  fi
2903
2923
  _AID_TARGET="$(cd "$_AID_TARGET" && pwd)"
2904
2924
 
2905
- # ---- C-table pre-check for 'update [tool]': missing .aid/ -> offer + exit 0 ----
2906
- # Must run BEFORE _resolve_tools_for_aid so we never reach exit-6 when no .aid/ exists.
2907
- # 'add' uses the B-table (checked inside the dispatch case); 'remove' is not in C-table.
2925
+ # ---- FR10: 'update' outside an AID repo -> update the CLI only (not offer-and-exit) ----
2926
+ # Outside a repo: delegates to the CLI-only update path; no tool loop.
2927
+ # Inside a repo: fall through to the full tool-update pass below.
2908
2928
  # _aid_is_project_dir excludes the CLI state home from the "is project" classification.
2909
2929
  if [[ "$SUBCMD" == "update" ]]; then
2910
2930
  if ! _aid_is_project_dir "${_AID_TARGET}"; then
2911
- _aid_cwd_no_aid_offer "${_AID_TARGET}"
2912
- # _aid_cwd_no_aid_offer always exits 0.
2931
+ # FR10 outside-repo: update the CLI only; no tool loop.
2932
+ # For a dry-run preview of the CLI self-update, use 'aid update self --dry-run'.
2933
+ _UPD_CLI_VER=""
2934
+ [[ -f "${AID_CODE_HOME}/VERSION" ]] && _UPD_CLI_VER="$(tr -d '[:space:]' < "${AID_CODE_HOME}/VERSION")"
2935
+ # Check if already latest using cached update-check result (no network call).
2936
+ _UPD_CACHE_FILE="${HOME}/.aid/.update-check"
2937
+ _UPD_CACHED_LATEST=""
2938
+ [[ -f "${_UPD_CACHE_FILE}" ]] && _UPD_CACHED_LATEST="$(awk 'NR==2{print $1}' "${_UPD_CACHE_FILE}" 2>/dev/null)" || true
2939
+ if [[ -n "$_UPD_CLI_VER" && -n "$_UPD_CACHED_LATEST" && "$_UPD_CLI_VER" == "$_UPD_CACHED_LATEST" ]]; then
2940
+ echo "CLI is current (v${_UPD_CLI_VER})"
2941
+ exit 0
2942
+ fi
2943
+ _aid_update_self_if_stale
2944
+ exit 0
2913
2945
  fi
2914
2946
  fi
2915
2947
 
2916
2948
  # ---- Self-update-if-needed preamble (FF-3 / CLI-2 / task-079) --------------
2917
- # For 'update [<tool>]' only (not 'add', not 'update self'). Ensures the CLI
2918
- # is current before the per-repo migration runs (FR38 / OQ-6). WARN-not-fail.
2949
+ # For 'update' inside an AID repo only (not 'add', not 'update self').
2950
+ # Ensures the CLI is current before the per-repo tool-update runs. WARN-not-fail.
2919
2951
  if [[ "$SUBCMD" == "update" ]]; then
2920
2952
  _aid_update_self_if_stale
2921
2953
  fi
@@ -3118,7 +3150,53 @@ case "$SUBCMD" in
3118
3150
  fi
3119
3151
  fi
3120
3152
 
3121
- # C-table (for 'update [tool]'): register-on-encounter + format gate.
3153
+ # ---------------------------------------------------------------------------
3154
+ # FR11: aid add version selection (same-version invariant).
3155
+ # First-tool (no existing tools in manifest): install at the CLI version.
3156
+ # Additional-tool (manifest already has >=1 tool): install at the EXISTING
3157
+ # tools' version to keep the repo uniform. add does NOT force a repo-wide
3158
+ # update. --version on add must apply to ALL tools or error (mixed-version
3159
+ # repo would result if the requested version differs from the existing one).
3160
+ # ---------------------------------------------------------------------------
3161
+ if [[ "$SUBCMD" == "add" ]]; then
3162
+ _FR11_CLI_VER=""
3163
+ [[ -f "${AID_CODE_HOME}/VERSION" ]] && \
3164
+ _FR11_CLI_VER="$(tr -d '[:space:]' < "${AID_CODE_HOME}/VERSION")"
3165
+ _FR11_EXISTING_VER=""
3166
+ if [[ -f "$_AID_MANIFEST" ]]; then
3167
+ _FR11_FIRST_TOOL="$(manifest_list_tools "$_AID_MANIFEST" | head -1)"
3168
+ if [[ -n "$_FR11_FIRST_TOOL" ]]; then
3169
+ _FR11_EXISTING_VER="$(manifest_read_tool_version "$_AID_MANIFEST" "$_FR11_FIRST_TOOL")"
3170
+ fi
3171
+ fi
3172
+
3173
+ if [[ -n "$_AID_VERSION_ARG" ]]; then
3174
+ # --version on add: validate it won't create a mixed-version repo.
3175
+ if [[ -n "$_FR11_EXISTING_VER" && "$_AID_VERSION_ARG" != "$_FR11_EXISTING_VER" ]]; then
3176
+ echo "ERROR: aid add: --version ${_AID_VERSION_ARG} would create a mixed-version repo." >&2
3177
+ echo " Existing tools are at v${_FR11_EXISTING_VER}. Either:" >&2
3178
+ echo " - Omit --version to install at the repo version (v${_FR11_EXISTING_VER}), or" >&2
3179
+ echo " - Run 'aid update --version ${_AID_VERSION_ARG}' first to advance the whole repo." >&2
3180
+ rm -rf "$_AID_STAGING_BASE"
3181
+ exit 2
3182
+ fi
3183
+ # --version provided and no conflict: apply to all tools (passed through to staging).
3184
+ elif [[ -n "$_FR11_EXISTING_VER" ]]; then
3185
+ # Additional-tool: pin staging to the existing repo version (not the CLI version).
3186
+ _AID_VERSION_ARG="$_FR11_EXISTING_VER"
3187
+ # Skew notice when CLI is ahead of the repo version.
3188
+ if [[ -n "$_FR11_CLI_VER" ]] && _semver_lt "$_FR11_EXISTING_VER" "$_FR11_CLI_VER"; then
3189
+ echo "repo is at v${_FR11_EXISTING_VER}; new tool(s) installed at v${_FR11_EXISTING_VER} to keep the repo uniform. Run 'aid update' to advance all tools to v${_FR11_CLI_VER}."
3190
+ fi
3191
+ else
3192
+ # First-tool: pin to CLI version (bundle supplies its own version; skip if so).
3193
+ if [[ -z "$_AID_FROM_BUNDLE" && -n "$_FR11_CLI_VER" ]]; then
3194
+ _AID_VERSION_ARG="$_FR11_CLI_VER"
3195
+ fi
3196
+ fi
3197
+ fi
3198
+
3199
+ # C-table (for 'update'): register-on-encounter + format gate.
3122
3200
  # The missing-.aid/ case was already intercepted above (pre-resolve-tools).
3123
3201
  if [[ "$SUBCMD" == "update" ]]; then
3124
3202
  # C-table register-on-encounter (best-effort).
@@ -3127,15 +3205,75 @@ case "$SUBCMD" in
3127
3205
  _aid_format_gate "${_AID_TARGET}" || exit $?
3128
3206
  fi
3129
3207
 
3208
+ # ---------------------------------------------------------------------------
3209
+ # FR10 Stage-all-first atomicity (task-009):
3210
+ # PHASE 1: Stage ALL tools (resolve version, fetch, checksum-verify, extract
3211
+ # to temp) BEFORE any destination write. A failure here aborts with
3212
+ # zero destination mutation.
3213
+ # ---------------------------------------------------------------------------
3214
+ declare -A _STAGE_MAP=() # tool -> staging_dir
3215
+ _STAGE_VERSION="" # single resolved version for all tools
3216
+
3130
3217
  for _tool in "${_AID_TOOLS[@]}"; do
3131
- echo ""
3132
3218
  _prepare_tool_staging_aid "$_tool" "$_AID_VERSION_ARG" "$_AID_FROM_BUNDLE"
3133
- echo "Installing ${_tool} v${_AID_RESOLVED_VERSION} -> ${_AID_TARGET}"
3134
- install_tool "$_AID_STAGING_DIR" "$_tool" "$_AID_TARGET" "$_AID_RESOLVED_VERSION" "$_AID_FORCE" || exit $?
3219
+ _STAGE_MAP["$_tool"]="$_AID_STAGING_DIR"
3220
+ # All tools must be at the same version (the first resolved wins, the rest
3221
+ # confirm by the same --version / bundle arg).
3222
+ if [[ -z "$_STAGE_VERSION" ]]; then
3223
+ _STAGE_VERSION="$_AID_RESOLVED_VERSION"
3224
+ fi
3225
+ done
3226
+
3227
+ # ---------------------------------------------------------------------------
3228
+ # FR10 --dry-run: print the plan and exit with no writes.
3229
+ # ---------------------------------------------------------------------------
3230
+ if [[ "${_AID_DRY_RUN:-0}" -eq 1 ]]; then
3231
+ echo "--- aid ${SUBCMD} --dry-run plan (no writes) ---"
3232
+ echo "Target: ${_AID_TARGET}"
3233
+ echo "Version: ${_STAGE_VERSION:-<current>}"
3234
+ for _tool in "${_AID_TOOLS[@]}"; do
3235
+ echo ""
3236
+ echo "Tool: ${_tool}"
3237
+ _dry_staging="${_STAGE_MAP[$_tool]}"
3238
+ # List files that would be copied.
3239
+ while IFS= read -r -d '' _dry_f; do
3240
+ echo " copy: ${_dry_f#${_dry_staging}/} -> ${_AID_TARGET}"
3241
+ done < <(find "${_dry_staging}" -type f -print0 2>/dev/null | sort -z)
3242
+ # List files that would be MOVED TO TRASH by the retired-root migration sweep
3243
+ # (marker 1: aid-* prefix; marker 2: inside an aid/ subtree).
3244
+ # Uses list_only=1 mode of _migrate_retired_layout (no writes).
3245
+ _dry_removed_out="$(_migrate_retired_layout "${_AID_TARGET}" "${_tool}" 1 2>/dev/null)"
3246
+ if [[ -n "$_dry_removed_out" ]]; then
3247
+ echo " Would MOVE TO TRASH (retired-layout migration):"
3248
+ printf '%s\n' "$_dry_removed_out"
3249
+ fi
3250
+ done
3251
+ echo ""
3252
+ echo "--- end dry-run plan ---"
3253
+ rm -rf "$_AID_STAGING_BASE"
3254
+ exit 0
3255
+ fi
3256
+
3257
+ # ---------------------------------------------------------------------------
3258
+ # PHASE 2: Commit all staged tools.
3259
+ # If any commit fails, exit non-zero with a re-run-to-heal message.
3260
+ # aid update is idempotent: re-running drives every tool to the target version.
3261
+ # ---------------------------------------------------------------------------
3262
+ for _tool in "${_AID_TOOLS[@]}"; do
3263
+ echo ""
3264
+ echo "Installing ${_tool} v${_STAGE_VERSION} -> ${_AID_TARGET}"
3265
+ install_tool "${_STAGE_MAP[$_tool]}" "$_tool" "$_AID_TARGET" "$_STAGE_VERSION" "$_AID_FORCE" || {
3266
+ _COMMIT_RC=$?
3267
+ echo "" >&2
3268
+ echo "ERROR: aid ${SUBCMD} failed mid-commit for tool '${_tool}' (rc=${_COMMIT_RC})." >&2
3269
+ echo " The repo may be at mixed versions. Re-run 'aid update' to heal." >&2
3270
+ rm -rf "$_AID_STAGING_BASE"
3271
+ exit "${_COMMIT_RC}"
3272
+ }
3135
3273
  done
3136
3274
 
3137
3275
  echo ""
3138
- echo "Done. AID ${_AID_RESOLVED_VERSION:-} installed into: ${_AID_TARGET}"
3276
+ echo "Done. AID ${_STAGE_VERSION:-} installed into: ${_AID_TARGET}"
3139
3277
 
3140
3278
  # B-table (for 'add'): tier-aware registration after successful install.
3141
3279
  # Decision #3 (unwritable) already handled above with error+abort.
@@ -3145,7 +3283,7 @@ case "$SUBCMD" in
3145
3283
  _btab_tier="$(_aid_resolve_tier "$_AID_TARGET")"
3146
3284
  registry_register "$_AID_TARGET" "$_btab_tier"
3147
3285
  else
3148
- # 'update [tool]': C-table register-on-encounter already ran above.
3286
+ # 'update': C-table register-on-encounter already ran above.
3149
3287
  # The post-install register is idempotent; route via user tier.
3150
3288
  registry_register "$_AID_TARGET" "user"
3151
3289
  fi