all-hands-cli 0.1.7 → 0.1.8

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/bin/sync-cli.js CHANGED
@@ -4905,6 +4905,15 @@ function getGitFiles(repoPath) {
4905
4905
  }
4906
4906
  return files;
4907
4907
  }
4908
+ function getFileBlobHash(filePath, repoPath) {
4909
+ const result = git(["hash-object", filePath], repoPath);
4910
+ return result.success ? result.stdout.trim() : null;
4911
+ }
4912
+ function fileExistsInHistory(relPath, blobHash, repoPath) {
4913
+ const result = git(["rev-list", "HEAD", "--objects", "--", relPath], repoPath);
4914
+ if (!result.success || !result.stdout) return false;
4915
+ return result.stdout.split("\n").some((line) => line.startsWith(blobHash + " "));
4916
+ }
4908
4917
 
4909
4918
  // src/lib/manifest.ts
4910
4919
  import { readFileSync as readFileSync5, existsSync as existsSync3, statSync as statSync3 } from "fs";
@@ -7224,6 +7233,12 @@ function checkPrerequisites(cwd) {
7224
7233
  }
7225
7234
  return { success: true, ghUser };
7226
7235
  }
7236
+ function wasModifiedByTargetRepo(cwd, relPath, allhandsRoot) {
7237
+ const localFile = join9(cwd, relPath);
7238
+ const localBlobHash = getFileBlobHash(localFile, allhandsRoot);
7239
+ if (!localBlobHash) return true;
7240
+ return !fileExistsInHistory(relPath, localBlobHash, allhandsRoot);
7241
+ }
7227
7242
  function collectFilesToPush(cwd, finalIncludes, finalExcludes) {
7228
7243
  const allhandsRoot = getAllhandsRoot();
7229
7244
  const manifest = new Manifest(allhandsRoot);
@@ -7246,7 +7261,9 @@ function collectFilesToPush(cwd, finalIncludes, finalExcludes) {
7246
7261
  const localFile = join9(cwd, relPath);
7247
7262
  const upstreamFile = join9(allhandsRoot, relPath);
7248
7263
  if (existsSync11(localFile) && filesAreDifferent(localFile, upstreamFile)) {
7249
- filesToPush.push({ path: relPath, type: "M" });
7264
+ if (wasModifiedByTargetRepo(cwd, relPath, allhandsRoot)) {
7265
+ filesToPush.push({ path: relPath, type: "M" });
7266
+ }
7250
7267
  }
7251
7268
  }
7252
7269
  for (const pattern of finalIncludes) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "all-hands-cli",
3
- "version": "0.1.7",
3
+ "version": "0.1.8",
4
4
  "description": "Agentic harness for model-first software development",
5
5
  "type": "module",
6
6
  "bin": {
@@ -3,7 +3,7 @@ import { tmpdir } from 'os';
3
3
  import { dirname, join } from 'path';
4
4
  import { minimatch } from 'minimatch';
5
5
  import * as readline from 'readline';
6
- import { git, isGitRepo, getGitFiles } from '../lib/git.js';
6
+ import { git, isGitRepo, getGitFiles, getFileBlobHash, fileExistsInHistory } from '../lib/git.js';
7
7
  import { checkGhAuth, checkGhInstalled, getGhUser, gh } from '../lib/gh.js';
8
8
  import { Manifest, filesAreDifferent } from '../lib/manifest.js';
9
9
  import { getAllhandsRoot, UPSTREAM_REPO } from '../lib/paths.js';
@@ -94,6 +94,23 @@ function checkPrerequisites(cwd: string): PrerequisiteResult {
94
94
  return { success: true, ghUser };
95
95
  }
96
96
 
97
+ /**
98
+ * Determine if a file was actually modified by the target repo,
99
+ * vs simply being out of date because upstream moved forward.
100
+ *
101
+ * Compares the target file's content against all historical versions
102
+ * in the upstream repo. If it matches any previous version, the target
103
+ * repo hasn't modified it.
104
+ */
105
+ function wasModifiedByTargetRepo(cwd: string, relPath: string, allhandsRoot: string): boolean {
106
+ const localFile = join(cwd, relPath);
107
+ const localBlobHash = getFileBlobHash(localFile, allhandsRoot);
108
+
109
+ if (!localBlobHash) return true; // safe default: assume modified on error
110
+
111
+ return !fileExistsInHistory(relPath, localBlobHash, allhandsRoot);
112
+ }
113
+
97
114
  function collectFilesToPush(
98
115
  cwd: string,
99
116
  finalIncludes: string[],
@@ -126,7 +143,9 @@ function collectFilesToPush(
126
143
  const upstreamFile = join(allhandsRoot, relPath);
127
144
 
128
145
  if (existsSync(localFile) && filesAreDifferent(localFile, upstreamFile)) {
129
- filesToPush.push({ path: relPath, type: 'M' });
146
+ if (wasModifiedByTargetRepo(cwd, relPath, allhandsRoot)) {
147
+ filesToPush.push({ path: relPath, type: 'M' });
148
+ }
130
149
  }
131
150
  }
132
151
 
package/src/lib/git.ts CHANGED
@@ -61,3 +61,22 @@ export function getGitFiles(repoPath: string): string[] {
61
61
  }
62
62
  return files;
63
63
  }
64
+
65
+ /**
66
+ * Compute the git blob hash of a file (works on files outside the repo).
67
+ */
68
+ export function getFileBlobHash(filePath: string, repoPath: string): string | null {
69
+ const result = git(['hash-object', filePath], repoPath);
70
+ return result.success ? result.stdout.trim() : null;
71
+ }
72
+
73
+ /**
74
+ * Check if a specific blob hash appears in the git history of a file path.
75
+ * Uses a single `rev-list --objects` call instead of per-commit lookups.
76
+ */
77
+ export function fileExistsInHistory(relPath: string, blobHash: string, repoPath: string): boolean {
78
+ const result = git(['rev-list', 'HEAD', '--objects', '--', relPath], repoPath);
79
+ if (!result.success || !result.stdout) return false;
80
+
81
+ return result.stdout.split('\n').some(line => line.startsWith(blobHash + ' '));
82
+ }