@ghl-ai/aw 0.1.36-beta.10 → 0.1.36-beta.12
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/pull.mjs +13 -1
- package/commands/push.mjs +13 -30
- package/git.mjs +15 -0
- package/package.json +1 -1
package/commands/pull.mjs
CHANGED
|
@@ -7,7 +7,7 @@ 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
|
-
import { fetchAndMerge, addToSparseCheckout, isValidClone } from '../git.mjs';
|
|
10
|
+
import { fetchAndMerge, addToSparseCheckout, isValidClone, isWorktree, rebaseOntoOriginMain } from '../git.mjs';
|
|
11
11
|
import { REGISTRY_DIR, REGISTRY_REPO, DOCS_SOURCE_DIR } from '../constants.mjs';
|
|
12
12
|
import { linkWorkspace } from '../link.mjs';
|
|
13
13
|
import { generateCommands, copyInstructions } from '../integrate.mjs';
|
|
@@ -73,6 +73,18 @@ export async function pullCommand(args) {
|
|
|
73
73
|
log.logWarn(`Conflicts in: ${fetchResult.conflicts.join(', ')}`);
|
|
74
74
|
}
|
|
75
75
|
|
|
76
|
+
// Always rebase project worktree's current branch onto origin/main
|
|
77
|
+
const localAw = join(cwd, '.aw');
|
|
78
|
+
if (cwd !== HOME && isWorktree(localAw)) {
|
|
79
|
+
try {
|
|
80
|
+
rebaseOntoOriginMain(localAw);
|
|
81
|
+
if (!silent) log.logStep('Local branch rebased onto latest main');
|
|
82
|
+
} catch (e) {
|
|
83
|
+
const msg = e.message?.split('\n').find(l => l.trim()) ?? e.message;
|
|
84
|
+
if (!silent) log.logWarn(`Rebase skipped: ${msg}`);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
76
88
|
// Sync content/ → platform/docs/
|
|
77
89
|
syncDocs(AW_HOME, GLOBAL_AW_DIR);
|
|
78
90
|
|
package/commands/push.mjs
CHANGED
|
@@ -12,11 +12,8 @@ import { walkRegistryTree } from '../registry.mjs';
|
|
|
12
12
|
import {
|
|
13
13
|
detectChanges,
|
|
14
14
|
getStagedFiles,
|
|
15
|
-
commitToCurrentBranch,
|
|
16
|
-
updatePushBranch,
|
|
17
15
|
createPushBranch,
|
|
18
16
|
checkoutMain,
|
|
19
|
-
getCurrentBranch,
|
|
20
17
|
isValidClone,
|
|
21
18
|
isWorktree,
|
|
22
19
|
getLocalRegistryDir,
|
|
@@ -26,19 +23,7 @@ const PUSHABLE_TYPES = ['agents', 'skills', 'commands', 'evals'];
|
|
|
26
23
|
|
|
27
24
|
// ── PR content generation ────────────────────────────────────────────
|
|
28
25
|
|
|
29
|
-
//
|
|
30
|
-
// Same branch is reused across pushes — force-pushed each time, one open PR.
|
|
31
|
-
function getPushBranchName(awHome) {
|
|
32
|
-
const branch = getCurrentBranch(awHome);
|
|
33
|
-
if (branch?.startsWith('worktree/')) {
|
|
34
|
-
return `push/${branch.slice('worktree/'.length)}`;
|
|
35
|
-
}
|
|
36
|
-
// Fallback for non-worktree or detached HEAD
|
|
37
|
-
const shortId = Date.now().toString(36).slice(-5);
|
|
38
|
-
return `push/batch-${shortId}`;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
// Timestamped branch for the global-clone (non-worktree) flow.
|
|
26
|
+
// Auto-generate a branch name from the files being pushed.
|
|
42
27
|
function generateBranchName(files) {
|
|
43
28
|
const shortId = Date.now().toString(36).slice(-5);
|
|
44
29
|
const namespaces = [...new Set(files.map(f => f.namespace))];
|
|
@@ -265,6 +250,7 @@ function createOrUpdatePR(awHome, branch, prTitle, prBody) {
|
|
|
265
250
|
const url = execFileSync('gh', [
|
|
266
251
|
'pr', 'create',
|
|
267
252
|
'--base', REGISTRY_BASE_BRANCH,
|
|
253
|
+
'--head', branch,
|
|
268
254
|
'--title', prTitle,
|
|
269
255
|
'--body', prBody,
|
|
270
256
|
], { cwd: awHome, encoding: 'utf8' }).trim();
|
|
@@ -280,10 +266,9 @@ function createOrUpdatePR(awHome, branch, prTitle, prBody) {
|
|
|
280
266
|
// ── Main push pipeline ────────────────────────────────────────────────
|
|
281
267
|
|
|
282
268
|
// worktreeFlow: true when awHome is a project worktree (not the global clone).
|
|
283
|
-
// -
|
|
284
|
-
// -
|
|
285
|
-
//
|
|
286
|
-
// Global flow (worktreeFlow=false): legacy branch-per-push on global clone.
|
|
269
|
+
// - Always creates a new branch from current state, commits, pushes, stays there.
|
|
270
|
+
// - Every aw push = one new branch + one new PR. No force-push, no reuse.
|
|
271
|
+
// Global flow (worktreeFlow=false): same but returns to main after push.
|
|
287
272
|
function doPush(files, awHome, dryRun, worktreeFlow = false, preStaged = false) {
|
|
288
273
|
const added = files.filter(f => !f.deleted);
|
|
289
274
|
const deleted = files.filter(f => f.deleted);
|
|
@@ -333,14 +318,13 @@ function doPush(files, awHome, dryRun, worktreeFlow = false, preStaged = false)
|
|
|
333
318
|
let finalBranch;
|
|
334
319
|
try {
|
|
335
320
|
if (worktreeFlow) {
|
|
336
|
-
// ── Worktree flow
|
|
337
|
-
//
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
finalBranch = updatePushBranch(awHome, getPushBranchName(awHome));
|
|
321
|
+
// ── Worktree flow ─────────────────────────────────────────────────
|
|
322
|
+
// Always create a new branch from current state, commit, push, stay there.
|
|
323
|
+
// Every push = one new branch + one new PR. No force-push, no branch reuse.
|
|
324
|
+
finalBranch = createPushBranch(awHome, generateBranchName(files), pathsToStage, commitMsg, preStaged);
|
|
341
325
|
} else {
|
|
342
|
-
// ── Global clone flow
|
|
343
|
-
// Checkout main → create
|
|
326
|
+
// ── Global clone flow ─────────────────────────────────────────────
|
|
327
|
+
// Checkout main → create branch → commit → push → return to main.
|
|
344
328
|
if (!preStaged) {
|
|
345
329
|
try { checkoutMain(awHome); } catch (e) {
|
|
346
330
|
s.stop(chalk.red('Push failed'));
|
|
@@ -367,7 +351,7 @@ function doPush(files, awHome, dryRun, worktreeFlow = false, preStaged = false)
|
|
|
367
351
|
fmt.logInfo(`New namespace${newNamespaces.length > 1 ? 's' : ''} ${chalk.cyan(newNamespaces.join(', '))} — CODEOWNERS entr${newNamespaces.length > 1 ? 'ies' : 'y'} added`);
|
|
368
352
|
}
|
|
369
353
|
if (worktreeFlow) {
|
|
370
|
-
fmt.logInfo(chalk.dim(
|
|
354
|
+
fmt.logInfo(chalk.dim(`On branch ${finalBranch} — run aw push again to open a new PR`));
|
|
371
355
|
}
|
|
372
356
|
fmt.logSuccess(`PR: ${chalk.cyan(prUrl)}`);
|
|
373
357
|
fmt.outro('Push complete');
|
|
@@ -391,7 +375,6 @@ export function pushCommand(args) {
|
|
|
391
375
|
const registrySubDir = join(awHome, REGISTRY_DIR);
|
|
392
376
|
const workspaceDir = getLocalRegistryDir(cwd, join(HOME, '.aw_registry'));
|
|
393
377
|
|
|
394
|
-
// Save current worktree branch so we can restore it after push
|
|
395
378
|
const worktreeFlow = hasWorktree;
|
|
396
379
|
|
|
397
380
|
fmt.intro('aw push');
|
|
@@ -530,7 +513,7 @@ export function pushCommand(args) {
|
|
|
530
513
|
slug,
|
|
531
514
|
isDir,
|
|
532
515
|
deleted: false,
|
|
533
|
-
}], awHome, dryRun,
|
|
516
|
+
}], awHome, dryRun, worktreeFlow);
|
|
534
517
|
}
|
|
535
518
|
|
|
536
519
|
// ── Utilities ─────────────────────────────────────────────────────────
|
package/git.mjs
CHANGED
|
@@ -404,6 +404,21 @@ export function checkoutMain(awHome) {
|
|
|
404
404
|
}
|
|
405
405
|
}
|
|
406
406
|
|
|
407
|
+
/**
|
|
408
|
+
* Rebase the current branch onto origin/main.
|
|
409
|
+
* Assumes `git fetch` has already been run (e.g. via fetchAndMerge).
|
|
410
|
+
* Throws if there are conflicts — caller should surface the message.
|
|
411
|
+
*/
|
|
412
|
+
export function rebaseOntoOriginMain(awHome) {
|
|
413
|
+
try {
|
|
414
|
+
execSync(`git -C "${awHome}" rebase origin/${REGISTRY_BASE_BRANCH}`, { stdio: 'pipe' });
|
|
415
|
+
} catch (e) {
|
|
416
|
+
// Surface stderr so callers can show a meaningful message
|
|
417
|
+
const stderr = e.stderr?.toString().trim() || e.stdout?.toString().trim() || e.message;
|
|
418
|
+
throw new Error(stderr);
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
|
|
407
422
|
// ── Project worktree operations ────────────────────────────────────────────────
|
|
408
423
|
|
|
409
424
|
/**
|