@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.
- package/README.md +18 -21
- package/dist/cli.d.ts +1 -1
- package/dist/cli.js +2 -38
- package/dist/config-migration/profile-files.d.ts +4 -0
- package/dist/config-migration/profile-files.js +22 -0
- package/dist/install/capability-preflight-error.js +5 -1
- package/dist/install/codex.d.ts +1 -0
- package/dist/install/generated-skill-payload-hashes.d.ts +1 -6
- package/dist/install/generated-skill-payload-hashes.js +1 -6
- package/dist/install/host-capabilities.d.ts +2 -0
- package/dist/install/host-capabilities.js +13 -1
- package/dist/install/index.js +3 -1
- package/dist/install/skill-catalog.d.ts +1 -1
- package/dist/install/skill-catalog.js +1 -6
- package/dist/install/skill-resource-hashes.d.ts +1 -1
- package/dist/install/skill-resource-hashes.js +1 -1
- package/dist/install/strict-config-probe.d.ts +2 -0
- package/dist/install/strict-config-probe.js +34 -5
- package/dist/install/uninstall.d.ts +2 -0
- package/dist/install/uninstall.js +34 -0
- package/marketplace/plugins/litcodex/.codex-plugin/plugin.json +1 -1
- package/marketplace/plugins/litcodex/components/auto-update/package.json +1 -1
- package/marketplace/plugins/litcodex/components/comment-checker/package.json +1 -1
- package/marketplace/plugins/litcodex/components/git-bash/package.json +1 -1
- package/marketplace/plugins/litcodex/components/lit-loop/dist/cli.js +3 -20
- package/marketplace/plugins/litcodex/components/lit-loop/dist/codex-hook.js +1 -8
- package/marketplace/plugins/litcodex/components/lit-loop/dist/hook-cli.d.ts +2 -1
- package/marketplace/plugins/litcodex/components/lit-loop/dist/hook-cli.js +4 -27
- package/marketplace/plugins/litcodex/components/lit-loop/dist/markers.d.ts +0 -2
- package/marketplace/plugins/litcodex/components/lit-loop/dist/markers.js +0 -2
- package/marketplace/plugins/litcodex/components/lit-loop/dist/modes.d.ts +1 -3
- package/marketplace/plugins/litcodex/components/lit-loop/dist/modes.js +1 -10
- package/marketplace/plugins/litcodex/components/lit-loop/package.json +1 -1
- package/marketplace/plugins/litcodex/components/lsp/package.json +1 -1
- package/marketplace/plugins/litcodex/components/rules/dist/static-injection.js +2 -2
- package/marketplace/plugins/litcodex/components/rules/package.json +1 -1
- package/marketplace/plugins/litcodex/components/start-work-continuation/package.json +1 -1
- package/marketplace/plugins/litcodex/components/telemetry/package.json +1 -1
- package/marketplace/plugins/litcodex/components/wikify-knowledge/package.json +1 -1
- package/marketplace/plugins/litcodex/skills/browser-drive/scripts/capability-probe.mjs +13 -5
- package/node_modules/@litcodex/lit-loop/README.md +1 -7
- package/node_modules/@litcodex/lit-loop/dist/cli.js +3 -20
- package/node_modules/@litcodex/lit-loop/dist/codex-hook.js +1 -8
- package/node_modules/@litcodex/lit-loop/dist/hook-cli.d.ts +2 -1
- package/node_modules/@litcodex/lit-loop/dist/hook-cli.js +4 -27
- package/node_modules/@litcodex/lit-loop/dist/markers.d.ts +0 -2
- package/node_modules/@litcodex/lit-loop/dist/markers.js +0 -2
- package/node_modules/@litcodex/lit-loop/dist/modes.d.ts +1 -3
- package/node_modules/@litcodex/lit-loop/dist/modes.js +1 -10
- package/node_modules/@litcodex/lit-loop/package.json +1 -1
- package/node_modules/@litcodex/lit-loop/skills/browser-drive/scripts/capability-probe.mjs +13 -5
- package/package.json +2 -2
- package/readme-assets/badge-version.svg +1 -1
- package/readme-assets/cover-motion.webp +0 -0
- package/marketplace/plugins/litcodex/components/lit-loop/directives/skill-observer.md +0 -105
- package/marketplace/plugins/litcodex/components/lit-loop/dist/skill-loop/apply.d.ts +0 -16
- package/marketplace/plugins/litcodex/components/lit-loop/dist/skill-loop/apply.js +0 -227
- package/marketplace/plugins/litcodex/components/lit-loop/dist/skill-loop/config.d.ts +0 -13
- package/marketplace/plugins/litcodex/components/lit-loop/dist/skill-loop/config.js +0 -12
- package/marketplace/plugins/litcodex/components/lit-loop/dist/skill-loop/curator.d.ts +0 -14
- package/marketplace/plugins/litcodex/components/lit-loop/dist/skill-loop/curator.js +0 -112
- package/marketplace/plugins/litcodex/components/lit-loop/dist/skill-loop/hook.d.ts +0 -19
- package/marketplace/plugins/litcodex/components/lit-loop/dist/skill-loop/hook.js +0 -435
- package/marketplace/plugins/litcodex/components/lit-loop/dist/skill-loop/ownership.d.ts +0 -6
- package/marketplace/plugins/litcodex/components/lit-loop/dist/skill-loop/ownership.js +0 -145
- package/marketplace/plugins/litcodex/components/lit-loop/dist/skill-loop/paths.d.ts +0 -18
- package/marketplace/plugins/litcodex/components/lit-loop/dist/skill-loop/paths.js +0 -43
- package/marketplace/plugins/litcodex/components/lit-loop/dist/skill-loop/review.d.ts +0 -28
- package/marketplace/plugins/litcodex/components/lit-loop/dist/skill-loop/review.js +0 -702
- package/marketplace/plugins/litcodex/components/lit-loop/dist/skill-loop/store.d.ts +0 -32
- package/marketplace/plugins/litcodex/components/lit-loop/dist/skill-loop/store.js +0 -667
- package/marketplace/plugins/litcodex/components/lit-loop/dist/skill-loop/transaction.d.ts +0 -26
- package/marketplace/plugins/litcodex/components/lit-loop/dist/skill-loop/transaction.js +0 -524
- package/marketplace/plugins/litcodex/components/lit-loop/dist/skill-loop/types.d.ts +0 -81
- package/marketplace/plugins/litcodex/components/lit-loop/dist/skill-loop/types.js +0 -246
- package/marketplace/plugins/litcodex/components/lit-loop/dist/skill-loop/usage.d.ts +0 -6
- package/marketplace/plugins/litcodex/components/lit-loop/dist/skill-loop/usage.js +0 -119
- package/marketplace/plugins/litcodex/components/lit-loop/dist/skill-loop-cli.d.ts +0 -8
- package/marketplace/plugins/litcodex/components/lit-loop/dist/skill-loop-cli.js +0 -111
- package/marketplace/plugins/litcodex/components/lit-loop/dist/skill-observer-cli.d.ts +0 -3
- package/marketplace/plugins/litcodex/components/lit-loop/dist/skill-observer-cli.js +0 -116
- package/marketplace/plugins/litcodex/components/lit-loop/dist/skill-observer-route.d.ts +0 -6
- package/marketplace/plugins/litcodex/components/lit-loop/dist/skill-observer-route.js +0 -12
- package/marketplace/plugins/litcodex/components/lit-loop/dist/skill-observer.d.ts +0 -18
- package/marketplace/plugins/litcodex/components/lit-loop/dist/skill-observer.js +0 -946
- package/marketplace/plugins/litcodex/skills/skill-observer/SKILL.md +0 -215
- package/marketplace/plugins/litcodex/skills/skill-observer/agents/openai.yaml +0 -6
- package/marketplace/plugins/litcodex/skills/skill-observer/references/review-contract.md +0 -77
- package/node_modules/@litcodex/lit-loop/directives/skill-observer.md +0 -105
- package/node_modules/@litcodex/lit-loop/dist/skill-loop/apply.d.ts +0 -16
- package/node_modules/@litcodex/lit-loop/dist/skill-loop/apply.js +0 -227
- package/node_modules/@litcodex/lit-loop/dist/skill-loop/config.d.ts +0 -13
- package/node_modules/@litcodex/lit-loop/dist/skill-loop/config.js +0 -12
- package/node_modules/@litcodex/lit-loop/dist/skill-loop/curator.d.ts +0 -14
- package/node_modules/@litcodex/lit-loop/dist/skill-loop/curator.js +0 -112
- package/node_modules/@litcodex/lit-loop/dist/skill-loop/hook.d.ts +0 -19
- package/node_modules/@litcodex/lit-loop/dist/skill-loop/hook.js +0 -435
- package/node_modules/@litcodex/lit-loop/dist/skill-loop/ownership.d.ts +0 -6
- package/node_modules/@litcodex/lit-loop/dist/skill-loop/ownership.js +0 -145
- package/node_modules/@litcodex/lit-loop/dist/skill-loop/paths.d.ts +0 -18
- package/node_modules/@litcodex/lit-loop/dist/skill-loop/paths.js +0 -43
- package/node_modules/@litcodex/lit-loop/dist/skill-loop/review.d.ts +0 -28
- package/node_modules/@litcodex/lit-loop/dist/skill-loop/review.js +0 -702
- package/node_modules/@litcodex/lit-loop/dist/skill-loop/store.d.ts +0 -32
- package/node_modules/@litcodex/lit-loop/dist/skill-loop/store.js +0 -667
- package/node_modules/@litcodex/lit-loop/dist/skill-loop/transaction.d.ts +0 -26
- package/node_modules/@litcodex/lit-loop/dist/skill-loop/transaction.js +0 -524
- package/node_modules/@litcodex/lit-loop/dist/skill-loop/types.d.ts +0 -81
- package/node_modules/@litcodex/lit-loop/dist/skill-loop/types.js +0 -246
- package/node_modules/@litcodex/lit-loop/dist/skill-loop/usage.d.ts +0 -6
- package/node_modules/@litcodex/lit-loop/dist/skill-loop/usage.js +0 -119
- package/node_modules/@litcodex/lit-loop/dist/skill-loop-cli.d.ts +0 -8
- package/node_modules/@litcodex/lit-loop/dist/skill-loop-cli.js +0 -111
- package/node_modules/@litcodex/lit-loop/dist/skill-observer-cli.d.ts +0 -3
- package/node_modules/@litcodex/lit-loop/dist/skill-observer-cli.js +0 -116
- package/node_modules/@litcodex/lit-loop/dist/skill-observer-route.d.ts +0 -6
- package/node_modules/@litcodex/lit-loop/dist/skill-observer-route.js +0 -12
- package/node_modules/@litcodex/lit-loop/dist/skill-observer.d.ts +0 -18
- package/node_modules/@litcodex/lit-loop/dist/skill-observer.js +0 -946
- package/node_modules/@litcodex/lit-loop/skills/skill-observer/SKILL.md +0 -215
- package/node_modules/@litcodex/lit-loop/skills/skill-observer/references/review-contract.md +0 -77
|
@@ -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
|
-
//
|
|
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,
|
|
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
|
|
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,
|
|
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
|
-
|
|
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,
|
|
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
|
-
|
|
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
|
-
|
|
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" | "
|
|
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,
|
|
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.
|
|
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,
|
|
@@ -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
|
|
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());
|
|
@@ -307,12 +307,19 @@ function unavailable(reason, detail, command = null, version = null) {
|
|
|
307
307
|
}
|
|
308
308
|
|
|
309
309
|
function probeUnsafe(options) {
|
|
310
|
-
|
|
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
|
-
?
|
|
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
|
|
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
|
-
//
|
|
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,
|
|
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
|
|
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,
|
|
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
|
-
|
|
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,
|
|
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
|
-
|
|
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
|
-
|
|
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" | "
|
|
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,
|
|
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.
|
|
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
|
-
|
|
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
|
-
?
|
|
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(
|