opensquid 0.5.441 → 0.5.449
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/README.md +1 -0
- package/dist/functions/arm_scope.d.ts +27 -0
- package/dist/functions/arm_scope.d.ts.map +1 -0
- package/dist/functions/arm_scope.js +52 -0
- package/dist/functions/arm_scope.js.map +1 -0
- package/dist/functions/index.d.ts +1 -0
- package/dist/functions/index.d.ts.map +1 -1
- package/dist/functions/index.js +1 -0
- package/dist/functions/index.js.map +1 -1
- package/dist/functions/recall_pre_inject.d.ts.map +1 -1
- package/dist/functions/recall_pre_inject.js +12 -0
- package/dist/functions/recall_pre_inject.js.map +1 -1
- package/dist/rag/store_git.d.ts +23 -0
- package/dist/rag/store_git.d.ts.map +1 -0
- package/dist/rag/store_git.js +57 -0
- package/dist/rag/store_git.js.map +1 -0
- package/dist/runtime/bootstrap.d.ts.map +1 -1
- package/dist/runtime/bootstrap.js +2 -0
- package/dist/runtime/bootstrap.js.map +1 -1
- package/dist/runtime/handoff/render.d.ts +5 -4
- package/dist/runtime/handoff/render.d.ts.map +1 -1
- package/dist/runtime/handoff/render.js +7 -7
- package/dist/runtime/handoff/render.js.map +1 -1
- package/dist/runtime/hooks/active_task_mirror.js +0 -0
- package/dist/runtime/hooks/apply_patch.js +0 -0
- package/dist/runtime/hooks/dispatch.js +0 -0
- package/dist/runtime/hooks/hook_output.js +0 -0
- package/dist/runtime/hooks/memory_reconcile.js +0 -0
- package/dist/runtime/hooks/new_project_detect.js +0 -0
- package/dist/runtime/hooks/profession_resolver.js +0 -0
- package/dist/runtime/hooks/scope_intent.js +0 -0
- package/dist/runtime/hooks/session-end.js +11 -0
- package/dist/runtime/hooks/session-end.js.map +1 -1
- package/dist/runtime/hooks/session_id.js +0 -0
- package/dist/runtime/hooks/session_liveness.js +0 -0
- package/dist/runtime/hooks/stop_drive.js +0 -0
- package/dist/runtime/hooks/stop_stream.js +0 -0
- package/dist/runtime/hooks/subagent_guard.js +0 -0
- package/dist/runtime/hooks/transcript.js +0 -0
- package/dist/runtime/hooks/transcript_tasks.js +0 -0
- package/dist/runtime/ralph/orchestrator.d.ts.map +1 -1
- package/dist/runtime/ralph/orchestrator.js +2 -1
- package/dist/runtime/ralph/orchestrator.js.map +1 -1
- package/dist/setup/cli/limits_state.d.ts.map +1 -1
- package/dist/setup/cli/limits_state.js +6 -40
- package/dist/setup/cli/limits_state.js.map +1 -1
- package/dist/setup/cli/pack_walk.d.ts +32 -0
- package/dist/setup/cli/pack_walk.d.ts.map +1 -0
- package/dist/setup/cli/pack_walk.js +76 -0
- package/dist/setup/cli/pack_walk.js.map +1 -0
- package/dist/setup/cli/permissions_state.d.ts.map +1 -1
- package/dist/setup/cli/permissions_state.js +6 -37
- package/dist/setup/cli/permissions_state.js.map +1 -1
- package/dist/setup/cli/triggers_state.d.ts.map +1 -1
- package/dist/setup/cli/triggers_state.js +3 -29
- package/dist/setup/cli/triggers_state.js.map +1 -1
- package/dist/workgraph/events.d.ts.map +1 -1
- package/dist/workgraph/events.js +10 -0
- package/dist/workgraph/events.js.map +1 -1
- package/dist/workgraph/store.d.ts.map +1 -1
- package/dist/workgraph/store.js +5 -0
- package/dist/workgraph/store.js.map +1 -1
- package/dist/workgraph/types.d.ts +2 -1
- package/dist/workgraph/types.d.ts.map +1 -1
- package/docs/ARCHITECTURE.md +268 -0
- package/docs/pack-runtime.md +15 -12
- package/docs/skill-grammar-guide.md +4 -4
- package/package.json +5 -3
- package/packs/builtin/coding-flow/skills/entry-and-handoffs/skill.yaml +13 -17
- package/dist/anti-drift/evaluator.d.ts +0 -88
- package/dist/anti-drift/evaluator.d.ts.map +0 -1
- package/dist/anti-drift/evaluator.js +0 -417
- package/dist/anti-drift/evaluator.js.map +0 -1
- package/dist/anti-drift/evaluator.test.js +0 -78
- package/dist/anti-drift/rules.d.ts +0 -80
- package/dist/anti-drift/rules.d.ts.map +0 -1
- package/dist/anti-drift/rules.js +0 -368
- package/dist/anti-drift/rules.js.map +0 -1
- package/dist/anti-drift/rules.test.js +0 -213
- package/dist/anti-drift/state.d.ts +0 -107
- package/dist/anti-drift/state.d.ts.map +0 -1
- package/dist/anti-drift/state.js +0 -177
- package/dist/anti-drift/state.js.map +0 -1
- package/dist/anti-drift/state.test.js +0 -120
- package/dist/chat/adapters/discord.d.ts +0 -41
- package/dist/chat/adapters/discord.d.ts.map +0 -1
- package/dist/chat/adapters/discord.js +0 -176
- package/dist/chat/adapters/discord.js.map +0 -1
- package/dist/chat/adapters/discord.test.js +0 -25
- package/dist/chat/adapters/slack.d.ts +0 -43
- package/dist/chat/adapters/slack.d.ts.map +0 -1
- package/dist/chat/adapters/slack.js +0 -172
- package/dist/chat/adapters/slack.js.map +0 -1
- package/dist/chat/adapters/slack.test.js +0 -30
- package/dist/chat/adapters/telegram.d.ts +0 -148
- package/dist/chat/adapters/telegram.d.ts.map +0 -1
- package/dist/chat/adapters/telegram.js +0 -498
- package/dist/chat/adapters/telegram.js.map +0 -1
- package/dist/chat/adapters/telegram.test.js +0 -94
- package/dist/chat/config.d.ts +0 -98
- package/dist/chat/config.d.ts.map +0 -1
- package/dist/chat/config.js +0 -185
- package/dist/chat/config.js.map +0 -1
- package/dist/chat/daemon/active-project.d.ts +0 -17
- package/dist/chat/daemon/active-project.d.ts.map +0 -1
- package/dist/chat/daemon/active-project.js +0 -23
- package/dist/chat/daemon/active-project.js.map +0 -1
- package/dist/chat/daemon/autospawn.d.ts +0 -40
- package/dist/chat/daemon/autospawn.d.ts.map +0 -1
- package/dist/chat/daemon/autospawn.js +0 -129
- package/dist/chat/daemon/autospawn.js.map +0 -1
- package/dist/chat/daemon/autospawn.test.js +0 -112
- package/dist/chat/daemon/cli.d.ts +0 -18
- package/dist/chat/daemon/cli.d.ts.map +0 -1
- package/dist/chat/daemon/cli.js +0 -71
- package/dist/chat/daemon/cli.js.map +0 -1
- package/dist/chat/daemon/collisions.js +0 -384
- package/dist/chat/daemon/health-check.d.ts +0 -69
- package/dist/chat/daemon/health-check.d.ts.map +0 -1
- package/dist/chat/daemon/health-check.js +0 -112
- package/dist/chat/daemon/health-check.js.map +0 -1
- package/dist/chat/daemon/inbox-read.d.ts +0 -35
- package/dist/chat/daemon/inbox-read.d.ts.map +0 -1
- package/dist/chat/daemon/inbox-read.js +0 -75
- package/dist/chat/daemon/inbox-read.js.map +0 -1
- package/dist/chat/daemon/inbox-read.test.js +0 -97
- package/dist/chat/daemon/inbox.d.ts +0 -63
- package/dist/chat/daemon/inbox.d.ts.map +0 -1
- package/dist/chat/daemon/inbox.js +0 -56
- package/dist/chat/daemon/inbox.js.map +0 -1
- package/dist/chat/daemon/inbox.test.js +0 -110
- package/dist/chat/daemon/lifecycle.d.ts +0 -71
- package/dist/chat/daemon/lifecycle.d.ts.map +0 -1
- package/dist/chat/daemon/lifecycle.js +0 -221
- package/dist/chat/daemon/lifecycle.js.map +0 -1
- package/dist/chat/daemon/lifecycle.test.js +0 -163
- package/dist/chat/daemon/protocol.d.ts +0 -107
- package/dist/chat/daemon/protocol.d.ts.map +0 -1
- package/dist/chat/daemon/protocol.js +0 -54
- package/dist/chat/daemon/protocol.js.map +0 -1
- package/dist/chat/daemon/routing.d.ts +0 -140
- package/dist/chat/daemon/routing.d.ts.map +0 -1
- package/dist/chat/daemon/routing.js +0 -198
- package/dist/chat/daemon/routing.js.map +0 -1
- package/dist/chat/daemon/routing.test.js +0 -259
- package/dist/chat/daemon/rpc-client.d.ts +0 -45
- package/dist/chat/daemon/rpc-client.d.ts.map +0 -1
- package/dist/chat/daemon/rpc-client.js +0 -133
- package/dist/chat/daemon/rpc-client.js.map +0 -1
- package/dist/chat/daemon/rpc-server.d.ts +0 -39
- package/dist/chat/daemon/rpc-server.d.ts.map +0 -1
- package/dist/chat/daemon/rpc-server.js +0 -385
- package/dist/chat/daemon/rpc-server.js.map +0 -1
- package/dist/chat/daemon/rpc.test.js +0 -177
- package/dist/chat/daemon/subscribers.js +0 -257
- package/dist/chat/daemon/worker.d.ts +0 -27
- package/dist/chat/daemon/worker.d.ts.map +0 -1
- package/dist/chat/daemon/worker.js +0 -313
- package/dist/chat/daemon/worker.js.map +0 -1
- package/dist/chat/daemon/workspace-topic.js +0 -324
- package/dist/chat/env-token.d.ts +0 -60
- package/dist/chat/env-token.d.ts.map +0 -1
- package/dist/chat/env-token.js +0 -137
- package/dist/chat/env-token.js.map +0 -1
- package/dist/chat/env-token.test.js +0 -160
- package/dist/chat/factory.d.ts +0 -30
- package/dist/chat/factory.d.ts.map +0 -1
- package/dist/chat/factory.js +0 -50
- package/dist/chat/factory.js.map +0 -1
- package/dist/chat/factory.test.js +0 -55
- package/dist/chat/gateway.d.ts +0 -176
- package/dist/chat/gateway.d.ts.map +0 -1
- package/dist/chat/gateway.js +0 -146
- package/dist/chat/gateway.js.map +0 -1
- package/dist/chat/gateway.test.js +0 -192
- package/dist/claude-md.d.ts +0 -39
- package/dist/claude-md.d.ts.map +0 -1
- package/dist/claude-md.js +0 -113
- package/dist/claude-md.js.map +0 -1
- package/dist/claude-md.test.js +0 -91
- package/dist/codex/activate.d.ts +0 -66
- package/dist/codex/activate.d.ts.map +0 -1
- package/dist/codex/activate.js +0 -329
- package/dist/codex/activate.js.map +0 -1
- package/dist/codex/activate.test.js +0 -229
- package/dist/codex/bundled-default/bundled-default.test.js +0 -161
- package/dist/codex/cli-publish.test.js +0 -133
- package/dist/codex/cli.d.ts +0 -35
- package/dist/codex/cli.d.ts.map +0 -1
- package/dist/codex/cli.js +0 -554
- package/dist/codex/cli.js.map +0 -1
- package/dist/codex/cli.test.js +0 -277
- package/dist/codex/import-skill-md.d.ts +0 -53
- package/dist/codex/import-skill-md.d.ts.map +0 -1
- package/dist/codex/import-skill-md.js +0 -236
- package/dist/codex/import-skill-md.js.map +0 -1
- package/dist/codex/import-skill-md.test.js +0 -225
- package/dist/codex/loader.d.ts +0 -27
- package/dist/codex/loader.d.ts.map +0 -1
- package/dist/codex/loader.js +0 -86
- package/dist/codex/loader.js.map +0 -1
- package/dist/codex/loader.test.js +0 -75
- package/dist/codex/parse.d.ts +0 -28
- package/dist/codex/parse.d.ts.map +0 -1
- package/dist/codex/parse.js +0 -309
- package/dist/codex/parse.js.map +0 -1
- package/dist/codex/parse.test.js +0 -241
- package/dist/codex/store.d.ts +0 -87
- package/dist/codex/store.d.ts.map +0 -1
- package/dist/codex/store.js +0 -205
- package/dist/codex/store.js.map +0 -1
- package/dist/codex/store.test.js +0 -242
- package/dist/codex/types.d.ts +0 -398
- package/dist/codex/types.d.ts.map +0 -1
- package/dist/codex/types.js +0 -21
- package/dist/codex/types.js.map +0 -1
- package/dist/config.d.ts +0 -53
- package/dist/config.d.ts.map +0 -1
- package/dist/config.js +0 -202
- package/dist/config.js.map +0 -1
- package/dist/config.test.js +0 -117
- package/dist/engine/cli.d.ts +0 -14
- package/dist/engine/cli.d.ts.map +0 -1
- package/dist/engine/cli.js +0 -171
- package/dist/engine/cli.js.map +0 -1
- package/dist/engine/client.d.ts +0 -219
- package/dist/engine/client.d.ts.map +0 -1
- package/dist/engine/client.js +0 -312
- package/dist/engine/client.js.map +0 -1
- package/dist/engine/config.d.ts +0 -62
- package/dist/engine/config.d.ts.map +0 -1
- package/dist/engine/config.js +0 -223
- package/dist/engine/config.js.map +0 -1
- package/dist/engine/index.d.ts +0 -17
- package/dist/engine/index.d.ts.map +0 -1
- package/dist/engine/index.js +0 -16
- package/dist/engine/index.js.map +0 -1
- package/dist/engine/resolver.d.ts +0 -62
- package/dist/engine/resolver.d.ts.map +0 -1
- package/dist/engine/resolver.js +0 -103
- package/dist/engine/resolver.js.map +0 -1
- package/dist/engine/singleton.d.ts +0 -95
- package/dist/engine/singleton.d.ts.map +0 -1
- package/dist/engine/singleton.js +0 -325
- package/dist/engine/singleton.js.map +0 -1
- package/dist/engine/types.d.ts +0 -402
- package/dist/engine/types.d.ts.map +0 -1
- package/dist/engine/types.js +0 -22
- package/dist/engine/types.js.map +0 -1
- package/dist/engine-binary-resolver.js +0 -110
- package/dist/engine-binary-resolver.test.js +0 -61
- package/dist/engine-cli.js +0 -60
- package/dist/engine-client.js +0 -301
- package/dist/engine-client.test.js +0 -118
- package/dist/functions/chain_state.d.ts +0 -51
- package/dist/functions/chain_state.d.ts.map +0 -1
- package/dist/functions/chain_state.js +0 -59
- package/dist/functions/chain_state.js.map +0 -1
- package/dist/hooks/drift-catalog.d.ts +0 -68
- package/dist/hooks/drift-catalog.d.ts.map +0 -1
- package/dist/hooks/drift-catalog.js +0 -184
- package/dist/hooks/drift-catalog.js.map +0 -1
- package/dist/hooks/drift-catalog.test.js +0 -154
- package/dist/hooks/drift-patterns.d.ts +0 -110
- package/dist/hooks/drift-patterns.d.ts.map +0 -1
- package/dist/hooks/drift-patterns.js +0 -289
- package/dist/hooks/drift-patterns.js.map +0 -1
- package/dist/hooks/drift-patterns.test.js +0 -325
- package/dist/hooks/engine-vocab-gate.d.ts +0 -108
- package/dist/hooks/engine-vocab-gate.d.ts.map +0 -1
- package/dist/hooks/engine-vocab-gate.js +0 -225
- package/dist/hooks/engine-vocab-gate.js.map +0 -1
- package/dist/hooks/engine-vocab-gate.test.js +0 -170
- package/dist/hooks/heartbeat.d.ts +0 -107
- package/dist/hooks/heartbeat.d.ts.map +0 -1
- package/dist/hooks/heartbeat.js +0 -316
- package/dist/hooks/heartbeat.js.map +0 -1
- package/dist/hooks/heartbeat.test.js +0 -393
- package/dist/hooks/honesty-ledger-session-scope.test.js +0 -100
- package/dist/hooks/honesty-ledger.d.ts +0 -123
- package/dist/hooks/honesty-ledger.d.ts.map +0 -1
- package/dist/hooks/honesty-ledger.js +0 -226
- package/dist/hooks/honesty-ledger.js.map +0 -1
- package/dist/hooks/honesty-ledger.test.js +0 -466
- package/dist/hooks/inline-report-check.d.ts +0 -63
- package/dist/hooks/inline-report-check.d.ts.map +0 -1
- package/dist/hooks/inline-report-check.js +0 -88
- package/dist/hooks/inline-report-check.js.map +0 -1
- package/dist/hooks/inline-report-check.test.js +0 -96
- package/dist/hooks/pre-tool-use.d.ts +0 -62
- package/dist/hooks/pre-tool-use.d.ts.map +0 -1
- package/dist/hooks/pre-tool-use.js +0 -342
- package/dist/hooks/pre-tool-use.js.map +0 -1
- package/dist/hooks/pre-tool-use.test.js +0 -134
- package/dist/hooks/session-end.d.ts +0 -15
- package/dist/hooks/session-end.d.ts.map +0 -1
- package/dist/hooks/session-end.js +0 -60
- package/dist/hooks/session-end.js.map +0 -1
- package/dist/hooks/session-end.test.js +0 -52
- package/dist/hooks/stop.d.ts +0 -35
- package/dist/hooks/stop.d.ts.map +0 -1
- package/dist/hooks/stop.js +0 -136
- package/dist/hooks/stop.js.map +0 -1
- package/dist/hooks/transcript-active-task.test.js +0 -342
- package/dist/hooks/transcript.d.ts +0 -26
- package/dist/hooks/transcript.d.ts.map +0 -1
- package/dist/hooks/transcript.js +0 -266
- package/dist/hooks/transcript.js.map +0 -1
- package/dist/hooks/transcript.test.js +0 -103
- package/dist/hooks/user-prompt-submit.d.ts +0 -74
- package/dist/hooks/user-prompt-submit.d.ts.map +0 -1
- package/dist/hooks/user-prompt-submit.js +0 -256
- package/dist/hooks/user-prompt-submit.js.map +0 -1
- package/dist/hooks/user-prompt-submit.test.js +0 -118
- package/dist/hooks/versioning-gate.d.ts +0 -101
- package/dist/hooks/versioning-gate.d.ts.map +0 -1
- package/dist/hooks/versioning-gate.js +0 -245
- package/dist/hooks/versioning-gate.js.map +0 -1
- package/dist/hooks/versioning-gate.test.js +0 -368
- package/dist/hooks/workflow-gate.d.ts +0 -64
- package/dist/hooks/workflow-gate.d.ts.map +0 -1
- package/dist/hooks/workflow-gate.js +0 -152
- package/dist/hooks/workflow-gate.js.map +0 -1
- package/dist/hooks/workflow-gate.test.js +0 -197
- package/dist/hooks-cli.d.ts +0 -25
- package/dist/hooks-cli.d.ts.map +0 -1
- package/dist/hooks-cli.js +0 -286
- package/dist/hooks-cli.js.map +0 -1
- package/dist/hooks-cli.test.js +0 -148
- package/dist/origin.d.ts +0 -16
- package/dist/origin.d.ts.map +0 -1
- package/dist/origin.js +0 -92
- package/dist/origin.js.map +0 -1
- package/dist/packs/seed_lessons_ingest.d.ts +0 -30
- package/dist/packs/seed_lessons_ingest.d.ts.map +0 -1
- package/dist/packs/seed_lessons_ingest.js +0 -107
- package/dist/packs/seed_lessons_ingest.js.map +0 -1
- package/dist/project-cli.d.ts +0 -7
- package/dist/project-cli.d.ts.map +0 -1
- package/dist/project-cli.js +0 -145
- package/dist/project-cli.js.map +0 -1
- package/dist/project.d.ts +0 -127
- package/dist/project.d.ts.map +0 -1
- package/dist/project.js +0 -281
- package/dist/project.js.map +0 -1
- package/dist/project.test.js +0 -287
- package/dist/rag/backends/loop_engine.d.ts +0 -61
- package/dist/rag/backends/loop_engine.d.ts.map +0 -1
- package/dist/rag/backends/loop_engine.js +0 -160
- package/dist/rag/backends/loop_engine.js.map +0 -1
- package/dist/recall.d.ts +0 -82
- package/dist/recall.d.ts.map +0 -1
- package/dist/recall.js +0 -81
- package/dist/recall.js.map +0 -1
- package/dist/runtime/agent_bridge/autospawn.d.ts +0 -131
- package/dist/runtime/agent_bridge/autospawn.d.ts.map +0 -1
- package/dist/runtime/agent_bridge/autospawn.js +0 -251
- package/dist/runtime/agent_bridge/autospawn.js.map +0 -1
- package/dist/runtime/chain_state.d.ts +0 -124
- package/dist/runtime/chain_state.d.ts.map +0 -1
- package/dist/runtime/chain_state.js +0 -189
- package/dist/runtime/chain_state.js.map +0 -1
- package/dist/runtime/hooks/permission_decision.d.ts +0 -34
- package/dist/runtime/hooks/permission_decision.d.ts.map +0 -1
- package/dist/runtime/hooks/permission_decision.js +0 -39
- package/dist/runtime/hooks/permission_decision.js.map +0 -1
- package/dist/runtime/workflow_fsm.d.ts +0 -21
- package/dist/runtime/workflow_fsm.d.ts.map +0 -1
- package/dist/runtime/workflow_fsm.js +0 -25
- package/dist/runtime/workflow_fsm.js.map +0 -1
- package/dist/runtime/workflow_map.d.ts +0 -26
- package/dist/runtime/workflow_map.d.ts.map +0 -1
- package/dist/runtime/workflow_map.js +0 -38
- package/dist/runtime/workflow_map.js.map +0 -1
- package/dist/scope.d.ts +0 -48
- package/dist/scope.d.ts.map +0 -1
- package/dist/scope.js +0 -111
- package/dist/scope.js.map +0 -1
- package/dist/setup/cli/topic_create_step.d.ts +0 -84
- package/dist/setup/cli/topic_create_step.d.ts.map +0 -1
- package/dist/setup/cli/topic_create_step.js +0 -213
- package/dist/setup/cli/topic_create_step.js.map +0 -1
- package/dist/system-export.d.ts +0 -65
- package/dist/system-export.d.ts.map +0 -1
- package/dist/system-export.js +0 -194
- package/dist/system-export.js.map +0 -1
- package/dist/utterance/classifier.d.ts +0 -53
- package/dist/utterance/classifier.d.ts.map +0 -1
- package/dist/utterance/classifier.js +0 -184
- package/dist/utterance/classifier.js.map +0 -1
- package/dist/utterance/classifier.test.js +0 -147
|
@@ -1,245 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Versioning gate — pre-commit check enforcing per-commit patch bumps
|
|
3
|
-
* (v0.6.3). Wired into the PreToolUse hook for `git commit` commands.
|
|
4
|
-
*
|
|
5
|
-
* Problem this fixes: I keep batching multiple fixes into one commit
|
|
6
|
-
* and bumping the minor (or no bump at all) instead of one patch per
|
|
7
|
-
* fix. The discipline rule was memorized (`mem-d2cc0e78`) but rules
|
|
8
|
-
* I can ignore aren't structural protection. This gate makes the
|
|
9
|
-
* discipline mechanical — if your commit touches source code AND
|
|
10
|
-
* doesn't include a manifest version bump in the same commit, it
|
|
11
|
-
* gets rejected before `git commit` runs.
|
|
12
|
-
*
|
|
13
|
-
* Detection:
|
|
14
|
-
* 1. `git diff --cached --name-only` → list of staged files
|
|
15
|
-
* 2. If no `src/**` files staged → allow (docs/CI/config commits
|
|
16
|
-
* don't need version bumps)
|
|
17
|
-
* 3. If `src/**` files staged → require a manifest (Cargo.toml or
|
|
18
|
-
* package.json) to also be staged with a `version` line diff
|
|
19
|
-
* 4. Otherwise → block with actionable message
|
|
20
|
-
*
|
|
21
|
-
* Fail-open invariant: any error running git or parsing output →
|
|
22
|
-
* allow with a stderr warning (per the honesty-ledger + workflow-gate
|
|
23
|
-
* precedent — never block on opensquid's own bug).
|
|
24
|
-
*
|
|
25
|
-
* Emergency override: `OPENSQUID_SKIP_VERSION_GATE=1` bypasses with a
|
|
26
|
-
* loud stderr warning. For genuine emergencies (revert commits,
|
|
27
|
-
* generated-code-only diffs, etc.) where the discipline doesn't
|
|
28
|
-
* apply.
|
|
29
|
-
*/
|
|
30
|
-
import { exec as execCb } from "node:child_process";
|
|
31
|
-
import { promisify } from "node:util";
|
|
32
|
-
const exec = promisify(execCb);
|
|
33
|
-
export async function evaluateVersioningGate(input = {}) {
|
|
34
|
-
if (checkOverrideEnv()) {
|
|
35
|
-
return {
|
|
36
|
-
block: false,
|
|
37
|
-
stderr: "🦑 [opensquid versioning-gate] BYPASSED via OPENSQUID_SKIP_VERSION_GATE=1\n",
|
|
38
|
-
};
|
|
39
|
-
}
|
|
40
|
-
const cwd = input.cwd ?? process.cwd();
|
|
41
|
-
// List staged files. `--no-renames` keeps the output simple (renames
|
|
42
|
-
// appear as both old + new path rather than `R100\told\tnew`).
|
|
43
|
-
let stagedFiles;
|
|
44
|
-
try {
|
|
45
|
-
const { stdout } = await exec("git diff --cached --name-only --no-renames", {
|
|
46
|
-
cwd,
|
|
47
|
-
maxBuffer: 1024 * 1024,
|
|
48
|
-
});
|
|
49
|
-
stagedFiles = stdout
|
|
50
|
-
.split("\n")
|
|
51
|
-
.map((l) => l.trim())
|
|
52
|
-
.filter(Boolean);
|
|
53
|
-
}
|
|
54
|
-
catch (err) {
|
|
55
|
-
return {
|
|
56
|
-
block: false,
|
|
57
|
-
stderr: `[opensquid versioning-gate] git diff failed (proceeding): ${err instanceof Error ? err.message : err}\n`,
|
|
58
|
-
};
|
|
59
|
-
}
|
|
60
|
-
if (stagedFiles.length === 0) {
|
|
61
|
-
// Nothing staged — git commit will fail on its own with no need
|
|
62
|
-
// for this gate to intervene.
|
|
63
|
-
return { block: false, stderr: "" };
|
|
64
|
-
}
|
|
65
|
-
const sourceFiles = stagedFiles.filter(isSourceFile);
|
|
66
|
-
if (sourceFiles.length === 0) {
|
|
67
|
-
// Docs / CI / config / fixtures / etc. — no source change, no bump needed.
|
|
68
|
-
return { block: false, stderr: "" };
|
|
69
|
-
}
|
|
70
|
-
const manifests = stagedFiles.filter(isManifestFile);
|
|
71
|
-
if (manifests.length === 0) {
|
|
72
|
-
return {
|
|
73
|
-
block: true,
|
|
74
|
-
stderr: buildBlockMessage(sourceFiles, []),
|
|
75
|
-
};
|
|
76
|
-
}
|
|
77
|
-
// At least one manifest is staged — check that at least one has a
|
|
78
|
-
// version-line diff (just touching the manifest without bumping
|
|
79
|
-
// version doesn't count).
|
|
80
|
-
let bumpedManifest = null;
|
|
81
|
-
for (const m of manifests) {
|
|
82
|
-
const jump = await readManifestVersionBump(cwd, m);
|
|
83
|
-
if (jump) {
|
|
84
|
-
bumpedManifest = { path: m, jump };
|
|
85
|
-
break;
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
if (!bumpedManifest) {
|
|
89
|
-
return {
|
|
90
|
-
block: true,
|
|
91
|
-
stderr: buildBlockMessage(sourceFiles, manifests),
|
|
92
|
-
};
|
|
93
|
-
}
|
|
94
|
-
// 0.7.23 / D5 — catch-up bump detection. The PATCH-ONLY rule
|
|
95
|
-
// ([[feedback_pre1_versioning]] v4) says every src commit = exactly
|
|
96
|
-
// one patch bump. A jump like 0.7.10 → 0.7.14 in a single commit
|
|
97
|
-
// means previous src commits skipped their bumps. Don't BLOCK
|
|
98
|
-
// (legitimate explicit catch-ups exist), but surface a loud warning
|
|
99
|
-
// so the skip is visible.
|
|
100
|
-
const { jump } = bumpedManifest;
|
|
101
|
-
if (jump && isMultiPatchJump(jump)) {
|
|
102
|
-
return {
|
|
103
|
-
block: false,
|
|
104
|
-
stderr: `🦑 [opensquid versioning-gate] WARN: catch-up bump detected (${jump.from} → ${jump.to})\n` +
|
|
105
|
-
` PATCH-ONLY rule says one patch per commit. A multi-patch jump in one\n` +
|
|
106
|
-
` commit usually means earlier src commits shipped without bumps. Drift D5.\n`,
|
|
107
|
-
};
|
|
108
|
-
}
|
|
109
|
-
return { block: false, stderr: "" };
|
|
110
|
-
}
|
|
111
|
-
/**
|
|
112
|
-
* Is this a source file that should trigger version-bump enforcement?
|
|
113
|
-
* Generous definition: anything under `src/` for any language we support.
|
|
114
|
-
*/
|
|
115
|
-
export function isSourceFile(p) {
|
|
116
|
-
// src/ at any depth (top-level or nested workspace member)
|
|
117
|
-
return /(^|\/)src\//.test(p);
|
|
118
|
-
}
|
|
119
|
-
/** Is this the repo's version manifest? */
|
|
120
|
-
export function isManifestFile(p) {
|
|
121
|
-
const base = p.split("/").pop() ?? "";
|
|
122
|
-
return base === "Cargo.toml" || base === "package.json";
|
|
123
|
-
}
|
|
124
|
-
/**
|
|
125
|
-
* Look at the staged diff of a manifest and return the version jump
|
|
126
|
-
* (from → to). Returns null when the diff doesn't touch a `version`
|
|
127
|
-
* line at all.
|
|
128
|
-
*
|
|
129
|
-
* Exported for direct testing.
|
|
130
|
-
*/
|
|
131
|
-
export async function readManifestVersionBump(cwd, manifestPath) {
|
|
132
|
-
let diff;
|
|
133
|
-
try {
|
|
134
|
-
const { stdout } = await exec(`git diff --cached --no-color -U0 -- ${quoteShell(manifestPath)}`, { cwd, maxBuffer: 1024 * 1024 });
|
|
135
|
-
diff = stdout;
|
|
136
|
-
}
|
|
137
|
-
catch {
|
|
138
|
-
return null;
|
|
139
|
-
}
|
|
140
|
-
return parseVersionJumpFromDiff(diff);
|
|
141
|
-
}
|
|
142
|
-
/**
|
|
143
|
-
* Parse `+`/`-` lines from a manifest diff and extract the version
|
|
144
|
-
* jump. Cargo: `version = "..."`. package.json: `"version": "..."`.
|
|
145
|
-
*
|
|
146
|
-
* Anchor discipline:
|
|
147
|
-
* - Cargo (TOML, line-oriented) → anchor `^version` so we don't
|
|
148
|
-
* match a dep with `version = "..."` in `[dependencies.foo]`.
|
|
149
|
-
* - package.json (JSON, can be MINIFIED single-line) → do NOT
|
|
150
|
-
* anchor; `"version"` can appear mid-line in minified JSON.
|
|
151
|
-
*
|
|
152
|
-
* Exported for direct testing.
|
|
153
|
-
*/
|
|
154
|
-
export function parseVersionJumpFromDiff(diff) {
|
|
155
|
-
let oldVersion = null;
|
|
156
|
-
let newVersion = null;
|
|
157
|
-
for (const line of diff.split("\n")) {
|
|
158
|
-
if (line.startsWith("+++") || line.startsWith("---"))
|
|
159
|
-
continue;
|
|
160
|
-
const sign = line[0];
|
|
161
|
-
if (sign !== "+" && sign !== "-")
|
|
162
|
-
continue;
|
|
163
|
-
const body = line.slice(1).trim();
|
|
164
|
-
let v = null;
|
|
165
|
-
const cargoMatch = body.match(/^version\s*=\s*"([^"]+)"/);
|
|
166
|
-
if (cargoMatch)
|
|
167
|
-
v = cargoMatch[1];
|
|
168
|
-
if (v === null) {
|
|
169
|
-
const npmMatch = body.match(/"version"\s*:\s*"([^"]+)"/);
|
|
170
|
-
if (npmMatch)
|
|
171
|
-
v = npmMatch[1];
|
|
172
|
-
}
|
|
173
|
-
if (v === null)
|
|
174
|
-
continue;
|
|
175
|
-
if (sign === "+")
|
|
176
|
-
newVersion = v;
|
|
177
|
-
else
|
|
178
|
-
oldVersion = v;
|
|
179
|
-
}
|
|
180
|
-
if (!newVersion)
|
|
181
|
-
return null;
|
|
182
|
-
// New-version only (e.g. brand-new manifest with no prior `version`
|
|
183
|
-
// line) is still a valid "version bump" — treat oldVersion as empty.
|
|
184
|
-
return { from: oldVersion ?? "", to: newVersion };
|
|
185
|
-
}
|
|
186
|
-
/**
|
|
187
|
-
* Detect a multi-patch jump: same major.minor, but patch advances by
|
|
188
|
-
* more than 1 (catch-up bump).
|
|
189
|
-
*
|
|
190
|
-
* Returns false for:
|
|
191
|
-
* - First-time bumps (from === "")
|
|
192
|
-
* - Same-patch (no actual jump, shouldn't happen with proper diff)
|
|
193
|
-
* - Minor/major bumps (those are user-authorized; PATCH-ONLY rule
|
|
194
|
-
* forbids the agent from naming them but doesn't make them "drift")
|
|
195
|
-
* - Non-SemVer version strings (best-effort parse)
|
|
196
|
-
*
|
|
197
|
-
* Exported for direct testing.
|
|
198
|
-
*/
|
|
199
|
-
export function isMultiPatchJump(jump) {
|
|
200
|
-
const oldParts = parseSemver(jump.from);
|
|
201
|
-
const newParts = parseSemver(jump.to);
|
|
202
|
-
if (!oldParts || !newParts)
|
|
203
|
-
return false;
|
|
204
|
-
// Only flag same-major.minor with patch jump > 1.
|
|
205
|
-
if (oldParts.major !== newParts.major)
|
|
206
|
-
return false;
|
|
207
|
-
if (oldParts.minor !== newParts.minor)
|
|
208
|
-
return false;
|
|
209
|
-
return newParts.patch > oldParts.patch + 1;
|
|
210
|
-
}
|
|
211
|
-
function parseSemver(v) {
|
|
212
|
-
const m = v.match(/^(\d+)\.(\d+)\.(\d+)/);
|
|
213
|
-
if (!m)
|
|
214
|
-
return null;
|
|
215
|
-
return { major: Number(m[1]), minor: Number(m[2]), patch: Number(m[3]) };
|
|
216
|
-
}
|
|
217
|
-
function quoteShell(s) {
|
|
218
|
-
// Defensive single-quote shell escape. Manifest paths are usually
|
|
219
|
-
// boring but we don't trust them blindly.
|
|
220
|
-
return `'${s.replace(/'/g, "'\\''")}'`;
|
|
221
|
-
}
|
|
222
|
-
function buildBlockMessage(sourceFiles, manifests) {
|
|
223
|
-
const srcSample = sourceFiles.slice(0, 5).join(", ") + (sourceFiles.length > 5 ? ", ..." : "");
|
|
224
|
-
const lines = [
|
|
225
|
-
`🦑 [opensquid versioning-gate] commit blocked — source changes without a version bump`,
|
|
226
|
-
` source files staged (${sourceFiles.length}): ${srcSample}`,
|
|
227
|
-
];
|
|
228
|
-
if (manifests.length === 0) {
|
|
229
|
-
lines.push(` No Cargo.toml or package.json staged.`, ` Bump the patch version (per mem-d2cc0e78 — fix per commit, not batched), \`git add\` the manifest, then re-commit.`);
|
|
230
|
-
}
|
|
231
|
-
else {
|
|
232
|
-
lines.push(` Manifest(s) staged but no version-line diff: ${manifests.join(", ")}`, ` Bump the version field (Cargo.toml: \`version = "x.y.z"\`, package.json: \`"version": "x.y.z"\`), re-stage, then re-commit.`);
|
|
233
|
-
}
|
|
234
|
-
lines.push(` Override (genuine emergency): set OPENSQUID_SKIP_VERSION_GATE=1 for this command.`);
|
|
235
|
-
return lines.join("\n") + "\n";
|
|
236
|
-
}
|
|
237
|
-
/**
|
|
238
|
-
* Emergency-override env var. Loud stderr warning on bypass so it
|
|
239
|
-
* always shows up in scrollback / CI logs. Exported for the test
|
|
240
|
-
* suite.
|
|
241
|
-
*/
|
|
242
|
-
export function checkOverrideEnv() {
|
|
243
|
-
return process.env.OPENSQUID_SKIP_VERSION_GATE === "1";
|
|
244
|
-
}
|
|
245
|
-
//# sourceMappingURL=versioning-gate.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"versioning-gate.js","sourceRoot":"","sources":["../../src.legacy/hooks/versioning-gate.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,368 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Versioning-gate tests — exercise against real git repos in tmpdirs.
|
|
3
|
-
* The gate's logic depends on actual `git diff --cached` output shape,
|
|
4
|
-
* so synthesized state wouldn't catch the same class of bug that
|
|
5
|
-
* v0.6.1 transcript-walker missed against real Claude Code shapes
|
|
6
|
-
* (per the v0.6.2 lesson). Each test inits a fresh tmp git repo,
|
|
7
|
-
* sets up the staged state we want, runs the gate, asserts.
|
|
8
|
-
*/
|
|
9
|
-
import { afterEach, beforeEach, describe, expect, it } from "vitest";
|
|
10
|
-
import { execSync } from "node:child_process";
|
|
11
|
-
import * as crypto from "node:crypto";
|
|
12
|
-
import { promises as fs } from "node:fs";
|
|
13
|
-
import * as os from "node:os";
|
|
14
|
-
import * as path from "node:path";
|
|
15
|
-
import { checkOverrideEnv, evaluateVersioningGate, isManifestFile, isMultiPatchJump, isSourceFile, parseVersionJumpFromDiff, } from "./versioning-gate.js";
|
|
16
|
-
// ---------------------------------------------------------------------
|
|
17
|
-
// Helpers
|
|
18
|
-
// ---------------------------------------------------------------------
|
|
19
|
-
let repoDir;
|
|
20
|
-
beforeEach(async () => {
|
|
21
|
-
repoDir = path.join(os.tmpdir(), `opensquid-ver-${crypto.randomUUID()}`);
|
|
22
|
-
await fs.mkdir(repoDir, { recursive: true });
|
|
23
|
-
// Minimal git init that doesn't depend on the user's global config.
|
|
24
|
-
execSync("git init -q", { cwd: repoDir });
|
|
25
|
-
execSync("git config user.email test@example.com", { cwd: repoDir });
|
|
26
|
-
execSync("git config user.name 'Test'", { cwd: repoDir });
|
|
27
|
-
});
|
|
28
|
-
afterEach(async () => {
|
|
29
|
-
await fs.rm(repoDir, { recursive: true, force: true });
|
|
30
|
-
delete process.env.OPENSQUID_SKIP_VERSION_GATE;
|
|
31
|
-
});
|
|
32
|
-
async function writeFile(rel, content) {
|
|
33
|
-
const full = path.join(repoDir, rel);
|
|
34
|
-
await fs.mkdir(path.dirname(full), { recursive: true });
|
|
35
|
-
await fs.writeFile(full, content, "utf8");
|
|
36
|
-
}
|
|
37
|
-
function stage(rel) {
|
|
38
|
-
execSync(`git add ${rel}`, { cwd: repoDir });
|
|
39
|
-
}
|
|
40
|
-
function commit(message) {
|
|
41
|
-
execSync(`git commit -q -m '${message}'`, { cwd: repoDir });
|
|
42
|
-
}
|
|
43
|
-
/** Initial commit so subsequent `git diff --cached` against HEAD works. */
|
|
44
|
-
async function seedInitial() {
|
|
45
|
-
await writeFile("README.md", "# seed\n");
|
|
46
|
-
stage("README.md");
|
|
47
|
-
commit("initial");
|
|
48
|
-
}
|
|
49
|
-
// ---------------------------------------------------------------------
|
|
50
|
-
// Pure helper tests (no git involvement)
|
|
51
|
-
// ---------------------------------------------------------------------
|
|
52
|
-
describe("isSourceFile", () => {
|
|
53
|
-
it("matches src/ at repo root", () => {
|
|
54
|
-
expect(isSourceFile("src/index.ts")).toBe(true);
|
|
55
|
-
expect(isSourceFile("src/hooks/foo.ts")).toBe(true);
|
|
56
|
-
});
|
|
57
|
-
it("matches nested src/ in workspace member", () => {
|
|
58
|
-
expect(isSourceFile("crates/engine/src/lib.rs")).toBe(true);
|
|
59
|
-
expect(isSourceFile("packages/x/src/foo.js")).toBe(true);
|
|
60
|
-
});
|
|
61
|
-
it("does not match top-level files outside src/", () => {
|
|
62
|
-
expect(isSourceFile("README.md")).toBe(false);
|
|
63
|
-
expect(isSourceFile("Cargo.toml")).toBe(false);
|
|
64
|
-
expect(isSourceFile("package.json")).toBe(false);
|
|
65
|
-
expect(isSourceFile("CHANGELOG.md")).toBe(false);
|
|
66
|
-
expect(isSourceFile(".github/workflows/ci.yml")).toBe(false);
|
|
67
|
-
expect(isSourceFile("tests/foo.test.ts")).toBe(false);
|
|
68
|
-
});
|
|
69
|
-
it("does not match 'srcfoo/' (false-prefix)", () => {
|
|
70
|
-
expect(isSourceFile("srcfoo/bar.ts")).toBe(false);
|
|
71
|
-
});
|
|
72
|
-
});
|
|
73
|
-
describe("isManifestFile", () => {
|
|
74
|
-
it("matches root-level manifests", () => {
|
|
75
|
-
expect(isManifestFile("Cargo.toml")).toBe(true);
|
|
76
|
-
expect(isManifestFile("package.json")).toBe(true);
|
|
77
|
-
});
|
|
78
|
-
it("matches nested manifests (workspace members)", () => {
|
|
79
|
-
expect(isManifestFile("crates/engine/Cargo.toml")).toBe(true);
|
|
80
|
-
expect(isManifestFile("packages/x/package.json")).toBe(true);
|
|
81
|
-
});
|
|
82
|
-
it("does not match other tomls / jsons", () => {
|
|
83
|
-
expect(isManifestFile("tsconfig.json")).toBe(false);
|
|
84
|
-
expect(isManifestFile("rustfmt.toml")).toBe(false);
|
|
85
|
-
expect(isManifestFile("clippy.toml")).toBe(false);
|
|
86
|
-
});
|
|
87
|
-
});
|
|
88
|
-
// ---------------------------------------------------------------------
|
|
89
|
-
// Allow paths — gate should NOT block
|
|
90
|
-
// ---------------------------------------------------------------------
|
|
91
|
-
describe("evaluateVersioningGate — allow paths", () => {
|
|
92
|
-
it("allows when nothing is staged", async () => {
|
|
93
|
-
await seedInitial();
|
|
94
|
-
const r = await evaluateVersioningGate({ cwd: repoDir });
|
|
95
|
-
expect(r.block).toBe(false);
|
|
96
|
-
expect(r.stderr).toBe("");
|
|
97
|
-
});
|
|
98
|
-
it("allows docs-only commit (no src/ staged)", async () => {
|
|
99
|
-
await seedInitial();
|
|
100
|
-
await writeFile("README.md", "# updated\n");
|
|
101
|
-
await writeFile("CHANGELOG.md", "## changes\n");
|
|
102
|
-
stage("README.md");
|
|
103
|
-
stage("CHANGELOG.md");
|
|
104
|
-
const r = await evaluateVersioningGate({ cwd: repoDir });
|
|
105
|
-
expect(r.block).toBe(false);
|
|
106
|
-
});
|
|
107
|
-
it("allows CI-only commit", async () => {
|
|
108
|
-
await seedInitial();
|
|
109
|
-
await writeFile(".github/workflows/ci.yml", "name: CI\n");
|
|
110
|
-
stage(".github/workflows/ci.yml");
|
|
111
|
-
const r = await evaluateVersioningGate({ cwd: repoDir });
|
|
112
|
-
expect(r.block).toBe(false);
|
|
113
|
-
});
|
|
114
|
-
it("allows src + Cargo.toml version bump in same commit", async () => {
|
|
115
|
-
await seedInitial();
|
|
116
|
-
await writeFile("Cargo.toml", 'version = "0.1.0"\n');
|
|
117
|
-
await writeFile("src/lib.rs", "// initial\n");
|
|
118
|
-
stage("Cargo.toml");
|
|
119
|
-
stage("src/lib.rs");
|
|
120
|
-
commit("initial src + manifest");
|
|
121
|
-
// Now bump:
|
|
122
|
-
await writeFile("Cargo.toml", 'version = "0.1.1"\n');
|
|
123
|
-
await writeFile("src/lib.rs", "// patched\n");
|
|
124
|
-
stage("Cargo.toml");
|
|
125
|
-
stage("src/lib.rs");
|
|
126
|
-
const r = await evaluateVersioningGate({ cwd: repoDir });
|
|
127
|
-
expect(r.block).toBe(false);
|
|
128
|
-
});
|
|
129
|
-
// Audit HIGH fix (v0.6.3): minified package.json was originally a
|
|
130
|
-
// false-positive block because the regex anchored `^"version"` and
|
|
131
|
-
// minified JSON has `"version"` mid-line. Drop the anchor.
|
|
132
|
-
it("allows src + MINIFIED package.json version bump (audit HIGH regression)", async () => {
|
|
133
|
-
await seedInitial();
|
|
134
|
-
await writeFile("package.json", '{"name":"x","version":"0.1.0"}\n');
|
|
135
|
-
await writeFile("src/index.ts", "// initial\n");
|
|
136
|
-
stage("package.json");
|
|
137
|
-
stage("src/index.ts");
|
|
138
|
-
commit("initial");
|
|
139
|
-
await writeFile("package.json", '{"name":"x","version":"0.1.1"}\n');
|
|
140
|
-
await writeFile("src/index.ts", "// patched\n");
|
|
141
|
-
stage("package.json");
|
|
142
|
-
stage("src/index.ts");
|
|
143
|
-
const r = await evaluateVersioningGate({ cwd: repoDir });
|
|
144
|
-
expect(r.block).toBe(false);
|
|
145
|
-
});
|
|
146
|
-
it("allows src + package.json version bump in same commit (realistic multi-line JSON)", async () => {
|
|
147
|
-
await seedInitial();
|
|
148
|
-
// Real package.json is pretty-printed multi-line so the diff
|
|
149
|
-
// surfaces a `"version": "..."` change on its own line.
|
|
150
|
-
const pkgV1 = JSON.stringify({ name: "x", version: "0.1.0" }, null, 2) + "\n";
|
|
151
|
-
const pkgV2 = JSON.stringify({ name: "x", version: "0.1.1" }, null, 2) + "\n";
|
|
152
|
-
await writeFile("package.json", pkgV1);
|
|
153
|
-
await writeFile("src/index.ts", "// initial\n");
|
|
154
|
-
stage("package.json");
|
|
155
|
-
stage("src/index.ts");
|
|
156
|
-
commit("initial");
|
|
157
|
-
await writeFile("package.json", pkgV2);
|
|
158
|
-
await writeFile("src/index.ts", "// patched\n");
|
|
159
|
-
stage("package.json");
|
|
160
|
-
stage("src/index.ts");
|
|
161
|
-
const r = await evaluateVersioningGate({ cwd: repoDir });
|
|
162
|
-
expect(r.block).toBe(false);
|
|
163
|
-
});
|
|
164
|
-
});
|
|
165
|
-
// ---------------------------------------------------------------------
|
|
166
|
-
// Block paths — gate SHOULD block
|
|
167
|
-
// ---------------------------------------------------------------------
|
|
168
|
-
describe("evaluateVersioningGate — block paths", () => {
|
|
169
|
-
it("blocks src/ change with no manifest staged", async () => {
|
|
170
|
-
await seedInitial();
|
|
171
|
-
await writeFile("Cargo.toml", 'version = "0.1.0"\n');
|
|
172
|
-
await writeFile("src/lib.rs", "// initial\n");
|
|
173
|
-
stage("Cargo.toml");
|
|
174
|
-
stage("src/lib.rs");
|
|
175
|
-
commit("initial src + manifest");
|
|
176
|
-
// Now ONLY src changes, no manifest bump:
|
|
177
|
-
await writeFile("src/lib.rs", "// edited\n");
|
|
178
|
-
stage("src/lib.rs");
|
|
179
|
-
const r = await evaluateVersioningGate({ cwd: repoDir });
|
|
180
|
-
expect(r.block).toBe(true);
|
|
181
|
-
expect(r.stderr).toContain("commit blocked");
|
|
182
|
-
expect(r.stderr).toContain("src/lib.rs");
|
|
183
|
-
expect(r.stderr).toContain("No Cargo.toml or package.json staged");
|
|
184
|
-
});
|
|
185
|
-
it("blocks src/ change with manifest staged but no version-line diff", async () => {
|
|
186
|
-
await seedInitial();
|
|
187
|
-
await writeFile("Cargo.toml", 'version = "0.1.0"\n[dependencies]\nfoo = "1"\n');
|
|
188
|
-
await writeFile("src/lib.rs", "// initial\n");
|
|
189
|
-
stage("Cargo.toml");
|
|
190
|
-
stage("src/lib.rs");
|
|
191
|
-
commit("initial");
|
|
192
|
-
// Touch manifest (add dep) but DON'T bump version, also touch src:
|
|
193
|
-
await writeFile("Cargo.toml", 'version = "0.1.0"\n[dependencies]\nfoo = "1"\nbar = "2"\n');
|
|
194
|
-
await writeFile("src/lib.rs", "// edited\n");
|
|
195
|
-
stage("Cargo.toml");
|
|
196
|
-
stage("src/lib.rs");
|
|
197
|
-
const r = await evaluateVersioningGate({ cwd: repoDir });
|
|
198
|
-
expect(r.block).toBe(true);
|
|
199
|
-
expect(r.stderr).toContain("no version-line diff");
|
|
200
|
-
expect(r.stderr).toContain("Cargo.toml");
|
|
201
|
-
});
|
|
202
|
-
});
|
|
203
|
-
// ---------------------------------------------------------------------
|
|
204
|
-
// Multi-manifest / workspace
|
|
205
|
-
// ---------------------------------------------------------------------
|
|
206
|
-
describe("evaluateVersioningGate — workspace / multi-manifest", () => {
|
|
207
|
-
it("allows when ANY staged manifest has a version bump", async () => {
|
|
208
|
-
await seedInitial();
|
|
209
|
-
await writeFile("crates/a/Cargo.toml", 'version = "0.1.0"\n');
|
|
210
|
-
await writeFile("crates/b/Cargo.toml", 'version = "0.1.0"\n');
|
|
211
|
-
await writeFile("crates/a/src/lib.rs", "// a\n");
|
|
212
|
-
await writeFile("crates/b/src/lib.rs", "// b\n");
|
|
213
|
-
stage("crates/a/Cargo.toml");
|
|
214
|
-
stage("crates/b/Cargo.toml");
|
|
215
|
-
stage("crates/a/src/lib.rs");
|
|
216
|
-
stage("crates/b/src/lib.rs");
|
|
217
|
-
commit("initial");
|
|
218
|
-
// Bump ONLY crate a; edit src in BOTH:
|
|
219
|
-
await writeFile("crates/a/Cargo.toml", 'version = "0.1.1"\n');
|
|
220
|
-
await writeFile("crates/a/src/lib.rs", "// a patched\n");
|
|
221
|
-
await writeFile("crates/b/src/lib.rs", "// b edited\n");
|
|
222
|
-
stage("crates/a/Cargo.toml");
|
|
223
|
-
stage("crates/a/src/lib.rs");
|
|
224
|
-
stage("crates/b/src/lib.rs");
|
|
225
|
-
const r = await evaluateVersioningGate({ cwd: repoDir });
|
|
226
|
-
// Liberal policy: ANY manifest bump is enough. Workspace-wide
|
|
227
|
-
// discipline is a v0.6.4+ refinement if needed.
|
|
228
|
-
expect(r.block).toBe(false);
|
|
229
|
-
});
|
|
230
|
-
});
|
|
231
|
-
// ---------------------------------------------------------------------
|
|
232
|
-
// Emergency override
|
|
233
|
-
// ---------------------------------------------------------------------
|
|
234
|
-
describe("evaluateVersioningGate — emergency override", () => {
|
|
235
|
-
it("ALLOWS with bypass warning when OPENSQUID_SKIP_VERSION_GATE=1", async () => {
|
|
236
|
-
process.env.OPENSQUID_SKIP_VERSION_GATE = "1";
|
|
237
|
-
expect(checkOverrideEnv()).toBe(true);
|
|
238
|
-
await seedInitial();
|
|
239
|
-
await writeFile("Cargo.toml", 'version = "0.1.0"\n');
|
|
240
|
-
await writeFile("src/lib.rs", "// initial\n");
|
|
241
|
-
stage("Cargo.toml");
|
|
242
|
-
stage("src/lib.rs");
|
|
243
|
-
commit("initial");
|
|
244
|
-
await writeFile("src/lib.rs", "// edited\n");
|
|
245
|
-
stage("src/lib.rs");
|
|
246
|
-
const r = await evaluateVersioningGate({ cwd: repoDir });
|
|
247
|
-
expect(r.block).toBe(false);
|
|
248
|
-
expect(r.stderr).toContain("BYPASSED");
|
|
249
|
-
});
|
|
250
|
-
it("respects the env var only when EXACTLY '1'", async () => {
|
|
251
|
-
process.env.OPENSQUID_SKIP_VERSION_GATE = "true";
|
|
252
|
-
expect(checkOverrideEnv()).toBe(false);
|
|
253
|
-
process.env.OPENSQUID_SKIP_VERSION_GATE = "1";
|
|
254
|
-
expect(checkOverrideEnv()).toBe(true);
|
|
255
|
-
});
|
|
256
|
-
});
|
|
257
|
-
// ---------------------------------------------------------------------
|
|
258
|
-
// 0.7.23 / D5 — multi-patch catch-up jump detection
|
|
259
|
-
// ---------------------------------------------------------------------
|
|
260
|
-
describe("parseVersionJumpFromDiff", () => {
|
|
261
|
-
it("parses a Cargo.toml patch bump", () => {
|
|
262
|
-
const diff = `--- a/Cargo.toml
|
|
263
|
-
+++ b/Cargo.toml
|
|
264
|
-
@@ -1 +1 @@
|
|
265
|
-
-version = "0.7.10"
|
|
266
|
-
+version = "0.7.11"
|
|
267
|
-
`;
|
|
268
|
-
expect(parseVersionJumpFromDiff(diff)).toEqual({ from: "0.7.10", to: "0.7.11" });
|
|
269
|
-
});
|
|
270
|
-
it("parses a package.json patch bump", () => {
|
|
271
|
-
const diff = `--- a/package.json
|
|
272
|
-
+++ b/package.json
|
|
273
|
-
@@ -2 +2 @@
|
|
274
|
-
- "version": "0.7.10",
|
|
275
|
-
+ "version": "0.7.11",
|
|
276
|
-
`;
|
|
277
|
-
expect(parseVersionJumpFromDiff(diff)).toEqual({ from: "0.7.10", to: "0.7.11" });
|
|
278
|
-
});
|
|
279
|
-
it("parses a multi-patch jump (D5 incident shape)", () => {
|
|
280
|
-
const diff = `--- a/package.json
|
|
281
|
-
+++ b/package.json
|
|
282
|
-
- "version": "0.7.10",
|
|
283
|
-
+ "version": "0.7.14",
|
|
284
|
-
`;
|
|
285
|
-
expect(parseVersionJumpFromDiff(diff)).toEqual({ from: "0.7.10", to: "0.7.14" });
|
|
286
|
-
});
|
|
287
|
-
it("returns null when no version line is touched", () => {
|
|
288
|
-
const diff = `--- a/package.json
|
|
289
|
-
+++ b/package.json
|
|
290
|
-
+ "description": "updated text",
|
|
291
|
-
- "description": "old text",
|
|
292
|
-
`;
|
|
293
|
-
expect(parseVersionJumpFromDiff(diff)).toBeNull();
|
|
294
|
-
});
|
|
295
|
-
});
|
|
296
|
-
describe("isMultiPatchJump", () => {
|
|
297
|
-
it("flags 0.7.10 → 0.7.14 (D5 catch-up)", () => {
|
|
298
|
-
expect(isMultiPatchJump({ from: "0.7.10", to: "0.7.14" })).toBe(true);
|
|
299
|
-
});
|
|
300
|
-
it("flags 0.7.10 → 0.7.12 (2-step jump)", () => {
|
|
301
|
-
expect(isMultiPatchJump({ from: "0.7.10", to: "0.7.12" })).toBe(true);
|
|
302
|
-
});
|
|
303
|
-
it("does NOT flag a normal 0.7.10 → 0.7.11 patch bump", () => {
|
|
304
|
-
expect(isMultiPatchJump({ from: "0.7.10", to: "0.7.11" })).toBe(false);
|
|
305
|
-
});
|
|
306
|
-
it("does NOT flag a minor bump (0.7.x → 0.8.0)", () => {
|
|
307
|
-
// Minor/major bumps are user-authorized; not the agent's drift to warn about.
|
|
308
|
-
expect(isMultiPatchJump({ from: "0.7.20", to: "0.8.0" })).toBe(false);
|
|
309
|
-
});
|
|
310
|
-
it("does NOT flag a first-time version (from empty)", () => {
|
|
311
|
-
expect(isMultiPatchJump({ from: "", to: "0.1.0" })).toBe(false);
|
|
312
|
-
});
|
|
313
|
-
it("does NOT flag non-SemVer strings", () => {
|
|
314
|
-
expect(isMultiPatchJump({ from: "wip", to: "wip-2" })).toBe(false);
|
|
315
|
-
});
|
|
316
|
-
});
|
|
317
|
-
describe("evaluateVersioningGate — multi-patch warning end-to-end (D5)", () => {
|
|
318
|
-
it("ALLOWS but WARNS when commit bumps version by >1 patch", async () => {
|
|
319
|
-
await seedInitial();
|
|
320
|
-
await writeFile("Cargo.toml", 'version = "0.7.10"\n');
|
|
321
|
-
await writeFile("src/lib.rs", "// initial\n");
|
|
322
|
-
stage("Cargo.toml");
|
|
323
|
-
stage("src/lib.rs");
|
|
324
|
-
commit("initial");
|
|
325
|
-
// Now jump 0.7.10 → 0.7.14 in one commit alongside a src change
|
|
326
|
-
await writeFile("Cargo.toml", 'version = "0.7.14"\n');
|
|
327
|
-
await writeFile("src/lib.rs", "// changed\n");
|
|
328
|
-
stage("Cargo.toml");
|
|
329
|
-
stage("src/lib.rs");
|
|
330
|
-
const r = await evaluateVersioningGate({ cwd: repoDir });
|
|
331
|
-
expect(r.block).toBe(false);
|
|
332
|
-
expect(r.stderr).toContain("catch-up bump detected");
|
|
333
|
-
expect(r.stderr).toContain("0.7.10 → 0.7.14");
|
|
334
|
-
expect(r.stderr).toContain("Drift D5");
|
|
335
|
-
});
|
|
336
|
-
it("does NOT warn on a clean +1 patch bump", async () => {
|
|
337
|
-
await seedInitial();
|
|
338
|
-
await writeFile("Cargo.toml", 'version = "0.7.10"\n');
|
|
339
|
-
await writeFile("src/lib.rs", "// initial\n");
|
|
340
|
-
stage("Cargo.toml");
|
|
341
|
-
stage("src/lib.rs");
|
|
342
|
-
commit("initial");
|
|
343
|
-
await writeFile("Cargo.toml", 'version = "0.7.11"\n');
|
|
344
|
-
await writeFile("src/lib.rs", "// changed\n");
|
|
345
|
-
stage("Cargo.toml");
|
|
346
|
-
stage("src/lib.rs");
|
|
347
|
-
const r = await evaluateVersioningGate({ cwd: repoDir });
|
|
348
|
-
expect(r.block).toBe(false);
|
|
349
|
-
expect(r.stderr).toBe("");
|
|
350
|
-
});
|
|
351
|
-
});
|
|
352
|
-
// ---------------------------------------------------------------------
|
|
353
|
-
// Fail-open invariant
|
|
354
|
-
// ---------------------------------------------------------------------
|
|
355
|
-
describe("evaluateVersioningGate — fail-open invariant", () => {
|
|
356
|
-
it("ALLOWS with stderr warning when git is not available (non-repo cwd)", async () => {
|
|
357
|
-
const notARepo = path.join(os.tmpdir(), `not-a-repo-${crypto.randomUUID()}`);
|
|
358
|
-
await fs.mkdir(notARepo, { recursive: true });
|
|
359
|
-
try {
|
|
360
|
-
const r = await evaluateVersioningGate({ cwd: notARepo });
|
|
361
|
-
expect(r.block).toBe(false);
|
|
362
|
-
expect(r.stderr).toContain("git diff failed");
|
|
363
|
-
}
|
|
364
|
-
finally {
|
|
365
|
-
await fs.rm(notARepo, { recursive: true, force: true });
|
|
366
|
-
}
|
|
367
|
-
});
|
|
368
|
-
});
|