@ghl-ai/aw 0.1.82 → 0.1.84

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.
Files changed (2) hide show
  1. package/commands/push.mjs +34 -12
  2. package/package.json +1 -1
package/commands/push.mjs CHANGED
@@ -416,26 +416,28 @@ function resolveAwDocsPublishConfig(projectRoot) {
416
416
  }
417
417
 
418
418
  async function removeTrackedAwSymlink(cloneDir) {
419
+ const awPath = join(cloneDir, '.aw');
420
+ // Only ever touch a STRAY on-disk `.aw` symlink (e.g. one the IDE/worktree
421
+ // `aw link` hook drops into the cache clone). Remove it from the WORKTREE
422
+ // ONLY, with a filesystem unlink — never a git command.
423
+ //
424
+ // The docs repo may track a real `.aw/` tree (ghl-aw-docs tracks
425
+ // `.aw/.aw_rules/**`). A `git rm .aw` here would stage a deletion of that
426
+ // committed content and push it away (this is exactly what corrupted
427
+ // master-sync). A plain unlink cannot stage anything, so it can never delete
428
+ // the committed tree — and since `.aw` is kept out of the sparse cone, the
429
+ // tracked tree is SKIP_WORKTREE and unaffected by removing the disk symlink.
419
430
  try {
420
- if (!lstatSync(join(cloneDir, '.aw')).isSymbolicLink()) return false;
431
+ if (!lstatSync(awPath).isSymbolicLink()) return false;
421
432
  } catch {
422
433
  return false;
423
434
  }
424
-
425
435
  try {
426
- await execFile('git', ['ls-files', '--error-unmatch', '.aw'], {
427
- cwd: cloneDir,
428
- encoding: 'utf8',
429
- });
436
+ rmSync(awPath, { force: true });
437
+ return true;
430
438
  } catch {
431
439
  return false;
432
440
  }
433
-
434
- await execFile('git', ['rm', '-f', '.aw'], {
435
- cwd: cloneDir,
436
- encoding: 'utf8',
437
- });
438
- return true;
439
441
  }
440
442
 
441
443
  function parseStatusPaths(status) {
@@ -480,9 +482,24 @@ async function selfHealManagedAwCacheDirtiness(cloneDir, status) {
480
482
  });
481
483
 
482
484
  if (await hasTrackedAwCachePaths(cloneDir)) {
485
+ // Restore a dirty tracked `.aw` from HEAD. In a full clone this cleans the
486
+ // worktree + index (the original behaviour). Best-effort (.catch): when `.aw`
487
+ // is sparse-excluded (out of cone) this pathspec can't match and the call is
488
+ // a no-op — but a sparse-excluded `.aw` is SKIP_WORKTREE and won't be dirty
489
+ // in the first place. This can only restore/un-stage, never delete tracked
490
+ // content.
483
491
  await execFile('git', ['restore', '--staged', '--worktree', '--', '.aw'], {
484
492
  cwd: cloneDir,
485
493
  encoding: 'utf8',
494
+ }).catch((e) => {
495
+ const msg = (e?.stderr || e?.message || '').toString();
496
+ // Expected + ignorable: when `.aw` is sparse-excluded (out of cone) the
497
+ // pathspec cannot match, so the restore is simply a no-op.
498
+ if (/did not match any file|outside .*sparse-checkout/i.test(msg)) return;
499
+ // Anything else (permissions, index corruption, ...) is unexpected —
500
+ // surface it so a future `.aw` cache issue is diagnosable, but don't
501
+ // block the publish on a best-effort cleanup step.
502
+ fmt.logWarn(`AW docs cache: could not restore .aw (${msg.trim()})`);
486
503
  });
487
504
  }
488
505
 
@@ -579,6 +596,11 @@ async function getProjectSourceRepo(projectRoot) {
579
596
  const AW_DOCS_GIT_ENV = { ...process.env, GIT_TERMINAL_PROMPT: '0', GCM_INTERACTIVE: 'never' };
580
597
  const AW_DOCS_CLONE_TIMEOUT_MS = Number(process.env.AW_DOCS_GIT_TIMEOUT_MS) || 180000;
581
598
  const AW_DOCS_NET_TIMEOUT_MS = Number(process.env.AW_DOCS_GIT_TIMEOUT_MS) || 120000;
599
+ // NOTE: `.aw` is intentionally NOT added to the sparse cone. The docs repo may
600
+ // track a real `.aw/` tree (ghl-aw-docs tracks `.aw/.aw_rules/**`); keeping it
601
+ // out of the cone leaves that tree SKIP_WORKTREE so no publish can materialise
602
+ // or (crucially) stage a deletion of it. Any stray on-disk `.aw` symlink is
603
+ // removed worktree-only via a filesystem unlink (see removeTrackedAwSymlink).
582
604
 
583
605
  async function awDocsSparseEnabled(cloneDir) {
584
606
  try {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ghl-ai/aw",
3
- "version": "0.1.82",
3
+ "version": "0.1.84",
4
4
  "description": "Agentic Workspace CLI — pull, push & manage agents, skills and commands from the registry",
5
5
  "type": "module",
6
6
  "bin": {