@open-mercato/cli 0.10.1-develop.8004.1.a8a79ee43f → 0.10.1-develop.8022.1.b6753de892
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/dist/agentic/guides/module-facts.json +162 -162
- package/dist/agentic/guides/module-facts.v2.json +162 -162
- package/dist/agentic/guides/modules/agent_orchestrator/index.md +1 -1
- package/dist/agentic/guides/modules/ai_assistant/index.md +1 -1
- package/dist/agentic/guides/modules/api_docs/index.md +1 -1
- package/dist/agentic/guides/modules/api_keys/index.md +1 -1
- package/dist/agentic/guides/modules/attachments/index.md +1 -1
- package/dist/agentic/guides/modules/audit_logs/index.md +1 -1
- package/dist/agentic/guides/modules/auth/index.md +1 -1
- package/dist/agentic/guides/modules/availability/index.md +1 -1
- package/dist/agentic/guides/modules/business_rules/index.md +1 -1
- package/dist/agentic/guides/modules/carrier_inpost/index.md +1 -1
- package/dist/agentic/guides/modules/cart/index.md +1 -1
- package/dist/agentic/guides/modules/catalog/index.md +1 -1
- package/dist/agentic/guides/modules/channel_apns/index.md +1 -1
- package/dist/agentic/guides/modules/channel_discord/index.md +1 -1
- package/dist/agentic/guides/modules/channel_expo/index.md +1 -1
- package/dist/agentic/guides/modules/channel_fcm/index.md +1 -1
- package/dist/agentic/guides/modules/channel_gmail/index.md +1 -1
- package/dist/agentic/guides/modules/channel_imap/index.md +1 -1
- package/dist/agentic/guides/modules/channel_resend/index.md +1 -1
- package/dist/agentic/guides/modules/channel_ses/index.md +1 -1
- package/dist/agentic/guides/modules/channel_smtp/index.md +1 -1
- package/dist/agentic/guides/modules/checkout/index.md +1 -1
- package/dist/agentic/guides/modules/communication_channels/index.md +1 -1
- package/dist/agentic/guides/modules/configs/index.md +1 -1
- package/dist/agentic/guides/modules/content/index.md +1 -1
- package/dist/agentic/guides/modules/currencies/index.md +1 -1
- package/dist/agentic/guides/modules/customer_accounts/index.md +1 -1
- package/dist/agentic/guides/modules/customer_groups/index.md +1 -1
- package/dist/agentic/guides/modules/customers/index.md +1 -1
- package/dist/agentic/guides/modules/dashboards/index.md +1 -1
- package/dist/agentic/guides/modules/data_sync/index.md +1 -1
- package/dist/agentic/guides/modules/design_system/index.md +1 -1
- package/dist/agentic/guides/modules/devices/index.md +1 -1
- package/dist/agentic/guides/modules/dictionaries/index.md +1 -1
- package/dist/agentic/guides/modules/directory/index.md +1 -1
- package/dist/agentic/guides/modules/documents/index.md +1 -1
- package/dist/agentic/guides/modules/ecommerce/index.md +1 -1
- package/dist/agentic/guides/modules/entities/index.md +1 -1
- package/dist/agentic/guides/modules/eudr/index.md +1 -1
- package/dist/agentic/guides/modules/events/index.md +1 -1
- package/dist/agentic/guides/modules/feature_toggles/index.md +1 -1
- package/dist/agentic/guides/modules/forms/index.md +1 -1
- package/dist/agentic/guides/modules/gateway_autopay/index.md +1 -1
- package/dist/agentic/guides/modules/gateway_stripe/index.md +1 -1
- package/dist/agentic/guides/modules/gateway_tpay/index.md +1 -1
- package/dist/agentic/guides/modules/generators/index.md +1 -1
- package/dist/agentic/guides/modules/inbox_ops/index.md +1 -1
- package/dist/agentic/guides/modules/integrations/index.md +1 -1
- package/dist/agentic/guides/modules/messages/index.md +1 -1
- package/dist/agentic/guides/modules/notifications/index.md +1 -1
- package/dist/agentic/guides/modules/onboarding/index.md +1 -1
- package/dist/agentic/guides/modules/payment_gateways/index.md +1 -1
- package/dist/agentic/guides/modules/perspectives/index.md +1 -1
- package/dist/agentic/guides/modules/phone_calls/index.md +1 -1
- package/dist/agentic/guides/modules/planner/index.md +1 -1
- package/dist/agentic/guides/modules/portal/index.md +1 -1
- package/dist/agentic/guides/modules/progress/index.md +1 -1
- package/dist/agentic/guides/modules/promotions/index.md +1 -1
- package/dist/agentic/guides/modules/push_notifications/index.md +1 -1
- package/dist/agentic/guides/modules/query_index/index.md +1 -1
- package/dist/agentic/guides/modules/record_locks/index.md +1 -1
- package/dist/agentic/guides/modules/resources/index.md +1 -1
- package/dist/agentic/guides/modules/sales/index.md +1 -1
- package/dist/agentic/guides/modules/scheduler/index.md +1 -1
- package/dist/agentic/guides/modules/search/index.md +1 -1
- package/dist/agentic/guides/modules/security/index.md +1 -1
- package/dist/agentic/guides/modules/seeds/index.md +1 -1
- package/dist/agentic/guides/modules/shipping_carriers/index.md +1 -1
- package/dist/agentic/guides/modules/sso/index.md +1 -1
- package/dist/agentic/guides/modules/staff/index.md +1 -1
- package/dist/agentic/guides/modules/storage_s3/index.md +1 -1
- package/dist/agentic/guides/modules/sync_akeneo/index.md +1 -1
- package/dist/agentic/guides/modules/sync_excel/index.md +1 -1
- package/dist/agentic/guides/modules/system_status_overlays/index.md +1 -1
- package/dist/agentic/guides/modules/telemetry/index.md +1 -1
- package/dist/agentic/guides/modules/tillio/index.md +1 -1
- package/dist/agentic/guides/modules/translations/index.md +1 -1
- package/dist/agentic/guides/modules/warranty_claims/index.md +1 -1
- package/dist/agentic/guides/modules/webhooks/index.md +1 -1
- package/dist/agentic/guides/modules/wms/index.md +1 -1
- package/dist/agentic/guides/modules/workflows/index.md +1 -1
- package/dist/agentic/guides/reference-module-facts.json +1 -1
- package/dist/agentic/guides/upstream/BACKWARD_COMPATIBILITY.md +4 -0
- package/dist/agentic/guides/upstream/manifest.json +2 -2
- package/dist/agentic/shared/ai/harness/cases.json +2 -2
- package/dist/agentic/shared/ai/trackers/github.md +257 -2
- package/dist/agentic/shared/scripts/execution-sandbox.mjs +1 -0
- package/dist/lib/generators/openapi.js +7 -2
- package/dist/lib/generators/openapi.js.map +2 -2
- package/dist/lib/telemetry-init.js +1 -1
- package/dist/lib/telemetry-init.js.map +1 -1
- package/dist/lib/testing/integration.js +22 -0
- package/dist/lib/testing/integration.js.map +2 -2
- package/package.json +7 -7
- package/src/lib/__tests__/telemetry-init.test.ts +1 -1
- package/src/lib/generators/__tests__/openapi.test.ts +24 -0
- package/src/lib/generators/openapi.ts +7 -2
- package/src/lib/telemetry-init.ts +1 -1
- package/src/lib/testing/__tests__/integration.test.ts +24 -0
- package/src/lib/testing/integration.ts +23 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
# staff — module facts (generated, do not edit)
|
|
2
|
-
<!-- generated from @open-mercato/core 0.10.1-develop.
|
|
2
|
+
<!-- generated from @open-mercato/core 0.10.1-develop.8022.1.b6753de892; core 0.10.1-develop.8022.1.b6753de892 — R1 staleness stamp -->
|
|
3
3
|
Source root: node_modules/@open-mercato/core/src/modules/staff
|
|
4
4
|
|
|
5
5
|
## Sections
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
# storage_s3 — module facts (generated, do not edit)
|
|
2
|
-
<!-- generated from @open-mercato/storage-s3 0.10.1-develop.
|
|
2
|
+
<!-- generated from @open-mercato/storage-s3 0.10.1-develop.8022.1.b6753de892; core 0.10.1-develop.8022.1.b6753de892 — R1 staleness stamp -->
|
|
3
3
|
Source root: node_modules/@open-mercato/storage-s3/src/modules/storage_s3
|
|
4
4
|
|
|
5
5
|
## Sections
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
# sync_akeneo — module facts (generated, do not edit)
|
|
2
|
-
<!-- generated from @open-mercato/sync-akeneo 0.10.1-develop.
|
|
2
|
+
<!-- generated from @open-mercato/sync-akeneo 0.10.1-develop.8022.1.b6753de892; core 0.10.1-develop.8022.1.b6753de892 — R1 staleness stamp -->
|
|
3
3
|
Source root: node_modules/@open-mercato/sync-akeneo/src/modules/sync_akeneo
|
|
4
4
|
|
|
5
5
|
## Sections
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
# sync_excel — module facts (generated, do not edit)
|
|
2
|
-
<!-- generated from @open-mercato/core 0.10.1-develop.
|
|
2
|
+
<!-- generated from @open-mercato/core 0.10.1-develop.8022.1.b6753de892; core 0.10.1-develop.8022.1.b6753de892 — R1 staleness stamp -->
|
|
3
3
|
Source root: node_modules/@open-mercato/core/src/modules/sync_excel
|
|
4
4
|
|
|
5
5
|
## Sections
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
# system_status_overlays — module facts (generated, do not edit)
|
|
2
|
-
<!-- generated from @open-mercato/enterprise 0.10.1-develop.
|
|
2
|
+
<!-- generated from @open-mercato/enterprise 0.10.1-develop.8022.1.b6753de892; core 0.10.1-develop.8022.1.b6753de892 — R1 staleness stamp -->
|
|
3
3
|
Source root: node_modules/@open-mercato/enterprise/src/modules/system_status_overlays
|
|
4
4
|
|
|
5
5
|
## Sections
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
# telemetry — module facts (generated, do not edit)
|
|
2
|
-
<!-- generated from @open-mercato/telemetry 0.10.1-develop.
|
|
2
|
+
<!-- generated from @open-mercato/telemetry 0.10.1-develop.8022.1.b6753de892; core 0.10.1-develop.8022.1.b6753de892 — R1 staleness stamp -->
|
|
3
3
|
Source root: node_modules/@open-mercato/telemetry/src/modules/telemetry
|
|
4
4
|
|
|
5
5
|
## Sections
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
# tillio — module facts (generated, do not edit)
|
|
2
|
-
<!-- generated from @open-mercato/tillio 0.10.1-develop.
|
|
2
|
+
<!-- generated from @open-mercato/tillio 0.10.1-develop.8022.1.b6753de892; core 0.10.1-develop.8022.1.b6753de892 — R1 staleness stamp -->
|
|
3
3
|
Source root: node_modules/@open-mercato/tillio/src/modules/tillio
|
|
4
4
|
|
|
5
5
|
## Sections
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
# translations — module facts (generated, do not edit)
|
|
2
|
-
<!-- generated from @open-mercato/core 0.10.1-develop.
|
|
2
|
+
<!-- generated from @open-mercato/core 0.10.1-develop.8022.1.b6753de892; core 0.10.1-develop.8022.1.b6753de892 — R1 staleness stamp -->
|
|
3
3
|
Source root: node_modules/@open-mercato/core/src/modules/translations
|
|
4
4
|
|
|
5
5
|
## Sections
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
# warranty_claims — module facts (generated, do not edit)
|
|
2
|
-
<!-- generated from @open-mercato/core 0.10.1-develop.
|
|
2
|
+
<!-- generated from @open-mercato/core 0.10.1-develop.8022.1.b6753de892; core 0.10.1-develop.8022.1.b6753de892 — R1 staleness stamp -->
|
|
3
3
|
Source root: node_modules/@open-mercato/core/src/modules/warranty_claims
|
|
4
4
|
|
|
5
5
|
## Sections
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
# webhooks — module facts (generated, do not edit)
|
|
2
|
-
<!-- generated from @open-mercato/webhooks 0.10.1-develop.
|
|
2
|
+
<!-- generated from @open-mercato/webhooks 0.10.1-develop.8022.1.b6753de892; core 0.10.1-develop.8022.1.b6753de892 — R1 staleness stamp -->
|
|
3
3
|
Source root: node_modules/@open-mercato/webhooks/src/modules/webhooks
|
|
4
4
|
|
|
5
5
|
## Sections
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
# wms — module facts (generated, do not edit)
|
|
2
|
-
<!-- generated from @open-mercato/core 0.10.1-develop.
|
|
2
|
+
<!-- generated from @open-mercato/core 0.10.1-develop.8022.1.b6753de892; core 0.10.1-develop.8022.1.b6753de892 — R1 staleness stamp -->
|
|
3
3
|
Source root: node_modules/@open-mercato/core/src/modules/wms
|
|
4
4
|
|
|
5
5
|
## Sections
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
# workflows — module facts (generated, do not edit)
|
|
2
|
-
<!-- generated from @open-mercato/core 0.10.1-develop.
|
|
2
|
+
<!-- generated from @open-mercato/core 0.10.1-develop.8022.1.b6753de892; core 0.10.1-develop.8022.1.b6753de892 — R1 staleness stamp -->
|
|
3
3
|
Source root: node_modules/@open-mercato/core/src/modules/workflows
|
|
4
4
|
|
|
5
5
|
## Sections
|
|
@@ -1185,7 +1185,7 @@
|
|
|
1185
1185
|
"facts": {
|
|
1186
1186
|
"title": "Example Module",
|
|
1187
1187
|
"description": "Demonstrates pages, APIs, entities and DI.",
|
|
1188
|
-
"coreVersion": "0.10.1-develop.
|
|
1188
|
+
"coreVersion": "0.10.1-develop.8022.1.b6753de892",
|
|
1189
1189
|
"sourcePackage": null,
|
|
1190
1190
|
"sourceVersion": null,
|
|
1191
1191
|
"sourceRoot": "src/modules/example",
|
|
@@ -635,6 +635,10 @@ STABLE tools/execute writes bypass approval; no bridge. [Migrate](UPGRADE_NOTES.
|
|
|
635
635
|
|
|
636
636
|
SCIM adds 429/503 before credentials; honor Retry-After. Optional `beforeAuth: ApiRouteBeforeAuth` is additive. See [contract and migration](.ai/specs/enterprise/implemented/SPEC-ENT-004-2026-02-19-sso-directory-sync.md#migration--backward-compatibility).
|
|
637
637
|
|
|
638
|
+
## Encryption maintenance safety gates (2026-11-02, #6767)
|
|
639
|
+
|
|
640
|
+
CLI safety confirmations changed; stop writers and restart replicas. [Flags, migration and stable formats](UPGRADE_NOTES.md#encryption-maintenance-safety-confirmations-6767).
|
|
641
|
+
|
|
638
642
|
## Staff Logout Uses Post/Redirect/Get (2026-11-05)
|
|
639
643
|
|
|
640
644
|
`POST /api/auth/logout` now returns `303 See Other` instead of `307`, including the cookieless branch ([#7383](https://github.com/open-mercato/open-mercato/issues/7383)). Browsers follow `Location: /login` with GET rather than repeating the logout POST. This intentionally corrects the status documented in the 2026-10-13 entry above; shared redirect helper defaults remain 307.
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 1,
|
|
3
|
-
"generator": "@open-mercato/cli@0.10.1-develop.
|
|
3
|
+
"generator": "@open-mercato/cli@0.10.1-develop.8022.1.b6753de892",
|
|
4
4
|
"files": {
|
|
5
5
|
"AGENTS.md": "35c948a32e06ca64b4706970c55ec60946412b410938b22478233a2c5c43df56",
|
|
6
|
-
"BACKWARD_COMPATIBILITY.md": "
|
|
6
|
+
"BACKWARD_COMPATIBILITY.md": "4e85dfc08b0e9542c78415e25a020e06e4ec3c3bb664b278b5aa3faa3523d873"
|
|
7
7
|
}
|
|
8
8
|
}
|
|
@@ -520,7 +520,7 @@
|
|
|
520
520
|
],
|
|
521
521
|
"maxContextFiles": 8,
|
|
522
522
|
"maxInitialContextBytes": 65536,
|
|
523
|
-
"maxTotalContextBytes":
|
|
523
|
+
"maxTotalContextBytes": 126976,
|
|
524
524
|
"relatedCases": [
|
|
525
525
|
"OMH-008"
|
|
526
526
|
]
|
|
@@ -5145,7 +5145,7 @@
|
|
|
5145
5145
|
],
|
|
5146
5146
|
"maxContextFiles": 8,
|
|
5147
5147
|
"maxInitialContextBytes": 65536,
|
|
5148
|
-
"maxTotalContextBytes":
|
|
5148
|
+
"maxTotalContextBytes": 126976,
|
|
5149
5149
|
"relatedCases": [
|
|
5150
5150
|
"OMH-065"
|
|
5151
5151
|
]
|
|
@@ -14,7 +14,7 @@ At runtime: `om-setup-agent-pipeline` copies this file into the repository at `.
|
|
|
14
14
|
- Issue and PR identifiers are numbers; in text they are written `#123`.
|
|
15
15
|
- A PR is linked to the issue it resolves with `Fixes #{issueId}` (or `Closes #{issueId}`) in the PR body; GitHub then closes the issue on merge. To reference without auto-closing, use a plain issue link.
|
|
16
16
|
- PRs open as **drafts** when a skill says so; a human (or **mark-pr-ready**) promotes them.
|
|
17
|
-
-
|
|
17
|
+
- GitHub claim ownership uses the create-only `refs/om-locks/{kind}-{number}` ref through **get-lock**, **acquire-lock**, and exact-SHA **release-lock**. Acquire first, retain run/comment ids and lock SHA, then assign when supported and verify guarded `in-progress`. For confirmed unassignable bot accounts, retain the atomic lock, timestamped claim comment and verified label without self-assignment. Foreign assignees and live or uncertain claims remain blockers. The `ci-monitoring` label is **not** a claim/lock signal: it marks a PR whose work is finished and already reported while an agent watches CI, so a PR carrying `ci-monitoring` without any of the three signals above MUST be treated as unclaimed and is free to claim.
|
|
18
18
|
- Long, multi-line comment bodies are posted with `--body-file` (or a heredoc via process substitution) so formatting is preserved.
|
|
19
19
|
- CI status truth comes from **get-pr-checks**; the set of *required* checks comes from **get-required-checks** (branch protection). When branch protection is not readable (404), treat every reported check as required.
|
|
20
20
|
|
|
@@ -234,7 +234,7 @@ gh api repos/{owner}/{repo}/issues/comments/{commentId} --jq '{body,user:.user.l
|
|
|
234
234
|
#### list-issue-comments
|
|
235
235
|
`{issueId or prNumber}` → conversation comments (PR conversation comments are issue comments on GitHub).
|
|
236
236
|
```bash
|
|
237
|
-
gh api repos/{owner}/{repo}/issues/{number}/comments --jq '.[] | {id,user:.user.login,body}'
|
|
237
|
+
gh api --paginate repos/{owner}/{repo}/issues/{number}/comments --jq '.[] | {id,user:.user.login,body,createdAt:.created_at,updatedAt:.updated_at}'
|
|
238
238
|
```
|
|
239
239
|
|
|
240
240
|
#### update-comment
|
|
@@ -243,6 +243,219 @@ gh api repos/{owner}/{repo}/issues/{number}/comments --jq '.[] | {id,user:.user.
|
|
|
243
243
|
gh api -X PATCH repos/{owner}/{repo}/issues/comments/{commentId} -F body=@<path>
|
|
244
244
|
```
|
|
245
245
|
|
|
246
|
+
```bash
|
|
247
|
+
tracker_repo() {
|
|
248
|
+
if [ -n "${REPO:-}" ]; then printf '%s\n' "$REPO";
|
|
249
|
+
else gh repo view --json nameWithOwner --jq .nameWithOwner; fi
|
|
250
|
+
}
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
#### get-lock
|
|
254
|
+
|
|
255
|
+
`{kind}` (`issue` or `pr`), `{item}` → `null` for an absent exact lock, or
|
|
256
|
+
`{ref,sha,repo,kind,item,runId,actor,createdAt}`. The authoritative GitHub lock is
|
|
257
|
+
`refs/om-locks/{kind}-{item}`. Its SHA points to an otherwise empty metadata
|
|
258
|
+
commit using the configured base's existing tree, with no branch/history edits.
|
|
259
|
+
The commit message binds the unique run id and actor; a base SHA alone cannot
|
|
260
|
+
identify two runs sharing a bot login. `createdAt` comes from the server commit
|
|
261
|
+
metadata, not a comment timestamp. Unknown/malformed refs and failed reads block.
|
|
262
|
+
Load these helpers before **acquire-lock** or **release-lock**:
|
|
263
|
+
|
|
264
|
+
```bash
|
|
265
|
+
gh_lock_target() {
|
|
266
|
+
case "$1" in issue|pr) ;; *) return 1 ;; esac
|
|
267
|
+
case "$2" in ''|*[!0-9]*) return 1 ;; esac
|
|
268
|
+
LOCK_REPO=$(tracker_repo) || return 1
|
|
269
|
+
LOCK_REF="refs/om-locks/$1-$2"
|
|
270
|
+
}
|
|
271
|
+
gh_get_lock() {
|
|
272
|
+
gh_lock_target "$1" "$2" || return 1
|
|
273
|
+
lock_refs=$(gh api "repos/$LOCK_REPO/git/matching-refs/om-locks/$1-$2") || return 1
|
|
274
|
+
lock_entry=$(printf '%s' "$lock_refs" | jq -c --arg ref "$LOCK_REF" '
|
|
275
|
+
if type != "array" then error("Invalid ref list") else
|
|
276
|
+
[.[] | select(.ref == $ref)] | if length == 0 then null
|
|
277
|
+
elif length == 1 and .[0].object.type == "commit" then .[0]
|
|
278
|
+
else error("Ambiguous lock ref") end end') || return 1
|
|
279
|
+
if [ "$lock_entry" = "null" ]; then printf 'null\n'; return 0; fi
|
|
280
|
+
lock_sha=$(printf '%s' "$lock_entry" | jq -er '.object.sha | select(test("^[0-9a-f]{40}$"))') || return 1
|
|
281
|
+
lock_commit=$(gh api "repos/$LOCK_REPO/git/commits/$lock_sha") || return 1
|
|
282
|
+
printf '%s' "$lock_commit" | jq -ce --arg repo "$LOCK_REPO" --arg kind "$1" --arg item "$2" --arg ref "$LOCK_REF" --arg sha "$lock_sha" '
|
|
283
|
+
.committer.date as $created |
|
|
284
|
+
.message | select(startswith("om-claim-v1\n")) | ltrimstr("om-claim-v1\n") | fromjson |
|
|
285
|
+
select(.repo == $repo and .kind == $kind and .item == $item and
|
|
286
|
+
(.runId | type == "string" and length > 0) and
|
|
287
|
+
(.actor | type == "string" and length > 0) and ($created | type == "string")) |
|
|
288
|
+
. + {ref:$ref,sha:$sha,createdAt:$created}'
|
|
289
|
+
}
|
|
290
|
+
gh_get_lock "{kind}" "{number}"
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
#### acquire-lock
|
|
294
|
+
|
|
295
|
+
`{kind}`, `{item}`, unique run id, authenticated actor, resolved base SHA →
|
|
296
|
+
`{status: acquired|owned|conflict, lock: <get-lock result>}`. On GitHub this is
|
|
297
|
+
mandatory, including for unassignable bots and PRs in split-provider setups.
|
|
298
|
+
Requires contents-write and authenticated Git transport for eventual release.
|
|
299
|
+
Never switch to comments on 403/422/transport errors: an existing ref is a
|
|
300
|
+
conflict only after an exact successful read proves its owner. Reconcile an
|
|
301
|
+
uncertain POST through **get-lock** before retrying. No labels/assignment/comment
|
|
302
|
+
candidate or work is produced by a losing fresh run.
|
|
303
|
+
|
|
304
|
+
```bash
|
|
305
|
+
gh_acquire_lock() {
|
|
306
|
+
# kind, item, run id, authenticated actor, configured base SHA
|
|
307
|
+
gh_lock_target "$1" "$2" || return 1
|
|
308
|
+
case "$3" in ''|*[!A-Za-z0-9._-]*) return 1 ;; esac
|
|
309
|
+
[ -n "$4" ] || return 1
|
|
310
|
+
printf '%s' "$5" | grep -Eq '^[0-9a-f]{40}$' || return 1
|
|
311
|
+
lock_before=$(gh_get_lock "$1" "$2") || return 1
|
|
312
|
+
if [ "$lock_before" != "null" ]; then
|
|
313
|
+
printf '%s' "$lock_before" | jq --arg run "$3" --arg actor "$4" '
|
|
314
|
+
{status:(if .runId == $run and .actor == $actor then "owned" else "conflict" end),lock:.}'
|
|
315
|
+
return 0
|
|
316
|
+
fi
|
|
317
|
+
lock_tree=$(gh api "repos/$LOCK_REPO/git/commits/$5" --jq '.tree.sha') || return 1
|
|
318
|
+
lock_message=$(jq -cn --arg repo "$LOCK_REPO" --arg kind "$1" --arg item "$2" --arg run "$3" --arg actor "$4" '
|
|
319
|
+
"om-claim-v1\n" + ({repo:$repo,kind:$kind,item:$item,runId:$run,actor:$actor}|tojson)') || return 1
|
|
320
|
+
lock_created=$(jq -n --argjson message "$lock_message" --arg tree "$lock_tree" --arg parent "$5" '
|
|
321
|
+
{message:$message,tree:$tree,parents:[$parent]}' |
|
|
322
|
+
gh api -X POST "repos/$LOCK_REPO/git/commits" --input -) || return 1
|
|
323
|
+
lock_proposed=$(printf '%s' "$lock_created" | jq -er '.sha | select(test("^[0-9a-f]{40}$"))') || return 1
|
|
324
|
+
# Create-only POST is the ownership decision; never PATCH/update an existing ref.
|
|
325
|
+
if gh api -X POST "repos/$LOCK_REPO/git/refs" -f "ref=$LOCK_REF" -f "sha=$lock_proposed" >/dev/null 2>&1; then
|
|
326
|
+
lock_posted=true
|
|
327
|
+
else
|
|
328
|
+
lock_posted=false
|
|
329
|
+
fi
|
|
330
|
+
lock_after=$(gh_get_lock "$1" "$2") || return 1
|
|
331
|
+
[ "$lock_after" != "null" ] || return 1
|
|
332
|
+
printf '%s' "$lock_after" | jq --arg run "$3" --arg actor "$4" --arg sha "$lock_proposed" --arg posted "$lock_posted" '
|
|
333
|
+
{status:(if .sha == $sha and .runId == $run and .actor == $actor then "acquired"
|
|
334
|
+
elif .runId == $run and .actor == $actor then "owned"
|
|
335
|
+
elif $posted == "false" then "conflict" else error("Lock replaced after creation") end),lock:.}'
|
|
336
|
+
}
|
|
337
|
+
gh_acquire_lock "{kind}" "{number}" "$CLAIM_RUN_ID" "$CURRENT_USER" "$BASE_SHA"
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
Persist the returned lock SHA plus run id before comment/label writes; reconcile
|
|
341
|
+
the same run on resume. A metadata commit created by a losing contender may be
|
|
342
|
+
unreferenced and garbage-collected; it contains no secrets or new project content.
|
|
343
|
+
|
|
344
|
+
#### release-lock
|
|
345
|
+
|
|
346
|
+
`{kind}`, `{item}`, exact expected lock SHA, expected owner run id/actor → delete
|
|
347
|
+
only that exact ref. Normal callers pass their own verified identity; recovery
|
|
348
|
+
passes the observed previous owner only after the shared stale/force/UI recovery
|
|
349
|
+
authorization checks. Keep the lock while cleaning up owned labels and marking
|
|
350
|
+
the comment released; delete the ref last. A loser never calls this operation.
|
|
351
|
+
|
|
352
|
+
```bash
|
|
353
|
+
gh_release_lock() {
|
|
354
|
+
# kind, item, expected SHA, expected owner's run id and actor
|
|
355
|
+
gh_lock_target "$1" "$2" || return 1
|
|
356
|
+
printf '%s' "$3" | grep -Eq '^[0-9a-f]{40}$' || return 1
|
|
357
|
+
lock_current=$(gh_get_lock "$1" "$2") || return 1
|
|
358
|
+
[ "$lock_current" != "null" ] || { printf 'absent\n'; return 0; }
|
|
359
|
+
printf '%s' "$lock_current" | jq -e --arg sha "$3" --arg run "$4" --arg actor "$5" '
|
|
360
|
+
.sha == $sha and .runId == $run and .actor == $actor' >/dev/null || return 1
|
|
361
|
+
lock_url=$(gh repo view "$LOCK_REPO" --json url --jq .url) || return 1
|
|
362
|
+
# Git's explicit expected-SHA lease is atomic compare-and-delete. REST DELETE
|
|
363
|
+
# has no expected-SHA condition and can remove a successor during recovery.
|
|
364
|
+
git push --porcelain --force-with-lease="$LOCK_REF:$3" "$lock_url.git" ":$LOCK_REF" || return 1
|
|
365
|
+
lock_remaining=$(gh_get_lock "$1" "$2") || return 1
|
|
366
|
+
if [ "$lock_remaining" = "null" ]; then printf 'released\n'
|
|
367
|
+
elif printf '%s' "$lock_remaining" | jq -e --arg sha "$3" '.sha != $sha' >/dev/null; then
|
|
368
|
+
printf 'released; successor retained\n'
|
|
369
|
+
else return 1; fi
|
|
370
|
+
}
|
|
371
|
+
gh_release_lock "{kind}" "{number}" "$CLAIM_LOCK_SHA" "$CLAIM_RUN_ID" "$CURRENT_USER"
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
This narrowly scoped lease-deletion is authorized lock housekeeping, never a
|
|
375
|
+
force-push of project branches. Resolve the target repository's GitHub URL as
|
|
376
|
+
above rather than assuming `origin` is the target. Do not change credentials,
|
|
377
|
+
remove hooks or retry with an unconditional REST DELETE when Git transport fails.
|
|
378
|
+
Absent is idempotent; a changed SHA/owner blocks and preserves the successor.
|
|
379
|
+
|
|
380
|
+
#### get-claim-reset
|
|
381
|
+
|
|
382
|
+
`{kind}`, `{item}` → latest tracker-audited human `claim-reset` label application
|
|
383
|
+
as `{id,createdAt,actor}`, or `null` if none. Read every event page, including past
|
|
384
|
+
applications after label removal. Verify the event actor is a human permitted to
|
|
385
|
+
manage item labels; bot applications and comment/body text never authorize reset.
|
|
386
|
+
A failed/unsupported audit read is not `null`: stop recovery and report the gap.
|
|
387
|
+
This cutoff permanently retires claim comments created strictly before it;
|
|
388
|
+
same-second/unknown timestamps are uncertain and remain blocking. It does not
|
|
389
|
+
relax QA, merge, scheduler reservations or command/process isolation.
|
|
390
|
+
|
|
391
|
+
```bash
|
|
392
|
+
gh_get_claim_reset() {
|
|
393
|
+
case "$1" in ''|*[!0-9]*) return 1 ;; esac
|
|
394
|
+
reset_pages=$(gh api --paginate --slurp "repos/$(tracker_repo)/issues/$1/events?per_page=100") || return 1
|
|
395
|
+
printf '%s' "$reset_pages" | jq -e 'type == "array" and all(.[]; type == "array")' >/dev/null || return 1
|
|
396
|
+
reset_event=$(printf '%s' "$reset_pages" | jq '
|
|
397
|
+
[ .[][] | select(.event == "labeled" and .label.name == "claim-reset" and .actor.type == "User") ]
|
|
398
|
+
| sort_by(.created_at, .id) | .[-1] // null') || return 1
|
|
399
|
+
if [ "$reset_event" = "null" ]; then printf 'null\n'; return 0; fi
|
|
400
|
+
reset_actor=$(printf '%s' "$reset_event" | jq -r '.actor.login') || return 1
|
|
401
|
+
case "$reset_actor" in ''|*[!A-Za-z0-9-]*) return 1 ;; esac
|
|
402
|
+
reset_permission=$(gh api "repos/$(tracker_repo)/collaborators/$reset_actor/permission") || return 1
|
|
403
|
+
printf '%s' "$reset_permission" | jq -e '
|
|
404
|
+
(.permission == "admin" or .permission == "write" or .permission == "maintain" or .permission == "triage")
|
|
405
|
+
or (.user.permissions | .admin == true or .maintain == true or .push == true or .triage == true)' >/dev/null || return 1
|
|
406
|
+
printf '%s' "$reset_event" | jq '{id: (.id | tostring), createdAt: .created_at, actor: .actor.login}'
|
|
407
|
+
}
|
|
408
|
+
gh_get_claim_reset "{number}"
|
|
409
|
+
```
|
|
410
|
+
|
|
411
|
+
The platform event plus repository-permission read proves human label authority.
|
|
412
|
+
A label still present is an operator-visible recovery breadcrumb, not a permanent
|
|
413
|
+
bypass. Removing it does not revive retired claims; remove and reapply to request
|
|
414
|
+
a later reset. Never apply this label automatically.
|
|
415
|
+
|
|
416
|
+
#### claim-winner
|
|
417
|
+
|
|
418
|
+
`{kind}`, `{item}`, `LIVE_CLAIM_IDS` (JSON array of comment handles from a complete
|
|
419
|
+
fresh **list-issue-comments** read, selected by the skill's live/stale policy) →
|
|
420
|
+
`{id,user,body}` for the lowest server creation-order candidate, or `null` when
|
|
421
|
+
none is visible. Missing/unreadable/incomplete data is an error, never an empty
|
|
422
|
+
success. Require the caller's own id in the fresh candidate set before proceeding.
|
|
423
|
+
Ignore explicitly `released`/`withdrawn` comments even if passed as live. Do not
|
|
424
|
+
filter by actor: two contenders may share one bot account. Numeric ids compare
|
|
425
|
+
numerically; opaque ids use creation time then stable id. The caller repeats the
|
|
426
|
+
read/election and performs the post-label ownership check; this is not atomic.
|
|
427
|
+
|
|
428
|
+
```bash
|
|
429
|
+
gh_claim_winner() {
|
|
430
|
+
# $1 = item number; $2 = LIVE_CLAIM_IDS as JSON string handles.
|
|
431
|
+
case "$1" in ''|*[!0-9]*) return 1 ;; esac
|
|
432
|
+
printf '%s' "$2" | jq -e 'type == "array" and all(.[]; type == "string")' >/dev/null || return 1
|
|
433
|
+
claim_pages=$(gh api --paginate --slurp "repos/$(tracker_repo)/issues/$1/comments?per_page=100") || return 1
|
|
434
|
+
printf '%s' "$claim_pages" | jq -e 'type == "array" and all(.[]; type == "array")' >/dev/null || return 1
|
|
435
|
+
printf '%s' "$claim_pages" | jq --argjson live "$2" '
|
|
436
|
+
[ .[][] | select((.id | tostring) as $id | $live | index($id))
|
|
437
|
+
| select((.body | test("(?m)^Claim-State: (released|withdrawn)\\r?$")) | not)
|
|
438
|
+
| {id: (.id | tostring), user: .user.login, body} ]
|
|
439
|
+
| sort_by(.id | [length, .]) | .[0] // null'
|
|
440
|
+
}
|
|
441
|
+
gh_claim_winner "{number}" "$LIVE_CLAIM_IDS"
|
|
442
|
+
```
|
|
443
|
+
|
|
444
|
+
All comment pages are read before ranking. Preserve REST numeric ids as string
|
|
445
|
+
handles at the operation boundary (do not substitute GraphQL node ids).
|
|
446
|
+
|
|
447
|
+
#### withdraw-claim
|
|
448
|
+
|
|
449
|
+
`{kind}`, `{item}`, `{commentId}`, full terminal body file, expected authenticated
|
|
450
|
+
actor and `Claim-Run` → rewrite only that run's original candidate through **update-comment**,
|
|
451
|
+
then read it back through **list-issue-comments**. Retain its legacy first line,
|
|
452
|
+
marker and run id; change `Claim-State: active` to `withdrawn` (loser) or `released`
|
|
453
|
+
(owner after cleanup), with the reason/winner. Before writing, verify exact item,
|
|
454
|
+
comment id, authenticated author and run id; a mismatch stops cleanup. Do not
|
|
455
|
+
edit a foreign candidate or delete its label. Return the same id and verified
|
|
456
|
+
terminal state; failed update/read-back is a blocker. Never fall back to a new
|
|
457
|
+
comment leaving the old active candidate in place.
|
|
458
|
+
|
|
246
459
|
### Pull requests
|
|
247
460
|
|
|
248
461
|
#### get-pr
|
|
@@ -478,3 +691,45 @@ gh label create risk-low --color 0e8a16 --description "Isolated, low bl
|
|
|
478
691
|
gh label create risk-medium --color fbca04 --description "Ordinary change with tests"
|
|
479
692
|
gh label create risk-high --color b60205 --description "Wide blast radius, review deeply"
|
|
480
693
|
```
|
|
694
|
+
|
|
695
|
+
#### list-review-comments
|
|
696
|
+
`{prNumber}` → every inline review comment on the diff (the conversation comments come from **list-issue-comments**; these are the ones anchored to a file and line).
|
|
697
|
+
```bash
|
|
698
|
+
gh api --paginate repos/{owner}/{repo}/pulls/{prNumber}/comments \
|
|
699
|
+
--jq '.[] | {id,user:.user.login,path,line:(.line // .original_line),body,url:.html_url,reply_to:.in_reply_to_id}'
|
|
700
|
+
```
|
|
701
|
+
REST does not expose a thread's resolved state (that lives in GraphQL's review threads), so treat every returned comment as potentially open and judge it against the current diff. `reply_to` is non-null on replies, which is what lets you reconstruct a thread. Consumers treat an unavailable operation as "inline feedback out of reach", not as a failure: they fall back to review bodies plus conversation comments and state the gap in their report.
|
|
702
|
+
|
|
703
|
+
|
|
704
|
+
#### approve-pending-runs
|
|
705
|
+
Head SHA → approve every workflow run on that commit that is waiting for maintainer approval (`conclusion` `action_required` — GitHub holds runs from first-time or outside contributors until a maintainer approves them). Prints the approved run ids; an empty result means nothing was waiting. Approving lets the contributor's workflow code run with this repository's CI, so callers approve only on a PR a human has authorized for automation (e.g. an `automerge` label) and read the diff's workflow changes first.
|
|
706
|
+
```bash
|
|
707
|
+
gh api "repos/{owner}/{repo}/actions/runs?head_sha={headSha}&status=action_required&per_page=100" \
|
|
708
|
+
--jq '.workflow_runs[].id' | while read -r run; do
|
|
709
|
+
gh api -X POST "repos/{owner}/{repo}/actions/runs/$run/approve" >/dev/null && echo "$run"
|
|
710
|
+
done
|
|
711
|
+
```
|
|
712
|
+
|
|
713
|
+
|
|
714
|
+
#### get-pr-author-association
|
|
715
|
+
`{prNumber}` → `{login, association}`, normalized from GitHub's `author_association`. GitHub reports `COLLABORATOR` for anyone with explicit repository access who is not an organization member, so on an organization-owned repository that is an `outside-collaborator`. `FIRST_TIMER` (first PR anywhere on GitHub) folds into `first-time-contributor`, and `MANNEQUIN` folds into `none`.
|
|
716
|
+
```bash
|
|
717
|
+
gh api "repos/{owner}/{repo}/pulls/{prNumber}" --jq '{login: .user.login, association: (
|
|
718
|
+
.author_association as $a | .base.repo.owner.type as $t |
|
|
719
|
+
if $a == "OWNER" then "owner"
|
|
720
|
+
elif $a == "MEMBER" then "member"
|
|
721
|
+
elif $a == "COLLABORATOR" then (if $t == "Organization" then "outside-collaborator" else "collaborator" end)
|
|
722
|
+
elif $a == "CONTRIBUTOR" then "contributor"
|
|
723
|
+
elif $a == "FIRST_TIME_CONTRIBUTOR" or $a == "FIRST_TIMER" then "first-time-contributor"
|
|
724
|
+
else "none" end)}'
|
|
725
|
+
```
|
|
726
|
+
|
|
727
|
+
|
|
728
|
+
#### close-pr
|
|
729
|
+
`{prNumber}` → close without merging; preserve the head branch, linked issues,
|
|
730
|
+
title and body. Post/update the caller's evidence note before calling. A fresh
|
|
731
|
+
**get-pr** must confirm `CLOSED` and no merge before reporting success; an
|
|
732
|
+
already merged PR is never reported as closed-obsolete.
|
|
733
|
+
```bash
|
|
734
|
+
gh api -X PATCH repos/{owner}/{repo}/pulls/{prNumber} -f state=closed
|
|
735
|
+
```
|
|
@@ -307,6 +307,7 @@ function linuxInvocation({ command, args, cwd, writableRoots, readOnlyRoots, net
|
|
|
307
307
|
sandboxArgs.push('--ro-bind', root, root)
|
|
308
308
|
}
|
|
309
309
|
for (const file of networkReadable) sandboxArgs.push('--ro-bind', file, file)
|
|
310
|
+
sandboxArgs.push('--remount-ro', '/', '--remount-ro', '/tmp')
|
|
310
311
|
const realCwd = regularDirectory(cwd, 'sandbox cwd')
|
|
311
312
|
sandboxArgs.push('--chdir', realCwd, '--', resolveExecutable(command, env), ...args)
|
|
312
313
|
return { command: bubblewrap, args: sandboxArgs, cwd: realCwd, env }
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import * as fs from "node:fs";
|
|
2
|
+
import { randomBytes } from "node:crypto";
|
|
2
3
|
import * as path from "node:path";
|
|
3
4
|
import { getEnabledModuleIdentities } from "../module-identity.js";
|
|
4
5
|
import { isModuleRouteFile } from "./scanner.js";
|
|
@@ -208,7 +209,7 @@ async function generateOpenApiViaBundle(routes, resolver, quiet) {
|
|
|
208
209
|
}
|
|
209
210
|
const cacheDir = path.join(rootDir, "node_modules", ".cache");
|
|
210
211
|
if (!fs.existsSync(cacheDir)) fs.mkdirSync(cacheDir, { recursive: true });
|
|
211
|
-
const bundlePath = path.join(cacheDir,
|
|
212
|
+
const bundlePath = path.join(cacheDir, `_openapi-bundle-${process.pid}-${randomBytes(6).toString("hex")}.mjs`);
|
|
212
213
|
let inputPaths = [];
|
|
213
214
|
const importLines = [
|
|
214
215
|
`import { buildOpenApiDocument } from ${JSON.stringify(generatorPath)};`
|
|
@@ -471,7 +472,11 @@ process.stdout.write(JSON.stringify(deepClone(doc), (_, v) =>
|
|
|
471
472
|
await esbuild.stop();
|
|
472
473
|
} catch {
|
|
473
474
|
}
|
|
474
|
-
|
|
475
|
+
try {
|
|
476
|
+
fs.unlinkSync(bundlePath);
|
|
477
|
+
} catch {
|
|
478
|
+
}
|
|
479
|
+
for (const file of ["_openapi-bundle.mjs", "_openapi-register.mjs", "_openapi-loader.mjs", "_next-stub.cjs"]) {
|
|
475
480
|
try {
|
|
476
481
|
fs.unlinkSync(path.join(cacheDir, file));
|
|
477
482
|
} catch {
|