@ghl-ai/aw 0.1.36-beta.3 → 0.1.36-beta.4
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/drop.mjs +2 -2
- package/commands/init.mjs +4 -4
- package/commands/link-project.mjs +3 -10
- package/commands/push.mjs +2 -1
- package/commands/search.mjs +3 -2
- package/git.mjs +21 -22
- package/hooks.mjs +2 -3
- package/integrate.mjs +3 -1
- package/link.mjs +3 -1
- package/package.json +1 -1
package/commands/drop.mjs
CHANGED
|
@@ -7,7 +7,7 @@ import * as config from '../config.mjs';
|
|
|
7
7
|
import * as fmt from '../fmt.mjs';
|
|
8
8
|
import { chalk } from '../fmt.mjs';
|
|
9
9
|
import { resolveInput } from '../paths.mjs';
|
|
10
|
-
import { removeFromSparseCheckout, isValidClone } from '../git.mjs';
|
|
10
|
+
import { removeFromSparseCheckout, isValidClone, getLocalRegistryDir } from '../git.mjs';
|
|
11
11
|
import { REGISTRY_DIR, REGISTRY_REPO } from '../constants.mjs';
|
|
12
12
|
import { linkWorkspace } from '../link.mjs';
|
|
13
13
|
|
|
@@ -18,7 +18,7 @@ export function dropCommand(args) {
|
|
|
18
18
|
const HOME = homedir();
|
|
19
19
|
const AW_HOME = join(HOME, '.aw');
|
|
20
20
|
const GLOBAL_AW_DIR = join(HOME, '.aw_registry');
|
|
21
|
-
const workspaceDir =
|
|
21
|
+
const workspaceDir = getLocalRegistryDir(cwd, GLOBAL_AW_DIR);
|
|
22
22
|
|
|
23
23
|
fmt.intro('aw drop');
|
|
24
24
|
|
package/commands/init.mjs
CHANGED
|
@@ -205,7 +205,7 @@ export async function initCommand(args) {
|
|
|
205
205
|
if (cwd !== HOME) await setupMcp(cwd, freshCfg?.namespace || team, { silent });
|
|
206
206
|
installGlobalHooks();
|
|
207
207
|
|
|
208
|
-
if (cwd !== HOME && !
|
|
208
|
+
if (cwd !== HOME && !isWorktree(join(cwd, '.aw'))) {
|
|
209
209
|
try {
|
|
210
210
|
addProjectWorktree(AW_HOME, cwd);
|
|
211
211
|
if (!silent) fmt.logStep('Linked current project as git worktree');
|
|
@@ -220,7 +220,7 @@ export async function initCommand(args) {
|
|
|
220
220
|
'',
|
|
221
221
|
` ${chalk.green('✓')} Registry updated`,
|
|
222
222
|
` ${chalk.green('✓')} IDE integration refreshed`,
|
|
223
|
-
cwd !== HOME &&
|
|
223
|
+
cwd !== HOME && isWorktree(join(cwd, '.aw')) ? ` ${chalk.green('✓')} Current project linked` : null,
|
|
224
224
|
].filter(Boolean).join('\n'));
|
|
225
225
|
}
|
|
226
226
|
return;
|
|
@@ -301,7 +301,7 @@ export async function initCommand(args) {
|
|
|
301
301
|
installIdeTasks();
|
|
302
302
|
|
|
303
303
|
// Step 4: Link current project as a git worktree (gives IDE git panel)
|
|
304
|
-
if (cwd !== HOME && !
|
|
304
|
+
if (cwd !== HOME && !isWorktree(join(cwd, '.aw'))) {
|
|
305
305
|
try {
|
|
306
306
|
addProjectWorktree(AW_HOME, cwd);
|
|
307
307
|
fmt.logStep('Linked current project as git worktree');
|
|
@@ -319,7 +319,7 @@ export async function initCommand(args) {
|
|
|
319
319
|
` ${chalk.green('✓')} IDE integration: ~/.claude/, ~/.cursor/, ~/.codex/`,
|
|
320
320
|
hooksInstalled ? ` ${chalk.green('✓')} Git hooks: auto-sync on pull/clone (core.hooksPath)` : null,
|
|
321
321
|
` ${chalk.green('✓')} IDE task: auto-sync on workspace open`,
|
|
322
|
-
cwd !== HOME &&
|
|
322
|
+
cwd !== HOME && isWorktree(join(cwd, '.aw')) ? ` ${chalk.green('✓')} Linked in current project` : null,
|
|
323
323
|
'',
|
|
324
324
|
` ${chalk.dim('Existing repos:')} ${chalk.bold('cd <project> && aw link')}`,
|
|
325
325
|
` ${chalk.dim('New clones:')} auto-linked via git hook`,
|
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
// commands/link-project.mjs — Link current project to registry via git worktree
|
|
2
2
|
|
|
3
|
-
import { existsSync } from 'node:fs';
|
|
4
3
|
import { join } from 'node:path';
|
|
5
4
|
import { homedir } from 'node:os';
|
|
6
5
|
import * as fmt from '../fmt.mjs';
|
|
7
6
|
import { chalk } from '../fmt.mjs';
|
|
8
7
|
import { addProjectWorktree, isWorktree, isValidClone } from '../git.mjs';
|
|
9
|
-
import { REGISTRY_REPO } from '../constants.mjs';
|
|
8
|
+
import { REGISTRY_DIR, REGISTRY_REPO } from '../constants.mjs';
|
|
10
9
|
|
|
11
10
|
const HOME = homedir();
|
|
12
11
|
const AW_HOME = join(HOME, '.aw');
|
|
@@ -28,25 +27,19 @@ export function linkProjectCommand(args) {
|
|
|
28
27
|
}
|
|
29
28
|
|
|
30
29
|
const worktreeDir = join(cwd, '.aw');
|
|
31
|
-
const registryLink = join(cwd, '.aw_registry');
|
|
32
30
|
|
|
33
31
|
if (isWorktree(worktreeDir)) {
|
|
34
32
|
fmt.logSuccess(`Already linked — ${chalk.dim('.aw/')} is a git worktree`);
|
|
35
33
|
return;
|
|
36
34
|
}
|
|
37
35
|
|
|
38
|
-
if (existsSync(registryLink)) {
|
|
39
|
-
fmt.logSuccess('.aw_registry already exists in this project');
|
|
40
|
-
return;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
36
|
try {
|
|
44
37
|
addProjectWorktree(AW_HOME, cwd);
|
|
45
38
|
fmt.logSuccess([
|
|
46
39
|
`Linked project as git worktree`,
|
|
47
40
|
'',
|
|
48
|
-
` ${chalk.green('✓')} ${chalk.dim('.aw/')}
|
|
49
|
-
` ${chalk.green('✓')} ${chalk.dim(
|
|
41
|
+
` ${chalk.green('✓')} ${chalk.dim('.aw/')} git worktree (IDE git panel enabled)`,
|
|
42
|
+
` ${chalk.green('✓')} ${chalk.dim(`.aw/${REGISTRY_DIR}/`)} registry content`,
|
|
50
43
|
].join('\n'));
|
|
51
44
|
} catch (e) {
|
|
52
45
|
fmt.cancel(`Failed to link project: ${e.message}`);
|
package/commands/push.mjs
CHANGED
|
@@ -16,6 +16,7 @@ import {
|
|
|
16
16
|
getCurrentBranch,
|
|
17
17
|
isValidClone,
|
|
18
18
|
isWorktree,
|
|
19
|
+
getLocalRegistryDir,
|
|
19
20
|
} from '../git.mjs';
|
|
20
21
|
|
|
21
22
|
const PUSHABLE_TYPES = ['agents', 'skills', 'commands', 'evals'];
|
|
@@ -355,7 +356,7 @@ export function pushCommand(args) {
|
|
|
355
356
|
const hasWorktree = isWorktree(localAw);
|
|
356
357
|
const awHome = hasWorktree ? localAw : globalAw;
|
|
357
358
|
const registrySubDir = join(awHome, REGISTRY_DIR);
|
|
358
|
-
const workspaceDir =
|
|
359
|
+
const workspaceDir = getLocalRegistryDir(cwd, join(HOME, '.aw_registry'));
|
|
359
360
|
|
|
360
361
|
// Save current worktree branch so we can restore it after push
|
|
361
362
|
const worktreeBranch = hasWorktree ? getCurrentBranch(awHome) : null;
|
package/commands/search.mjs
CHANGED
|
@@ -2,12 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
import { readFileSync, existsSync, readdirSync, statSync, mkdtempSync } from 'node:fs';
|
|
4
4
|
import { join } from 'node:path';
|
|
5
|
-
import { tmpdir } from 'node:os';
|
|
5
|
+
import { tmpdir, homedir } from 'node:os';
|
|
6
6
|
import { execSync } from 'node:child_process';
|
|
7
7
|
import * as config from '../config.mjs';
|
|
8
8
|
import * as fmt from '../fmt.mjs';
|
|
9
9
|
import { chalk } from '../fmt.mjs';
|
|
10
10
|
import { REGISTRY_BASE_BRANCH, REGISTRY_REPO, REGISTRY_DIR } from '../constants.mjs';
|
|
11
|
+
import { getLocalRegistryDir } from '../git.mjs';
|
|
11
12
|
|
|
12
13
|
export function searchCommand(args) {
|
|
13
14
|
const query = (args._positional || []).join(' ').toLowerCase();
|
|
@@ -19,7 +20,7 @@ export function searchCommand(args) {
|
|
|
19
20
|
fmt.intro('aw search');
|
|
20
21
|
|
|
21
22
|
const cwd = process.cwd();
|
|
22
|
-
const workspaceDir =
|
|
23
|
+
const workspaceDir = getLocalRegistryDir(cwd, join(homedir(), '.aw_registry'));
|
|
23
24
|
|
|
24
25
|
// ── Local search ──
|
|
25
26
|
const localResults = searchLocal(workspaceDir, query);
|
package/git.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// git.mjs — Git helpers: sparse checkout (temp) + persistent clone operations.
|
|
2
2
|
|
|
3
3
|
import { execSync, exec as execCb } from 'node:child_process';
|
|
4
|
-
import { mkdtempSync, existsSync, lstatSync,
|
|
4
|
+
import { mkdtempSync, existsSync, lstatSync, rmSync } from 'node:fs';
|
|
5
5
|
import { join, basename } from 'node:path';
|
|
6
6
|
import { tmpdir } from 'node:os';
|
|
7
7
|
import { promisify } from 'node:util';
|
|
@@ -28,7 +28,7 @@ export function sparseCheckout(repo, paths) {
|
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
try {
|
|
31
|
-
execSync('git sparse-checkout init --cone', { cwd: tempDir, stdio: 'pipe' });
|
|
31
|
+
execSync('git sparse-checkout init --no-cone', { cwd: tempDir, stdio: 'pipe' });
|
|
32
32
|
execSync(`git sparse-checkout set --skip-checks ${paths.map(p => `"${p}"`).join(' ')}`, {
|
|
33
33
|
cwd: tempDir, stdio: 'pipe',
|
|
34
34
|
});
|
|
@@ -55,7 +55,7 @@ export async function sparseCheckoutAsync(repo, paths) {
|
|
|
55
55
|
}
|
|
56
56
|
|
|
57
57
|
try {
|
|
58
|
-
await exec('git sparse-checkout init --cone', { cwd: tempDir });
|
|
58
|
+
await exec('git sparse-checkout init --no-cone', { cwd: tempDir });
|
|
59
59
|
await exec(`git sparse-checkout set --skip-checks ${paths.map(p => `"${p}"`).join(' ')}`, { cwd: tempDir });
|
|
60
60
|
await exec(`git checkout ${REGISTRY_BASE_BRANCH}`, { cwd: tempDir });
|
|
61
61
|
} catch (e) {
|
|
@@ -123,7 +123,7 @@ export function initPersistentClone(repoUrl, awHome, sparsePaths) {
|
|
|
123
123
|
}
|
|
124
124
|
|
|
125
125
|
try {
|
|
126
|
-
execSync('git sparse-checkout init --cone', { cwd: awHome, stdio: 'pipe' });
|
|
126
|
+
execSync('git sparse-checkout init --no-cone', { cwd: awHome, stdio: 'pipe' });
|
|
127
127
|
execSync(`git sparse-checkout set ${sparsePaths.map(p => `"${p}"`).join(' ')}`, { cwd: awHome, stdio: 'pipe' });
|
|
128
128
|
execSync(`git checkout ${REGISTRY_BASE_BRANCH}`, { cwd: awHome, stdio: 'pipe' });
|
|
129
129
|
} catch (e) {
|
|
@@ -327,6 +327,20 @@ export function checkoutMain(awHome) {
|
|
|
327
327
|
|
|
328
328
|
// ── Project worktree operations ────────────────────────────────────────────────
|
|
329
329
|
|
|
330
|
+
/**
|
|
331
|
+
* Resolve the registry directory for a given working directory.
|
|
332
|
+
*
|
|
333
|
+
* - If cwd/.aw/ is a linked worktree → returns cwd/.aw/.aw_registry/
|
|
334
|
+
* - Otherwise → returns fallback (usually ~/.aw_registry/)
|
|
335
|
+
*
|
|
336
|
+
* Works correctly when cwd is HOME: ~/.aw/ is the main clone (not a linked
|
|
337
|
+
* worktree), so isWorktree returns false and the global fallback is used.
|
|
338
|
+
*/
|
|
339
|
+
export function getLocalRegistryDir(cwd, fallback) {
|
|
340
|
+
if (isWorktree(join(cwd, '.aw'))) return join(cwd, '.aw', REGISTRY_DIR);
|
|
341
|
+
return fallback;
|
|
342
|
+
}
|
|
343
|
+
|
|
330
344
|
/**
|
|
331
345
|
* Check if dir is a git linked worktree (has .git as a FILE, not a directory).
|
|
332
346
|
*/
|
|
@@ -348,15 +362,9 @@ export function isWorktree(dir) {
|
|
|
348
362
|
*/
|
|
349
363
|
export function addProjectWorktree(awHome, projectDir) {
|
|
350
364
|
const worktreeDir = join(projectDir, '.aw');
|
|
351
|
-
const registryLink = join(projectDir, '.aw_registry');
|
|
352
365
|
|
|
353
|
-
// Already set up
|
|
354
|
-
if (isWorktree(worktreeDir))
|
|
355
|
-
if (!existsSync(registryLink)) {
|
|
356
|
-
symlinkSync(join('.aw', REGISTRY_DIR), registryLink);
|
|
357
|
-
}
|
|
358
|
-
return worktreeDir;
|
|
359
|
-
}
|
|
366
|
+
// Already set up
|
|
367
|
+
if (isWorktree(worktreeDir)) return worktreeDir;
|
|
360
368
|
|
|
361
369
|
const slug = basename(projectDir)
|
|
362
370
|
.toLowerCase()
|
|
@@ -388,7 +396,7 @@ export function addProjectWorktree(awHome, projectDir) {
|
|
|
388
396
|
|
|
389
397
|
// Set up sparse checkout in the worktree, mirroring the main clone's paths
|
|
390
398
|
try {
|
|
391
|
-
execSync(`git -C "${worktreeDir}" sparse-checkout init --cone`, { stdio: 'pipe' });
|
|
399
|
+
execSync(`git -C "${worktreeDir}" sparse-checkout init --no-cone`, { stdio: 'pipe' });
|
|
392
400
|
|
|
393
401
|
let sparsePaths = [];
|
|
394
402
|
try {
|
|
@@ -406,11 +414,6 @@ export function addProjectWorktree(awHome, projectDir) {
|
|
|
406
414
|
throw new Error(`Failed to configure worktree sparse checkout: ${e.message}`);
|
|
407
415
|
}
|
|
408
416
|
|
|
409
|
-
// Relative symlink: project/.aw_registry → .aw/.aw_registry
|
|
410
|
-
if (!existsSync(registryLink)) {
|
|
411
|
-
symlinkSync(join('.aw', REGISTRY_DIR), registryLink);
|
|
412
|
-
}
|
|
413
|
-
|
|
414
417
|
return worktreeDir;
|
|
415
418
|
}
|
|
416
419
|
|
|
@@ -420,10 +423,6 @@ export function addProjectWorktree(awHome, projectDir) {
|
|
|
420
423
|
*/
|
|
421
424
|
export function removeProjectWorktree(awHome, projectDir) {
|
|
422
425
|
const worktreeDir = join(projectDir, '.aw');
|
|
423
|
-
const registryLink = join(projectDir, '.aw_registry');
|
|
424
|
-
|
|
425
|
-
// Remove .aw_registry symlink
|
|
426
|
-
try { rmSync(registryLink, { force: true }); } catch { /* best effort */ }
|
|
427
426
|
|
|
428
427
|
// Remove via git first
|
|
429
428
|
try {
|
package/hooks.mjs
CHANGED
|
@@ -55,9 +55,8 @@ if command -v aw >/dev/null 2>&1; then
|
|
|
55
55
|
fi`);
|
|
56
56
|
|
|
57
57
|
const POST_CHECKOUT = makeDispatcher('post-checkout', `\
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
ln -s "$AW_REGISTRY" ".aw_registry" 2>/dev/null
|
|
58
|
+
if [ -d "$HOME/.aw" ] && [ ! -d ".aw" ] && [ -d ".git" ] && command -v aw >/dev/null 2>&1; then
|
|
59
|
+
aw link >/dev/null 2>&1 &
|
|
61
60
|
fi
|
|
62
61
|
if command -v aw >/dev/null 2>&1; then
|
|
63
62
|
aw init --silent >/dev/null 2>&1 &
|
package/integrate.mjs
CHANGED
|
@@ -2,15 +2,17 @@
|
|
|
2
2
|
|
|
3
3
|
import { existsSync, mkdirSync, writeFileSync, readFileSync, readdirSync, rmSync } from 'node:fs';
|
|
4
4
|
import { join } from 'node:path';
|
|
5
|
+
import { homedir } from 'node:os';
|
|
5
6
|
import * as fmt from './fmt.mjs';
|
|
6
7
|
import * as config from './config.mjs';
|
|
8
|
+
import { getLocalRegistryDir } from './git.mjs';
|
|
7
9
|
|
|
8
10
|
/**
|
|
9
11
|
* Count hand-written commands already present in the registry.
|
|
10
12
|
* No CLI stub generation — all commands come from the registry itself.
|
|
11
13
|
*/
|
|
12
14
|
export function generateCommands(cwd) {
|
|
13
|
-
const awDir =
|
|
15
|
+
const awDir = getLocalRegistryDir(cwd, join(homedir(), '.aw_registry'));
|
|
14
16
|
|
|
15
17
|
// Clean old .generated-commands if it exists (migration)
|
|
16
18
|
const oldGenDir = join(awDir, '.generated-commands');
|
package/link.mjs
CHANGED
|
@@ -4,6 +4,7 @@ import { existsSync, lstatSync, mkdirSync, readdirSync, unlinkSync, symlinkSync,
|
|
|
4
4
|
import { join, relative } from 'node:path';
|
|
5
5
|
import { homedir } from 'node:os';
|
|
6
6
|
import * as fmt from './fmt.mjs';
|
|
7
|
+
import { getLocalRegistryDir } from './git.mjs';
|
|
7
8
|
|
|
8
9
|
function forceSymlink(target, linkPath) {
|
|
9
10
|
try { unlinkSync(linkPath); } catch { /* not there yet */ }
|
|
@@ -126,7 +127,8 @@ function flatName(ns, name) {
|
|
|
126
127
|
* file content is resolved by LLMs at runtime using AW-PROTOCOL.md context.
|
|
127
128
|
*/
|
|
128
129
|
export function linkWorkspace(cwd) {
|
|
129
|
-
const
|
|
130
|
+
const GLOBAL_AW_DIR = join(homedir(), '.aw_registry');
|
|
131
|
+
const awDir = getLocalRegistryDir(cwd, GLOBAL_AW_DIR);
|
|
130
132
|
if (!existsSync(awDir)) return 0;
|
|
131
133
|
|
|
132
134
|
let created = 0;
|