@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.
Files changed (224) hide show
  1. package/.codex-plugin/plugin.json +13 -0
  2. package/.codex-plugin/resources.json +1827 -0
  3. package/README.md +22 -0
  4. package/package.json +9 -2
  5. package/skills/app-dev/airflow/SKILL.md +1 -1
  6. package/skills/app-dev/airflow/release-check.mjs +3 -1
  7. package/skills/app-dev/android-foundation/SKILL.md +92 -34
  8. package/skills/app-dev/android-foundation/assets/android-ci-job.yml +13 -7
  9. package/skills/app-dev/android-foundation/references/ci.md +23 -13
  10. package/skills/app-dev/android-foundation/references/delivery-focus.md +29 -0
  11. package/skills/app-dev/android-foundation/references/diagnosis.md +136 -0
  12. package/skills/app-dev/android-foundation/references/gotchas.md +20 -11
  13. package/skills/app-dev/android-foundation/references/setup.md +15 -6
  14. package/skills/app-dev/android-foundation/release-check.mjs +3 -1
  15. package/skills/app-dev/android-foundation/scripts/device-run.sh +148 -42
  16. package/skills/app-dev/app-debug/SKILL.md +1 -1
  17. package/skills/app-dev/app-debug/release-check.mjs +3 -1
  18. package/skills/app-dev/better-auth/SKILL.md +1 -1
  19. package/skills/app-dev/better-auth/release-check.mjs +3 -1
  20. package/skills/app-dev/data-catalog/SKILL.md +1 -1
  21. package/skills/app-dev/data-catalog/release-check.mjs +3 -1
  22. package/skills/app-dev/data-quality/SKILL.md +1 -1
  23. package/skills/app-dev/data-quality/release-check.mjs +3 -1
  24. package/skills/app-dev/ios-foundation/SKILL.md +1 -1
  25. package/skills/app-dev/ios-foundation/release-check.mjs +3 -1
  26. package/skills/app-dev/monorepo/SKILL.md +1 -1
  27. package/skills/app-dev/monorepo/release-check.mjs +3 -1
  28. package/skills/app-dev/nextjs-fullstack/SKILL.md +1 -1
  29. package/skills/app-dev/nextjs-fullstack/release-check.mjs +3 -1
  30. package/skills/app-dev/prisma-setup/SKILL.md +1 -1
  31. package/skills/app-dev/prisma-setup/release-check.mjs +3 -1
  32. package/skills/app-dev/pyspark/SKILL.md +1 -1
  33. package/skills/app-dev/pyspark/release-check.mjs +3 -1
  34. package/skills/app-dev/python-backend/SKILL.md +1 -1
  35. package/skills/app-dev/python-backend/release-check.mjs +3 -1
  36. package/skills/app-dev/shadcn/SKILL.md +1 -1
  37. package/skills/app-dev/shadcn/release-check.mjs +3 -1
  38. package/skills/app-dev/zod-v4/SKILL.md +1 -1
  39. package/skills/app-dev/zod-v4/release-check.mjs +3 -1
  40. package/skills/cicd/cloud-build/SKILL.md +1 -1
  41. package/skills/cicd/cloud-build/release-check.mjs +3 -1
  42. package/skills/cicd/cloud-debug/SKILL.md +1 -1
  43. package/skills/cicd/cloud-debug/release-check.mjs +3 -1
  44. package/skills/cicd/cloud-deploy/SKILL.md +1 -1
  45. package/skills/cicd/cloud-deploy/release-check.mjs +3 -1
  46. package/skills/cicd/docker/SKILL.md +1 -1
  47. package/skills/cicd/docker/release-check.mjs +3 -1
  48. package/skills/cicd/github-actions/SKILL.md +1 -1
  49. package/skills/cicd/github-actions/release-check.mjs +3 -1
  50. package/skills/cicd/github-flow/SKILL.md +1 -1
  51. package/skills/cicd/github-flow/release-check.mjs +3 -1
  52. package/skills/cicd/google-cloud/SKILL.md +1 -1
  53. package/skills/cicd/google-cloud/release-check.mjs +3 -1
  54. package/skills/cicd/mergify/SKILL.md +1 -1
  55. package/skills/cicd/mergify/release-check.mjs +3 -1
  56. package/skills/cicd/podman/SKILL.md +1 -1
  57. package/skills/cicd/podman/release-check.mjs +3 -1
  58. package/skills/content/article-review/SKILL.md +1 -1
  59. package/skills/content/article-review/release-check.mjs +3 -1
  60. package/skills/content/article-to-image/SKILL.md +1 -1
  61. package/skills/content/article-to-image/release-check.mjs +3 -1
  62. package/skills/content/flowchart-svg/SKILL.md +1 -1
  63. package/skills/content/flowchart-svg/release-check.mjs +3 -1
  64. package/skills/content/image-gen/SKILL.md +1 -1
  65. package/skills/content/image-gen/release-check.mjs +3 -1
  66. package/skills/content/mermaid/SKILL.md +1 -1
  67. package/skills/content/mermaid/release-check.mjs +3 -1
  68. package/skills/content/wechat-article-writer/SKILL.md +1 -1
  69. package/skills/content/wechat-article-writer/release-check.mjs +3 -1
  70. package/skills/content/wechat-publisher/SKILL.md +1 -1
  71. package/skills/content/wechat-publisher/release-check.mjs +3 -1
  72. package/skills/content/wechat-search/SKILL.md +1 -1
  73. package/skills/content/wechat-search/release-check.mjs +3 -1
  74. package/skills/content/xai-search/SKILL.md +88 -13
  75. package/skills/content/xai-search/release-check.mjs +3 -1
  76. package/skills/content/xai-search/scripts/xai_search.sh +125 -149
  77. package/skills/core/distill-writing/SKILL.md +1 -1
  78. package/skills/core/distill-writing/release-check.mjs +3 -1
  79. package/skills/core/doc-to-md/SKILL.md +1 -1
  80. package/skills/core/doc-to-md/release-check.mjs +3 -1
  81. package/skills/core/editorial-review/SKILL.md +1 -1
  82. package/skills/core/editorial-review/release-check.mjs +3 -1
  83. package/skills/core/house-style/SKILL.md +1 -1
  84. package/skills/core/house-style/release-check.mjs +3 -1
  85. package/skills/core/plain-language/SKILL.md +1 -1
  86. package/skills/core/plain-language/release-check.mjs +3 -1
  87. package/skills/core/polish-cn/SKILL.md +1 -1
  88. package/skills/core/polish-cn/release-check.mjs +3 -1
  89. package/skills/core/reg-parser/SKILL.md +1 -1
  90. package/skills/core/reg-parser/release-check.mjs +3 -1
  91. package/skills/core/terminology/SKILL.md +1 -1
  92. package/skills/core/terminology/release-check.mjs +3 -1
  93. package/skills/core/write-doc/SKILL.md +1 -1
  94. package/skills/core/write-doc/release-check.mjs +3 -1
  95. package/skills/engineering/better-review/SKILL.md +1 -1
  96. package/skills/engineering/better-review/release-check.mjs +3 -1
  97. package/skills/engineering/contributing/SKILL.md +1 -1
  98. package/skills/engineering/contributing/release-check.mjs +3 -1
  99. package/skills/engineering/e2e-test/SKILL.md +1 -1
  100. package/skills/engineering/e2e-test/release-check.mjs +3 -1
  101. package/skills/engineering/engineering-runtime/SKILL.md +1 -1
  102. package/skills/engineering/engineering-runtime/coherence/workflow.json +13 -13
  103. package/skills/engineering/engineering-runtime/release-check.mjs +3 -1
  104. package/skills/engineering/engineering-runtime/scripts/installation-resolver.mjs +191 -0
  105. package/skills/engineering/engineering-runtime/scripts/workflow-coherence.mjs +51 -10
  106. package/skills/engineering/ensure-coverage/SKILL.md +1 -1
  107. package/skills/engineering/ensure-coverage/release-check.mjs +3 -1
  108. package/skills/engineering/golden-path/SKILL.md +1 -1
  109. package/skills/engineering/golden-path/release-check.mjs +3 -1
  110. package/skills/engineering/harness-runtime/SKILL.md +1 -1
  111. package/skills/engineering/harness-runtime/release-check.mjs +3 -1
  112. package/skills/engineering/resolve-issues/SKILL.md +11 -20
  113. package/skills/engineering/resolve-issues/references/delivery-progress.md +63 -0
  114. package/skills/engineering/resolve-issues/references/expire.md +24 -11
  115. package/skills/engineering/resolve-issues/references/implementation.md +9 -1
  116. package/skills/engineering/resolve-issues/references/preflight.md +7 -0
  117. package/skills/engineering/resolve-issues/references/shared-modules.md +27 -0
  118. package/skills/engineering/resolve-issues/references/task-plan.md +12 -5
  119. package/skills/engineering/resolve-issues/release-check.mjs +3 -1
  120. package/skills/engineering/resolve-issues/scripts/active-installation.mjs +32 -0
  121. package/skills/engineering/resolve-issues/scripts/install-hooks.mjs +3 -0
  122. package/skills/engineering/resolve-issues/scripts/rehydrate.mjs +17 -1
  123. package/skills/engineering/resolve-release/SKILL.md +1 -1
  124. package/skills/engineering/resolve-release/release-check.mjs +3 -1
  125. package/skills/engineering/rush-issues/SKILL.md +5 -2
  126. package/skills/engineering/rush-issues/release-check.mjs +3 -1
  127. package/skills/engineering/rush-release/SKILL.md +1 -1
  128. package/skills/engineering/rush-release/release-check.mjs +3 -1
  129. package/skills/engineering/test-quality/SKILL.md +1 -1
  130. package/skills/engineering/test-quality/release-check.mjs +3 -1
  131. package/skills/risk-compliance/compliance-audit/SKILL.md +1 -1
  132. package/skills/risk-compliance/compliance-audit/release-check.mjs +3 -1
  133. package/skills/risk-compliance/contract-compare/SKILL.md +1 -1
  134. package/skills/risk-compliance/contract-compare/release-check.mjs +3 -1
  135. package/skills/risk-compliance/contract-review/SKILL.md +1 -1
  136. package/skills/risk-compliance/contract-review/release-check.mjs +3 -1
  137. package/skills/risk-compliance/doc-authenticity/SKILL.md +1 -1
  138. package/skills/risk-compliance/doc-authenticity/release-check.mjs +3 -1
  139. package/skills/risk-compliance/fraud-analysis/SKILL.md +1 -1
  140. package/skills/risk-compliance/fraud-analysis/release-check.mjs +3 -1
  141. package/skills/risk-compliance/payment-analysis/SKILL.md +1 -1
  142. package/skills/risk-compliance/payment-analysis/release-check.mjs +3 -1
  143. package/skills/risk-compliance/similar-domain/SKILL.md +1 -1
  144. package/skills/risk-compliance/similar-domain/release-check.mjs +3 -1
  145. package/skills/risk-compliance/tld-detection/SKILL.md +1 -1
  146. package/skills/risk-compliance/tld-detection/release-check.mjs +3 -1
  147. package/skills/app-dev/android-foundation/scripts/device-run.test.mjs +0 -172
  148. package/skills/app-dev/data-catalog/scripts/data-catalog.test.mjs +0 -36
  149. package/skills/app-dev/data-quality/scripts/data-quality.test.mjs +0 -12
  150. package/skills/cicd/github-actions/scripts/ci-run-audit.test.mjs +0 -637
  151. package/skills/cicd/github-flow/scripts/flow.test.mjs +0 -114
  152. package/skills/cicd/github-flow/scripts/persist-conventions.test.mjs +0 -108
  153. package/skills/cicd/mergify/scripts/audit.test.mjs +0 -201
  154. package/skills/cicd/mergify/scripts/entrypoints.test.mjs +0 -106
  155. package/skills/cicd/mergify/scripts/pr-620-mergify-comments.fixture.json +0 -30
  156. package/skills/cicd/mergify/scripts/stack-push.test.mjs +0 -233
  157. package/skills/cicd/mergify/scripts/watch-pr-delivery.test.mjs +0 -1826
  158. package/skills/content/image-gen/scripts/credentials.test.mjs +0 -212
  159. package/skills/content/image-gen/scripts/options.test.mjs +0 -245
  160. package/skills/content/xai-search/tests/smoke_test.sh +0 -36
  161. package/skills/core/polish-cn/scripts/polish-cn.test.mjs +0 -244
  162. package/skills/core/reg-parser/scripts/reg-parser.test.mjs +0 -165
  163. package/skills/engineering/better-review/scripts/pr-context.test.mjs +0 -168
  164. package/skills/engineering/better-review/scripts/rereview-scope.test.mjs +0 -587
  165. package/skills/engineering/better-review/scripts/scan-diff.test.mjs +0 -414
  166. package/skills/engineering/better-review/scripts/vendor-sync.test.mjs +0 -96
  167. package/skills/engineering/contributing/scripts/persist-conventions.test.mjs +0 -118
  168. package/skills/engineering/e2e-test/scripts/presentation-checks.test.mjs +0 -106
  169. package/skills/engineering/e2e-test/scripts/presentation-perceivability.test.mjs +0 -117
  170. package/skills/engineering/e2e-test/scripts/presentation-reachability.test.mjs +0 -69
  171. package/skills/engineering/e2e-test/scripts/presentation-render-health.test.mjs +0 -98
  172. package/skills/engineering/e2e-test/scripts/presentation-sweep.test.mjs +0 -71
  173. package/skills/engineering/e2e-test/scripts/presentation-temporal.test.mjs +0 -59
  174. package/skills/engineering/e2e-test/scripts/project-route-manifest.test.mjs +0 -76
  175. package/skills/engineering/engineering-runtime/engineering-runtime.test.mjs +0 -68
  176. package/skills/engineering/engineering-runtime/scripts/invocation-policy.test.mjs +0 -95
  177. package/skills/engineering/engineering-runtime/scripts/main-module.test.mjs +0 -288
  178. package/skills/engineering/engineering-runtime/scripts/required-check-plan.test.mjs +0 -96
  179. package/skills/engineering/ensure-coverage/scripts/adapters/nextjs-inventory.test.mjs +0 -96
  180. package/skills/engineering/ensure-coverage/scripts/check-quarantine-expiry.test.mjs +0 -47
  181. package/skills/engineering/ensure-coverage/scripts/ci-audit.test.mjs +0 -86
  182. package/skills/engineering/ensure-coverage/scripts/coverage-ledger.test.mjs +0 -447
  183. package/skills/engineering/ensure-coverage/scripts/design-parity.test.mjs +0 -552
  184. package/skills/engineering/ensure-coverage/scripts/lint-tests.test.mjs +0 -289
  185. package/skills/engineering/ensure-coverage/scripts/mock-policy-config.test.mjs +0 -119
  186. package/skills/engineering/golden-path/scripts/golden-path.test.mjs +0 -1457
  187. package/skills/engineering/harness-runtime/discover-models.test.mjs +0 -363
  188. package/skills/engineering/harness-runtime/harness-runtime.test.mjs +0 -967
  189. package/skills/engineering/harness-runtime/model-catalog-seed.test.mjs +0 -829
  190. package/skills/engineering/harness-runtime/model-catalog.test.mjs +0 -366
  191. package/skills/engineering/resolve-issues/scripts/cleanup-runs.test.mjs +0 -280
  192. package/skills/engineering/resolve-issues/scripts/dropbox.test.mjs +0 -346
  193. package/skills/engineering/resolve-issues/scripts/findings-reuse.test.mjs +0 -88
  194. package/skills/engineering/resolve-issues/scripts/github-reviews.test.mjs +0 -264
  195. package/skills/engineering/resolve-issues/scripts/install-hooks.test.mjs +0 -79
  196. package/skills/engineering/resolve-issues/scripts/issue-tree.test.mjs +0 -107
  197. package/skills/engineering/resolve-issues/scripts/manual-invocation.test.mjs +0 -14
  198. package/skills/engineering/resolve-issues/scripts/next-actions-capacity.test.mjs +0 -149
  199. package/skills/engineering/resolve-issues/scripts/next-actions.test.mjs +0 -915
  200. package/skills/engineering/resolve-issues/scripts/plan-sync.test.mjs +0 -156
  201. package/skills/engineering/resolve-issues/scripts/preflight-models.test.mjs +0 -448
  202. package/skills/engineering/resolve-issues/scripts/ready-check.test.mjs +0 -217
  203. package/skills/engineering/resolve-issues/scripts/rehydrate.test.mjs +0 -91
  204. package/skills/engineering/resolve-issues/scripts/review-verdict.test.mjs +0 -1060
  205. package/skills/engineering/resolve-issues/scripts/size-check.test.mjs +0 -458
  206. package/skills/engineering/resolve-release/scripts/apply.test.mjs +0 -99
  207. package/skills/engineering/resolve-release/scripts/dark-flags.test.mjs +0 -100
  208. package/skills/engineering/resolve-release/scripts/flow.test.mjs +0 -340
  209. package/skills/engineering/resolve-release/scripts/green-head.test.mjs +0 -101
  210. package/skills/engineering/resolve-release/scripts/npm-version-absence.test.mjs +0 -426
  211. package/skills/engineering/resolve-release/scripts/plan-npm.test.mjs +0 -659
  212. package/skills/engineering/resolve-release/scripts/plan-toml-boundary.test.mjs +0 -317
  213. package/skills/engineering/resolve-release/scripts/plan-uv.test.mjs +0 -291
  214. package/skills/engineering/resolve-release/scripts/plan.test.mjs +0 -428
  215. package/skills/engineering/test-quality/scripts/lint-tests.test.mjs +0 -591
  216. package/skills/engineering/test-quality/scripts/mock-policy-config.test.mjs +0 -119
  217. package/skills/engineering/test-quality/scripts/persist-conventions.test.mjs +0 -104
  218. package/skills/risk-compliance/compliance-audit/scripts/compliance-audit.test.mjs +0 -14
  219. package/skills/risk-compliance/doc-authenticity/manual-invocation.test.mjs +0 -12
  220. package/skills/risk-compliance/doc-authenticity/scripts/validate_verdict.test.mjs +0 -212
  221. package/skills/risk-compliance/tld-detection/scripts/detect_ladders.test.mjs +0 -14
  222. package/skills/risk-compliance/tld-detection/scripts/detect_streams.test.mjs +0 -14
  223. package/skills/risk-compliance/tld-detection/tests/test_detect_ladders.py +0 -134
  224. package/skills/risk-compliance/tld-detection/tests/test_detect_streams.py +0 -520
@@ -1,363 +0,0 @@
1
- // discover-models tests — real fixture config files under a temp HOME, NEVER the
2
- // user's real ~/.pi / ~/.codex / ~/.claude. Every case writes its own config tree
3
- // into a scratch dir and runs the script with `HOME=<tmp>` and an INJECTED env for
4
- // the apiKey `$VAR` resolution, so no test reads or depends on the real machine's
5
- // config or environment. A test that touched the real config would be a defect —
6
- // the whole point of this unit is a trustworthy, isolated discovery read.
7
-
8
- import { test } from 'node:test'
9
- import assert from 'node:assert/strict'
10
- import fs from 'node:fs'
11
- import os from 'node:os'
12
- import path from 'node:path'
13
- import { fileURLToPath } from 'node:url'
14
- import { execFileSync } from 'node:child_process'
15
-
16
- import { discoverPi, discoverCodex, discoverClaudeCode, apiKeyResolves } from './discover-models.mjs'
17
-
18
- const scriptPath = path.join(path.dirname(fileURLToPath(import.meta.url)), 'bin', 'discover-models.mjs')
19
-
20
- // ---- temp-HOME fixture scaffolding ----
21
-
22
- function mkHome() {
23
- return fs.mkdtempSync(path.join(os.tmpdir(), 'discover-models-'))
24
- }
25
-
26
- function writeJson(file, obj) {
27
- fs.mkdirSync(path.dirname(file), { recursive: true })
28
- fs.writeFileSync(file, JSON.stringify(obj, null, 2))
29
- }
30
-
31
- function writeText(file, text) {
32
- fs.mkdirSync(path.dirname(file), { recursive: true })
33
- fs.writeFileSync(file, text)
34
- }
35
-
36
- // Run the script with a fully-controlled env: an explicit HOME (the fixture tree)
37
- // and only the env vars a case injects — so `$VAR` resolution is tested against
38
- // injected values, never the real environment. Returns { code, stdout, json }.
39
- function run(args, { home, extraEnv = {} } = {}) {
40
- const env = { PATH: process.env.PATH, HOME: home, ...extraEnv }
41
- let stdout = ''
42
- let code = 0
43
- try {
44
- stdout = execFileSync('node', [scriptPath, ...args], { encoding: 'utf8', env })
45
- } catch (err) {
46
- code = err.status ?? 1
47
- stdout = err.stdout ?? ''
48
- }
49
- let json = null
50
- try {
51
- json = JSON.parse(stdout)
52
- } catch {
53
- /* non-JSON (help/usage) — leave json null */
54
- }
55
- return { code, stdout, json }
56
- }
57
-
58
- const ids = (json) => json.discovered.map((d) => d.id)
59
-
60
- // ---- Pi: the full credentialed-remainder fixture ----
61
-
62
- // Builds the Pi fixture the task spec asks for, under a fresh temp HOME:
63
- // - enabledModels: the curated picker set
64
- // - a default provider/model
65
- // - a models.json custom entry whose provider apiKey is a LITERAL (resolves)
66
- // - a models.json custom entry whose provider apiKey is $SET_VAR (resolves)
67
- // - a models.json custom entry whose provider apiKey is $UNSET_VAR (does NOT resolve)
68
- // - an auth.json-credentialed provider with NO enabledModels entry (provider-level)
69
- function buildPiHome() {
70
- const home = mkHome()
71
- writeJson(path.join(home, '.pi', 'agent', 'settings.json'), {
72
- defaultProvider: 'openai',
73
- defaultModel: 'gpt-x-terra',
74
- enabledModels: ['openai/gpt-x-terra', 'openai/gpt-x-sol', 'acme/curated-1'],
75
- })
76
- writeJson(path.join(home, '.pi', 'agent', 'models.json'), {
77
- providers: {
78
- // openai is curated (has enabledModels entries) — a proxy provider, no models[]
79
- openai: { baseUrl: 'https://example/v1', apiKey: '$OPENAI_KEY' },
80
- // literal apiKey → resolves; custom models emitted at model level
81
- litprov: { apiKey: 'sk-literal-abc', models: [{ id: 'lit-model-1' }, { id: 'lit-model-2' }] },
82
- // $SET_VAR apiKey → resolves (env injected)
83
- setprov: { apiKey: '$SET_VAR', models: [{ id: 'set-model-1' }] },
84
- // $UNSET_VAR apiKey → does NOT resolve; its custom model is a KNOWN definition
85
- // the user cannot run — the never-a-source / credential-gate case.
86
- unsetprov: { apiKey: '$UNSET_VAR', models: [{ id: 'unset-model-1' }] },
87
- },
88
- })
89
- // A provider credentialed via auth.json with no enabledModels entry and no
90
- // models[] detail — listed at PROVIDER level only.
91
- writeJson(path.join(home, '.pi', 'agent', 'auth.json'), {
92
- google: { type: 'apiKey', key: 'stored-google-key' },
93
- })
94
- return home
95
- }
96
-
97
- // @covers package:harness-runtime
98
- // @level integration
99
- test('pi: discovers enabledModels, the default, and credentialed custom models', () => {
100
- const home = buildPiHome()
101
- const { code, json } = run(['--harness', 'pi'], { home, extraEnv: { OPENAI_KEY: 'x', SET_VAR: 'yes' } })
102
- assert.equal(code, 0)
103
- assert.equal(json.harness, 'pi')
104
- assert.equal(json.completeness, 'full')
105
- const discovered = ids(json)
106
- // curated picker set
107
- assert.ok(discovered.includes('openai/gpt-x-terra'))
108
- assert.ok(discovered.includes('openai/gpt-x-sol'))
109
- assert.ok(discovered.includes('acme/curated-1'))
110
- // literal-apiKey custom models
111
- assert.ok(discovered.includes('litprov/lit-model-1'))
112
- assert.ok(discovered.includes('litprov/lit-model-2'))
113
- // $SET_VAR-apiKey custom model
114
- assert.ok(discovered.includes('setprov/set-model-1'))
115
- })
116
-
117
- test('pi: the default provider/model is present and sourced as the default', () => {
118
- const home = buildPiHome()
119
- const { json } = run(['--harness', 'pi'], { home, extraEnv: { OPENAI_KEY: 'x', SET_VAR: 'yes' } })
120
- const entry = json.discovered.find((d) => d.id === 'openai/gpt-x-terra')
121
- assert.ok(entry, 'default model must be discovered')
122
- // It is already in enabledModels, so first-source-wins keeps the enabledModels source.
123
- assert.equal(entry.source, 'settings.json:enabledModels')
124
- })
125
-
126
- test('pi: an auth.json-credentialed provider with no enabledModels entry is listed at PROVIDER level only', () => {
127
- const home = buildPiHome()
128
- const { json } = run(['--harness', 'pi'], { home, extraEnv: { OPENAI_KEY: 'x', SET_VAR: 'yes' } })
129
- const discovered = ids(json)
130
- assert.ok(discovered.includes('google/*'), 'expected provider-level google/*')
131
- // NEVER an expanded per-model registry for the credentialed-but-uncurated provider.
132
- assert.ok(!discovered.some((id) => id.startsWith('google/') && id !== 'google/*'),
133
- 'google must appear only at provider level, never expanded into concrete model ids')
134
- const entry = json.discovered.find((d) => d.id === 'google/*')
135
- assert.match(entry.source, /auth\.json entry/)
136
- })
137
-
138
- test('pi: NEVER-A-SOURCE — a config-known model whose provider key does not resolve is NOT emitted', () => {
139
- const home = buildPiHome()
140
- // $UNSET_VAR is deliberately absent from the injected env.
141
- const { json } = run(['--harness', 'pi'], { home, extraEnv: { OPENAI_KEY: 'x', SET_VAR: 'yes' } })
142
- const discovered = ids(json)
143
- assert.ok(
144
- !discovered.includes('unsetprov/unset-model-1'),
145
- 'a custom model whose provider apiKey ($UNSET_VAR) does not resolve must NOT be discovered — ' +
146
- 'it is a definition the config knows but the user cannot run',
147
- )
148
- // And the provider itself is not credentialed, so no provider-level entry either.
149
- assert.ok(!discovered.includes('unsetprov/*'))
150
- })
151
-
152
- test('pi: records the never-a-source rule as a note', () => {
153
- const home = buildPiHome()
154
- const { json } = run(['--harness', 'pi'], { home, extraEnv: { OPENAI_KEY: 'x', SET_VAR: 'yes' } })
155
- assert.ok(json.notes.some((n) => /never a discovery source/.test(n) && /pi --models/.test(n)))
156
- })
157
-
158
- test('pi: missing config is graceful — empty set + note, exit 0, no crash', () => {
159
- const home = mkHome() // no .pi tree at all
160
- const { code, json } = run(['--harness', 'pi'], { home })
161
- assert.equal(code, 0)
162
- assert.equal(json.completeness, 'full')
163
- assert.deepEqual(json.discovered, [])
164
- assert.ok(json.notes.some((n) => /not found/.test(n)))
165
- })
166
-
167
- // ---- Codex ----
168
-
169
- // @covers package:harness-runtime
170
- // @level integration
171
- test('codex: discovers configured defaults without claiming a complete runnable inventory', () => {
172
- const home = mkHome()
173
- writeText(path.join(home, '.codex', 'config.toml'),
174
- 'model = "gpt-x-sol"\n' +
175
- 'model_reasoning_effort = "high"\n' + // must NOT be read as a model
176
- 'model_context_window = 1000000\n' +
177
- '\n' +
178
- '[profiles.deep]\n' +
179
- 'model = "gpt-x-max"\n')
180
- const { code, json } = run(['--harness', 'codex'], { home })
181
- assert.equal(code, 0)
182
- assert.equal(json.harness, 'codex')
183
- assert.equal(json.completeness, 'partial')
184
- const discovered = ids(json)
185
- assert.deepEqual(discovered.sort(), ['gpt-x-max', 'gpt-x-sol'].sort())
186
- // The `model_*` keys must not leak in as models.
187
- assert.ok(!discovered.includes('high'))
188
- assert.ok(!discovered.some((id) => /^\d+$/.test(id)))
189
- // The top-level model is sourced as config.toml:model; the profile one carries its table.
190
- assert.equal(json.discovered.find((d) => d.id === 'gpt-x-sol').source, 'config.toml:model')
191
- assert.match(json.discovered.find((d) => d.id === 'gpt-x-max').source, /\[profiles\.deep\]/)
192
- assert.ok(json.notes.some((note) => /partial/.test(note)))
193
- })
194
-
195
- test('codex: current-turn advertised ids are preserved, unioned, and make discovery full', () => {
196
- const home = mkHome()
197
- writeText(path.join(home, '.codex', 'config.toml'), 'model = "configured-default"\n')
198
- const { code, json } = run([
199
- '--harness', 'codex',
200
- '--available', 'advertised/model-a,configured-default,advertised:model-b',
201
- ], { home })
202
-
203
- assert.equal(code, 0)
204
- assert.equal(json.completeness, 'full')
205
- assert.deepEqual(ids(json), ['advertised/model-a', 'configured-default', 'advertised:model-b'])
206
- assert.equal(json.discovered[0].source, 'current-turn')
207
- assert.equal(json.discovered[2].source, 'current-turn')
208
- })
209
-
210
- test('codex: a human-named runnable id is evidence but does not turn partial discovery into full', () => {
211
- const home = mkHome()
212
- const { code, json } = run([
213
- '--harness', 'codex',
214
- '--human-named', 'operator/model-exact',
215
- ], { home })
216
-
217
- assert.equal(code, 0)
218
- assert.equal(json.completeness, 'partial')
219
- assert.deepEqual(json.discovered, [{ id: 'operator/model-exact', source: 'human-named' }])
220
- })
221
-
222
- test('codex: missing config is graceful — empty set + note, exit 0', () => {
223
- const home = mkHome()
224
- const { code, json } = run(['--harness', 'codex'], { home })
225
- assert.equal(code, 0)
226
- assert.equal(json.completeness, 'partial')
227
- assert.deepEqual(json.discovered, [])
228
- assert.ok(json.notes.some((n) => /not found/.test(n)))
229
- })
230
-
231
- // ---- Claude Code (honest-partial) ----
232
-
233
- // @covers package:harness-runtime
234
- // @level integration
235
- test('claude-code: is honest-partial — records that discovery stays manual and does NOT read the banked catalog', () => {
236
- const home = mkHome()
237
- writeJson(path.join(home, '.claude', 'settings.json'), { effortLevel: 'high', permissions: {} })
238
- // A banked catalog is present — it must NOT be treated as an availability source.
239
- writeJson(path.join(home, '.claude', 'model-catalog.json'), {
240
- harness: 'claude-code',
241
- models: [{ id: 'should-not-appear', tiers: { high: 'frontier' } }],
242
- })
243
- const { code, json } = run(['--harness', 'claude-code'], { home })
244
- assert.equal(code, 0)
245
- assert.equal(json.harness, 'claude-code')
246
- assert.equal(json.completeness, 'partial')
247
- assert.ok(!ids(json).includes('should-not-appear'),
248
- 'the banked model-catalog.json is a cache of confirmations, never an availability source')
249
- assert.ok(json.notes.some((n) => /Agent-tool model enum/.test(n) && /stays manual/.test(n)))
250
- })
251
-
252
- test('claude-code: current-turn advertised ids complete discovery and union with settings', () => {
253
- const home = mkHome()
254
- writeJson(path.join(home, '.claude', 'settings.json'), { model: 'configured-model' })
255
- const { code, json } = run([
256
- '--harness', 'claude-code',
257
- '--available', 'advertised-model,configured-model',
258
- ], { home })
259
-
260
- assert.equal(code, 0)
261
- assert.equal(json.completeness, 'full')
262
- assert.deepEqual(ids(json), ['advertised-model', 'configured-model'])
263
- assert.ok(json.discovered.every((model) => model.source === 'current-turn'))
264
- })
265
-
266
- // ---- CLI contract: help, unknown flags, auto-detect ----
267
-
268
- test('--help exits 0 with non-empty usage naming the flags and exit codes', () => {
269
- const { code, stdout } = run(['--help'], { home: mkHome() })
270
- assert.equal(code, 0)
271
- assert.ok(stdout.includes('--harness'))
272
- assert.ok(stdout.includes('--available'))
273
- assert.ok(stdout.includes('--human-named'))
274
- assert.ok(stdout.includes('Exit codes'))
275
- assert.ok(/pi\|codex\|claude-code/.test(stdout))
276
- })
277
-
278
- test('-h is an alias for --help (exit 0)', () => {
279
- const { code, stdout } = run(['-h'], { home: mkHome() })
280
- assert.equal(code, 0)
281
- assert.ok(stdout.length > 0)
282
- })
283
-
284
- test('an unknown flag exits 2 with usage', () => {
285
- const { code } = run(['--bogus'], { home: mkHome() })
286
- assert.equal(code, 2)
287
- })
288
-
289
- test('an unknown --harness value exits 2', () => {
290
- const { code } = run(['--harness', 'nope'], { home: mkHome() })
291
- assert.equal(code, 2)
292
- })
293
-
294
- test('no --harness with an ambiguous/empty HOME exits 2 (never guesses)', () => {
295
- const { code } = run([], { home: mkHome() }) // empty HOME: no harness present
296
- assert.equal(code, 2)
297
- })
298
-
299
- test('no --harness auto-detects the sole present harness', () => {
300
- const home = mkHome()
301
- writeText(path.join(home, '.codex', 'config.toml'), 'model = "solo-model"\n')
302
- const { code, json } = run([], { home })
303
- assert.equal(code, 0)
304
- assert.equal(json.harness, 'codex')
305
- assert.ok(ids(json).includes('solo-model'))
306
- })
307
-
308
- // ---- pure-core unit checks (fast, no spawn) ----
309
-
310
- test('apiKeyResolves: literal resolves; $SET resolves; $UNSET does not; empty does not', () => {
311
- assert.equal(apiKeyResolves('sk-abc', {}).resolved, true)
312
- assert.equal(apiKeyResolves('$K', { K: 'v' }).resolved, true)
313
- assert.equal(apiKeyResolves('$K', {}).resolved, false)
314
- assert.equal(apiKeyResolves('', {}).resolved, false)
315
- assert.equal(apiKeyResolves(undefined, {}).resolved, false)
316
- })
317
-
318
- test('discoverPi (pure): credential gate excludes the unresolved custom model', () => {
319
- const { discovered } = discoverPi({
320
- settings: { enabledModels: ['a/one'] },
321
- models: {
322
- providers: {
323
- ok: { apiKey: 'lit', models: [{ id: 'runnable' }] },
324
- no: { apiKey: '$MISSING', models: [{ id: 'notrunnable' }] },
325
- },
326
- },
327
- auth: {},
328
- env: {},
329
- })
330
- const set = discovered.map((d) => d.id)
331
- assert.ok(set.includes('a/one'))
332
- assert.ok(set.includes('ok/runnable'))
333
- assert.ok(!set.includes('no/notrunnable'))
334
- })
335
-
336
- // @covers package:harness-runtime
337
- // @level unit
338
- test('discoverCodex (pure): explicit current-turn ids pass unchanged and take source precedence', () => {
339
- const advertised = ['provider/model-a', 'model:b']
340
- const { discovered, completeness } = discoverCodex({
341
- configText: 'model = "provider/model-a"\nmodel = "config-only"\n',
342
- spawnModelIds: advertised,
343
- })
344
- assert.equal(completeness, 'full')
345
- assert.deepEqual(discovered, [
346
- { id: 'provider/model-a', source: 'current-turn' },
347
- { id: 'model:b', source: 'current-turn' },
348
- { id: 'config-only', source: 'config.toml:model' },
349
- ])
350
- assert.deepEqual(advertised, ['provider/model-a', 'model:b'])
351
- })
352
-
353
- test('discoverCodex (pure): empty text yields empty + note, not a throw', () => {
354
- const { discovered, notes, completeness } = discoverCodex({ configText: null })
355
- assert.deepEqual(discovered, [])
356
- assert.equal(completeness, 'partial')
357
- assert.ok(notes.length > 0)
358
- })
359
-
360
- test('discoverClaudeCode (pure): always carries the honest-manual note', () => {
361
- const { notes } = discoverClaudeCode({ settings: {} })
362
- assert.ok(notes.some((n) => /stays manual/.test(n)))
363
- })