orizu 0.5.19 → 0.5.20

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 (141) hide show
  1. package/README.md +23 -0
  2. package/dist/diff-comments-cli.js +18 -2
  3. package/dist/gepa-engine-dispatch.js +261 -0
  4. package/dist/gepa-python-command.js +26 -0
  5. package/dist/gepa-python-paths.js +39 -0
  6. package/dist/help.js +4 -4
  7. package/dist/index.js +34 -40
  8. package/dist/markdown-report-input.js +15 -1
  9. package/dist/prompt-length-wire.js +2 -2
  10. package/dist/prompt-report-cli.js +2 -2
  11. package/dist/report-markdown-blankness.js +6 -0
  12. package/dist/report-replacement-warning.js +31 -0
  13. package/package.json +2 -2
  14. package/scripts/build-cli-dist.mjs +30 -0
  15. package/scripts/orizu-source-checkout.d.mts +1 -0
  16. package/scripts/orizu-source-checkout.mjs +10 -0
  17. package/scripts/vendor-gepa-python.mjs +187 -4
  18. package/src/diff-comments-cli.ts +37 -3
  19. package/src/gepa-engine-dispatch.ts +300 -0
  20. package/src/gepa-python-command.ts +31 -0
  21. package/src/gepa-python-paths.ts +53 -0
  22. package/src/help.ts +4 -4
  23. package/src/index.ts +35 -43
  24. package/src/markdown-report-input.ts +19 -1
  25. package/src/prompt-length-wire.ts +1 -1
  26. package/src/prompt-report-cli.ts +2 -2
  27. package/src/report-markdown-blankness.ts +6 -0
  28. package/src/report-replacement-warning.ts +35 -0
  29. package/vendor/gepa-python/LICENSE +7 -0
  30. package/vendor/gepa-python/manifest.json +107 -0
  31. package/vendor/gepa-python/src/gepa/__init__.py +22 -0
  32. package/vendor/gepa-python/src/gepa/adapters/__init__.py +0 -0
  33. package/vendor/gepa-python/src/gepa/adapters/anymaths_adapter/__init__.py +1 -0
  34. package/vendor/gepa-python/src/gepa/adapters/anymaths_adapter/anymaths_adapter.py +174 -0
  35. package/vendor/gepa-python/src/gepa/adapters/confidence_adapter/__init__.py +26 -0
  36. package/vendor/gepa-python/src/gepa/adapters/confidence_adapter/confidence_adapter.py +618 -0
  37. package/vendor/gepa-python/src/gepa/adapters/confidence_adapter/scoring.py +206 -0
  38. package/vendor/gepa-python/src/gepa/adapters/default_adapter/__init__.py +0 -0
  39. package/vendor/gepa-python/src/gepa/adapters/default_adapter/default_adapter.py +206 -0
  40. package/vendor/gepa-python/src/gepa/adapters/dspy_adapter/__init__.py +0 -0
  41. package/vendor/gepa-python/src/gepa/adapters/dspy_adapter/dspy_adapter.py +525 -0
  42. package/vendor/gepa-python/src/gepa/adapters/dspy_adapter/instruction_proposal.py +500 -0
  43. package/vendor/gepa-python/src/gepa/adapters/dspy_full_program_adapter/__init__.py +6 -0
  44. package/vendor/gepa-python/src/gepa/adapters/dspy_full_program_adapter/dspy_program_proposal_signature.py +137 -0
  45. package/vendor/gepa-python/src/gepa/adapters/dspy_full_program_adapter/full_program_adapter.py +269 -0
  46. package/vendor/gepa-python/src/gepa/adapters/generic_rag_adapter/__init__.py +56 -0
  47. package/vendor/gepa-python/src/gepa/adapters/generic_rag_adapter/evaluation_metrics.py +226 -0
  48. package/vendor/gepa-python/src/gepa/adapters/generic_rag_adapter/generic_rag_adapter.py +496 -0
  49. package/vendor/gepa-python/src/gepa/adapters/generic_rag_adapter/rag_pipeline.py +238 -0
  50. package/vendor/gepa-python/src/gepa/adapters/generic_rag_adapter/vector_store_interface.py +212 -0
  51. package/vendor/gepa-python/src/gepa/adapters/generic_rag_adapter/vector_stores/__init__.py +2 -0
  52. package/vendor/gepa-python/src/gepa/adapters/generic_rag_adapter/vector_stores/chroma_store.py +196 -0
  53. package/vendor/gepa-python/src/gepa/adapters/generic_rag_adapter/vector_stores/lancedb_store.py +422 -0
  54. package/vendor/gepa-python/src/gepa/adapters/generic_rag_adapter/vector_stores/milvus_store.py +409 -0
  55. package/vendor/gepa-python/src/gepa/adapters/generic_rag_adapter/vector_stores/qdrant_store.py +368 -0
  56. package/vendor/gepa-python/src/gepa/adapters/generic_rag_adapter/vector_stores/weaviate_store.py +418 -0
  57. package/vendor/gepa-python/src/gepa/adapters/langchain_adapter/__init__.py +11 -0
  58. package/vendor/gepa-python/src/gepa/adapters/langchain_adapter/langchain_adapter.py +261 -0
  59. package/vendor/gepa-python/src/gepa/adapters/mcp_adapter/__init__.py +37 -0
  60. package/vendor/gepa-python/src/gepa/adapters/mcp_adapter/mcp_adapter.py +693 -0
  61. package/vendor/gepa-python/src/gepa/adapters/mcp_adapter/mcp_client.py +364 -0
  62. package/vendor/gepa-python/src/gepa/adapters/optimize_anything_adapter/optimize_anything_adapter.py +879 -0
  63. package/vendor/gepa-python/src/gepa/adapters/terminal_bench_adapter/__init__.py +0 -0
  64. package/vendor/gepa-python/src/gepa/adapters/terminal_bench_adapter/terminal_bench_adapter.py +217 -0
  65. package/vendor/gepa-python/src/gepa/api.py +468 -0
  66. package/vendor/gepa-python/src/gepa/core/__init__.py +0 -0
  67. package/vendor/gepa-python/src/gepa/core/adapter.py +227 -0
  68. package/vendor/gepa-python/src/gepa/core/callbacks.py +551 -0
  69. package/vendor/gepa-python/src/gepa/core/data_loader.py +74 -0
  70. package/vendor/gepa-python/src/gepa/core/engine.py +1025 -0
  71. package/vendor/gepa-python/src/gepa/core/result.py +271 -0
  72. package/vendor/gepa-python/src/gepa/core/state.py +706 -0
  73. package/vendor/gepa-python/src/gepa/examples/__init__.py +0 -0
  74. package/vendor/gepa-python/src/gepa/examples/aime.py +24 -0
  75. package/vendor/gepa-python/src/gepa/examples/anymaths-bench/eval_default.py +111 -0
  76. package/vendor/gepa-python/src/gepa/examples/anymaths-bench/train_anymaths.py +177 -0
  77. package/vendor/gepa-python/src/gepa/examples/mcp_adapter/__init__.py +4 -0
  78. package/vendor/gepa-python/src/gepa/examples/mcp_adapter/mcp_optimization_example.py +456 -0
  79. package/vendor/gepa-python/src/gepa/examples/rag_adapter/__init__.py +9 -0
  80. package/vendor/gepa-python/src/gepa/examples/rag_adapter/rag_optimization.py +824 -0
  81. package/vendor/gepa-python/src/gepa/examples/terminal-bench/train_terminus.py +161 -0
  82. package/vendor/gepa-python/src/gepa/gepa_utils.py +117 -0
  83. package/vendor/gepa-python/src/gepa/gskill/__init__.py +1 -0
  84. package/vendor/gepa-python/src/gepa/gskill/gskill/__init__.py +0 -0
  85. package/vendor/gepa-python/src/gepa/gskill/gskill/cost_tracker.py +194 -0
  86. package/vendor/gepa-python/src/gepa/gskill/gskill/evaluate/__init__.py +0 -0
  87. package/vendor/gepa-python/src/gepa/gskill/gskill/evaluate/claude_code.py +1117 -0
  88. package/vendor/gepa-python/src/gepa/gskill/gskill/evaluate/claude_code_skills.py +613 -0
  89. package/vendor/gepa-python/src/gepa/gskill/gskill/evaluate/mini_swe_agent.py +440 -0
  90. package/vendor/gepa-python/src/gepa/gskill/gskill/experiment_logger.py +367 -0
  91. package/vendor/gepa-python/src/gepa/gskill/gskill/swe_fitness_fn.py +209 -0
  92. package/vendor/gepa-python/src/gepa/gskill/gskill/swe_harness.py +352 -0
  93. package/vendor/gepa-python/src/gepa/gskill/gskill/train_optimize_anything.py +830 -0
  94. package/vendor/gepa-python/src/gepa/image.py +104 -0
  95. package/vendor/gepa-python/src/gepa/lm.py +261 -0
  96. package/vendor/gepa-python/src/gepa/logging/__init__.py +0 -0
  97. package/vendor/gepa-python/src/gepa/logging/experiment_tracker.py +457 -0
  98. package/vendor/gepa-python/src/gepa/logging/logger.py +75 -0
  99. package/vendor/gepa-python/src/gepa/logging/utils.py +130 -0
  100. package/vendor/gepa-python/src/gepa/optimize_anything.py +1701 -0
  101. package/vendor/gepa-python/src/gepa/proposer/__init__.py +0 -0
  102. package/vendor/gepa-python/src/gepa/proposer/base.py +53 -0
  103. package/vendor/gepa-python/src/gepa/proposer/merge.py +403 -0
  104. package/vendor/gepa-python/src/gepa/proposer/reflective_mutation/__init__.py +0 -0
  105. package/vendor/gepa-python/src/gepa/proposer/reflective_mutation/base.py +64 -0
  106. package/vendor/gepa-python/src/gepa/proposer/reflective_mutation/reflection_lm.py +178 -0
  107. package/vendor/gepa-python/src/gepa/proposer/reflective_mutation/reflective_mutation.py +641 -0
  108. package/vendor/gepa-python/src/gepa/py.typed +0 -0
  109. package/vendor/gepa-python/src/gepa/strategies/__init__.py +0 -0
  110. package/vendor/gepa-python/src/gepa/strategies/acceptance.py +66 -0
  111. package/vendor/gepa-python/src/gepa/strategies/batch_sampler.py +103 -0
  112. package/vendor/gepa-python/src/gepa/strategies/candidate_selector.py +82 -0
  113. package/vendor/gepa-python/src/gepa/strategies/component_selector.py +36 -0
  114. package/vendor/gepa-python/src/gepa/strategies/eval_policy.py +64 -0
  115. package/vendor/gepa-python/src/gepa/strategies/instruction_proposal.py +153 -0
  116. package/vendor/gepa-python/src/gepa/strategies/proposal_sampling.py +128 -0
  117. package/vendor/gepa-python/src/gepa/strategies/proposal_selection.py +84 -0
  118. package/vendor/gepa-python/src/gepa/utils/__init__.py +63 -0
  119. package/vendor/gepa-python/src/gepa/utils/code_execution.py +626 -0
  120. package/vendor/gepa-python/src/gepa/utils/stdio_capture.py +145 -0
  121. package/vendor/gepa-python/src/gepa/utils/stop_condition.py +230 -0
  122. package/vendor/gepa-python/src/gepa/visualization.py +359 -0
  123. package/vendor/orizu-gepa/pyproject.toml +18 -0
  124. package/vendor/orizu-gepa/src/orizu_gepa_connector/__init__.py +8 -0
  125. package/vendor/orizu-gepa/src/orizu_gepa_connector/__main__.py +5 -0
  126. package/vendor/orizu-gepa/src/orizu_gepa_connector/adapter.py +132 -0
  127. package/vendor/orizu-gepa/src/orizu_gepa_connector/callbacks.py +652 -0
  128. package/vendor/orizu-gepa/src/orizu_gepa_connector/cli.py +7 -0
  129. package/vendor/orizu-gepa/src/orizu_gepa_connector/engine.py +177 -0
  130. package/vendor/orizu-gepa/src/orizu_gepa_connector/preflight.py +64 -0
  131. package/vendor/orizu-gepa/src/orizu_gepa_connector/reflection.py +106 -0
  132. package/vendor/orizu-gepa/src/orizu_gepa_connector/runtime.py +643 -0
  133. package/vendor/orizu-gepa/src/orizu_gepa_connector/stop_conditions.py +38 -0
  134. package/vendor/orizu-gepa/src/orizu_gepa_connector/translator.py +202 -0
  135. package/vendor/orizu-gepa-python/pyproject.toml +1 -1
  136. package/vendor/orizu-gepa-python/src/orizu_gepa/cli.py +1 -0
  137. package/vendor/orizu-gepa-python/src/orizu_gepa/local_log.py +49 -0
  138. package/vendor/skills/orizu-cli/SKILL.md +1 -1
  139. package/vendor/skills/orizu-cli/references/optimization-reports.md +1 -1
  140. package/vendor/skills/orizu-cli/references/optimization-with-gepa.md +1 -1
  141. package/vendor/skills/orizu-cli/references/prompt-control-plane.md +6 -3
@@ -0,0 +1,31 @@
1
+ /**
2
+ * ALI-1452: a shared, human-readable warning for a replaced prompt-version
3
+ * report on a push/draft response.
4
+ *
5
+ * Re-pushing an unchanged prompt with a report deliberately replaces the
6
+ * version's existing report (reports are correctable; versions are immutable).
7
+ * The server discloses that replacement as `report_replaced:
8
+ * { source_name, updated_at } | null`; this turns a non-null disclosure into
9
+ * the stderr warning line the push commands print. JSON mode prints nothing —
10
+ * the payload already carries `report_replaced`.
11
+ */
12
+ function isRecord(value) {
13
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
14
+ }
15
+ /**
16
+ * A one-line warning when a push response discloses that it replaced an
17
+ * existing report, or null when nothing was replaced (or no report was sent).
18
+ */
19
+ export function reportReplacementWarning(data) {
20
+ const replaced = data.report_replaced;
21
+ if (!isRecord(replaced))
22
+ return null;
23
+ const sourceName = typeof replaced.source_name === 'string'
24
+ ? replaced.source_name
25
+ : 'unknown source';
26
+ const updatedAt = typeof replaced.updated_at === 'string'
27
+ ? replaced.updated_at
28
+ : 'unknown time';
29
+ return ('Warning: replaced the existing report for this version ' +
30
+ `(${sourceName}, last updated ${updatedAt})`);
31
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "orizu",
3
- "version": "0.5.19",
3
+ "version": "0.5.20",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "bin": {
@@ -16,7 +16,7 @@
16
16
  ],
17
17
  "scripts": {
18
18
  "build": "tsc -p tsconfig.json",
19
- "prepack": "node scripts/vendor-gepa-python.mjs && node scripts/vendor-orizu-skill.mjs",
19
+ "prepack": "node scripts/build-cli-dist.mjs && node scripts/vendor-gepa-python.mjs && node scripts/vendor-orizu-skill.mjs",
20
20
  "postpack": "node scripts/vendor-gepa-python.mjs --clean && node scripts/vendor-orizu-skill.mjs --clean"
21
21
  },
22
22
  "dependencies": {
@@ -0,0 +1,30 @@
1
+ import { existsSync, rmSync } from 'node:fs'
2
+ import { spawnSync } from 'node:child_process'
3
+ import { dirname, resolve } from 'node:path'
4
+ import { fileURLToPath } from 'node:url'
5
+
6
+ import { isOrizuSourceCheckout } from './orizu-source-checkout.mjs'
7
+
8
+ const scriptDir = dirname(fileURLToPath(import.meta.url))
9
+ const cliRoot = resolve(scriptDir, '..')
10
+ const repoRoot = resolve(cliRoot, '..', '..')
11
+ const packedEntrypoint = resolve(cliRoot, 'dist', 'index.js')
12
+
13
+ // A source checkout has the compiler and must always rebuild before packing so
14
+ // ignored dist cannot carry an old CLI. A published tarball has no dev compiler;
15
+ // it may be repacked only when it already carries the built entrypoint.
16
+ if (!isOrizuSourceCheckout(resolve(repoRoot, 'package.json'))) {
17
+ if (!existsSync(packedEntrypoint)) {
18
+ throw new Error('Unable to pack CLI: published package is missing dist/index.js')
19
+ }
20
+ process.exit(0)
21
+ }
22
+
23
+ const npm = process.platform === 'win32' ? 'npm.cmd' : 'npm'
24
+ // Delete old compiler output first: npm pack must never retain a module whose
25
+ // TypeScript source was renamed or removed since the previous build.
26
+ rmSync(resolve(cliRoot, 'dist'), { recursive: true, force: true })
27
+ const result = spawnSync(npm, ['run', 'build'], { cwd: cliRoot, stdio: 'inherit' })
28
+ if (result.status !== 0) {
29
+ throw new Error(`Unable to build CLI dist before packing: ${result.error?.message || 'npm run build failed'}`)
30
+ }
@@ -0,0 +1 @@
1
+ export function isOrizuSourceCheckout(packageJsonPath: string): boolean
@@ -0,0 +1,10 @@
1
+ import { readFileSync } from 'node:fs'
2
+
3
+ /** True only for the Orizu monorepo, never merely for a consumer Git checkout. */
4
+ export function isOrizuSourceCheckout(packageJsonPath) {
5
+ try {
6
+ return JSON.parse(readFileSync(packageJsonPath, 'utf8')).name === 'orizu'
7
+ } catch {
8
+ return false
9
+ }
10
+ }
@@ -1,4 +1,6 @@
1
- import { cpSync, existsSync, mkdirSync, rmSync } from 'node:fs'
1
+ import { cpSync, existsSync, mkdirSync, readdirSync, rmSync, statSync, writeFileSync, readFileSync } from 'node:fs'
2
+ import { createHash } from 'node:crypto'
3
+ import { spawnSync } from 'node:child_process'
2
4
  import { dirname, resolve } from 'node:path'
3
5
  import { fileURLToPath } from 'node:url'
4
6
 
@@ -7,32 +9,194 @@ const cliRoot = resolve(scriptDir, '..')
7
9
  const repoRoot = resolve(cliRoot, '..', '..')
8
10
  const sourceRoot = resolve(repoRoot, 'packages', 'orizu-gepa-python')
9
11
  const vendorRoot = resolve(cliRoot, 'vendor', 'orizu-gepa-python')
12
+ const connectorSourceRoot = resolve(repoRoot, 'packages', 'orizu-gepa')
13
+ const connectorVendorRoot = resolve(cliRoot, 'vendor', 'orizu-gepa')
14
+ const officialArchive = resolve(cliRoot, 'gepa-python-source.zip')
15
+ const officialVendorRoot = resolve(cliRoot, 'vendor', 'gepa-python')
10
16
  const shouldClean = process.argv.includes('--clean')
17
+ const shouldRefresh = process.argv.includes('--refresh')
18
+ const archiveArgumentIndex = process.argv.indexOf('--archive')
19
+ const suppliedArchive = archiveArgumentIndex === -1
20
+ ? null
21
+ : process.argv[archiveArgumentIndex + 1]
11
22
  const sourceSrc = resolve(sourceRoot, 'src')
12
23
  const sourcePyproject = resolve(sourceRoot, 'pyproject.toml')
13
24
  const sourceManifest = resolve(sourceRoot, 'manifest.json')
14
25
  const vendoredSrc = resolve(vendorRoot, 'src')
15
26
  const vendoredPyproject = resolve(vendorRoot, 'pyproject.toml')
16
27
  const vendoredManifest = resolve(vendorRoot, 'manifest.json')
28
+ const officialVendoredManifest = resolve(officialVendorRoot, 'manifest.json')
29
+ const officialVendoredGepa = resolve(officialVendorRoot, 'src', 'gepa', '__init__.py')
30
+ const GEPA_VERSION = '0.1.4'
31
+ const GEPA_RELEASE_COMMIT = '8b0ce6cd99a234f6b74daf37558a2ac0ce18f975'
32
+ const GEPA_WHEEL_FILENAME = 'gepa-0.1.4-py3-none-any.whl'
33
+ const GEPA_WHEEL_SHA256 = '12b971039599625c156d2231f6d72a29c31a22e9c237689459b5f1a3c353f532'
17
34
  const hasSourcePackage = existsSync(sourceSrc)
18
35
  && existsSync(sourcePyproject)
19
36
  && existsSync(sourceManifest)
37
+ const hasConnectorSourcePackage = existsSync(resolve(connectorSourceRoot, 'src'))
38
+ && existsSync(resolve(connectorSourceRoot, 'pyproject.toml'))
20
39
  const hasVendoredPackage = existsSync(vendoredSrc)
21
40
  && existsSync(vendoredPyproject)
22
41
  && existsSync(vendoredManifest)
42
+ const hasVendoredConnectorPackage = existsSync(resolve(connectorVendorRoot, 'src', 'orizu_gepa_connector', '__main__.py'))
43
+ && existsSync(resolve(connectorVendorRoot, 'pyproject.toml'))
44
+ const hasOfficialVendoredPackage = existsSync(officialVendoredManifest)
45
+ && existsSync(officialVendoredGepa)
46
+
47
+ function sha256File(path) {
48
+ return createHash('sha256').update(readFileSync(path)).digest('hex')
49
+ }
50
+
51
+ function assertPinnedGepaArchive(path) {
52
+ if (!existsSync(path)) {
53
+ throw new Error(`Unable to vendor official GEPA: source archive not found at ${path}`)
54
+ }
55
+
56
+ const actualSha256 = sha256File(path)
57
+ if (actualSha256 !== GEPA_WHEEL_SHA256) {
58
+ throw new Error(
59
+ `Official GEPA source archive sha256 mismatch: expected ${GEPA_WHEEL_SHA256}, got ${actualSha256}`
60
+ )
61
+ }
62
+ }
63
+
64
+ function collectFileHashes(root, prefix = '') {
65
+ const files = {}
66
+ for (const entry of readdirSync(root).sort()) {
67
+ const path = resolve(root, entry)
68
+ const relativePath = prefix ? `${prefix}/${entry}` : entry
69
+ if (statSync(path).isDirectory()) {
70
+ Object.assign(files, collectFileHashes(path, relativePath))
71
+ } else {
72
+ files[relativePath] = sha256File(path)
73
+ }
74
+ }
75
+ return files
76
+ }
77
+
78
+ function assertOfficialVendoredManifest() {
79
+ let manifest
80
+ try {
81
+ manifest = JSON.parse(readFileSync(officialVendoredManifest, 'utf8'))
82
+ } catch (error) {
83
+ throw new Error(`Official GEPA vendored manifest is unreadable: ${error.message}`)
84
+ }
85
+
86
+ if (!manifest.files || typeof manifest.files !== 'object' || Array.isArray(manifest.files)) {
87
+ throw new Error('Official GEPA vendored manifest is missing file hashes')
88
+ }
89
+
90
+ const actualFiles = collectFileHashes(officialVendorRoot)
91
+ delete actualFiles['manifest.json']
92
+ const expectedEntries = Object.entries(manifest.files).sort(([left], [right]) => left.localeCompare(right))
93
+ const actualEntries = Object.entries(actualFiles).sort(([left], [right]) => left.localeCompare(right))
94
+ if (expectedEntries.length !== actualEntries.length) {
95
+ throw new Error('Official GEPA vendored manifest file count does not match extracted files')
96
+ }
97
+
98
+ for (let index = 0; index < expectedEntries.length; index += 1) {
99
+ const [expectedPath, expectedSha256] = expectedEntries[index]
100
+ const [actualPath, actualSha256] = actualEntries[index]
101
+ if (expectedPath !== actualPath || expectedSha256 !== actualSha256) {
102
+ throw new Error(`Official GEPA vendored manifest mismatch at ${expectedPath}`)
103
+ }
104
+ }
105
+ }
106
+
107
+ function extractPinnedGepa(archivePath) {
108
+ const extractor = String.raw`
109
+ from pathlib import Path, PurePosixPath
110
+ import shutil
111
+ import sys
112
+ import zipfile
113
+
114
+ archive_path = Path(sys.argv[1])
115
+ destination_root = Path(sys.argv[2])
116
+ license_member = 'gepa-0.1.4.dist-info/licenses/LICENSE'
117
+
118
+ with zipfile.ZipFile(archive_path) as archive:
119
+ for member in archive.infolist():
120
+ if member.is_dir():
121
+ continue
122
+ if member.filename.startswith('gepa/'):
123
+ relative_path = PurePosixPath('src') / PurePosixPath(member.filename)
124
+ elif member.filename == license_member:
125
+ relative_path = PurePosixPath('LICENSE')
126
+ else:
127
+ continue
128
+ if relative_path.is_absolute() or '..' in relative_path.parts:
129
+ raise ValueError(f'unsafe GEPA wheel member: {member.filename}')
130
+ destination = destination_root.joinpath(*relative_path.parts)
131
+ destination.parent.mkdir(parents=True, exist_ok=True)
132
+ with archive.open(member) as source, destination.open('wb') as output:
133
+ shutil.copyfileobj(source, output)
134
+ `
135
+ const result = spawnSync('python3', ['-c', extractor, archivePath, officialVendorRoot], {
136
+ encoding: 'utf8',
137
+ })
138
+ if (result.status !== 0) {
139
+ const details = result.error?.message || result.stderr || result.stdout || 'no subprocess output'
140
+ throw new Error(`Unable to extract verified official GEPA wheel; python3 is required: ${details}`)
141
+ }
142
+ }
143
+
144
+ function vendorOfficialGepa(archivePath) {
145
+ assertPinnedGepaArchive(archivePath)
146
+ rmSync(officialVendorRoot, { recursive: true, force: true })
147
+ mkdirSync(officialVendorRoot, { recursive: true })
148
+ extractPinnedGepa(archivePath)
149
+
150
+ const files = collectFileHashes(officialVendorRoot)
151
+ writeFileSync(officialVendoredManifest, `${JSON.stringify({
152
+ schemaVersion: 'gepa-vendor.v1',
153
+ upstream: {
154
+ package: 'gepa',
155
+ version: GEPA_VERSION,
156
+ repositoryCommit: GEPA_RELEASE_COMMIT,
157
+ wheel: {
158
+ filename: GEPA_WHEEL_FILENAME,
159
+ sha256: GEPA_WHEEL_SHA256,
160
+ },
161
+ },
162
+ files,
163
+ }, null, 2)}\n`)
164
+ }
165
+
166
+ if (archiveArgumentIndex !== -1 && (!suppliedArchive || suppliedArchive.startsWith('--'))) {
167
+ throw new Error('Expected a source archive path after --archive')
168
+ }
169
+
170
+ if (shouldRefresh) {
171
+ if (!suppliedArchive) {
172
+ throw new Error('Refreshing official GEPA requires --archive <verified-wheel-path>')
173
+ }
174
+ assertPinnedGepaArchive(suppliedArchive)
175
+ cpSync(suppliedArchive, officialArchive)
176
+ }
23
177
 
24
178
  if (shouldClean) {
25
179
  if (hasSourcePackage) {
26
180
  rmSync(vendorRoot, { recursive: true, force: true })
27
181
  }
182
+ if (hasConnectorSourcePackage) {
183
+ rmSync(connectorVendorRoot, { recursive: true, force: true })
184
+ }
185
+ if (hasSourcePackage || hasConnectorSourcePackage) {
186
+ rmSync(officialVendorRoot, { recursive: true, force: true })
187
+ }
28
188
  process.exit(0)
29
189
  }
30
190
 
31
- if (!hasSourcePackage) {
32
- if (hasVendoredPackage) {
191
+ if (!hasSourcePackage || !hasConnectorSourcePackage) {
192
+ if (hasVendoredPackage && hasVendoredConnectorPackage && hasOfficialVendoredPackage) {
193
+ assertOfficialVendoredManifest()
33
194
  process.exit(0)
34
195
  }
35
- throw new Error(`Unable to vendor orizu-gepa-python: source package not found at ${sourceRoot}`)
196
+ if (hasVendoredPackage || hasVendoredConnectorPackage || hasOfficialVendoredPackage) {
197
+ throw new Error('Unable to vendor GEPA packages: vendored legacy, connector, or official package is incomplete')
198
+ }
199
+ throw new Error(`Unable to vendor GEPA packages: source package not found at ${sourceRoot} or ${connectorSourceRoot}`)
36
200
  }
37
201
 
38
202
  rmSync(vendorRoot, { recursive: true, force: true })
@@ -52,3 +216,22 @@ cpSync(sourceSrc, resolve(vendorRoot, 'src'), {
52
216
  && !normalizedPath.endsWith('/.DS_Store')
53
217
  },
54
218
  })
219
+
220
+ rmSync(connectorVendorRoot, { recursive: true, force: true })
221
+ mkdirSync(connectorVendorRoot, { recursive: true })
222
+ cpSync(resolve(connectorSourceRoot, 'pyproject.toml'), resolve(connectorVendorRoot, 'pyproject.toml'))
223
+ cpSync(resolve(connectorSourceRoot, 'src'), resolve(connectorVendorRoot, 'src'), {
224
+ recursive: true,
225
+ filter: sourcePath => {
226
+ const normalizedPath = sourcePath.replace(/\\/g, '/')
227
+ return !normalizedPath.endsWith('/__pycache__')
228
+ && !normalizedPath.includes('/__pycache__/')
229
+ && !normalizedPath.endsWith('.pyc')
230
+ && !normalizedPath.endsWith('.pyo')
231
+ && !normalizedPath.endsWith('/.pytest_cache')
232
+ && !normalizedPath.includes('/.pytest_cache/')
233
+ && !normalizedPath.endsWith('/.DS_Store')
234
+ },
235
+ })
236
+
237
+ vendorOfficialGepa(suppliedArchive ?? officialArchive)
@@ -50,7 +50,11 @@ interface DiffCommentPayloadPairContext {
50
50
  bodies: { from: string; to: string } | null
51
51
  degraded: { reason: DiffCommentContextUnavailableReason } | null
52
52
  lengthStats: CliLengthStatsPair | null
53
- lengthDelta: CliLengthDelta | null
53
+ lengthDelta: (
54
+ Partial<Record<keyof Omit<CliLengthDelta, 'splitUnavailableReason'>, unknown>> & {
55
+ splitUnavailableReason?: unknown
56
+ }
57
+ ) | null
54
58
  lengthDeltaUnavailableReason?: CliLengthMeasurementUnavailableReason
55
59
  comments: DiffCommentPayloadComment[]
56
60
  }
@@ -76,6 +80,12 @@ interface DiffCommentsPayload {
76
80
  pairs: DiffCommentPayloadPair[]
77
81
  }
78
82
 
83
+ interface RenderableLengthMetricDelta {
84
+ removed: number | null
85
+ added: number | null
86
+ net: number | null
87
+ }
88
+
79
89
  export interface DiffCommentsCliContext {
80
90
  getArg: (name: string) => string | null
81
91
  rejectDashPrefixedOptionValue: (name: string, value: string | null) => void
@@ -171,6 +181,22 @@ function formatDeltaValue(
171
181
  return metric === 'tokens' ? `~${formatted}` : formatted
172
182
  }
173
183
 
184
+ function isLengthMetricDelta(
185
+ value: unknown
186
+ ): value is RenderableLengthMetricDelta {
187
+ if (typeof value !== 'object' || value === null || Array.isArray(value)) {
188
+ return false
189
+ }
190
+ const delta = value as Record<string, unknown>
191
+ const isNullableFiniteNumber = (candidate: unknown) =>
192
+ candidate === null || (
193
+ typeof candidate === 'number' && Number.isFinite(candidate)
194
+ )
195
+ return isNullableFiniteNumber(delta.removed) &&
196
+ isNullableFiniteNumber(delta.added) &&
197
+ isNullableFiniteNumber(delta.net)
198
+ }
199
+
174
200
  function printLengthMeasurements(
175
201
  ctx: DiffCommentsCliContext,
176
202
  pair: DiffCommentPayloadPair
@@ -210,11 +236,15 @@ function printLengthMeasurements(
210
236
  return
211
237
  }
212
238
 
213
- if (pair.lengthDelta.splitUnavailableReason) {
239
+ const splitUnavailableReason = pair.lengthDelta.splitUnavailableReason
240
+ if (
241
+ typeof splitUnavailableReason === 'string' &&
242
+ splitUnavailableReason.length > 0
243
+ ) {
214
244
  ctx.printLine(
215
245
  ` Split unavailable: ${sanitizeHumanInlineText(
216
246
  ctx.sanitizeTerminalText,
217
- pair.lengthDelta.splitUnavailableReason
247
+ splitUnavailableReason
218
248
  )}`
219
249
  )
220
250
  }
@@ -225,6 +255,10 @@ function printLengthMeasurements(
225
255
  ['words', 'Words'],
226
256
  ] as const) {
227
257
  const delta = pair.lengthDelta[metric]
258
+ if (!isLengthMetricDelta(delta)) {
259
+ ctx.printLine(` ${label}: unavailable`)
260
+ continue
261
+ }
228
262
  ctx.printLine(
229
263
  ` ${label}: removed ${formatDeltaValue(delta.removed, metric)} · ` +
230
264
  `added ${formatDeltaValue(delta.added, metric)} · ` +