@ghl-ai/aw 0.1.9 → 0.1.12
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 +53 -30
- package/commands/nuke.mjs +1 -1
- package/commands/pull.mjs +25 -26
- package/package.json +1 -1
package/commands/init.mjs
CHANGED
|
@@ -73,9 +73,9 @@ function installIdeTasks() {
|
|
|
73
73
|
version: '2.0.0',
|
|
74
74
|
tasks: [
|
|
75
75
|
{
|
|
76
|
-
label: 'aw:
|
|
76
|
+
label: 'aw: sync registry',
|
|
77
77
|
type: 'shell',
|
|
78
|
-
command: 'aw
|
|
78
|
+
command: 'aw init --silent',
|
|
79
79
|
presentation: { reveal: 'silent', panel: 'shared', close: true },
|
|
80
80
|
runOptions: { runOn: 'folderOpen' },
|
|
81
81
|
problemMatcher: [],
|
|
@@ -93,7 +93,7 @@ function installIdeTasks() {
|
|
|
93
93
|
// Don't override existing tasks — check if aw task already there
|
|
94
94
|
try {
|
|
95
95
|
const existing = JSON.parse(readFileSync(tasksPath, 'utf8'));
|
|
96
|
-
if (existing.tasks?.some(t => t.label === 'aw: pull registry')) continue;
|
|
96
|
+
if (existing.tasks?.some(t => t.label === 'aw: sync registry' || t.label === 'aw: pull registry')) continue;
|
|
97
97
|
// Add our task to existing
|
|
98
98
|
existing.tasks = existing.tasks || [];
|
|
99
99
|
existing.tasks.push(vscodeTask.tasks[0]);
|
|
@@ -127,25 +127,56 @@ export async function initCommand(args) {
|
|
|
127
127
|
fmt.cancel("'ghl' is a reserved namespace — it is the shared platform layer");
|
|
128
128
|
}
|
|
129
129
|
|
|
130
|
-
|
|
130
|
+
const isExisting = config.exists(GLOBAL_AW_DIR);
|
|
131
|
+
const silent = args['--silent'] === true;
|
|
132
|
+
const cwd = process.cwd();
|
|
133
|
+
|
|
134
|
+
// ── Fast path: already initialized → just pull + link ─────────────────
|
|
135
|
+
|
|
136
|
+
if (isExisting) {
|
|
137
|
+
if (!silent) fmt.logStep('Already initialized — syncing...');
|
|
138
|
+
|
|
139
|
+
// Pull latest
|
|
140
|
+
pullCommand({ ...args, _positional: [], _workspaceDir: GLOBAL_AW_DIR, '--silent': silent });
|
|
141
|
+
|
|
142
|
+
// Re-link IDE dirs (idempotent)
|
|
143
|
+
linkWorkspace(HOME);
|
|
144
|
+
generateCommands(HOME);
|
|
145
|
+
copyInstructions(HOME, null, namespace) || [];
|
|
146
|
+
initAwDocs(HOME);
|
|
147
|
+
setupMcp(HOME, namespace) || [];
|
|
131
148
|
|
|
132
|
-
|
|
133
|
-
|
|
149
|
+
// Link current project if needed
|
|
150
|
+
if (cwd !== HOME && !existsSync(join(cwd, '.aw_registry'))) {
|
|
151
|
+
try {
|
|
152
|
+
symlinkSync(GLOBAL_AW_DIR, join(cwd, '.aw_registry'));
|
|
153
|
+
if (!silent) fmt.logStep('Linked .aw_registry in current project');
|
|
154
|
+
} catch { /* best effort */ }
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
if (!silent) {
|
|
158
|
+
fmt.outro([
|
|
159
|
+
'Sync complete',
|
|
160
|
+
'',
|
|
161
|
+
` ${chalk.green('✓')} Registry updated`,
|
|
162
|
+
` ${chalk.green('✓')} IDE integration refreshed`,
|
|
163
|
+
cwd !== HOME && existsSync(join(cwd, '.aw_registry')) ? ` ${chalk.green('✓')} Current project linked` : null,
|
|
164
|
+
].filter(Boolean).join('\n'));
|
|
165
|
+
}
|
|
166
|
+
return;
|
|
134
167
|
}
|
|
135
168
|
|
|
136
|
-
// ──
|
|
169
|
+
// ── Full init: first time setup ───────────────────────────────────────
|
|
137
170
|
|
|
171
|
+
// Auto-detect user
|
|
138
172
|
if (!user) {
|
|
139
173
|
try {
|
|
140
174
|
user = execSync('git config user.name', { encoding: 'utf8', stdio: ['pipe', 'pipe', 'pipe'] }).trim();
|
|
141
175
|
} catch { /* git not configured */ }
|
|
142
176
|
}
|
|
143
177
|
|
|
144
|
-
//
|
|
145
|
-
|
|
146
|
-
if (!existsSync(GLOBAL_AW_DIR)) {
|
|
147
|
-
mkdirSync(GLOBAL_AW_DIR, { recursive: true });
|
|
148
|
-
}
|
|
178
|
+
// Step 1: Create global source of truth
|
|
179
|
+
mkdirSync(GLOBAL_AW_DIR, { recursive: true });
|
|
149
180
|
|
|
150
181
|
const cfg = config.create(GLOBAL_AW_DIR, { namespace, user });
|
|
151
182
|
|
|
@@ -156,42 +187,35 @@ export async function initCommand(args) {
|
|
|
156
187
|
`${chalk.dim('version:')} v${VERSION}`,
|
|
157
188
|
].filter(Boolean).join('\n'), 'Config created');
|
|
158
189
|
|
|
159
|
-
//
|
|
160
|
-
|
|
190
|
+
// Step 2: Pull registry content
|
|
161
191
|
pullCommand({ ...args, _positional: ['ghl'], _workspaceDir: GLOBAL_AW_DIR });
|
|
162
192
|
|
|
163
193
|
if (namespace) {
|
|
164
194
|
pullCommand({ ...args, _positional: ['[template]'], _renameNamespace: namespace, _workspaceDir: GLOBAL_AW_DIR });
|
|
165
195
|
}
|
|
166
196
|
|
|
167
|
-
//
|
|
168
|
-
|
|
197
|
+
// Step 3: Link to global IDE dirs
|
|
169
198
|
linkWorkspace(HOME);
|
|
170
199
|
generateCommands(HOME);
|
|
171
200
|
const instructionFiles = copyInstructions(HOME, null, namespace) || [];
|
|
172
201
|
initAwDocs(HOME);
|
|
173
202
|
const mcpFiles = setupMcp(HOME, namespace) || [];
|
|
174
203
|
|
|
175
|
-
//
|
|
176
|
-
|
|
204
|
+
// Step 4: Git template hook (omnipresence)
|
|
177
205
|
const gitTemplateInstalled = installGitTemplate();
|
|
178
206
|
|
|
179
|
-
//
|
|
180
|
-
|
|
207
|
+
// Step 5: IDE auto-init tasks
|
|
181
208
|
installIdeTasks();
|
|
182
209
|
|
|
183
|
-
//
|
|
184
|
-
|
|
185
|
-
const cwd = process.cwd();
|
|
186
|
-
if (cwd !== HOME && existsSync(join(cwd, '.git')) && !existsSync(join(cwd, '.aw_registry'))) {
|
|
210
|
+
// Step 6: Symlink in current directory if it's a git repo
|
|
211
|
+
if (cwd !== HOME && !existsSync(join(cwd, '.aw_registry'))) {
|
|
187
212
|
try {
|
|
188
213
|
symlinkSync(GLOBAL_AW_DIR, join(cwd, '.aw_registry'));
|
|
189
214
|
fmt.logStep('Linked .aw_registry in current project');
|
|
190
215
|
} catch { /* best effort */ }
|
|
191
216
|
}
|
|
192
217
|
|
|
193
|
-
//
|
|
194
|
-
|
|
218
|
+
// Step 7: Write manifest for nuke cleanup
|
|
195
219
|
const manifest = {
|
|
196
220
|
version: 1,
|
|
197
221
|
installedAt: new Date().toISOString(),
|
|
@@ -204,20 +228,19 @@ export async function initCommand(args) {
|
|
|
204
228
|
};
|
|
205
229
|
saveManifest(manifest);
|
|
206
230
|
|
|
207
|
-
//
|
|
208
|
-
|
|
231
|
+
// Done
|
|
209
232
|
fmt.outro([
|
|
210
233
|
'Install complete',
|
|
211
234
|
'',
|
|
212
235
|
` ${chalk.green('✓')} Source of truth: ~/.aw_registry/`,
|
|
213
236
|
` ${chalk.green('✓')} IDE integration: ~/.claude/, ~/.cursor/, ~/.codex/`,
|
|
214
237
|
gitTemplateInstalled ? ` ${chalk.green('✓')} Git hook: new clones auto-link .aw_registry` : null,
|
|
215
|
-
` ${chalk.green('✓')} IDE task: auto-
|
|
238
|
+
` ${chalk.green('✓')} IDE task: auto-sync on workspace open`,
|
|
216
239
|
cwd !== HOME && existsSync(join(cwd, '.aw_registry')) ? ` ${chalk.green('✓')} Linked in current project` : null,
|
|
217
240
|
'',
|
|
218
241
|
` ${chalk.dim('Existing repos:')} ${chalk.bold('cd <project> && aw link')}`,
|
|
219
242
|
` ${chalk.dim('New clones:')} auto-linked via git hook`,
|
|
220
|
-
` ${chalk.dim('Update:')} ${chalk.bold('aw
|
|
243
|
+
` ${chalk.dim('Update:')} ${chalk.bold('aw init')} ${chalk.dim('(or auto on IDE open)')}`,
|
|
221
244
|
` ${chalk.dim('Uninstall:')} ${chalk.bold('aw nuke')}`,
|
|
222
245
|
].filter(Boolean).join('\n'));
|
|
223
246
|
}
|
package/commands/nuke.mjs
CHANGED
|
@@ -146,7 +146,7 @@ export function nukeCommand(args) {
|
|
|
146
146
|
try {
|
|
147
147
|
const data = JSON.parse(readFileSync(tasksPath, 'utf8'));
|
|
148
148
|
const before = data.tasks?.length || 0;
|
|
149
|
-
data.tasks = (data.tasks || []).filter(t => t.label !== 'aw: pull registry');
|
|
149
|
+
data.tasks = (data.tasks || []).filter(t => t.label !== 'aw: sync registry' && t.label !== 'aw: pull registry');
|
|
150
150
|
if (data.tasks.length < before) {
|
|
151
151
|
if (data.tasks.length === 0) {
|
|
152
152
|
unlinkSync(tasksPath);
|
package/commands/pull.mjs
CHANGED
|
@@ -28,28 +28,27 @@ export function pullCommand(args) {
|
|
|
28
28
|
const silent = args['--silent'] === true || args._silent === true;
|
|
29
29
|
const renameNamespace = args._renameNamespace || null;
|
|
30
30
|
|
|
31
|
-
// Silent mode: suppress all output and exit cleanly on errors
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
}
|
|
31
|
+
// Silent mode: wrap fmt to suppress all output and exit cleanly on errors
|
|
32
|
+
const log = {
|
|
33
|
+
cancel: silent ? () => { process.exit(0); } : fmt.cancel,
|
|
34
|
+
logInfo: silent ? () => {} : fmt.logInfo,
|
|
35
|
+
logSuccess: silent ? () => {} : fmt.logSuccess,
|
|
36
|
+
logStep: silent ? () => {} : fmt.logStep,
|
|
37
|
+
logWarn: silent ? () => {} : fmt.logWarn,
|
|
38
|
+
logMessage: silent ? () => {} : fmt.logMessage,
|
|
39
|
+
note: silent ? () => {} : fmt.note,
|
|
40
|
+
outro: silent ? () => {} : fmt.outro,
|
|
41
|
+
spinner: silent ? () => ({ start: () => {}, stop: () => {} }) : fmt.spinner,
|
|
42
|
+
};
|
|
44
43
|
|
|
45
44
|
// No args = re-pull everything in sync config
|
|
46
45
|
if (!input) {
|
|
47
46
|
const cfg = config.load(workspaceDir);
|
|
48
|
-
if (!cfg)
|
|
47
|
+
if (!cfg) log.cancel('No .sync-config.json found. Run: aw init');
|
|
49
48
|
if (cfg.include.length === 0) {
|
|
50
|
-
|
|
49
|
+
log.cancel('Nothing to pull. Add paths first:\n\n aw pull <path>');
|
|
51
50
|
}
|
|
52
|
-
|
|
51
|
+
log.logInfo(`Pulling ${chalk.cyan(cfg.include.length)} synced path${cfg.include.length > 1 ? 's' : ''}...`);
|
|
53
52
|
for (const p of cfg.include) {
|
|
54
53
|
pullCommand({ ...args, _positional: [p], _skipIntegrate: true });
|
|
55
54
|
}
|
|
@@ -65,7 +64,7 @@ export function pullCommand(args) {
|
|
|
65
64
|
let pattern = resolved.registryPath;
|
|
66
65
|
|
|
67
66
|
if (!pattern) {
|
|
68
|
-
|
|
67
|
+
log.cancel(`Could not resolve "${input}" to a registry path`);
|
|
69
68
|
}
|
|
70
69
|
|
|
71
70
|
// Ensure workspace exists
|
|
@@ -76,11 +75,11 @@ export function pullCommand(args) {
|
|
|
76
75
|
// Load config
|
|
77
76
|
const cfg = config.load(workspaceDir);
|
|
78
77
|
if (!cfg) {
|
|
79
|
-
|
|
78
|
+
log.cancel('No .sync-config.json found. Run: aw init');
|
|
80
79
|
}
|
|
81
80
|
|
|
82
81
|
// Fetch from registry
|
|
83
|
-
const s =
|
|
82
|
+
const s = log.spinner();
|
|
84
83
|
s.start('Fetching from registry...');
|
|
85
84
|
|
|
86
85
|
const sparsePaths = includeToSparsePaths([pattern]);
|
|
@@ -89,7 +88,7 @@ export function pullCommand(args) {
|
|
|
89
88
|
tempDir = sparseCheckout(cfg.repo, sparsePaths);
|
|
90
89
|
} catch (e) {
|
|
91
90
|
s.stop(chalk.red('Fetch failed'));
|
|
92
|
-
|
|
91
|
+
log.cancel(e.message);
|
|
93
92
|
}
|
|
94
93
|
|
|
95
94
|
try {
|
|
@@ -104,8 +103,8 @@ export function pullCommand(args) {
|
|
|
104
103
|
|
|
105
104
|
if (registryDirs.length === 0) {
|
|
106
105
|
s.stop(chalk.red('Not found'));
|
|
107
|
-
if (
|
|
108
|
-
|
|
106
|
+
if (silent) return;
|
|
107
|
+
log.cancel(`Nothing found in registry for ${chalk.cyan(pattern)}`);
|
|
109
108
|
}
|
|
110
109
|
|
|
111
110
|
// Rename namespace if requested (e.g., [template] → dev)
|
|
@@ -132,8 +131,8 @@ export function pullCommand(args) {
|
|
|
132
131
|
if (!hasMatch) {
|
|
133
132
|
s.stop(chalk.red('Not found'));
|
|
134
133
|
cleanup(tempDir);
|
|
135
|
-
if (
|
|
136
|
-
|
|
134
|
+
if (silent) return;
|
|
135
|
+
log.cancel(`Nothing found in registry for ${chalk.cyan(pattern)}\n\n Check the pattern exists in the registry repo.`);
|
|
137
136
|
}
|
|
138
137
|
|
|
139
138
|
const fetched = registryDirs.map(d => chalk.cyan(d.name)).join(', ');
|
|
@@ -142,7 +141,7 @@ export function pullCommand(args) {
|
|
|
142
141
|
// Add to config if not already there
|
|
143
142
|
if (!cfg.include.includes(pattern)) {
|
|
144
143
|
config.addPattern(workspaceDir, pattern);
|
|
145
|
-
|
|
144
|
+
log.logSuccess(`Added ${chalk.cyan(pattern)} to config`);
|
|
146
145
|
}
|
|
147
146
|
|
|
148
147
|
// Compute plan
|
|
@@ -156,7 +155,7 @@ export function pullCommand(args) {
|
|
|
156
155
|
}
|
|
157
156
|
|
|
158
157
|
// Apply
|
|
159
|
-
const s2 =
|
|
158
|
+
const s2 = log.spinner();
|
|
160
159
|
s2.start('Applying changes...');
|
|
161
160
|
const conflictCount = applyActions(actions);
|
|
162
161
|
updateManifest(workspaceDir, actions, cfg.namespace);
|