onto-mcp 0.3.2 → 0.4.0
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/.onto/processes/reconstruct/actionable-ontology-seed-recomposition-design.md +447 -0
- package/.onto/processes/reconstruct/foundry-style-ontology-seed-contract.md +934 -0
- package/.onto/processes/reconstruct/reconstruct-boundary-contract.md +303 -725
- package/.onto/processes/reconstruct/reconstruct-contract-registry.yaml +1645 -0
- package/.onto/processes/reconstruct/reconstruct-execution-ux-contract.md +26 -22
- package/.onto/processes/reconstruct/source-profile-contract.md +49 -23
- package/.onto/processes/reconstruct/source-profiles/code.md +6 -3
- package/.onto/processes/reconstruct/source-profiles/database.md +5 -2
- package/.onto/processes/reconstruct/source-profiles/document.md +5 -2
- package/.onto/processes/reconstruct/source-profiles/spreadsheet.md +5 -4
- package/.onto/processes/review/review-execution-ux-contract.md +40 -0
- package/.onto/processes/shared/pipeline-execution-ledger-contract.md +26 -10
- package/.onto/processes/shared/target-material-kind-contract.md +29 -16
- package/AGENTS.md +6 -4
- package/README.md +135 -76
- package/dist/cli.js +8 -8
- package/dist/core-api/reconstruct-api.js +117 -31
- package/dist/core-api/review-api.js +47 -0
- package/dist/core-runtime/cli/codex-review-unit-executor.js +39 -2
- package/dist/core-runtime/cli/complete-review-session.js +2 -2
- package/dist/core-runtime/cli/mock-review-unit-executor.js +1 -1
- package/dist/core-runtime/cli/review-invoke.js +9 -9
- package/dist/core-runtime/cli/run-review-prompt-execution.js +39 -5
- package/dist/core-runtime/cli/spawn-watcher.js +266 -47
- package/dist/core-runtime/cli/start-review-session.js +3 -3
- package/dist/core-runtime/llm/llm-caller.js +11 -0
- package/dist/core-runtime/llm/llm-tool-loop.js +2 -0
- package/dist/core-runtime/observability/runtime-stream-observation.js +118 -0
- package/dist/core-runtime/onboard/cli-host.js +149 -0
- package/dist/core-runtime/onboard/host-target.js +22 -0
- package/dist/core-runtime/onboard/json-config-host.js +122 -0
- package/dist/core-runtime/onboard/path-scan.js +26 -0
- package/dist/core-runtime/onboard/prompt.js +51 -0
- package/dist/core-runtime/onboard/register.js +207 -0
- package/dist/core-runtime/onboard/types.js +27 -0
- package/dist/core-runtime/reconstruct/actionable-seed-validation.js +1777 -0
- package/dist/core-runtime/reconstruct/artifact-types.js +10 -4
- package/dist/core-runtime/reconstruct/contract-registry.js +623 -0
- package/dist/core-runtime/reconstruct/domain-id.js +10 -0
- package/dist/core-runtime/reconstruct/governing-snapshot.js +716 -0
- package/dist/core-runtime/reconstruct/material-profile-validation.js +191 -0
- package/dist/core-runtime/reconstruct/materialize-preparation.js +49 -11
- package/dist/core-runtime/reconstruct/pipeline-execution-ledger.js +269 -79
- package/dist/core-runtime/reconstruct/post-seed-validation.js +1194 -51
- package/dist/core-runtime/reconstruct/record.js +104 -20
- package/dist/core-runtime/reconstruct/run.js +2107 -413
- package/dist/core-runtime/reconstruct/seed-claim-projections.js +268 -0
- package/dist/core-runtime/reconstruct/source-profiles.js +93 -4
- package/dist/core-runtime/reconstruct/terminal-validation.js +807 -0
- package/dist/core-runtime/review/review-invocation-runner.js +4 -4
- package/dist/mcp/server.js +110 -38
- package/dist/mcp/tool-schemas.js +20 -6
- package/package.json +8 -17
- package/scripts/onto-review-watch.sh +486 -0
- package/scripts/onto-runtime-watch.sh +122 -0
- package/scripts/postinstall-hint.js +22 -0
- package/.onto/processes/reconstruct/top-level-concept-discovery-contract.md +0 -387
- package/dist/core-runtime/cli/bootstrap-review-binding.js +0 -186
- package/dist/core-runtime/cli/codex-nested-dispatch.test.js +0 -390
- package/dist/core-runtime/cli/codex-nested-teamlead-executor.test.js +0 -335
- package/dist/core-runtime/cli/coordinator-helpers.js +0 -583
- package/dist/core-runtime/cli/coordinator-state-machine-deliberation.test.js +0 -167
- package/dist/core-runtime/cli/coordinator-state-machine.js +0 -794
- package/dist/core-runtime/cli/e2e-codex-multi-agent-fixes.test.js +0 -615
- package/dist/core-runtime/cli/e2e-start-review-session.test.js +0 -312
- package/dist/core-runtime/cli/health.js +0 -44
- package/dist/core-runtime/cli/inline-http-review-unit-executor.test.js +0 -567
- package/dist/core-runtime/cli/materialize-review-execution-preparation.js +0 -104
- package/dist/core-runtime/cli/migrate-session-roots.js +0 -118
- package/dist/core-runtime/cli/repo-layout-migration-replace.smoke.test.js +0 -106
- package/dist/core-runtime/cli/review-invoke-auto-resolution.test.js +0 -268
- package/dist/core-runtime/cli/review-invoke-coordinator-topology.test.js +0 -136
- package/dist/core-runtime/cli/review-invoke-resolver-caching.test.js +0 -201
- package/dist/core-runtime/cli/review-invoke-topology-dispatch.test.js +0 -192
- package/dist/core-runtime/cli/session-root-guard.js +0 -168
- package/dist/core-runtime/cli/spawn-watcher.test.js +0 -457
- package/dist/core-runtime/cli/strip-wrapping-code-fence.test.js +0 -79
- package/dist/core-runtime/cli/teamcreate-lens-deliberation-executor.js +0 -412
- package/dist/core-runtime/cli/teamcreate-lens-deliberation-executor.test.js +0 -351
- package/dist/core-runtime/cli/topology-executor-mapping.js +0 -139
- package/dist/core-runtime/cli/topology-executor-mapping.test.js +0 -173
- package/dist/core-runtime/cli/write-review-interpretation.js +0 -81
- package/dist/core-runtime/config/onto-config-cli.js +0 -278
- package/dist/core-runtime/config/onto-config-key-path.js +0 -288
- package/dist/core-runtime/config/onto-config-key-path.test.js +0 -195
- package/dist/core-runtime/config/onto-config-preview.js +0 -108
- package/dist/core-runtime/config/onto-config-preview.test.js +0 -132
- package/dist/core-runtime/discovery/config-chain.js +0 -118
- package/dist/core-runtime/discovery/config-chain.test.js +0 -103
- package/dist/core-runtime/discovery/config-profile.js +0 -199
- package/dist/core-runtime/discovery/config-profile.test.js +0 -233
- package/dist/core-runtime/discovery/host-detection.test.js +0 -186
- package/dist/core-runtime/discovery/installation-paths.test.js +0 -65
- package/dist/core-runtime/discovery/lens-registry.test.js +0 -81
- package/dist/core-runtime/discovery/path-normalization.test.js +0 -22
- package/dist/core-runtime/discovery/plugin-path.js +0 -72
- package/dist/core-runtime/discovery/plugin-path.test.js +0 -95
- package/dist/core-runtime/evolve/adapters/code-product/compile/compile-defense.js +0 -344
- package/dist/core-runtime/evolve/adapters/code-product/compile/compile-defense.test.js +0 -915
- package/dist/core-runtime/evolve/adapters/code-product/compile/compile.js +0 -564
- package/dist/core-runtime/evolve/adapters/code-product/compile/compile.test.js +0 -708
- package/dist/core-runtime/evolve/adapters/code-product/parsers/brief-parser.js +0 -165
- package/dist/core-runtime/evolve/adapters/code-product/parsers/brief-parser.test.js +0 -227
- package/dist/core-runtime/evolve/adapters/code-product/validators/validate.js +0 -59
- package/dist/core-runtime/evolve/adapters/code-product/validators/validate.test.js +0 -205
- package/dist/core-runtime/evolve/adapters/methodology/adapter.js +0 -16
- package/dist/core-runtime/evolve/adapters/methodology/adapter.test.js +0 -9
- package/dist/core-runtime/evolve/adapters/methodology/perspectives/authority-consistency.js +0 -298
- package/dist/core-runtime/evolve/adapters/methodology/perspectives/authority-consistency.test.js +0 -70
- package/dist/core-runtime/evolve/adapters/methodology/scope-types/process.js +0 -46
- package/dist/core-runtime/evolve/adapters/methodology/scope-types/process.test.js +0 -73
- package/dist/core-runtime/evolve/adapters/registry.js +0 -47
- package/dist/core-runtime/evolve/adapters/registry.test.js +0 -67
- package/dist/core-runtime/evolve/cli.js +0 -256
- package/dist/core-runtime/evolve/commands/align.js +0 -194
- package/dist/core-runtime/evolve/commands/align.test.js +0 -82
- package/dist/core-runtime/evolve/commands/apply.js +0 -161
- package/dist/core-runtime/evolve/commands/apply.test.js +0 -138
- package/dist/core-runtime/evolve/commands/close.js +0 -39
- package/dist/core-runtime/evolve/commands/close.test.js +0 -99
- package/dist/core-runtime/evolve/commands/defer.js +0 -40
- package/dist/core-runtime/evolve/commands/defer.test.js +0 -134
- package/dist/core-runtime/evolve/commands/draft.js +0 -323
- package/dist/core-runtime/evolve/commands/draft.test.js +0 -178
- package/dist/core-runtime/evolve/commands/e2e-evolve-full-cycle.test.js +0 -208
- package/dist/core-runtime/evolve/commands/error-messages.js +0 -125
- package/dist/core-runtime/evolve/commands/error-messages.test.js +0 -167
- package/dist/core-runtime/evolve/commands/propose-align.js +0 -222
- package/dist/core-runtime/evolve/commands/propose-align.test.js +0 -136
- package/dist/core-runtime/evolve/commands/reconstruct.js +0 -330
- package/dist/core-runtime/evolve/commands/reconstruct.test.js +0 -278
- package/dist/core-runtime/evolve/commands/shared.js +0 -22
- package/dist/core-runtime/evolve/commands/stale-check.js +0 -103
- package/dist/core-runtime/evolve/commands/stale-check.test.js +0 -84
- package/dist/core-runtime/evolve/commands/start.js +0 -887
- package/dist/core-runtime/evolve/commands/start.test.js +0 -396
- package/dist/core-runtime/evolve/config/project-config.js +0 -99
- package/dist/core-runtime/evolve/config/project-config.test.js +0 -170
- package/dist/core-runtime/evolve/renderers/align-packet.js +0 -280
- package/dist/core-runtime/evolve/renderers/align-packet.test.js +0 -332
- package/dist/core-runtime/evolve/renderers/draft-packet.js +0 -303
- package/dist/core-runtime/evolve/renderers/draft-packet.test.js +0 -377
- package/dist/core-runtime/evolve/renderers/format.js +0 -5
- package/dist/core-runtime/evolve/renderers/scope-md.js +0 -237
- package/dist/core-runtime/evolve/renderers/scope-md.test.js +0 -306
- package/dist/core-runtime/govern/cli.js +0 -369
- package/dist/core-runtime/govern/cli.test.js +0 -314
- package/dist/core-runtime/govern/drift-engine.js +0 -103
- package/dist/core-runtime/govern/drift-engine.test.js +0 -319
- package/dist/core-runtime/govern/promote-principle.js +0 -206
- package/dist/core-runtime/govern/promote-principle.test.js +0 -368
- package/dist/core-runtime/govern/queue.js +0 -81
- package/dist/core-runtime/govern/types.js +0 -16
- package/dist/core-runtime/install/cli.js +0 -530
- package/dist/core-runtime/install/detect.js +0 -128
- package/dist/core-runtime/install/detect.test.js +0 -155
- package/dist/core-runtime/install/gitignore-update.js +0 -74
- package/dist/core-runtime/install/gitignore-update.test.js +0 -64
- package/dist/core-runtime/install/install-integration.test.js +0 -373
- package/dist/core-runtime/install/prompts.js +0 -389
- package/dist/core-runtime/install/prompts.test.js +0 -293
- package/dist/core-runtime/install/types.js +0 -26
- package/dist/core-runtime/install/validation.js +0 -295
- package/dist/core-runtime/install/validation.test.js +0 -313
- package/dist/core-runtime/install/writer.js +0 -254
- package/dist/core-runtime/install/writer.test.js +0 -218
- package/dist/core-runtime/learning/extractor.js +0 -461
- package/dist/core-runtime/learning/feedback.js +0 -179
- package/dist/core-runtime/learning/health-report.js +0 -165
- package/dist/core-runtime/learning/health-report.test.js +0 -169
- package/dist/core-runtime/learning/loader.js +0 -388
- package/dist/core-runtime/learning/loader.test.js +0 -102
- package/dist/core-runtime/learning/promote/apply-state.js +0 -240
- package/dist/core-runtime/learning/promote/audit-obligation.js +0 -195
- package/dist/core-runtime/learning/promote/collector.js +0 -432
- package/dist/core-runtime/learning/promote/degraded-state.js +0 -125
- package/dist/core-runtime/learning/promote/domain-doc-proposer.js +0 -166
- package/dist/core-runtime/learning/promote/e2e-promote.test.js +0 -6385
- package/dist/core-runtime/learning/promote/health-snapshot.js +0 -150
- package/dist/core-runtime/learning/promote/insight-reclassifier.js +0 -544
- package/dist/core-runtime/learning/promote/judgment-auditor.js +0 -517
- package/dist/core-runtime/learning/promote/panel-reviewer.js +0 -1158
- package/dist/core-runtime/learning/promote/promote-executor.js +0 -1675
- package/dist/core-runtime/learning/promote/promoter.js +0 -307
- package/dist/core-runtime/learning/promote/retirement.js +0 -122
- package/dist/core-runtime/learning/promote/types.js +0 -23
- package/dist/core-runtime/learning/prompt-sections.js +0 -51
- package/dist/core-runtime/learning/shared/artifact-registry-init.js +0 -45
- package/dist/core-runtime/learning/shared/artifact-registry.js +0 -254
- package/dist/core-runtime/learning/shared/audit-obligation-kernel.js +0 -73
- package/dist/core-runtime/learning/shared/audit-state.js +0 -99
- package/dist/core-runtime/learning/shared/duplicate-check.js +0 -28
- package/dist/core-runtime/learning/shared/llm-caller.js +0 -831
- package/dist/core-runtime/learning/shared/llm-caller.test.js +0 -601
- package/dist/core-runtime/learning/shared/llm-tool-loop.js +0 -393
- package/dist/core-runtime/learning/shared/mode.js +0 -25
- package/dist/core-runtime/learning/shared/paths.js +0 -84
- package/dist/core-runtime/learning/shared/paths.test.js +0 -79
- package/dist/core-runtime/learning/shared/patterns.js +0 -37
- package/dist/core-runtime/learning/shared/recoverability.js +0 -355
- package/dist/core-runtime/learning/shared/recovery-context.js +0 -374
- package/dist/core-runtime/learning/shared/scope.js +0 -1
- package/dist/core-runtime/learning/shared/semantic-classifier.js +0 -94
- package/dist/core-runtime/learning/shared/specs/apply-execution-state-spec.js +0 -42
- package/dist/core-runtime/learning/shared/specs/audit-state-spec.js +0 -37
- package/dist/core-runtime/learning/shared/specs/backup-metadata-spec.js +0 -39
- package/dist/core-runtime/learning/shared/specs/emergency-log-spec.js +0 -41
- package/dist/core-runtime/learning/shared/specs/layout-version-spec.js +0 -38
- package/dist/core-runtime/learning/shared/specs/promote-decisions-spec.js +0 -43
- package/dist/core-runtime/learning/shared/specs/promote-report-spec.js +0 -113
- package/dist/core-runtime/learning/shared/specs/prune-log-spec.js +0 -36
- package/dist/core-runtime/learning/shared/specs/recovery-resolution-spec.js +0 -48
- package/dist/core-runtime/learning/shared/specs/restore-manifest-spec.js +0 -43
- package/dist/core-runtime/learning/shared/specs/spec-helpers.js +0 -64
- package/dist/core-runtime/learning/usage-tracker.js +0 -190
- package/dist/core-runtime/learning/usage-tracker.test.js +0 -176
- package/dist/core-runtime/onboard/detect-review-axes.js +0 -122
- package/dist/core-runtime/onboard/detect-review-axes.test.js +0 -127
- package/dist/core-runtime/onboard/write-review-block.js +0 -188
- package/dist/core-runtime/onboard/write-review-block.test.js +0 -240
- package/dist/core-runtime/readers/brownfield-builder.js +0 -150
- package/dist/core-runtime/readers/brownfield-builder.test.js +0 -136
- package/dist/core-runtime/readers/code-chunk-collector.js +0 -53
- package/dist/core-runtime/readers/code-chunk-collector.test.js +0 -136
- package/dist/core-runtime/readers/file-utils.js +0 -240
- package/dist/core-runtime/readers/file-utils.test.js +0 -146
- package/dist/core-runtime/readers/lexicon-citation-check.js +0 -93
- package/dist/core-runtime/readers/lexicon-citation-check.test.js +0 -77
- package/dist/core-runtime/readers/mcp-figma.js +0 -30
- package/dist/core-runtime/readers/mcp-figma.test.js +0 -82
- package/dist/core-runtime/readers/mcp-generic.js +0 -31
- package/dist/core-runtime/readers/mcp-generic.test.js +0 -76
- package/dist/core-runtime/readers/ontology-index.js +0 -148
- package/dist/core-runtime/readers/ontology-index.test.js +0 -245
- package/dist/core-runtime/readers/ontology-query.js +0 -168
- package/dist/core-runtime/readers/ontology-query.test.js +0 -311
- package/dist/core-runtime/readers/ontology-resolve.js +0 -48
- package/dist/core-runtime/readers/ontology-resolve.test.js +0 -48
- package/dist/core-runtime/readers/patterns/index.js +0 -7
- package/dist/core-runtime/readers/review-log.js +0 -213
- package/dist/core-runtime/readers/review-log.test.js +0 -313
- package/dist/core-runtime/readers/scan-local.js +0 -102
- package/dist/core-runtime/readers/scan-local.test.js +0 -102
- package/dist/core-runtime/readers/scan-tarball.js +0 -121
- package/dist/core-runtime/readers/scan-tarball.test.js +0 -283
- package/dist/core-runtime/readers/scan-vault.js +0 -34
- package/dist/core-runtime/readers/scan-vault.test.js +0 -81
- package/dist/core-runtime/readers/types.js +0 -42
- package/dist/core-runtime/readers/types.test.js +0 -94
- package/dist/core-runtime/readers/viewpoint-collectors.js +0 -229
- package/dist/core-runtime/reconstruct/seed-candidate-validation.js +0 -385
- package/dist/core-runtime/review/citation-audit.test.js +0 -165
- package/dist/core-runtime/review/execution-plan-resolver.js +0 -247
- package/dist/core-runtime/review/execution-plan-resolver.test.js +0 -243
- package/dist/core-runtime/review/execution-topology-resolver-axis-first.test.js +0 -246
- package/dist/core-runtime/review/execution-topology-resolver.js +0 -401
- package/dist/core-runtime/review/execution-topology-resolver.test.js +0 -315
- package/dist/core-runtime/review/inline-context-embedder.test.js +0 -154
- package/dist/core-runtime/review/legacy-mode-policy.js +0 -88
- package/dist/core-runtime/review/materializers-effort-persist.test.js +0 -79
- package/dist/core-runtime/review/ontology-path-classifier.js +0 -179
- package/dist/core-runtime/review/ontology-path-classifier.test.js +0 -216
- package/dist/core-runtime/review/packet-boundary-policy.test.js +0 -107
- package/dist/core-runtime/review/participating-lens-paths.test.js +0 -73
- package/dist/core-runtime/review/review-config-legacy-translate.js +0 -244
- package/dist/core-runtime/review/review-config-legacy-translate.test.js +0 -161
- package/dist/core-runtime/review/review-config-validator.js +0 -289
- package/dist/core-runtime/review/review-config-validator.test.js +0 -236
- package/dist/core-runtime/review/shape-pipeline-audit.test.js +0 -311
- package/dist/core-runtime/review/shape-to-topology-id.js +0 -117
- package/dist/core-runtime/review/shape-to-topology-id.test.js +0 -132
- package/dist/core-runtime/review/topology-shape-derivation.js +0 -155
- package/dist/core-runtime/review/topology-shape-derivation.test.js +0 -195
- package/dist/core-runtime/scope-runtime/constants.js +0 -12
- package/dist/core-runtime/scope-runtime/constraint-pool.js +0 -166
- package/dist/core-runtime/scope-runtime/constraint-pool.test.js +0 -674
- package/dist/core-runtime/scope-runtime/domain-validation-log.js +0 -135
- package/dist/core-runtime/scope-runtime/domain-validation-log.test.js +0 -156
- package/dist/core-runtime/scope-runtime/eval-persistence.js +0 -65
- package/dist/core-runtime/scope-runtime/eval-persistence.test.js +0 -84
- package/dist/core-runtime/scope-runtime/event-pipeline.js +0 -64
- package/dist/core-runtime/scope-runtime/event-pipeline.test.js +0 -450
- package/dist/core-runtime/scope-runtime/event-store.js +0 -39
- package/dist/core-runtime/scope-runtime/event-store.test.js +0 -95
- package/dist/core-runtime/scope-runtime/gate-guard.js +0 -348
- package/dist/core-runtime/scope-runtime/gate-guard.test.js +0 -1047
- package/dist/core-runtime/scope-runtime/hash.js +0 -4
- package/dist/core-runtime/scope-runtime/hash.test.js +0 -33
- package/dist/core-runtime/scope-runtime/id.js +0 -4
- package/dist/core-runtime/scope-runtime/id.test.js +0 -17
- package/dist/core-runtime/scope-runtime/reducer.js +0 -297
- package/dist/core-runtime/scope-runtime/reducer.test.js +0 -759
- package/dist/core-runtime/scope-runtime/scope-manager.js +0 -161
- package/dist/core-runtime/scope-runtime/state-machine.js +0 -309
- package/dist/core-runtime/scope-runtime/state-machine.test.js +0 -704
- package/dist/core-runtime/scope-runtime/types.js +0 -116
- package/dist/core-runtime/scope-runtime/types.test.js +0 -69
- package/dist/core-runtime/translate/render-for-user.js +0 -169
- package/dist/core-runtime/translate/render-for-user.test.js +0 -122
- package/dist/providers/capability-contract.js +0 -1
|
@@ -1,155 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, beforeEach, afterEach } from "vitest";
|
|
2
|
-
import fs from "node:fs";
|
|
3
|
-
import os from "node:os";
|
|
4
|
-
import path from "node:path";
|
|
5
|
-
import { formatPreflightSummary, globalConfigPath, projectConfigPath, runPreflight, } from "./detect.js";
|
|
6
|
-
const ENV_KEYS = [
|
|
7
|
-
"ANTHROPIC_API_KEY",
|
|
8
|
-
"OPENAI_API_KEY",
|
|
9
|
-
"LITELLM_BASE_URL",
|
|
10
|
-
"CLAUDECODE",
|
|
11
|
-
"CLAUDE_PROJECT_DIR",
|
|
12
|
-
"CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS",
|
|
13
|
-
];
|
|
14
|
-
let savedEnv = {};
|
|
15
|
-
function saveEnv() {
|
|
16
|
-
savedEnv = {};
|
|
17
|
-
for (const key of ENV_KEYS) {
|
|
18
|
-
savedEnv[key] = process.env[key];
|
|
19
|
-
delete process.env[key];
|
|
20
|
-
}
|
|
21
|
-
savedEnv.PATH = process.env.PATH;
|
|
22
|
-
// Empty PATH neutralizes codex binary detection.
|
|
23
|
-
process.env.PATH = "";
|
|
24
|
-
savedEnv.HOME = process.env.HOME;
|
|
25
|
-
}
|
|
26
|
-
function restoreEnv() {
|
|
27
|
-
for (const [key, value] of Object.entries(savedEnv)) {
|
|
28
|
-
if (value === undefined) {
|
|
29
|
-
delete process.env[key];
|
|
30
|
-
}
|
|
31
|
-
else {
|
|
32
|
-
process.env[key] = value;
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
/** Point HOME at a tmpdir so ~/.onto/ / ~/.codex/ checks are isolated. */
|
|
37
|
-
function isolateHome() {
|
|
38
|
-
const tmpHome = fs.mkdtempSync(path.join(os.tmpdir(), "onto-install-test-"));
|
|
39
|
-
process.env.HOME = tmpHome;
|
|
40
|
-
return tmpHome;
|
|
41
|
-
}
|
|
42
|
-
function cleanupHome(tmpHome) {
|
|
43
|
-
fs.rmSync(tmpHome, { recursive: true, force: true });
|
|
44
|
-
}
|
|
45
|
-
describe("runPreflight", () => {
|
|
46
|
-
let tmpHome;
|
|
47
|
-
let tmpProject;
|
|
48
|
-
beforeEach(() => {
|
|
49
|
-
saveEnv();
|
|
50
|
-
tmpHome = isolateHome();
|
|
51
|
-
tmpProject = fs.mkdtempSync(path.join(os.tmpdir(), "onto-install-proj-"));
|
|
52
|
-
});
|
|
53
|
-
afterEach(() => {
|
|
54
|
-
restoreEnv();
|
|
55
|
-
cleanupHome(tmpHome);
|
|
56
|
-
fs.rmSync(tmpProject, { recursive: true, force: true });
|
|
57
|
-
});
|
|
58
|
-
it("returns all-false baseline when environment is empty", () => {
|
|
59
|
-
const result = runPreflight(tmpProject);
|
|
60
|
-
expect(result).toEqual({
|
|
61
|
-
existingGlobalConfig: false,
|
|
62
|
-
existingProjectConfig: false,
|
|
63
|
-
hasAnthropicKey: false,
|
|
64
|
-
hasOpenAiKey: false,
|
|
65
|
-
hasLitellmBaseUrl: false,
|
|
66
|
-
hasCodexBinary: false,
|
|
67
|
-
hasCodexAuth: false,
|
|
68
|
-
hostIsClaudeCode: false,
|
|
69
|
-
});
|
|
70
|
-
});
|
|
71
|
-
it("detects ANTHROPIC_API_KEY", () => {
|
|
72
|
-
process.env.ANTHROPIC_API_KEY = "sk-ant-test";
|
|
73
|
-
const result = runPreflight(tmpProject);
|
|
74
|
-
expect(result.hasAnthropicKey).toBe(true);
|
|
75
|
-
expect(result.hasOpenAiKey).toBe(false);
|
|
76
|
-
});
|
|
77
|
-
it("detects OPENAI_API_KEY from env", () => {
|
|
78
|
-
process.env.OPENAI_API_KEY = "sk-test";
|
|
79
|
-
const result = runPreflight(tmpProject);
|
|
80
|
-
expect(result.hasOpenAiKey).toBe(true);
|
|
81
|
-
});
|
|
82
|
-
it("detects OPENAI_API_KEY from ~/.codex/auth.json", () => {
|
|
83
|
-
const codexDir = path.join(tmpHome, ".codex");
|
|
84
|
-
fs.mkdirSync(codexDir, { recursive: true });
|
|
85
|
-
fs.writeFileSync(path.join(codexDir, "auth.json"), JSON.stringify({ OPENAI_API_KEY: "sk-from-file" }));
|
|
86
|
-
const result = runPreflight(tmpProject);
|
|
87
|
-
expect(result.hasOpenAiKey).toBe(true);
|
|
88
|
-
expect(result.hasCodexAuth).toBe(true);
|
|
89
|
-
});
|
|
90
|
-
it("captures LITELLM_BASE_URL value when present", () => {
|
|
91
|
-
process.env.LITELLM_BASE_URL = "http://localhost:4000/v1";
|
|
92
|
-
const result = runPreflight(tmpProject);
|
|
93
|
-
expect(result.hasLitellmBaseUrl).toBe(true);
|
|
94
|
-
expect(result.litellmBaseUrlValue).toBe("http://localhost:4000/v1");
|
|
95
|
-
});
|
|
96
|
-
it("detects Claude Code session via CLAUDECODE env signal", () => {
|
|
97
|
-
process.env.CLAUDECODE = "1";
|
|
98
|
-
const result = runPreflight(tmpProject);
|
|
99
|
-
expect(result.hostIsClaudeCode).toBe(true);
|
|
100
|
-
});
|
|
101
|
-
it("splits codex binary and auth presence for install UX", () => {
|
|
102
|
-
// Binary present, auth missing — the "run `codex login`" branch.
|
|
103
|
-
const fakeBinDir = fs.mkdtempSync(path.join(os.tmpdir(), "onto-install-bin-"));
|
|
104
|
-
fs.writeFileSync(path.join(fakeBinDir, "codex"), "#!/bin/sh\nexit 0");
|
|
105
|
-
fs.chmodSync(path.join(fakeBinDir, "codex"), 0o755);
|
|
106
|
-
try {
|
|
107
|
-
process.env.PATH = fakeBinDir;
|
|
108
|
-
const result = runPreflight(tmpProject);
|
|
109
|
-
expect(result.hasCodexBinary).toBe(true);
|
|
110
|
-
expect(result.hasCodexAuth).toBe(false);
|
|
111
|
-
}
|
|
112
|
-
finally {
|
|
113
|
-
fs.rmSync(fakeBinDir, { recursive: true, force: true });
|
|
114
|
-
}
|
|
115
|
-
});
|
|
116
|
-
it("detects existing global and project config files independently", () => {
|
|
117
|
-
fs.mkdirSync(path.join(tmpHome, ".onto"), { recursive: true });
|
|
118
|
-
fs.writeFileSync(path.join(tmpHome, ".onto", "config.yml"), "output_language: ko\n");
|
|
119
|
-
fs.mkdirSync(path.join(tmpProject, ".onto"), { recursive: true });
|
|
120
|
-
fs.writeFileSync(path.join(tmpProject, ".onto", "config.yml"), "output_language: en\n");
|
|
121
|
-
const result = runPreflight(tmpProject);
|
|
122
|
-
expect(result.existingGlobalConfig).toBe(true);
|
|
123
|
-
expect(result.existingProjectConfig).toBe(true);
|
|
124
|
-
});
|
|
125
|
-
});
|
|
126
|
-
describe("path helpers", () => {
|
|
127
|
-
it("globalConfigPath points at ~/.onto/config.yml", () => {
|
|
128
|
-
expect(globalConfigPath()).toBe(path.join(os.homedir(), ".onto", "config.yml"));
|
|
129
|
-
});
|
|
130
|
-
it("projectConfigPath joins project root with .onto/config.yml", () => {
|
|
131
|
-
expect(projectConfigPath("/tmp/proj")).toBe("/tmp/proj/.onto/config.yml");
|
|
132
|
-
});
|
|
133
|
-
});
|
|
134
|
-
describe("formatPreflightSummary", () => {
|
|
135
|
-
it("uses ✓ for present signals and · for absent ones", () => {
|
|
136
|
-
const snapshot = {
|
|
137
|
-
existingGlobalConfig: true,
|
|
138
|
-
existingProjectConfig: false,
|
|
139
|
-
hasAnthropicKey: true,
|
|
140
|
-
hasOpenAiKey: false,
|
|
141
|
-
hasLitellmBaseUrl: true,
|
|
142
|
-
litellmBaseUrlValue: "http://localhost:4000/v1",
|
|
143
|
-
hasCodexBinary: false,
|
|
144
|
-
hasCodexAuth: false,
|
|
145
|
-
hostIsClaudeCode: true,
|
|
146
|
-
};
|
|
147
|
-
const out = formatPreflightSummary(snapshot);
|
|
148
|
-
expect(out).toContain("✓ global config");
|
|
149
|
-
expect(out).toContain("· project config");
|
|
150
|
-
expect(out).toContain("✓ ANTHROPIC_API_KEY");
|
|
151
|
-
expect(out).toContain("· OPENAI_API_KEY");
|
|
152
|
-
expect(out).toContain("http://localhost:4000/v1");
|
|
153
|
-
expect(out).toContain("✓ running inside Claude Code");
|
|
154
|
-
});
|
|
155
|
-
});
|
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* `.gitignore` updater for project-scope install.
|
|
3
|
-
*
|
|
4
|
-
* When the user picks project scope, the `.env` file lives under the
|
|
5
|
-
* repo at `<root>/.onto/.env` — secrets on a developer machine. The
|
|
6
|
-
* gitignore needs to exclude that path; otherwise a `git add` of
|
|
7
|
-
* anything under `.onto/` would stage credentials.
|
|
8
|
-
*
|
|
9
|
-
* Scope of this module:
|
|
10
|
-
*
|
|
11
|
-
* - **In**: append `.onto/.env` to the project `.gitignore` if the
|
|
12
|
-
* file exists and the entry is missing.
|
|
13
|
-
* - **In**: create a new `.gitignore` with a single entry if it
|
|
14
|
-
* doesn't exist yet.
|
|
15
|
-
* - **Out**: touching `.env.example`, `config.yml`, or any other
|
|
16
|
-
* tracked onto resource. Those are intentionally in git.
|
|
17
|
-
* - **Out**: global scope — `~/.onto/.env` doesn't live in any repo.
|
|
18
|
-
*
|
|
19
|
-
* # Why idempotent match-on-trimmed-line
|
|
20
|
-
*
|
|
21
|
-
* `.gitignore` tolerates variations: blank lines, inline comments,
|
|
22
|
-
* leading slash, trailing slash. We normalize each line for the
|
|
23
|
-
* membership test but append the canonical form if missing. This
|
|
24
|
-
* means re-running install never produces a duplicate entry.
|
|
25
|
-
*/
|
|
26
|
-
import fs from "node:fs";
|
|
27
|
-
const CANONICAL_ENTRY = ".onto/.env";
|
|
28
|
-
/**
|
|
29
|
-
* Line-level check: does `line` match our target entry, ignoring
|
|
30
|
-
* leading/trailing whitespace, a leading `/`, and any inline comment
|
|
31
|
-
* (gitignore doesn't support inline comments on entry lines, but we
|
|
32
|
-
* tolerate them defensively)?
|
|
33
|
-
*/
|
|
34
|
-
function lineMatches(line, target) {
|
|
35
|
-
const stripped = line.split("#")[0]?.trim() ?? "";
|
|
36
|
-
if (!stripped)
|
|
37
|
-
return false;
|
|
38
|
-
const normalized = stripped.replace(/^\//, "");
|
|
39
|
-
return normalized === target;
|
|
40
|
-
}
|
|
41
|
-
/**
|
|
42
|
-
* Ensure `.onto/.env` is listed in the given `.gitignore` file.
|
|
43
|
-
*
|
|
44
|
-
* Creates the file if absent. Appends the entry if the file exists
|
|
45
|
-
* but the entry isn't found. No-ops when the entry is already
|
|
46
|
-
* present (as `/X`, `X`, `X # comment`, etc.).
|
|
47
|
-
*
|
|
48
|
-
* Returns the resulting file content so the caller can log it in
|
|
49
|
-
* dry-run mode or include it in the completion summary.
|
|
50
|
-
*/
|
|
51
|
-
export function ensureGitignoreEntry(gitignorePath, options = {}) {
|
|
52
|
-
const { dryRun = false } = options;
|
|
53
|
-
if (!fs.existsSync(gitignorePath)) {
|
|
54
|
-
const content = `${CANONICAL_ENTRY}\n`;
|
|
55
|
-
if (!dryRun) {
|
|
56
|
-
fs.writeFileSync(gitignorePath, content, "utf8");
|
|
57
|
-
}
|
|
58
|
-
return { alreadyPresent: false, created: true, content };
|
|
59
|
-
}
|
|
60
|
-
const original = fs.readFileSync(gitignorePath, "utf8");
|
|
61
|
-
const lines = original.split(/\r?\n/);
|
|
62
|
-
const already = lines.some((line) => lineMatches(line, CANONICAL_ENTRY));
|
|
63
|
-
if (already) {
|
|
64
|
-
return { alreadyPresent: true, created: false, content: original };
|
|
65
|
-
}
|
|
66
|
-
// Append — preserve trailing newline convention.
|
|
67
|
-
const trailingNewline = original.endsWith("\n");
|
|
68
|
-
const prefix = trailingNewline ? original : `${original}\n`;
|
|
69
|
-
const content = `${prefix}${CANONICAL_ENTRY}\n`;
|
|
70
|
-
if (!dryRun) {
|
|
71
|
-
fs.writeFileSync(gitignorePath, content, "utf8");
|
|
72
|
-
}
|
|
73
|
-
return { alreadyPresent: false, created: false, content };
|
|
74
|
-
}
|
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, beforeEach, afterEach } from "vitest";
|
|
2
|
-
import fs from "node:fs";
|
|
3
|
-
import os from "node:os";
|
|
4
|
-
import path from "node:path";
|
|
5
|
-
import { ensureGitignoreEntry } from "./gitignore-update.js";
|
|
6
|
-
describe("ensureGitignoreEntry", () => {
|
|
7
|
-
let tmpDir;
|
|
8
|
-
beforeEach(() => {
|
|
9
|
-
tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "onto-install-git-"));
|
|
10
|
-
});
|
|
11
|
-
afterEach(() => {
|
|
12
|
-
fs.rmSync(tmpDir, { recursive: true, force: true });
|
|
13
|
-
});
|
|
14
|
-
it("creates a new .gitignore with the entry when file absent", () => {
|
|
15
|
-
const gi = path.join(tmpDir, ".gitignore");
|
|
16
|
-
const result = ensureGitignoreEntry(gi);
|
|
17
|
-
expect(result.created).toBe(true);
|
|
18
|
-
expect(result.alreadyPresent).toBe(false);
|
|
19
|
-
expect(fs.readFileSync(gi, "utf8")).toBe(".onto/.env\n");
|
|
20
|
-
});
|
|
21
|
-
it("appends the entry to an existing .gitignore without duplication", () => {
|
|
22
|
-
const gi = path.join(tmpDir, ".gitignore");
|
|
23
|
-
fs.writeFileSync(gi, "node_modules/\ndist/\n");
|
|
24
|
-
const result = ensureGitignoreEntry(gi);
|
|
25
|
-
expect(result.created).toBe(false);
|
|
26
|
-
expect(result.alreadyPresent).toBe(false);
|
|
27
|
-
const content = fs.readFileSync(gi, "utf8");
|
|
28
|
-
expect(content).toContain("node_modules/");
|
|
29
|
-
expect(content.trim().endsWith(".onto/.env")).toBe(true);
|
|
30
|
-
});
|
|
31
|
-
it("is a no-op when the entry is already present", () => {
|
|
32
|
-
const gi = path.join(tmpDir, ".gitignore");
|
|
33
|
-
const original = "dist/\n.onto/.env\nnode_modules/\n";
|
|
34
|
-
fs.writeFileSync(gi, original);
|
|
35
|
-
const result = ensureGitignoreEntry(gi);
|
|
36
|
-
expect(result.alreadyPresent).toBe(true);
|
|
37
|
-
expect(fs.readFileSync(gi, "utf8")).toBe(original);
|
|
38
|
-
});
|
|
39
|
-
it("recognizes leading slash variants", () => {
|
|
40
|
-
const gi = path.join(tmpDir, ".gitignore");
|
|
41
|
-
fs.writeFileSync(gi, "/.onto/.env\n");
|
|
42
|
-
const result = ensureGitignoreEntry(gi);
|
|
43
|
-
expect(result.alreadyPresent).toBe(true);
|
|
44
|
-
});
|
|
45
|
-
it("ignores inline comments on the entry line", () => {
|
|
46
|
-
const gi = path.join(tmpDir, ".gitignore");
|
|
47
|
-
fs.writeFileSync(gi, ".onto/.env # secrets\n");
|
|
48
|
-
const result = ensureGitignoreEntry(gi);
|
|
49
|
-
expect(result.alreadyPresent).toBe(true);
|
|
50
|
-
});
|
|
51
|
-
it("adds a trailing newline when the existing file has none", () => {
|
|
52
|
-
const gi = path.join(tmpDir, ".gitignore");
|
|
53
|
-
fs.writeFileSync(gi, "dist/");
|
|
54
|
-
const result = ensureGitignoreEntry(gi);
|
|
55
|
-
expect(result.alreadyPresent).toBe(false);
|
|
56
|
-
expect(fs.readFileSync(gi, "utf8")).toBe("dist/\n.onto/.env\n");
|
|
57
|
-
});
|
|
58
|
-
it("dry-run returns expected content without writing", () => {
|
|
59
|
-
const gi = path.join(tmpDir, ".gitignore");
|
|
60
|
-
const result = ensureGitignoreEntry(gi, { dryRun: true });
|
|
61
|
-
expect(result.content).toBe(".onto/.env\n");
|
|
62
|
-
expect(fs.existsSync(gi)).toBe(false);
|
|
63
|
-
});
|
|
64
|
-
});
|
|
@@ -1,373 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Integration-level tests for `onto install`.
|
|
3
|
-
*
|
|
4
|
-
* These drive `handleInstallCliWithOverrides()` with real argv,
|
|
5
|
-
* scoped to a tmp HOME + tmp project root, and exercise the full
|
|
6
|
-
* non-interactive orchestration end-to-end (flag parsing → preflight
|
|
7
|
-
* → decision resolution → write → validate → completion). Network
|
|
8
|
-
* calls go through a stub `fetch` passed via the overrides struct.
|
|
9
|
-
*
|
|
10
|
-
* The goal is to cover PR 4's promised scenario matrix:
|
|
11
|
-
* - global-anthropic happy path
|
|
12
|
-
* - project-main-native (with a learn provider required by design)
|
|
13
|
-
* - reconfigure guard + --reconfigure bypass
|
|
14
|
-
* - dry-run
|
|
15
|
-
* - validation failure
|
|
16
|
-
* - env-file loading
|
|
17
|
-
* - ONTO_INSTALL_* env fallback
|
|
18
|
-
*
|
|
19
|
-
* Interactive path unit coverage lives in `prompts.test.ts`; this
|
|
20
|
-
* file intentionally skips re-covering prompts.
|
|
21
|
-
*/
|
|
22
|
-
import { describe, it, expect, beforeEach, afterEach } from "vitest";
|
|
23
|
-
import fs from "node:fs";
|
|
24
|
-
import os from "node:os";
|
|
25
|
-
import path from "node:path";
|
|
26
|
-
import yaml from "yaml";
|
|
27
|
-
import { handleInstallCliWithOverrides } from "./cli.js";
|
|
28
|
-
const MANAGED_ENV = [
|
|
29
|
-
"ANTHROPIC_API_KEY",
|
|
30
|
-
"OPENAI_API_KEY",
|
|
31
|
-
"LITELLM_BASE_URL",
|
|
32
|
-
"LITELLM_API_KEY",
|
|
33
|
-
"ONTO_INSTALL_NON_INTERACTIVE",
|
|
34
|
-
"ONTO_INSTALL_PROFILE_SCOPE",
|
|
35
|
-
"ONTO_INSTALL_REVIEW_PROVIDER",
|
|
36
|
-
"ONTO_INSTALL_LEARN_PROVIDER",
|
|
37
|
-
"ONTO_INSTALL_OUTPUT_LANGUAGE",
|
|
38
|
-
"ONTO_INSTALL_LITELLM_BASE_URL",
|
|
39
|
-
"ONTO_INSTALL_ENV_FILE",
|
|
40
|
-
"ONTO_INSTALL_RECONFIGURE",
|
|
41
|
-
"ONTO_INSTALL_SKIP_VALIDATION",
|
|
42
|
-
"ONTO_INSTALL_DRY_RUN",
|
|
43
|
-
"CLAUDECODE",
|
|
44
|
-
"CLAUDE_PROJECT_DIR",
|
|
45
|
-
"CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS",
|
|
46
|
-
];
|
|
47
|
-
let savedEnv;
|
|
48
|
-
function saveAndClearEnv() {
|
|
49
|
-
savedEnv = {};
|
|
50
|
-
for (const key of MANAGED_ENV) {
|
|
51
|
-
savedEnv[key] = process.env[key];
|
|
52
|
-
delete process.env[key];
|
|
53
|
-
}
|
|
54
|
-
savedEnv.PATH = process.env.PATH;
|
|
55
|
-
process.env.PATH = "";
|
|
56
|
-
savedEnv.HOME = process.env.HOME;
|
|
57
|
-
}
|
|
58
|
-
function restoreEnv() {
|
|
59
|
-
for (const [key, value] of Object.entries(savedEnv)) {
|
|
60
|
-
if (value === undefined)
|
|
61
|
-
delete process.env[key];
|
|
62
|
-
else
|
|
63
|
-
process.env[key] = value;
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
function stubFetchReturning(status) {
|
|
67
|
-
return (async () => new Response("{}", { status }));
|
|
68
|
-
}
|
|
69
|
-
describe("handleInstallCliWithOverrides — non-interactive E2E", () => {
|
|
70
|
-
let tmpHome;
|
|
71
|
-
let tmpProject;
|
|
72
|
-
let stdout;
|
|
73
|
-
let stderr;
|
|
74
|
-
beforeEach(() => {
|
|
75
|
-
saveAndClearEnv();
|
|
76
|
-
tmpHome = fs.mkdtempSync(path.join(os.tmpdir(), "onto-install-e2e-home-"));
|
|
77
|
-
tmpProject = fs.mkdtempSync(path.join(os.tmpdir(), "onto-install-e2e-proj-"));
|
|
78
|
-
process.env.HOME = tmpHome;
|
|
79
|
-
stdout = [];
|
|
80
|
-
stderr = [];
|
|
81
|
-
});
|
|
82
|
-
afterEach(() => {
|
|
83
|
-
fs.rmSync(tmpHome, { recursive: true, force: true });
|
|
84
|
-
fs.rmSync(tmpProject, { recursive: true, force: true });
|
|
85
|
-
restoreEnv();
|
|
86
|
-
});
|
|
87
|
-
function runInstall(argv, extras = {}) {
|
|
88
|
-
for (const [k, v] of Object.entries(extras.envOverrides ?? {})) {
|
|
89
|
-
process.env[k] = v;
|
|
90
|
-
}
|
|
91
|
-
return handleInstallCliWithOverrides("/unused", argv, {
|
|
92
|
-
homeDir: tmpHome,
|
|
93
|
-
projectRoot: tmpProject,
|
|
94
|
-
...(extras.fetch ? { fetch: extras.fetch } : {}),
|
|
95
|
-
write: (t) => stdout.push(t),
|
|
96
|
-
writeErr: (t) => stderr.push(t),
|
|
97
|
-
});
|
|
98
|
-
}
|
|
99
|
-
// -------------------------------------------------------------------
|
|
100
|
-
// Happy paths
|
|
101
|
-
// -------------------------------------------------------------------
|
|
102
|
-
it("global-anthropic writes config.yml + .env at ~/.onto/ and passes validation", async () => {
|
|
103
|
-
const exit = await runInstall([
|
|
104
|
-
"--non-interactive",
|
|
105
|
-
"--profile-scope",
|
|
106
|
-
"global",
|
|
107
|
-
"--review-provider",
|
|
108
|
-
"anthropic",
|
|
109
|
-
"--learn-provider",
|
|
110
|
-
"same",
|
|
111
|
-
], {
|
|
112
|
-
fetch: stubFetchReturning(200),
|
|
113
|
-
envOverrides: { ANTHROPIC_API_KEY: "sk-ant-xyz" },
|
|
114
|
-
});
|
|
115
|
-
expect(exit).toBe(0);
|
|
116
|
-
const configYmlPath = path.join(tmpHome, ".onto", "config.yml");
|
|
117
|
-
expect(fs.existsSync(configYmlPath)).toBe(true);
|
|
118
|
-
const config = yaml.parse(fs.readFileSync(configYmlPath, "utf8").replace(/^#[^\n]*\n/g, ""));
|
|
119
|
-
expect(config.output_language).toBe("ko");
|
|
120
|
-
expect(config.review.subagent.provider).toBe("anthropic");
|
|
121
|
-
expect(config.subagent_llm.provider).toBe("anthropic");
|
|
122
|
-
expect(config.external_http_provider).toBe("anthropic");
|
|
123
|
-
const envPath = path.join(tmpHome, ".onto", ".env");
|
|
124
|
-
const envText = fs.readFileSync(envPath, "utf8");
|
|
125
|
-
expect(envText).toContain("ANTHROPIC_API_KEY=sk-ant-xyz");
|
|
126
|
-
const mode = fs.statSync(envPath).mode & 0o777;
|
|
127
|
-
if (process.platform !== "win32")
|
|
128
|
-
expect(mode).toBe(0o600);
|
|
129
|
-
});
|
|
130
|
-
it("project scope adds .onto/.env to .gitignore", async () => {
|
|
131
|
-
await runInstall([
|
|
132
|
-
"--non-interactive",
|
|
133
|
-
"--profile-scope",
|
|
134
|
-
"project",
|
|
135
|
-
"--review-provider",
|
|
136
|
-
"anthropic",
|
|
137
|
-
"--learn-provider",
|
|
138
|
-
"same",
|
|
139
|
-
"--skip-validation",
|
|
140
|
-
], { envOverrides: { ANTHROPIC_API_KEY: "sk-ant-xyz" } });
|
|
141
|
-
const giPath = path.join(tmpProject, ".gitignore");
|
|
142
|
-
expect(fs.existsSync(giPath)).toBe(true);
|
|
143
|
-
expect(fs.readFileSync(giPath, "utf8")).toContain(".onto/.env");
|
|
144
|
-
});
|
|
145
|
-
it("main-native review + separate learn provider succeeds with Claude Code host", async () => {
|
|
146
|
-
const exit = await runInstall([
|
|
147
|
-
"--non-interactive",
|
|
148
|
-
"--profile-scope",
|
|
149
|
-
"global",
|
|
150
|
-
"--review-provider",
|
|
151
|
-
"main-native",
|
|
152
|
-
"--learn-provider",
|
|
153
|
-
"anthropic",
|
|
154
|
-
], {
|
|
155
|
-
fetch: stubFetchReturning(200),
|
|
156
|
-
envOverrides: { ANTHROPIC_API_KEY: "sk-ant-xyz", CLAUDECODE: "1" },
|
|
157
|
-
});
|
|
158
|
-
expect(exit).toBe(0);
|
|
159
|
-
const config = yaml.parse(fs
|
|
160
|
-
.readFileSync(path.join(tmpHome, ".onto", "config.yml"), "utf8")
|
|
161
|
-
.replace(/^#[^\n]*\n/g, ""));
|
|
162
|
-
expect(config.review.subagent.provider).toBe("main-native");
|
|
163
|
-
expect(config.subagent_llm.provider).toBe("anthropic");
|
|
164
|
-
});
|
|
165
|
-
// -------------------------------------------------------------------
|
|
166
|
-
// Flag validation
|
|
167
|
-
// -------------------------------------------------------------------
|
|
168
|
-
it("errors when required flags are missing in non-interactive mode", async () => {
|
|
169
|
-
const exit = await runInstall([
|
|
170
|
-
"--non-interactive",
|
|
171
|
-
"--review-provider",
|
|
172
|
-
"anthropic",
|
|
173
|
-
// missing --profile-scope
|
|
174
|
-
]);
|
|
175
|
-
expect(exit).toBe(1);
|
|
176
|
-
expect(stderr.join("")).toContain("--profile-scope");
|
|
177
|
-
});
|
|
178
|
-
it("errors when review=main-native but no explicit --learn-provider", async () => {
|
|
179
|
-
const exit = await runInstall([
|
|
180
|
-
"--non-interactive",
|
|
181
|
-
"--profile-scope",
|
|
182
|
-
"global",
|
|
183
|
-
"--review-provider",
|
|
184
|
-
"main-native",
|
|
185
|
-
// learn-provider defaults to 'same' which can't be main-native
|
|
186
|
-
]);
|
|
187
|
-
expect(exit).toBe(1);
|
|
188
|
-
expect(stderr.join("")).toContain("main-native");
|
|
189
|
-
});
|
|
190
|
-
it("errors when credentials are missing", async () => {
|
|
191
|
-
const exit = await runInstall([
|
|
192
|
-
"--non-interactive",
|
|
193
|
-
"--profile-scope",
|
|
194
|
-
"global",
|
|
195
|
-
"--review-provider",
|
|
196
|
-
"anthropic",
|
|
197
|
-
"--learn-provider",
|
|
198
|
-
"same",
|
|
199
|
-
"--skip-validation",
|
|
200
|
-
]);
|
|
201
|
-
expect(exit).toBe(1);
|
|
202
|
-
expect(stderr.join("")).toContain("ANTHROPIC_API_KEY");
|
|
203
|
-
});
|
|
204
|
-
// -------------------------------------------------------------------
|
|
205
|
-
// Reconfigure guard
|
|
206
|
-
// -------------------------------------------------------------------
|
|
207
|
-
it("halts when existing config present and --reconfigure absent", async () => {
|
|
208
|
-
fs.mkdirSync(path.join(tmpHome, ".onto"), { recursive: true });
|
|
209
|
-
fs.writeFileSync(path.join(tmpHome, ".onto", "config.yml"), "output_language: en\n");
|
|
210
|
-
const exit = await runInstall([
|
|
211
|
-
"--non-interactive",
|
|
212
|
-
"--profile-scope",
|
|
213
|
-
"global",
|
|
214
|
-
"--review-provider",
|
|
215
|
-
"anthropic",
|
|
216
|
-
"--learn-provider",
|
|
217
|
-
"same",
|
|
218
|
-
]);
|
|
219
|
-
expect(exit).toBe(1);
|
|
220
|
-
expect(stderr.join("")).toContain("기존 config");
|
|
221
|
-
});
|
|
222
|
-
it("proceeds when --reconfigure is set", async () => {
|
|
223
|
-
fs.mkdirSync(path.join(tmpHome, ".onto"), { recursive: true });
|
|
224
|
-
fs.writeFileSync(path.join(tmpHome, ".onto", "config.yml"), "output_language: en\n");
|
|
225
|
-
const exit = await runInstall([
|
|
226
|
-
"--non-interactive",
|
|
227
|
-
"--profile-scope",
|
|
228
|
-
"global",
|
|
229
|
-
"--review-provider",
|
|
230
|
-
"anthropic",
|
|
231
|
-
"--learn-provider",
|
|
232
|
-
"same",
|
|
233
|
-
"--reconfigure",
|
|
234
|
-
"--skip-validation",
|
|
235
|
-
], { envOverrides: { ANTHROPIC_API_KEY: "sk-ant-xyz" } });
|
|
236
|
-
expect(exit).toBe(0);
|
|
237
|
-
const content = fs.readFileSync(path.join(tmpHome, ".onto", "config.yml"), "utf8");
|
|
238
|
-
expect(content).toContain("output_language: ko");
|
|
239
|
-
});
|
|
240
|
-
// -------------------------------------------------------------------
|
|
241
|
-
// Dry-run
|
|
242
|
-
// -------------------------------------------------------------------
|
|
243
|
-
it("--dry-run leaves no files on disk", async () => {
|
|
244
|
-
const exit = await runInstall([
|
|
245
|
-
"--non-interactive",
|
|
246
|
-
"--profile-scope",
|
|
247
|
-
"global",
|
|
248
|
-
"--review-provider",
|
|
249
|
-
"anthropic",
|
|
250
|
-
"--learn-provider",
|
|
251
|
-
"same",
|
|
252
|
-
"--dry-run",
|
|
253
|
-
], { envOverrides: { ANTHROPIC_API_KEY: "sk-ant-xyz" } });
|
|
254
|
-
expect(exit).toBe(0);
|
|
255
|
-
expect(fs.existsSync(path.join(tmpHome, ".onto", "config.yml"))).toBe(false);
|
|
256
|
-
expect(stdout.join("")).toContain("미리보기");
|
|
257
|
-
});
|
|
258
|
-
// -------------------------------------------------------------------
|
|
259
|
-
// Validation
|
|
260
|
-
// -------------------------------------------------------------------
|
|
261
|
-
it("exits 1 when live validation fails", async () => {
|
|
262
|
-
const exit = await runInstall([
|
|
263
|
-
"--non-interactive",
|
|
264
|
-
"--profile-scope",
|
|
265
|
-
"global",
|
|
266
|
-
"--review-provider",
|
|
267
|
-
"anthropic",
|
|
268
|
-
"--learn-provider",
|
|
269
|
-
"same",
|
|
270
|
-
], {
|
|
271
|
-
fetch: stubFetchReturning(401),
|
|
272
|
-
envOverrides: { ANTHROPIC_API_KEY: "sk-bad" },
|
|
273
|
-
});
|
|
274
|
-
expect(exit).toBe(1);
|
|
275
|
-
expect(stderr.join("")).toContain("provider 검증 실패");
|
|
276
|
-
});
|
|
277
|
-
it("--skip-validation bypasses the ping", async () => {
|
|
278
|
-
const exit = await runInstall([
|
|
279
|
-
"--non-interactive",
|
|
280
|
-
"--profile-scope",
|
|
281
|
-
"global",
|
|
282
|
-
"--review-provider",
|
|
283
|
-
"anthropic",
|
|
284
|
-
"--learn-provider",
|
|
285
|
-
"same",
|
|
286
|
-
"--skip-validation",
|
|
287
|
-
], { envOverrides: { ANTHROPIC_API_KEY: "sk-bad" } });
|
|
288
|
-
expect(exit).toBe(0);
|
|
289
|
-
});
|
|
290
|
-
// -------------------------------------------------------------------
|
|
291
|
-
// env-file loading
|
|
292
|
-
// -------------------------------------------------------------------
|
|
293
|
-
it("--env-file loads credentials from the specified file", async () => {
|
|
294
|
-
const envFilePath = path.join(tmpProject, "custom.env");
|
|
295
|
-
fs.writeFileSync(envFilePath, "ANTHROPIC_API_KEY=sk-from-file\n");
|
|
296
|
-
const exit = await runInstall([
|
|
297
|
-
"--non-interactive",
|
|
298
|
-
"--profile-scope",
|
|
299
|
-
"global",
|
|
300
|
-
"--review-provider",
|
|
301
|
-
"anthropic",
|
|
302
|
-
"--learn-provider",
|
|
303
|
-
"same",
|
|
304
|
-
"--env-file",
|
|
305
|
-
envFilePath,
|
|
306
|
-
"--skip-validation",
|
|
307
|
-
]);
|
|
308
|
-
expect(exit).toBe(0);
|
|
309
|
-
const envText = fs.readFileSync(path.join(tmpHome, ".onto", ".env"), "utf8");
|
|
310
|
-
expect(envText).toContain("ANTHROPIC_API_KEY=sk-from-file");
|
|
311
|
-
});
|
|
312
|
-
it("--env-file errors when path does not exist", async () => {
|
|
313
|
-
const exit = await runInstall([
|
|
314
|
-
"--non-interactive",
|
|
315
|
-
"--env-file",
|
|
316
|
-
"/no/such/file",
|
|
317
|
-
]);
|
|
318
|
-
expect(exit).toBe(1);
|
|
319
|
-
expect(stderr.join("")).toContain("--env-file");
|
|
320
|
-
});
|
|
321
|
-
// -------------------------------------------------------------------
|
|
322
|
-
// ONTO_INSTALL_* env fallback
|
|
323
|
-
// -------------------------------------------------------------------
|
|
324
|
-
it("reads ONTO_INSTALL_* env vars as flag defaults", async () => {
|
|
325
|
-
const exit = await runInstall(["--skip-validation"], {
|
|
326
|
-
envOverrides: {
|
|
327
|
-
ONTO_INSTALL_NON_INTERACTIVE: "1",
|
|
328
|
-
ONTO_INSTALL_PROFILE_SCOPE: "global",
|
|
329
|
-
ONTO_INSTALL_REVIEW_PROVIDER: "anthropic",
|
|
330
|
-
ONTO_INSTALL_LEARN_PROVIDER: "same",
|
|
331
|
-
ONTO_INSTALL_OUTPUT_LANGUAGE: "en",
|
|
332
|
-
ANTHROPIC_API_KEY: "sk-ant-xyz",
|
|
333
|
-
},
|
|
334
|
-
});
|
|
335
|
-
expect(exit).toBe(0);
|
|
336
|
-
const config = yaml.parse(fs
|
|
337
|
-
.readFileSync(path.join(tmpHome, ".onto", "config.yml"), "utf8")
|
|
338
|
-
.replace(/^#[^\n]*\n/g, ""));
|
|
339
|
-
expect(config.output_language).toBe("en");
|
|
340
|
-
});
|
|
341
|
-
it("argv flag wins over ONTO_INSTALL_* env", async () => {
|
|
342
|
-
await runInstall([
|
|
343
|
-
"--non-interactive",
|
|
344
|
-
"--profile-scope",
|
|
345
|
-
"global",
|
|
346
|
-
"--review-provider",
|
|
347
|
-
"anthropic",
|
|
348
|
-
"--learn-provider",
|
|
349
|
-
"same",
|
|
350
|
-
"--output-language",
|
|
351
|
-
"ko",
|
|
352
|
-
"--skip-validation",
|
|
353
|
-
], {
|
|
354
|
-
envOverrides: {
|
|
355
|
-
ONTO_INSTALL_OUTPUT_LANGUAGE: "en",
|
|
356
|
-
ANTHROPIC_API_KEY: "sk-ant-xyz",
|
|
357
|
-
},
|
|
358
|
-
});
|
|
359
|
-
const config = yaml.parse(fs
|
|
360
|
-
.readFileSync(path.join(tmpHome, ".onto", "config.yml"), "utf8")
|
|
361
|
-
.replace(/^#[^\n]*\n/g, ""));
|
|
362
|
-
expect(config.output_language).toBe("ko");
|
|
363
|
-
});
|
|
364
|
-
// -------------------------------------------------------------------
|
|
365
|
-
// --help
|
|
366
|
-
// -------------------------------------------------------------------
|
|
367
|
-
it("--help prints usage and returns 0 without touching disk", async () => {
|
|
368
|
-
const exit = await runInstall(["--help"]);
|
|
369
|
-
expect(exit).toBe(0);
|
|
370
|
-
expect(stdout.join("")).toContain("Usage: onto install");
|
|
371
|
-
expect(fs.existsSync(path.join(tmpHome, ".onto"))).toBe(false);
|
|
372
|
-
});
|
|
373
|
-
});
|