@codyswann/lisa 2.273.0 → 2.275.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/doctor-readiness-journey-freshness.d.ts +36 -0
- package/dist/cli/doctor-readiness-journey-freshness.d.ts.map +1 -0
- package/dist/cli/doctor-readiness-journey-freshness.js +166 -0
- package/dist/cli/doctor-readiness-journey-freshness.js.map +1 -0
- package/dist/cli/doctor-readiness-journey.d.ts +110 -0
- package/dist/cli/doctor-readiness-journey.d.ts.map +1 -0
- package/dist/cli/doctor-readiness-journey.js +233 -0
- package/dist/cli/doctor-readiness-journey.js.map +1 -0
- package/dist/cli/doctor-readiness.d.ts.map +1 -1
- package/dist/cli/doctor-readiness.js +25 -5
- package/dist/cli/doctor-readiness.js.map +1 -1
- package/dist/cli/doctor-worker-epoch.d.ts +5 -0
- package/dist/cli/doctor-worker-epoch.d.ts.map +1 -1
- package/dist/cli/doctor-worker-epoch.js +10 -134
- package/dist/cli/doctor-worker-epoch.js.map +1 -1
- package/dist/cli/doctor-worker-journey.d.ts +118 -0
- package/dist/cli/doctor-worker-journey.d.ts.map +1 -0
- package/dist/cli/doctor-worker-journey.js +222 -0
- package/dist/cli/doctor-worker-journey.js.map +1 -0
- package/dist/cli/health-cmd.d.ts +31 -0
- package/dist/cli/health-cmd.d.ts.map +1 -0
- package/dist/cli/health-cmd.js +101 -0
- package/dist/cli/health-cmd.js.map +1 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +20 -1
- package/dist/cli/index.js.map +1 -1
- package/dist/core/upstream-evidence-manifest.d.ts.map +1 -1
- package/dist/core/upstream-evidence-manifest.js +30 -1
- package/dist/core/upstream-evidence-manifest.js.map +1 -1
- package/dist/health/agentic.d.ts +2 -0
- package/dist/health/agentic.d.ts.map +1 -1
- package/dist/health/agentic.js +4 -4
- package/dist/health/agentic.js.map +1 -1
- package/dist/health/consumer.d.ts +28 -0
- package/dist/health/consumer.d.ts.map +1 -0
- package/dist/health/consumer.js +50 -0
- package/dist/health/consumer.js.map +1 -0
- package/dist/health/evaluation-protocol.d.ts +45 -0
- package/dist/health/evaluation-protocol.d.ts.map +1 -0
- package/dist/health/evaluation-protocol.js +119 -0
- package/dist/health/evaluation-protocol.js.map +1 -0
- package/dist/health/index.d.ts +3 -0
- package/dist/health/index.d.ts.map +1 -1
- package/dist/health/index.js +3 -0
- package/dist/health/index.js.map +1 -1
- package/dist/health/prepare.d.ts +15 -0
- package/dist/health/prepare.d.ts.map +1 -0
- package/dist/health/prepare.js +31 -0
- package/dist/health/prepare.js.map +1 -0
- package/dist/health/storage.d.ts +8 -0
- package/dist/health/storage.d.ts.map +1 -1
- package/dist/health/storage.js +13 -3
- package/dist/health/storage.js.map +1 -1
- package/package.json +3 -2
- package/plugins/lisa/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa/.codex-plugin/skills/lisa-health/SKILL.md +142 -0
- package/plugins/lisa/.codex-plugin/skills/lisa-health/agents/openai.yaml +4 -0
- package/plugins/lisa/commands/health.md +8 -0
- package/plugins/lisa/skills/lisa-health/SKILL.md +142 -0
- package/plugins/lisa/skills/lisa-health/agents/openai.yaml +4 -0
- package/plugins/lisa-agy/commands/lisa/health.md +8 -0
- package/plugins/lisa-agy/plugin.json +1 -1
- package/plugins/lisa-agy/skills/lisa-health/SKILL.md +142 -0
- package/plugins/lisa-cdk/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cdk/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-cdk-agy/plugin.json +1 -1
- package/plugins/lisa-cdk-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cdk-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-copilot/commands/lisa/health.md +8 -0
- package/plugins/lisa-copilot/skills/lisa-health/SKILL.md +142 -0
- package/plugins/lisa-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cursor/commands/lisa/health.md +8 -0
- package/plugins/lisa-cursor/skills/lisa-health/SKILL.md +142 -0
- package/plugins/lisa-expo/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-expo/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-expo-agy/plugin.json +1 -1
- package/plugins/lisa-expo-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-expo-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric-agy/plugin.json +1 -1
- package/plugins/lisa-harper-fabric-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs-agy/plugin.json +1 -1
- package/plugins/lisa-nestjs-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw-agy/plugin.json +1 -1
- package/plugins/lisa-openclaw-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser-agy/plugin.json +1 -1
- package/plugins/lisa-phaser-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-rails/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-rails/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-rails-agy/plugin.json +1 -1
- package/plugins/lisa-rails-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-rails-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript-agy/plugin.json +1 -1
- package/plugins/lisa-typescript-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki-agy/plugin.json +1 -1
- package/plugins/lisa-wiki-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/src/base/commands/health.md +8 -0
- package/plugins/src/base/skills/lisa-health/SKILL.md +142 -0
- package/scripts/verify-health-consumer-built.mjs +239 -0
- package/ui/README.md +16 -12
|
@@ -4,6 +4,11 @@ import type { DoctorCheck } from "./doctor.js";
|
|
|
4
4
|
* runtime signature still matches it. This is intentionally read-only: doctor
|
|
5
5
|
* tells the operator when requalification is needed; lifecycle/repair flows own
|
|
6
6
|
* filing any build-ready tickets from failed representative journeys.
|
|
7
|
+
*
|
|
8
|
+
* The journey machinery it consumes now lives in `doctor-worker-journey.ts` so
|
|
9
|
+
* the readiness execution/proof dimension (RRR-6, #1858) reuses the exact same
|
|
10
|
+
* runner rather than forking a second harness (intake decision F5). This
|
|
11
|
+
* function's output is unchanged by that extraction.
|
|
7
12
|
* @param targetPath - Project path to inspect
|
|
8
13
|
* @returns Doctor check result
|
|
9
14
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"doctor-worker-epoch.d.ts","sourceRoot":"","sources":["../../src/cli/doctor-worker-epoch.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"doctor-worker-epoch.d.ts","sourceRoot":"","sources":["../../src/cli/doctor-worker-epoch.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAe/C;;;;;;;;;;;;GAYG;AACH,wBAAsB,gBAAgB,CACpC,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,WAAW,CAAC,CAoCtB"}
|
|
@@ -1,12 +1,18 @@
|
|
|
1
1
|
import { existsSync } from "node:fs";
|
|
2
|
-
import {
|
|
2
|
+
import { readFile } from "node:fs/promises";
|
|
3
3
|
import * as path from "node:path";
|
|
4
|
+
import { computeWorkerDrift, countWorkerWorkaroundCandidates, currentRuntimeWorkerSignature, findWorkerRecordForHost, normalizeWorkerAgents, resolveRecordedEvidence, } from "./doctor-worker-journey.js";
|
|
4
5
|
const WORKER_EPOCH_CHECK_NAME = "Worker epoch qualified?";
|
|
5
6
|
/**
|
|
6
7
|
* Report whether the project has a worker-epoch record and whether the current
|
|
7
8
|
* runtime signature still matches it. This is intentionally read-only: doctor
|
|
8
9
|
* tells the operator when requalification is needed; lifecycle/repair flows own
|
|
9
10
|
* filing any build-ready tickets from failed representative journeys.
|
|
11
|
+
*
|
|
12
|
+
* The journey machinery it consumes now lives in `doctor-worker-journey.ts` so
|
|
13
|
+
* the readiness execution/proof dimension (RRR-6, #1858) reuses the exact same
|
|
14
|
+
* runner rather than forking a second harness (intake decision F5). This
|
|
15
|
+
* function's output is unchanged by that extraction.
|
|
10
16
|
* @param targetPath - Project path to inspect
|
|
11
17
|
* @returns Doctor check result
|
|
12
18
|
*/
|
|
@@ -62,10 +68,7 @@ async function evaluateWorkerEpochRecord(targetPath, record, signature) {
|
|
|
62
68
|
detail: ".lisa/worker-config.json does not list any qualified workers; add agent host, model, version, and evidence entries",
|
|
63
69
|
};
|
|
64
70
|
}
|
|
65
|
-
const currentRecord = agents
|
|
66
|
-
return (typeof agent.host === "string" &&
|
|
67
|
-
agent.host.toLowerCase() === signature.host);
|
|
68
|
-
});
|
|
71
|
+
const currentRecord = findWorkerRecordForHost(agents, signature);
|
|
69
72
|
if (!currentRecord) {
|
|
70
73
|
return {
|
|
71
74
|
name: WORKER_EPOCH_CHECK_NAME,
|
|
@@ -84,14 +87,9 @@ async function evaluateWorkerEpochRecord(targetPath, record, signature) {
|
|
|
84
87
|
* @returns Doctor check result
|
|
85
88
|
*/
|
|
86
89
|
async function renderWorkerEpochMatch(targetPath, currentRecord, signature) {
|
|
87
|
-
const
|
|
88
|
-
const recordedVersion = stringField(currentRecord.version);
|
|
89
|
-
const drift = [
|
|
90
|
-
compareWorkerField("model", recordedModel, signature.model),
|
|
91
|
-
compareWorkerField("version", recordedVersion, signature.version),
|
|
92
|
-
].filter((entry) => entry !== null);
|
|
90
|
+
const drift = computeWorkerDrift(currentRecord, signature);
|
|
93
91
|
const subtractionCount = await countWorkerWorkaroundCandidates(targetPath);
|
|
94
|
-
const evidence =
|
|
92
|
+
const evidence = resolveRecordedEvidence(currentRecord);
|
|
95
93
|
if (drift.length > 0) {
|
|
96
94
|
return {
|
|
97
95
|
name: WORKER_EPOCH_CHECK_NAME,
|
|
@@ -109,126 +107,4 @@ async function renderWorkerEpochMatch(targetPath, currentRecord, signature) {
|
|
|
109
107
|
: `Worker epoch matches ${signature.host}, but no qualification evidence is recorded. Scaffolding-subtraction candidates surfaced: ${subtractionCount}.`,
|
|
110
108
|
};
|
|
111
109
|
}
|
|
112
|
-
/**
|
|
113
|
-
* Normalize object- and array-shaped worker records into one array.
|
|
114
|
-
* @param record - Parsed worker epoch record
|
|
115
|
-
* @returns Normalized worker entries
|
|
116
|
-
*/
|
|
117
|
-
function normalizeWorkerAgents(record) {
|
|
118
|
-
if (Array.isArray(record.agents)) {
|
|
119
|
-
return record.agents.filter(isRecord);
|
|
120
|
-
}
|
|
121
|
-
if (Array.isArray(record.workers)) {
|
|
122
|
-
return record.workers.filter(isRecord);
|
|
123
|
-
}
|
|
124
|
-
if (isRecord(record.agents)) {
|
|
125
|
-
return Object.entries(record.agents).map(([id, value]) => ({
|
|
126
|
-
...(isRecord(value) ? value : {}),
|
|
127
|
-
id,
|
|
128
|
-
}));
|
|
129
|
-
}
|
|
130
|
-
if (isRecord(record.workers)) {
|
|
131
|
-
return Object.entries(record.workers).map(([id, value]) => ({
|
|
132
|
-
...(isRecord(value) ? value : {}),
|
|
133
|
-
id,
|
|
134
|
-
}));
|
|
135
|
-
}
|
|
136
|
-
return [];
|
|
137
|
-
}
|
|
138
|
-
/**
|
|
139
|
-
* Infer a stable worker signature from explicit Lisa variables first,
|
|
140
|
-
* falling back to `LISA_REMOTE_AGENT` (set by the remote-agent bootstrap for
|
|
141
|
-
* Cursor, Copilot, OpenCode, and Antigravity) and then Codex/Claude-specific
|
|
142
|
-
* markers.
|
|
143
|
-
* @returns Current runtime signature
|
|
144
|
-
*/
|
|
145
|
-
function currentRuntimeWorkerSignature() {
|
|
146
|
-
const env = process["env"];
|
|
147
|
-
const host = env.LISA_WORKER_HOST ??
|
|
148
|
-
env.LISA_REMOTE_AGENT ??
|
|
149
|
-
(env.CODEX_HOME || env.CODEX_SANDBOX
|
|
150
|
-
? "codex"
|
|
151
|
-
: env.CLAUDECODE
|
|
152
|
-
? "claude"
|
|
153
|
-
: "unknown");
|
|
154
|
-
return {
|
|
155
|
-
host: host.toLowerCase(),
|
|
156
|
-
model: env.LISA_WORKER_MODEL ?? env.CODEX_MODEL ?? "unknown",
|
|
157
|
-
version: env.LISA_WORKER_VERSION ?? env.CODEX_VERSION ?? "unknown",
|
|
158
|
-
};
|
|
159
|
-
}
|
|
160
|
-
/**
|
|
161
|
-
* Return a human-readable drift fragment for one worker field.
|
|
162
|
-
* @param name - Field name
|
|
163
|
-
* @param recorded - Recorded value
|
|
164
|
-
* @param current - Current value
|
|
165
|
-
* @returns Drift fragment, or null when unchanged/unobservable
|
|
166
|
-
*/
|
|
167
|
-
function compareWorkerField(name, recorded, current) {
|
|
168
|
-
if (!recorded || current === "unknown" || recorded === current) {
|
|
169
|
-
return null;
|
|
170
|
-
}
|
|
171
|
-
return `${name} recorded ${recorded} now ${current}`;
|
|
172
|
-
}
|
|
173
|
-
/**
|
|
174
|
-
* Count local rules/skills whose rationale mentions worker-specific workarounds.
|
|
175
|
-
* @param targetPath - Project path to scan
|
|
176
|
-
* @returns Number of candidate files
|
|
177
|
-
*/
|
|
178
|
-
async function countWorkerWorkaroundCandidates(targetPath) {
|
|
179
|
-
const roots = [
|
|
180
|
-
path.join(targetPath, "plugins", "src", "base", "rules"),
|
|
181
|
-
path.join(targetPath, "plugins", "src", "base", "skills"),
|
|
182
|
-
];
|
|
183
|
-
const counts = await Promise.all(roots.map(root => countMatchingMarkdownFiles(root, isWorkerWorkaround)));
|
|
184
|
-
return counts.reduce((total, count) => total + count, 0);
|
|
185
|
-
}
|
|
186
|
-
/**
|
|
187
|
-
* Determine whether a markdown file describes a worker workaround.
|
|
188
|
-
* @param content - Markdown content
|
|
189
|
-
* @returns True when content is a subtraction-pass candidate
|
|
190
|
-
*/
|
|
191
|
-
function isWorkerWorkaround(content) {
|
|
192
|
-
return /\b(model|worker|host|epoch|claude|codex|cursor|opencode|copilot|agy|antigravity)\b[\s\S]{0,160}\b(workaround|limitation|quirk|scaffold|temporary|native capability)\b/iu.test(content);
|
|
193
|
-
}
|
|
194
|
-
/**
|
|
195
|
-
* Recursively count markdown files matching a predicate.
|
|
196
|
-
* @param directory - Directory to scan
|
|
197
|
-
* @param predicate - Markdown content predicate
|
|
198
|
-
* @returns Number of matching files
|
|
199
|
-
*/
|
|
200
|
-
async function countMatchingMarkdownFiles(directory, predicate) {
|
|
201
|
-
if (!existsSync(directory)) {
|
|
202
|
-
return 0;
|
|
203
|
-
}
|
|
204
|
-
const counts = await Promise.all((await readdir(directory)).map(async (entry) => {
|
|
205
|
-
const entryPath = path.join(directory, entry);
|
|
206
|
-
const entryStat = await stat(entryPath);
|
|
207
|
-
if (entryStat.isDirectory()) {
|
|
208
|
-
return countMatchingMarkdownFiles(entryPath, predicate);
|
|
209
|
-
}
|
|
210
|
-
if (entry.endsWith(".md") &&
|
|
211
|
-
predicate(await readFile(entryPath, "utf8"))) {
|
|
212
|
-
return 1;
|
|
213
|
-
}
|
|
214
|
-
return 0;
|
|
215
|
-
}));
|
|
216
|
-
return counts.reduce((total, count) => total + count, 0);
|
|
217
|
-
}
|
|
218
|
-
/**
|
|
219
|
-
* Narrow unknown JSON values to plain records.
|
|
220
|
-
* @param value - Value to inspect
|
|
221
|
-
* @returns True for plain object records
|
|
222
|
-
*/
|
|
223
|
-
function isRecord(value) {
|
|
224
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
225
|
-
}
|
|
226
|
-
/**
|
|
227
|
-
* Normalize a possibly empty string field.
|
|
228
|
-
* @param value - Value to normalize
|
|
229
|
-
* @returns Trimmed string or null
|
|
230
|
-
*/
|
|
231
|
-
function stringField(value) {
|
|
232
|
-
return typeof value === "string" && value.trim() ? value.trim() : null;
|
|
233
|
-
}
|
|
234
110
|
//# sourceMappingURL=doctor-worker-epoch.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"doctor-worker-epoch.js","sourceRoot":"","sources":["../../src/cli/doctor-worker-epoch.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"doctor-worker-epoch.js","sourceRoot":"","sources":["../../src/cli/doctor-worker-epoch.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
/** One worker entry from `.lisa/worker-config.json`. */
|
|
2
|
+
export interface WorkerEpochAgentRecord {
|
|
3
|
+
id?: unknown;
|
|
4
|
+
host?: unknown;
|
|
5
|
+
version?: unknown;
|
|
6
|
+
model?: unknown;
|
|
7
|
+
modelId?: unknown;
|
|
8
|
+
qualificationEvidence?: unknown;
|
|
9
|
+
evidence?: unknown;
|
|
10
|
+
qualifiedAt?: unknown;
|
|
11
|
+
recordedAt?: unknown;
|
|
12
|
+
}
|
|
13
|
+
/** Supported top-level worker epoch record shapes. */
|
|
14
|
+
export interface WorkerEpochRecord {
|
|
15
|
+
agents?: unknown;
|
|
16
|
+
workers?: unknown;
|
|
17
|
+
}
|
|
18
|
+
/** Current runtime identity used for epoch comparison. */
|
|
19
|
+
export interface RuntimeWorkerSignature {
|
|
20
|
+
host: string;
|
|
21
|
+
model: string;
|
|
22
|
+
version: string;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* The consolidated journey-evidence resolution for the current worker, shared by
|
|
26
|
+
* the epoch-drift path and the readiness execution/proof dimension so both read
|
|
27
|
+
* one source of truth.
|
|
28
|
+
*/
|
|
29
|
+
export interface WorkerJourneyEvidence {
|
|
30
|
+
/** Absolute path to `.lisa/worker-config.json`. */
|
|
31
|
+
readonly recordPath: string;
|
|
32
|
+
/** Whether `.lisa/worker-config.json` exists on disk. */
|
|
33
|
+
readonly recordExists: boolean;
|
|
34
|
+
/** A parse error message when the record is present but not valid JSON. */
|
|
35
|
+
readonly parseError: string | null;
|
|
36
|
+
/** The current runtime worker signature (host/model/version). */
|
|
37
|
+
readonly signature: RuntimeWorkerSignature;
|
|
38
|
+
/** The recorded worker entry matching the current host, if any. */
|
|
39
|
+
readonly matched: WorkerEpochAgentRecord | undefined;
|
|
40
|
+
/** The recorded qualification-evidence pointer, or null when absent. */
|
|
41
|
+
readonly evidence: string | null;
|
|
42
|
+
/** Human-readable model/version drift fragments (empty when in sync). */
|
|
43
|
+
readonly drift: readonly string[];
|
|
44
|
+
/** #1742's scaffolding-subtraction candidate count (surfaced, never deleted). */
|
|
45
|
+
readonly subtractionCount: number;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Resolve the shared journey evidence for the current worker: read the record,
|
|
49
|
+
* find the entry for this host, and compute drift, evidence, and the
|
|
50
|
+
* subtraction-candidate count in one pass. This is the single journey runner
|
|
51
|
+
* both #1742's epoch-drift path and RRR-6's readiness dimension consume — no
|
|
52
|
+
* second harness. It never throws: an unreadable record degrades to
|
|
53
|
+
* `parseError`, and a missing record to `recordExists: false`.
|
|
54
|
+
* @param targetPath - Project path to inspect
|
|
55
|
+
* @returns The consolidated worker journey evidence
|
|
56
|
+
*/
|
|
57
|
+
export declare function resolveWorkerJourneyEvidence(targetPath: string): Promise<WorkerJourneyEvidence>;
|
|
58
|
+
/**
|
|
59
|
+
* Infer a stable worker signature from explicit Lisa variables first, falling
|
|
60
|
+
* back to `LISA_REMOTE_AGENT` (set by the remote-agent bootstrap for Cursor,
|
|
61
|
+
* Copilot, OpenCode, and Antigravity) and then Codex/Claude-specific markers.
|
|
62
|
+
* @returns Current runtime signature
|
|
63
|
+
*/
|
|
64
|
+
export declare function currentRuntimeWorkerSignature(): RuntimeWorkerSignature;
|
|
65
|
+
/**
|
|
66
|
+
* Normalize object- and array-shaped worker records into one array.
|
|
67
|
+
* @param record - Parsed worker epoch record
|
|
68
|
+
* @returns Normalized worker entries
|
|
69
|
+
*/
|
|
70
|
+
export declare function normalizeWorkerAgents(record: WorkerEpochRecord): WorkerEpochAgentRecord[];
|
|
71
|
+
/**
|
|
72
|
+
* Find the recorded worker entry whose host matches the current signature.
|
|
73
|
+
* @param agents - Normalized worker entries
|
|
74
|
+
* @param signature - Current runtime worker signature
|
|
75
|
+
* @returns The matching worker entry, or undefined
|
|
76
|
+
*/
|
|
77
|
+
export declare function findWorkerRecordForHost(agents: readonly WorkerEpochAgentRecord[], signature: RuntimeWorkerSignature): WorkerEpochAgentRecord | undefined;
|
|
78
|
+
/**
|
|
79
|
+
* Compute the model/version drift fragments between a recorded worker entry and
|
|
80
|
+
* the current runtime signature. An empty array means the epoch is in sync.
|
|
81
|
+
* @param record - Recorded worker entry for the current host
|
|
82
|
+
* @param signature - Current runtime worker signature
|
|
83
|
+
* @returns Human-readable drift fragments
|
|
84
|
+
*/
|
|
85
|
+
export declare function computeWorkerDrift(record: WorkerEpochAgentRecord, signature: RuntimeWorkerSignature): string[];
|
|
86
|
+
/**
|
|
87
|
+
* Resolve the recorded qualification-evidence pointer for a worker entry.
|
|
88
|
+
* @param record - Recorded worker entry
|
|
89
|
+
* @returns Trimmed evidence pointer, or null when absent
|
|
90
|
+
*/
|
|
91
|
+
export declare function resolveRecordedEvidence(record: WorkerEpochAgentRecord): string | null;
|
|
92
|
+
/**
|
|
93
|
+
* Return a human-readable drift fragment for one worker field.
|
|
94
|
+
* @param name - Field name
|
|
95
|
+
* @param recorded - Recorded value
|
|
96
|
+
* @param current - Current value
|
|
97
|
+
* @returns Drift fragment, or null when unchanged/unobservable
|
|
98
|
+
*/
|
|
99
|
+
export declare function compareWorkerField(name: string, recorded: string | null, current: string): string | null;
|
|
100
|
+
/**
|
|
101
|
+
* Count local rules/skills whose rationale mentions worker-specific workarounds.
|
|
102
|
+
* @param targetPath - Project path to scan
|
|
103
|
+
* @returns Number of candidate files
|
|
104
|
+
*/
|
|
105
|
+
export declare function countWorkerWorkaroundCandidates(targetPath: string): Promise<number>;
|
|
106
|
+
/**
|
|
107
|
+
* Narrow unknown JSON values to plain records.
|
|
108
|
+
* @param value - Value to inspect
|
|
109
|
+
* @returns True for plain object records
|
|
110
|
+
*/
|
|
111
|
+
export declare function isRecord(value: unknown): value is Record<string, unknown>;
|
|
112
|
+
/**
|
|
113
|
+
* Normalize a possibly empty string field.
|
|
114
|
+
* @param value - Value to normalize
|
|
115
|
+
* @returns Trimmed string or null
|
|
116
|
+
*/
|
|
117
|
+
export declare function stringField(value: unknown): string | null;
|
|
118
|
+
//# sourceMappingURL=doctor-worker-journey.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"doctor-worker-journey.d.ts","sourceRoot":"","sources":["../../src/cli/doctor-worker-journey.ts"],"names":[],"mappings":"AAuBA,wDAAwD;AACxD,MAAM,WAAW,sBAAsB;IACrC,EAAE,CAAC,EAAE,OAAO,CAAC;IACb,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,sDAAsD;AACtD,MAAM,WAAW,iBAAiB;IAChC,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,0DAA0D;AAC1D,MAAM,WAAW,sBAAsB;IACrC,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;;;GAIG;AACH,MAAM,WAAW,qBAAqB;IACpC,mDAAmD;IACnD,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,yDAAyD;IACzD,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAC;IAC/B,2EAA2E;IAC3E,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,iEAAiE;IACjE,QAAQ,CAAC,SAAS,EAAE,sBAAsB,CAAC;IAC3C,mEAAmE;IACnE,QAAQ,CAAC,OAAO,EAAE,sBAAsB,GAAG,SAAS,CAAC;IACrD,wEAAwE;IACxE,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,yEAAyE;IACzE,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;IAClC,iFAAiF;IACjF,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;CACnC;AAED;;;;;;;;;GASG;AACH,wBAAsB,4BAA4B,CAChD,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,qBAAqB,CAAC,CAsChC;AAED;;;;;GAKG;AACH,wBAAgB,6BAA6B,IAAI,sBAAsB,CAetE;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,iBAAiB,GACxB,sBAAsB,EAAE,CAoB1B;AAED;;;;;GAKG;AACH,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,SAAS,sBAAsB,EAAE,EACzC,SAAS,EAAE,sBAAsB,GAChC,sBAAsB,GAAG,SAAS,CAMpC;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,sBAAsB,EAC9B,SAAS,EAAE,sBAAsB,GAChC,MAAM,EAAE,CAOV;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,sBAAsB,GAC7B,MAAM,GAAG,IAAI,CAEf;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,GAAG,IAAI,EACvB,OAAO,EAAE,MAAM,GACd,MAAM,GAAG,IAAI,CAKf;AAED;;;;GAIG;AACH,wBAAsB,+BAA+B,CACnD,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,MAAM,CAAC,CASjB;AA6CD;;;;GAIG;AACH,wBAAgB,QAAQ,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAEzE;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAEzD"}
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The shared worker-epoch journey runner (RRR-6, #1858).
|
|
3
|
+
*
|
|
4
|
+
* #1742 shipped requalification journeys inside `lisa doctor`
|
|
5
|
+
* (`doctor-worker-epoch.ts`): it reads `.lisa/worker-config.json`, compares the
|
|
6
|
+
* recorded qualified epoch against the current runtime signature, reads the
|
|
7
|
+
* recorded `qualificationEvidence`, and surfaces scaffolding-subtraction
|
|
8
|
+
* candidates. RRR-6 must connect that same machinery to the readiness verdict
|
|
9
|
+
* *without building a second harness* (intake decision F5). This module is the
|
|
10
|
+
* extraction: the primitives both the epoch-drift path (`checkWorkerEpoch`) and
|
|
11
|
+
* the readiness execution/proof dimension consume, so there is exactly one
|
|
12
|
+
* journey runner. `checkWorkerEpoch` keeps its byte-identical output by calling
|
|
13
|
+
* these helpers; readiness calls {@link resolveWorkerJourneyEvidence} on top of
|
|
14
|
+
* them. Nothing here files tickets or drives a browser — journey selection and
|
|
15
|
+
* mutation policy live in `lisa-use-the-product`; this only resolves the worker
|
|
16
|
+
* record and the evidence it already carries.
|
|
17
|
+
* @module cli/doctor-worker-journey
|
|
18
|
+
*/
|
|
19
|
+
import { existsSync } from "node:fs";
|
|
20
|
+
import { readdir, readFile, stat } from "node:fs/promises";
|
|
21
|
+
import * as path from "node:path";
|
|
22
|
+
import process from "node:process";
|
|
23
|
+
/**
|
|
24
|
+
* Resolve the shared journey evidence for the current worker: read the record,
|
|
25
|
+
* find the entry for this host, and compute drift, evidence, and the
|
|
26
|
+
* subtraction-candidate count in one pass. This is the single journey runner
|
|
27
|
+
* both #1742's epoch-drift path and RRR-6's readiness dimension consume — no
|
|
28
|
+
* second harness. It never throws: an unreadable record degrades to
|
|
29
|
+
* `parseError`, and a missing record to `recordExists: false`.
|
|
30
|
+
* @param targetPath - Project path to inspect
|
|
31
|
+
* @returns The consolidated worker journey evidence
|
|
32
|
+
*/
|
|
33
|
+
export async function resolveWorkerJourneyEvidence(targetPath) {
|
|
34
|
+
const recordPath = path.join(targetPath, ".lisa", "worker-config.json");
|
|
35
|
+
const signature = currentRuntimeWorkerSignature();
|
|
36
|
+
const subtractionCount = await countWorkerWorkaroundCandidates(targetPath);
|
|
37
|
+
const base = {
|
|
38
|
+
recordPath,
|
|
39
|
+
signature,
|
|
40
|
+
subtractionCount,
|
|
41
|
+
matched: undefined,
|
|
42
|
+
evidence: null,
|
|
43
|
+
drift: [],
|
|
44
|
+
};
|
|
45
|
+
if (!existsSync(recordPath)) {
|
|
46
|
+
return { ...base, recordExists: false, parseError: null };
|
|
47
|
+
}
|
|
48
|
+
try {
|
|
49
|
+
const record = JSON.parse(await readFile(recordPath, "utf8"));
|
|
50
|
+
const matched = findWorkerRecordForHost(normalizeWorkerAgents(record), signature);
|
|
51
|
+
return {
|
|
52
|
+
...base,
|
|
53
|
+
recordExists: true,
|
|
54
|
+
parseError: null,
|
|
55
|
+
matched,
|
|
56
|
+
evidence: matched ? resolveRecordedEvidence(matched) : null,
|
|
57
|
+
drift: matched ? computeWorkerDrift(matched, signature) : [],
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
catch (error) {
|
|
61
|
+
return {
|
|
62
|
+
...base,
|
|
63
|
+
recordExists: true,
|
|
64
|
+
parseError: error instanceof Error ? error.message : String(error),
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Infer a stable worker signature from explicit Lisa variables first, falling
|
|
70
|
+
* back to `LISA_REMOTE_AGENT` (set by the remote-agent bootstrap for Cursor,
|
|
71
|
+
* Copilot, OpenCode, and Antigravity) and then Codex/Claude-specific markers.
|
|
72
|
+
* @returns Current runtime signature
|
|
73
|
+
*/
|
|
74
|
+
export function currentRuntimeWorkerSignature() {
|
|
75
|
+
const env = process["env"];
|
|
76
|
+
const host = env.LISA_WORKER_HOST ??
|
|
77
|
+
env.LISA_REMOTE_AGENT ??
|
|
78
|
+
(env.CODEX_HOME || env.CODEX_SANDBOX
|
|
79
|
+
? "codex"
|
|
80
|
+
: env.CLAUDECODE
|
|
81
|
+
? "claude"
|
|
82
|
+
: "unknown");
|
|
83
|
+
return {
|
|
84
|
+
host: host.toLowerCase(),
|
|
85
|
+
model: env.LISA_WORKER_MODEL ?? env.CODEX_MODEL ?? "unknown",
|
|
86
|
+
version: env.LISA_WORKER_VERSION ?? env.CODEX_VERSION ?? "unknown",
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Normalize object- and array-shaped worker records into one array.
|
|
91
|
+
* @param record - Parsed worker epoch record
|
|
92
|
+
* @returns Normalized worker entries
|
|
93
|
+
*/
|
|
94
|
+
export function normalizeWorkerAgents(record) {
|
|
95
|
+
if (Array.isArray(record.agents)) {
|
|
96
|
+
return record.agents.filter(isRecord);
|
|
97
|
+
}
|
|
98
|
+
if (Array.isArray(record.workers)) {
|
|
99
|
+
return record.workers.filter(isRecord);
|
|
100
|
+
}
|
|
101
|
+
if (isRecord(record.agents)) {
|
|
102
|
+
return Object.entries(record.agents).map(([id, value]) => ({
|
|
103
|
+
...(isRecord(value) ? value : {}),
|
|
104
|
+
id,
|
|
105
|
+
}));
|
|
106
|
+
}
|
|
107
|
+
if (isRecord(record.workers)) {
|
|
108
|
+
return Object.entries(record.workers).map(([id, value]) => ({
|
|
109
|
+
...(isRecord(value) ? value : {}),
|
|
110
|
+
id,
|
|
111
|
+
}));
|
|
112
|
+
}
|
|
113
|
+
return [];
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Find the recorded worker entry whose host matches the current signature.
|
|
117
|
+
* @param agents - Normalized worker entries
|
|
118
|
+
* @param signature - Current runtime worker signature
|
|
119
|
+
* @returns The matching worker entry, or undefined
|
|
120
|
+
*/
|
|
121
|
+
export function findWorkerRecordForHost(agents, signature) {
|
|
122
|
+
return agents.find(agent => typeof agent.host === "string" &&
|
|
123
|
+
agent.host.toLowerCase() === signature.host);
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Compute the model/version drift fragments between a recorded worker entry and
|
|
127
|
+
* the current runtime signature. An empty array means the epoch is in sync.
|
|
128
|
+
* @param record - Recorded worker entry for the current host
|
|
129
|
+
* @param signature - Current runtime worker signature
|
|
130
|
+
* @returns Human-readable drift fragments
|
|
131
|
+
*/
|
|
132
|
+
export function computeWorkerDrift(record, signature) {
|
|
133
|
+
const recordedModel = stringField(record.modelId ?? record.model);
|
|
134
|
+
const recordedVersion = stringField(record.version);
|
|
135
|
+
return [
|
|
136
|
+
compareWorkerField("model", recordedModel, signature.model),
|
|
137
|
+
compareWorkerField("version", recordedVersion, signature.version),
|
|
138
|
+
].filter((entry) => entry !== null);
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Resolve the recorded qualification-evidence pointer for a worker entry.
|
|
142
|
+
* @param record - Recorded worker entry
|
|
143
|
+
* @returns Trimmed evidence pointer, or null when absent
|
|
144
|
+
*/
|
|
145
|
+
export function resolveRecordedEvidence(record) {
|
|
146
|
+
return stringField(record.qualificationEvidence ?? record.evidence);
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Return a human-readable drift fragment for one worker field.
|
|
150
|
+
* @param name - Field name
|
|
151
|
+
* @param recorded - Recorded value
|
|
152
|
+
* @param current - Current value
|
|
153
|
+
* @returns Drift fragment, or null when unchanged/unobservable
|
|
154
|
+
*/
|
|
155
|
+
export function compareWorkerField(name, recorded, current) {
|
|
156
|
+
if (!recorded || current === "unknown" || recorded === current) {
|
|
157
|
+
return null;
|
|
158
|
+
}
|
|
159
|
+
return `${name} recorded ${recorded} now ${current}`;
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Count local rules/skills whose rationale mentions worker-specific workarounds.
|
|
163
|
+
* @param targetPath - Project path to scan
|
|
164
|
+
* @returns Number of candidate files
|
|
165
|
+
*/
|
|
166
|
+
export async function countWorkerWorkaroundCandidates(targetPath) {
|
|
167
|
+
const roots = [
|
|
168
|
+
path.join(targetPath, "plugins", "src", "base", "rules"),
|
|
169
|
+
path.join(targetPath, "plugins", "src", "base", "skills"),
|
|
170
|
+
];
|
|
171
|
+
const counts = await Promise.all(roots.map(root => countMatchingMarkdownFiles(root, isWorkerWorkaround)));
|
|
172
|
+
return counts.reduce((total, count) => total + count, 0);
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Determine whether a markdown file describes a worker workaround.
|
|
176
|
+
* @param content - Markdown content
|
|
177
|
+
* @returns True when content is a subtraction-pass candidate
|
|
178
|
+
*/
|
|
179
|
+
function isWorkerWorkaround(content) {
|
|
180
|
+
return /\b(model|worker|host|epoch|claude|codex|cursor|opencode|copilot|agy|antigravity)\b[\s\S]{0,160}\b(workaround|limitation|quirk|scaffold|temporary|native capability)\b/iu.test(content);
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* Recursively count markdown files matching a predicate.
|
|
184
|
+
* @param directory - Directory to scan
|
|
185
|
+
* @param predicate - Markdown content predicate
|
|
186
|
+
* @returns Number of matching files
|
|
187
|
+
*/
|
|
188
|
+
async function countMatchingMarkdownFiles(directory, predicate) {
|
|
189
|
+
if (!existsSync(directory)) {
|
|
190
|
+
return 0;
|
|
191
|
+
}
|
|
192
|
+
const counts = await Promise.all((await readdir(directory)).map(async (entry) => {
|
|
193
|
+
const entryPath = path.join(directory, entry);
|
|
194
|
+
const entryStat = await stat(entryPath);
|
|
195
|
+
if (entryStat.isDirectory()) {
|
|
196
|
+
return countMatchingMarkdownFiles(entryPath, predicate);
|
|
197
|
+
}
|
|
198
|
+
if (entry.endsWith(".md") &&
|
|
199
|
+
predicate(await readFile(entryPath, "utf8"))) {
|
|
200
|
+
return 1;
|
|
201
|
+
}
|
|
202
|
+
return 0;
|
|
203
|
+
}));
|
|
204
|
+
return counts.reduce((total, count) => total + count, 0);
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* Narrow unknown JSON values to plain records.
|
|
208
|
+
* @param value - Value to inspect
|
|
209
|
+
* @returns True for plain object records
|
|
210
|
+
*/
|
|
211
|
+
export function isRecord(value) {
|
|
212
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* Normalize a possibly empty string field.
|
|
216
|
+
* @param value - Value to normalize
|
|
217
|
+
* @returns Trimmed string or null
|
|
218
|
+
*/
|
|
219
|
+
export function stringField(value) {
|
|
220
|
+
return typeof value === "string" && value.trim() ? value.trim() : null;
|
|
221
|
+
}
|
|
222
|
+
//# sourceMappingURL=doctor-worker-journey.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"doctor-worker-journey.js","sourceRoot":"","sources":["../../src/cli/doctor-worker-journey.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { prepareHealthEvaluation, runPersistedHealth, serializeHealthEvaluationRequest } from "../health/index.js";
|
|
2
|
+
/** Options accepted by `lisa health`. */
|
|
3
|
+
export interface HealthCliOptions {
|
|
4
|
+
/** Emit a bounded evaluator request without persisting a result. */
|
|
5
|
+
readonly prepareAgentic?: boolean;
|
|
6
|
+
/** Read a digest-bound evaluator response from standard input. */
|
|
7
|
+
readonly agenticEvaluation?: boolean;
|
|
8
|
+
}
|
|
9
|
+
/** Injectable process boundaries for deterministic CLI tests. */
|
|
10
|
+
export interface HealthCliDependencies {
|
|
11
|
+
readonly cwd?: string;
|
|
12
|
+
readonly prepare: typeof prepareHealthEvaluation;
|
|
13
|
+
readonly runPersisted: typeof runPersistedHealth;
|
|
14
|
+
readonly serializeRequest: typeof serializeHealthEvaluationRequest;
|
|
15
|
+
readonly readStdin: () => Promise<string>;
|
|
16
|
+
readonly write: (payload: string) => void;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Read strict UTF-8 evaluator JSON under the protocol's aggregate bound.
|
|
20
|
+
* @param stream - Standard input or an injected test stream
|
|
21
|
+
* @returns Bounded UTF-8 payload
|
|
22
|
+
*/
|
|
23
|
+
export declare function readBoundedHealthInput(stream: AsyncIterable<Buffer | string>): Promise<string>;
|
|
24
|
+
/**
|
|
25
|
+
* Run the public Health v1 CLI without reconstructing any result fields.
|
|
26
|
+
* @param projectPath - Optional host-project path
|
|
27
|
+
* @param options - Prepare/finalize mode
|
|
28
|
+
* @param dependencies - Injectable process and health boundaries
|
|
29
|
+
*/
|
|
30
|
+
export declare function runHealthCli(projectPath: string | undefined, options: HealthCliOptions, dependencies?: Partial<HealthCliDependencies>): Promise<void>;
|
|
31
|
+
//# sourceMappingURL=health-cmd.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"health-cmd.d.ts","sourceRoot":"","sources":["../../src/cli/health-cmd.ts"],"names":[],"mappings":"AAGA,OAAO,EAGL,uBAAuB,EACvB,kBAAkB,EAClB,gCAAgC,EACjC,MAAM,oBAAoB,CAAC;AAI5B,yCAAyC;AACzC,MAAM,WAAW,gBAAgB;IAC/B,oEAAoE;IACpE,QAAQ,CAAC,cAAc,CAAC,EAAE,OAAO,CAAC;IAClC,kEAAkE;IAClE,QAAQ,CAAC,iBAAiB,CAAC,EAAE,OAAO,CAAC;CACtC;AAED,iEAAiE;AACjE,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,OAAO,uBAAuB,CAAC;IACjD,QAAQ,CAAC,YAAY,EAAE,OAAO,kBAAkB,CAAC;IACjD,QAAQ,CAAC,gBAAgB,EAAE,OAAO,gCAAgC,CAAC;IACnE,QAAQ,CAAC,SAAS,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;IAC1C,QAAQ,CAAC,KAAK,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;CAC3C;AAUD;;;;GAIG;AACH,wBAAsB,sBAAsB,CAC1C,MAAM,EAAE,aAAa,CAAC,MAAM,GAAG,MAAM,CAAC,GACrC,OAAO,CAAC,MAAM,CAAC,CAsBjB;AAED;;;;;GAKG;AACH,wBAAsB,YAAY,CAChC,WAAW,EAAE,MAAM,GAAG,SAAS,EAC/B,OAAO,EAAE,gBAAgB,EACzB,YAAY,GAAE,OAAO,CAAC,qBAAqB,CAAM,GAChD,OAAO,CAAC,IAAI,CAAC,CAgCf"}
|