@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 CHANGED
@@ -73,9 +73,9 @@ function installIdeTasks() {
73
73
  version: '2.0.0',
74
74
  tasks: [
75
75
  {
76
- label: 'aw: pull registry',
76
+ label: 'aw: sync registry',
77
77
  type: 'shell',
78
- command: 'aw pull',
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
- // ── Check existing install ────────────────────────────────────────────
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
- if (config.exists(GLOBAL_AW_DIR)) {
133
- fmt.logStep('Existing install found re-initializing...');
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
- // ── Auto-detect user ──────────────────────────────────────────────────
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
- // ── Step 1: Create global source of truth ─────────────────────────────
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
- // ── Step 2: Pull registry content ─────────────────────────────────────
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
- // ── Step 3: Link to global IDE dirs ───────────────────────────────────
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
- // ── Step 4: Git template hook (omnipresence) ──────────────────────────
176
-
204
+ // Step 4: Git template hook (omnipresence)
177
205
  const gitTemplateInstalled = installGitTemplate();
178
206
 
179
- // ── Step 5: IDE auto-pull tasks ───────────────────────────────────────
180
-
207
+ // Step 5: IDE auto-init tasks
181
208
  installIdeTasks();
182
209
 
183
- // ── Step 6: Symlink in current directory if it's a git repo ───────────
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
- // ── Step 7: Write manifest for nuke cleanup ───────────────────────────
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
- // ── Done ──────────────────────────────────────────────────────────────
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-pull on workspace open`,
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 pull')} ${chalk.dim('(or auto on IDE open)')}`,
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
- if (silent) {
33
- const origCancel = fmt.cancel;
34
- fmt.cancel = () => { process.exit(0); };
35
- fmt.logInfo = () => {};
36
- fmt.logSuccess = () => {};
37
- fmt.logStep = () => {};
38
- fmt.logWarn = () => {};
39
- fmt.logMessage = () => {};
40
- fmt.note = () => {};
41
- fmt.outro = () => {};
42
- fmt.spinner = () => ({ start: () => {}, stop: () => {} });
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) fmt.cancel('No .sync-config.json found. Run: aw init');
47
+ if (!cfg) log.cancel('No .sync-config.json found. Run: aw init');
49
48
  if (cfg.include.length === 0) {
50
- fmt.cancel('Nothing to pull. Add paths first:\n\n aw pull <path>');
49
+ log.cancel('Nothing to pull. Add paths first:\n\n aw pull <path>');
51
50
  }
52
- fmt.logInfo(`Pulling ${chalk.cyan(cfg.include.length)} synced path${cfg.include.length > 1 ? 's' : ''}...`);
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
- fmt.cancel(`Could not resolve "${input}" to a registry path`);
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
- fmt.cancel('No .sync-config.json found. Run: aw init');
78
+ log.cancel('No .sync-config.json found. Run: aw init');
80
79
  }
81
80
 
82
81
  // Fetch from registry
83
- const s = fmt.spinner();
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
- fmt.cancel(e.message);
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 (args._silent) return;
108
- fmt.cancel(`Nothing found in registry for ${chalk.cyan(pattern)}`);
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 (args._silent) return;
136
- fmt.cancel(`Nothing found in registry for ${chalk.cyan(pattern)}\n\n Check the pattern exists in the registry repo.`);
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
- fmt.logSuccess(`Added ${chalk.cyan(pattern)} to config`);
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 = fmt.spinner();
158
+ const s2 = log.spinner();
160
159
  s2.start('Applying changes...');
161
160
  const conflictCount = applyActions(actions);
162
161
  updateManifest(workspaceDir, actions, cfg.namespace);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ghl-ai/aw",
3
- "version": "0.1.9",
3
+ "version": "0.1.12",
4
4
  "description": "Agentic Workspace CLI — pull, push & manage agents, skills and commands from the registry",
5
5
  "type": "module",
6
6
  "bin": {