@codyswann/lisa 2.255.0 → 2.256.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/package.json +1 -1
- 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-automation-status/SKILL.md +11 -3
- package/plugins/lisa/scripts/automation-status-claude-adapter.mjs +64 -8
- package/plugins/lisa/scripts/automation-status-codex-adapter.mjs +61 -5
- package/plugins/lisa/scripts/automation-status-report.mjs +30 -0
- package/plugins/lisa/scripts/automation-status-run-history.mjs +185 -0
- package/plugins/lisa/skills/lisa-automation-status/SKILL.md +11 -3
- package/plugins/lisa-agy/plugin.json +1 -1
- package/plugins/lisa-agy/scripts/automation-status-claude-adapter.mjs +64 -8
- package/plugins/lisa-agy/scripts/automation-status-codex-adapter.mjs +61 -5
- package/plugins/lisa-agy/scripts/automation-status-report.mjs +30 -0
- package/plugins/lisa-agy/scripts/automation-status-run-history.mjs +185 -0
- package/plugins/lisa-agy/skills/lisa-automation-status/SKILL.md +11 -3
- 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/scripts/automation-status-claude-adapter.mjs +64 -8
- package/plugins/lisa-copilot/scripts/automation-status-codex-adapter.mjs +61 -5
- package/plugins/lisa-copilot/scripts/automation-status-report.mjs +30 -0
- package/plugins/lisa-copilot/scripts/automation-status-run-history.mjs +185 -0
- package/plugins/lisa-copilot/skills/lisa-automation-status/SKILL.md +11 -3
- package/plugins/lisa-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cursor/scripts/automation-status-claude-adapter.mjs +64 -8
- package/plugins/lisa-cursor/scripts/automation-status-codex-adapter.mjs +61 -5
- package/plugins/lisa-cursor/scripts/automation-status-report.mjs +30 -0
- package/plugins/lisa-cursor/scripts/automation-status-run-history.mjs +185 -0
- package/plugins/lisa-cursor/skills/lisa-automation-status/SKILL.md +11 -3
- 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/scripts/automation-status-claude-adapter.mjs +64 -8
- package/plugins/src/base/scripts/automation-status-codex-adapter.mjs +61 -5
- package/plugins/src/base/scripts/automation-status-report.mjs +30 -0
- package/plugins/src/base/scripts/automation-status-run-history.mjs +185 -0
- package/plugins/src/base/skills/lisa-automation-status/SKILL.md +11 -3
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Shared read-only run-history projection for `/lisa:automation-status`.
|
|
4
|
+
*
|
|
5
|
+
* The durable run-outcome substrate (RBC-3, `automation-run-record.mjs`) stores
|
|
6
|
+
* one bounded JSONL file per registered loop under `.lisa/automations/runs/`.
|
|
7
|
+
* This module turns that substrate — plus the checked-in per-loop runbook
|
|
8
|
+
* (`automation-runbook-contract`) — into the per-item display fields both
|
|
9
|
+
* runtime adapters attach to their status rows, so the Codex and Claude
|
|
10
|
+
* adapters never diverge on how the contract, last outcome, and bounded history
|
|
11
|
+
* are rendered.
|
|
12
|
+
*
|
|
13
|
+
* STRICTLY READ-ONLY: it stats the runbook and reads the run-record file. It
|
|
14
|
+
* never creates the runs directory, a runbook, or a run record — a status read
|
|
15
|
+
* must leave the fleet byte-identical.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
import fs from "node:fs/promises";
|
|
19
|
+
import path from "node:path";
|
|
20
|
+
|
|
21
|
+
import {
|
|
22
|
+
automationRunRecordPath,
|
|
23
|
+
readAutomationRunRecords,
|
|
24
|
+
} from "./automation-run-record.mjs";
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Inline history cap: the newest N outcomes are listed, the remainder is only
|
|
28
|
+
* counted. A bounded view of an already-bounded file, with the trim stated in
|
|
29
|
+
* the output rather than applied silently.
|
|
30
|
+
*/
|
|
31
|
+
export const AUTOMATION_RUN_HISTORY_DISPLAY_LIMIT = 5;
|
|
32
|
+
|
|
33
|
+
/** The recorded outcome that signals a loop could not finish its own work. */
|
|
34
|
+
export const RECOVERY_REQUIRED_OUTCOME = "recovery-required";
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* How many trailing `recovery-required` runs in a row flip a loop to `FAILING`.
|
|
38
|
+
* The RBC-5 acceptance criteria pin "last three runs" as the escalation
|
|
39
|
+
* trigger; that wins over the ticket prose's looser "five in a row" pattern.
|
|
40
|
+
*/
|
|
41
|
+
export const RECOVERY_REQUIRED_ESCALATION_THRESHOLD = 3;
|
|
42
|
+
|
|
43
|
+
const RUNBOOK_NOT_SCAFFOLDED_LINE =
|
|
44
|
+
"not scaffolded — run /lisa:setup-automations";
|
|
45
|
+
const NO_RECORDED_RUNS_LINE = "no recorded runs yet";
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* @typedef {{
|
|
49
|
+
* readonly ts: string
|
|
50
|
+
* readonly outcome: string
|
|
51
|
+
* readonly summary: string
|
|
52
|
+
* }} AutomationLastOutcome
|
|
53
|
+
*
|
|
54
|
+
* @typedef {{
|
|
55
|
+
* readonly runbook: string
|
|
56
|
+
* readonly lastOutcome?: AutomationLastOutcome
|
|
57
|
+
* readonly outcomeHistory: readonly string[]
|
|
58
|
+
* readonly olderRecordCount: number
|
|
59
|
+
* readonly recoveryRequiredStreak: number
|
|
60
|
+
* readonly recoverySummaries: readonly string[]
|
|
61
|
+
* readonly skippedCorruptLines: number
|
|
62
|
+
* }} AutomationRunDisplay
|
|
63
|
+
*/
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Resolve the read-only run-history display fields for one registered loop.
|
|
67
|
+
*
|
|
68
|
+
* @param {{
|
|
69
|
+
* readonly projectRoot?: string
|
|
70
|
+
* readonly loopId: string
|
|
71
|
+
* readonly runbookPath?: string
|
|
72
|
+
* }} input
|
|
73
|
+
* @returns {Promise<AutomationRunDisplay>}
|
|
74
|
+
*/
|
|
75
|
+
export async function resolveAutomationRunDisplay(input) {
|
|
76
|
+
const projectRoot = path.resolve(input.projectRoot ?? process.cwd());
|
|
77
|
+
const runbook = await resolveRunbookLine(projectRoot, input.runbookPath);
|
|
78
|
+
const { records, skippedCorruptLines } = await readAutomationRunRecords(
|
|
79
|
+
automationRunRecordPath(projectRoot, input.loopId)
|
|
80
|
+
);
|
|
81
|
+
|
|
82
|
+
const newestFirst = records.toReversed();
|
|
83
|
+
const latest = records.at(-1);
|
|
84
|
+
const lastOutcome = latest
|
|
85
|
+
? { ts: latest.ts, outcome: latest.outcome, summary: latest.summary }
|
|
86
|
+
: undefined;
|
|
87
|
+
const outcomeHistory = newestFirst
|
|
88
|
+
.slice(0, AUTOMATION_RUN_HISTORY_DISPLAY_LIMIT)
|
|
89
|
+
.map(record => record.outcome);
|
|
90
|
+
const olderRecordCount = Math.max(
|
|
91
|
+
0,
|
|
92
|
+
records.length - AUTOMATION_RUN_HISTORY_DISPLAY_LIMIT
|
|
93
|
+
);
|
|
94
|
+
const trailingRecovery = collectTrailingRecoveryRuns(records);
|
|
95
|
+
|
|
96
|
+
return {
|
|
97
|
+
runbook,
|
|
98
|
+
lastOutcome,
|
|
99
|
+
outcomeHistory,
|
|
100
|
+
olderRecordCount,
|
|
101
|
+
recoveryRequiredStreak: trailingRecovery.length,
|
|
102
|
+
recoverySummaries: trailingRecovery.map(record => record.summary),
|
|
103
|
+
skippedCorruptLines,
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Force a `FAILING` verdict when a loop has recorded three or more consecutive
|
|
109
|
+
* `recovery-required` runs — the fleet-health signal the scheduler surface
|
|
110
|
+
* cannot see on its own. Returns a run-signal-shaped escalation, or null when
|
|
111
|
+
* the streak is below the threshold.
|
|
112
|
+
*
|
|
113
|
+
* @param {AutomationRunDisplay | undefined} runDisplay
|
|
114
|
+
* @returns {{ readonly status: "FAILING", readonly summary: string, readonly remediation: string } | null}
|
|
115
|
+
*/
|
|
116
|
+
export function resolveRecoveryEscalation(runDisplay) {
|
|
117
|
+
if (
|
|
118
|
+
!runDisplay ||
|
|
119
|
+
runDisplay.recoveryRequiredStreak < RECOVERY_REQUIRED_ESCALATION_THRESHOLD
|
|
120
|
+
) {
|
|
121
|
+
return null;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// Number the citations rather than joining on a delimiter: recorded summaries
|
|
125
|
+
// carry their own `;` and `.`, so a `; `-separated list is ambiguous. `(1) …
|
|
126
|
+
// (2) …` stays legible no matter what punctuation a summary contains.
|
|
127
|
+
const citations = runDisplay.recoverySummaries
|
|
128
|
+
.map((summary, index) => `(${index + 1}) ${summary}`)
|
|
129
|
+
.join(" ");
|
|
130
|
+
return {
|
|
131
|
+
status: "FAILING",
|
|
132
|
+
summary: `the last ${runDisplay.recoveryRequiredStreak} recorded runs all required recovery`,
|
|
133
|
+
remediation: `Repeated recovery-required runs — ${citations} Inspect the loop's runbook and the cited runs, fix the recurring failure, then let the next scheduled run confirm recovery.`,
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* @param {string} projectRoot
|
|
139
|
+
* @param {string | undefined} runbookPath
|
|
140
|
+
* @returns {Promise<string>}
|
|
141
|
+
*/
|
|
142
|
+
async function resolveRunbookLine(projectRoot, runbookPath) {
|
|
143
|
+
if (!runbookPath) {
|
|
144
|
+
return RUNBOOK_NOT_SCAFFOLDED_LINE;
|
|
145
|
+
}
|
|
146
|
+
const scaffolded = await runbookIsScaffolded(
|
|
147
|
+
path.join(projectRoot, runbookPath)
|
|
148
|
+
);
|
|
149
|
+
return scaffolded ? runbookPath : RUNBOOK_NOT_SCAFFOLDED_LINE;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Read-only existence check for a checked-in runbook. Any stat failure — the
|
|
154
|
+
* file is absent, unreadable, or not a regular file — degrades to "not
|
|
155
|
+
* scaffolded" so the status read never implies health it could not confirm and
|
|
156
|
+
* never throws mid-report.
|
|
157
|
+
*
|
|
158
|
+
* @param {string} runbookAbsolutePath
|
|
159
|
+
* @returns {Promise<boolean>}
|
|
160
|
+
*/
|
|
161
|
+
async function runbookIsScaffolded(runbookAbsolutePath) {
|
|
162
|
+
try {
|
|
163
|
+
const stat = await fs.stat(runbookAbsolutePath);
|
|
164
|
+
return stat.isFile();
|
|
165
|
+
} catch {
|
|
166
|
+
return false;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* @param {readonly import("./automation-run-record.mjs").AutomationRunRecord[]} records
|
|
172
|
+
* @returns {readonly import("./automation-run-record.mjs").AutomationRunRecord[]} trailing recovery-required runs, newest first
|
|
173
|
+
*/
|
|
174
|
+
function collectTrailingRecoveryRuns(records) {
|
|
175
|
+
const trailing = [];
|
|
176
|
+
for (let index = records.length - 1; index >= 0; index -= 1) {
|
|
177
|
+
if (records[index].outcome !== RECOVERY_REQUIRED_OUTCOME) {
|
|
178
|
+
break;
|
|
179
|
+
}
|
|
180
|
+
trailing.push(records[index]);
|
|
181
|
+
}
|
|
182
|
+
return trailing;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
export { RUNBOOK_NOT_SCAFFOLDED_LINE, NO_RECORDED_RUNS_LINE };
|
|
@@ -53,8 +53,13 @@ For each expected automation, report:
|
|
|
53
53
|
4. Any detected drift in name, cadence, command shape, or queue arguments.
|
|
54
54
|
5. Any available recent-run health signal such as stale last-run timing or repeated failure status.
|
|
55
55
|
6. A concise remediation hint when attention is needed.
|
|
56
|
+
7. Where the loop's checked-in runbook lives (`automation-runbook-contract`), or `not scaffolded — run /lisa:setup-automations` when it is absent.
|
|
57
|
+
8. How the last recorded run ended — its outcome, one-line summary, and timestamp — or `no recorded runs yet` when the loop has never recorded one.
|
|
58
|
+
9. A bounded run history: the five most recent outcomes newest first, plus a count of how many older records exist when the file holds more.
|
|
56
59
|
|
|
57
|
-
|
|
60
|
+
The last-run and history facts come from the durable run-outcome substrate recorded by each loop (the RBC-3 records under `.lisa/automations/runs/<loop-id>.jsonl`, read through `readAutomationRunRecords`). That directory is local scheduler state, not project knowledge — read it, never write it.
|
|
61
|
+
|
|
62
|
+
Emit an overall grouped fleet verdict such as `HEALTHY`, `ATTENTION_NEEDED`, or `PARTIAL_SUPPORT`, plus the runtime surface inspected. **Repeated recovery is a fleet-health signal the scheduler cannot see**: when a loop's last three or more consecutive recorded runs are all `recovery-required`, report that loop `FAILING` — and therefore the overall verdict `ATTENTION_NEEDED` — even when its scheduler entry itself looks healthy, and point the remediation at the recorded run summaries.
|
|
58
63
|
|
|
59
64
|
## Operator usage
|
|
60
65
|
|
|
@@ -89,7 +94,7 @@ Status-specific remediation guidance:
|
|
|
89
94
|
- `MISSING`: tell the operator which job is absent and recommend rerunning `/lisa:setup-automations` or recreating the missing job with the expected cadence and command.
|
|
90
95
|
- `DRIFTED`: show the expected versus observed cadence/command mismatch and recommend aligning the scheduler entry with Lisa's current setup contract, usually by rerunning `/lisa:setup-automations`.
|
|
91
96
|
- `STALE`: explain that the job exists but has not run recently enough for its cadence. Recommend inspecting the runtime's recent-run history or failure logs before changing queue state.
|
|
92
|
-
- `FAILING`: surface the failure signal directly and recommend checking the latest runtime error plus the affected queue command (`/lisa:intake`, `/lisa:repair-intake`, or exploratory job) after the scheduler issue is resolved.
|
|
97
|
+
- `FAILING`: surface the failure signal directly and recommend checking the latest runtime error plus the affected queue command (`/lisa:intake`, `/lisa:repair-intake`, or exploratory job) after the scheduler issue is resolved. A loop also reports `FAILING` when its last three or more consecutive recorded runs are all `recovery-required` — even with a healthy scheduler entry — in which case cite the recorded run summaries and point the operator at the loop's runbook.
|
|
93
98
|
- `UNSUPPORTED`: explain why the job is intentionally absent and say that no remediation is required unless the project stack or runtime support changed.
|
|
94
99
|
|
|
95
100
|
Render the report in grouped sections using the shared `scripts/automation-status-report.mjs` contract:
|
|
@@ -104,10 +109,13 @@ Generated at: <ISO timestamp>
|
|
|
104
109
|
- <STATUS> <automation-id>: <summary>
|
|
105
110
|
Expected: <cadence> -> <command>
|
|
106
111
|
Observed: <what the runtime exposed>
|
|
112
|
+
Runbook: <.lisa/automations/<loop-id>.runbook.md, or "not scaffolded — run /lisa:setup-automations">
|
|
113
|
+
Last run: <outcome> — <summary> (<ts>), or "no recorded runs yet"
|
|
114
|
+
History: <outcome>, <outcome>, … (newest first); … and <N> older records
|
|
107
115
|
Remediation: <next step when attention is needed>
|
|
108
116
|
```
|
|
109
117
|
|
|
110
|
-
Keep observable runtime facts separate from remediation guidance so operators can distinguish drift, unsupported jobs, and actual failures quickly.
|
|
118
|
+
The Runbook, Last run, and History lines are observable facts and sit between Observed and Remediation. Keep observable runtime facts separate from remediation guidance so operators can distinguish drift, unsupported jobs, and actual failures quickly.
|
|
111
119
|
|
|
112
120
|
## Rules
|
|
113
121
|
|