opensquid 0.5.441 → 0.5.447
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/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_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/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,229 +0,0 @@
|
|
|
1
|
-
import * as crypto from "node:crypto";
|
|
2
|
-
import { promises as fs } from "node:fs";
|
|
3
|
-
import * as os from "node:os";
|
|
4
|
-
import * as path from "node:path";
|
|
5
|
-
import { afterEach, beforeEach, describe, expect, it } from "vitest";
|
|
6
|
-
import { CodexActivationCache, evaluateDetection, extractCodexId, isCodexActive, } from "./activate.js";
|
|
7
|
-
import { installCodex } from "./store.js";
|
|
8
|
-
let tmpCwd;
|
|
9
|
-
let tmpStore;
|
|
10
|
-
beforeEach(async () => {
|
|
11
|
-
const uniq = crypto.randomUUID();
|
|
12
|
-
tmpCwd = path.join(os.tmpdir(), `oscli-activate-cwd-${uniq}`);
|
|
13
|
-
tmpStore = path.join(os.tmpdir(), `oscli-activate-store-${uniq}`);
|
|
14
|
-
await fs.mkdir(tmpCwd, { recursive: true });
|
|
15
|
-
await fs.mkdir(tmpStore, { recursive: true });
|
|
16
|
-
});
|
|
17
|
-
afterEach(async () => {
|
|
18
|
-
await fs.rm(tmpCwd, { recursive: true, force: true });
|
|
19
|
-
await fs.rm(tmpStore, { recursive: true, force: true });
|
|
20
|
-
});
|
|
21
|
-
// ---------------------------------------------------------------------
|
|
22
|
-
// extractCodexId
|
|
23
|
-
// ---------------------------------------------------------------------
|
|
24
|
-
describe("extractCodexId", () => {
|
|
25
|
-
it("extracts id from codex-suffixed description", () => {
|
|
26
|
-
expect(extractCodexId("before any push (codex:loop-engineering-workflow)")).toBe("loop-engineering-workflow");
|
|
27
|
-
});
|
|
28
|
-
it("trims trailing whitespace tolerantly", () => {
|
|
29
|
-
expect(extractCodexId("rule (codex:x) ")).toBe("x");
|
|
30
|
-
});
|
|
31
|
-
it("returns null when no suffix", () => {
|
|
32
|
-
expect(extractCodexId("some legacy lesson description")).toBeNull();
|
|
33
|
-
});
|
|
34
|
-
it("returns null for non-id-shaped content in parens", () => {
|
|
35
|
-
expect(extractCodexId("see (PR #42)")).toBeNull();
|
|
36
|
-
expect(extractCodexId("see (codex:Bad-Id)")).toBeNull();
|
|
37
|
-
});
|
|
38
|
-
});
|
|
39
|
-
// ---------------------------------------------------------------------
|
|
40
|
-
// evaluateDetection — filesystem signals
|
|
41
|
-
// ---------------------------------------------------------------------
|
|
42
|
-
describe("evaluateDetection: file_exists", () => {
|
|
43
|
-
it("matches when file present", async () => {
|
|
44
|
-
await fs.writeFile(path.join(tmpCwd, "package.json"), "{}", "utf8");
|
|
45
|
-
expect(await evaluateDetection({ kind: "file_exists", path: "package.json" }, tmpCwd)).toBe(true);
|
|
46
|
-
});
|
|
47
|
-
it("misses when file absent", async () => {
|
|
48
|
-
expect(await evaluateDetection({ kind: "file_exists", path: "package.json" }, tmpCwd)).toBe(false);
|
|
49
|
-
});
|
|
50
|
-
it("misses when path is a directory", async () => {
|
|
51
|
-
await fs.mkdir(path.join(tmpCwd, "package.json"));
|
|
52
|
-
expect(await evaluateDetection({ kind: "file_exists", path: "package.json" }, tmpCwd)).toBe(false);
|
|
53
|
-
});
|
|
54
|
-
});
|
|
55
|
-
describe("evaluateDetection: dir_exists", () => {
|
|
56
|
-
it("matches when dir present", async () => {
|
|
57
|
-
await fs.mkdir(path.join(tmpCwd, "src/components/atoms"), { recursive: true });
|
|
58
|
-
expect(await evaluateDetection({ kind: "dir_exists", path: "src/components/atoms" }, tmpCwd)).toBe(true);
|
|
59
|
-
});
|
|
60
|
-
it("misses when dir absent", async () => {
|
|
61
|
-
expect(await evaluateDetection({ kind: "dir_exists", path: "src/components/atoms" }, tmpCwd)).toBe(false);
|
|
62
|
-
});
|
|
63
|
-
});
|
|
64
|
-
describe("evaluateDetection: file_match (JSON)", () => {
|
|
65
|
-
it("matches when dotted path resolves to a truthy value", async () => {
|
|
66
|
-
await fs.writeFile(path.join(tmpCwd, "package.json"), JSON.stringify({ dependencies: { react: "^19.0.0" } }), "utf8");
|
|
67
|
-
expect(await evaluateDetection({
|
|
68
|
-
kind: "file_match",
|
|
69
|
-
path: "package.json",
|
|
70
|
-
matches: { "dependencies.react": ">=19" },
|
|
71
|
-
}, tmpCwd)).toBe(true);
|
|
72
|
-
});
|
|
73
|
-
it("misses when dotted path is missing", async () => {
|
|
74
|
-
await fs.writeFile(path.join(tmpCwd, "package.json"), JSON.stringify({ name: "x" }), "utf8");
|
|
75
|
-
expect(await evaluateDetection({
|
|
76
|
-
kind: "file_match",
|
|
77
|
-
path: "package.json",
|
|
78
|
-
matches: { "dependencies.react": ">=19" },
|
|
79
|
-
}, tmpCwd)).toBe(false);
|
|
80
|
-
});
|
|
81
|
-
it("misses when file is absent", async () => {
|
|
82
|
-
expect(await evaluateDetection({
|
|
83
|
-
kind: "file_match",
|
|
84
|
-
path: "package.json",
|
|
85
|
-
matches: { "dependencies.react": ">=19" },
|
|
86
|
-
}, tmpCwd)).toBe(false);
|
|
87
|
-
});
|
|
88
|
-
});
|
|
89
|
-
describe("evaluateDetection: file_glob", () => {
|
|
90
|
-
it("matches when min_count met", async () => {
|
|
91
|
-
await fs.mkdir(path.join(tmpCwd, "data"));
|
|
92
|
-
await fs.writeFile(path.join(tmpCwd, "data/sample1.h5ad"), "", "utf8");
|
|
93
|
-
await fs.writeFile(path.join(tmpCwd, "data/sample2.h5ad"), "", "utf8");
|
|
94
|
-
expect(await evaluateDetection({ kind: "file_glob", pattern: "**/*.h5ad", min_count: 2 }, tmpCwd)).toBe(true);
|
|
95
|
-
});
|
|
96
|
-
it("misses when below min_count", async () => {
|
|
97
|
-
await fs.mkdir(path.join(tmpCwd, "data"));
|
|
98
|
-
await fs.writeFile(path.join(tmpCwd, "data/sample1.h5ad"), "", "utf8");
|
|
99
|
-
expect(await evaluateDetection({ kind: "file_glob", pattern: "**/*.h5ad", min_count: 2 }, tmpCwd)).toBe(false);
|
|
100
|
-
});
|
|
101
|
-
it("skips node_modules + dot-dirs during walk", async () => {
|
|
102
|
-
await fs.mkdir(path.join(tmpCwd, "node_modules/foo"), { recursive: true });
|
|
103
|
-
await fs.mkdir(path.join(tmpCwd, ".git"), { recursive: true });
|
|
104
|
-
await fs.writeFile(path.join(tmpCwd, "node_modules/foo/x.h5ad"), "", "utf8");
|
|
105
|
-
await fs.writeFile(path.join(tmpCwd, ".git/x.h5ad"), "", "utf8");
|
|
106
|
-
expect(await evaluateDetection({ kind: "file_glob", pattern: "**/*.h5ad", min_count: 1 }, tmpCwd)).toBe(false);
|
|
107
|
-
});
|
|
108
|
-
});
|
|
109
|
-
describe("evaluateDetection: user_pinned", () => {
|
|
110
|
-
it("always returns true", async () => {
|
|
111
|
-
expect(await evaluateDetection({ kind: "user_pinned" }, tmpCwd)).toBe(true);
|
|
112
|
-
});
|
|
113
|
-
});
|
|
114
|
-
describe("evaluateDetection: all_of / any_of", () => {
|
|
115
|
-
it("all_of requires every condition", async () => {
|
|
116
|
-
await fs.writeFile(path.join(tmpCwd, "a"), "", "utf8");
|
|
117
|
-
expect(await evaluateDetection({
|
|
118
|
-
kind: "all_of",
|
|
119
|
-
conditions: [
|
|
120
|
-
{ kind: "file_exists", path: "a" },
|
|
121
|
-
{ kind: "file_exists", path: "b" },
|
|
122
|
-
],
|
|
123
|
-
}, tmpCwd)).toBe(false);
|
|
124
|
-
await fs.writeFile(path.join(tmpCwd, "b"), "", "utf8");
|
|
125
|
-
expect(await evaluateDetection({
|
|
126
|
-
kind: "all_of",
|
|
127
|
-
conditions: [
|
|
128
|
-
{ kind: "file_exists", path: "a" },
|
|
129
|
-
{ kind: "file_exists", path: "b" },
|
|
130
|
-
],
|
|
131
|
-
}, tmpCwd)).toBe(true);
|
|
132
|
-
});
|
|
133
|
-
it("any_of accepts any single match", async () => {
|
|
134
|
-
await fs.writeFile(path.join(tmpCwd, "a"), "", "utf8");
|
|
135
|
-
expect(await evaluateDetection({
|
|
136
|
-
kind: "any_of",
|
|
137
|
-
conditions: [
|
|
138
|
-
{ kind: "file_exists", path: "a" },
|
|
139
|
-
{ kind: "file_exists", path: "b" },
|
|
140
|
-
],
|
|
141
|
-
}, tmpCwd)).toBe(true);
|
|
142
|
-
});
|
|
143
|
-
});
|
|
144
|
-
describe("evaluateDetection: memory_match / conversation_signal", () => {
|
|
145
|
-
it("memory_match defaults to true (runtime context not available here)", async () => {
|
|
146
|
-
expect(await evaluateDetection({ kind: "memory_match", memory_kind: "profession", value: "clinician" }, tmpCwd)).toBe(true);
|
|
147
|
-
});
|
|
148
|
-
it("conversation_signal defaults to true", async () => {
|
|
149
|
-
expect(await evaluateDetection({ kind: "conversation_signal", contains: ["case law"] }, tmpCwd)).toBe(true);
|
|
150
|
-
});
|
|
151
|
-
});
|
|
152
|
-
// ---------------------------------------------------------------------
|
|
153
|
-
// isCodexActive
|
|
154
|
-
// ---------------------------------------------------------------------
|
|
155
|
-
describe("isCodexActive", () => {
|
|
156
|
-
function focused(detected_by) {
|
|
157
|
-
return {
|
|
158
|
-
id: "test",
|
|
159
|
-
version: "1.0.0",
|
|
160
|
-
detected_by,
|
|
161
|
-
};
|
|
162
|
-
}
|
|
163
|
-
it("composite codexes are inactive (includes activate via their own detected_by)", async () => {
|
|
164
|
-
const composite = {
|
|
165
|
-
id: "x",
|
|
166
|
-
kind: "composite",
|
|
167
|
-
version: "1.0.0",
|
|
168
|
-
includes: [{ id: "a", semver: ">=1" }],
|
|
169
|
-
};
|
|
170
|
-
expect(await isCodexActive(composite, tmpCwd)).toBe(false);
|
|
171
|
-
});
|
|
172
|
-
it("focused codex with no detected_by defaults to active", async () => {
|
|
173
|
-
expect(await isCodexActive(focused(undefined), tmpCwd)).toBe(true);
|
|
174
|
-
expect(await isCodexActive(focused([]), tmpCwd)).toBe(true);
|
|
175
|
-
});
|
|
176
|
-
it("top-level detected_by list = OR semantics", async () => {
|
|
177
|
-
await fs.writeFile(path.join(tmpCwd, "tsconfig.json"), "{}", "utf8");
|
|
178
|
-
expect(await isCodexActive(focused([
|
|
179
|
-
{ kind: "file_exists", path: "Cargo.toml" }, // miss
|
|
180
|
-
{ kind: "file_exists", path: "tsconfig.json" }, // hit
|
|
181
|
-
]), tmpCwd)).toBe(true);
|
|
182
|
-
});
|
|
183
|
-
it("no matching detection → inactive", async () => {
|
|
184
|
-
expect(await isCodexActive(focused([{ kind: "file_exists", path: "Cargo.toml" }]), tmpCwd)).toBe(false);
|
|
185
|
-
});
|
|
186
|
-
});
|
|
187
|
-
// ---------------------------------------------------------------------
|
|
188
|
-
// CodexActivationCache
|
|
189
|
-
// ---------------------------------------------------------------------
|
|
190
|
-
describe("CodexActivationCache", () => {
|
|
191
|
-
it("returns true for an installed user_pinned codex", async () => {
|
|
192
|
-
const codex = {
|
|
193
|
-
id: "wf",
|
|
194
|
-
version: "1.0.0",
|
|
195
|
-
activation_scope: "user",
|
|
196
|
-
detected_by: [{ kind: "user_pinned" }],
|
|
197
|
-
};
|
|
198
|
-
await installCodex(codex, { rootDir: tmpStore });
|
|
199
|
-
const cache = new CodexActivationCache(tmpCwd, tmpStore);
|
|
200
|
-
expect(await cache.isActive("wf")).toBe(true);
|
|
201
|
-
});
|
|
202
|
-
it("returns false when detected_by doesn't match cwd", async () => {
|
|
203
|
-
const codex = {
|
|
204
|
-
id: "react-19",
|
|
205
|
-
version: "1.0.0",
|
|
206
|
-
detected_by: [{ kind: "file_exists", path: "package.json" }],
|
|
207
|
-
};
|
|
208
|
-
await installCodex(codex, { rootDir: tmpStore });
|
|
209
|
-
const cache = new CodexActivationCache(tmpCwd, tmpStore);
|
|
210
|
-
expect(await cache.isActive("react-19")).toBe(false);
|
|
211
|
-
});
|
|
212
|
-
it("returns false for non-installed codex (stale lesson reference)", async () => {
|
|
213
|
-
const cache = new CodexActivationCache(tmpCwd, tmpStore);
|
|
214
|
-
expect(await cache.isActive("ghost-codex")).toBe(false);
|
|
215
|
-
});
|
|
216
|
-
it("caches the same decision across repeated lookups", async () => {
|
|
217
|
-
const codex = {
|
|
218
|
-
id: "wf",
|
|
219
|
-
version: "1.0.0",
|
|
220
|
-
detected_by: [{ kind: "user_pinned" }],
|
|
221
|
-
};
|
|
222
|
-
await installCodex(codex, { rootDir: tmpStore });
|
|
223
|
-
const cache = new CodexActivationCache(tmpCwd, tmpStore);
|
|
224
|
-
const a = await cache.isActive("wf");
|
|
225
|
-
const b = await cache.isActive("wf");
|
|
226
|
-
expect(a).toBe(true);
|
|
227
|
-
expect(b).toBe(true);
|
|
228
|
-
});
|
|
229
|
-
});
|
|
@@ -1,161 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Verifies that the bundled-default codex round-trips through the
|
|
3
|
-
* codex parser. Acts as both a fixture test (proves the schema
|
|
4
|
-
* additions actually parse) and a CI tripwire (any drift between
|
|
5
|
-
* codex YAML + zod schema fails here first).
|
|
6
|
-
*
|
|
7
|
-
* Part of drift-as-codex chunk 1 (#146).
|
|
8
|
-
*/
|
|
9
|
-
import { promises as fs } from "node:fs";
|
|
10
|
-
import * as path from "node:path";
|
|
11
|
-
import { fileURLToPath } from "node:url";
|
|
12
|
-
import { describe, expect, it } from "vitest";
|
|
13
|
-
import { parseCodexYaml } from "../parse.js";
|
|
14
|
-
import { isFocusedCodex } from "../types.js";
|
|
15
|
-
const HERE = path.dirname(fileURLToPath(import.meta.url));
|
|
16
|
-
const BUNDLED_DEFAULT_PATH = path.join(HERE, "codex.yaml");
|
|
17
|
-
describe("bundled-default codex", () => {
|
|
18
|
-
it("parses without errors", async () => {
|
|
19
|
-
const yaml = await fs.readFile(BUNDLED_DEFAULT_PATH, "utf8");
|
|
20
|
-
expect(() => parseCodexYaml(yaml)).not.toThrow();
|
|
21
|
-
});
|
|
22
|
-
it("is a focused codex with the expected id + version", async () => {
|
|
23
|
-
const yaml = await fs.readFile(BUNDLED_DEFAULT_PATH, "utf8");
|
|
24
|
-
const c = parseCodexYaml(yaml);
|
|
25
|
-
expect(isFocusedCodex(c)).toBe(true);
|
|
26
|
-
if (!isFocusedCodex(c))
|
|
27
|
-
return;
|
|
28
|
-
expect(c.id).toBe("opensquid-default");
|
|
29
|
-
expect(c.version).toBe("1.0.0");
|
|
30
|
-
});
|
|
31
|
-
it("declares the four standard drifts (never-amend / no-implicit-push / substrate-purity / no-force-push-main)", async () => {
|
|
32
|
-
const yaml = await fs.readFile(BUNDLED_DEFAULT_PATH, "utf8");
|
|
33
|
-
const c = parseCodexYaml(yaml);
|
|
34
|
-
if (!isFocusedCodex(c))
|
|
35
|
-
throw new Error("expected focused codex");
|
|
36
|
-
const ids = (c.drifts ?? []).map((d) => d.id);
|
|
37
|
-
expect(ids).toEqual(expect.arrayContaining([
|
|
38
|
-
"never-amend",
|
|
39
|
-
"no-implicit-push",
|
|
40
|
-
"substrate-purity",
|
|
41
|
-
"no-force-push-main",
|
|
42
|
-
]));
|
|
43
|
-
});
|
|
44
|
-
it("declares the standard-7-phase workflow with all 7 phases", async () => {
|
|
45
|
-
const yaml = await fs.readFile(BUNDLED_DEFAULT_PATH, "utf8");
|
|
46
|
-
const c = parseCodexYaml(yaml);
|
|
47
|
-
if (!isFocusedCodex(c))
|
|
48
|
-
throw new Error("expected focused codex");
|
|
49
|
-
const wf = (c.workflows ?? []).find((w) => w.id === "standard-7-phase");
|
|
50
|
-
expect(wf).toBeDefined();
|
|
51
|
-
expect(wf?.phases.map((p) => p.name)).toEqual([
|
|
52
|
-
"pre_research",
|
|
53
|
-
"learn",
|
|
54
|
-
"code",
|
|
55
|
-
"test",
|
|
56
|
-
"audit",
|
|
57
|
-
"post_research",
|
|
58
|
-
"fix",
|
|
59
|
-
]);
|
|
60
|
-
expect(c.default_workflow_id).toBe("standard-7-phase");
|
|
61
|
-
});
|
|
62
|
-
it("marks `fix` phase as optional (skip-with-reason allowed)", async () => {
|
|
63
|
-
const yaml = await fs.readFile(BUNDLED_DEFAULT_PATH, "utf8");
|
|
64
|
-
const c = parseCodexYaml(yaml);
|
|
65
|
-
if (!isFocusedCodex(c))
|
|
66
|
-
throw new Error("expected focused codex");
|
|
67
|
-
const wf = (c.workflows ?? []).find((w) => w.id === "standard-7-phase");
|
|
68
|
-
const fixPhase = wf?.phases.find((p) => p.name === "fix");
|
|
69
|
-
expect(fixPhase?.required).toBe(false);
|
|
70
|
-
});
|
|
71
|
-
it("declares the PATCH-ONLY pre-1.0 versioning policy", async () => {
|
|
72
|
-
const yaml = await fs.readFile(BUNDLED_DEFAULT_PATH, "utf8");
|
|
73
|
-
const c = parseCodexYaml(yaml);
|
|
74
|
-
if (!isFocusedCodex(c))
|
|
75
|
-
throw new Error("expected focused codex");
|
|
76
|
-
const versioning = (c.policies ?? []).find((p) => p.kind === "versioning");
|
|
77
|
-
expect(versioning).toBeDefined();
|
|
78
|
-
if (versioning?.kind !== "versioning")
|
|
79
|
-
return;
|
|
80
|
-
expect(versioning.params.allowed_slots).toEqual(["patch"]);
|
|
81
|
-
expect(versioning.params.per_commit_required).toBe(true);
|
|
82
|
-
expect(versioning.params.slot_for?.bug_fix).toBe("patch");
|
|
83
|
-
expect(versioning.params.slot_for?.feature).toBe("patch");
|
|
84
|
-
expect(versioning.params.slot_for?.breaking).toBe("patch");
|
|
85
|
-
});
|
|
86
|
-
it("declares a phase_logged policy that references the standard workflow", async () => {
|
|
87
|
-
const yaml = await fs.readFile(BUNDLED_DEFAULT_PATH, "utf8");
|
|
88
|
-
const c = parseCodexYaml(yaml);
|
|
89
|
-
if (!isFocusedCodex(c))
|
|
90
|
-
throw new Error("expected focused codex");
|
|
91
|
-
const phasePolicy = (c.policies ?? []).find((p) => p.kind === "phase_logged");
|
|
92
|
-
expect(phasePolicy).toBeDefined();
|
|
93
|
-
if (phasePolicy?.kind !== "phase_logged")
|
|
94
|
-
return;
|
|
95
|
-
expect(phasePolicy.params.workflow_id).toBe("standard-7-phase");
|
|
96
|
-
expect(phasePolicy.params.enforce_on).toContain("git_commit");
|
|
97
|
-
});
|
|
98
|
-
it("ports the five load-bearing honesty-ledger claims", async () => {
|
|
99
|
-
const yaml = await fs.readFile(BUNDLED_DEFAULT_PATH, "utf8");
|
|
100
|
-
const c = parseCodexYaml(yaml);
|
|
101
|
-
if (!isFocusedCodex(c))
|
|
102
|
-
throw new Error("expected focused codex");
|
|
103
|
-
const ids = (c.claims ?? []).map((cl) => cl.id);
|
|
104
|
-
expect(ids).toEqual(expect.arrayContaining(["telegram-sent", "pushed", "tagged", "phase-logged", "fmt-clippy"]));
|
|
105
|
-
});
|
|
106
|
-
it("uses any_of evidence for the telegram-sent claim (proves recursive schema works)", async () => {
|
|
107
|
-
const yaml = await fs.readFile(BUNDLED_DEFAULT_PATH, "utf8");
|
|
108
|
-
const c = parseCodexYaml(yaml);
|
|
109
|
-
if (!isFocusedCodex(c))
|
|
110
|
-
throw new Error("expected focused codex");
|
|
111
|
-
const telegramSent = (c.claims ?? []).find((cl) => cl.id === "telegram-sent");
|
|
112
|
-
expect(telegramSent?.evidence.kind).toBe("any_of");
|
|
113
|
-
if (telegramSent?.evidence.kind !== "any_of")
|
|
114
|
-
return;
|
|
115
|
-
expect(telegramSent.evidence.options.length).toBeGreaterThanOrEqual(2);
|
|
116
|
-
});
|
|
117
|
-
});
|
|
118
|
-
describe("FocusedCodex schema — drift-as-codex additions (chunk 1)", () => {
|
|
119
|
-
it("accepts a codex with no drift-as-codex sections (backward compat)", () => {
|
|
120
|
-
const c = parseCodexYaml(`id: legacy\nversion: "1.0.0"\n`);
|
|
121
|
-
expect(isFocusedCodex(c)).toBe(true);
|
|
122
|
-
});
|
|
123
|
-
it("rejects a drift entry with an unknown severity", () => {
|
|
124
|
-
const bad = `
|
|
125
|
-
id: bad
|
|
126
|
-
version: "1.0.0"
|
|
127
|
-
drifts:
|
|
128
|
-
- id: x
|
|
129
|
-
tool: Bash
|
|
130
|
-
trigger: { kind: bash_regex, pattern: "foo" }
|
|
131
|
-
lesson: y
|
|
132
|
-
severity: maybe
|
|
133
|
-
message: hi
|
|
134
|
-
`;
|
|
135
|
-
expect(() => parseCodexYaml(bad)).toThrow();
|
|
136
|
-
});
|
|
137
|
-
it("rejects a workflow with zero phases", () => {
|
|
138
|
-
const bad = `
|
|
139
|
-
id: bad
|
|
140
|
-
version: "1.0.0"
|
|
141
|
-
workflows:
|
|
142
|
-
- id: empty
|
|
143
|
-
enforce_on: [git_commit]
|
|
144
|
-
phases: []
|
|
145
|
-
`;
|
|
146
|
-
expect(() => parseCodexYaml(bad)).toThrow();
|
|
147
|
-
});
|
|
148
|
-
it("rejects a versioning policy with empty allowed_slots", () => {
|
|
149
|
-
const bad = `
|
|
150
|
-
id: bad
|
|
151
|
-
version: "1.0.0"
|
|
152
|
-
policies:
|
|
153
|
-
- id: bad-pol
|
|
154
|
-
kind: versioning
|
|
155
|
-
params:
|
|
156
|
-
per_commit_required: true
|
|
157
|
-
allowed_slots: []
|
|
158
|
-
`;
|
|
159
|
-
expect(() => parseCodexYaml(bad)).toThrow();
|
|
160
|
-
});
|
|
161
|
-
});
|
|
@@ -1,133 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Tests for #116 — codex-install auto-publish to CLAUDE.md.
|
|
3
|
-
*
|
|
4
|
-
* Covers `publishSeededLessonToClaudeMd` directly so we don't need a
|
|
5
|
-
* real engine subprocess to verify the auto-publish behavior.
|
|
6
|
-
*/
|
|
7
|
-
import * as crypto from "node:crypto";
|
|
8
|
-
import { promises as fs } from "node:fs";
|
|
9
|
-
import * as os from "node:os";
|
|
10
|
-
import * as path from "node:path";
|
|
11
|
-
import { afterEach, beforeEach, describe, expect, it } from "vitest";
|
|
12
|
-
import { publishSeededLessonToClaudeMd } from "./cli.js";
|
|
13
|
-
let tmpDir;
|
|
14
|
-
let claudeMdPath;
|
|
15
|
-
const INSTALLED_BLOCK = [
|
|
16
|
-
"# CLAUDE.md",
|
|
17
|
-
"",
|
|
18
|
-
"<!-- opensquid-automation:start v0.4.0 -->",
|
|
19
|
-
"Some opensquid automation guidance lives here.",
|
|
20
|
-
"",
|
|
21
|
-
"<!-- opensquid-rules:start (auto-managed) -->",
|
|
22
|
-
"(no promoted lessons yet — this block populates as `lesson.promote`",
|
|
23
|
-
"succeeds for user-endorsed candidates)",
|
|
24
|
-
"<!-- opensquid-rules:end -->",
|
|
25
|
-
"<!-- opensquid-automation:end -->",
|
|
26
|
-
"",
|
|
27
|
-
].join("\n");
|
|
28
|
-
beforeEach(async () => {
|
|
29
|
-
tmpDir = path.join(os.tmpdir(), `opensquid-publish-test-${crypto.randomUUID()}`);
|
|
30
|
-
await fs.mkdir(tmpDir, { recursive: true });
|
|
31
|
-
claudeMdPath = path.join(tmpDir, "CLAUDE.md");
|
|
32
|
-
await fs.writeFile(claudeMdPath, INSTALLED_BLOCK, "utf8");
|
|
33
|
-
});
|
|
34
|
-
afterEach(async () => {
|
|
35
|
-
await fs.rm(tmpDir, { recursive: true, force: true });
|
|
36
|
-
});
|
|
37
|
-
describe("publishSeededLessonToClaudeMd", () => {
|
|
38
|
-
it("appends a new line into the rules block", async () => {
|
|
39
|
-
const appended = await publishSeededLessonToClaudeMd({
|
|
40
|
-
engineLessonId: "les-abc12345",
|
|
41
|
-
description: "before doing X (codex:test-codex)",
|
|
42
|
-
createdAt: "2026-05-15T22:00:00Z",
|
|
43
|
-
codexLessonId: "do-x",
|
|
44
|
-
}, { target: claudeMdPath });
|
|
45
|
-
expect(appended).toBe(true);
|
|
46
|
-
const content = await fs.readFile(claudeMdPath, "utf8");
|
|
47
|
-
expect(content).toContain("(lesson:les-abc12345)");
|
|
48
|
-
expect(content).toContain("before doing X (codex:test-codex)");
|
|
49
|
-
expect(content).toContain("promoted 2026-05-15T22:00:00Z");
|
|
50
|
-
// Placeholder line should be gone.
|
|
51
|
-
expect(content).not.toContain("(no promoted lessons yet");
|
|
52
|
-
});
|
|
53
|
-
it("is idempotent — second call with same id is a no-op", async () => {
|
|
54
|
-
const first = await publishSeededLessonToClaudeMd({
|
|
55
|
-
engineLessonId: "les-dup",
|
|
56
|
-
description: "x",
|
|
57
|
-
createdAt: "2026-05-15T22:00:00Z",
|
|
58
|
-
codexLessonId: "x",
|
|
59
|
-
}, { target: claudeMdPath });
|
|
60
|
-
expect(first).toBe(true);
|
|
61
|
-
const second = await publishSeededLessonToClaudeMd({
|
|
62
|
-
engineLessonId: "les-dup",
|
|
63
|
-
description: "x",
|
|
64
|
-
createdAt: "2026-05-15T22:01:00Z",
|
|
65
|
-
codexLessonId: "x",
|
|
66
|
-
}, { target: claudeMdPath });
|
|
67
|
-
expect(second).toBe(false);
|
|
68
|
-
const content = await fs.readFile(claudeMdPath, "utf8");
|
|
69
|
-
const matches = content.match(/\(lesson:les-dup\)/g);
|
|
70
|
-
expect(matches?.length).toBe(1);
|
|
71
|
-
});
|
|
72
|
-
it("appends multiple distinct lesson ids in order", async () => {
|
|
73
|
-
await publishSeededLessonToClaudeMd({
|
|
74
|
-
engineLessonId: "les-1",
|
|
75
|
-
description: "first",
|
|
76
|
-
createdAt: "2026-05-15T22:00:00Z",
|
|
77
|
-
codexLessonId: "a",
|
|
78
|
-
}, { target: claudeMdPath });
|
|
79
|
-
await publishSeededLessonToClaudeMd({
|
|
80
|
-
engineLessonId: "les-2",
|
|
81
|
-
description: "second",
|
|
82
|
-
createdAt: "2026-05-15T22:00:01Z",
|
|
83
|
-
codexLessonId: "b",
|
|
84
|
-
}, { target: claudeMdPath });
|
|
85
|
-
await publishSeededLessonToClaudeMd({
|
|
86
|
-
engineLessonId: "les-3",
|
|
87
|
-
description: "third",
|
|
88
|
-
createdAt: "2026-05-15T22:00:02Z",
|
|
89
|
-
codexLessonId: "c",
|
|
90
|
-
}, { target: claudeMdPath });
|
|
91
|
-
const content = await fs.readFile(claudeMdPath, "utf8");
|
|
92
|
-
const idx1 = content.indexOf("first");
|
|
93
|
-
const idx2 = content.indexOf("second");
|
|
94
|
-
const idx3 = content.indexOf("third");
|
|
95
|
-
expect(idx1).toBeGreaterThan(0);
|
|
96
|
-
expect(idx2).toBeGreaterThan(idx1);
|
|
97
|
-
expect(idx3).toBeGreaterThan(idx2);
|
|
98
|
-
});
|
|
99
|
-
it("returns false when engineLessonId is undefined", async () => {
|
|
100
|
-
const appended = await publishSeededLessonToClaudeMd({
|
|
101
|
-
engineLessonId: undefined,
|
|
102
|
-
description: "no id",
|
|
103
|
-
createdAt: "2026-05-15T22:00:00Z",
|
|
104
|
-
codexLessonId: "no-id",
|
|
105
|
-
}, { target: claudeMdPath });
|
|
106
|
-
expect(appended).toBe(false);
|
|
107
|
-
const content = await fs.readFile(claudeMdPath, "utf8");
|
|
108
|
-
expect(content).toContain("(no promoted lessons yet");
|
|
109
|
-
});
|
|
110
|
-
it("returns false (silent no-op) when CLAUDE.md is missing", async () => {
|
|
111
|
-
const appended = await publishSeededLessonToClaudeMd({
|
|
112
|
-
engineLessonId: "les-orphan",
|
|
113
|
-
description: "orphan",
|
|
114
|
-
createdAt: "2026-05-15T22:00:00Z",
|
|
115
|
-
codexLessonId: "orphan",
|
|
116
|
-
}, { target: path.join(tmpDir, "does-not-exist.md") });
|
|
117
|
-
expect(appended).toBe(false);
|
|
118
|
-
});
|
|
119
|
-
it("returns false when CLAUDE.md exists but has no rules block", async () => {
|
|
120
|
-
const noBlockPath = path.join(tmpDir, "no-block.md");
|
|
121
|
-
await fs.writeFile(noBlockPath, "# CLAUDE.md\n\nNo opensquid block here.\n", "utf8");
|
|
122
|
-
const appended = await publishSeededLessonToClaudeMd({
|
|
123
|
-
engineLessonId: "les-orphan2",
|
|
124
|
-
description: "orphan2",
|
|
125
|
-
createdAt: "2026-05-15T22:00:00Z",
|
|
126
|
-
codexLessonId: "orphan2",
|
|
127
|
-
}, { target: noBlockPath });
|
|
128
|
-
expect(appended).toBe(false);
|
|
129
|
-
// Original file is untouched.
|
|
130
|
-
const content = await fs.readFile(noBlockPath, "utf8");
|
|
131
|
-
expect(content).toBe("# CLAUDE.md\n\nNo opensquid block here.\n");
|
|
132
|
-
});
|
|
133
|
-
});
|
package/dist/codex/cli.d.ts
DELETED
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
export declare class CodexCliError extends Error {
|
|
2
|
-
readonly hint?: string | undefined;
|
|
3
|
-
constructor(message: string, hint?: string | undefined);
|
|
4
|
-
}
|
|
5
|
-
/**
|
|
6
|
-
* Iterate the codex's seed lessons and seed each into the engine's
|
|
7
|
-
* lesson store at `promoted` status via `lesson.create` with
|
|
8
|
-
* `authored_by: "pack"` + `seed_as_promoted: true`. The engine treats
|
|
9
|
-
* Pack provenance as user-equivalent (codex install = user authorship).
|
|
10
|
-
*/
|
|
11
|
-
/**
|
|
12
|
-
* Append a single seeded lesson's one-line summary to the user's
|
|
13
|
-
* CLAUDE.md `opensquid-rules` block. Exported for direct unit testing
|
|
14
|
-
* — covers the auto-publish behavior without spawning the real engine.
|
|
15
|
-
*
|
|
16
|
-
* Returns true if a new line was appended, false if it was an idempotent
|
|
17
|
-
* no-op (lesson id already present, or rules block missing). Failure is
|
|
18
|
-
* non-fatal and logged to stderr — CLAUDE.md is downstream display, not
|
|
19
|
-
* source of truth.
|
|
20
|
-
*/
|
|
21
|
-
export declare function publishSeededLessonToClaudeMd(args: {
|
|
22
|
-
/** The engine-assigned `les-...` id for the seeded lesson. */
|
|
23
|
-
engineLessonId: string | undefined;
|
|
24
|
-
/** Human-readable description (typically `${trigger} (codex:${codexId})`). */
|
|
25
|
-
description: string;
|
|
26
|
-
/** ISO timestamp; defaults to now if engine doesn't return one. */
|
|
27
|
-
createdAt: string;
|
|
28
|
-
/** Codex-local lesson id, used only for error logging context. */
|
|
29
|
-
codexLessonId: string;
|
|
30
|
-
}, options?: {
|
|
31
|
-
target?: string;
|
|
32
|
-
}): Promise<boolean>;
|
|
33
|
-
export type CodexCliCmd = "install" | "list" | "remove" | "doctor" | "export";
|
|
34
|
-
export declare function runCodexCli(cmd: CodexCliCmd, argv: string[]): Promise<void>;
|
|
35
|
-
//# sourceMappingURL=cli.d.ts.map
|
package/dist/codex/cli.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../../src.legacy/codex/cli.ts"],"names":[],"mappings":"AAwDA,qBAAa,aAAc,SAAQ,KAAK;aAGpB,IAAI,CAAC,EAAE,MAAM;gBAD7B,OAAO,EAAE,MAAM,EACC,IAAI,CAAC,EAAE,MAAM,YAAA;CAKhC;AA8RD;;;;;GAKG;AACH;;;;;;;;;GASG;AACH,wBAAsB,6BAA6B,CACjD,IAAI,EAAE;IACJ,8DAA8D;IAC9D,cAAc,EAAE,MAAM,GAAG,SAAS,CAAC;IACnC,8EAA8E;IAC9E,WAAW,EAAE,MAAM,CAAC;IACpB,mEAAmE;IACnE,SAAS,EAAE,MAAM,CAAC;IAClB,kEAAkE;IAClE,aAAa,EAAE,MAAM,CAAC;CACvB,EACD,OAAO,GAAE;IAAE,MAAM,CAAC,EAAE,MAAM,CAAA;CAAO,GAChC,OAAO,CAAC,OAAO,CAAC,CAiBlB;AA2QD,MAAM,MAAM,WAAW,GAAG,SAAS,GAAG,MAAM,GAAG,QAAQ,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAE9E,wBAAsB,WAAW,CAAC,GAAG,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAmBjF"}
|