gaia-framework 1.52.0 → 1.53.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/README.md CHANGED
@@ -460,7 +460,7 @@ The single source of truth is `_gaia/_config/global.yaml`:
460
460
 
461
461
  ```yaml
462
462
  framework_name: "GAIA"
463
- framework_version: "1.52.0"
463
+ framework_version: "1.53.0"
464
464
  user_name: "your-name"
465
465
  project_name: "your-project"
466
466
  ```
@@ -5,10 +5,10 @@
5
5
  // Clones the GAIA repo, delegates to gaia-install.sh, and cleans up.
6
6
  // ─────────────────────────────────────────────────────────────────────────────
7
7
 
8
- const { execSync, execFileSync } = require("child_process");
9
- const { mkdtempSync, rmSync, existsSync } = require("fs");
10
- const { join } = require("path");
11
- const { tmpdir } = require("os");
8
+ const childProcess = require("child_process");
9
+ const fs = require("fs");
10
+ const path = require("path");
11
+ const os = require("os");
12
12
 
13
13
  const REPO_URL = "https://github.com/jlouage/Gaia-framework.git";
14
14
  const SCRIPT_NAME = "gaia-install.sh";
@@ -23,19 +23,19 @@ function findBash() {
23
23
 
24
24
  // Try bash in PATH first (WSL, Git Bash in PATH, etc.)
25
25
  try {
26
- execSync("bash --version", { stdio: "ignore" });
26
+ childProcess.execSync("bash --version", { stdio: "ignore" });
27
27
  return "bash";
28
28
  } catch {}
29
29
 
30
30
  // Try Git for Windows default locations
31
31
  const gitBashPaths = [
32
- join(process.env.ProgramFiles || "C:\\Program Files", "Git", "bin", "bash.exe"),
33
- join(process.env["ProgramFiles(x86)"] || "C:\\Program Files (x86)", "Git", "bin", "bash.exe"),
34
- join(process.env.LOCALAPPDATA || "", "Programs", "Git", "bin", "bash.exe"),
32
+ path.join(process.env.ProgramFiles || "C:\\Program Files", "Git", "bin", "bash.exe"),
33
+ path.join(process.env["ProgramFiles(x86)"] || "C:\\Program Files (x86)", "Git", "bin", "bash.exe"),
34
+ path.join(process.env.LOCALAPPDATA || "", "Programs", "Git", "bin", "bash.exe"),
35
35
  ];
36
36
 
37
37
  for (const p of gitBashPaths) {
38
- if (existsSync(p)) return p;
38
+ if (fs.existsSync(p)) return p;
39
39
  }
40
40
 
41
41
  return null;
@@ -51,9 +51,9 @@ function info(message) {
51
51
  }
52
52
 
53
53
  function cleanup() {
54
- if (tempDir && existsSync(tempDir)) {
54
+ if (tempDir && fs.existsSync(tempDir)) {
55
55
  try {
56
- rmSync(tempDir, { recursive: true, force: true });
56
+ fs.rmSync(tempDir, { recursive: true, force: true });
57
57
  } catch {
58
58
  // Best-effort cleanup
59
59
  }
@@ -62,7 +62,7 @@ function cleanup() {
62
62
 
63
63
  function ensureGit() {
64
64
  try {
65
- execSync("git --version", { stdio: "ignore" });
65
+ childProcess.execSync("git --version", { stdio: "ignore" });
66
66
  } catch {
67
67
  fail(
68
68
  "git is required but was not found.\n" +
@@ -72,8 +72,7 @@ function ensureGit() {
72
72
  }
73
73
 
74
74
  function readPackageVersion(pkgPath) {
75
- const { readFileSync } = require("fs");
76
- const raw = readFileSync(pkgPath, "utf8");
75
+ const raw = fs.readFileSync(pkgPath, "utf8");
77
76
  const pkg = JSON.parse(raw);
78
77
  if (!pkg.version) {
79
78
  throw new Error(`No version field found in ${pkgPath}`);
@@ -111,7 +110,15 @@ Examples:
111
110
 
112
111
  // ─── Main ───────────────────────────────────────────────────────────────────
113
112
 
114
- function main() {
113
+ function main(deps) {
114
+ // Dependency injection for testability — defaults to real modules
115
+ const _exec = deps && deps.execSync || childProcess.execSync;
116
+ const _execFile = deps && deps.execFileSync || childProcess.execFileSync;
117
+ const _mkdtemp = deps && deps.mkdtempSync || fs.mkdtempSync;
118
+ const _exists = deps && deps.existsSync || fs.existsSync;
119
+ const _join = deps && deps.join || path.join;
120
+ const _tmpdir = deps && deps.tmpdir || os.tmpdir;
121
+
115
122
  const args = process.argv.slice(2);
116
123
 
117
124
  // Handle help / no args
@@ -137,7 +144,7 @@ function main() {
137
144
  ensureGit();
138
145
 
139
146
  // Clone the repo to a temp directory
140
- tempDir = mkdtempSync(join(tmpdir(), "gaia-framework-"));
147
+ tempDir = _mkdtemp(_join(_tmpdir(), "gaia-framework-"));
141
148
 
142
149
  // Register cleanup for all exit scenarios
143
150
  process.on("exit", cleanup);
@@ -147,7 +154,7 @@ function main() {
147
154
  info("Cloning GAIA framework from GitHub...");
148
155
 
149
156
  try {
150
- execSync(`git clone --depth 1 ${REPO_URL} "${tempDir}"`, {
157
+ _exec(`git clone --depth 1 ${REPO_URL} "${tempDir}"`, {
151
158
  stdio: ["ignore", "ignore", "pipe"],
152
159
  });
153
160
  } catch (err) {
@@ -158,8 +165,8 @@ function main() {
158
165
  }
159
166
 
160
167
  // Locate the installer script
161
- const scriptPath = join(tempDir, SCRIPT_NAME);
162
- if (!existsSync(scriptPath)) {
168
+ const scriptPath = _join(tempDir, SCRIPT_NAME);
169
+ if (!_exists(scriptPath)) {
163
170
  fail(`Installer script not found in cloned repo: ${SCRIPT_NAME}`);
164
171
  }
165
172
 
@@ -182,7 +189,7 @@ function main() {
182
189
  info("Running installer...\n");
183
190
 
184
191
  try {
185
- execFileSync(bashPath, [scriptPath, ...passthrough], {
192
+ _execFile(bashPath, [scriptPath, ...passthrough], {
186
193
  stdio: "inherit",
187
194
  env: { ...process.env, GAIA_SOURCE: tempDir },
188
195
  });
@@ -191,4 +198,8 @@ function main() {
191
198
  }
192
199
  }
193
200
 
194
- main();
201
+ if (require.main === module) {
202
+ main();
203
+ }
204
+
205
+ module.exports = { findBash, ensureGit, showUsage, fail, info, cleanup, readPackageVersion, main };
package/gaia-install.sh CHANGED
@@ -6,7 +6,7 @@ set -euo pipefail
6
6
  # Installs, updates, validates, and reports on GAIA installations.
7
7
  # ─────────────────────────────────────────────────────────────────────────────
8
8
 
9
- readonly VERSION="1.52.0"
9
+ readonly VERSION="1.53.0"
10
10
  readonly GITHUB_REPO="https://github.com/jlouage/Gaia-framework.git"
11
11
  readonly MANIFEST_REL="_gaia/_config/manifest.yaml"
12
12
 
@@ -182,77 +182,6 @@ copy_with_backup() {
182
182
  [[ "$OPT_VERBOSE" == true ]] && detail "Updated (backed up): $dst" || true
183
183
  }
184
184
 
185
- # Remove .resolved/*.yaml files from target _gaia/ directory.
186
- # Called after cp/tar copy to replicate rsync's --exclude behavior.
187
- # Only .resolved/*.yaml is relevant to the _gaia/ subtree; the other rsync
188
- # --exclude patterns target _memory/ paths outside _gaia/ and never match.
189
- clean_resolved_yaml() {
190
- local target_gaia="$1"
191
- find "$target_gaia" -path '*/.resolved/*.yaml' -delete 2>/dev/null || true
192
- }
193
-
194
- # Copy _gaia/ directory from source to target using a fallback chain:
195
- # rsync → cp -rp → tar
196
- # Tries each tool in order. If a tool is found but fails at runtime (e.g.,
197
- # broken rsync stub on Windows), falls through to the next tool. Exits with
198
- # a diagnostic error if all tools fail or none are available.
199
- #
200
- # Excludes .resolved/*.yaml files from the final output (rsync handles this
201
- # natively via --exclude; cp and tar do a post-copy cleanup).
202
- #
203
- # Note: No symlinks currently exist in _gaia/. If symlinks are introduced
204
- # in the future, verify that cp -rp behavior matches rsync -a on all
205
- # target platforms (ADR-004).
206
- copy_gaia_files() {
207
- local src="$1" dst="$2"
208
- local copy_done=false
209
-
210
- # Try rsync first (preferred — handles excludes natively)
211
- if command -v rsync >/dev/null 2>&1; then
212
- if rsync -a \
213
- --exclude='_memory/checkpoints/*.yaml' \
214
- --exclude='_memory/checkpoints/completed/*.yaml' \
215
- --exclude='.resolved/*.yaml' \
216
- --exclude='_memory/*-sidecar/*.md' \
217
- --exclude='_memory/*-sidecar/*.yaml' \
218
- "$src/_gaia/" "$dst/_gaia/" 2>/dev/null; then
219
- detail "Copied framework files using rsync"
220
- copy_done=true
221
- else
222
- detail "rsync found but failed — trying fallback methods"
223
- fi
224
- fi
225
-
226
- # Fallback: cp -rp (preserves permissions like rsync -a)
227
- if [[ "$copy_done" == false ]] && command -v cp >/dev/null 2>&1; then
228
- if cp -rp "$src/_gaia/" "$dst/_gaia/" 2>/dev/null; then
229
- clean_resolved_yaml "$dst/_gaia"
230
- detail "Copied framework files using cp -rp (rsync unavailable)"
231
- copy_done=true
232
- else
233
- error "cp failed to copy framework files — check permissions and disk space"
234
- exit 1
235
- fi
236
- fi
237
-
238
- # Fallback: tar (last resort — available on virtually all POSIX systems)
239
- if [[ "$copy_done" == false ]] && command -v tar >/dev/null 2>&1; then
240
- if (tar -cf - -C "$src" _gaia | tar -xf - -C "$dst") 2>/dev/null; then
241
- clean_resolved_yaml "$dst/_gaia"
242
- detail "Copied framework files using tar (rsync and cp unavailable)"
243
- copy_done=true
244
- else
245
- error "tar failed to copy framework files — check permissions and disk space"
246
- exit 1
247
- fi
248
- fi
249
-
250
- if [[ "$copy_done" == false ]]; then
251
- error "No suitable copy tool found (tried rsync, cp, tar). Cannot copy framework files."
252
- exit 1
253
- fi
254
- }
255
-
256
185
  append_if_missing() {
257
186
  local file="$1" marker="$2" content="$3"
258
187
  if [[ -f "$file" ]] && grep -qF "$marker" "$file"; then
@@ -332,22 +261,18 @@ cmd_init() {
332
261
  done
333
262
 
334
263
  # Step 2: Copy _gaia/ recursively (excluding checkpoints and .resolved/*.yaml)
335
- # Uses rsync if available, falls back to cp -rp, then tar (ADR-004: Windows best-effort)
336
264
  step "Copying framework files..."
337
265
  if [[ "$OPT_DRY_RUN" == true ]]; then
338
- if command -v rsync >/dev/null 2>&1; then
339
- detail "[dry-run] Would copy _gaia/ using rsync (excluding checkpoints and .resolved/*.yaml)"
340
- elif command -v cp >/dev/null 2>&1; then
341
- detail "[dry-run] Would copy _gaia/ using cp -rp (rsync unavailable)"
342
- elif command -v tar >/dev/null 2>&1; then
343
- detail "[dry-run] Would copy _gaia/ using tar (rsync and cp unavailable)"
344
- else
345
- error "No suitable copy tool found (tried rsync, cp, tar)"
346
- exit 1
347
- fi
266
+ detail "[dry-run] Would copy _gaia/ (excluding checkpoints and .resolved/*.yaml)"
348
267
  else
349
268
  mkdir -p "$TARGET/_gaia"
350
- copy_gaia_files "$source" "$TARGET"
269
+ rsync -a \
270
+ --exclude='_memory/checkpoints/*.yaml' \
271
+ --exclude='_memory/checkpoints/completed/*.yaml' \
272
+ --exclude='.resolved/*.yaml' \
273
+ --exclude='_memory/*-sidecar/*.md' \
274
+ --exclude='_memory/*-sidecar/*.yaml' \
275
+ "$source/_gaia/" "$TARGET/_gaia/"
351
276
  fi
352
277
 
353
278
  # Step 3: Create _memory/ directory tree at project root (ADR-013)
package/package.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "gaia-framework",
3
- "version": "1.52.0",
3
+ "version": "1.53.0",
4
4
  "description": "GAIA — Generative Agile Intelligence Architecture installer",
5
5
  "bin": {
6
6
  "gaia-framework": "./bin/gaia-framework.js"
7
7
  },
8
8
  "scripts": {
9
- "test": "vitest run",
9
+ "test": "vitest run --coverage",
10
10
  "test:watch": "vitest",
11
11
  "test:coverage": "vitest run --coverage",
12
12
  "test:unit": "vitest run test/unit",