@1aboveio/skills 1.0.7 → 1.0.9
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/.codex-plugin/plugin.json +13 -0
- package/.codex-plugin/resources.json +1827 -0
- package/README.md +22 -0
- package/package.json +9 -2
- package/skills/app-dev/airflow/SKILL.md +1 -1
- package/skills/app-dev/airflow/release-check.mjs +3 -1
- package/skills/app-dev/android-foundation/SKILL.md +92 -34
- package/skills/app-dev/android-foundation/assets/android-ci-job.yml +13 -7
- package/skills/app-dev/android-foundation/references/ci.md +23 -13
- package/skills/app-dev/android-foundation/references/delivery-focus.md +29 -0
- package/skills/app-dev/android-foundation/references/diagnosis.md +136 -0
- package/skills/app-dev/android-foundation/references/gotchas.md +20 -11
- package/skills/app-dev/android-foundation/references/setup.md +15 -6
- package/skills/app-dev/android-foundation/release-check.mjs +3 -1
- package/skills/app-dev/android-foundation/scripts/device-run.sh +148 -42
- package/skills/app-dev/app-debug/SKILL.md +1 -1
- package/skills/app-dev/app-debug/release-check.mjs +3 -1
- package/skills/app-dev/better-auth/SKILL.md +1 -1
- package/skills/app-dev/better-auth/release-check.mjs +3 -1
- package/skills/app-dev/data-catalog/SKILL.md +1 -1
- package/skills/app-dev/data-catalog/release-check.mjs +3 -1
- package/skills/app-dev/data-quality/SKILL.md +1 -1
- package/skills/app-dev/data-quality/release-check.mjs +3 -1
- package/skills/app-dev/ios-foundation/SKILL.md +1 -1
- package/skills/app-dev/ios-foundation/release-check.mjs +3 -1
- package/skills/app-dev/monorepo/SKILL.md +1 -1
- package/skills/app-dev/monorepo/release-check.mjs +3 -1
- package/skills/app-dev/nextjs-fullstack/SKILL.md +1 -1
- package/skills/app-dev/nextjs-fullstack/release-check.mjs +3 -1
- package/skills/app-dev/prisma-setup/SKILL.md +1 -1
- package/skills/app-dev/prisma-setup/release-check.mjs +3 -1
- package/skills/app-dev/pyspark/SKILL.md +1 -1
- package/skills/app-dev/pyspark/release-check.mjs +3 -1
- package/skills/app-dev/python-backend/SKILL.md +1 -1
- package/skills/app-dev/python-backend/release-check.mjs +3 -1
- package/skills/app-dev/shadcn/SKILL.md +1 -1
- package/skills/app-dev/shadcn/release-check.mjs +3 -1
- package/skills/app-dev/zod-v4/SKILL.md +1 -1
- package/skills/app-dev/zod-v4/release-check.mjs +3 -1
- package/skills/cicd/cloud-build/SKILL.md +1 -1
- package/skills/cicd/cloud-build/release-check.mjs +3 -1
- package/skills/cicd/cloud-debug/SKILL.md +1 -1
- package/skills/cicd/cloud-debug/release-check.mjs +3 -1
- package/skills/cicd/cloud-deploy/SKILL.md +1 -1
- package/skills/cicd/cloud-deploy/release-check.mjs +3 -1
- package/skills/cicd/docker/SKILL.md +1 -1
- package/skills/cicd/docker/release-check.mjs +3 -1
- package/skills/cicd/github-actions/SKILL.md +1 -1
- package/skills/cicd/github-actions/release-check.mjs +3 -1
- package/skills/cicd/github-flow/SKILL.md +1 -1
- package/skills/cicd/github-flow/release-check.mjs +3 -1
- package/skills/cicd/google-cloud/SKILL.md +1 -1
- package/skills/cicd/google-cloud/release-check.mjs +3 -1
- package/skills/cicd/mergify/SKILL.md +1 -1
- package/skills/cicd/mergify/release-check.mjs +3 -1
- package/skills/cicd/podman/SKILL.md +1 -1
- package/skills/cicd/podman/release-check.mjs +3 -1
- package/skills/content/article-review/SKILL.md +1 -1
- package/skills/content/article-review/release-check.mjs +3 -1
- package/skills/content/article-to-image/SKILL.md +1 -1
- package/skills/content/article-to-image/release-check.mjs +3 -1
- package/skills/content/flowchart-svg/SKILL.md +1 -1
- package/skills/content/flowchart-svg/release-check.mjs +3 -1
- package/skills/content/image-gen/SKILL.md +1 -1
- package/skills/content/image-gen/release-check.mjs +3 -1
- package/skills/content/mermaid/SKILL.md +1 -1
- package/skills/content/mermaid/release-check.mjs +3 -1
- package/skills/content/wechat-article-writer/SKILL.md +1 -1
- package/skills/content/wechat-article-writer/release-check.mjs +3 -1
- package/skills/content/wechat-publisher/SKILL.md +1 -1
- package/skills/content/wechat-publisher/release-check.mjs +3 -1
- package/skills/content/wechat-search/SKILL.md +1 -1
- package/skills/content/wechat-search/release-check.mjs +3 -1
- package/skills/content/xai-search/SKILL.md +88 -13
- package/skills/content/xai-search/release-check.mjs +3 -1
- package/skills/content/xai-search/scripts/xai_search.sh +125 -149
- package/skills/core/distill-writing/SKILL.md +1 -1
- package/skills/core/distill-writing/release-check.mjs +3 -1
- package/skills/core/doc-to-md/SKILL.md +1 -1
- package/skills/core/doc-to-md/release-check.mjs +3 -1
- package/skills/core/editorial-review/SKILL.md +1 -1
- package/skills/core/editorial-review/release-check.mjs +3 -1
- package/skills/core/house-style/SKILL.md +1 -1
- package/skills/core/house-style/release-check.mjs +3 -1
- package/skills/core/plain-language/SKILL.md +1 -1
- package/skills/core/plain-language/release-check.mjs +3 -1
- package/skills/core/polish-cn/SKILL.md +1 -1
- package/skills/core/polish-cn/release-check.mjs +3 -1
- package/skills/core/reg-parser/SKILL.md +1 -1
- package/skills/core/reg-parser/release-check.mjs +3 -1
- package/skills/core/terminology/SKILL.md +1 -1
- package/skills/core/terminology/release-check.mjs +3 -1
- package/skills/core/write-doc/SKILL.md +1 -1
- package/skills/core/write-doc/release-check.mjs +3 -1
- package/skills/engineering/better-review/SKILL.md +1 -1
- package/skills/engineering/better-review/release-check.mjs +3 -1
- package/skills/engineering/contributing/SKILL.md +1 -1
- package/skills/engineering/contributing/release-check.mjs +3 -1
- package/skills/engineering/e2e-test/SKILL.md +1 -1
- package/skills/engineering/e2e-test/release-check.mjs +3 -1
- package/skills/engineering/engineering-runtime/SKILL.md +1 -1
- package/skills/engineering/engineering-runtime/coherence/workflow.json +13 -13
- package/skills/engineering/engineering-runtime/release-check.mjs +3 -1
- package/skills/engineering/engineering-runtime/scripts/installation-resolver.mjs +191 -0
- package/skills/engineering/engineering-runtime/scripts/workflow-coherence.mjs +51 -10
- package/skills/engineering/ensure-coverage/SKILL.md +1 -1
- package/skills/engineering/ensure-coverage/release-check.mjs +3 -1
- package/skills/engineering/golden-path/SKILL.md +1 -1
- package/skills/engineering/golden-path/release-check.mjs +3 -1
- package/skills/engineering/harness-runtime/SKILL.md +1 -1
- package/skills/engineering/harness-runtime/release-check.mjs +3 -1
- package/skills/engineering/resolve-issues/SKILL.md +11 -20
- package/skills/engineering/resolve-issues/references/delivery-progress.md +63 -0
- package/skills/engineering/resolve-issues/references/expire.md +24 -11
- package/skills/engineering/resolve-issues/references/implementation.md +9 -1
- package/skills/engineering/resolve-issues/references/preflight.md +7 -0
- package/skills/engineering/resolve-issues/references/shared-modules.md +27 -0
- package/skills/engineering/resolve-issues/references/task-plan.md +12 -5
- package/skills/engineering/resolve-issues/release-check.mjs +3 -1
- package/skills/engineering/resolve-issues/scripts/active-installation.mjs +32 -0
- package/skills/engineering/resolve-issues/scripts/install-hooks.mjs +3 -0
- package/skills/engineering/resolve-issues/scripts/rehydrate.mjs +17 -1
- package/skills/engineering/resolve-release/SKILL.md +1 -1
- package/skills/engineering/resolve-release/release-check.mjs +3 -1
- package/skills/engineering/rush-issues/SKILL.md +5 -2
- package/skills/engineering/rush-issues/release-check.mjs +3 -1
- package/skills/engineering/rush-release/SKILL.md +1 -1
- package/skills/engineering/rush-release/release-check.mjs +3 -1
- package/skills/engineering/test-quality/SKILL.md +1 -1
- package/skills/engineering/test-quality/release-check.mjs +3 -1
- package/skills/risk-compliance/compliance-audit/SKILL.md +1 -1
- package/skills/risk-compliance/compliance-audit/release-check.mjs +3 -1
- package/skills/risk-compliance/contract-compare/SKILL.md +1 -1
- package/skills/risk-compliance/contract-compare/release-check.mjs +3 -1
- package/skills/risk-compliance/contract-review/SKILL.md +1 -1
- package/skills/risk-compliance/contract-review/release-check.mjs +3 -1
- package/skills/risk-compliance/doc-authenticity/SKILL.md +1 -1
- package/skills/risk-compliance/doc-authenticity/release-check.mjs +3 -1
- package/skills/risk-compliance/fraud-analysis/SKILL.md +1 -1
- package/skills/risk-compliance/fraud-analysis/release-check.mjs +3 -1
- package/skills/risk-compliance/payment-analysis/SKILL.md +1 -1
- package/skills/risk-compliance/payment-analysis/release-check.mjs +3 -1
- package/skills/risk-compliance/similar-domain/SKILL.md +1 -1
- package/skills/risk-compliance/similar-domain/release-check.mjs +3 -1
- package/skills/risk-compliance/tld-detection/SKILL.md +1 -1
- package/skills/risk-compliance/tld-detection/release-check.mjs +3 -1
- package/skills/app-dev/android-foundation/scripts/device-run.test.mjs +0 -172
- package/skills/app-dev/data-catalog/scripts/data-catalog.test.mjs +0 -36
- package/skills/app-dev/data-quality/scripts/data-quality.test.mjs +0 -12
- package/skills/cicd/github-actions/scripts/ci-run-audit.test.mjs +0 -637
- package/skills/cicd/github-flow/scripts/flow.test.mjs +0 -114
- package/skills/cicd/github-flow/scripts/persist-conventions.test.mjs +0 -108
- package/skills/cicd/mergify/scripts/audit.test.mjs +0 -201
- package/skills/cicd/mergify/scripts/entrypoints.test.mjs +0 -106
- package/skills/cicd/mergify/scripts/pr-620-mergify-comments.fixture.json +0 -30
- package/skills/cicd/mergify/scripts/stack-push.test.mjs +0 -233
- package/skills/cicd/mergify/scripts/watch-pr-delivery.test.mjs +0 -1826
- package/skills/content/image-gen/scripts/credentials.test.mjs +0 -212
- package/skills/content/image-gen/scripts/options.test.mjs +0 -245
- package/skills/content/xai-search/tests/smoke_test.sh +0 -36
- package/skills/core/polish-cn/scripts/polish-cn.test.mjs +0 -244
- package/skills/core/reg-parser/scripts/reg-parser.test.mjs +0 -165
- package/skills/engineering/better-review/scripts/pr-context.test.mjs +0 -168
- package/skills/engineering/better-review/scripts/rereview-scope.test.mjs +0 -587
- package/skills/engineering/better-review/scripts/scan-diff.test.mjs +0 -414
- package/skills/engineering/better-review/scripts/vendor-sync.test.mjs +0 -96
- package/skills/engineering/contributing/scripts/persist-conventions.test.mjs +0 -118
- package/skills/engineering/e2e-test/scripts/presentation-checks.test.mjs +0 -106
- package/skills/engineering/e2e-test/scripts/presentation-perceivability.test.mjs +0 -117
- package/skills/engineering/e2e-test/scripts/presentation-reachability.test.mjs +0 -69
- package/skills/engineering/e2e-test/scripts/presentation-render-health.test.mjs +0 -98
- package/skills/engineering/e2e-test/scripts/presentation-sweep.test.mjs +0 -71
- package/skills/engineering/e2e-test/scripts/presentation-temporal.test.mjs +0 -59
- package/skills/engineering/e2e-test/scripts/project-route-manifest.test.mjs +0 -76
- package/skills/engineering/engineering-runtime/engineering-runtime.test.mjs +0 -68
- package/skills/engineering/engineering-runtime/scripts/invocation-policy.test.mjs +0 -95
- package/skills/engineering/engineering-runtime/scripts/main-module.test.mjs +0 -288
- package/skills/engineering/engineering-runtime/scripts/required-check-plan.test.mjs +0 -96
- package/skills/engineering/ensure-coverage/scripts/adapters/nextjs-inventory.test.mjs +0 -96
- package/skills/engineering/ensure-coverage/scripts/check-quarantine-expiry.test.mjs +0 -47
- package/skills/engineering/ensure-coverage/scripts/ci-audit.test.mjs +0 -86
- package/skills/engineering/ensure-coverage/scripts/coverage-ledger.test.mjs +0 -447
- package/skills/engineering/ensure-coverage/scripts/design-parity.test.mjs +0 -552
- package/skills/engineering/ensure-coverage/scripts/lint-tests.test.mjs +0 -289
- package/skills/engineering/ensure-coverage/scripts/mock-policy-config.test.mjs +0 -119
- package/skills/engineering/golden-path/scripts/golden-path.test.mjs +0 -1457
- package/skills/engineering/harness-runtime/discover-models.test.mjs +0 -363
- package/skills/engineering/harness-runtime/harness-runtime.test.mjs +0 -967
- package/skills/engineering/harness-runtime/model-catalog-seed.test.mjs +0 -829
- package/skills/engineering/harness-runtime/model-catalog.test.mjs +0 -366
- package/skills/engineering/resolve-issues/scripts/cleanup-runs.test.mjs +0 -280
- package/skills/engineering/resolve-issues/scripts/dropbox.test.mjs +0 -346
- package/skills/engineering/resolve-issues/scripts/findings-reuse.test.mjs +0 -88
- package/skills/engineering/resolve-issues/scripts/github-reviews.test.mjs +0 -264
- package/skills/engineering/resolve-issues/scripts/install-hooks.test.mjs +0 -79
- package/skills/engineering/resolve-issues/scripts/issue-tree.test.mjs +0 -107
- package/skills/engineering/resolve-issues/scripts/manual-invocation.test.mjs +0 -14
- package/skills/engineering/resolve-issues/scripts/next-actions-capacity.test.mjs +0 -149
- package/skills/engineering/resolve-issues/scripts/next-actions.test.mjs +0 -915
- package/skills/engineering/resolve-issues/scripts/plan-sync.test.mjs +0 -156
- package/skills/engineering/resolve-issues/scripts/preflight-models.test.mjs +0 -448
- package/skills/engineering/resolve-issues/scripts/ready-check.test.mjs +0 -217
- package/skills/engineering/resolve-issues/scripts/rehydrate.test.mjs +0 -91
- package/skills/engineering/resolve-issues/scripts/review-verdict.test.mjs +0 -1060
- package/skills/engineering/resolve-issues/scripts/size-check.test.mjs +0 -458
- package/skills/engineering/resolve-release/scripts/apply.test.mjs +0 -99
- package/skills/engineering/resolve-release/scripts/dark-flags.test.mjs +0 -100
- package/skills/engineering/resolve-release/scripts/flow.test.mjs +0 -340
- package/skills/engineering/resolve-release/scripts/green-head.test.mjs +0 -101
- package/skills/engineering/resolve-release/scripts/npm-version-absence.test.mjs +0 -426
- package/skills/engineering/resolve-release/scripts/plan-npm.test.mjs +0 -659
- package/skills/engineering/resolve-release/scripts/plan-toml-boundary.test.mjs +0 -317
- package/skills/engineering/resolve-release/scripts/plan-uv.test.mjs +0 -291
- package/skills/engineering/resolve-release/scripts/plan.test.mjs +0 -428
- package/skills/engineering/test-quality/scripts/lint-tests.test.mjs +0 -591
- package/skills/engineering/test-quality/scripts/mock-policy-config.test.mjs +0 -119
- package/skills/engineering/test-quality/scripts/persist-conventions.test.mjs +0 -104
- package/skills/risk-compliance/compliance-audit/scripts/compliance-audit.test.mjs +0 -14
- package/skills/risk-compliance/doc-authenticity/manual-invocation.test.mjs +0 -12
- package/skills/risk-compliance/doc-authenticity/scripts/validate_verdict.test.mjs +0 -212
- package/skills/risk-compliance/tld-detection/scripts/detect_ladders.test.mjs +0 -14
- package/skills/risk-compliance/tld-detection/scripts/detect_streams.test.mjs +0 -14
- package/skills/risk-compliance/tld-detection/tests/test_detect_ladders.py +0 -134
- package/skills/risk-compliance/tld-detection/tests/test_detect_streams.py +0 -520
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
name: reg-parser
|
|
3
3
|
version: 1.1.0
|
|
4
4
|
description: "Parse regulatory/scheme documents into structured outputs: convert a regulation (AML, VARS, PCI-DSS, KYC, GDPR) into an audit-ready compliance checklist, or trace contract clauses to a mandate source. Suggest proactively when a regulation PDF accompanies a contract review or compliance task. NOT general summarization (doc-to-md), or writing the gap analysis or policy from the checklist (write-doc)."
|
|
5
|
-
release-version: 0.
|
|
5
|
+
release-version: 0.44.0
|
|
6
6
|
---
|
|
7
7
|
**Updates:** Once/session run `node <skill-base-dir>/release-check.mjs`.
|
|
8
8
|
# reg-parser
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { spawnSync } from 'node:child_process';
|
|
3
3
|
import { mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
4
4
|
import { homedir } from 'node:os';
|
|
5
|
-
import { dirname, join } from 'node:path';
|
|
5
|
+
import { dirname, join, resolve } from 'node:path';
|
|
6
6
|
import { fileURLToPath } from 'node:url';
|
|
7
7
|
|
|
8
8
|
const DAY_MS = 24 * 60 * 60 * 1000;
|
|
@@ -46,6 +46,8 @@ function writeCache(path, value) {
|
|
|
46
46
|
|
|
47
47
|
function main(now = Date.now()) {
|
|
48
48
|
if (process.env.ONEABOVEIO_NO_UPDATE_CHECK) return;
|
|
49
|
+
const bundle = readJson(join(resolve(here, '../../..'), 'package.json'));
|
|
50
|
+
if (bundle.name === '@1aboveio/skills' && bundle.nativeCodex?.schemaVersion === 1) return;
|
|
49
51
|
const skill = readFileSync(join(here, 'SKILL.md'), 'utf8');
|
|
50
52
|
const name = frontmatterValue(skill, 'name');
|
|
51
53
|
const localVersion = stableVersion(frontmatterValue(skill, 'release-version'));
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: terminology
|
|
3
3
|
description: "Build and keep a project's TERMINOLOGY.md: the preferred term per concept in English, 简体 and 繁體, and the terms to avoid. Use to set it up from the project's documents, when the user settles or corrects a term, or when another writing skill needs the format. NOT for writing documents (write-doc) or the code domain model (domain-modeling)."
|
|
4
|
-
release-version: 0.
|
|
4
|
+
release-version: 0.44.0
|
|
5
5
|
---
|
|
6
6
|
**Updates:** Once/session run `node <skill-base-dir>/release-check.mjs`.
|
|
7
7
|
# Terminology
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { spawnSync } from 'node:child_process';
|
|
3
3
|
import { mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
4
4
|
import { homedir } from 'node:os';
|
|
5
|
-
import { dirname, join } from 'node:path';
|
|
5
|
+
import { dirname, join, resolve } from 'node:path';
|
|
6
6
|
import { fileURLToPath } from 'node:url';
|
|
7
7
|
|
|
8
8
|
const DAY_MS = 24 * 60 * 60 * 1000;
|
|
@@ -46,6 +46,8 @@ function writeCache(path, value) {
|
|
|
46
46
|
|
|
47
47
|
function main(now = Date.now()) {
|
|
48
48
|
if (process.env.ONEABOVEIO_NO_UPDATE_CHECK) return;
|
|
49
|
+
const bundle = readJson(join(resolve(here, '../../..'), 'package.json'));
|
|
50
|
+
if (bundle.name === '@1aboveio/skills' && bundle.nativeCodex?.schemaVersion === 1) return;
|
|
49
51
|
const skill = readFileSync(join(here, 'SKILL.md'), 'utf8');
|
|
50
52
|
const name = frontmatterValue(skill, 'name');
|
|
51
53
|
const localVersion = stableVersion(frontmatterValue(skill, 'release-version'));
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: write-doc
|
|
3
3
|
description: "Write or edit documents and compliance reports in the project's house style: BRD, PRD, gap analysis, technical spec, integration guide, proposal, policy, risk procedure, audit report, external assessment, management report or Visa VARS Review Report; English, Chinese or bilingual. Use automatically whenever asked to draft, write, revise or edit a document, without needing a slash command, including 'write up the findings'. Route explicit requests to remember a writing preference to its persistence owner. Markdown by default; export when requested. NOT for ordinary chat replies (plain-language), learning style from samples or preference-only saves (distill-writing), performing an audit (compliance-audit), or WeChat articles (wechat-article-writer)."
|
|
4
|
-
release-version: 0.
|
|
4
|
+
release-version: 0.44.0
|
|
5
5
|
---
|
|
6
6
|
**Updates:** Once/session run `node <skill-base-dir>/release-check.mjs`.
|
|
7
7
|
# Write a document
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { spawnSync } from 'node:child_process';
|
|
3
3
|
import { mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
4
4
|
import { homedir } from 'node:os';
|
|
5
|
-
import { dirname, join } from 'node:path';
|
|
5
|
+
import { dirname, join, resolve } from 'node:path';
|
|
6
6
|
import { fileURLToPath } from 'node:url';
|
|
7
7
|
|
|
8
8
|
const DAY_MS = 24 * 60 * 60 * 1000;
|
|
@@ -46,6 +46,8 @@ function writeCache(path, value) {
|
|
|
46
46
|
|
|
47
47
|
function main(now = Date.now()) {
|
|
48
48
|
if (process.env.ONEABOVEIO_NO_UPDATE_CHECK) return;
|
|
49
|
+
const bundle = readJson(join(resolve(here, '../../..'), 'package.json'));
|
|
50
|
+
if (bundle.name === '@1aboveio/skills' && bundle.nativeCodex?.schemaVersion === 1) return;
|
|
49
51
|
const skill = readFileSync(join(here, 'SKILL.md'), 'utf8');
|
|
50
52
|
const name = frontmatterValue(skill, 'name');
|
|
51
53
|
const localVersion = stableVersion(frontmatterValue(skill, 'release-version'));
|
|
@@ -4,7 +4,7 @@ description: "Slash/explicit-only (/better-review). Single-agent adversarial rev
|
|
|
4
4
|
disable-model-invocation: true
|
|
5
5
|
dependencies:
|
|
6
6
|
- engineering-runtime
|
|
7
|
-
release-version: 0.
|
|
7
|
+
release-version: 0.44.0
|
|
8
8
|
---
|
|
9
9
|
**Updates:** Once/session run `node <skill-base-dir>/release-check.mjs`.
|
|
10
10
|
# Better Review
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { spawnSync } from 'node:child_process';
|
|
3
3
|
import { mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
4
4
|
import { homedir } from 'node:os';
|
|
5
|
-
import { dirname, join } from 'node:path';
|
|
5
|
+
import { dirname, join, resolve } from 'node:path';
|
|
6
6
|
import { fileURLToPath } from 'node:url';
|
|
7
7
|
|
|
8
8
|
const DAY_MS = 24 * 60 * 60 * 1000;
|
|
@@ -46,6 +46,8 @@ function writeCache(path, value) {
|
|
|
46
46
|
|
|
47
47
|
function main(now = Date.now()) {
|
|
48
48
|
if (process.env.ONEABOVEIO_NO_UPDATE_CHECK) return;
|
|
49
|
+
const bundle = readJson(join(resolve(here, '../../..'), 'package.json'));
|
|
50
|
+
if (bundle.name === '@1aboveio/skills' && bundle.nativeCodex?.schemaVersion === 1) return;
|
|
49
51
|
const skill = readFileSync(join(here, 'SKILL.md'), 'utf8');
|
|
50
52
|
const name = frontmatterValue(skill, 'name');
|
|
51
53
|
const localVersion = stableVersion(frontmatterValue(skill, 'release-version'));
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: contributing
|
|
3
3
|
description: "The conventions a repo's CONTRIBUTING.md holds, starting with tracker routing: which tracker an issue belongs in (GitHub for engineering, Linear for product), duplicate search, and linking back to the source requirement. Use before creating any issue, spec, epic, ticket or sub-issue on GitHub or Linear, including inside /to-spec, /to-tickets and /triage, and whenever work that started from a Linear issue turns into engineering work. Also writes the rules as the Issue tracking section of the repo's CONTRIBUTING.md. NOT for delivering a PR (github-flow) or splitting work into slices (to-tickets)."
|
|
4
|
-
release-version: 0.
|
|
4
|
+
release-version: 0.44.0
|
|
5
5
|
---
|
|
6
6
|
**Updates:** Once/session run `node <skill-base-dir>/release-check.mjs`.
|
|
7
7
|
# Contributing
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { spawnSync } from 'node:child_process';
|
|
3
3
|
import { mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
4
4
|
import { homedir } from 'node:os';
|
|
5
|
-
import { dirname, join } from 'node:path';
|
|
5
|
+
import { dirname, join, resolve } from 'node:path';
|
|
6
6
|
import { fileURLToPath } from 'node:url';
|
|
7
7
|
|
|
8
8
|
const DAY_MS = 24 * 60 * 60 * 1000;
|
|
@@ -46,6 +46,8 @@ function writeCache(path, value) {
|
|
|
46
46
|
|
|
47
47
|
function main(now = Date.now()) {
|
|
48
48
|
if (process.env.ONEABOVEIO_NO_UPDATE_CHECK) return;
|
|
49
|
+
const bundle = readJson(join(resolve(here, '../../..'), 'package.json'));
|
|
50
|
+
if (bundle.name === '@1aboveio/skills' && bundle.nativeCodex?.schemaVersion === 1) return;
|
|
49
51
|
const skill = readFileSync(join(here, 'SKILL.md'), 'utf8');
|
|
50
52
|
const name = frontmatterValue(skill, 'name');
|
|
51
53
|
const localVersion = stableVersion(frontmatterValue(skill, 'release-version'));
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: e2e-test
|
|
3
3
|
description: "Playwright end-to-end standard: the 3-tier suite (render-health / functional / journey), generated route manifest, and presentation sweep. Use when browser routes or user flows ship or change, or a Playwright test flakes. NOT for non-browser tests, defining what to test (ensure-coverage), the curated ALIVE/DEAD golden-path gate (golden-path), or CI workflow YAML (github-actions)."
|
|
4
|
-
release-version: 0.
|
|
4
|
+
release-version: 0.44.0
|
|
5
5
|
---
|
|
6
6
|
**Updates:** Once/session run `node <skill-base-dir>/release-check.mjs`.
|
|
7
7
|
# E2E Testing Standard
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { spawnSync } from 'node:child_process';
|
|
3
3
|
import { mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
4
4
|
import { homedir } from 'node:os';
|
|
5
|
-
import { dirname, join } from 'node:path';
|
|
5
|
+
import { dirname, join, resolve } from 'node:path';
|
|
6
6
|
import { fileURLToPath } from 'node:url';
|
|
7
7
|
|
|
8
8
|
const DAY_MS = 24 * 60 * 60 * 1000;
|
|
@@ -46,6 +46,8 @@ function writeCache(path, value) {
|
|
|
46
46
|
|
|
47
47
|
function main(now = Date.now()) {
|
|
48
48
|
if (process.env.ONEABOVEIO_NO_UPDATE_CHECK) return;
|
|
49
|
+
const bundle = readJson(join(resolve(here, '../../..'), 'package.json'));
|
|
50
|
+
if (bundle.name === '@1aboveio/skills' && bundle.nativeCodex?.schemaVersion === 1) return;
|
|
49
51
|
const skill = readFileSync(join(here, 'SKILL.md'), 'utf8');
|
|
50
52
|
const name = frontmatterValue(skill, 'name');
|
|
51
53
|
const localVersion = stableVersion(frontmatterValue(skill, 'release-version'));
|
|
@@ -3,7 +3,7 @@ name: engineering-runtime
|
|
|
3
3
|
description: Internal support package for shared Engineering Workflow executable behavior. Never select or invoke this package as a user capability.
|
|
4
4
|
disable-model-invocation: true
|
|
5
5
|
user-invocable: false
|
|
6
|
-
release-version: 0.
|
|
6
|
+
release-version: 0.44.0
|
|
7
7
|
---
|
|
8
8
|
**Updates:** Once/session run `node <skill-base-dir>/release-check.mjs`.
|
|
9
9
|
# Engineering Runtime
|
|
@@ -369,7 +369,7 @@
|
|
|
369
369
|
"repository": "1aboveio/ai",
|
|
370
370
|
"revision": "main"
|
|
371
371
|
},
|
|
372
|
-
"contentDigest": "
|
|
372
|
+
"contentDigest": "ae8ace5c97889e14e669829d72a92bd90d593ba1099c4bd690c98eca8b9c94e3",
|
|
373
373
|
"digestExcludes": []
|
|
374
374
|
},
|
|
375
375
|
{
|
|
@@ -382,7 +382,7 @@
|
|
|
382
382
|
"repository": "1aboveio/ai",
|
|
383
383
|
"revision": "main"
|
|
384
384
|
},
|
|
385
|
-
"contentDigest": "
|
|
385
|
+
"contentDigest": "ddf8e11e23f667cdc677c9d70edb6ed59da53b5a0b82af29f6be36eda35861c2",
|
|
386
386
|
"digestExcludes": []
|
|
387
387
|
},
|
|
388
388
|
{
|
|
@@ -395,7 +395,7 @@
|
|
|
395
395
|
"repository": "1aboveio/ai",
|
|
396
396
|
"revision": "main"
|
|
397
397
|
},
|
|
398
|
-
"contentDigest": "
|
|
398
|
+
"contentDigest": "0e3c87b01b5c337a7628ae5ba5c78a3b208ab404b8d848e4d8299f221224726d",
|
|
399
399
|
"digestExcludes": []
|
|
400
400
|
},
|
|
401
401
|
{
|
|
@@ -408,7 +408,7 @@
|
|
|
408
408
|
"repository": "1aboveio/ai",
|
|
409
409
|
"revision": "main"
|
|
410
410
|
},
|
|
411
|
-
"contentDigest": "
|
|
411
|
+
"contentDigest": "de98656af030369ea229112e90f441626863dcca5e21f2f358e26041d0624f3e",
|
|
412
412
|
"digestExcludes": []
|
|
413
413
|
},
|
|
414
414
|
{
|
|
@@ -421,7 +421,7 @@
|
|
|
421
421
|
"repository": "1aboveio/ai",
|
|
422
422
|
"revision": "main"
|
|
423
423
|
},
|
|
424
|
-
"contentDigest": "
|
|
424
|
+
"contentDigest": "c4f55e7aed013006d00fde40504db87c32c48ca8b04ef4aeacf9c7fe31995fed",
|
|
425
425
|
"digestExcludes": []
|
|
426
426
|
},
|
|
427
427
|
{
|
|
@@ -434,7 +434,7 @@
|
|
|
434
434
|
"repository": "1aboveio/ai",
|
|
435
435
|
"revision": "main"
|
|
436
436
|
},
|
|
437
|
-
"contentDigest": "
|
|
437
|
+
"contentDigest": "7ec336f6920ec1195fbe08b40234ac72f8213a3b94f575e2c463108b36884a25",
|
|
438
438
|
"digestExcludes": []
|
|
439
439
|
},
|
|
440
440
|
{
|
|
@@ -447,7 +447,7 @@
|
|
|
447
447
|
"repository": "1aboveio/ai",
|
|
448
448
|
"revision": "main"
|
|
449
449
|
},
|
|
450
|
-
"contentDigest": "
|
|
450
|
+
"contentDigest": "845c78252f5308aa71b8eaabc80718c25a772d016d5d74eb888737cd7ffbe664",
|
|
451
451
|
"digestExcludes": []
|
|
452
452
|
},
|
|
453
453
|
{
|
|
@@ -460,7 +460,7 @@
|
|
|
460
460
|
"repository": "1aboveio/ai",
|
|
461
461
|
"revision": "main"
|
|
462
462
|
},
|
|
463
|
-
"contentDigest": "
|
|
463
|
+
"contentDigest": "0c9e35d5014ebd7b4512aeb7705cd39977252ccaa639821fa87f8f463364b613",
|
|
464
464
|
"digestExcludes": []
|
|
465
465
|
},
|
|
466
466
|
{
|
|
@@ -473,7 +473,7 @@
|
|
|
473
473
|
"repository": "1aboveio/ai",
|
|
474
474
|
"revision": "main"
|
|
475
475
|
},
|
|
476
|
-
"contentDigest": "
|
|
476
|
+
"contentDigest": "1c5c3dd92653706d7ca78926f10dbf266e4be4a807e6759ea6e8560b3be72f24",
|
|
477
477
|
"digestExcludes": []
|
|
478
478
|
},
|
|
479
479
|
{
|
|
@@ -486,7 +486,7 @@
|
|
|
486
486
|
"repository": "1aboveio/ai",
|
|
487
487
|
"revision": "main"
|
|
488
488
|
},
|
|
489
|
-
"contentDigest": "
|
|
489
|
+
"contentDigest": "d4f589fdb746755388a47eef8d34670a631584fac2bd32af1550da741434b4d6",
|
|
490
490
|
"digestExcludes": []
|
|
491
491
|
},
|
|
492
492
|
{
|
|
@@ -499,7 +499,7 @@
|
|
|
499
499
|
"repository": "1aboveio/ai",
|
|
500
500
|
"revision": "main"
|
|
501
501
|
},
|
|
502
|
-
"contentDigest": "
|
|
502
|
+
"contentDigest": "d8b6513b1259b3b91f81c4ac9e9ebe66c2c3735534326ee793b99dc305dc3897",
|
|
503
503
|
"digestExcludes": []
|
|
504
504
|
},
|
|
505
505
|
{
|
|
@@ -512,13 +512,13 @@
|
|
|
512
512
|
"repository": "1aboveio/ai",
|
|
513
513
|
"revision": "main"
|
|
514
514
|
},
|
|
515
|
-
"contentDigest": "
|
|
515
|
+
"contentDigest": "bf49dc85c84e81e6561b6682003709bb792f4309a295cddad2c5e97e5e85f5b1",
|
|
516
516
|
"digestExcludes": [
|
|
517
517
|
"coherence/workflow.json"
|
|
518
518
|
]
|
|
519
519
|
}
|
|
520
520
|
],
|
|
521
|
-
"releaseIdentity": "
|
|
521
|
+
"releaseIdentity": "a7f5ec670bb7b0f8dcfb585c5de1d5cfd0bd55799d72e994034674c7c84f5c40",
|
|
522
522
|
"lifecycleAuthority": "native-skills-cli",
|
|
523
523
|
"repairRecipe": {
|
|
524
524
|
"id": "engineering-workflow-dependency-first",
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { spawnSync } from 'node:child_process';
|
|
3
3
|
import { mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
4
4
|
import { homedir } from 'node:os';
|
|
5
|
-
import { dirname, join } from 'node:path';
|
|
5
|
+
import { dirname, join, resolve } from 'node:path';
|
|
6
6
|
import { fileURLToPath } from 'node:url';
|
|
7
7
|
|
|
8
8
|
const DAY_MS = 24 * 60 * 60 * 1000;
|
|
@@ -46,6 +46,8 @@ function writeCache(path, value) {
|
|
|
46
46
|
|
|
47
47
|
function main(now = Date.now()) {
|
|
48
48
|
if (process.env.ONEABOVEIO_NO_UPDATE_CHECK) return;
|
|
49
|
+
const bundle = readJson(join(resolve(here, '../../..'), 'package.json'));
|
|
50
|
+
if (bundle.name === '@1aboveio/skills' && bundle.nativeCodex?.schemaVersion === 1) return;
|
|
49
51
|
const skill = readFileSync(join(here, 'SKILL.md'), 'utf8');
|
|
50
52
|
const name = frontmatterValue(skill, 'name');
|
|
51
53
|
const localVersion = stableVersion(frontmatterValue(skill, 'release-version'));
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
import { existsSync, lstatSync, readFileSync, realpathSync } from 'node:fs';
|
|
3
|
+
import { isAbsolute, join, relative, resolve } from 'node:path';
|
|
4
|
+
import { isDeepStrictEqual } from 'node:util';
|
|
5
|
+
import { contentDigest, contentFiles, firstPartySource } from './workflow-coherence.mjs';
|
|
6
|
+
import { reviewedSourceInjections } from './invocation-policy.mjs';
|
|
7
|
+
import { isMainModule } from './main-module.mjs';
|
|
8
|
+
|
|
9
|
+
export const NATIVE_METADATA_PATH = '.codex-plugin/resources.json';
|
|
10
|
+
export const NATIVE_PLUGIN_NAME = '1aboveio-skills';
|
|
11
|
+
const SHA256 = /^[a-f0-9]{64}$/;
|
|
12
|
+
const NAME = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
13
|
+
export const sha256 = (bytes) => createHash('sha256').update(bytes).digest('hex');
|
|
14
|
+
|
|
15
|
+
function freeze(value) {
|
|
16
|
+
if (value && typeof value === 'object') {
|
|
17
|
+
for (const child of Object.values(value)) freeze(child);
|
|
18
|
+
Object.freeze(value);
|
|
19
|
+
}
|
|
20
|
+
return value;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function containedPath(root, path) {
|
|
24
|
+
if (!isAbsolute(root) || typeof path !== 'string' || !path || isAbsolute(path)
|
|
25
|
+
|| path.includes('\\') || path.split('/').some((part) => !part || part === '.' || part === '..')) {
|
|
26
|
+
throw new Error('Invalid installation root or relative resource path');
|
|
27
|
+
}
|
|
28
|
+
const target = resolve(root, path);
|
|
29
|
+
if (relative(root, target).startsWith('..')) throw new Error('Resource escapes selected installation');
|
|
30
|
+
// Reject links at every component, including the root. No cache or shared-store fallback.
|
|
31
|
+
if (realpathSync(root) !== root) throw new Error('Selected installation root changed or is ambiguous');
|
|
32
|
+
let current = root;
|
|
33
|
+
for (const part of path.split('/')) {
|
|
34
|
+
current = join(current, part);
|
|
35
|
+
if (lstatSync(current).isSymbolicLink()) throw new Error(`Resource symlink is not supported: ${path}`);
|
|
36
|
+
}
|
|
37
|
+
return target;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export function metadataIdentity(metadata) {
|
|
41
|
+
const { releaseIdentity, ...body } = metadata;
|
|
42
|
+
return sha256(JSON.stringify(body));
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export function validateResourceMetadata(metadata) {
|
|
46
|
+
if (metadata?.schemaVersion !== 1 || metadata.pluginName !== NATIVE_PLUGIN_NAME
|
|
47
|
+
|| metadata.packageName !== '@1aboveio/skills' || !SHA256.test(metadata.releaseIdentity ?? '')
|
|
48
|
+
|| metadataIdentity(metadata) !== metadata.releaseIdentity || !Array.isArray(metadata.members)
|
|
49
|
+
|| metadata.members.length === 0) throw new Error('Invalid native resource metadata identity');
|
|
50
|
+
const names = new Set();
|
|
51
|
+
const paths = new Set();
|
|
52
|
+
for (const member of metadata.members) {
|
|
53
|
+
if (!NAME.test(member.canonicalName ?? '') || names.has(member.canonicalName)
|
|
54
|
+
|| !SHA256.test(member.contentDigest ?? '') || !member.expectedSource
|
|
55
|
+
|| !Array.isArray(member.digestExcludes) || !member.resourceDigests
|
|
56
|
+
|| (firstPartySource(member.expectedSource) && !SHA256.test(member.resourceDigests['SKILL.md'] ?? ''))) throw new Error('Invalid or duplicate resource member');
|
|
57
|
+
names.add(member.canonicalName);
|
|
58
|
+
const source = member.expectedSource;
|
|
59
|
+
if (firstPartySource(source)) {
|
|
60
|
+
if (source.id !== 'first-party' || source.repository !== '1aboveio/ai' || source.revision !== 'main'
|
|
61
|
+
|| !NAME.test(member.packageId ?? '') || member.bundlePath !== `skills/${member.packageId}/${member.canonicalName}`
|
|
62
|
+
|| paths.has(member.bundlePath)) throw new Error('Invalid first-party resource ownership');
|
|
63
|
+
paths.add(member.bundlePath);
|
|
64
|
+
} else if (source.type !== 'external' || !SHA256.test(member.contentDigest)
|
|
65
|
+
|| !/^[a-f0-9]{40}$/.test(source.revision ?? '') || !source.repository) {
|
|
66
|
+
throw new Error('Invalid pinned external identity');
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return metadata;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function readPinnedMetadata(root, path, digest, identity) {
|
|
73
|
+
const bytes = readFileSync(containedPath(root, path));
|
|
74
|
+
if (sha256(bytes) !== digest) throw new Error('Resource metadata digest mismatch');
|
|
75
|
+
const metadata = validateResourceMetadata(JSON.parse(bytes));
|
|
76
|
+
if (metadata.releaseIdentity !== identity) throw new Error('Selected release identity mismatch');
|
|
77
|
+
return metadata;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Callers obtain these pins from a verified artifact or trusted generation, not the mutable
|
|
81
|
+
// package group index. The JSON descriptor is safe to persist in a run and pass to workers.
|
|
82
|
+
export function selectInstallation({ layout, root, metadataPath, metadataDigest, releaseIdentity, externalRoots = {} }) {
|
|
83
|
+
if (!['source', 'installed', 'bundle'].includes(layout) || typeof root !== 'string' || !isAbsolute(root)
|
|
84
|
+
|| !SHA256.test(metadataDigest ?? '') || !SHA256.test(releaseIdentity ?? '')) {
|
|
85
|
+
throw new Error('Select one absolute installation root and expected metadata/release identities');
|
|
86
|
+
}
|
|
87
|
+
const canonicalRoot = realpathSync(root);
|
|
88
|
+
if (canonicalRoot !== root) throw new Error('Selected installation root changed or is ambiguous');
|
|
89
|
+
const path = metadataPath ?? (layout === 'bundle' ? NATIVE_METADATA_PATH : null);
|
|
90
|
+
const metadata = readPinnedMetadata(canonicalRoot, path, metadataDigest, releaseIdentity);
|
|
91
|
+
const roots = {};
|
|
92
|
+
for (const [name, mapping] of Object.entries(externalRoots)) {
|
|
93
|
+
const member = metadata.members.find((candidate) => candidate.canonicalName === name);
|
|
94
|
+
if (!member || firstPartySource(member.expectedSource) || !isAbsolute(mapping?.root ?? '')
|
|
95
|
+
|| !isDeepStrictEqual(mapping.expectedSource, member.expectedSource)) {
|
|
96
|
+
throw new Error(`Unknown or unpinned external root: ${name}`);
|
|
97
|
+
}
|
|
98
|
+
const externalRoot = realpathSync(mapping.root);
|
|
99
|
+
if (externalRoot !== mapping.root || externalRoot === canonicalRoot
|
|
100
|
+
|| Object.values(roots).some((entry) => entry.root === externalRoot)) {
|
|
101
|
+
throw new Error(`Ambiguous external root: ${name}`);
|
|
102
|
+
}
|
|
103
|
+
roots[name] = { root: externalRoot, expectedSource: structuredClone(mapping.expectedSource) };
|
|
104
|
+
}
|
|
105
|
+
return freeze({ layout, root: canonicalRoot, metadataPath: path, metadataDigest, releaseIdentity, externalRoots: roots });
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export function installationMetadata(installation) {
|
|
109
|
+
const selected = selectInstallation(installation);
|
|
110
|
+
return freeze(readPinnedMetadata(selected.root, selected.metadataPath, selected.metadataDigest, selected.releaseIdentity));
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export function memberPath(installation, member) {
|
|
114
|
+
if (!firstPartySource(member.expectedSource)) {
|
|
115
|
+
const mapping = installation.externalRoots?.[member.canonicalName];
|
|
116
|
+
if (!mapping || !isDeepStrictEqual(mapping.expectedSource, member.expectedSource)) {
|
|
117
|
+
throw new Error(`Missing pinned external dependency: ${member.canonicalName}`);
|
|
118
|
+
}
|
|
119
|
+
// The explicit external root is the member itself, not a directory to search.
|
|
120
|
+
containedPath(mapping.root, 'SKILL.md');
|
|
121
|
+
return mapping.root;
|
|
122
|
+
}
|
|
123
|
+
return containedPath(installation.root, installation.layout === 'bundle' ? member.bundlePath
|
|
124
|
+
: installation.layout === 'installed' ? member.canonicalName : member.sourcePath);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
export function resolveResource(installation, canonicalName, resource = 'SKILL.md', { hostIdentity = null } = {}) {
|
|
128
|
+
const selected = selectInstallation(installation);
|
|
129
|
+
const metadata = installationMetadata(selected);
|
|
130
|
+
const member = metadata.members.find((candidate) => candidate.canonicalName === canonicalName);
|
|
131
|
+
if (!member) throw new Error(`Unknown canonical skill: ${canonicalName}`);
|
|
132
|
+
if (firstPartySource(member.expectedSource) && !Object.hasOwn(member.resourceDigests, resource)) {
|
|
133
|
+
throw new Error(`Unknown resource: ${canonicalName}/${resource}`);
|
|
134
|
+
}
|
|
135
|
+
const directory = memberPath(selected, member);
|
|
136
|
+
let injected = [];
|
|
137
|
+
if (!firstPartySource(member.expectedSource) && member.invocationPolicy) {
|
|
138
|
+
try { injected = reviewedSourceInjections(directory, member.invocationPolicy); } catch { /* Raw upstream is also allowed. */ }
|
|
139
|
+
}
|
|
140
|
+
const digestOptions = { exclude: member.digestExcludes, published: firstPartySource(member.expectedSource), injected };
|
|
141
|
+
const actual = contentDigest(directory, digestOptions);
|
|
142
|
+
if (actual !== member.contentDigest) throw new Error(`Modified skill resources: ${canonicalName}`);
|
|
143
|
+
const pinned = Object.hasOwn(member.resourceDigests, resource);
|
|
144
|
+
if (!pinned && !contentFiles(directory, digestOptions).some((file) => file.relativePath === resource)) {
|
|
145
|
+
throw new Error(`Unverified resource: ${canonicalName}/${resource}`);
|
|
146
|
+
}
|
|
147
|
+
const path = containedPath(directory, resource);
|
|
148
|
+
const actualResourceDigest = sha256(readFileSync(path));
|
|
149
|
+
if (pinned && actualResourceDigest !== member.resourceDigests[resource]) {
|
|
150
|
+
throw new Error(`Modified resource: ${canonicalName}/${resource}`);
|
|
151
|
+
}
|
|
152
|
+
return freeze({ canonicalName, hostIdentity, path, directory, expectedSource: structuredClone(member.expectedSource),
|
|
153
|
+
contentDigest: actual, resourceDigest: actualResourceDigest, releaseIdentity: selected.releaseIdentity, installation: selected });
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
export function workerResources(installation, requests) {
|
|
157
|
+
if (!Array.isArray(requests) || requests.length === 0) throw new Error('Worker resources must be explicit');
|
|
158
|
+
return freeze(requests.map(({ canonicalName, resource, hostIdentity }) =>
|
|
159
|
+
resolveResource(installation, canonicalName, resource, { hostIdentity })));
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
export function diagnoseOverlap(installation, sharedRoot) {
|
|
163
|
+
if (!isAbsolute(sharedRoot ?? '')) throw new Error('Overlap diagnosis needs an explicit shared root');
|
|
164
|
+
return installationMetadata(installation).members.filter((member) => firstPartySource(member.expectedSource)
|
|
165
|
+
&& existsSync(join(sharedRoot, member.canonicalName, 'SKILL.md')))
|
|
166
|
+
.map((member) => ({ canonicalName: member.canonicalName, selected: memberPath(installation, member),
|
|
167
|
+
shared: join(sharedRoot, member.canonicalName), requiresExplicitSelection: true }));
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// Identify only the fixed bundle ancestor of a known executing skill. Never scan caches.
|
|
171
|
+
export function executingBundleRoot(skillDirectory) {
|
|
172
|
+
const root = resolve(skillDirectory, '../../..');
|
|
173
|
+
try {
|
|
174
|
+
const pkg = JSON.parse(readFileSync(join(root, 'package.json'), 'utf8'));
|
|
175
|
+
if (pkg.name === '@1aboveio/skills' && existsSync(join(root, NATIVE_METADATA_PATH))
|
|
176
|
+
&& relative(root, skillDirectory).startsWith('skills/')) return root;
|
|
177
|
+
} catch { /* Source and flat installations have no bundle marker. */ }
|
|
178
|
+
return null;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
if (isMainModule(import.meta.url)) {
|
|
182
|
+
try {
|
|
183
|
+
const [command, descriptor, name, resource] = process.argv.slice(2);
|
|
184
|
+
const selected = JSON.parse(readFileSync(descriptor, 'utf8'));
|
|
185
|
+
const result = command === 'select' ? selectInstallation(selected)
|
|
186
|
+
: command === 'resolve' ? resolveResource(selected, name, resource)
|
|
187
|
+
: command === 'overlap' ? diagnoseOverlap(selected, name) : null;
|
|
188
|
+
if (!result) throw new Error('Usage: installation-resolver.mjs <select|resolve|overlap> <descriptor.json> [canonical-name|shared-root] [resource]');
|
|
189
|
+
process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
|
|
190
|
+
} catch (error) { process.stderr.write(`${error.message}\n`); process.exitCode = 1; }
|
|
191
|
+
}
|
|
@@ -3,6 +3,7 @@ import { existsSync, readdirSync, readFileSync } from 'node:fs';
|
|
|
3
3
|
import { isAbsolute, join, normalize, relative } from 'node:path';
|
|
4
4
|
import { isDeepStrictEqual } from 'node:util';
|
|
5
5
|
|
|
6
|
+
import { containedPath, resolveResource, selectInstallation } from './installation-resolver.mjs';
|
|
6
7
|
import { reviewedSourceInjections } from './invocation-policy.mjs';
|
|
7
8
|
import { isMainModule } from './main-module.mjs';
|
|
8
9
|
import {
|
|
@@ -190,6 +191,7 @@ function collectFiles(baseDir, currentDir, excludedPaths, files, published) {
|
|
|
190
191
|
}
|
|
191
192
|
|
|
192
193
|
/**
|
|
194
|
+
* List the exact digest-covered files, including reviewed replacements for invocation overlays.
|
|
193
195
|
* @param {object} [options]
|
|
194
196
|
* @param {string[]} [options.exclude] member-relative paths to omit
|
|
195
197
|
* @param {object[]} [options.injected] generated content to digest instead of reading from disk
|
|
@@ -198,13 +200,17 @@ function collectFiles(baseDir, currentDir, excludedPaths, files, published) {
|
|
|
198
200
|
* published release; left off for external members, whose authority is the reviewed upstream tree
|
|
199
201
|
* byte for byte. See {@link publishedContentExcluded}.
|
|
200
202
|
*/
|
|
201
|
-
export function
|
|
203
|
+
export function contentFiles(directory, { exclude = [], injected = [], published = false } = {}) {
|
|
202
204
|
const files = [];
|
|
203
205
|
const excluded = new Set(exclude);
|
|
204
206
|
for (const file of injected) excluded.add(file.relativePath);
|
|
205
207
|
collectFiles(directory, directory, excluded, files, published);
|
|
206
208
|
for (const file of injected) files.push({ relativePath: file.relativePath, contents: file.contents });
|
|
207
|
-
files.sort((left, right) => left.relativePath.localeCompare(right.relativePath));
|
|
209
|
+
return files.sort((left, right) => left.relativePath.localeCompare(right.relativePath));
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
export function contentDigest(directory, options = {}) {
|
|
213
|
+
const files = contentFiles(directory, options);
|
|
208
214
|
const hash = createHash('sha256');
|
|
209
215
|
for (const file of files) {
|
|
210
216
|
hash.update(file.relativePath);
|
|
@@ -354,9 +360,10 @@ function validateManifest(manifest) {
|
|
|
354
360
|
}
|
|
355
361
|
|
|
356
362
|
function memberDirectory(member, options) {
|
|
357
|
-
if (options.
|
|
363
|
+
if (options.installation) return resolveResource(options.installation, member.installName).directory;
|
|
364
|
+
if (options.layout === 'installed') return containedPath(options.skillsRoot, member.installName);
|
|
358
365
|
const sourceRoot = options.sourceRoots?.[member.expectedSource.id];
|
|
359
|
-
return sourceRoot ?
|
|
366
|
+
return sourceRoot ? containedPath(sourceRoot, member.sourcePath) : null;
|
|
360
367
|
}
|
|
361
368
|
|
|
362
369
|
function missingManifestResult(layout, code, detail, invokedSkills) {
|
|
@@ -380,11 +387,32 @@ function missingManifestResult(layout, code, detail, invokedSkills) {
|
|
|
380
387
|
}
|
|
381
388
|
|
|
382
389
|
export function verifyWorkflowCoherence(options = {}) {
|
|
390
|
+
let result;
|
|
391
|
+
try {
|
|
392
|
+
const installation = options.installation ? selectInstallation(options.installation) : null;
|
|
393
|
+
result = verifySelectedWorkflow({ ...options, ...(installation ? { installation, layout: installation.layout } : {}) });
|
|
394
|
+
} catch (error) {
|
|
395
|
+
result = missingManifestResult(options.installation?.layout ?? options.layout ?? 'installed',
|
|
396
|
+
'installation-invalid', error.message, options.invokedSkills);
|
|
397
|
+
}
|
|
398
|
+
if (options.installation?.layout === 'bundle') {
|
|
399
|
+
result.repairRecipe = null;
|
|
400
|
+
for (const entry of result.findings) entry.repairRecipe = null;
|
|
401
|
+
}
|
|
402
|
+
return result;
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
function verifySelectedWorkflow(options = {}) {
|
|
383
406
|
const layout = options.layout ?? 'installed';
|
|
384
|
-
if (!['installed', 'source'].includes(layout)) {
|
|
407
|
+
if (!['installed', 'source', 'bundle'].includes(layout) || layout === 'bundle' && !options.installation) {
|
|
385
408
|
return missingManifestResult(layout, 'layout-invalid', 'The requested installation layout is unsupported.', options.invokedSkills);
|
|
386
409
|
}
|
|
387
|
-
const
|
|
410
|
+
const selectedManifest = options.installation
|
|
411
|
+
? resolveResource(options.installation, 'engineering-runtime', 'coherence/workflow.json').path : null;
|
|
412
|
+
if (selectedManifest && options.manifestPath && options.manifestPath !== selectedManifest) {
|
|
413
|
+
throw new Error('A selected installation cannot use another coherence manifest');
|
|
414
|
+
}
|
|
415
|
+
const manifestPath = selectedManifest ?? options.manifestPath ?? (layout === 'installed'
|
|
388
416
|
? join(options.skillsRoot ?? '', 'engineering-runtime', 'coherence', 'workflow.json')
|
|
389
417
|
: join(options.sourceRoots?.['first-party'] ?? '', WORKFLOW_COHERENCE_PATH));
|
|
390
418
|
if (!manifestPath || !existsSync(manifestPath)) {
|
|
@@ -451,7 +479,14 @@ export function verifyWorkflowCoherence(options = {}) {
|
|
|
451
479
|
|
|
452
480
|
const selectedMembers = manifest.members.filter((member) => selectedNames.has(member.installName));
|
|
453
481
|
for (const member of selectedMembers) {
|
|
454
|
-
|
|
482
|
+
let directory;
|
|
483
|
+
try { directory = memberDirectory(member, { ...options, layout }); } catch (error) {
|
|
484
|
+
if (error.code !== 'ENOENT') {
|
|
485
|
+
findings.push(finding({ state: 'missing', code: 'member-resolution-invalid', member: member.installName,
|
|
486
|
+
ownership: member.ownership, expectedSource: member.expectedSource, manifest, detail: error.message }));
|
|
487
|
+
continue;
|
|
488
|
+
}
|
|
489
|
+
}
|
|
455
490
|
if (!directory || !existsSync(directory)) {
|
|
456
491
|
findings.push(finding({
|
|
457
492
|
state: 'missing',
|
|
@@ -475,7 +510,7 @@ export function verifyWorkflowCoherence(options = {}) {
|
|
|
475
510
|
// proved `expectedSource` deep-equal to the trusted policy above (`member-source-identity-
|
|
476
511
|
// invalid` returns before this loop), so the derivation reads trusted data, not manifest claims.
|
|
477
512
|
let policyInjections = [];
|
|
478
|
-
if (layout
|
|
513
|
+
if (layout !== 'source' && member.invocationPolicy) {
|
|
479
514
|
try {
|
|
480
515
|
policyInjections = reviewedSourceInjections(directory, member.invocationPolicy);
|
|
481
516
|
} catch {
|
|
@@ -520,7 +555,8 @@ export function verifyWorkflowCoherence(options = {}) {
|
|
|
520
555
|
const memberByName = new Map(manifest.members.map((member) => [member.installName, member]));
|
|
521
556
|
for (const identity of selectedGenerated.values()) {
|
|
522
557
|
const member = memberByName.get(identity.member);
|
|
523
|
-
|
|
558
|
+
let directory = null;
|
|
559
|
+
try { directory = member ? memberDirectory(member, { ...options, layout }) : null; } catch { /* Report missing identity below. */ }
|
|
524
560
|
const generatedPath = directory ? join(directory, identity.path) : null;
|
|
525
561
|
let actualDigest = null;
|
|
526
562
|
if (generatedPath && existsSync(generatedPath)) {
|
|
@@ -555,7 +591,8 @@ export function verifyWorkflowCoherence(options = {}) {
|
|
|
555
591
|
export function runWorkflowCoherenceCli(args) {
|
|
556
592
|
if (args[0] !== 'verify') {
|
|
557
593
|
process.stderr.write(
|
|
558
|
-
'Usage: workflow-coherence.mjs verify --
|
|
594
|
+
'Usage: workflow-coherence.mjs verify --installation <descriptor.json> [--invoked-skill <canonical-name>]...\n'
|
|
595
|
+
+ ' or: workflow-coherence.mjs verify --layout installed --skills-root <path> [--manifest <path>] [--invoked-skill <name>]...\n'
|
|
559
596
|
+ ' or: workflow-coherence.mjs verify --layout source --source-root <id=path>... [--manifest <path>] [--invoked-skill <name>]...\n',
|
|
560
597
|
);
|
|
561
598
|
return 2;
|
|
@@ -570,6 +607,10 @@ export function runWorkflowCoherenceCli(args) {
|
|
|
570
607
|
const key = argument === '--layout' ? 'layout' : argument === '--skills-root' ? 'skillsRoot' : 'manifestPath';
|
|
571
608
|
options[key] = value;
|
|
572
609
|
index += 1;
|
|
610
|
+
} else if (argument === '--installation') {
|
|
611
|
+
if (!value) return 2;
|
|
612
|
+
try { options.installation = JSON.parse(readFileSync(value, 'utf8')); } catch { return 2; }
|
|
613
|
+
index += 1;
|
|
573
614
|
} else if (argument === '--source-root') {
|
|
574
615
|
const separator = value?.indexOf('=') ?? -1;
|
|
575
616
|
if (separator < 1 || separator === value.length - 1) return 2;
|