@ghl-ai/aw 0.1.37-beta.6 → 0.1.37-beta.60

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/cli.mjs CHANGED
@@ -4,7 +4,7 @@ import { readFileSync } from 'node:fs';
4
4
  import { join, dirname } from 'node:path';
5
5
  import { fileURLToPath } from 'node:url';
6
6
  import * as fmt from './fmt.mjs';
7
- import { chalk } from './fmt.mjs';
7
+ import { chalk, CancelError } from './fmt.mjs';
8
8
  import { checkForUpdate, notifyUpdate } from './update.mjs';
9
9
  import { startSpan } from './telemetry.mjs';
10
10
 
@@ -15,6 +15,7 @@ const COMMANDS = {
15
15
  init: () => import('./commands/init.mjs').then(m => m.initCommand),
16
16
  pull: () => import('./commands/pull.mjs').then(m => m.pullCommand),
17
17
  push: () => import('./commands/push.mjs').then(m => m.pushCommand),
18
+ 'push-rules': () => import('./commands/push-rules.mjs').then(m => m.pushRulesCommand),
18
19
  drop: () => import('./commands/drop.mjs').then(m => m.dropCommand),
19
20
  status: () => import('./commands/status.mjs').then(m => m.statusCommand),
20
21
  search: () => import('./commands/search.mjs').then(m => m.searchCommand),
@@ -22,6 +23,7 @@ const COMMANDS = {
22
23
  nuke: () => import('./commands/nuke.mjs').then(m => m.nukeCommand),
23
24
  daemon: () => import('./commands/daemon.mjs').then(m => m.daemonCommand),
24
25
  telemetry: () => import('./commands/telemetry.mjs').then(m => m.telemetryCommand),
26
+ memory: () => import('./commands/memory.mjs').then(m => m.memoryCommand),
25
27
  };
26
28
 
27
29
  function parseArgs(argv) {
@@ -88,6 +90,7 @@ function printHelp() {
88
90
  sec('Upload'),
89
91
  cmd('aw push', 'Push all modified files (creates one PR)'),
90
92
  cmd('aw push <path>', 'Push file, folder, or namespace to registry'),
93
+ cmd('aw push-rules [path]', 'Push platform rules to platform-docs'),
91
94
  cmd('aw push --dry-run [path]', 'Preview what would be pushed'),
92
95
 
93
96
  sec('Discover'),
@@ -103,6 +106,12 @@ function printHelp() {
103
106
  cmd('aw daemon uninstall', 'Stop the background daemon'),
104
107
  cmd('aw daemon status', 'Check if daemon is running'),
105
108
 
109
+ sec('Memory'),
110
+ cmd('aw memory store <content>', 'Store a memory (curated)'),
111
+ cmd('aw memory search <query>', 'Search memories'),
112
+ cmd('aw memory pack <query>', 'Get a memory pack (token-budgeted)'),
113
+ cmd('aw memory stats', 'Show memory statistics'),
114
+
106
115
  sec('Settings'),
107
116
  cmd('aw telemetry status', 'Show telemetry status'),
108
117
  cmd('aw telemetry disable', 'Opt out of anonymous analytics'),
@@ -122,6 +131,8 @@ function printHelp() {
122
131
  cmd('aw push .aw_registry/<team>/', 'Push entire namespace (one PR)'),
123
132
  cmd('aw push .aw_registry/agents/<name>.md', 'Push a single agent'),
124
133
  cmd('aw push .aw_registry/skills/<name>/', 'Push a single skill folder'),
134
+ cmd('aw push .aw_rules', 'Auto-redirects to aw push-rules'),
135
+ cmd('aw push-rules', 'Pushes .aw_rules or .aw_registry/.aw_rules'),
125
136
  '',
126
137
  ` ${chalk.dim('# Remove content from workspace')}`,
127
138
  cmd('aw drop <team>', 'Stop syncing a namespace (removes all files)'),
@@ -154,7 +165,7 @@ export async function run(argv) {
154
165
  }
155
166
 
156
167
  if (command && COMMANDS[command]) {
157
- const span = startSpan(command, args);
168
+ const span = await startSpan(command, args);
158
169
  span.notice();
159
170
  args._updateCheck = updateCheck;
160
171
  try {
@@ -162,6 +173,10 @@ export async function run(argv) {
162
173
  await handler(args);
163
174
  await span.end({ status: 'completed' });
164
175
  } catch (err) {
176
+ if (err instanceof CancelError) {
177
+ await span.end({ status: 'cancelled', error_type: 'CancelError' });
178
+ process.exit(err.exitCode ?? 1);
179
+ }
165
180
  await span.end({ status: 'failed', error_type: err.constructor.name });
166
181
  throw err;
167
182
  }
@@ -174,5 +189,5 @@ export async function run(argv) {
174
189
  process.exit(0);
175
190
  }
176
191
 
177
- fmt.cancel(`Unknown command: ${command}`);
192
+ fmt.cancelAndExit(`Unknown command: ${command}`);
178
193
  }
package/commands/init.mjs CHANGED
@@ -4,7 +4,18 @@
4
4
  // Uses core.hooksPath (git-lfs pattern) for system-wide hook interception.
5
5
  // Uses IDE tasks for auto-pull on workspace open.
6
6
 
7
- import { existsSync, writeFileSync, symlinkSync, lstatSync, readdirSync, readFileSync, rmSync, realpathSync, appendFileSync } from 'node:fs';
7
+ import {
8
+ existsSync,
9
+ mkdirSync,
10
+ writeFileSync,
11
+ symlinkSync,
12
+ lstatSync,
13
+ readdirSync,
14
+ readFileSync,
15
+ rmSync,
16
+ realpathSync,
17
+ appendFileSync,
18
+ } from 'node:fs';
8
19
  import { execSync } from 'node:child_process';
9
20
  import { join, dirname, sep } from 'node:path';
10
21
  import { homedir } from 'node:os';
@@ -15,6 +26,7 @@ import { chalk } from '../fmt.mjs';
15
26
  import { linkWorkspace } from '../link.mjs';
16
27
  import { generateCommands, copyInstructions, initAwDocs } from '../integrate.mjs';
17
28
  import { setupMcp } from '../mcp.mjs';
29
+ import { installLocalCommitHook } from '../hooks.mjs';
18
30
  import { autoUpdate, promptUpdate } from '../update.mjs';
19
31
  import { installGlobalHooks } from '../hooks.mjs';
20
32
  import { installAwEcc } from '../ecc.mjs';
@@ -31,7 +43,8 @@ import {
31
43
  syncWorktreeSparseCheckout,
32
44
  findNearestWorktree,
33
45
  } from '../git.mjs';
34
- import { REGISTRY_DIR, REGISTRY_REPO, REGISTRY_URL } from '../constants.mjs';
46
+ import { REGISTRY_DIR, REGISTRY_REPO, REGISTRY_URL, RULES_SOURCE_DIR } from '../constants.mjs';
47
+ import { syncFileTree } from '../file-tree.mjs';
35
48
 
36
49
  const __dirname = dirname(fileURLToPath(import.meta.url));
37
50
  const VERSION = JSON.parse(readFileSync(join(__dirname, '..', 'package.json'), 'utf8')).version;
@@ -195,7 +208,7 @@ export async function initCommand(args) {
195
208
  }
196
209
 
197
210
  if (choice === 'platform-only') {
198
- namespace = null; team = null; subTeam = null; folderName = null;
211
+ namespace = 'platform'; team = 'platform'; subTeam = null; folderName = null;
199
212
  }
200
213
  }
201
214
 
@@ -210,7 +223,7 @@ export async function initCommand(args) {
210
223
  const isNewSubTeam = folderName && cfg && !cfg.include.includes(folderName);
211
224
  if (isNewSubTeam) {
212
225
  if (!silent) fmt.logStep(`Adding sub-team ${chalk.cyan(folderName)}...`);
213
- const newSparsePaths = [`.aw_registry/${folderName}`, `content`];
226
+ const newSparsePaths = [`.aw_registry/${folderName}`, 'content', RULES_SOURCE_DIR];
214
227
  addToSparseCheckout(AW_HOME, newSparsePaths);
215
228
  config.addPattern(GLOBAL_AW_DIR, folderName);
216
229
  } else {
@@ -234,7 +247,11 @@ export async function initCommand(args) {
234
247
  }
235
248
 
236
249
  ensureAwGitignore(AW_HOME);
250
+ mkdirSync(join(GLOBAL_AW_DIR, 'memory'), { recursive: true });
237
251
  const freshCfg = config.load(GLOBAL_AW_DIR);
252
+ if (existsSync(GLOBAL_AW_DIR)) {
253
+ syncFileTree(join(AW_HOME, RULES_SOURCE_DIR), join(GLOBAL_AW_DIR, RULES_SOURCE_DIR));
254
+ }
238
255
 
239
256
  // Ensure project worktree sparse checkout matches the global clone.
240
257
  // Covers the case where a namespace was added from HOME (or another project)
@@ -279,6 +296,7 @@ export async function initCommand(args) {
279
296
  const awDirForLinks = (projectRegistryDir && existsSync(projectRegistryDir)) ? projectRegistryDir : null;
280
297
  const symlinks = linkWorkspace(HOME, awDirForLinks, { silent: true });
281
298
  const commands = generateCommands(HOME, { silent: true });
299
+ if (cwd !== HOME) installLocalCommitHook(cwd);
282
300
 
283
301
  if (silent) {
284
302
  autoUpdate(await args._updateCheck);
@@ -317,7 +335,7 @@ export async function initCommand(args) {
317
335
  }
318
336
 
319
337
  // Determine sparse paths
320
- const sparsePaths = [`.aw_registry/platform`, `content`, `.aw_registry/AW-PROTOCOL.md`, `CODEOWNERS`];
338
+ const sparsePaths = [`.aw_registry/platform`, `content`, RULES_SOURCE_DIR, `.aw_registry/AW-PROTOCOL.md`, `CODEOWNERS`];
321
339
  if (folderName) {
322
340
  sparsePaths.push(`.aw_registry/${folderName}`);
323
341
  }
@@ -363,11 +381,17 @@ export async function initCommand(args) {
363
381
  }
364
382
  }
365
383
 
366
- // Create sync config
367
- const cfg = config.create(GLOBAL_AW_DIR, { namespace: team, user });
384
+ // Create memory dir after symlink so GLOBAL_AW_DIR resolves correctly
385
+ mkdirSync(join(GLOBAL_AW_DIR, 'memory'), { recursive: true });
386
+
387
+ // Create sync config — default to 'platform' when no namespace specified
388
+ const cfg = config.create(GLOBAL_AW_DIR, { namespace: team || 'platform', user });
368
389
  if (folderName) {
369
390
  config.addPattern(GLOBAL_AW_DIR, folderName);
370
391
  }
392
+ if (existsSync(GLOBAL_AW_DIR)) {
393
+ syncFileTree(join(AW_HOME, RULES_SOURCE_DIR), join(GLOBAL_AW_DIR, RULES_SOURCE_DIR));
394
+ }
371
395
 
372
396
  // Step 3: Setup tasks, MCP, hooks
373
397
  await installAwEcc(cwd, { silent });
@@ -406,6 +430,7 @@ export async function initCommand(args) {
406
430
  const projectRegistryDir = cwd !== HOME ? join(cwd, '.aw', REGISTRY_DIR) : null;
407
431
  const awDirForLinks = (projectRegistryDir && existsSync(projectRegistryDir)) ? projectRegistryDir : null;
408
432
  const symlinks = linkWorkspace(HOME, awDirForLinks, { silent: true });
433
+ if (cwd !== HOME) installLocalCommitHook(cwd);
409
434
  ideSpinner.message('Generating commands...');
410
435
  const commands = generateCommands(HOME, { silent: true });
411
436
  ideSpinner.stop(`IDE wired — ${chalk.bold(symlinks)} symlinks · ${chalk.bold(commands)} commands`);
@@ -9,6 +9,7 @@ import { addProjectWorktree, isWorktree, isValidClone } from '../git.mjs';
9
9
  import { REGISTRY_DIR, REGISTRY_URL } from '../constants.mjs';
10
10
  import { linkWorkspace } from '../link.mjs';
11
11
  import { generateCommands } from '../integrate.mjs';
12
+ import { installLocalCommitHook } from '../hooks.mjs';
12
13
 
13
14
  const HOME = homedir();
14
15
  const AW_HOME = join(HOME, '.aw');
@@ -40,6 +41,7 @@ export function linkProjectCommand(args) {
40
41
  const awDirForLinks = existsSync(projectRegistryDir) ? projectRegistryDir : null;
41
42
  const symlinks = linkWorkspace(HOME, awDirForLinks, { silent: true });
42
43
  const commands = generateCommands(HOME, { silent: true });
44
+ installLocalCommitHook(cwd);
43
45
  fmt.logSuccess(`Already linked — refreshed ${chalk.bold(symlinks)} IDE symlinks · ${chalk.bold(commands)} commands`);
44
46
  return;
45
47
  }
@@ -50,6 +52,7 @@ export function linkProjectCommand(args) {
50
52
  const awDirForLinks = existsSync(projectRegistryDir) ? projectRegistryDir : null;
51
53
  const symlinks = linkWorkspace(HOME, awDirForLinks, { silent: true });
52
54
  const commands = generateCommands(HOME, { silent: true });
55
+ installLocalCommitHook(cwd);
53
56
  fmt.logSuccess([
54
57
  `Project linked — ${chalk.bold(symlinks)} IDE symlinks · ${chalk.bold(commands)} commands`,
55
58
  '',