@pome-sh/cli 0.23.12 → 0.23.14

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.12",
4
- "git_sha": "4f319a591b247522df587c1d0156a97130c2b0ae",
5
- "build_time": "2026-08-11T13:27:14.712Z"
3
+ "version": "0.23.14",
4
+ "git_sha": "43a7d48701b728fa11ae89ac2f7979764f57202b",
5
+ "build_time": "2026-08-11T19:35:40.126Z"
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-MA7NQHL2.js');
186
+ const { bootTwin } = await import('./twinHarness-7DY2UT3E.js');
187
187
  harness = await bootTwin({
188
188
  twin: "github",
189
189
  seedState: void 0,
@@ -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-YVKEN52P.js';
2
+ import { createHostedClient, perTwinReturnedByCloud, parseTaskFile, runAgentCommand, writeRunArtifactsCore, toTwinHttpEvent, redactJsonl, uploadRunBlobs, scoreFromFinalizeResponse, scoreStatus, evaluationCounts } from './chunk-YOTVS3WV.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 { existsSync } from 'node:fs';
@@ -1,4 +1,4 @@
1
- import { TWIN_NAMES, isTwinName, TWIN_REGISTRY } from './chunk-VO3FOSAZ.js';
1
+ import { TWIN_NAMES, isTwinName, TWIN_REGISTRY } from './chunk-LIU7WE6S.js';
2
2
  import { createFileBackedRecorderStore, createRecorderStore } from './chunk-TV5S6WQV.js';
3
3
 
4
4
  // src/recorder/recorder.ts
@@ -1,14 +1,14 @@
1
1
  // ../packages/twin-github/package.json
2
2
  var package_default = {
3
- version: "0.10.4"};
3
+ version: "0.10.6"};
4
4
 
5
5
  // ../packages/twin-slack/package.json
6
6
  var package_default2 = {
7
- version: "0.4.0"};
7
+ version: "0.4.1"};
8
8
 
9
9
  // ../packages/twin-stripe/package.json
10
10
  var package_default3 = {
11
- version: "0.4.6"};
11
+ version: "0.4.7"};
12
12
 
13
13
  // ../packages/twin-gmail/package.json
14
14
  var package_default4 = {
@@ -39,7 +39,7 @@ var TWIN_REGISTRY = {
39
39
  defaultSeedState,
40
40
  GitHubDomain,
41
41
  openGitHubCloneDatabase
42
- } = await import('./src-LX2POCA3.js');
42
+ } = await import('./src-WCMVMQYY.js');
43
43
  const db = openGitHubCloneDatabase();
44
44
  const domain = new GitHubDomain(db);
45
45
  domain.seed(seedState === void 0 ? defaultSeedState() : seedState);
@@ -59,9 +59,9 @@ var TWIN_REGISTRY = {
59
59
  envName: "SLACK",
60
60
  defaultPort: 3333,
61
61
  version: package_default2.version,
62
- defaultSeed: async () => (await import('./src-ZRMSHGVJ.js')).defaultSeedState(),
62
+ defaultSeed: async () => (await import('./src-W6P253DD.js')).defaultSeedState(),
63
63
  async boot({ seedState, runId, recorder }) {
64
- const { createSlackTwinApp, openSlackTwinDatabase, SlackDomain } = await import('./src-ZRMSHGVJ.js');
64
+ const { createSlackTwinApp, openSlackTwinDatabase, SlackDomain } = await import('./src-W6P253DD.js');
65
65
  const db = openSlackTwinDatabase(":memory:");
66
66
  const domain = new SlackDomain(db);
67
67
  domain.applySeed(seedState);
@@ -84,9 +84,9 @@ var TWIN_REGISTRY = {
84
84
  envName: "STRIPE",
85
85
  defaultPort: 3333,
86
86
  version: package_default3.version,
87
- defaultSeed: async () => (await import('./src-C2SRMLET.js')).defaultSeed(),
87
+ defaultSeed: async () => (await import('./src-ITPKDJJN.js')).defaultSeed(),
88
88
  async boot({ seedState, runId, recorder, twinBaseUrl }) {
89
- const stripeTwin = await import('./src-C2SRMLET.js');
89
+ const stripeTwin = await import('./src-ITPKDJJN.js');
90
90
  const { createApp } = await import('./server-DR56XIGP.js');
91
91
  const {
92
92
  applySeed: applyStripeSeed,
@@ -173,7 +173,7 @@ var TWIN_REGISTRY = {
173
173
  }
174
174
  };
175
175
  async function createGitHubSmokeApp() {
176
- const { createGitHubCloneApp } = await import('./src-LX2POCA3.js');
176
+ const { createGitHubCloneApp } = await import('./src-WCMVMQYY.js');
177
177
  return createGitHubCloneApp();
178
178
  }
179
179
  function defaultPortFor(twin, env = process.env) {
@@ -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-YVKEN52P.js';
4
- import { createRecorder, bootTwin } from './chunk-JT6MYL7P.js';
3
+ import { parseTaskFile, seedStateForTwin, runAgentCommand, writeRunArtifactsCore } from './chunk-YOTVS3WV.js';
4
+ import { createRecorder, bootTwin } from './chunk-55GQPSNU.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';
@@ -2,7 +2,7 @@ import { criterionSchema, finalizeResponseSchema, HostedDiscardRefusedError, Hos
2
2
  import { seedSchema, parseSeed, defaultSeedState as defaultSeedState$2 } from './chunk-KIUIKAVU.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-VO3FOSAZ.js';
5
+ import { isTwinName, TWIN_REGISTRY } from './chunk-LIU7WE6S.js';
6
6
  import { toTwinHttpEventRow } from './chunk-TV5S6WQV.js';
7
7
  import { redactEvent, redactSecrets } from './chunk-SG6ZTIMT.js';
8
8
  import { mkdir, appendFile, writeFile, readFile } from 'node:fs/promises';
@@ -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-W53FUKXL.js';
3
+ import { runTask, demoTaskPath, DEMO_TASK_NAME, DEMO_REPO } from './chunk-QN65HV4S.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-YVKEN52P.js';
6
+ import { createHostedClient, parseTaskFile, uploadRunBlobs, scoreFromFinalizeResponse, scoreStatus, outcomeOf } from './chunk-YOTVS3WV.js';
7
7
  import './chunk-NW7HGA2K.js';
8
8
  import { HostedQuotaError, HostedOrchError } from './chunk-X66JOOO7.js';
9
9
  import './chunk-KIUIKAVU.js';
10
10
  import './chunk-NJ246QPJ.js';
11
11
  import './chunk-ZKID2HS3.js';
12
- import { bootTwin } from './chunk-JT6MYL7P.js';
13
- import './chunk-VO3FOSAZ.js';
12
+ import { bootTwin } from './chunk-55GQPSNU.js';
13
+ import './chunk-LIU7WE6S.js';
14
14
  import './chunk-TV5S6WQV.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-PH6WR7HX.js';
2
+ import { runTaskHosted, resolveRunAgentIdentity } from './chunk-2QCITOSZ.js';
3
3
  import './chunk-ABM3CMQB.js';
4
- import { createHostedClient, parseTaskFile, outcomeOf } from './chunk-YVKEN52P.js';
4
+ import { createHostedClient, parseTaskFile, outcomeOf } from './chunk-YOTVS3WV.js';
5
5
  import './chunk-NW7HGA2K.js';
6
6
  import { HostedQuotaError, HostedTrialError } from './chunk-X66JOOO7.js';
7
7
  import './chunk-KIUIKAVU.js';
8
8
  import './chunk-NJ246QPJ.js';
9
9
  import './chunk-ZKID2HS3.js';
10
- import './chunk-VO3FOSAZ.js';
10
+ import './chunk-LIU7WE6S.js';
11
11
  import './chunk-TV5S6WQV.js';
12
12
  import './chunk-VBATFCWR.js';
13
13
  import './chunk-SG6ZTIMT.js';
@@ -1,10 +1,10 @@
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-PH6WR7HX.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-2QCITOSZ.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-W53FUKXL.js';
4
+ import { assetPath, runTask, resolvePackageRoot, DEMO_TASK_NAME, demoTaskPath } from '../../chunk-QN65HV4S.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-YVKEN52P.js';
7
+ import { parseTaskFile, scoreStatus, runScoreLine, readLatestRun, readMetaSummary, outcomeOf, readConfigTwins, scoreCountsSummary, markerFor, criterionMarkerLabel, twinSkipSuffix, readCodeCriteria, createHostedClient, toTwinHttpEvent, redactJsonl, scoreFromFinalizeResponse, parseGitHubSeedState, uploadRunBlobs, isPreSatisfied } from '../../chunk-YOTVS3WV.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';
@@ -15,8 +15,8 @@ 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-JT6MYL7P.js';
19
- import { TWIN_NAME_LIST, isTwinName, createGitHubSmokeApp } from '../../chunk-VO3FOSAZ.js';
18
+ import '../../chunk-55GQPSNU.js';
19
+ import { TWIN_NAME_LIST, isTwinName, createGitHubSmokeApp } from '../../chunk-LIU7WE6S.js';
20
20
  import '../../chunk-TV5S6WQV.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-LX2POCA3.js');
853
+ const { GitHubDomain, openGitHubCloneDatabase } = await import('../../src-WCMVMQYY.js');
854
854
  const db = openGitHubCloneDatabase(":memory:");
855
855
  try {
856
856
  new GitHubDomain(db).seed(seed);
@@ -4541,7 +4541,7 @@ var DEFAULT_AGENT_COMMAND = `node ${DEFAULT_AGENT_FILE}`;
4541
4541
  var MANIFEST_SCHEMA_URL = "https://pome.sh/schemas/v1/pome.json";
4542
4542
  var MAX_UNREADABLE_PATHS_SHOWN = 5;
4543
4543
  function readPackageVersion() {
4544
- if ("0.23.12".length > 0) return "0.23.12";
4544
+ if ("0.23.14".length > 0) return "0.23.14";
4545
4545
  try {
4546
4546
  const here = dirname(fileURLToPath(import.meta.url));
4547
4547
  const candidates = [
@@ -4996,7 +4996,7 @@ function createProgram() {
4996
4996
  return;
4997
4997
  }
4998
4998
  {
4999
- const { runDoctorChecks } = await import('../../checks-WOC5R2KN.js');
4999
+ const { runDoctorChecks } = await import('../../checks-CRT2VDNJ.js');
5000
5000
  const { renderDoctorReport } = await import('../../render-ZQQ4UMNO.js');
5001
5001
  const doctorReport = await runDoctorChecks({ mode: useLocal ? "full" : "hosted" });
5002
5002
  if (!doctorReport.ok) {
@@ -5034,7 +5034,7 @@ function createProgram() {
5034
5034
  taskForRuns.config.runs
5035
5035
  );
5036
5036
  if (k > 1) {
5037
- const { runTrialGroup } = await import('../../runTrialGroup-AVB6BMGB.js');
5037
+ const { runTrialGroup } = await import('../../runTrialGroup-DRMURVDS.js');
5038
5038
  const fileForRerun = relative(process.cwd(), file);
5039
5039
  const rerunCommand = defaultTask ? options.trials !== void 0 ? `pome run -n ${k}` : "pome run" : `pome run ${fileForRerun && !fileForRerun.startsWith("..") ? fileForRerun : file} -n ${k}`;
5040
5040
  const groupResult = await runTrialGroup({
@@ -5128,7 +5128,7 @@ function createProgram() {
5128
5128
  process.exitCode = 5;
5129
5129
  return;
5130
5130
  }
5131
- const { runDemo } = await import('../../runDemo-S3EGEUKV.js');
5131
+ const { runDemo } = await import('../../runDemo-5M6UZ63N.js');
5132
5132
  const result = await runDemo({
5133
5133
  apiBase: opts.apiUrl.replace(/\/$/, ""),
5134
5134
  dashboardBase: process.env.POME_DASHBOARD_URL ?? DEFAULT_DASHBOARD_URL,
@@ -5146,7 +5146,7 @@ function createProgram() {
5146
5146
  program.command("doctor").description(
5147
5147
  "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."
5148
5148
  ).action(async () => {
5149
- const { runDoctorChecks } = await import('../../checks-WOC5R2KN.js');
5149
+ const { runDoctorChecks } = await import('../../checks-CRT2VDNJ.js');
5150
5150
  const { renderDoctorReport } = await import('../../render-ZQQ4UMNO.js');
5151
5151
  const report = await runDoctorChecks();
5152
5152
  for (const line of renderDoctorReport(report, { passNote: true })) console.error(line);
@@ -5322,7 +5322,7 @@ function createProgram() {
5322
5322
  ).description(
5323
5323
  "Start a standalone twin as a long-lived foreground server (Ctrl-C to stop)"
5324
5324
  ).action(async (name, options) => {
5325
- const { runTwinStartCommand } = await import('../../twinStart-HKIRLN4U.js');
5325
+ const { runTwinStartCommand } = await import('../../twinStart-UFOABD4N.js');
5326
5326
  await runTwinStartCommand(name, options);
5327
5327
  });
5328
5328
  twin.command("reset").argument("[name]", "Twin name (default: github)", "github").description("Reset standalone twin state").action(async (name) => {
@@ -2947,11 +2947,27 @@ var STRIPE_ROUTES = {
2947
2947
  bodyEncoding: "form",
2948
2948
  body: CUSTOMER_FIELDS_BODY
2949
2949
  }),
2950
+ // F-1389 (ST-DECL-IN-001) — NOT `LIST_QUERY`. This is the one list surface
2951
+ // that does not take `created`: `GetCustomersCustomerPaymentMethods` declares
2952
+ // `allow_redisplay, ending_before, expand, limit, starting_after, type` and
2953
+ // nothing else, and Stripe's measured disposition is `refuse` — it publishes
2954
+ // `parameter_unknown`. Sharing `LIST_QUERY` here meant a request Stripe
2955
+ // rejects outright succeeded, so an exam scored a call the real API declined.
2956
+ // Leaving it undeclared is what makes the twin refuse it too: the declaration
2957
+ // IS the validator, and this twin's declarer is `refuse`. That is why this
2958
+ // one is spelled out rather than fixed by spreading a narrower shared shape —
2959
+ // the point is the absence, and a future `LIST_QUERY` edit must not put
2960
+ // `created` back by inheritance.
2950
2961
  listCustomerPaymentMethods: declareInputs({
2951
2962
  method: "GET",
2952
2963
  path: "/v1/customers/:id/payment_methods",
2953
2964
  pathParams: ID_PATH,
2954
- query: { ...LIST_QUERY, type: z.string().optional() }
2965
+ query: {
2966
+ limit: LIST_QUERY.limit,
2967
+ starting_after: LIST_QUERY.starting_after,
2968
+ ending_before: LIST_QUERY.ending_before,
2969
+ type: z.string().optional()
2970
+ }
2955
2971
  }),
2956
2972
  retrieveCustomer: declareInputs({
2957
2973
  method: "GET",
@@ -1526,7 +1526,7 @@ function conversationsOpen(domain, args, actor, onDelta = NOOP3) {
1526
1526
  function filesUpload(domain, args, actor, onDelta = NOOP3) {
1527
1527
  const workspace = domain.requireWorkspace();
1528
1528
  const acting = domain.resolveActorUser(actor);
1529
- const channelsRaw = args.channels ?? args.channel ?? "";
1529
+ const channelsRaw = args.channels ?? "";
1530
1530
  const channelIds = channelsRaw.split(",").map((s) => s.trim()).filter(Boolean).map((ref) => domain.requireChannel(ref).id);
1531
1531
  const id = domain.allocId(workspace.id, "F");
1532
1532
  const name = args.filename ?? `untitled-${id}.txt`;
@@ -2475,8 +2475,14 @@ var SLACK_WRITES = {
2475
2475
  timestamp: emptyIfAbsent()
2476
2476
  }),
2477
2477
  filesUpload: slackWrite("/files.upload", {
2478
+ // F-1389 (SLACK-DECL-IN-003) — `channels` (plural, comma-separated) only.
2479
+ // Slack has never documented a singular `channel` here, and the vendored
2480
+ // `slack_web_openapi_v2` snapshot agrees: it declares `channels` and eight
2481
+ // other real arguments, so it is not thin on this method. An upload
2482
+ // addressed `channel=C123` landed in that channel here and in no channel at
2483
+ // all on Slack. Undeclared now, so slack's measured disposition (`ignore`)
2484
+ // discards it instead of the handler forwarding it to `domain.filesUpload`.
2478
2485
  channels: absentIfEmpty(),
2479
- channel: absentIfEmpty(),
2480
2486
  filename: absentIfEmpty(),
2481
2487
  title: absentIfEmpty(),
2482
2488
  filetype: absentIfEmpty(),
@@ -2645,7 +2651,6 @@ function registerSlackRoutes(app, { domain, recorder }) {
2645
2651
  }, actor));
2646
2652
  write(SLACK_WRITES.filesUpload, (args, actor, delta) => domain.filesUpload({
2647
2653
  channels: args.channels,
2648
- channel: args.channel,
2649
2654
  filename: args.filename,
2650
2655
  title: args.title,
2651
2656
  filetype: args.filetype,
@@ -25,6 +25,22 @@ var repositoryBody = {
25
25
  var commentBody = { body: z.string().min(1) };
26
26
  var GITHUB_ROUTES = {
27
27
  // ----- search -----
28
+ //
29
+ // GH-DECL-IN-001 / GH-DECL-IN-002 (F-1389) — all five take `q` and nothing but
30
+ // `q`. GitHub's search API has ONE scoping input and encodes every filter as a
31
+ // qualifier inside it (`repo:octocat/hello-world`, `state:open`); its OpenAPI
32
+ // declares `q, sort, order, per_page, page`. `/search/code`,
33
+ // `/search/commits` and `/search/issues` used to declare `owner` / `repo`
34
+ // (and `state`) alongside and scope by them, so the same request was scoped
35
+ // here and unscoped on GitHub.
36
+ //
37
+ // They are undeclared rather than refused, per github's measured `ignore`
38
+ // ruling — a request still sending them gets the answer it would have got
39
+ // without them, which is what real GitHub does. The scoping moved into `q`:
40
+ // `domain/search.ts` parses `repo:` / `user:` / `org:` / `state:` out of it.
41
+ // Both halves had to land together — deleting the parameters alone would have
42
+ // left `q=idempotency repo:acme/api` still answering zero, which is the
43
+ // mirror defect and the worse one.
28
44
  searchRepositories: declareInputs({
29
45
  method: "GET",
30
46
  path: "/search/repositories",
@@ -33,23 +49,12 @@ var GITHUB_ROUTES = {
33
49
  searchCode: declareInputs({
34
50
  method: "GET",
35
51
  path: "/search/code",
36
- query: {
37
- q: z.string().optional(),
38
- owner: z.string().optional(),
39
- repo: z.string().optional(),
40
- ...pageQuery
41
- }
52
+ query: { q: z.string().optional(), ...pageQuery }
42
53
  }),
43
54
  searchIssues: declareInputs({
44
55
  method: "GET",
45
56
  path: "/search/issues",
46
- query: {
47
- q: z.string().optional(),
48
- owner: z.string().optional(),
49
- repo: z.string().optional(),
50
- state: stateFilter,
51
- ...pageQuery
52
- }
57
+ query: { q: z.string().optional(), ...pageQuery }
53
58
  }),
54
59
  searchUsers: declareInputs({
55
60
  method: "GET",
@@ -59,12 +64,7 @@ var GITHUB_ROUTES = {
59
64
  searchCommits: declareInputs({
60
65
  method: "GET",
61
66
  path: "/search/commits",
62
- query: {
63
- q: z.string().optional(),
64
- owner: z.string().optional(),
65
- repo: z.string().optional(),
66
- ...pageQuery
67
- }
67
+ query: { q: z.string().optional(), ...pageQuery }
68
68
  }),
69
69
  // ----- repositories -----
70
70
  getRepository: declareInputs({
@@ -76,15 +76,22 @@ var GITHUB_ROUTES = {
76
76
  method: "POST",
77
77
  path: "/user/repos",
78
78
  bodyEncoding: "json",
79
- body: { ...repositoryBody, owner: z.string().min(1).optional() }
79
+ // F-1389 (GH-DECL-IN-003) — no `owner`. This surface creates a repository
80
+ // for the AUTHENTICATED USER, which is its whole meaning;
81
+ // `repos/create-for-authenticated-user` declares 23 body properties and
82
+ // `owner` is not one. `routes.ts` passed the body straight to
83
+ // `domain.createRepository`, so the one surface defined not to take an
84
+ // owner could be made to create a repository under an arbitrary one.
85
+ // Undeclared now, so `parse()` never hands it to the handler, and github's
86
+ // measured disposition (`ignore`) discards it rather than 422-ing a request
87
+ // real GitHub accepts and ignores.
88
+ body: { ...repositoryBody }
80
89
  }),
81
- // `owner` is declared in BOTH locations, because the twin accepts it in both.
82
- //
83
- // The handler spreads the body schema and then overwrites `owner` with the
84
- // path value, so the body copy is read and discarded. Declaring only the path
85
- // one would turn that into a 422 for a request the twin has always accepted —
86
- // a divergence this ticket invented rather than found. The declaration records
87
- // what is true: two locations, one of which the handler ignores.
90
+ // `owner` stays declared on the ORG surface, and the contrast is the whole
91
+ // argument: there the handler overwrites it with the path value, so the body
92
+ // copy is read and discarded and nothing observable differs. That one is
93
+ // registered `accepted` (GH-DECL-IN-004); the `/user/repos` one above was
94
+ // registered `open-defect` because there the body copy reached the domain.
88
95
  createOrgRepository: declareInputs({
89
96
  method: "POST",
90
97
  path: "/orgs/:owner/repos",
@@ -121,8 +128,16 @@ var GITHUB_ROUTES = {
121
128
  message: z.string().min(1),
122
129
  content: z.string(),
123
130
  branch: z.string().optional(),
124
- sha: z.string().optional(),
125
- encoding: z.enum(["utf-8", "base64"]).optional()
131
+ sha: z.string().optional()
132
+ // F-1389 (GH-DECL-IN-005) — no `encoding`. GitHub declares `content` as
133
+ // "the new file content, using Base64 encoding" and takes no `encoding`
134
+ // parameter: base64 is the only encoding this surface has. Undeclared
135
+ // now, so github's measured disposition (`ignore`) discards it.
136
+ //
137
+ // ⚠️ This closes the DECLARED drift, not the behavioural one. The twin
138
+ // still treats `content` as plain text rather than base64 — recorded as
139
+ // divergence 24, and unified across both doors in the follow-up ticket
140
+ // that owns the 47-call-site migration.
126
141
  }
127
142
  }),
128
143
  listCommits: declareInputs({
@@ -996,10 +1011,17 @@ function executeTool(domain, name, input, onDelta, options = {}) {
996
1011
  return domain.getPullRequestCommits(pull);
997
1012
  case "get_reviews":
998
1013
  return domain.getPullRequestReviews(pull);
999
- // GitHub distinguishes issue-level `get_comments` from diff-level
1000
- // `get_review_comments`; this twin stores one comment thread per PR and
1001
- // answers both from it rather than inventing a split it does not model.
1014
+ // GitHub distinguishes the issue-level `get_comments` from the
1015
+ // diff-level `get_review_comments`, and so does this twin: a PR's
1016
+ // CONVERSATION lives in `issue_comments`, keyed on the PR's own number
1017
+ // because GitHub models a pull request as an issue (F-1151), while the
1018
+ // comments anchored to a file and line live in
1019
+ // `pull_request_review_comments`. Both halves of the justification that
1020
+ // stood here — one thread per PR, a split the twin does not model —
1021
+ // stopped being true at F-1151, and F-1421 then gave the seed both
1022
+ // vocabularies as separate fields (F-1423).
1002
1023
  case "get_comments":
1024
+ return domain.getPullRequestConversation(pull);
1003
1025
  case "get_review_comments":
1004
1026
  return domain.getPullRequestComments(pull);
1005
1027
  case "get_check_runs": {
@@ -2940,6 +2962,12 @@ function getPullRequestComments(domain, input) {
2940
2962
  const rows = domain.listPullRequestReviewCommentRows(repo.id, input.pull_number);
2941
2963
  return paginate(rows, input.page, input.per_page ?? input.perPage).map((comment) => pullRequestReviewCommentJson(comment, repo));
2942
2964
  }
2965
+ function getPullRequestConversation(domain, input) {
2966
+ const repo = domain.requireRepo(input.owner, input.repo);
2967
+ domain.requirePullRequest(repo.id, input.pull_number);
2968
+ const rows = domain.listIssueCommentRows(repo.id, input.pull_number);
2969
+ return paginate(rows, input.page, input.per_page ?? input.perPage).map((comment) => issueCommentJson(comment, repo, "pull_request"));
2970
+ }
2943
2971
  function getPullRequestStatus(domain, input) {
2944
2972
  const repo = domain.requireRepo(input.owner, input.repo);
2945
2973
  const pr = domain.requirePullRequest(repo.id, input.pull_number);
@@ -3293,6 +3321,39 @@ function addCollaboratorAction(domain, input, onDelta) {
3293
3321
  }
3294
3322
 
3295
3323
  // ../packages/twin-github/dist/src/domain/search.js
3324
+ var QUALIFIER = /(^|\s)(repo|user|org|state):(\S+)/gi;
3325
+ function parseSearchQuery(raw, options = {}) {
3326
+ const owners = [];
3327
+ const fullNames = [];
3328
+ let state;
3329
+ const text = raw.replace(QUALIFIER, (whole, lead, key, rawValue) => {
3330
+ const value = rawValue.toLowerCase();
3331
+ switch (key.toLowerCase()) {
3332
+ case "repo":
3333
+ if (!value.includes("/"))
3334
+ return whole;
3335
+ fullNames.push(value);
3336
+ return lead;
3337
+ case "user":
3338
+ case "org":
3339
+ owners.push(value);
3340
+ return lead;
3341
+ case "state":
3342
+ if (!options.state || value !== "open" && value !== "closed")
3343
+ return whole;
3344
+ state = value;
3345
+ return lead;
3346
+ default:
3347
+ return whole;
3348
+ }
3349
+ });
3350
+ return { text: text.replace(/\s+/g, " ").trim().toLowerCase(), owners, fullNames, state };
3351
+ }
3352
+ function inScope(parsed, owner, fullName) {
3353
+ if (parsed.owners.length === 0 && parsed.fullNames.length === 0)
3354
+ return true;
3355
+ return parsed.fullNames.includes(fullName.toLowerCase()) || parsed.owners.includes(owner.toLowerCase());
3356
+ }
3296
3357
  function searchRepositories(domain, input) {
3297
3358
  const query = (input.query ?? input.q ?? "").toLowerCase();
3298
3359
  const repos = domain.db.prepare("SELECT * FROM repositories ORDER BY full_name ASC").all().filter((repo) => !query || repo.full_name.toLowerCase().includes(query) || repo.description.toLowerCase().includes(query));
@@ -3306,13 +3367,14 @@ function searchUsers(domain, input) {
3306
3367
  return { total_count: users.length, incomplete_results: false, items: paginate(users, input.page, input.per_page ?? input.perPage).map((user) => userJson(user.login, user.type)) };
3307
3368
  }
3308
3369
  function searchCode(domain, input) {
3309
- const query = (input.query ?? input.q ?? "").toLowerCase();
3370
+ const parsed = parseSearchQuery(input.query ?? input.q ?? "");
3310
3371
  let rows = domain.db.prepare("SELECT files.*, repositories.owner, repositories.name, repositories.full_name, repositories.description, repositories.private, repositories.default_branch, repositories.fork, repositories.parent_full_name, repositories.entity_counter, repositories.created_at, repositories.updated_at FROM files INNER JOIN repositories ON files.repo_id = repositories.id WHERE files.branch = repositories.default_branch ORDER BY repositories.full_name, files.path").all();
3311
3372
  if (input.owner)
3312
3373
  rows = rows.filter((row) => row.owner === input.owner);
3313
3374
  if (input.repo)
3314
3375
  rows = rows.filter((row) => row.name === input.repo);
3315
- rows = rows.filter((row) => !query || row.path.toLowerCase().includes(query) || row.content.toLowerCase().includes(query));
3376
+ rows = rows.filter((row) => inScope(parsed, row.owner, row.full_name));
3377
+ rows = rows.filter((row) => !parsed.text || row.path.toLowerCase().includes(parsed.text) || row.content.toLowerCase().includes(parsed.text));
3316
3378
  return {
3317
3379
  total_count: rows.length,
3318
3380
  incomplete_results: false,
@@ -3328,19 +3390,20 @@ function searchCode(domain, input) {
3328
3390
  };
3329
3391
  }
3330
3392
  function searchCommits(domain, input) {
3331
- const query = (input.query ?? input.q ?? "").toLowerCase();
3393
+ const parsed = parseSearchQuery(input.query ?? input.q ?? "");
3332
3394
  let repos = domain.db.prepare("SELECT * FROM repositories ORDER BY full_name ASC").all();
3333
3395
  if (input.owner)
3334
3396
  repos = repos.filter((repo) => repo.owner === input.owner);
3335
3397
  if (input.repo)
3336
3398
  repos = repos.filter((repo) => repo.name === input.repo);
3399
+ repos = repos.filter((repo) => inScope(parsed, repo.owner, repo.full_name));
3337
3400
  const matches = [];
3338
3401
  for (const repo of repos) {
3339
3402
  const branch = domain.db.prepare("SELECT * FROM branches WHERE repo_id = ? AND name = ?").get(repo.id, repo.default_branch);
3340
3403
  if (!branch?.head_sha)
3341
3404
  continue;
3342
3405
  for (const commit of domain.commitAncestry(repo.id, branch.head_sha)) {
3343
- if (!query || commit.message.toLowerCase().includes(query) || commit.author_login.toLowerCase().includes(query))
3406
+ if (!parsed.text || commit.message.toLowerCase().includes(parsed.text) || commit.author_login.toLowerCase().includes(parsed.text))
3344
3407
  matches.push({ commit, repo });
3345
3408
  }
3346
3409
  }
@@ -3351,15 +3414,17 @@ function searchCommits(domain, input) {
3351
3414
  };
3352
3415
  }
3353
3416
  function searchIssues(domain, input) {
3354
- const query = (input.query ?? input.q ?? "").toLowerCase();
3417
+ const parsed = parseSearchQuery(input.query ?? input.q ?? "", { state: true });
3355
3418
  const rows = domain.db.prepare("SELECT issues.*, repositories.owner, repositories.name, repositories.full_name, repositories.description, repositories.private, repositories.default_branch, repositories.fork, repositories.parent_full_name, repositories.entity_counter, repositories.created_at AS repo_created_at, repositories.updated_at AS repo_updated_at FROM issues INNER JOIN repositories ON issues.repo_id = repositories.id ORDER BY issues.updated_at DESC").all();
3356
- let filtered = rows.filter((issue) => !query || issue.title.toLowerCase().includes(query) || issue.body.toLowerCase().includes(query) || issue.full_name.toLowerCase().includes(query));
3419
+ let filtered = rows.filter((issue) => !parsed.text || issue.title.toLowerCase().includes(parsed.text) || issue.body.toLowerCase().includes(parsed.text) || issue.full_name.toLowerCase().includes(parsed.text));
3420
+ filtered = filtered.filter((issue) => inScope(parsed, issue.owner, issue.full_name));
3357
3421
  if (input.owner)
3358
3422
  filtered = filtered.filter((issue) => issue.owner === input.owner);
3359
3423
  if (input.repo)
3360
3424
  filtered = filtered.filter((issue) => issue.name === input.repo);
3361
- if (input.state && input.state !== "all")
3362
- filtered = filtered.filter((issue) => issue.state === input.state);
3425
+ const state = parsed.state ?? (input.state === "all" ? void 0 : input.state);
3426
+ if (state)
3427
+ filtered = filtered.filter((issue) => issue.state === state);
3363
3428
  return {
3364
3429
  total_count: filtered.length,
3365
3430
  incomplete_results: false,
@@ -3700,6 +3765,9 @@ var GitHubDomain = class {
3700
3765
  getPullRequestComments(input) {
3701
3766
  return getPullRequestComments(this, input);
3702
3767
  }
3768
+ getPullRequestConversation(input) {
3769
+ return getPullRequestConversation(this, input);
3770
+ }
3703
3771
  getPullRequestStatus(input) {
3704
3772
  return getPullRequestStatus(this, input);
3705
3773
  }
@@ -0,0 +1,5 @@
1
+ export { UnsupportedTwinError, bootTwin } from './chunk-55GQPSNU.js';
2
+ export { STRIPE_LOCAL_ACCOUNT_ID } from './chunk-LIU7WE6S.js';
3
+ import './chunk-TV5S6WQV.js';
4
+ import './chunk-VBATFCWR.js';
5
+ import './chunk-SG6ZTIMT.js';
@@ -1,5 +1,5 @@
1
- import { bootTwin } from './chunk-JT6MYL7P.js';
2
- import { isTwinName, TWIN_NAMES, defaultPortFor, TWIN_REGISTRY } from './chunk-VO3FOSAZ.js';
1
+ import { bootTwin } from './chunk-55GQPSNU.js';
2
+ import { isTwinName, TWIN_NAMES, defaultPortFor, TWIN_REGISTRY } from './chunk-LIU7WE6S.js';
3
3
  import './chunk-TV5S6WQV.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.12",
3
+ "version": "0.23.14",
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-JT6MYL7P.js';
2
- export { STRIPE_LOCAL_ACCOUNT_ID } from './chunk-VO3FOSAZ.js';
3
- import './chunk-TV5S6WQV.js';
4
- import './chunk-VBATFCWR.js';
5
- import './chunk-SG6ZTIMT.js';