@pome-sh/cli 0.23.41 → 0.23.43

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.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "package": "pome-sh",
3
- "version": "0.23.41",
4
- "git_sha": "f60a1f05eb4991a7bda87742ea75a1832a9b269b",
5
- "build_time": "2026-08-13T02:40:36.333Z"
3
+ "version": "0.23.43",
4
+ "git_sha": "299810b816d73cf13826991a602af497b264c09e",
5
+ "build_time": "2026-08-13T13:52:24.164Z"
6
6
  }
@@ -183,7 +183,7 @@ async function checkTwinReachable(_configDir) {
183
183
  });
184
184
  let harness;
185
185
  try {
186
- const { bootTwin } = await import('./twinHarness-CKDJQ6TF.js');
186
+ const { bootTwin } = await import('./twinHarness-HQL3WCWU.js');
187
187
  harness = await bootTwin({
188
188
  twin: "github",
189
189
  seedState: void 0,
@@ -19,7 +19,52 @@ var seedSchema = z.object({
19
19
  color: z.string().default("ededed"),
20
20
  description: z.string().default("")
21
21
  })).default([]),
22
- files: z.array(z.object({ path: z.string().min(1), content: z.string(), branch: z.string().optional() })).default([]),
22
+ // F-1500 `renamed_from` is how a seed expresses a MOVE, and with it the
23
+ // `status: "renamed"` the row type has always declared and no world could
24
+ // reach. A seeded branch is created from the default branch and inherits
25
+ // every path, and a plain `files[]` entry can only add or overwrite, so
26
+ // before this there was no way to make a path ABSENT from the head branch
27
+ // — and `previous_filename` was therefore unreachable from any seed, not
28
+ // merely unemitted.
29
+ //
30
+ // `content` is refused alongside `renamed_from` rather than merged with
31
+ // it: the diff detects a move by pairing identical blobs (see
32
+ // `calculatePullFiles`), so a seed naming a source AND different content
33
+ // would be asking for a rename the diff would report as an add plus a
34
+ // remove. Refusing it keeps "the seed asked for a rename" and "the twin
35
+ // serves a rename" the same statement. The content comes from the source
36
+ // path, which the domain resolves on the branch the move happens on.
37
+ files: z.array(z.object({
38
+ path: z.string().min(1),
39
+ content: z.string().optional(),
40
+ branch: z.string().optional(),
41
+ renamed_from: z.string().min(1).optional()
42
+ }).superRefine((file, ctx) => {
43
+ if (file.renamed_from === void 0) {
44
+ if (file.content === void 0) {
45
+ ctx.addIssue({
46
+ code: "custom",
47
+ path: ["content"],
48
+ message: "content is required on a file entry that declares no renamed_from"
49
+ });
50
+ }
51
+ return;
52
+ }
53
+ if (file.content !== void 0) {
54
+ ctx.addIssue({
55
+ code: "custom",
56
+ path: ["content"],
57
+ message: `renamed_from carries the source file's content, so content must be omitted (${file.path})`
58
+ });
59
+ }
60
+ if (file.renamed_from === file.path) {
61
+ ctx.addIssue({
62
+ code: "custom",
63
+ path: ["renamed_from"],
64
+ message: `renamed_from must name a different path than the file it moves to (${file.path})`
65
+ });
66
+ }
67
+ })).default([]),
23
68
  // F-1421 — milestones, tags and releases are repository-level entities the
24
69
  // twin already SERVES (`GET /milestones`, `/tags`, `/releases`,
25
70
  // `/releases/latest`, `/releases/tags/:tag`) and the seed could not
@@ -1,7 +1,7 @@
1
1
  import { getAvailablePort } from './chunk-XDU6TD4O.js';
2
2
  import { buildEgressAllowlist, readBlockedEgress } from './chunk-CBFKZZBR.js';
3
- import { parseTaskFile, seedStateForTwin, runAgentCommand, writeRunArtifactsCore } from './chunk-S3XYJUD6.js';
4
- import { createRecorder, bootTwin } from './chunk-IA2EYQ3Q.js';
3
+ import { parseTaskFile, seedStateForTwin, runAgentCommand, writeRunArtifactsCore } from './chunk-NAQHX4KD.js';
4
+ import { createRecorder, bootTwin } from './chunk-JGZFB6ZZ.js';
5
5
  import { eventSchema } from './chunk-VBATFCWR.js';
6
6
  import { redactSecrets, redactEvent } from './chunk-SG6ZTIMT.js';
7
7
  import { serve } from '@hono/node-server';
@@ -1,4 +1,4 @@
1
- import { TWIN_NAMES, isTwinName, TWIN_REGISTRY } from './chunk-PRK5EFUZ.js';
1
+ import { TWIN_NAMES, isTwinName, TWIN_REGISTRY } from './chunk-LA52VCI4.js';
2
2
  import { createFileBackedRecorderStore, createRecorderStore } from './chunk-OW7VVW6X.js';
3
3
 
4
4
  // src/recorder/recorder.ts
@@ -39,7 +39,7 @@ var TWIN_REGISTRY = {
39
39
  defaultSeedState,
40
40
  GitHubDomain,
41
41
  openGitHubCloneDatabase
42
- } = await import('./src-XBWNIRBG.js');
42
+ } = await import('./src-VKYIOI2P.js');
43
43
  const db = openGitHubCloneDatabase();
44
44
  const domain = new GitHubDomain(db);
45
45
  domain.seed(seedState === void 0 ? defaultSeedState() : seedState);
@@ -173,7 +173,7 @@ var TWIN_REGISTRY = {
173
173
  }
174
174
  };
175
175
  async function createGitHubSmokeApp() {
176
- const { createGitHubCloneApp } = await import('./src-XBWNIRBG.js');
176
+ const { createGitHubCloneApp } = await import('./src-VKYIOI2P.js');
177
177
  return createGitHubCloneApp();
178
178
  }
179
179
  function defaultPortFor(twin, env = process.env) {
@@ -1,8 +1,8 @@
1
1
  import { criterionSchema, finalizeResponseSchema, HostedDiscardRefusedError, HostedOrchError, HostedAuthError, HostedQuotaError, submitResultResponseSchema, createEvalSessionResponseSchema, createSessionResponseSchema, sessionPublicSchema } from './chunk-X66JOOO7.js';
2
- import { seedSchema, parseSeed, defaultSeedState as defaultSeedState$2 } from './chunk-KIUIKAVU.js';
2
+ import { seedSchema, parseSeed, defaultSeedState as defaultSeedState$2 } from './chunk-B22TYIEM.js';
3
3
  import { gmailSeedSchema, defaultSeedState } from './chunk-NJ246QPJ.js';
4
4
  import { linearSeedSchema, defaultSeedState as defaultSeedState$1 } from './chunk-ZKID2HS3.js';
5
- import { isTwinName, TWIN_REGISTRY } from './chunk-PRK5EFUZ.js';
5
+ import { isTwinName, TWIN_REGISTRY } from './chunk-LA52VCI4.js';
6
6
  import { toTwinHttpEventRow } from './chunk-OW7VVW6X.js';
7
7
  import { redactEvent, redactSecrets } from './chunk-SG6ZTIMT.js';
8
8
  import { mkdir, appendFile, writeFile, readFile } from 'node:fs/promises';
@@ -1,5 +1,5 @@
1
1
  import { readManifest, normalizeManifestTwins } from './chunk-ABM3CMQB.js';
2
- import { createHostedClient, perTwinReturnedByCloud, parseTaskFile, runAgentCommand, writeRunArtifactsCore, toTwinHttpEvent, redactJsonl, uploadRunBlobs, scoreFromFinalizeResponse, scoreStatus, evaluationCounts } from './chunk-S3XYJUD6.js';
2
+ import { createHostedClient, perTwinReturnedByCloud, parseTaskFile, runAgentCommand, writeRunArtifactsCore, toTwinHttpEvent, redactJsonl, uploadRunBlobs, scoreFromFinalizeResponse, scoreStatus, evaluationCounts } from './chunk-NAQHX4KD.js';
3
3
  import { MOUNTED_TWINS, HostedAuthError, HostedDiscardRefusedError, HostedQuotaError, HostedOrchError, HostedTrialError, agentResponseSchema } from './chunk-X66JOOO7.js';
4
4
  import { redactSecrets, redactEvent } from './chunk-SG6ZTIMT.js';
5
5
  import { randomUUID, createHash } from 'node:crypto';
@@ -1,16 +1,16 @@
1
1
  import { newGroupId, reassuranceBox, twinReadyLine, trialsHeaderLine, trialLine, summaryLines, evaluatingLine, criterionPhrase } from './chunk-RGZBC7NF.js';
2
2
  import { DemoCapacityError, capacityLabel, parseCapacityMarker, capacityKindFrom } from './chunk-ZX4WNSZ5.js';
3
- import { runTask, demoTaskPath, DEMO_TASK_NAME, DEMO_REPO } from './chunk-DBVHA3LI.js';
3
+ import { runTask, demoTaskPath, DEMO_TASK_NAME, DEMO_REPO } from './chunk-GHRZRQW5.js';
4
4
  import { getAvailablePort } from './chunk-XDU6TD4O.js';
5
5
  import './chunk-CBFKZZBR.js';
6
- import { createHostedClient, parseTaskFile, uploadRunBlobs, scoreFromFinalizeResponse, scoreStatus, outcomeOf } from './chunk-S3XYJUD6.js';
6
+ import { createHostedClient, parseTaskFile, uploadRunBlobs, scoreFromFinalizeResponse, scoreStatus, outcomeOf } from './chunk-NAQHX4KD.js';
7
7
  import './chunk-NW7HGA2K.js';
8
8
  import { HostedQuotaError, HostedOrchError } from './chunk-X66JOOO7.js';
9
- import './chunk-KIUIKAVU.js';
9
+ import './chunk-B22TYIEM.js';
10
10
  import './chunk-NJ246QPJ.js';
11
11
  import './chunk-ZKID2HS3.js';
12
- import { bootTwin } from './chunk-IA2EYQ3Q.js';
13
- import './chunk-PRK5EFUZ.js';
12
+ import { bootTwin } from './chunk-JGZFB6ZZ.js';
13
+ import './chunk-LA52VCI4.js';
14
14
  import './chunk-OW7VVW6X.js';
15
15
  import './chunk-VBATFCWR.js';
16
16
  import './chunk-SG6ZTIMT.js';
@@ -1,13 +1,13 @@
1
1
  import { newGroupId, criterionPhrase } from './chunk-RGZBC7NF.js';
2
- import { runTaskHosted, resolveRunAgentIdentity } from './chunk-E2HQ7WRL.js';
2
+ import { runTaskHosted, resolveRunAgentIdentity } from './chunk-NCHH5LIC.js';
3
3
  import './chunk-ABM3CMQB.js';
4
- import { createHostedClient, parseTaskFile, outcomeOf } from './chunk-S3XYJUD6.js';
4
+ import { createHostedClient, parseTaskFile, outcomeOf } from './chunk-NAQHX4KD.js';
5
5
  import './chunk-NW7HGA2K.js';
6
6
  import { HostedQuotaError, HostedTrialError } from './chunk-X66JOOO7.js';
7
- import './chunk-KIUIKAVU.js';
7
+ import './chunk-B22TYIEM.js';
8
8
  import './chunk-NJ246QPJ.js';
9
9
  import './chunk-ZKID2HS3.js';
10
- import './chunk-PRK5EFUZ.js';
10
+ import './chunk-LA52VCI4.js';
11
11
  import './chunk-OW7VVW6X.js';
12
12
  import './chunk-VBATFCWR.js';
13
13
  import './chunk-SG6ZTIMT.js';
@@ -1,22 +1,22 @@
1
1
  #!/usr/bin/env node
2
- import { DEFAULT_CONTROL_PLANE_URL, DEFAULT_DASHBOARD_URL, clearLocalCredentials, friendlyHostedError, runSessionCreate, runSessionList, runSessionStop, resolveCredentials, runTaskHosted, discoverRunSet, VERDICT_ARTIFACT_VERSION, persistCredentialsAfterLogin, DEFAULT_DOCS_SITE_ORIGIN, resolveSeams, resolveCachedAgentId, readLinkCache, postAgentResolver, writeLinkCache, ensurePomeGitignored } from '../../chunk-E2HQ7WRL.js';
2
+ import { DEFAULT_CONTROL_PLANE_URL, DEFAULT_DASHBOARD_URL, clearLocalCredentials, friendlyHostedError, runSessionCreate, runSessionList, runSessionStop, resolveCredentials, runTaskHosted, discoverRunSet, VERDICT_ARTIFACT_VERSION, persistCredentialsAfterLogin, DEFAULT_DOCS_SITE_ORIGIN, resolveSeams, resolveCachedAgentId, readLinkCache, postAgentResolver, writeLinkCache, ensurePomeGitignored } from '../../chunk-NCHH5LIC.js';
3
3
  import { readManifest, writeManifest, MANIFEST_JSON, readRequiredManifest, normalizeManifestTwins } from '../../chunk-ABM3CMQB.js';
4
- import { assetPath, runTask, resolvePackageRoot, DEMO_TASK_NAME, demoTaskPath } from '../../chunk-DBVHA3LI.js';
4
+ import { assetPath, runTask, resolvePackageRoot, DEMO_TASK_NAME, demoTaskPath } from '../../chunk-GHRZRQW5.js';
5
5
  import '../../chunk-XDU6TD4O.js';
6
6
  import '../../chunk-CBFKZZBR.js';
7
- import { parseTaskFile, scoreStatus, runScoreLine, readLatestRun, readMetaSummary, outcomeOf, readConfigTwins, scoreCountsSummary, markerFor, criterionMarkerLabel, twinSkipSuffix, readCodeCriteria, createHostedClient, toTwinHttpEvent, redactJsonl, scoreFromFinalizeResponse, parseGitHubSeedState, uploadRunBlobs, isPreSatisfied } from '../../chunk-S3XYJUD6.js';
7
+ import { parseTaskFile, scoreStatus, runScoreLine, readLatestRun, readMetaSummary, outcomeOf, readConfigTwins, scoreCountsSummary, markerFor, criterionMarkerLabel, twinSkipSuffix, readCodeCriteria, createHostedClient, toTwinHttpEvent, redactJsonl, scoreFromFinalizeResponse, parseGitHubSeedState, uploadRunBlobs, isPreSatisfied } from '../../chunk-NAQHX4KD.js';
8
8
  import '../../chunk-NW7HGA2K.js';
9
9
  import { MOUNTED_TWINS, deriveAgentSlug, exitCodeFor, HostedUsageError, HostedOrchError, HostedAuthError, HostedQuotaError } from '../../chunk-X66JOOO7.js';
10
10
  import { TAPE_ASSERTABLE_TOOLS } from '../../chunk-FKZZWWYC.js';
11
- import { seedSchema } from '../../chunk-KIUIKAVU.js';
11
+ import { seedSchema } from '../../chunk-B22TYIEM.js';
12
12
  import { SLACK_CHECKS } from '../../chunk-IDNSKKEC.js';
13
13
  import { GMAIL_CHECKS } from '../../chunk-JM6VS62R.js';
14
14
  import '../../chunk-NJ246QPJ.js';
15
15
  import { LINEAR_CHECKS } from '../../chunk-XBT6ZLBG.js';
16
16
  import '../../chunk-ZKID2HS3.js';
17
17
  import { oneOf, defineCheck, repoRef, VACUITY_SENTINEL_NUMBER, childStatePath, VACUITY_SENTINEL, statePath, templateSlots, renderCheck, checksDigest, checkPattern, checkNearMissPattern } from '../../chunk-JWJYNAWI.js';
18
- import '../../chunk-IA2EYQ3Q.js';
19
- import { TWIN_NAME_LIST, isTwinName, createGitHubSmokeApp } from '../../chunk-PRK5EFUZ.js';
18
+ import '../../chunk-JGZFB6ZZ.js';
19
+ import { TWIN_NAME_LIST, isTwinName, createGitHubSmokeApp } from '../../chunk-LA52VCI4.js';
20
20
  import '../../chunk-OW7VVW6X.js';
21
21
  import { isLegacyEventRow, eventSchema } from '../../chunk-VBATFCWR.js';
22
22
  import { redactEvent, redactSecrets } from '../../chunk-SG6ZTIMT.js';
@@ -850,7 +850,7 @@ async function throwForStatus(res) {
850
850
 
851
851
  // src/task/seed-verifier.ts
852
852
  async function verifySeedWithTwin(seed) {
853
- const { GitHubDomain, openGitHubCloneDatabase } = await import('../../src-XBWNIRBG.js');
853
+ const { GitHubDomain, openGitHubCloneDatabase } = await import('../../src-VKYIOI2P.js');
854
854
  const db = openGitHubCloneDatabase(":memory:");
855
855
  try {
856
856
  new GitHubDomain(db).seed(seed);
@@ -4580,7 +4580,7 @@ var DEFAULT_AGENT_COMMAND = `node ${DEFAULT_AGENT_FILE}`;
4580
4580
  var MANIFEST_SCHEMA_URL = "https://pome.sh/schemas/v1/pome.json";
4581
4581
  var MAX_UNREADABLE_PATHS_SHOWN = 5;
4582
4582
  function readPackageVersion() {
4583
- if ("0.23.41".length > 0) return "0.23.41";
4583
+ if ("0.23.43".length > 0) return "0.23.43";
4584
4584
  try {
4585
4585
  const here = dirname(fileURLToPath(import.meta.url));
4586
4586
  const candidates = [
@@ -5035,7 +5035,7 @@ function createProgram() {
5035
5035
  return;
5036
5036
  }
5037
5037
  {
5038
- const { runDoctorChecks } = await import('../../checks-34HBZTRP.js');
5038
+ const { runDoctorChecks } = await import('../../checks-YI7MUJIE.js');
5039
5039
  const { renderDoctorReport } = await import('../../render-ZQQ4UMNO.js');
5040
5040
  const doctorReport = await runDoctorChecks({ mode: useLocal ? "full" : "hosted" });
5041
5041
  if (!doctorReport.ok) {
@@ -5073,7 +5073,7 @@ function createProgram() {
5073
5073
  taskForRuns.config.runs
5074
5074
  );
5075
5075
  if (k > 1) {
5076
- const { runTrialGroup } = await import('../../runTrialGroup-A6XUGJAD.js');
5076
+ const { runTrialGroup } = await import('../../runTrialGroup-KDVWTFDR.js');
5077
5077
  const fileForRerun = relative(process.cwd(), file);
5078
5078
  const rerunCommand = defaultTask ? options.trials !== void 0 ? `pome run -n ${k}` : "pome run" : `pome run ${fileForRerun && !fileForRerun.startsWith("..") ? fileForRerun : file} -n ${k}`;
5079
5079
  const groupResult = await runTrialGroup({
@@ -5167,7 +5167,7 @@ function createProgram() {
5167
5167
  process.exitCode = 5;
5168
5168
  return;
5169
5169
  }
5170
- const { runDemo } = await import('../../runDemo-V3LQQJCT.js');
5170
+ const { runDemo } = await import('../../runDemo-5P3FBTOI.js');
5171
5171
  const result = await runDemo({
5172
5172
  apiBase: opts.apiUrl.replace(/\/$/, ""),
5173
5173
  dashboardBase: process.env.POME_DASHBOARD_URL ?? DEFAULT_DASHBOARD_URL,
@@ -5185,7 +5185,7 @@ function createProgram() {
5185
5185
  program.command("doctor").description(
5186
5186
  "Check the agent\u2194twin wiring: pome.json (or pome.yaml) present + valid, the local twin boots + serves, requests routed to the twin (not a hardcoded production host), egress floor active. On failure prints one named cause (file:line where knowable) + one concrete fix and exits non-zero."
5187
5187
  ).action(async () => {
5188
- const { runDoctorChecks } = await import('../../checks-34HBZTRP.js');
5188
+ const { runDoctorChecks } = await import('../../checks-YI7MUJIE.js');
5189
5189
  const { renderDoctorReport } = await import('../../render-ZQQ4UMNO.js');
5190
5190
  const report = await runDoctorChecks();
5191
5191
  for (const line of renderDoctorReport(report, { passNote: true })) console.error(line);
@@ -5361,7 +5361,7 @@ function createProgram() {
5361
5361
  ).description(
5362
5362
  "Start a standalone twin as a long-lived foreground server (Ctrl-C to stop)"
5363
5363
  ).action(async (name, options) => {
5364
- const { runTwinStartCommand } = await import('../../twinStart-2N5WGHH4.js');
5364
+ const { runTwinStartCommand } = await import('../../twinStart-DR3NHOYR.js');
5365
5365
  await runTwinStartCommand(name, options);
5366
5366
  });
5367
5367
  twin.command("reset").argument("[name]", "Twin name (default: github)", "github").description("Reset standalone twin state").action(async (name) => {
@@ -1,6 +1,6 @@
1
1
  import './chunk-FKZZWWYC.js';
2
- import { defaultSeedState, parseSeed } from './chunk-KIUIKAVU.js';
3
- export { defaultSeedState, parseSeed, seedSchema } from './chunk-KIUIKAVU.js';
2
+ import { defaultSeedState, parseSeed } from './chunk-B22TYIEM.js';
3
+ export { defaultSeedState, parseSeed, seedSchema } from './chunk-B22TYIEM.js';
4
4
  import { routeInputDeclarer, integerInput, mountDeclaredRoute, UndeclaredInputError, MalformedBodyError } from './chunk-2Q3P45LK.js';
5
5
  import { loadMcpToolFixture, defineTwin, twinBuildInfo, deriveMcpToolTable, UnknownToolError, openTwinDatabase, createApp } from './chunk-OW7VVW6X.js';
6
6
  import './chunk-VBATFCWR.js';
@@ -2260,6 +2260,12 @@ CREATE TABLE IF NOT EXISTS pull_request_files (
2260
2260
  raw_url TEXT NOT NULL DEFAULT '',
2261
2261
  contents_url TEXT NOT NULL DEFAULT '',
2262
2262
  patch TEXT NOT NULL DEFAULT '',
2263
+ -- F-1500 \u2014 the pre-rename path, NULL on every status but 'renamed'. Nullable
2264
+ -- rather than DEFAULT '': the serializer reads presence off the status, and
2265
+ -- an empty string here would be indistinguishable from a rename whose source
2266
+ -- path the diff failed to resolve. (No backticks in this literal: it is a
2267
+ -- template string, and one would close it.)
2268
+ previous_filename TEXT,
2263
2269
  PRIMARY KEY (repo_id, pull_number, filename),
2264
2270
  FOREIGN KEY (repo_id, pull_number) REFERENCES pull_requests(repo_id, number) ON DELETE CASCADE
2265
2271
  );
@@ -2353,6 +2359,7 @@ function migrate(db) {
2353
2359
  ensureColumn(db, "pull_request_review_comments", "in_reply_to_id", "INTEGER");
2354
2360
  ensureColumn(db, "collaborators", "invitation_state", "TEXT NOT NULL DEFAULT 'accepted'");
2355
2361
  ensureColumn(db, "releases", "updated_at", "TEXT NOT NULL DEFAULT ''");
2362
+ ensureColumn(db, "pull_request_files", "previous_filename", "TEXT");
2356
2363
  ensureIssueNumberCascade(db);
2357
2364
  ensureCommentsAllowPullRequests(db);
2358
2365
  hydrateDerivedColumns(db);
@@ -2478,6 +2485,23 @@ function paginate(items, page = 1, perPage = 30) {
2478
2485
  const start = (safePage - 1) * safePerPage;
2479
2486
  return items.slice(start, start + safePerPage);
2480
2487
  }
2488
+ function detectRenames(removed, added) {
2489
+ const byContent = /* @__PURE__ */ new Map();
2490
+ for (const file of [...removed].sort((a, b) => a.path.localeCompare(b.path))) {
2491
+ const paths = byContent.get(file.sha);
2492
+ if (paths)
2493
+ paths.push(file.path);
2494
+ else
2495
+ byContent.set(file.sha, [file.path]);
2496
+ }
2497
+ const renames = /* @__PURE__ */ new Map();
2498
+ for (const file of [...added].sort((a, b) => a.path.localeCompare(b.path))) {
2499
+ const source = byContent.get(file.sha)?.shift();
2500
+ if (source !== void 0)
2501
+ renames.set(file.path, source);
2502
+ }
2503
+ return renames;
2504
+ }
2481
2505
  function linesChanged(before, after) {
2482
2506
  if (before === void 0) {
2483
2507
  return { additions: after.split("\n").filter(Boolean).length || 1, deletions: 0 };
@@ -2849,7 +2873,15 @@ function pullRequestFileJson(file) {
2849
2873
  blob_url: file.blob_url,
2850
2874
  raw_url: file.raw_url,
2851
2875
  contents_url: file.contents_url,
2852
- patch: file.patch
2876
+ patch: file.patch,
2877
+ // F-1500 — GitHub sends `previous_filename` exactly when `status` is
2878
+ // `"renamed"` and omits the KEY otherwise, so this is a conditional spread
2879
+ // rather than a `null`: emitting `previous_filename: null` on an added file
2880
+ // would trade a missing-field divergence for a type-changed one and have
2881
+ // every file claim to know where it came from. `status` is what gates it,
2882
+ // not the column being set, so a row that somehow carried a source path on
2883
+ // another status cannot leak it onto the wire.
2884
+ ...file.status === "renamed" && file.previous_filename ? { previous_filename: file.previous_filename } : {}
2853
2885
  };
2854
2886
  }
2855
2887
  function reviewJson(review, repo) {
@@ -4302,12 +4334,16 @@ var GitHubDomain = class {
4302
4334
  }
4303
4335
  this.createBranchInternal(repo, repo.default_branch, null);
4304
4336
  const files = repoSeed.files?.filter((file) => (file.branch ?? repo.default_branch) === repo.default_branch) ?? [];
4337
+ const rootRename = files.find((file) => file.renamed_from !== void 0);
4338
+ if (rootRename) {
4339
+ conflict(`Seed sets renamed_from on ${rootRename.path} with no branch: the default branch is the initial commit, so there is no earlier tree to move out of`);
4340
+ }
4305
4341
  this.commitFiles(repo, repo.default_branch, "Initial seed commit", files, "pome-agent");
4306
4342
  const nonDefaultBranches = new Set((repoSeed.files ?? []).map((file) => file.branch ?? repo.default_branch).filter((branch) => branch !== repo.default_branch));
4307
4343
  for (const branch of nonDefaultBranches) {
4308
4344
  this.createBranch({ owner: repo.owner, repo: repo.name, branch, from_branch: repo.default_branch });
4309
4345
  const branchFiles = repoSeed.files?.filter((file) => (file.branch ?? repo.default_branch) === branch) ?? [];
4310
- this.commitFiles(repo, branch, `Seed ${branch}`, branchFiles, "pome-agent");
4346
+ this.commitFiles(repo, branch, `Seed ${branch}`, this.seedFileChanges(repo, branch, branchFiles), "pome-agent");
4311
4347
  }
4312
4348
  for (const issue of repoSeed.issues ?? []) {
4313
4349
  const legacyAssignee = issue.assignee;
@@ -4412,6 +4448,34 @@ var GitHubDomain = class {
4412
4448
  after: { repositories: this.summarizeRepositories() }
4413
4449
  });
4414
4450
  }
4451
+ /**
4452
+ * F-1500 — expand a branch's seeded file entries into the commit that produces
4453
+ * them, turning each `renamed_from` into what a move actually is: the source
4454
+ * path deleted and its content written at the new path, in ONE commit.
4455
+ *
4456
+ * The source content is read off the branch rather than taken from the seed, so
4457
+ * a seeded move is an exact one by construction — the two blobs cannot drift
4458
+ * apart, which is the condition `calculatePullFiles` pairs on. (`seedSchema`
4459
+ * refuses a `renamed_from` entry that also names `content` for the same
4460
+ * reason.) The branch was created from the default branch a line earlier, so
4461
+ * the source path is the copy it inherited.
4462
+ */
4463
+ seedFileChanges(repo, branch, entries) {
4464
+ const changes = [];
4465
+ for (const entry2 of entries) {
4466
+ if (entry2.renamed_from === void 0) {
4467
+ changes.push({ path: entry2.path, content: entry2.content ?? "" });
4468
+ continue;
4469
+ }
4470
+ const source = this.getFile(repo.id, branch, normalizePath(entry2.renamed_from));
4471
+ if (!source) {
4472
+ conflict(`Seed sets renamed_from to ${entry2.renamed_from} on branch ${branch}, which holds no such file: a move's source must exist on the branch it moves on`);
4473
+ }
4474
+ changes.push({ path: entry2.renamed_from, content: "", delete: true });
4475
+ changes.push({ path: entry2.path, content: source.content });
4476
+ }
4477
+ return changes;
4478
+ }
4415
4479
  /**
4416
4480
  * F-1421 — plant one conversation comment on an issue or a pull request.
4417
4481
  *
@@ -4810,7 +4874,14 @@ var GitHubDomain = class {
4810
4874
  blob_url: `https://github.com/${repo.full_name}/blob/${commit.sha}/${version.path}`,
4811
4875
  raw_url: `https://raw.githubusercontent.com/${repo.full_name}/${commit.sha}/${version.path}`,
4812
4876
  contents_url: `https://api.github.com/repos/${repo.full_name}/contents/${version.path}?ref=${commit.sha}`,
4813
- patch: `@@ ${version.path} @@`
4877
+ patch: `@@ ${version.path} @@`,
4878
+ // F-1500 detects moves on the PULL REQUEST's branch diff only. The
4879
+ // commit and compare surfaces read `file_versions`, whose `status`
4880
+ // column has no `renamed` member, so they report a move the way they
4881
+ // always have — an add and a remove — and carry no pre-rename path.
4882
+ // Widening them is a shape change on two more routes and belongs with
4883
+ // whatever measures those routes, not here.
4884
+ previous_filename: null
4814
4885
  };
4815
4886
  });
4816
4887
  }
@@ -4836,7 +4907,9 @@ var GitHubDomain = class {
4836
4907
  blob_url: `https://github.com/${repo.full_name}/blob/${head.sha}/${path}`,
4837
4908
  raw_url: `https://raw.githubusercontent.com/${repo.full_name}/${head.sha}/${path}`,
4838
4909
  contents_url: `https://api.github.com/repos/${repo.full_name}/contents/${path}?ref=${head.sha}`,
4839
- patch: `@@ ${path} @@`
4910
+ patch: `@@ ${path} @@`,
4911
+ // See `computeCommitFiles` — the compare surface is outside F-1500.
4912
+ previous_filename: null
4840
4913
  });
4841
4914
  }
4842
4915
  return rows;
@@ -4936,25 +5009,35 @@ var GitHubDomain = class {
4936
5009
  const baseFiles = new Map(this.db.prepare("SELECT * FROM files WHERE repo_id = ? AND branch = ?").all(baseRepo.id, baseRef).map((file) => [file.path, file]));
4937
5010
  const headFiles = new Map(this.db.prepare("SELECT * FROM files WHERE repo_id = ? AND branch = ?").all(headRepo.id, headRef).map((file) => [file.path, file]));
4938
5011
  const paths = [.../* @__PURE__ */ new Set([...baseFiles.keys(), ...headFiles.keys()])].sort();
5012
+ const renames = detectRenames(paths.filter((path) => baseFiles.has(path) && !headFiles.has(path)).map((path) => ({ path, sha: baseFiles.get(path).sha })), paths.filter((path) => headFiles.has(path) && !baseFiles.has(path)).map((path) => ({ path, sha: headFiles.get(path).sha })));
5013
+ const movedFrom = new Set(renames.values());
4939
5014
  const rows = [];
4940
5015
  for (const path of paths) {
4941
5016
  const base = baseFiles.get(path);
4942
5017
  const head = headFiles.get(path);
4943
5018
  if (base?.sha === head?.sha)
4944
5019
  continue;
5020
+ if (movedFrom.has(path))
5021
+ continue;
5022
+ const previousFilename = renames.get(path) ?? null;
4945
5023
  const diff = linesChanged(base?.content, head?.content ?? "");
4946
5024
  rows.push({
4947
5025
  repo_id: baseRepo.id,
4948
5026
  pull_number: 0,
4949
5027
  filename: path,
4950
- status: base && head ? "modified" : head ? "added" : "removed",
4951
- additions: diff.additions,
4952
- deletions: head ? diff.deletions : base?.content.split("\n").length ?? 0,
4953
- changes: diff.additions + diff.deletions,
5028
+ status: previousFilename ? "renamed" : base && head ? "modified" : head ? "added" : "removed",
5029
+ // A detected move is an EXACT one (identical blobs), so it touches no
5030
+ // lines which is what GitHub reports for it. `linesChanged` would call
5031
+ // the whole file an addition, because from its path-by-path view the
5032
+ // destination is a file that did not exist.
5033
+ additions: previousFilename ? 0 : diff.additions,
5034
+ deletions: previousFilename ? 0 : head ? diff.deletions : base?.content.split("\n").length ?? 0,
5035
+ changes: previousFilename ? 0 : diff.additions + diff.deletions,
4954
5036
  blob_url: `https://github.com/${headRepo.full_name}/blob/${headRef}/${path}`,
4955
5037
  raw_url: `https://raw.githubusercontent.com/${headRepo.full_name}/${headRef}/${path}`,
4956
5038
  contents_url: `https://api.github.com/repos/${headRepo.full_name}/contents/${path}`,
4957
- patch: `@@ ${path} @@`
5039
+ patch: `@@ ${path} @@`,
5040
+ previous_filename: previousFilename
4958
5041
  });
4959
5042
  }
4960
5043
  return rows;
@@ -4962,7 +5045,7 @@ var GitHubDomain = class {
4962
5045
  replacePullFiles(repoId, pullNumber, files) {
4963
5046
  this.db.prepare("DELETE FROM pull_request_files WHERE repo_id = ? AND pull_number = ?").run(repoId, pullNumber);
4964
5047
  for (const file of files) {
4965
- this.db.prepare("INSERT INTO pull_request_files (repo_id, pull_number, filename, status, additions, deletions, changes, blob_url, raw_url, contents_url, patch) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)").run(repoId, pullNumber, file.filename, file.status, file.additions, file.deletions, file.changes, file.blob_url, file.raw_url, file.contents_url, file.patch);
5048
+ this.db.prepare("INSERT INTO pull_request_files (repo_id, pull_number, filename, status, additions, deletions, changes, blob_url, raw_url, contents_url, patch, previous_filename) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)").run(repoId, pullNumber, file.filename, file.status, file.additions, file.deletions, file.changes, file.blob_url, file.raw_url, file.contents_url, file.patch, file.previous_filename);
4966
5049
  }
4967
5050
  }
4968
5051
  // F-1178 — the `stack` member of GitHub's `pull-request` / `pull-request-simple`
@@ -0,0 +1,5 @@
1
+ export { UnsupportedTwinError, bootTwin } from './chunk-JGZFB6ZZ.js';
2
+ export { STRIPE_LOCAL_ACCOUNT_ID } from './chunk-LA52VCI4.js';
3
+ import './chunk-OW7VVW6X.js';
4
+ import './chunk-VBATFCWR.js';
5
+ import './chunk-SG6ZTIMT.js';
@@ -1,5 +1,5 @@
1
- import { bootTwin } from './chunk-IA2EYQ3Q.js';
2
- import { isTwinName, TWIN_NAMES, defaultPortFor, TWIN_REGISTRY } from './chunk-PRK5EFUZ.js';
1
+ import { bootTwin } from './chunk-JGZFB6ZZ.js';
2
+ import { isTwinName, TWIN_NAMES, defaultPortFor, TWIN_REGISTRY } from './chunk-LA52VCI4.js';
3
3
  import './chunk-OW7VVW6X.js';
4
4
  import './chunk-VBATFCWR.js';
5
5
  import './chunk-SG6ZTIMT.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pome-sh/cli",
3
- "version": "0.23.41",
3
+ "version": "0.23.43",
4
4
  "description": "Digital-twin testing for AI agents \u2014 run tasks against resettable local or hosted twins and record tool-call traces for evaluation on pome.sh.",
5
5
  "keywords": [
6
6
  "ai",
@@ -1,5 +0,0 @@
1
- export { UnsupportedTwinError, bootTwin } from './chunk-IA2EYQ3Q.js';
2
- export { STRIPE_LOCAL_ACCOUNT_ID } from './chunk-PRK5EFUZ.js';
3
- import './chunk-OW7VVW6X.js';
4
- import './chunk-VBATFCWR.js';
5
- import './chunk-SG6ZTIMT.js';