@ghl-ai/aw 0.1.39-beta.1 → 0.1.39-beta.6
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 +71 -15
- package/ecc.mjs +1 -1
- package/git.mjs +23 -4
- package/mcp.mjs +10 -2
- package/package.json +1 -1
package/commands/init.mjs
CHANGED
|
@@ -47,6 +47,23 @@ import { syncFileTree } from '../file-tree.mjs';
|
|
|
47
47
|
|
|
48
48
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
49
49
|
const VERSION = JSON.parse(readFileSync(join(__dirname, '..', 'package.json'), 'utf8')).version;
|
|
50
|
+
const DEBUG_INIT_LOG = process.env.AW_DEBUG_INIT_LOG;
|
|
51
|
+
|
|
52
|
+
function debugInit(message) {
|
|
53
|
+
if (!DEBUG_INIT_LOG) return;
|
|
54
|
+
try {
|
|
55
|
+
appendFileSync(DEBUG_INIT_LOG, `${new Date().toISOString()} ${message}\n`);
|
|
56
|
+
} catch { /* best effort */ }
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function createSpinner(enabled) {
|
|
60
|
+
if (enabled) return fmt.spinner();
|
|
61
|
+
return {
|
|
62
|
+
start() {},
|
|
63
|
+
stop() {},
|
|
64
|
+
message() {},
|
|
65
|
+
};
|
|
66
|
+
}
|
|
50
67
|
|
|
51
68
|
// Resolve HOME to the real path — on macOS /var is a symlink to /private/var,
|
|
52
69
|
// so homedir() returns /var/... while process.cwd() returns /private/var/...
|
|
@@ -121,8 +138,12 @@ export async function initCommand(args) {
|
|
|
121
138
|
let namespace = args['--namespace'] || null;
|
|
122
139
|
let user = args['--user'] || '';
|
|
123
140
|
const silent = args['--silent'] === true;
|
|
141
|
+
const interactiveUi = !silent && Boolean(process.stdout.isTTY);
|
|
124
142
|
|
|
125
|
-
|
|
143
|
+
if (interactiveUi) {
|
|
144
|
+
fmt.intro(`aw init ${chalk.dim('v' + VERSION)}`);
|
|
145
|
+
}
|
|
146
|
+
debugInit('init:start');
|
|
126
147
|
|
|
127
148
|
// ── Validate ──────────────────────────────────────────────────────────
|
|
128
149
|
|
|
@@ -170,7 +191,7 @@ export async function initCommand(args) {
|
|
|
170
191
|
|
|
171
192
|
let namespaceExistsInRemote = false;
|
|
172
193
|
if (folderName && !silent && !isGitNative && !isLegacy) {
|
|
173
|
-
const probeSpinner =
|
|
194
|
+
const probeSpinner = createSpinner(interactiveUi);
|
|
174
195
|
probeSpinner.start(`Checking namespace ${chalk.cyan(folderName)} in registry...`);
|
|
175
196
|
try {
|
|
176
197
|
const probePaths = includeToSparsePaths([folderName]);
|
|
@@ -183,11 +204,15 @@ export async function initCommand(args) {
|
|
|
183
204
|
} finally {
|
|
184
205
|
cleanup(probeDir);
|
|
185
206
|
}
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
207
|
+
if (interactiveUi) {
|
|
208
|
+
probeSpinner.stop(namespaceExistsInRemote
|
|
209
|
+
? `Namespace ${chalk.cyan(folderName)} found in registry`
|
|
210
|
+
: `Namespace ${chalk.cyan(folderName)} not yet in registry`);
|
|
211
|
+
}
|
|
189
212
|
} catch {
|
|
190
|
-
|
|
213
|
+
if (interactiveUi) {
|
|
214
|
+
probeSpinner.stop(chalk.dim('Could not verify namespace (continuing)'));
|
|
215
|
+
}
|
|
191
216
|
namespaceExistsInRemote = true;
|
|
192
217
|
}
|
|
193
218
|
}
|
|
@@ -229,7 +254,7 @@ export async function initCommand(args) {
|
|
|
229
254
|
if (!silent) fmt.logStep('Already initialized — syncing...');
|
|
230
255
|
}
|
|
231
256
|
|
|
232
|
-
const s =
|
|
257
|
+
const s = createSpinner(interactiveUi);
|
|
233
258
|
if (!silent) s.start('Fetching latest from registry...');
|
|
234
259
|
try {
|
|
235
260
|
const { conflicts } = await fetchAndMerge(AW_HOME, { silent });
|
|
@@ -338,21 +363,26 @@ export async function initCommand(args) {
|
|
|
338
363
|
sparsePaths.push(`.aw_registry/${folderName}`);
|
|
339
364
|
}
|
|
340
365
|
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
366
|
+
if (interactiveUi) {
|
|
367
|
+
fmt.note([
|
|
368
|
+
`${chalk.dim('source:')} ~/.aw/ → ~/.aw_registry/ (symlink)`,
|
|
369
|
+
folderName ? `${chalk.dim('namespace:')} ${folderName}` : `${chalk.dim('namespace:')} ${chalk.dim('none')}`,
|
|
370
|
+
user ? `${chalk.dim('user:')} ${user}` : null,
|
|
371
|
+
`${chalk.dim('version:')} v${VERSION}`,
|
|
372
|
+
].filter(Boolean).join('\n'), 'Config');
|
|
373
|
+
}
|
|
347
374
|
|
|
348
|
-
const s =
|
|
375
|
+
const s = createSpinner(interactiveUi);
|
|
349
376
|
s.start(`Cloning registry...`);
|
|
350
377
|
|
|
351
378
|
try {
|
|
379
|
+
debugInit(`clone:start repo=${repoUrl}`);
|
|
352
380
|
await initPersistentClone(repoUrl, AW_HOME, sparsePaths);
|
|
381
|
+
debugInit('clone:done');
|
|
353
382
|
ensureAwGitignore(AW_HOME);
|
|
354
383
|
s.stop('Registry cloned');
|
|
355
384
|
} catch (e) {
|
|
385
|
+
debugInit(`clone:error ${e.message}`);
|
|
356
386
|
s.stop(chalk.red('Clone failed'));
|
|
357
387
|
fmt.cancel(e.message);
|
|
358
388
|
}
|
|
@@ -363,38 +393,55 @@ export async function initCommand(args) {
|
|
|
363
393
|
try { awRegistryLstat = lstatSync(GLOBAL_AW_DIR); } catch { /* doesn't exist */ }
|
|
364
394
|
if (!awRegistryLstat) {
|
|
365
395
|
try {
|
|
396
|
+
debugInit('symlink:create:start');
|
|
366
397
|
symlinkSync(join(AW_HOME, REGISTRY_DIR), GLOBAL_AW_DIR);
|
|
398
|
+
debugInit('symlink:create:done');
|
|
367
399
|
fmt.logStep('Created ~/.aw_registry/ symlink');
|
|
368
400
|
} catch (e) {
|
|
401
|
+
debugInit(`symlink:create:error ${e.message}`);
|
|
369
402
|
fmt.logWarn(`Could not create symlink ~/.aw_registry/: ${e.message}`);
|
|
370
403
|
}
|
|
371
404
|
} else if (awRegistryLstat.isSymbolicLink()) {
|
|
372
405
|
// Stale or dangling — re-point to the new clone
|
|
373
406
|
try {
|
|
407
|
+
debugInit('symlink:update:start');
|
|
374
408
|
rmSync(GLOBAL_AW_DIR);
|
|
375
409
|
symlinkSync(join(AW_HOME, REGISTRY_DIR), GLOBAL_AW_DIR);
|
|
410
|
+
debugInit('symlink:update:done');
|
|
376
411
|
fmt.logStep('Updated ~/.aw_registry/ symlink');
|
|
377
412
|
} catch (e) {
|
|
413
|
+
debugInit(`symlink:update:error ${e.message}`);
|
|
378
414
|
fmt.logWarn(`Could not update symlink ~/.aw_registry/: ${e.message}`);
|
|
379
415
|
}
|
|
380
416
|
}
|
|
381
417
|
|
|
382
418
|
// Create sync config — default to 'platform' when no namespace specified
|
|
383
419
|
const cfg = config.create(GLOBAL_AW_DIR, { namespace: team || 'platform', user });
|
|
420
|
+
debugInit('config:create:done');
|
|
384
421
|
if (folderName) {
|
|
385
422
|
config.addPattern(GLOBAL_AW_DIR, folderName);
|
|
423
|
+
debugInit('config:add-pattern:done');
|
|
386
424
|
}
|
|
387
425
|
if (existsSync(GLOBAL_AW_DIR)) {
|
|
426
|
+
debugInit('sync-file-tree:start');
|
|
388
427
|
syncFileTree(join(AW_HOME, RULES_SOURCE_DIR), join(GLOBAL_AW_DIR, RULES_SOURCE_DIR));
|
|
428
|
+
debugInit('sync-file-tree:done');
|
|
389
429
|
}
|
|
390
430
|
|
|
391
431
|
// Step 3: Setup tasks, MCP, hooks
|
|
432
|
+
debugInit('ecc:start');
|
|
392
433
|
await installAwEcc(cwd, { silent });
|
|
434
|
+
debugInit('ecc:done');
|
|
393
435
|
const instructionFiles = copyInstructions(HOME, null, team) || [];
|
|
436
|
+
debugInit(`instructions:done count=${instructionFiles.length}`);
|
|
394
437
|
initAwDocs(HOME);
|
|
438
|
+
debugInit('aw-docs:done');
|
|
395
439
|
const mcpFiles = await setupMcp(HOME, team, { silent }) || [];
|
|
440
|
+
debugInit(`mcp:done count=${mcpFiles.length}`);
|
|
396
441
|
const hooksInstalled = installGlobalHooks();
|
|
442
|
+
debugInit(`hooks:done installed=${hooksInstalled}`);
|
|
397
443
|
installIdeTasks();
|
|
444
|
+
debugInit('ide-tasks:done');
|
|
398
445
|
|
|
399
446
|
// Remove old local .git/hooks/post-checkout that pre-dates core.hooksPath
|
|
400
447
|
if (cwd !== HOME) {
|
|
@@ -413,24 +460,33 @@ export async function initCommand(args) {
|
|
|
413
460
|
const isAlreadySymlinkFresh = (() => { try { return lstatSync(awLinkFresh).isSymbolicLink() && existsSync(awLinkFresh); } catch { return false; } })();
|
|
414
461
|
if (cwd !== HOME && !isInsideAw && !isAlreadySymlinkFresh) {
|
|
415
462
|
try {
|
|
463
|
+
debugInit('link-project:start');
|
|
416
464
|
addProjectWorktree(AW_HOME, cwd);
|
|
465
|
+
debugInit('link-project:done');
|
|
417
466
|
fmt.logStep('Linked current project');
|
|
418
467
|
} catch { /* best effort */ }
|
|
419
468
|
}
|
|
420
469
|
|
|
421
470
|
// Step 5: Wire ~/.claude/.cursor/.codex to the project's registry when in a project,
|
|
422
471
|
// so edits to project/.aw/.aw_registry/ are instantly visible in global IDE dirs.
|
|
423
|
-
const ideSpinner =
|
|
472
|
+
const ideSpinner = createSpinner(interactiveUi);
|
|
424
473
|
ideSpinner.start('Wiring IDE symlinks...');
|
|
474
|
+
debugInit('ide-wire:start');
|
|
425
475
|
const projectRegistryDir = cwd !== HOME ? join(cwd, '.aw', REGISTRY_DIR) : null;
|
|
426
476
|
const awDirForLinks = (projectRegistryDir && existsSync(projectRegistryDir)) ? projectRegistryDir : null;
|
|
427
477
|
const symlinks = linkWorkspace(HOME, awDirForLinks, { silent: true });
|
|
428
478
|
if (cwd !== HOME) installLocalCommitHook(cwd);
|
|
429
479
|
ideSpinner.message('Generating commands...');
|
|
430
480
|
const commands = generateCommands(HOME, { silent: true });
|
|
481
|
+
debugInit(`ide-wire:done symlinks=${symlinks} commands=${commands}`);
|
|
431
482
|
ideSpinner.stop(`IDE wired — ${chalk.bold(symlinks)} symlinks · ${chalk.bold(commands)} commands`);
|
|
432
483
|
|
|
433
484
|
// Offer to update if a newer version is available
|
|
485
|
+
if (silent) {
|
|
486
|
+
autoUpdate(await args._updateCheck);
|
|
487
|
+
return;
|
|
488
|
+
}
|
|
489
|
+
|
|
434
490
|
await promptUpdate(await args._updateCheck);
|
|
435
491
|
|
|
436
492
|
fmt.outro([
|
package/ecc.mjs
CHANGED
|
@@ -9,7 +9,7 @@ import * as fmt from "./fmt.mjs";
|
|
|
9
9
|
|
|
10
10
|
const AW_ECC_REPO_SSH = "git@github.com:shreyansh-ghl/aw-ecc.git";
|
|
11
11
|
const AW_ECC_REPO_HTTPS = "https://github.com/shreyansh-ghl/aw-ecc.git";
|
|
12
|
-
const AW_ECC_TAG = "v1.4.
|
|
12
|
+
const AW_ECC_TAG = "v1.4.31";
|
|
13
13
|
|
|
14
14
|
const MARKETPLACE_NAME = "aw-marketplace";
|
|
15
15
|
const PLUGIN_KEY = `aw@${MARKETPLACE_NAME}`;
|
package/git.mjs
CHANGED
|
@@ -124,15 +124,34 @@ export async function initPersistentClone(repoUrl, awHome, sparsePaths) {
|
|
|
124
124
|
}
|
|
125
125
|
|
|
126
126
|
try {
|
|
127
|
-
|
|
127
|
+
execSync(`git clone --filter=blob:none --no-checkout "${repoUrl}" "${awHome}"`, {
|
|
128
|
+
stdio: 'pipe',
|
|
129
|
+
encoding: 'utf8',
|
|
130
|
+
env: {
|
|
131
|
+
...process.env,
|
|
132
|
+
GIT_TERMINAL_PROMPT: process.env.GIT_TERMINAL_PROMPT ?? '0',
|
|
133
|
+
},
|
|
134
|
+
});
|
|
128
135
|
} catch (e) {
|
|
129
136
|
throw new Error(`Failed to clone ${repoUrl}: ${e.message}`);
|
|
130
137
|
}
|
|
131
138
|
|
|
132
139
|
try {
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
140
|
+
execSync('git sparse-checkout init --no-cone', {
|
|
141
|
+
cwd: awHome,
|
|
142
|
+
stdio: 'pipe',
|
|
143
|
+
encoding: 'utf8',
|
|
144
|
+
});
|
|
145
|
+
execSync(`git sparse-checkout set ${sparsePaths.map(p => `"${p}"`).join(' ')}`, {
|
|
146
|
+
cwd: awHome,
|
|
147
|
+
stdio: 'pipe',
|
|
148
|
+
encoding: 'utf8',
|
|
149
|
+
});
|
|
150
|
+
execSync(`git checkout ${REGISTRY_BASE_BRANCH}`, {
|
|
151
|
+
cwd: awHome,
|
|
152
|
+
stdio: 'pipe',
|
|
153
|
+
encoding: 'utf8',
|
|
154
|
+
});
|
|
136
155
|
} catch (e) {
|
|
137
156
|
throw new Error(`Failed to configure sparse checkout: ${e.message}`);
|
|
138
157
|
}
|
package/mcp.mjs
CHANGED
|
@@ -168,8 +168,16 @@ async function resolveClickUpToken(silent = false, cwd = process.cwd()) {
|
|
|
168
168
|
return existing.token;
|
|
169
169
|
}
|
|
170
170
|
|
|
171
|
-
// In silent mode (git hooks, auto-pull) there is no terminal — skip prompt
|
|
172
|
-
|
|
171
|
+
// In silent mode (git hooks, auto-pull) there is no terminal — skip prompt.
|
|
172
|
+
// Also skip in any non-TTY context so automation and CI runs never crash
|
|
173
|
+
// while trying to render interactive prompts for an optional integration.
|
|
174
|
+
const hasInteractiveTty = Boolean(process.stdin.isTTY && process.stdout.isTTY);
|
|
175
|
+
if (silent || !hasInteractiveTty) {
|
|
176
|
+
if (!silent && !hasInteractiveTty) {
|
|
177
|
+
fmt.logInfo('Skipping ClickUp setup — no interactive terminal detected');
|
|
178
|
+
}
|
|
179
|
+
return null;
|
|
180
|
+
}
|
|
173
181
|
|
|
174
182
|
// 3. Ask first — don't assume the user wants ClickUp
|
|
175
183
|
const wantsClickUp = await p.select({
|