@ghl-ai/aw 0.1.40 → 0.1.41-beta.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/commands/init.mjs +54 -14
- package/package.json +1 -1
- package/telemetry.mjs +13 -3
package/commands/init.mjs
CHANGED
|
@@ -13,7 +13,6 @@ import {
|
|
|
13
13
|
readFileSync,
|
|
14
14
|
rmSync,
|
|
15
15
|
realpathSync,
|
|
16
|
-
appendFileSync,
|
|
17
16
|
} from 'node:fs';
|
|
18
17
|
import { execSync } from 'node:child_process';
|
|
19
18
|
import { join, dirname, sep } from 'node:path';
|
|
@@ -88,24 +87,65 @@ function syncHomeAndProjectInstructions(cwd, namespace) {
|
|
|
88
87
|
}
|
|
89
88
|
}
|
|
90
89
|
|
|
91
|
-
// ── Ensure ~/.aw/.
|
|
92
|
-
|
|
93
|
-
|
|
90
|
+
// ── Ensure ~/.aw/.git/info/exclude has the whitelist block ─────────────
|
|
91
|
+
//
|
|
92
|
+
// Strategy: only .aw_registry/, .aw_rules/, content/ are tracked — everything
|
|
93
|
+
// else at the top level of ~/.aw/ is local-only (telemetry/, hooks/, logs,
|
|
94
|
+
// .DS_Store, etc.). We write to .git/info/exclude (not tracked .gitignore)
|
|
95
|
+
// so upstream pulls never conflict.
|
|
96
|
+
|
|
97
|
+
const AW_MANAGED_BEGIN = '# BEGIN aw-managed (do not edit; managed by `aw init`)';
|
|
98
|
+
const AW_MANAGED_END = '# END aw-managed';
|
|
99
|
+
|
|
100
|
+
const AW_MANAGED_BLOCK = [
|
|
101
|
+
AW_MANAGED_BEGIN,
|
|
102
|
+
'# Whitelist: only these top-level entries are tracked; everything else is local-only.',
|
|
103
|
+
'/*',
|
|
104
|
+
'!/.aw_registry',
|
|
105
|
+
'!/.aw_rules',
|
|
106
|
+
'!/content',
|
|
107
|
+
'',
|
|
108
|
+
'# Nested local state within whitelisted dirs',
|
|
109
|
+
'/.aw_registry/.sync-config.json',
|
|
110
|
+
AW_MANAGED_END,
|
|
111
|
+
'',
|
|
112
|
+
].join('\n');
|
|
113
|
+
|
|
114
|
+
// Legacy flat lines appended by earlier versions of ensureAwGitignore — strip on upgrade
|
|
115
|
+
// so we don't leave stale rules lingering outside the managed block.
|
|
116
|
+
const LEGACY_GITIGNORE_LINES = new Set([
|
|
94
117
|
'.aw_registry/.sync-config.json',
|
|
95
118
|
'hooks/',
|
|
96
|
-
|
|
119
|
+
'# aw: personal/local — do not commit',
|
|
120
|
+
]);
|
|
121
|
+
|
|
122
|
+
function escapeRegex(s) {
|
|
123
|
+
return s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
124
|
+
}
|
|
97
125
|
|
|
98
|
-
function ensureAwGitignore(awHome) {
|
|
99
|
-
// Use .git/info/exclude so the tracked .gitignore stays clean
|
|
126
|
+
export function ensureAwGitignore(awHome) {
|
|
100
127
|
const excludePath = join(awHome, '.git', 'info', 'exclude');
|
|
101
128
|
let existing = '';
|
|
102
|
-
try { existing = readFileSync(excludePath, 'utf8'); } catch { /* doesn't exist yet */ }
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
const
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
129
|
+
try { existing = readFileSync(excludePath, 'utf8'); } catch (err) { void err; /* doesn't exist yet */ }
|
|
130
|
+
|
|
131
|
+
// Strip any prior aw-managed block so re-rendering is idempotent.
|
|
132
|
+
const blockRegex = new RegExp(
|
|
133
|
+
`${escapeRegex(AW_MANAGED_BEGIN)}[\\s\\S]*?${escapeRegex(AW_MANAGED_END)}\\n?`,
|
|
134
|
+
'g'
|
|
135
|
+
);
|
|
136
|
+
const withoutManaged = existing.replace(blockRegex, '');
|
|
137
|
+
|
|
138
|
+
// Strip legacy flat lines (pre-whitelist implementation).
|
|
139
|
+
const cleaned = withoutManaged
|
|
140
|
+
.split('\n')
|
|
141
|
+
.filter(line => !LEGACY_GITIGNORE_LINES.has(line.trim()))
|
|
142
|
+
.join('\n');
|
|
143
|
+
|
|
144
|
+
const prefix = cleaned === '' || cleaned.endsWith('\n') ? cleaned : cleaned + '\n';
|
|
145
|
+
const next = prefix + AW_MANAGED_BLOCK;
|
|
146
|
+
|
|
147
|
+
if (next === existing) return; // already up to date
|
|
148
|
+
try { writeFileSync(excludePath, next); } catch (err) { void err; /* best effort */ }
|
|
109
149
|
}
|
|
110
150
|
|
|
111
151
|
// ── IDE tasks for auto-pull ─────────────────────────────────────────────
|
package/package.json
CHANGED
package/telemetry.mjs
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
import { createHash, randomUUID } from 'node:crypto';
|
|
9
9
|
import { hostname, userInfo, platform, arch, release } from 'node:os';
|
|
10
|
-
import { readFileSync, writeFileSync, mkdirSync, existsSync, readdirSync } from 'node:fs';
|
|
10
|
+
import { readFileSync, writeFileSync, mkdirSync, existsSync, readdirSync, lstatSync, unlinkSync } from 'node:fs';
|
|
11
11
|
import { join, dirname } from 'node:path';
|
|
12
12
|
import { fileURLToPath } from 'node:url';
|
|
13
13
|
import { execSync } from 'node:child_process';
|
|
@@ -16,7 +16,9 @@ import { TELEMETRY_URL, AW_HOME } from './constants.mjs';
|
|
|
16
16
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
17
17
|
const VERSION = JSON.parse(readFileSync(join(__dirname, 'package.json'), 'utf8')).version;
|
|
18
18
|
|
|
19
|
-
const
|
|
19
|
+
const CONFIG_DIR = join(AW_HOME, 'telemetry');
|
|
20
|
+
const CONFIG_PATH = join(CONFIG_DIR, 'config.json');
|
|
21
|
+
const LEGACY_CONFIG_PATH = join(AW_HOME, '.telemetry');
|
|
20
22
|
|
|
21
23
|
// ── Config ──────────────────────────────────────────────────────────
|
|
22
24
|
|
|
@@ -30,7 +32,15 @@ export function loadConfig() {
|
|
|
30
32
|
if (existsSync(CONFIG_PATH)) {
|
|
31
33
|
return JSON.parse(readFileSync(CONFIG_PATH, 'utf8'));
|
|
32
34
|
}
|
|
33
|
-
|
|
35
|
+
// One-time migration from legacy single-file shape (~/.aw/.telemetry).
|
|
36
|
+
// Only triggered when new path is missing, so re-running is a no-op.
|
|
37
|
+
if (existsSync(LEGACY_CONFIG_PATH) && lstatSync(LEGACY_CONFIG_PATH).isFile()) {
|
|
38
|
+
const legacy = JSON.parse(readFileSync(LEGACY_CONFIG_PATH, 'utf8'));
|
|
39
|
+
saveConfig(legacy);
|
|
40
|
+
try { unlinkSync(LEGACY_CONFIG_PATH); } catch (err) { void err; /* best-effort cleanup */ }
|
|
41
|
+
return legacy;
|
|
42
|
+
}
|
|
43
|
+
} catch (err) { void err; /* corrupt file — fall through to fresh config */ }
|
|
34
44
|
|
|
35
45
|
const config = {
|
|
36
46
|
machine_id: generateMachineId(),
|