@litfamily/litcodex 1.0.0 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (121) hide show
  1. package/README.md +18 -21
  2. package/dist/cli.d.ts +1 -1
  3. package/dist/cli.js +2 -38
  4. package/dist/config-migration/profile-files.d.ts +4 -0
  5. package/dist/config-migration/profile-files.js +22 -0
  6. package/dist/install/capability-preflight-error.js +5 -1
  7. package/dist/install/codex.d.ts +1 -0
  8. package/dist/install/generated-skill-payload-hashes.d.ts +1 -6
  9. package/dist/install/generated-skill-payload-hashes.js +1 -6
  10. package/dist/install/host-capabilities.d.ts +2 -0
  11. package/dist/install/host-capabilities.js +13 -1
  12. package/dist/install/index.js +3 -1
  13. package/dist/install/skill-catalog.d.ts +1 -1
  14. package/dist/install/skill-catalog.js +1 -6
  15. package/dist/install/skill-resource-hashes.d.ts +1 -1
  16. package/dist/install/skill-resource-hashes.js +1 -1
  17. package/dist/install/strict-config-probe.d.ts +2 -0
  18. package/dist/install/strict-config-probe.js +34 -5
  19. package/dist/install/uninstall.d.ts +2 -0
  20. package/dist/install/uninstall.js +34 -0
  21. package/marketplace/plugins/litcodex/.codex-plugin/plugin.json +1 -1
  22. package/marketplace/plugins/litcodex/components/auto-update/package.json +1 -1
  23. package/marketplace/plugins/litcodex/components/comment-checker/package.json +1 -1
  24. package/marketplace/plugins/litcodex/components/git-bash/package.json +1 -1
  25. package/marketplace/plugins/litcodex/components/lit-loop/dist/cli.js +3 -20
  26. package/marketplace/plugins/litcodex/components/lit-loop/dist/codex-hook.js +1 -8
  27. package/marketplace/plugins/litcodex/components/lit-loop/dist/hook-cli.d.ts +2 -1
  28. package/marketplace/plugins/litcodex/components/lit-loop/dist/hook-cli.js +4 -27
  29. package/marketplace/plugins/litcodex/components/lit-loop/dist/markers.d.ts +0 -2
  30. package/marketplace/plugins/litcodex/components/lit-loop/dist/markers.js +0 -2
  31. package/marketplace/plugins/litcodex/components/lit-loop/dist/modes.d.ts +1 -3
  32. package/marketplace/plugins/litcodex/components/lit-loop/dist/modes.js +1 -10
  33. package/marketplace/plugins/litcodex/components/lit-loop/package.json +1 -1
  34. package/marketplace/plugins/litcodex/components/lsp/package.json +1 -1
  35. package/marketplace/plugins/litcodex/components/rules/dist/static-injection.js +2 -2
  36. package/marketplace/plugins/litcodex/components/rules/package.json +1 -1
  37. package/marketplace/plugins/litcodex/components/start-work-continuation/package.json +1 -1
  38. package/marketplace/plugins/litcodex/components/telemetry/package.json +1 -1
  39. package/marketplace/plugins/litcodex/components/wikify-knowledge/package.json +1 -1
  40. package/marketplace/plugins/litcodex/skills/browser-drive/scripts/capability-probe.mjs +13 -5
  41. package/node_modules/@litcodex/lit-loop/README.md +1 -7
  42. package/node_modules/@litcodex/lit-loop/dist/cli.js +3 -20
  43. package/node_modules/@litcodex/lit-loop/dist/codex-hook.js +1 -8
  44. package/node_modules/@litcodex/lit-loop/dist/hook-cli.d.ts +2 -1
  45. package/node_modules/@litcodex/lit-loop/dist/hook-cli.js +4 -27
  46. package/node_modules/@litcodex/lit-loop/dist/markers.d.ts +0 -2
  47. package/node_modules/@litcodex/lit-loop/dist/markers.js +0 -2
  48. package/node_modules/@litcodex/lit-loop/dist/modes.d.ts +1 -3
  49. package/node_modules/@litcodex/lit-loop/dist/modes.js +1 -10
  50. package/node_modules/@litcodex/lit-loop/package.json +1 -1
  51. package/node_modules/@litcodex/lit-loop/skills/browser-drive/scripts/capability-probe.mjs +13 -5
  52. package/package.json +2 -2
  53. package/readme-assets/badge-version.svg +1 -1
  54. package/readme-assets/cover-motion.webp +0 -0
  55. package/marketplace/plugins/litcodex/components/lit-loop/directives/skill-observer.md +0 -105
  56. package/marketplace/plugins/litcodex/components/lit-loop/dist/skill-loop/apply.d.ts +0 -16
  57. package/marketplace/plugins/litcodex/components/lit-loop/dist/skill-loop/apply.js +0 -227
  58. package/marketplace/plugins/litcodex/components/lit-loop/dist/skill-loop/config.d.ts +0 -13
  59. package/marketplace/plugins/litcodex/components/lit-loop/dist/skill-loop/config.js +0 -12
  60. package/marketplace/plugins/litcodex/components/lit-loop/dist/skill-loop/curator.d.ts +0 -14
  61. package/marketplace/plugins/litcodex/components/lit-loop/dist/skill-loop/curator.js +0 -112
  62. package/marketplace/plugins/litcodex/components/lit-loop/dist/skill-loop/hook.d.ts +0 -19
  63. package/marketplace/plugins/litcodex/components/lit-loop/dist/skill-loop/hook.js +0 -435
  64. package/marketplace/plugins/litcodex/components/lit-loop/dist/skill-loop/ownership.d.ts +0 -6
  65. package/marketplace/plugins/litcodex/components/lit-loop/dist/skill-loop/ownership.js +0 -145
  66. package/marketplace/plugins/litcodex/components/lit-loop/dist/skill-loop/paths.d.ts +0 -18
  67. package/marketplace/plugins/litcodex/components/lit-loop/dist/skill-loop/paths.js +0 -43
  68. package/marketplace/plugins/litcodex/components/lit-loop/dist/skill-loop/review.d.ts +0 -28
  69. package/marketplace/plugins/litcodex/components/lit-loop/dist/skill-loop/review.js +0 -702
  70. package/marketplace/plugins/litcodex/components/lit-loop/dist/skill-loop/store.d.ts +0 -32
  71. package/marketplace/plugins/litcodex/components/lit-loop/dist/skill-loop/store.js +0 -667
  72. package/marketplace/plugins/litcodex/components/lit-loop/dist/skill-loop/transaction.d.ts +0 -26
  73. package/marketplace/plugins/litcodex/components/lit-loop/dist/skill-loop/transaction.js +0 -524
  74. package/marketplace/plugins/litcodex/components/lit-loop/dist/skill-loop/types.d.ts +0 -81
  75. package/marketplace/plugins/litcodex/components/lit-loop/dist/skill-loop/types.js +0 -246
  76. package/marketplace/plugins/litcodex/components/lit-loop/dist/skill-loop/usage.d.ts +0 -6
  77. package/marketplace/plugins/litcodex/components/lit-loop/dist/skill-loop/usage.js +0 -119
  78. package/marketplace/plugins/litcodex/components/lit-loop/dist/skill-loop-cli.d.ts +0 -8
  79. package/marketplace/plugins/litcodex/components/lit-loop/dist/skill-loop-cli.js +0 -111
  80. package/marketplace/plugins/litcodex/components/lit-loop/dist/skill-observer-cli.d.ts +0 -3
  81. package/marketplace/plugins/litcodex/components/lit-loop/dist/skill-observer-cli.js +0 -116
  82. package/marketplace/plugins/litcodex/components/lit-loop/dist/skill-observer-route.d.ts +0 -6
  83. package/marketplace/plugins/litcodex/components/lit-loop/dist/skill-observer-route.js +0 -12
  84. package/marketplace/plugins/litcodex/components/lit-loop/dist/skill-observer.d.ts +0 -18
  85. package/marketplace/plugins/litcodex/components/lit-loop/dist/skill-observer.js +0 -946
  86. package/marketplace/plugins/litcodex/skills/skill-observer/SKILL.md +0 -215
  87. package/marketplace/plugins/litcodex/skills/skill-observer/agents/openai.yaml +0 -6
  88. package/marketplace/plugins/litcodex/skills/skill-observer/references/review-contract.md +0 -77
  89. package/node_modules/@litcodex/lit-loop/directives/skill-observer.md +0 -105
  90. package/node_modules/@litcodex/lit-loop/dist/skill-loop/apply.d.ts +0 -16
  91. package/node_modules/@litcodex/lit-loop/dist/skill-loop/apply.js +0 -227
  92. package/node_modules/@litcodex/lit-loop/dist/skill-loop/config.d.ts +0 -13
  93. package/node_modules/@litcodex/lit-loop/dist/skill-loop/config.js +0 -12
  94. package/node_modules/@litcodex/lit-loop/dist/skill-loop/curator.d.ts +0 -14
  95. package/node_modules/@litcodex/lit-loop/dist/skill-loop/curator.js +0 -112
  96. package/node_modules/@litcodex/lit-loop/dist/skill-loop/hook.d.ts +0 -19
  97. package/node_modules/@litcodex/lit-loop/dist/skill-loop/hook.js +0 -435
  98. package/node_modules/@litcodex/lit-loop/dist/skill-loop/ownership.d.ts +0 -6
  99. package/node_modules/@litcodex/lit-loop/dist/skill-loop/ownership.js +0 -145
  100. package/node_modules/@litcodex/lit-loop/dist/skill-loop/paths.d.ts +0 -18
  101. package/node_modules/@litcodex/lit-loop/dist/skill-loop/paths.js +0 -43
  102. package/node_modules/@litcodex/lit-loop/dist/skill-loop/review.d.ts +0 -28
  103. package/node_modules/@litcodex/lit-loop/dist/skill-loop/review.js +0 -702
  104. package/node_modules/@litcodex/lit-loop/dist/skill-loop/store.d.ts +0 -32
  105. package/node_modules/@litcodex/lit-loop/dist/skill-loop/store.js +0 -667
  106. package/node_modules/@litcodex/lit-loop/dist/skill-loop/transaction.d.ts +0 -26
  107. package/node_modules/@litcodex/lit-loop/dist/skill-loop/transaction.js +0 -524
  108. package/node_modules/@litcodex/lit-loop/dist/skill-loop/types.d.ts +0 -81
  109. package/node_modules/@litcodex/lit-loop/dist/skill-loop/types.js +0 -246
  110. package/node_modules/@litcodex/lit-loop/dist/skill-loop/usage.d.ts +0 -6
  111. package/node_modules/@litcodex/lit-loop/dist/skill-loop/usage.js +0 -119
  112. package/node_modules/@litcodex/lit-loop/dist/skill-loop-cli.d.ts +0 -8
  113. package/node_modules/@litcodex/lit-loop/dist/skill-loop-cli.js +0 -111
  114. package/node_modules/@litcodex/lit-loop/dist/skill-observer-cli.d.ts +0 -3
  115. package/node_modules/@litcodex/lit-loop/dist/skill-observer-cli.js +0 -116
  116. package/node_modules/@litcodex/lit-loop/dist/skill-observer-route.d.ts +0 -6
  117. package/node_modules/@litcodex/lit-loop/dist/skill-observer-route.js +0 -12
  118. package/node_modules/@litcodex/lit-loop/dist/skill-observer.d.ts +0 -18
  119. package/node_modules/@litcodex/lit-loop/dist/skill-observer.js +0 -946
  120. package/node_modules/@litcodex/lit-loop/skills/skill-observer/SKILL.md +0 -215
  121. package/node_modules/@litcodex/lit-loop/skills/skill-observer/references/review-contract.md +0 -77
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@litcodex/git-bash",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "description": "LitCodex Git-Bash hook: reminds Windows sessions to prefer the git_bash MCP before the built-in shell.",
5
5
  "type": "module",
6
6
  "private": true,
@@ -2,7 +2,7 @@
2
2
  // src/cli.ts — M06-owned component bin dispatcher (A2 §3/§6.4, A3 addendum A1).
3
3
  //
4
4
  // Bin `litcodex-lit-loop` → dist/cli.js, the target the aggregate hooks.json invokes. Knows exactly
5
- // three route prefixes — `hook`, `loop`, and `observer` — and NO `config` route (config migration is
5
+ // two route prefixes — `hook` and `loop` — and NO `config` route (config migration is
6
6
  // owned by the separate litcodex-ai installer bin, not this dispatcher).
7
7
  //
8
8
  // Exit-code table (A3 addendum A1.2):
@@ -14,10 +14,8 @@
14
14
  //
15
15
  // `main` NEVER calls process.exit (the shebang wrapper does); it resolves exactly one integer, so
16
16
  // the dispatcher is unit-testable with an injected argv array.
17
- import { runPreToolUseCreateGoalGuardCli, runStopSkillReviewHookCli, runUserPromptSubmitHookCli } from "./hook-cli.js";
17
+ import { runPreToolUseCreateGoalGuardCli, runStopPlanPersistenceHookCli, runUserPromptSubmitHookCli, } from "./hook-cli.js";
18
18
  import { loopCommand } from "./loop-cli.js";
19
- import { skillLoopCommand } from "./skill-loop-cli.js";
20
- import { runSkillObserverCli } from "./skill-observer-cli.js";
21
19
  const UNKNOWN_COMMAND = "lit-loop: unknown command\n";
22
20
  /**
23
21
  * Dispatch one argv vector to a route and resolve its exit code. Pure of process.exit; writes only
@@ -32,7 +30,7 @@ export async function main(argv, stdin, stdout, stderr) {
32
30
  if (subcommand === "pre-tool-use")
33
31
  return runPreToolUseCreateGoalGuardCli(stdin, stdout, stderr);
34
32
  if (subcommand === "stop")
35
- return runStopSkillReviewHookCli(stdin, stdout, stderr);
33
+ return runStopPlanPersistenceHookCli(stdin, stdout, stderr);
36
34
  stderr.write(UNKNOWN_COMMAND);
37
35
  return 1;
38
36
  }
@@ -41,21 +39,6 @@ export async function main(argv, stdin, stdout, stderr) {
41
39
  // and never calls process.exit. The `doctor` subcommand is still the M09 stub until M11/T16.
42
40
  return loopCommand(argv.slice(3), { stdout, stderr, stdin });
43
41
  }
44
- if (command === "observer") {
45
- if (argv.length !== 3) {
46
- stderr.write(UNKNOWN_COMMAND);
47
- return 1;
48
- }
49
- return runSkillObserverCli(stdin, stdout, stderr);
50
- }
51
- if (command === "skill-loop") {
52
- return skillLoopCommand(argv.slice(3), {
53
- cwd: process.cwd(),
54
- env: process.env,
55
- stdout,
56
- stderr,
57
- });
58
- }
59
42
  stderr.write(UNKNOWN_COMMAND);
60
43
  return 1;
61
44
  }
@@ -21,9 +21,8 @@ import { isExactBrowserDrivePrompt, shouldSuppressBrowserDriveInjection } from "
21
21
  import { LitLoopDirectiveError, loadDirectiveWithSkillBodyFrom, loadSkillInvocationContext } from "./directive.js";
22
22
  import { hasContextPressureMarker, shouldSuppressInjection, transcriptHasContextPressureMarker, transcriptHasDirectiveMarker, } from "./guards.js";
23
23
  import { isExactBareHandoffPrompt, shouldSuppressHandoffInjection } from "./handoff-route.js";
24
- import { BROWSER_DRIVE_MODE_SPEC, HANDOFF_MODE_SPEC, modeForToken, resolveSkillPath, SCIENTIFIC_VISUALIZATION_MODE_SPEC, SKILL_OBSERVER_MODE_SPEC, } from "./modes.js";
24
+ import { BROWSER_DRIVE_MODE_SPEC, HANDOFF_MODE_SPEC, modeForToken, resolveSkillPath, SCIENTIFIC_VISUALIZATION_MODE_SPEC, } from "./modes.js";
25
25
  import { isExactBareScientificVisualizationPrompt, isScientificVisualizationWhitespaceNearMiss, shouldSuppressScientificVisualizationInjection, } from "./scientific-visualization-route.js";
26
- import { isExactSkillObserverPrompt, shouldSuppressSkillObserverInjection } from "./skill-observer-route.js";
27
26
  import { matchRenamedSkillInvocation, skillRenameNote } from "./skill-renames.js";
28
27
  import { maskMarkdownCode, matchLitTrigger } from "./trigger.js";
29
28
  const HOOK_EVENT_NAME = "UserPromptSubmit";
@@ -200,12 +199,6 @@ export function runUserPromptSubmitHook(input) {
200
199
  const stdout = formatAdditionalContextOutput(loadDirectiveForModeFailSilent(BROWSER_DRIVE_MODE_SPEC));
201
200
  return stdout === "" ? { kind: "noop" } : { kind: "inject", stdout };
202
201
  }
203
- if (isExactSkillObserverPrompt(input.prompt)) {
204
- if (shouldSuppressSkillObserverInjection(transcriptPath))
205
- return { kind: "noop" };
206
- const stdout = formatAdditionalContextOutput(loadDirectiveForModeFailSilent(SKILL_OBSERVER_MODE_SPEC));
207
- return stdout === "" ? { kind: "noop" } : { kind: "inject", stdout };
208
- }
209
202
  if (isScientificVisualizationWhitespaceNearMiss(input.prompt))
210
203
  return { kind: "noop" };
211
204
  // Guard 0 / routing: which bounded lit-family token matched → which mode + directive.
@@ -15,5 +15,6 @@ export type LitHookErrorCode = "LIT_HOOK_STDIN_INVALID_JSON" | "LIT_HOOK_STDIN_T
15
15
  * line to stderr on malformed / oversized stdin.
16
16
  */
17
17
  export declare function runUserPromptSubmitHookCli(stdin: NodeJS.ReadableStream, stdout: NodeJS.WritableStream, stderr: NodeJS.WritableStream, repoRoot?: string): Promise<number>;
18
- export declare function runStopSkillReviewHookCli(stdin: NodeJS.ReadableStream, stdout: NodeJS.WritableStream, stderr: NodeJS.WritableStream, repoRoot?: string): Promise<number>;
18
+ /** Enforce lit-plan persistence when a Stop hook event arrives. */
19
+ export declare function runStopPlanPersistenceHookCli(stdin: NodeJS.ReadableStream, stdout: NodeJS.WritableStream, stderr: NodeJS.WritableStream, repoRoot?: string): Promise<number>;
19
20
  export declare function runPreToolUseCreateGoalGuardCli(stdin: NodeJS.ReadableStream, stdout: NodeJS.WritableStream, stderr: NodeJS.WritableStream): Promise<number>;
@@ -7,9 +7,8 @@
7
7
  // machine-readable LitHookError JSON line on stderr. NEVER calls process.exit (the dispatcher does)
8
8
  // and NEVER throws.
9
9
  import { isAbsolute } from "node:path";
10
- import { applyPreToolUseCreateGoalGuard, formatAdditionalContextOutput, isLitUserPromptSubmitInput, runUserPromptSubmitHook, } from "./codex-hook.js";
10
+ import { applyPreToolUseCreateGoalGuard, runUserPromptSubmitHook } from "./codex-hook.js";
11
11
  import { evaluatePlanPersistence, formatStopBlockOutput, recordLitPlanActivation } from "./plan-persistence.js";
12
- import { markPendingReviews, pendingReviewNotice } from "./skill-loop/hook.js";
13
12
  /** Hard cap on stdin to bound memory / ReDoS exposure inside the 5 s Codex hook budget. 8 MB. */
14
13
  export const MAX_STDIN_BYTES = 8_000_000;
15
14
  const INVALID_JSON_MESSAGE = "lit hook: stdin was not valid JSON";
@@ -95,25 +94,8 @@ export async function runUserPromptSubmitHookCli(stdin, stdout, stderr, repoRoot
95
94
  if (scope !== null)
96
95
  recordLitPlanActivation(scope.cwd, scope.sessionId);
97
96
  }
98
- let notice = null;
99
- if (isLitUserPromptSubmitInput(parsed)) {
100
- try {
101
- notice = pendingReviewNotice(repoRoot);
102
- }
103
- catch {
104
- // Pending-review surfacing is advisory and may never disable the existing prompt routes.
105
- }
106
- }
107
- if (decision.kind === "inject" && notice !== null) {
108
- const envelope = JSON.parse(decision.stdout);
109
- stdout.write(formatAdditionalContextOutput(`${envelope.hookSpecificOutput.additionalContext}\n\n${notice}`));
110
- }
111
- else if (decision.kind === "inject") {
97
+ if (decision.kind === "inject")
112
98
  stdout.write(decision.stdout);
113
- }
114
- else if (notice !== null) {
115
- stdout.write(formatAdditionalContextOutput(notice));
116
- }
117
99
  return 0;
118
100
  }
119
101
  /** Read `{ session_id, cwd }` from a hook event; `cwd` falls back to `repoRoot` when absent or relative. */
@@ -127,7 +109,8 @@ function hookSessionScope(parsed, repoRoot) {
127
109
  const cwd = record["cwd"];
128
110
  return { sessionId, cwd: typeof cwd === "string" && isAbsolute(cwd) ? cwd : repoRoot };
129
111
  }
130
- export async function runStopSkillReviewHookCli(stdin, stdout, stderr, repoRoot = process.cwd()) {
112
+ /** Enforce lit-plan persistence when a Stop hook event arrives. */
113
+ export async function runStopPlanPersistenceHookCli(stdin, stdout, stderr, repoRoot = process.cwd()) {
131
114
  const decoded = await readStdin(stdin);
132
115
  if (decoded === null) {
133
116
  stderr.write(errorLine("LIT_HOOK_STDIN_TOO_LARGE", TOO_LARGE_MESSAGE));
@@ -146,12 +129,6 @@ export async function runStopSkillReviewHookCli(stdin, stdout, stderr, repoRoot
146
129
  stderr.write(errorLine("LIT_HOOK_STDIN_INVALID_JSON", INVALID_JSON_MESSAGE));
147
130
  return 2;
148
131
  }
149
- try {
150
- markPendingReviews(repoRoot, parsed, { env: process.env });
151
- }
152
- catch {
153
- // Pending-review marking is advisory and never blocks the existing start-work handler.
154
- }
155
132
  const scope = hookSessionScope(parsed, repoRoot);
156
133
  if (scope !== null) {
157
134
  const persistence = evaluatePlanPersistence(scope.cwd, scope.sessionId);
@@ -26,8 +26,6 @@ export declare const SCIENTIFIC_VISUALIZATION_DIRECTIVE_MARKER: "<lit-scientific
26
26
  export declare const SCIENTIFIC_VISUALIZATION_DIRECTIVE_CLOSE: "</lit-scientific-visualization-mode>";
27
27
  export declare const BROWSER_DRIVE_DIRECTIVE_MARKER: "<browser-drive-mode>";
28
28
  export declare const BROWSER_DRIVE_DIRECTIVE_CLOSE: "</browser-drive-mode>";
29
- export declare const SKILL_OBSERVER_DIRECTIVE_MARKER: "<skill-observer-mode>";
30
- export declare const SKILL_OBSERVER_DIRECTIVE_CLOSE: "</skill-observer-mode>";
31
29
  export declare const LIT_COMPREHEND_DIRECTIVE_MARKER: "<lit-comprehend-mode>";
32
30
  export declare const LIT_COMPREHEND_DIRECTIVE_CLOSE: "</lit-comprehend-mode>";
33
31
  export type LitLoopDirectiveMarker = typeof LIT_LOOP_DIRECTIVE_MARKER;
@@ -32,7 +32,5 @@ export const SCIENTIFIC_VISUALIZATION_DIRECTIVE_MARKER = "<lit-scientific-visual
32
32
  export const SCIENTIFIC_VISUALIZATION_DIRECTIVE_CLOSE = "</lit-scientific-visualization-mode>";
33
33
  export const BROWSER_DRIVE_DIRECTIVE_MARKER = "<browser-drive-mode>";
34
34
  export const BROWSER_DRIVE_DIRECTIVE_CLOSE = "</browser-drive-mode>";
35
- export const SKILL_OBSERVER_DIRECTIVE_MARKER = "<skill-observer-mode>";
36
- export const SKILL_OBSERVER_DIRECTIVE_CLOSE = "</skill-observer-mode>";
37
35
  export const LIT_COMPREHEND_DIRECTIVE_MARKER = "<lit-comprehend-mode>";
38
36
  export const LIT_COMPREHEND_DIRECTIVE_CLOSE = "</lit-comprehend-mode>";
@@ -1,7 +1,7 @@
1
1
  import type { RenamedSkillId } from "./skill-renames.js";
2
2
  import type { LitTriggerToken } from "./trigger.js";
3
3
  /** Lit-family modes. Multiple tokens may map to one mode (lit/litcodex/lit-loop → lit-loop). */
4
- export type LitMode = RenamedSkillId | "browser-drive" | "skill-observer" | "lit-handoff" | "lit-scientific-visualization" | "deep-interview" | "lit-crucible" | "lit-init" | "lit-loop" | "litwork" | "lit-plan" | "litgoal" | "review-work" | "litresearch" | "start-work" | "lit-recap" | "lit-comprehend";
4
+ export type LitMode = RenamedSkillId | "browser-drive" | "lit-handoff" | "lit-scientific-visualization" | "deep-interview" | "lit-crucible" | "lit-init" | "lit-loop" | "litwork" | "lit-plan" | "litgoal" | "review-work" | "litresearch" | "start-work" | "lit-recap" | "lit-comprehend";
5
5
  /** Per-mode routing spec: its marker pair (guard) + resolved directive path (loader). */
6
6
  export interface LitModeSpec {
7
7
  readonly mode: LitMode;
@@ -21,8 +21,6 @@ export declare const HANDOFF_MODE_SPEC: LitModeSpec;
21
21
  export declare const SCIENTIFIC_VISUALIZATION_MODE_SPEC: LitModeSpec;
22
22
  /** Exact browser-drive and `$litcodex:browser-drive` are standalone routes outside token matching. */
23
23
  export declare const BROWSER_DRIVE_MODE_SPEC: LitModeSpec;
24
- /** Exact skill-observer and `$litcodex:skill-observer` are standalone routes. */
25
- export declare const SKILL_OBSERVER_MODE_SPEC: LitModeSpec;
26
24
  /** Token → mode spec. Frozen; the single source the hook router branches on. */
27
25
  export declare const MODE_BY_TOKEN: Readonly<Record<LitTriggerToken, LitModeSpec>>;
28
26
  /** The mode spec for a matched token. Total over the token union (every token has a spec). */
@@ -15,7 +15,7 @@
15
15
  // Imports markers + the trigger token type only (no cycle: hook → modes → {markers, trigger}).
16
16
  import { existsSync } from "node:fs";
17
17
  import { fileURLToPath } from "node:url";
18
- import { BROWSER_DRIVE_DIRECTIVE_CLOSE, BROWSER_DRIVE_DIRECTIVE_MARKER, DEEP_INTERVIEW_DIRECTIVE_CLOSE, DEEP_INTERVIEW_DIRECTIVE_MARKER, HANDOFF_DIRECTIVE_CLOSE, HANDOFF_DIRECTIVE_MARKER, LIT_COMPREHEND_DIRECTIVE_CLOSE, LIT_COMPREHEND_DIRECTIVE_MARKER, LIT_CRUCIBLE_DIRECTIVE_CLOSE, LIT_CRUCIBLE_DIRECTIVE_MARKER, LIT_INIT_DIRECTIVE_CLOSE, LIT_INIT_DIRECTIVE_MARKER, LIT_LOOP_DIRECTIVE_CLOSE, LIT_LOOP_DIRECTIVE_MARKER, LIT_PLAN_DIRECTIVE_CLOSE, LIT_PLAN_DIRECTIVE_MARKER, LIT_RECAP_DIRECTIVE_CLOSE, LIT_RECAP_DIRECTIVE_MARKER, LITGOAL_DIRECTIVE_CLOSE, LITGOAL_DIRECTIVE_MARKER, LITRESEARCH_DIRECTIVE_CLOSE, LITRESEARCH_DIRECTIVE_MARKER, LITWORK_DIRECTIVE_CLOSE, LITWORK_DIRECTIVE_MARKER, REVIEW_WORK_DIRECTIVE_CLOSE, REVIEW_WORK_DIRECTIVE_MARKER, SCIENTIFIC_VISUALIZATION_DIRECTIVE_CLOSE, SCIENTIFIC_VISUALIZATION_DIRECTIVE_MARKER, SKILL_OBSERVER_DIRECTIVE_CLOSE, SKILL_OBSERVER_DIRECTIVE_MARKER, START_WORK_DIRECTIVE_CLOSE, START_WORK_DIRECTIVE_MARKER, } from "./markers.js";
18
+ import { BROWSER_DRIVE_DIRECTIVE_CLOSE, BROWSER_DRIVE_DIRECTIVE_MARKER, DEEP_INTERVIEW_DIRECTIVE_CLOSE, DEEP_INTERVIEW_DIRECTIVE_MARKER, HANDOFF_DIRECTIVE_CLOSE, HANDOFF_DIRECTIVE_MARKER, LIT_COMPREHEND_DIRECTIVE_CLOSE, LIT_COMPREHEND_DIRECTIVE_MARKER, LIT_CRUCIBLE_DIRECTIVE_CLOSE, LIT_CRUCIBLE_DIRECTIVE_MARKER, LIT_INIT_DIRECTIVE_CLOSE, LIT_INIT_DIRECTIVE_MARKER, LIT_LOOP_DIRECTIVE_CLOSE, LIT_LOOP_DIRECTIVE_MARKER, LIT_PLAN_DIRECTIVE_CLOSE, LIT_PLAN_DIRECTIVE_MARKER, LIT_RECAP_DIRECTIVE_CLOSE, LIT_RECAP_DIRECTIVE_MARKER, LITGOAL_DIRECTIVE_CLOSE, LITGOAL_DIRECTIVE_MARKER, LITRESEARCH_DIRECTIVE_CLOSE, LITRESEARCH_DIRECTIVE_MARKER, LITWORK_DIRECTIVE_CLOSE, LITWORK_DIRECTIVE_MARKER, REVIEW_WORK_DIRECTIVE_CLOSE, REVIEW_WORK_DIRECTIVE_MARKER, SCIENTIFIC_VISUALIZATION_DIRECTIVE_CLOSE, SCIENTIFIC_VISUALIZATION_DIRECTIVE_MARKER, START_WORK_DIRECTIVE_CLOSE, START_WORK_DIRECTIVE_MARKER, } from "./markers.js";
19
19
  /** Resolve a path relative to this module (percent-decoding, space/#/Hangul-safe). */
20
20
  function resolveFromHere(rel) {
21
21
  return fileURLToPath(new URL(rel, import.meta.url));
@@ -67,15 +67,6 @@ export const BROWSER_DRIVE_MODE_SPEC = Object.freeze({
67
67
  skillName: "browser-drive",
68
68
  skillPath: resolveSkillPath("browser-drive"),
69
69
  });
70
- /** Exact skill-observer and `$litcodex:skill-observer` are standalone routes. */
71
- export const SKILL_OBSERVER_MODE_SPEC = Object.freeze({
72
- mode: "skill-observer",
73
- openMarker: SKILL_OBSERVER_DIRECTIVE_MARKER,
74
- closeMarker: SKILL_OBSERVER_DIRECTIVE_CLOSE,
75
- directivePath: resolveFromHere("../directives/skill-observer.md"),
76
- skillName: "skill-observer",
77
- skillPath: resolveSkillPath("skill-observer"),
78
- });
79
70
  /** Token → mode spec. Frozen; the single source the hook router branches on. */
80
71
  export const MODE_BY_TOKEN = Object.freeze({
81
72
  "lit-crucible": Object.freeze({
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@litcodex/lit-loop",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "description": "LitCodex Lit-Loop runtime: durable repo-native multi-goal orchestration with embedded success criteria and observable evidence audit.",
5
5
  "type": "module",
6
6
  "private": true,
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@litcodex/lsp",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "description": "LitCodex LSP hook (inert placeholder): post-edit diagnostics + cache reset, no-op until an LSP daemon is provided.",
5
5
  "type": "module",
6
6
  "private": true,
@@ -94,13 +94,13 @@ function runPostCompactRecovery(input) {
94
94
  }
95
95
  const fullBodyRules = missingRules.filter((rule) => isNeverTruncatedRule(ruleDisplayPath(rule)));
96
96
  const listedRules = missingRules.filter((rule) => !isNeverTruncatedRule(ruleDisplayPath(rule)));
97
- const directiveCandidate = buildPostCompactReadDirective([...listedRules.map((rule) => rule.path), ...dynamicRulePaths], effectiveConfig.maxResultChars);
97
+ const formatted = fullBodyRules.length === 0 ? { block: "", rules: [] } : engine.formatStaticResult(fullBodyRules);
98
+ const directiveCandidate = buildPostCompactReadDirective([...listedRules.map((rule) => rule.path), ...dynamicRulePaths], Math.max(0, effectiveConfig.maxResultChars - (fullBodyRules.length > 0 ? 2 : 0)));
98
99
  const directiveBudget = withOptionalContextBudget(effectiveConfig, [directiveCandidate], fullBodyRules.length > 0);
99
100
  Object.assign(effectiveConfig, directiveBudget.config);
100
101
  const directive = directiveBudget.blocks[0] ?? "";
101
102
  const contextBudget = withOptionalContextBudget(effectiveConfig, [shellAwareness, outputStyle], fullBodyRules.length > 0 || directive.length > 0);
102
103
  Object.assign(effectiveConfig, contextBudget.config);
103
- const formatted = fullBodyRules.length === 0 ? { block: "", rules: [] } : engine.formatStaticResult(fullBodyRules);
104
104
  const combinedContext = combineStaticContext(formatted.block, directive, ...contextBudget.blocks);
105
105
  const deliveredContext = prepareAdditionalContext(combinedContext);
106
106
  const formattedDelivered = formatted.block.length > 0 && deliveredContext.startsWith(formatted.block.trim());
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@litcodex/rules",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "description": "LitCodex rules: injects project rule files (AGENTS.md etc.) into model context through lifecycle hooks.",
5
5
  "type": "module",
6
6
  "private": true,
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@litcodex/start-work-continuation",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "description": "LitCodex Start-Work continuation hook: resumes in-flight start-work state on root Stop.",
5
5
  "type": "module",
6
6
  "private": true,
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@litcodex/telemetry",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "description": "LitCodex telemetry: a deliberately inert, local-only SessionStart hook (NO network, NO data collection).",
5
5
  "type": "module",
6
6
  "private": true,
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@litcodex/wikify-knowledge",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "description": "Local review-gated knowledge records for the LitCodex Wikify surface.",
5
5
  "type": "module",
6
6
  "private": true,
@@ -307,12 +307,19 @@ function unavailable(reason, detail, command = null, version = null) {
307
307
  }
308
308
 
309
309
  function probeUnsafe(options) {
310
- const input = isRecord(options) ? options : {};
310
+ if (!isRecord(options)) {
311
+ return unavailable("probe-error", `${DRIVER_COMMAND} capability probe received malformed input`);
312
+ }
313
+ const input = options;
311
314
  const hasExplicitPath = Object.hasOwn(input, "path");
315
+ if (hasExplicitPath && typeof input.path !== "string") {
316
+ return unavailable("probe-error", `${DRIVER_COMMAND} capability probe received malformed input`);
317
+ }
318
+ if (Object.hasOwn(input, "runCommand") && typeof input.runCommand !== "function") {
319
+ return unavailable("probe-error", `${DRIVER_COMMAND} capability probe received malformed input`);
320
+ }
312
321
  const searchPath = hasExplicitPath
313
- ? typeof input.path === "string"
314
- ? input.path
315
- : ""
322
+ ? input.path
316
323
  : typeof process.env.PATH === "string"
317
324
  ? process.env.PATH
318
325
  : "";
@@ -419,8 +426,9 @@ function probeUnsafe(options) {
419
426
  * @param {unknown} options
420
427
  * @returns {BrowserDriverProbeResult}
421
428
  */
422
- export function probeBrowserDriver(options = {}) {
429
+ export function probeBrowserDriver(options) {
423
430
  try {
431
+ if (arguments.length === 0) options = {};
424
432
  return probeUnsafe(options);
425
433
  } catch {
426
434
  return unavailable(
@@ -14,13 +14,10 @@ autonomous work loop that maintains durable state, verifies progress, checkpoint
14
14
  continues until the work is genuinely done or blocked. The same hook also routes bounded phrases such
15
15
  as `lit plan`, `lit review`, `lit research`, `lit goal`, and `lit start work`; code spans/fences and
16
16
  slash-command-style mentions are ignored except the explicit `/litresearch` research route.
17
- Exact bare `handoff`, `lit-scientific-visualization`, and `skill-observer` prompts are dedicated standalone routes. The
17
+ Exact bare `handoff` and `lit-scientific-visualization` prompts are dedicated standalone routes. The
18
18
  scientific route injects its `<lit-scientific-visualization-mode>` envelope plus the complete bundled
19
19
  adapter, while quoted, fenced, mixed, slash-style, scoped, and near-miss forms remain inert.
20
20
 
21
- The `skill-observer` route injects a proposal-only contract. Its storage module writes only
22
- `.litcodex/skill-observer/observations.jsonl` and never changes a skill file.
23
-
24
21
  ## Loop state
25
22
 
26
23
  Durable state lives under `.litcodex/lit-loop/` in the project:
@@ -44,9 +41,6 @@ Descriptor-dependent Python routes therefore fail closed on Windows with
44
41
 
45
42
  ## Commands
46
43
 
47
- `litcodex observer` records one proposal from bounded JSON on stdin. The command binds the current
48
- working directory as the project root.
49
-
50
44
  `litcodex loop create | status | run | checkpoint | record-evidence | doctor` — see the
51
45
  [repository README](../../../../README.md) for the full loop model.
52
46
 
@@ -2,7 +2,7 @@
2
2
  // src/cli.ts — M06-owned component bin dispatcher (A2 §3/§6.4, A3 addendum A1).
3
3
  //
4
4
  // Bin `litcodex-lit-loop` → dist/cli.js, the target the aggregate hooks.json invokes. Knows exactly
5
- // three route prefixes — `hook`, `loop`, and `observer` — and NO `config` route (config migration is
5
+ // two route prefixes — `hook` and `loop` — and NO `config` route (config migration is
6
6
  // owned by the separate litcodex-ai installer bin, not this dispatcher).
7
7
  //
8
8
  // Exit-code table (A3 addendum A1.2):
@@ -14,10 +14,8 @@
14
14
  //
15
15
  // `main` NEVER calls process.exit (the shebang wrapper does); it resolves exactly one integer, so
16
16
  // the dispatcher is unit-testable with an injected argv array.
17
- import { runPreToolUseCreateGoalGuardCli, runStopSkillReviewHookCli, runUserPromptSubmitHookCli } from "./hook-cli.js";
17
+ import { runPreToolUseCreateGoalGuardCli, runStopPlanPersistenceHookCli, runUserPromptSubmitHookCli, } from "./hook-cli.js";
18
18
  import { loopCommand } from "./loop-cli.js";
19
- import { skillLoopCommand } from "./skill-loop-cli.js";
20
- import { runSkillObserverCli } from "./skill-observer-cli.js";
21
19
  const UNKNOWN_COMMAND = "lit-loop: unknown command\n";
22
20
  /**
23
21
  * Dispatch one argv vector to a route and resolve its exit code. Pure of process.exit; writes only
@@ -32,7 +30,7 @@ export async function main(argv, stdin, stdout, stderr) {
32
30
  if (subcommand === "pre-tool-use")
33
31
  return runPreToolUseCreateGoalGuardCli(stdin, stdout, stderr);
34
32
  if (subcommand === "stop")
35
- return runStopSkillReviewHookCli(stdin, stdout, stderr);
33
+ return runStopPlanPersistenceHookCli(stdin, stdout, stderr);
36
34
  stderr.write(UNKNOWN_COMMAND);
37
35
  return 1;
38
36
  }
@@ -41,21 +39,6 @@ export async function main(argv, stdin, stdout, stderr) {
41
39
  // and never calls process.exit. The `doctor` subcommand is still the M09 stub until M11/T16.
42
40
  return loopCommand(argv.slice(3), { stdout, stderr, stdin });
43
41
  }
44
- if (command === "observer") {
45
- if (argv.length !== 3) {
46
- stderr.write(UNKNOWN_COMMAND);
47
- return 1;
48
- }
49
- return runSkillObserverCli(stdin, stdout, stderr);
50
- }
51
- if (command === "skill-loop") {
52
- return skillLoopCommand(argv.slice(3), {
53
- cwd: process.cwd(),
54
- env: process.env,
55
- stdout,
56
- stderr,
57
- });
58
- }
59
42
  stderr.write(UNKNOWN_COMMAND);
60
43
  return 1;
61
44
  }
@@ -21,9 +21,8 @@ import { isExactBrowserDrivePrompt, shouldSuppressBrowserDriveInjection } from "
21
21
  import { LitLoopDirectiveError, loadDirectiveWithSkillBodyFrom, loadSkillInvocationContext } from "./directive.js";
22
22
  import { hasContextPressureMarker, shouldSuppressInjection, transcriptHasContextPressureMarker, transcriptHasDirectiveMarker, } from "./guards.js";
23
23
  import { isExactBareHandoffPrompt, shouldSuppressHandoffInjection } from "./handoff-route.js";
24
- import { BROWSER_DRIVE_MODE_SPEC, HANDOFF_MODE_SPEC, modeForToken, resolveSkillPath, SCIENTIFIC_VISUALIZATION_MODE_SPEC, SKILL_OBSERVER_MODE_SPEC, } from "./modes.js";
24
+ import { BROWSER_DRIVE_MODE_SPEC, HANDOFF_MODE_SPEC, modeForToken, resolveSkillPath, SCIENTIFIC_VISUALIZATION_MODE_SPEC, } from "./modes.js";
25
25
  import { isExactBareScientificVisualizationPrompt, isScientificVisualizationWhitespaceNearMiss, shouldSuppressScientificVisualizationInjection, } from "./scientific-visualization-route.js";
26
- import { isExactSkillObserverPrompt, shouldSuppressSkillObserverInjection } from "./skill-observer-route.js";
27
26
  import { matchRenamedSkillInvocation, skillRenameNote } from "./skill-renames.js";
28
27
  import { maskMarkdownCode, matchLitTrigger } from "./trigger.js";
29
28
  const HOOK_EVENT_NAME = "UserPromptSubmit";
@@ -200,12 +199,6 @@ export function runUserPromptSubmitHook(input) {
200
199
  const stdout = formatAdditionalContextOutput(loadDirectiveForModeFailSilent(BROWSER_DRIVE_MODE_SPEC));
201
200
  return stdout === "" ? { kind: "noop" } : { kind: "inject", stdout };
202
201
  }
203
- if (isExactSkillObserverPrompt(input.prompt)) {
204
- if (shouldSuppressSkillObserverInjection(transcriptPath))
205
- return { kind: "noop" };
206
- const stdout = formatAdditionalContextOutput(loadDirectiveForModeFailSilent(SKILL_OBSERVER_MODE_SPEC));
207
- return stdout === "" ? { kind: "noop" } : { kind: "inject", stdout };
208
- }
209
202
  if (isScientificVisualizationWhitespaceNearMiss(input.prompt))
210
203
  return { kind: "noop" };
211
204
  // Guard 0 / routing: which bounded lit-family token matched → which mode + directive.
@@ -15,5 +15,6 @@ export type LitHookErrorCode = "LIT_HOOK_STDIN_INVALID_JSON" | "LIT_HOOK_STDIN_T
15
15
  * line to stderr on malformed / oversized stdin.
16
16
  */
17
17
  export declare function runUserPromptSubmitHookCli(stdin: NodeJS.ReadableStream, stdout: NodeJS.WritableStream, stderr: NodeJS.WritableStream, repoRoot?: string): Promise<number>;
18
- export declare function runStopSkillReviewHookCli(stdin: NodeJS.ReadableStream, stdout: NodeJS.WritableStream, stderr: NodeJS.WritableStream, repoRoot?: string): Promise<number>;
18
+ /** Enforce lit-plan persistence when a Stop hook event arrives. */
19
+ export declare function runStopPlanPersistenceHookCli(stdin: NodeJS.ReadableStream, stdout: NodeJS.WritableStream, stderr: NodeJS.WritableStream, repoRoot?: string): Promise<number>;
19
20
  export declare function runPreToolUseCreateGoalGuardCli(stdin: NodeJS.ReadableStream, stdout: NodeJS.WritableStream, stderr: NodeJS.WritableStream): Promise<number>;
@@ -7,9 +7,8 @@
7
7
  // machine-readable LitHookError JSON line on stderr. NEVER calls process.exit (the dispatcher does)
8
8
  // and NEVER throws.
9
9
  import { isAbsolute } from "node:path";
10
- import { applyPreToolUseCreateGoalGuard, formatAdditionalContextOutput, isLitUserPromptSubmitInput, runUserPromptSubmitHook, } from "./codex-hook.js";
10
+ import { applyPreToolUseCreateGoalGuard, runUserPromptSubmitHook } from "./codex-hook.js";
11
11
  import { evaluatePlanPersistence, formatStopBlockOutput, recordLitPlanActivation } from "./plan-persistence.js";
12
- import { markPendingReviews, pendingReviewNotice } from "./skill-loop/hook.js";
13
12
  /** Hard cap on stdin to bound memory / ReDoS exposure inside the 5 s Codex hook budget. 8 MB. */
14
13
  export const MAX_STDIN_BYTES = 8_000_000;
15
14
  const INVALID_JSON_MESSAGE = "lit hook: stdin was not valid JSON";
@@ -95,25 +94,8 @@ export async function runUserPromptSubmitHookCli(stdin, stdout, stderr, repoRoot
95
94
  if (scope !== null)
96
95
  recordLitPlanActivation(scope.cwd, scope.sessionId);
97
96
  }
98
- let notice = null;
99
- if (isLitUserPromptSubmitInput(parsed)) {
100
- try {
101
- notice = pendingReviewNotice(repoRoot);
102
- }
103
- catch {
104
- // Pending-review surfacing is advisory and may never disable the existing prompt routes.
105
- }
106
- }
107
- if (decision.kind === "inject" && notice !== null) {
108
- const envelope = JSON.parse(decision.stdout);
109
- stdout.write(formatAdditionalContextOutput(`${envelope.hookSpecificOutput.additionalContext}\n\n${notice}`));
110
- }
111
- else if (decision.kind === "inject") {
97
+ if (decision.kind === "inject")
112
98
  stdout.write(decision.stdout);
113
- }
114
- else if (notice !== null) {
115
- stdout.write(formatAdditionalContextOutput(notice));
116
- }
117
99
  return 0;
118
100
  }
119
101
  /** Read `{ session_id, cwd }` from a hook event; `cwd` falls back to `repoRoot` when absent or relative. */
@@ -127,7 +109,8 @@ function hookSessionScope(parsed, repoRoot) {
127
109
  const cwd = record["cwd"];
128
110
  return { sessionId, cwd: typeof cwd === "string" && isAbsolute(cwd) ? cwd : repoRoot };
129
111
  }
130
- export async function runStopSkillReviewHookCli(stdin, stdout, stderr, repoRoot = process.cwd()) {
112
+ /** Enforce lit-plan persistence when a Stop hook event arrives. */
113
+ export async function runStopPlanPersistenceHookCli(stdin, stdout, stderr, repoRoot = process.cwd()) {
131
114
  const decoded = await readStdin(stdin);
132
115
  if (decoded === null) {
133
116
  stderr.write(errorLine("LIT_HOOK_STDIN_TOO_LARGE", TOO_LARGE_MESSAGE));
@@ -146,12 +129,6 @@ export async function runStopSkillReviewHookCli(stdin, stdout, stderr, repoRoot
146
129
  stderr.write(errorLine("LIT_HOOK_STDIN_INVALID_JSON", INVALID_JSON_MESSAGE));
147
130
  return 2;
148
131
  }
149
- try {
150
- markPendingReviews(repoRoot, parsed, { env: process.env });
151
- }
152
- catch {
153
- // Pending-review marking is advisory and never blocks the existing start-work handler.
154
- }
155
132
  const scope = hookSessionScope(parsed, repoRoot);
156
133
  if (scope !== null) {
157
134
  const persistence = evaluatePlanPersistence(scope.cwd, scope.sessionId);
@@ -26,8 +26,6 @@ export declare const SCIENTIFIC_VISUALIZATION_DIRECTIVE_MARKER: "<lit-scientific
26
26
  export declare const SCIENTIFIC_VISUALIZATION_DIRECTIVE_CLOSE: "</lit-scientific-visualization-mode>";
27
27
  export declare const BROWSER_DRIVE_DIRECTIVE_MARKER: "<browser-drive-mode>";
28
28
  export declare const BROWSER_DRIVE_DIRECTIVE_CLOSE: "</browser-drive-mode>";
29
- export declare const SKILL_OBSERVER_DIRECTIVE_MARKER: "<skill-observer-mode>";
30
- export declare const SKILL_OBSERVER_DIRECTIVE_CLOSE: "</skill-observer-mode>";
31
29
  export declare const LIT_COMPREHEND_DIRECTIVE_MARKER: "<lit-comprehend-mode>";
32
30
  export declare const LIT_COMPREHEND_DIRECTIVE_CLOSE: "</lit-comprehend-mode>";
33
31
  export type LitLoopDirectiveMarker = typeof LIT_LOOP_DIRECTIVE_MARKER;
@@ -32,7 +32,5 @@ export const SCIENTIFIC_VISUALIZATION_DIRECTIVE_MARKER = "<lit-scientific-visual
32
32
  export const SCIENTIFIC_VISUALIZATION_DIRECTIVE_CLOSE = "</lit-scientific-visualization-mode>";
33
33
  export const BROWSER_DRIVE_DIRECTIVE_MARKER = "<browser-drive-mode>";
34
34
  export const BROWSER_DRIVE_DIRECTIVE_CLOSE = "</browser-drive-mode>";
35
- export const SKILL_OBSERVER_DIRECTIVE_MARKER = "<skill-observer-mode>";
36
- export const SKILL_OBSERVER_DIRECTIVE_CLOSE = "</skill-observer-mode>";
37
35
  export const LIT_COMPREHEND_DIRECTIVE_MARKER = "<lit-comprehend-mode>";
38
36
  export const LIT_COMPREHEND_DIRECTIVE_CLOSE = "</lit-comprehend-mode>";
@@ -1,7 +1,7 @@
1
1
  import type { RenamedSkillId } from "./skill-renames.js";
2
2
  import type { LitTriggerToken } from "./trigger.js";
3
3
  /** Lit-family modes. Multiple tokens may map to one mode (lit/litcodex/lit-loop → lit-loop). */
4
- export type LitMode = RenamedSkillId | "browser-drive" | "skill-observer" | "lit-handoff" | "lit-scientific-visualization" | "deep-interview" | "lit-crucible" | "lit-init" | "lit-loop" | "litwork" | "lit-plan" | "litgoal" | "review-work" | "litresearch" | "start-work" | "lit-recap" | "lit-comprehend";
4
+ export type LitMode = RenamedSkillId | "browser-drive" | "lit-handoff" | "lit-scientific-visualization" | "deep-interview" | "lit-crucible" | "lit-init" | "lit-loop" | "litwork" | "lit-plan" | "litgoal" | "review-work" | "litresearch" | "start-work" | "lit-recap" | "lit-comprehend";
5
5
  /** Per-mode routing spec: its marker pair (guard) + resolved directive path (loader). */
6
6
  export interface LitModeSpec {
7
7
  readonly mode: LitMode;
@@ -21,8 +21,6 @@ export declare const HANDOFF_MODE_SPEC: LitModeSpec;
21
21
  export declare const SCIENTIFIC_VISUALIZATION_MODE_SPEC: LitModeSpec;
22
22
  /** Exact browser-drive and `$litcodex:browser-drive` are standalone routes outside token matching. */
23
23
  export declare const BROWSER_DRIVE_MODE_SPEC: LitModeSpec;
24
- /** Exact skill-observer and `$litcodex:skill-observer` are standalone routes. */
25
- export declare const SKILL_OBSERVER_MODE_SPEC: LitModeSpec;
26
24
  /** Token → mode spec. Frozen; the single source the hook router branches on. */
27
25
  export declare const MODE_BY_TOKEN: Readonly<Record<LitTriggerToken, LitModeSpec>>;
28
26
  /** The mode spec for a matched token. Total over the token union (every token has a spec). */
@@ -15,7 +15,7 @@
15
15
  // Imports markers + the trigger token type only (no cycle: hook → modes → {markers, trigger}).
16
16
  import { existsSync } from "node:fs";
17
17
  import { fileURLToPath } from "node:url";
18
- import { BROWSER_DRIVE_DIRECTIVE_CLOSE, BROWSER_DRIVE_DIRECTIVE_MARKER, DEEP_INTERVIEW_DIRECTIVE_CLOSE, DEEP_INTERVIEW_DIRECTIVE_MARKER, HANDOFF_DIRECTIVE_CLOSE, HANDOFF_DIRECTIVE_MARKER, LIT_COMPREHEND_DIRECTIVE_CLOSE, LIT_COMPREHEND_DIRECTIVE_MARKER, LIT_CRUCIBLE_DIRECTIVE_CLOSE, LIT_CRUCIBLE_DIRECTIVE_MARKER, LIT_INIT_DIRECTIVE_CLOSE, LIT_INIT_DIRECTIVE_MARKER, LIT_LOOP_DIRECTIVE_CLOSE, LIT_LOOP_DIRECTIVE_MARKER, LIT_PLAN_DIRECTIVE_CLOSE, LIT_PLAN_DIRECTIVE_MARKER, LIT_RECAP_DIRECTIVE_CLOSE, LIT_RECAP_DIRECTIVE_MARKER, LITGOAL_DIRECTIVE_CLOSE, LITGOAL_DIRECTIVE_MARKER, LITRESEARCH_DIRECTIVE_CLOSE, LITRESEARCH_DIRECTIVE_MARKER, LITWORK_DIRECTIVE_CLOSE, LITWORK_DIRECTIVE_MARKER, REVIEW_WORK_DIRECTIVE_CLOSE, REVIEW_WORK_DIRECTIVE_MARKER, SCIENTIFIC_VISUALIZATION_DIRECTIVE_CLOSE, SCIENTIFIC_VISUALIZATION_DIRECTIVE_MARKER, SKILL_OBSERVER_DIRECTIVE_CLOSE, SKILL_OBSERVER_DIRECTIVE_MARKER, START_WORK_DIRECTIVE_CLOSE, START_WORK_DIRECTIVE_MARKER, } from "./markers.js";
18
+ import { BROWSER_DRIVE_DIRECTIVE_CLOSE, BROWSER_DRIVE_DIRECTIVE_MARKER, DEEP_INTERVIEW_DIRECTIVE_CLOSE, DEEP_INTERVIEW_DIRECTIVE_MARKER, HANDOFF_DIRECTIVE_CLOSE, HANDOFF_DIRECTIVE_MARKER, LIT_COMPREHEND_DIRECTIVE_CLOSE, LIT_COMPREHEND_DIRECTIVE_MARKER, LIT_CRUCIBLE_DIRECTIVE_CLOSE, LIT_CRUCIBLE_DIRECTIVE_MARKER, LIT_INIT_DIRECTIVE_CLOSE, LIT_INIT_DIRECTIVE_MARKER, LIT_LOOP_DIRECTIVE_CLOSE, LIT_LOOP_DIRECTIVE_MARKER, LIT_PLAN_DIRECTIVE_CLOSE, LIT_PLAN_DIRECTIVE_MARKER, LIT_RECAP_DIRECTIVE_CLOSE, LIT_RECAP_DIRECTIVE_MARKER, LITGOAL_DIRECTIVE_CLOSE, LITGOAL_DIRECTIVE_MARKER, LITRESEARCH_DIRECTIVE_CLOSE, LITRESEARCH_DIRECTIVE_MARKER, LITWORK_DIRECTIVE_CLOSE, LITWORK_DIRECTIVE_MARKER, REVIEW_WORK_DIRECTIVE_CLOSE, REVIEW_WORK_DIRECTIVE_MARKER, SCIENTIFIC_VISUALIZATION_DIRECTIVE_CLOSE, SCIENTIFIC_VISUALIZATION_DIRECTIVE_MARKER, START_WORK_DIRECTIVE_CLOSE, START_WORK_DIRECTIVE_MARKER, } from "./markers.js";
19
19
  /** Resolve a path relative to this module (percent-decoding, space/#/Hangul-safe). */
20
20
  function resolveFromHere(rel) {
21
21
  return fileURLToPath(new URL(rel, import.meta.url));
@@ -67,15 +67,6 @@ export const BROWSER_DRIVE_MODE_SPEC = Object.freeze({
67
67
  skillName: "browser-drive",
68
68
  skillPath: resolveSkillPath("browser-drive"),
69
69
  });
70
- /** Exact skill-observer and `$litcodex:skill-observer` are standalone routes. */
71
- export const SKILL_OBSERVER_MODE_SPEC = Object.freeze({
72
- mode: "skill-observer",
73
- openMarker: SKILL_OBSERVER_DIRECTIVE_MARKER,
74
- closeMarker: SKILL_OBSERVER_DIRECTIVE_CLOSE,
75
- directivePath: resolveFromHere("../directives/skill-observer.md"),
76
- skillName: "skill-observer",
77
- skillPath: resolveSkillPath("skill-observer"),
78
- });
79
70
  /** Token → mode spec. Frozen; the single source the hook router branches on. */
80
71
  export const MODE_BY_TOKEN = Object.freeze({
81
72
  "lit-crucible": Object.freeze({
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@litcodex/lit-loop",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "description": "LitCodex Lit-Loop runtime: durable repo-native multi-goal orchestration with embedded success criteria and observable evidence audit.",
5
5
  "type": "module",
6
6
  "private": true,
@@ -307,12 +307,19 @@ function unavailable(reason, detail, command = null, version = null) {
307
307
  }
308
308
 
309
309
  function probeUnsafe(options) {
310
- const input = isRecord(options) ? options : {};
310
+ if (!isRecord(options)) {
311
+ return unavailable("probe-error", `${DRIVER_COMMAND} capability probe received malformed input`);
312
+ }
313
+ const input = options;
311
314
  const hasExplicitPath = Object.hasOwn(input, "path");
315
+ if (hasExplicitPath && typeof input.path !== "string") {
316
+ return unavailable("probe-error", `${DRIVER_COMMAND} capability probe received malformed input`);
317
+ }
318
+ if (Object.hasOwn(input, "runCommand") && typeof input.runCommand !== "function") {
319
+ return unavailable("probe-error", `${DRIVER_COMMAND} capability probe received malformed input`);
320
+ }
312
321
  const searchPath = hasExplicitPath
313
- ? typeof input.path === "string"
314
- ? input.path
315
- : ""
322
+ ? input.path
316
323
  : typeof process.env.PATH === "string"
317
324
  ? process.env.PATH
318
325
  : "";
@@ -419,8 +426,9 @@ function probeUnsafe(options) {
419
426
  * @param {unknown} options
420
427
  * @returns {BrowserDriverProbeResult}
421
428
  */
422
- export function probeBrowserDriver(options = {}) {
429
+ export function probeBrowserDriver(options) {
423
430
  try {
431
+ if (arguments.length === 0) options = {};
424
432
  return probeUnsafe(options);
425
433
  } catch {
426
434
  return unavailable(