@ghl-ai/aw 0.1.47-beta.10 → 0.1.47-beta.11

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/push.mjs CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  import {
4
4
  existsSync,
5
+ lstatSync,
5
6
  statSync,
6
7
  readFileSync,
7
8
  appendFileSync,
@@ -36,6 +37,7 @@ import {
36
37
  AW_DOCS_PUBLISH_DIR,
37
38
  AW_DOCS_PUBLIC_BASE_URL,
38
39
  AW_CO_AUTHOR,
40
+ defaultAwDocsGithubDocsConfig,
39
41
  } from '../constants.mjs';
40
42
  import { resolveInput } from '../paths.mjs';
41
43
  import { walkRegistryTree, getAllFiles } from '../registry.mjs';
@@ -172,6 +174,34 @@ function readAwDocsConfig(projectRoot) {
172
174
  }
173
175
  }
174
176
 
177
+ function writeAwDocsConfigIfChanged(projectRoot, config) {
178
+ const configPath = join(projectRoot, AW_DOCS_DIR, 'config.json');
179
+ const nextText = JSON.stringify(config, null, 2) + '\n';
180
+ const existingText = existsSync(configPath) ? readFileSync(configPath, 'utf8') : '';
181
+ if (existingText !== nextText) {
182
+ mkdirSync(dirname(configPath), { recursive: true });
183
+ writeFileSync(configPath, nextText);
184
+ }
185
+ }
186
+
187
+ function ensureAwDocsPublishConfig(projectRoot) {
188
+ const config = readAwDocsConfig(projectRoot);
189
+ const defaultGithubDocs = defaultAwDocsGithubDocsConfig();
190
+ const next = {
191
+ ...config,
192
+ sync: {
193
+ ...(config.sync || {}),
194
+ github_docs: {
195
+ ...defaultGithubDocs,
196
+ ...(config.sync?.github_docs || {}),
197
+ },
198
+ },
199
+ };
200
+
201
+ writeAwDocsConfigIfChanged(projectRoot, next);
202
+ return next;
203
+ }
204
+
175
205
  function repoCloneUrl(repo) {
176
206
  const value = String(repo || '').trim();
177
207
  if (!value) return AW_DOCS_URL;
@@ -180,7 +210,7 @@ function repoCloneUrl(repo) {
180
210
  }
181
211
 
182
212
  function resolveAwDocsPublishConfig(projectRoot) {
183
- const config = readAwDocsConfig(projectRoot);
213
+ const config = ensureAwDocsPublishConfig(projectRoot);
184
214
  const githubDocs = config.sync?.github_docs || {};
185
215
  const repo = process.env.AW_DOCS_REPO || githubDocs.repo || AW_DOCS_REPO;
186
216
  const branch = AW_DOCS_BASE_BRANCH;
@@ -201,6 +231,24 @@ function resolveAwDocsPublishConfig(projectRoot) {
201
231
  };
202
232
  }
203
233
 
234
+ function isOnlyUntrackedAwSymlink(status, cloneDir) {
235
+ const lines = status.trim().split('\n').filter(Boolean);
236
+ if (lines.length !== 1 || !/^\?\?\s+\.aw\/?$/.test(lines[0])) return false;
237
+ try {
238
+ return lstatSync(join(cloneDir, '.aw')).isSymbolicLink();
239
+ } catch {
240
+ return false;
241
+ }
242
+ }
243
+
244
+ async function getGitStatus(repoDir) {
245
+ const { stdout } = await execFile('git', ['status', '--porcelain'], {
246
+ cwd: repoDir,
247
+ encoding: 'utf8',
248
+ });
249
+ return stdout;
250
+ }
251
+
204
252
  function parseGitHubRepo(remoteUrl) {
205
253
  const match = remoteUrl.trim().match(/github\.com[:/]([^/]+)\/(.+?)(?:\.git)?$/);
206
254
  if (!match) return null;
@@ -249,12 +297,17 @@ async function ensureAwDocsRepoClone(home, publishConfig) {
249
297
  });
250
298
  }
251
299
 
252
- const { stdout: status } = await execFile('git', ['status', '--porcelain'], {
253
- cwd: cloneDir,
254
- encoding: 'utf8',
255
- });
300
+ let status = await getGitStatus(cloneDir);
301
+ if (status.trim() && isOnlyUntrackedAwSymlink(status, cloneDir)) {
302
+ rmSync(join(cloneDir, '.aw'), { force: true });
303
+ status = await getGitStatus(cloneDir);
304
+ }
256
305
  if (status.trim()) {
257
- throw new Error(`AW docs repo worktree is dirty: ${cloneDir}`);
306
+ throw new Error([
307
+ `AW docs repo worktree is dirty: ${cloneDir}`,
308
+ status.trim(),
309
+ 'Clean the cached docs repo or set AW_DOCS_WORKTREE to a clean clone before publishing.',
310
+ ].join('\n'));
258
311
  }
259
312
 
260
313
  await execFile('git', ['fetch', 'origin'], {
package/constants.mjs CHANGED
@@ -34,6 +34,14 @@ export const AW_DOCS_SEED_BRANCH = process.env.AW_DOCS_SEED_BRANCH || 'scaffold'
34
34
  export const AW_DOCS_PUBLISH_DIR = 'aw_docs';
35
35
  export const AW_DOCS_PUBLIC_BASE_URL = process.env.AW_DOCS_PUBLIC_BASE_URL || `https://github.com/${AW_DOCS_REPO}/blob/${AW_DOCS_BASE_BRANCH}`;
36
36
 
37
+ export function defaultAwDocsGithubDocsConfig() {
38
+ return {
39
+ enabled: true,
40
+ repo: AW_DOCS_REPO,
41
+ dest: AW_DOCS_PUBLISH_DIR,
42
+ };
43
+ }
44
+
37
45
  /** Persistent git clone root — ~/.aw/ */
38
46
  export const AW_HOME = join(homedir(), '.aw');
39
47
 
package/integrate.mjs CHANGED
@@ -13,6 +13,10 @@ import {
13
13
  resolveRulesSourceDir,
14
14
  } from './render-rules.mjs';
15
15
  import { isDefaultRoutingEnabled } from './startup.mjs';
16
+ import {
17
+ AW_DOCS_DIR,
18
+ defaultAwDocsGithubDocsConfig,
19
+ } from './constants.mjs';
16
20
 
17
21
  const AW_ROUTER_BRIDGE_HEADER = 'AW Router Bridge';
18
22
  const AW_ROUTER_BRIDGE_START_MARKER = '<!-- aw-managed:start router-bridge -->';
@@ -610,14 +614,14 @@ Run with: \`/platform:eval agent:<slug>\` or \`/platform:eval skill:<slug>\`
610
614
  * Creates run tracking, learnings, task board, and cache directories.
611
615
  */
612
616
  export function initAwDocs(cwd) {
613
- const awDocsDir = join(cwd, '.aw_docs');
614
- if (existsSync(awDocsDir)) return; // Already initialized
617
+ const awDocsDir = join(cwd, AW_DOCS_DIR);
618
+ const alreadyInitialized = existsSync(awDocsDir);
615
619
 
616
620
  const dirs = [
617
- '.aw_docs/runs',
618
- '.aw_docs/learnings',
619
- '.aw_docs/tasks',
620
- '.aw_docs/cache',
621
+ `${AW_DOCS_DIR}/runs`,
622
+ `${AW_DOCS_DIR}/learnings`,
623
+ `${AW_DOCS_DIR}/tasks`,
624
+ `${AW_DOCS_DIR}/cache`,
621
625
  ];
622
626
 
623
627
  for (const dir of dirs) {
@@ -625,7 +629,9 @@ export function initAwDocs(cwd) {
625
629
  }
626
630
 
627
631
  // STATE.md — workspace state
628
- writeFileSync(join(awDocsDir, 'STATE.md'), `---
632
+ const statePath = join(awDocsDir, 'STATE.md');
633
+ if (!existsSync(statePath)) {
634
+ writeFileSync(statePath, `---
629
635
  active_run: null
630
636
  last_run: null
631
637
  last_workflow: null
@@ -638,24 +644,60 @@ pending_sync_count: 0
638
644
 
639
645
  No active runs. Use \`/aw:<team>-<command>\` to start a workflow.
640
646
  `);
647
+ }
641
648
 
642
649
  // config.json — registry paths, sync settings
643
- writeFileSync(join(awDocsDir, 'config.json'), JSON.stringify({
650
+ const configPath = join(awDocsDir, 'config.json');
651
+ const defaultConfig = {
644
652
  sync: {
645
653
  eager: true,
646
654
  batch_threshold: 10,
647
655
  mcp_memory_enabled: true,
656
+ github_docs: defaultAwDocsGithubDocsConfig(),
648
657
  },
649
658
  paths: {
650
- runs: '.aw_docs/runs',
651
- learnings: '.aw_docs/learnings',
652
- tasks: '.aw_docs/tasks',
653
- cache: '.aw_docs/cache',
659
+ runs: `${AW_DOCS_DIR}/runs`,
660
+ learnings: `${AW_DOCS_DIR}/learnings`,
661
+ tasks: `${AW_DOCS_DIR}/tasks`,
662
+ cache: `${AW_DOCS_DIR}/cache`,
654
663
  },
655
- }, null, 2) + '\n');
664
+ };
665
+ let nextConfig = defaultConfig;
666
+ if (existsSync(configPath)) {
667
+ try {
668
+ const existing = JSON.parse(readFileSync(configPath, 'utf8'));
669
+ nextConfig = {
670
+ ...existing,
671
+ sync: {
672
+ ...defaultConfig.sync,
673
+ ...(existing.sync || {}),
674
+ github_docs: {
675
+ ...defaultConfig.sync.github_docs,
676
+ ...(existing.sync?.github_docs || {}),
677
+ },
678
+ },
679
+ paths: {
680
+ ...defaultConfig.paths,
681
+ ...(existing.paths || {}),
682
+ },
683
+ };
684
+ } catch (e) {
685
+ fmt.logWarn(`Could not migrate ${AW_DOCS_DIR}/config.json: ${e.message}`);
686
+ nextConfig = null;
687
+ }
688
+ }
689
+ if (nextConfig) {
690
+ const nextConfigText = JSON.stringify(nextConfig, null, 2) + '\n';
691
+ const existingText = existsSync(configPath) ? readFileSync(configPath, 'utf8') : '';
692
+ if (existingText !== nextConfigText) {
693
+ writeFileSync(configPath, nextConfigText);
694
+ }
695
+ }
656
696
 
657
697
  // BOARD.md — task board
658
- writeFileSync(join(awDocsDir, 'tasks', 'BOARD.md'), `---
698
+ const boardPath = join(awDocsDir, 'tasks', 'BOARD.md');
699
+ if (!existsSync(boardPath)) {
700
+ writeFileSync(boardPath, `---
659
701
  tasks: []
660
702
  updated_at: null
661
703
  ---
@@ -664,11 +706,17 @@ updated_at: null
664
706
 
665
707
  No active tasks. Tasks are created during workflow execution.
666
708
  `);
709
+ }
667
710
 
668
711
  // _pending-sync.jsonl — sync queue (empty)
669
- writeFileSync(join(awDocsDir, 'learnings', '_pending-sync.jsonl'), '');
712
+ const pendingSyncPath = join(awDocsDir, 'learnings', '_pending-sync.jsonl');
713
+ if (!existsSync(pendingSyncPath)) {
714
+ writeFileSync(pendingSyncPath, '');
715
+ }
670
716
 
671
- fmt.logSuccess('Orchestration state ready');
717
+ if (!alreadyInitialized) {
718
+ fmt.logSuccess('Orchestration state ready');
719
+ }
672
720
  }
673
721
 
674
722
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ghl-ai/aw",
3
- "version": "0.1.47-beta.10",
3
+ "version": "0.1.47-beta.11",
4
4
  "description": "Agentic Workspace CLI — pull, push & manage agents, skills and commands from the registry",
5
5
  "type": "module",
6
6
  "bin": {