gaia-framework 1.53.4 → 1.54.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 +2 -2
- package/bin/gaia-framework.js +24 -13
- package/gaia-install.sh +140 -20
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# GAIA — Generative Agile Intelligence Architecture
|
|
2
2
|
|
|
3
|
-
[]()
|
|
4
4
|
[]()
|
|
5
5
|
[]()
|
|
6
6
|
[]()
|
|
@@ -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.
|
|
463
|
+
framework_version: "1.54.1"
|
|
464
464
|
user_name: "your-name"
|
|
465
465
|
project_name: "your-project"
|
|
466
466
|
```
|
package/bin/gaia-framework.js
CHANGED
|
@@ -35,9 +35,9 @@ function findBash() {
|
|
|
35
35
|
|
|
36
36
|
// 1. Try Git for Windows FIRST (preferred — simpler path mapping)
|
|
37
37
|
const gitBashPaths = [
|
|
38
|
-
join(process.env.ProgramFiles || "C:\\Program Files", "Git", "bin", "bash.exe"),
|
|
39
|
-
join(process.env["ProgramFiles(x86)"] || "C:\\Program Files (x86)", "Git", "bin", "bash.exe"),
|
|
40
|
-
join(process.env.LOCALAPPDATA || "", "Programs", "Git", "bin", "bash.exe"),
|
|
38
|
+
path.join(process.env.ProgramFiles || "C:\\Program Files", "Git", "bin", "bash.exe"),
|
|
39
|
+
path.join(process.env["ProgramFiles(x86)"] || "C:\\Program Files (x86)", "Git", "bin", "bash.exe"),
|
|
40
|
+
path.join(process.env.LOCALAPPDATA || "", "Programs", "Git", "bin", "bash.exe"),
|
|
41
41
|
];
|
|
42
42
|
|
|
43
43
|
for (const p of gitBashPaths) {
|
|
@@ -83,9 +83,9 @@ function info(message) {
|
|
|
83
83
|
}
|
|
84
84
|
|
|
85
85
|
function cleanup() {
|
|
86
|
-
if (tempDir && existsSync(tempDir)) {
|
|
86
|
+
if (tempDir && fs.existsSync(tempDir)) {
|
|
87
87
|
try {
|
|
88
|
-
rmSync(tempDir, { recursive: true, force: true });
|
|
88
|
+
fs.rmSync(tempDir, { recursive: true, force: true });
|
|
89
89
|
} catch {
|
|
90
90
|
// Best-effort cleanup
|
|
91
91
|
}
|
|
@@ -94,7 +94,7 @@ function cleanup() {
|
|
|
94
94
|
|
|
95
95
|
function ensureGit() {
|
|
96
96
|
try {
|
|
97
|
-
execSync("git --version", { stdio: "ignore" });
|
|
97
|
+
childProcess.execSync("git --version", { stdio: "ignore" });
|
|
98
98
|
} catch {
|
|
99
99
|
fail(
|
|
100
100
|
"git is required but was not found.\n" +
|
|
@@ -104,8 +104,7 @@ function ensureGit() {
|
|
|
104
104
|
}
|
|
105
105
|
|
|
106
106
|
function readPackageVersion(pkgPath) {
|
|
107
|
-
const
|
|
108
|
-
const raw = readFileSync(pkgPath, "utf8");
|
|
107
|
+
const raw = fs.readFileSync(pkgPath, "utf8");
|
|
109
108
|
const pkg = JSON.parse(raw);
|
|
110
109
|
if (!pkg.version) {
|
|
111
110
|
throw new Error(`No version field found in ${pkgPath}`);
|
|
@@ -143,7 +142,15 @@ Examples:
|
|
|
143
142
|
|
|
144
143
|
// ─── Main ───────────────────────────────────────────────────────────────────
|
|
145
144
|
|
|
146
|
-
function main() {
|
|
145
|
+
function main(deps) {
|
|
146
|
+
// Dependency injection for testability — defaults to real modules
|
|
147
|
+
const _exec = deps && deps.execSync || childProcess.execSync;
|
|
148
|
+
const _execFile = deps && deps.execFileSync || childProcess.execFileSync;
|
|
149
|
+
const _mkdtemp = deps && deps.mkdtempSync || fs.mkdtempSync;
|
|
150
|
+
const _exists = deps && deps.existsSync || fs.existsSync;
|
|
151
|
+
const _join = deps && deps.join || path.join;
|
|
152
|
+
const _tmpdir = deps && deps.tmpdir || os.tmpdir;
|
|
153
|
+
|
|
147
154
|
const args = process.argv.slice(2);
|
|
148
155
|
|
|
149
156
|
// Handle help / no args
|
|
@@ -190,7 +197,7 @@ function main() {
|
|
|
190
197
|
info("Cloning GAIA framework from GitHub...");
|
|
191
198
|
|
|
192
199
|
try {
|
|
193
|
-
|
|
200
|
+
_exec(`git clone --depth 1 ${REPO_URL} "${tempDir}"`, {
|
|
194
201
|
stdio: ["ignore", "ignore", "pipe"],
|
|
195
202
|
});
|
|
196
203
|
} catch (err) {
|
|
@@ -201,8 +208,8 @@ function main() {
|
|
|
201
208
|
}
|
|
202
209
|
|
|
203
210
|
// Locate the installer script
|
|
204
|
-
const scriptPath =
|
|
205
|
-
if (!
|
|
211
|
+
const scriptPath = _join(tempDir, SCRIPT_NAME);
|
|
212
|
+
if (!_exists(scriptPath)) {
|
|
206
213
|
fail(`Installer script not found in cloned repo: ${SCRIPT_NAME}`);
|
|
207
214
|
}
|
|
208
215
|
|
|
@@ -246,4 +253,8 @@ function main() {
|
|
|
246
253
|
}
|
|
247
254
|
}
|
|
248
255
|
|
|
249
|
-
main
|
|
256
|
+
if (require.main === module) {
|
|
257
|
+
main();
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
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.
|
|
9
|
+
readonly VERSION="1.54.1"
|
|
10
10
|
readonly GITHUB_REPO="https://github.com/jlouage/Gaia-framework.git"
|
|
11
11
|
readonly MANIFEST_REL="_gaia/_config/manifest.yaml"
|
|
12
12
|
|
|
@@ -105,6 +105,11 @@ clone_from_github() {
|
|
|
105
105
|
echo "$TEMP_CLONE_DIR"
|
|
106
106
|
}
|
|
107
107
|
|
|
108
|
+
normalize_path() {
|
|
109
|
+
local p="${1//\\//}"
|
|
110
|
+
echo "$p"
|
|
111
|
+
}
|
|
112
|
+
|
|
108
113
|
resolve_source() {
|
|
109
114
|
local resolved=""
|
|
110
115
|
|
|
@@ -116,10 +121,14 @@ resolve_source() {
|
|
|
116
121
|
elif [[ -n "${GAIA_SOURCE:-}" ]]; then
|
|
117
122
|
resolved="$GAIA_SOURCE"
|
|
118
123
|
[[ "$OPT_VERBOSE" == true ]] && detail "Source from \$GAIA_SOURCE: $resolved" >&2
|
|
119
|
-
# 3. Self-detect: script's own directory
|
|
120
|
-
elif [[ -d "$(dirname "$(realpath "$0")")/_gaia" ]]; then
|
|
124
|
+
# 3. Self-detect: script's own directory (guard realpath for Git Bash compatibility)
|
|
125
|
+
elif command -v realpath &>/dev/null && [[ -d "$(dirname "$(realpath "$0")")/_gaia" ]]; then
|
|
121
126
|
resolved="$(dirname "$(realpath "$0")")"
|
|
122
127
|
[[ "$OPT_VERBOSE" == true ]] && detail "Source from script location: $resolved" >&2
|
|
128
|
+
# 3b. Fallback when realpath is unavailable (e.g., Git Bash without MSYS2 extras)
|
|
129
|
+
elif [[ -d "$(cd "$(dirname "$0")" && pwd)/_gaia" ]]; then
|
|
130
|
+
resolved="$(cd "$(dirname "$0")" && pwd)"
|
|
131
|
+
[[ "$OPT_VERBOSE" == true ]] && detail "Source from script location (cd fallback): $resolved" >&2
|
|
123
132
|
# 4. GitHub clone
|
|
124
133
|
else
|
|
125
134
|
resolved="$(clone_from_github)"
|
|
@@ -182,6 +191,77 @@ copy_with_backup() {
|
|
|
182
191
|
[[ "$OPT_VERBOSE" == true ]] && detail "Updated (backed up): $dst" || true
|
|
183
192
|
}
|
|
184
193
|
|
|
194
|
+
# Remove .resolved/*.yaml files from target _gaia/ directory.
|
|
195
|
+
# Called after cp/tar copy to replicate rsync's --exclude behavior.
|
|
196
|
+
# Only .resolved/*.yaml is relevant to the _gaia/ subtree; the other rsync
|
|
197
|
+
# --exclude patterns target _memory/ paths outside _gaia/ and never match.
|
|
198
|
+
clean_resolved_yaml() {
|
|
199
|
+
local target_gaia="$1"
|
|
200
|
+
find "$target_gaia" -path '*/.resolved/*.yaml' -delete 2>/dev/null || true
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
# Copy _gaia/ directory from source to target using a fallback chain:
|
|
204
|
+
# rsync → cp -rp → tar
|
|
205
|
+
# Tries each tool in order. If a tool is found but fails at runtime (e.g.,
|
|
206
|
+
# broken rsync stub on Windows), falls through to the next tool. Exits with
|
|
207
|
+
# a diagnostic error if all tools fail or none are available.
|
|
208
|
+
#
|
|
209
|
+
# Excludes .resolved/*.yaml files from the final output (rsync handles this
|
|
210
|
+
# natively via --exclude; cp and tar do a post-copy cleanup).
|
|
211
|
+
#
|
|
212
|
+
# Note: No symlinks currently exist in _gaia/. If symlinks are introduced
|
|
213
|
+
# in the future, verify that cp -rp behavior matches rsync -a on all
|
|
214
|
+
# target platforms (ADR-004).
|
|
215
|
+
copy_gaia_files() {
|
|
216
|
+
local src="$1" dst="$2"
|
|
217
|
+
local copy_done=false
|
|
218
|
+
|
|
219
|
+
# Try rsync first (preferred — handles excludes natively)
|
|
220
|
+
if command -v rsync >/dev/null 2>&1; then
|
|
221
|
+
if rsync -a \
|
|
222
|
+
--exclude='_memory/checkpoints/*.yaml' \
|
|
223
|
+
--exclude='_memory/checkpoints/completed/*.yaml' \
|
|
224
|
+
--exclude='.resolved/*.yaml' \
|
|
225
|
+
--exclude='_memory/*-sidecar/*.md' \
|
|
226
|
+
--exclude='_memory/*-sidecar/*.yaml' \
|
|
227
|
+
"$src/_gaia/" "$dst/_gaia/" 2>/dev/null; then
|
|
228
|
+
detail "Copied framework files using rsync"
|
|
229
|
+
copy_done=true
|
|
230
|
+
else
|
|
231
|
+
detail "rsync found but failed — trying fallback methods"
|
|
232
|
+
fi
|
|
233
|
+
fi
|
|
234
|
+
|
|
235
|
+
# Fallback: cp -rp (preserves permissions like rsync -a)
|
|
236
|
+
if [[ "$copy_done" == false ]] && command -v cp >/dev/null 2>&1; then
|
|
237
|
+
if cp -rp "$src/_gaia/" "$dst/_gaia/" 2>/dev/null; then
|
|
238
|
+
clean_resolved_yaml "$dst/_gaia"
|
|
239
|
+
detail "Copied framework files using cp -rp (rsync unavailable)"
|
|
240
|
+
copy_done=true
|
|
241
|
+
else
|
|
242
|
+
error "cp failed to copy framework files — check permissions and disk space"
|
|
243
|
+
exit 1
|
|
244
|
+
fi
|
|
245
|
+
fi
|
|
246
|
+
|
|
247
|
+
# Fallback: tar (last resort — available on virtually all POSIX systems)
|
|
248
|
+
if [[ "$copy_done" == false ]] && command -v tar >/dev/null 2>&1; then
|
|
249
|
+
if (tar -cf - -C "$src" _gaia | tar -xf - -C "$dst") 2>/dev/null; then
|
|
250
|
+
clean_resolved_yaml "$dst/_gaia"
|
|
251
|
+
detail "Copied framework files using tar (rsync and cp unavailable)"
|
|
252
|
+
copy_done=true
|
|
253
|
+
else
|
|
254
|
+
error "tar failed to copy framework files — check permissions and disk space"
|
|
255
|
+
exit 1
|
|
256
|
+
fi
|
|
257
|
+
fi
|
|
258
|
+
|
|
259
|
+
if [[ "$copy_done" == false ]]; then
|
|
260
|
+
error "No suitable copy tool found (tried rsync, cp, tar). Cannot copy framework files."
|
|
261
|
+
exit 1
|
|
262
|
+
fi
|
|
263
|
+
}
|
|
264
|
+
|
|
185
265
|
append_if_missing() {
|
|
186
266
|
local file="$1" marker="$2" content="$3"
|
|
187
267
|
if [[ -f "$file" ]] && grep -qF "$marker" "$file"; then
|
|
@@ -261,18 +341,22 @@ cmd_init() {
|
|
|
261
341
|
done
|
|
262
342
|
|
|
263
343
|
# Step 2: Copy _gaia/ recursively (excluding checkpoints and .resolved/*.yaml)
|
|
344
|
+
# Uses rsync if available, falls back to cp -rp, then tar (ADR-004: Windows best-effort)
|
|
264
345
|
step "Copying framework files..."
|
|
265
346
|
if [[ "$OPT_DRY_RUN" == true ]]; then
|
|
266
|
-
|
|
347
|
+
if command -v rsync >/dev/null 2>&1; then
|
|
348
|
+
detail "[dry-run] Would copy _gaia/ using rsync (excluding checkpoints and .resolved/*.yaml)"
|
|
349
|
+
elif command -v cp >/dev/null 2>&1; then
|
|
350
|
+
detail "[dry-run] Would copy _gaia/ using cp -rp (rsync unavailable)"
|
|
351
|
+
elif command -v tar >/dev/null 2>&1; then
|
|
352
|
+
detail "[dry-run] Would copy _gaia/ using tar (rsync and cp unavailable)"
|
|
353
|
+
else
|
|
354
|
+
error "No suitable copy tool found (tried rsync, cp, tar)"
|
|
355
|
+
exit 1
|
|
356
|
+
fi
|
|
267
357
|
else
|
|
268
358
|
mkdir -p "$TARGET/_gaia"
|
|
269
|
-
|
|
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/"
|
|
359
|
+
copy_gaia_files "$source" "$TARGET"
|
|
276
360
|
fi
|
|
277
361
|
|
|
278
362
|
# Step 3: Create _memory/ directory tree at project root (ADR-013)
|
|
@@ -351,7 +435,10 @@ cmd_init() {
|
|
|
351
435
|
else
|
|
352
436
|
local global_file="$TARGET/_gaia/_config/global.yaml"
|
|
353
437
|
if [[ -f "$global_file" ]]; then
|
|
354
|
-
# Use portable sed for both macOS and Linux
|
|
438
|
+
# Use portable sed for both macOS and Linux.
|
|
439
|
+
# macOS (Darwin) requires sed -i '' (empty extension). Linux/GNU sed uses sed -i (no arg).
|
|
440
|
+
# Git Bash on Windows: uname returns "MINGW64_NT-*", which falls into the else branch
|
|
441
|
+
# (GNU sed), which is correct — Git for Windows ships GNU sed.
|
|
355
442
|
if [[ "$(uname)" == "Darwin" ]]; then
|
|
356
443
|
sed -i '' "s|^project_name:.*|project_name: \"$project_name\"|" "$global_file"
|
|
357
444
|
sed -i '' "s|^user_name:.*|user_name: \"$user_name\"|" "$global_file"
|
|
@@ -430,6 +517,21 @@ GITIGNORE
|
|
|
430
517
|
echo ""
|
|
431
518
|
}
|
|
432
519
|
|
|
520
|
+
# ─── find_files_in_dir ──────────────────────────────────────────────────────
|
|
521
|
+
# Lists all files in a directory tree. Uses null-delimited output (find -print0)
|
|
522
|
+
# when supported, falls back to newline-delimited output on systems where -print0
|
|
523
|
+
# is unavailable (e.g., Windows Git Bash with busybox find).
|
|
524
|
+
# GAIA file paths never contain newlines, so the newline-delimited fallback is safe.
|
|
525
|
+
|
|
526
|
+
find_files_in_dir() {
|
|
527
|
+
local dir="$1"
|
|
528
|
+
if find /dev/null -maxdepth 0 -print0 2>/dev/null | head -c0 2>/dev/null; then
|
|
529
|
+
find "$dir" -type f -print0
|
|
530
|
+
else
|
|
531
|
+
find "$dir" -type f
|
|
532
|
+
fi
|
|
533
|
+
}
|
|
534
|
+
|
|
433
535
|
# ─── cmd_update ─────────────────────────────────────────────────────────────
|
|
434
536
|
|
|
435
537
|
cmd_update() {
|
|
@@ -497,6 +599,12 @@ cmd_update() {
|
|
|
497
599
|
step "Updating framework files..."
|
|
498
600
|
local updated=0 skipped=0 changed=0
|
|
499
601
|
|
|
602
|
+
# Feature-detect find -print0 support once before the loop (E6-S2)
|
|
603
|
+
local use_print0=false
|
|
604
|
+
if find /dev/null -maxdepth 0 -print0 2>/dev/null | head -c0 2>/dev/null; then
|
|
605
|
+
use_print0=true
|
|
606
|
+
fi
|
|
607
|
+
|
|
500
608
|
for entry in "${update_targets[@]}"; do
|
|
501
609
|
local src_path="$source/_gaia/$entry"
|
|
502
610
|
local dst_path="$TARGET/_gaia/$entry"
|
|
@@ -515,12 +623,24 @@ cmd_update() {
|
|
|
515
623
|
copy_with_backup "$src_path" "$dst_path" "$backup_dir"
|
|
516
624
|
updated=$((updated + 1))
|
|
517
625
|
elif [[ -d "$src_path" ]]; then
|
|
518
|
-
# Directory — update each file
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
626
|
+
# Directory — update each file via find_files_in_dir helper
|
|
627
|
+
if [[ "$use_print0" == true ]]; then
|
|
628
|
+
# Null-delimited path (macOS/Linux with GNU or BSD find)
|
|
629
|
+
while IFS= read -r -d '' file; do
|
|
630
|
+
local rel="${file#$src_path/}"
|
|
631
|
+
copy_with_backup "$file" "$dst_path/$rel" "$backup_dir"
|
|
632
|
+
updated=$((updated + 1))
|
|
633
|
+
done < <(find_files_in_dir "$src_path") || true
|
|
634
|
+
else
|
|
635
|
+
# Newline-delimited fallback (Windows Git Bash / busybox find)
|
|
636
|
+
# Safe because GAIA file paths never contain newlines
|
|
637
|
+
while IFS= read -r file; do
|
|
638
|
+
[[ -z "$file" ]] && continue
|
|
639
|
+
local rel="${file#$src_path/}"
|
|
640
|
+
copy_with_backup "$file" "$dst_path/$rel" "$backup_dir"
|
|
641
|
+
updated=$((updated + 1))
|
|
642
|
+
done < <(find_files_in_dir "$src_path") || true
|
|
643
|
+
fi
|
|
524
644
|
fi
|
|
525
645
|
done
|
|
526
646
|
|
|
@@ -830,7 +950,7 @@ parse_args() {
|
|
|
830
950
|
error "--source requires a path argument"
|
|
831
951
|
exit 1
|
|
832
952
|
fi
|
|
833
|
-
SOURCE_FLAG="$2"
|
|
953
|
+
SOURCE_FLAG="$(normalize_path "$2")"
|
|
834
954
|
shift 2
|
|
835
955
|
;;
|
|
836
956
|
--yes|-y)
|
|
@@ -858,7 +978,7 @@ parse_args() {
|
|
|
858
978
|
error "Unexpected argument: $1"
|
|
859
979
|
exit 1
|
|
860
980
|
fi
|
|
861
|
-
TARGET="$1"
|
|
981
|
+
TARGET="$(normalize_path "$1")"
|
|
862
982
|
shift
|
|
863
983
|
;;
|
|
864
984
|
esac
|
package/package.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gaia-framework",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.54.1",
|
|
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",
|