@codyswann/lisa 2.85.1 → 2.87.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.
Files changed (26) hide show
  1. package/package.json +1 -1
  2. package/plugins/lisa/.claude-plugin/plugin.json +1 -1
  3. package/plugins/lisa/.codex-plugin/plugin.json +1 -1
  4. package/plugins/lisa/commands/automation-status.md +5 -0
  5. package/plugins/lisa/scripts/automation-status-report.mjs +170 -0
  6. package/plugins/lisa/skills/automation-status/SKILL.md +75 -0
  7. package/plugins/lisa/skills/automation-status/agents/openai.yaml +4 -0
  8. package/plugins/lisa-cdk/.claude-plugin/plugin.json +1 -1
  9. package/plugins/lisa-cdk/.codex-plugin/plugin.json +1 -1
  10. package/plugins/lisa-expo/.claude-plugin/plugin.json +1 -1
  11. package/plugins/lisa-expo/.codex-plugin/plugin.json +1 -1
  12. package/plugins/lisa-harper-fabric/.claude-plugin/plugin.json +1 -1
  13. package/plugins/lisa-harper-fabric/.codex-plugin/plugin.json +1 -1
  14. package/plugins/lisa-nestjs/.claude-plugin/plugin.json +1 -1
  15. package/plugins/lisa-nestjs/.codex-plugin/plugin.json +1 -1
  16. package/plugins/lisa-openclaw/.claude-plugin/plugin.json +1 -1
  17. package/plugins/lisa-openclaw/.codex-plugin/plugin.json +1 -1
  18. package/plugins/lisa-rails/.claude-plugin/plugin.json +1 -1
  19. package/plugins/lisa-rails/.codex-plugin/plugin.json +1 -1
  20. package/plugins/lisa-typescript/.claude-plugin/plugin.json +1 -1
  21. package/plugins/lisa-typescript/.codex-plugin/plugin.json +1 -1
  22. package/plugins/lisa-wiki/.claude-plugin/plugin.json +1 -1
  23. package/plugins/lisa-wiki/.codex-plugin/plugin.json +1 -1
  24. package/plugins/src/base/commands/automation-status.md +5 -0
  25. package/plugins/src/base/scripts/automation-status-report.mjs +170 -0
  26. package/plugins/src/base/skills/automation-status/SKILL.md +75 -0
package/package.json CHANGED
@@ -82,7 +82,7 @@
82
82
  "lodash": ">=4.18.1"
83
83
  },
84
84
  "name": "@codyswann/lisa",
85
- "version": "2.85.1",
85
+ "version": "2.87.0",
86
86
  "description": "Claude Code governance framework that applies guardrails, guidance, and automated enforcement to projects",
87
87
  "main": "dist/index.js",
88
88
  "exports": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa",
3
- "version": "2.85.1",
3
+ "version": "2.87.0",
4
4
  "description": "Universal governance — agents, skills, commands, hooks, and rules for all projects",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa",
3
- "version": "2.85.1",
3
+ "version": "2.87.0",
4
4
  "description": "Universal governance: agents, skills, commands, hooks, and rules for all projects.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -0,0 +1,5 @@
1
+ ---
2
+ description: "Inspect the current project's Lisa automation fleet and report whether the expected recurring jobs exist, match Lisa's setup contract, and show healthy recent activity. Read-only by default."
3
+ ---
4
+
5
+ Use the /lisa:automation-status skill to inspect the current project's expected Lisa automations, compare them with the runtime's scheduler metadata, and report fleet health, drift, staleness, unsupported jobs, and remediation hints. $ARGUMENTS
@@ -0,0 +1,170 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Shared automation-status report helpers for the base Lisa operator surface.
4
+ *
5
+ * Keep this dependency-free so the grouped fleet rendering contract can ship in
6
+ * plugin distributions and downstream repos before the runtime adapters land.
7
+ */
8
+
9
+ export const AUTOMATION_HEALTH_STATUSES = [
10
+ "HEALTHY",
11
+ "MISSING",
12
+ "UNSUPPORTED",
13
+ "DRIFTED",
14
+ "STALE",
15
+ "FAILING",
16
+ ];
17
+
18
+ export const AUTOMATION_FLEET_VERDICTS = [
19
+ "HEALTHY",
20
+ "PARTIAL_SUPPORT",
21
+ "ATTENTION_NEEDED",
22
+ ];
23
+
24
+ /**
25
+ * @typedef {"HEALTHY" | "MISSING" | "UNSUPPORTED" | "DRIFTED" | "STALE" | "FAILING"} AutomationHealthStatus
26
+ * @typedef {"HEALTHY" | "PARTIAL_SUPPORT" | "ATTENTION_NEEDED"} AutomationFleetVerdict
27
+ *
28
+ * @typedef {{
29
+ * readonly id: string
30
+ * readonly status: AutomationHealthStatus
31
+ * readonly summary: string
32
+ * readonly expectedCadence?: string
33
+ * readonly expectedCommand?: string
34
+ * readonly observed?: string
35
+ * readonly remediation?: string
36
+ * }} AutomationStatusItem
37
+ *
38
+ * @typedef {{
39
+ * readonly id: string
40
+ * readonly title: string
41
+ * readonly items: readonly AutomationStatusItem[]
42
+ * }} AutomationStatusGroup
43
+ *
44
+ * @typedef {{
45
+ * readonly runtime?: string
46
+ * readonly generatedAt?: string
47
+ * readonly groups: readonly AutomationStatusGroup[]
48
+ * }} AutomationStatusReportInput
49
+ */
50
+
51
+ /**
52
+ * @param {readonly AutomationStatusGroup[]} groups
53
+ * @returns {AutomationFleetVerdict}
54
+ */
55
+ export function computeAutomationFleetVerdict(groups) {
56
+ const items = groups.flatMap(group => group.items);
57
+ if (
58
+ items.some(item =>
59
+ ["MISSING", "DRIFTED", "STALE", "FAILING"].includes(item.status)
60
+ )
61
+ ) {
62
+ return "ATTENTION_NEEDED";
63
+ }
64
+ if (items.some(item => item.status === "UNSUPPORTED")) {
65
+ return "PARTIAL_SUPPORT";
66
+ }
67
+ return "HEALTHY";
68
+ }
69
+
70
+ /**
71
+ * @param {readonly AutomationStatusGroup[]} groups
72
+ * @returns {Record<AutomationHealthStatus, number>}
73
+ */
74
+ export function countAutomationHealthStatuses(groups) {
75
+ return groups
76
+ .flatMap(group => group.items)
77
+ .reduce(
78
+ (counts, item) => ({
79
+ ...counts,
80
+ [item.status]: counts[item.status] + 1,
81
+ }),
82
+ {
83
+ HEALTHY: 0,
84
+ MISSING: 0,
85
+ UNSUPPORTED: 0,
86
+ DRIFTED: 0,
87
+ STALE: 0,
88
+ FAILING: 0,
89
+ }
90
+ );
91
+ }
92
+
93
+ /**
94
+ * @param {AutomationStatusReportInput} input
95
+ * @returns {{ readonly verdict: AutomationFleetVerdict, readonly counts: Record<AutomationHealthStatus, number>, readonly text: string }}
96
+ */
97
+ export function renderAutomationStatusReport(input) {
98
+ const groups = input.groups.map(normalizeGroup);
99
+ const verdict = computeAutomationFleetVerdict(groups);
100
+ const counts = countAutomationHealthStatuses(groups);
101
+ const lines = [
102
+ `Overall verdict: ${verdict}`,
103
+ `Counts: ${AUTOMATION_HEALTH_STATUSES.map(status => `${counts[status]} ${status}`).join(", ")}`,
104
+ ];
105
+
106
+ if (input.runtime) {
107
+ lines.push(`Runtime inspected: ${input.runtime}`);
108
+ }
109
+
110
+ if (input.generatedAt) {
111
+ lines.push(`Generated at: ${input.generatedAt}`);
112
+ }
113
+
114
+ for (const group of groups) {
115
+ lines.push("", `${group.id}. ${group.title}`);
116
+ if (group.items.length === 0) {
117
+ lines.push(
118
+ "- UNSUPPORTED empty-group: no automations expected in this group"
119
+ );
120
+ continue;
121
+ }
122
+
123
+ for (const item of group.items) {
124
+ lines.push(`- ${item.status} ${item.id}: ${item.summary}`);
125
+ if (item.expectedCadence || item.expectedCommand) {
126
+ const cadence = item.expectedCadence ?? "cadence unavailable";
127
+ const command = item.expectedCommand ?? "command unavailable";
128
+ lines.push(` Expected: ${cadence} -> ${command}`);
129
+ }
130
+ if (item.observed) {
131
+ lines.push(` Observed: ${item.observed}`);
132
+ }
133
+ if (item.remediation) {
134
+ lines.push(` Remediation: ${item.remediation}`);
135
+ }
136
+ }
137
+ }
138
+
139
+ return {
140
+ verdict,
141
+ counts,
142
+ text: `${lines.join("\n")}\n`,
143
+ };
144
+ }
145
+
146
+ /**
147
+ * @param {AutomationStatusGroup} group
148
+ * @returns {AutomationStatusGroup}
149
+ */
150
+ function normalizeGroup(group) {
151
+ return {
152
+ ...group,
153
+ items: group.items.map(normalizeItem),
154
+ };
155
+ }
156
+
157
+ /**
158
+ * @param {AutomationStatusItem} item
159
+ * @returns {AutomationStatusItem}
160
+ */
161
+ function normalizeItem(item) {
162
+ const normalizedStatus = AUTOMATION_HEALTH_STATUSES.includes(item.status)
163
+ ? item.status
164
+ : "FAILING";
165
+
166
+ return {
167
+ ...item,
168
+ status: normalizedStatus,
169
+ };
170
+ }
@@ -0,0 +1,75 @@
1
+ ---
2
+ name: automation-status
3
+ description: "Read-only operator surface for the current project's Lisa automation fleet. Resolves the expected recurring jobs from the same setup-automations contract Lisa uses to create them, inspects the active runtime scheduler (Codex automations or Claude /schedule), compares live command/cadence/queue arguments against the expected contract, and reports grouped fleet health such as healthy, missing, unsupported, drifted, stale, or failing with remediation guidance."
4
+ allowed-tools: ["Skill", "Bash", "Read"]
5
+ ---
6
+
7
+ # Automation Status: $ARGUMENTS
8
+
9
+ `/lisa:automation-status` is the operator-facing inspection surface for Lisa's unattended job fleet. It answers, for the **current repo only**, whether the recurring Lisa automations that should exist actually exist, still match Lisa's setup contract, and appear healthy based on the runtime metadata available.
10
+
11
+ This command is **read-only** in v1. It does not create, update, resume, rerun, pause, or delete automations. It complements `/lisa:setup-automations`, `/lisa:tear-down-automations`, `/lisa:intake`, `/lisa:repair-intake`, `doctor`, and `monitor`; it does not replace them.
12
+
13
+ ## Confirmation policy
14
+
15
+ Do **not** ask for confirmation once invoked. This skill inspects scheduler state and reports what it finds. There are no write-side effects in the v1 surface.
16
+
17
+ ## Scope
18
+
19
+ Inspect only the Lisa automation fleet for the current project:
20
+
21
+ - `intake-repair`
22
+ - `intake-prd`
23
+ - `intake-tickets`
24
+ - `exploratory-bugs` when the current stack supports `exploratory-qa`
25
+ - `exploratory-prds`
26
+
27
+ Resolve the expected project identifier, fleet naming prefix, queue arguments, cadence, and stack-support rules from the same contract used by `setup-automations` and `tear-down-automations`. Do **not** invent a second source of truth for fleet naming or queue resolution.
28
+
29
+ ## Runtime inspection
30
+
31
+ Branch on the active runtime and prefer the runtime's native automation listing surface:
32
+
33
+ - **Codex**: inspect Codex automations metadata first. Use backing-store files only as a fallback or to enrich timestamps when the runtime surface cannot provide enough status detail directly.
34
+ - **Claude**: inspect the `/schedule` listing surface and any exposed recency or failure metadata available there.
35
+ - **Other runtimes**: if no native recurring-task inspection exists, report that automation-status is unsupported in this runtime rather than guessing.
36
+
37
+ The report must stay repo-scoped: inspect only automations whose names belong to the current repo's Lisa fleet prefix, and do not absorb unrelated automations into the result.
38
+
39
+ ## What to report
40
+
41
+ For each expected automation, report:
42
+
43
+ 1. Whether it exists.
44
+ 2. Whether it is expected or intentionally unsupported.
45
+ 3. The configured command and cadence Lisa expects.
46
+ 4. Any detected drift in name, cadence, command shape, or queue arguments.
47
+ 5. Any available recent-run health signal such as stale last-run timing or repeated failure status.
48
+ 6. A concise remediation hint when attention is needed.
49
+
50
+ Emit an overall grouped fleet verdict such as `HEALTHY`, `ATTENTION_NEEDED`, or `PARTIAL_SUPPORT`, plus the runtime surface inspected.
51
+
52
+ Render the report in grouped sections using the shared `scripts/automation-status-report.mjs` contract:
53
+
54
+ ```text
55
+ Overall verdict: <VERDICT>
56
+ Counts: <n HEALTHY>, <n MISSING>, <n UNSUPPORTED>, <n DRIFTED>, <n STALE>, <n FAILING>
57
+ Runtime inspected: <runtime surface>
58
+ Generated at: <ISO timestamp>
59
+
60
+ 1. <group title>
61
+ - <STATUS> <automation-id>: <summary>
62
+ Expected: <cadence> -> <command>
63
+ Observed: <what the runtime exposed>
64
+ Remediation: <next step when attention is needed>
65
+ ```
66
+
67
+ Keep observable runtime facts separate from remediation guidance so operators can distinguish drift, unsupported jobs, and actual failures quickly.
68
+
69
+ ## Rules
70
+
71
+ - Stay **read-only**. Never create, update, delete, enable, disable, or rerun automations from this skill.
72
+ - Reuse `setup-automations` contract logic for expected fleet resolution, cadence, queue arguments, naming, and stack-specific support checks.
73
+ - Distinguish **unsupported** from **missing**. An exploratory job omitted because the current stack lacks `exploratory-qa` is not a failure.
74
+ - If the runtime cannot expose a field such as last-run timestamp or failure state, say that explicitly instead of implying health.
75
+ - Keep the output operational and repo-scoped so operators can tell whether Lisa's unattended surfaces are present, current, and healthy right now.
@@ -0,0 +1,4 @@
1
+ display_name: "Automation Status"
2
+ short_description: "Read-only operator surface for the current project's Lisa automation fleet"
3
+ default_prompt:
4
+ - "Use $automation-status: Read-only operator surface for the current project's Lisa automation fleet."
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-cdk",
3
- "version": "2.85.1",
3
+ "version": "2.87.0",
4
4
  "description": "AWS CDK-specific plugin",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-cdk",
3
- "version": "2.85.1",
3
+ "version": "2.87.0",
4
4
  "description": "AWS CDK-specific Lisa plugin.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-expo",
3
- "version": "2.85.1",
3
+ "version": "2.87.0",
4
4
  "description": "Expo/React Native-specific skills, agents, rules, and MCP servers",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-expo",
3
- "version": "2.85.1",
3
+ "version": "2.87.0",
4
4
  "description": "Expo and React Native-specific skills, agents, rules, and MCP servers.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-harper-fabric",
3
- "version": "2.85.1",
3
+ "version": "2.87.0",
4
4
  "description": "Harper/Fabric-specific rules for TypeScript component apps",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-harper-fabric",
3
- "version": "2.85.1",
3
+ "version": "2.87.0",
4
4
  "description": "Harper/Fabric-specific Lisa rules for TypeScript component apps.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-nestjs",
3
- "version": "2.85.1",
3
+ "version": "2.87.0",
4
4
  "description": "NestJS-specific skills (GraphQL, TypeORM) and hooks (migration write-protection)",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-nestjs",
3
- "version": "2.85.1",
3
+ "version": "2.87.0",
4
4
  "description": "NestJS-specific skills and migration write-protection hooks.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-openclaw",
3
- "version": "2.85.1",
3
+ "version": "2.87.0",
4
4
  "description": "Connect staff roles to Telegram or Slack via OpenClaw — facilitator/specialist hub-and-spoke routing and repo-coding topics, for Claude Code and Codex",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-openclaw",
3
- "version": "2.85.1",
3
+ "version": "2.87.0",
4
4
  "description": "Connect staff roles to Telegram or Slack via OpenClaw — facilitator/specialist hub-and-spoke routing and repo-coding topics, across Claude and Codex.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-rails",
3
- "version": "2.85.1",
3
+ "version": "2.87.0",
4
4
  "description": "Ruby on Rails-specific hooks — RuboCop linting/formatting and ast-grep scanning on edit",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-rails",
3
- "version": "2.85.1",
3
+ "version": "2.87.0",
4
4
  "description": "Ruby on Rails-specific skills and hooks for RuboCop and ast-grep scanning on edit.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-typescript",
3
- "version": "2.85.1",
3
+ "version": "2.87.0",
4
4
  "description": "TypeScript-specific hooks — Prettier formatting, ESLint linting, and ast-grep scanning on edit",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-typescript",
3
- "version": "2.85.1",
3
+ "version": "2.87.0",
4
4
  "description": "TypeScript-specific hooks for formatting, linting, and ast-grep scanning on edit.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-wiki",
3
- "version": "2.85.1",
3
+ "version": "2.87.0",
4
4
  "description": "LLM Wiki — a distributable, git-native markdown knowledge base for Claude Code and Codex",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-wiki",
3
- "version": "2.85.1",
3
+ "version": "2.87.0",
4
4
  "description": "Distributable LLM Wiki kernel — ingest, query, lint, and maintain a git-native markdown knowledge base across Claude and Codex.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -0,0 +1,5 @@
1
+ ---
2
+ description: "Inspect the current project's Lisa automation fleet and report whether the expected recurring jobs exist, match Lisa's setup contract, and show healthy recent activity. Read-only by default."
3
+ ---
4
+
5
+ Use the /lisa:automation-status skill to inspect the current project's expected Lisa automations, compare them with the runtime's scheduler metadata, and report fleet health, drift, staleness, unsupported jobs, and remediation hints. $ARGUMENTS
@@ -0,0 +1,170 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Shared automation-status report helpers for the base Lisa operator surface.
4
+ *
5
+ * Keep this dependency-free so the grouped fleet rendering contract can ship in
6
+ * plugin distributions and downstream repos before the runtime adapters land.
7
+ */
8
+
9
+ export const AUTOMATION_HEALTH_STATUSES = [
10
+ "HEALTHY",
11
+ "MISSING",
12
+ "UNSUPPORTED",
13
+ "DRIFTED",
14
+ "STALE",
15
+ "FAILING",
16
+ ];
17
+
18
+ export const AUTOMATION_FLEET_VERDICTS = [
19
+ "HEALTHY",
20
+ "PARTIAL_SUPPORT",
21
+ "ATTENTION_NEEDED",
22
+ ];
23
+
24
+ /**
25
+ * @typedef {"HEALTHY" | "MISSING" | "UNSUPPORTED" | "DRIFTED" | "STALE" | "FAILING"} AutomationHealthStatus
26
+ * @typedef {"HEALTHY" | "PARTIAL_SUPPORT" | "ATTENTION_NEEDED"} AutomationFleetVerdict
27
+ *
28
+ * @typedef {{
29
+ * readonly id: string
30
+ * readonly status: AutomationHealthStatus
31
+ * readonly summary: string
32
+ * readonly expectedCadence?: string
33
+ * readonly expectedCommand?: string
34
+ * readonly observed?: string
35
+ * readonly remediation?: string
36
+ * }} AutomationStatusItem
37
+ *
38
+ * @typedef {{
39
+ * readonly id: string
40
+ * readonly title: string
41
+ * readonly items: readonly AutomationStatusItem[]
42
+ * }} AutomationStatusGroup
43
+ *
44
+ * @typedef {{
45
+ * readonly runtime?: string
46
+ * readonly generatedAt?: string
47
+ * readonly groups: readonly AutomationStatusGroup[]
48
+ * }} AutomationStatusReportInput
49
+ */
50
+
51
+ /**
52
+ * @param {readonly AutomationStatusGroup[]} groups
53
+ * @returns {AutomationFleetVerdict}
54
+ */
55
+ export function computeAutomationFleetVerdict(groups) {
56
+ const items = groups.flatMap(group => group.items);
57
+ if (
58
+ items.some(item =>
59
+ ["MISSING", "DRIFTED", "STALE", "FAILING"].includes(item.status)
60
+ )
61
+ ) {
62
+ return "ATTENTION_NEEDED";
63
+ }
64
+ if (items.some(item => item.status === "UNSUPPORTED")) {
65
+ return "PARTIAL_SUPPORT";
66
+ }
67
+ return "HEALTHY";
68
+ }
69
+
70
+ /**
71
+ * @param {readonly AutomationStatusGroup[]} groups
72
+ * @returns {Record<AutomationHealthStatus, number>}
73
+ */
74
+ export function countAutomationHealthStatuses(groups) {
75
+ return groups
76
+ .flatMap(group => group.items)
77
+ .reduce(
78
+ (counts, item) => ({
79
+ ...counts,
80
+ [item.status]: counts[item.status] + 1,
81
+ }),
82
+ {
83
+ HEALTHY: 0,
84
+ MISSING: 0,
85
+ UNSUPPORTED: 0,
86
+ DRIFTED: 0,
87
+ STALE: 0,
88
+ FAILING: 0,
89
+ }
90
+ );
91
+ }
92
+
93
+ /**
94
+ * @param {AutomationStatusReportInput} input
95
+ * @returns {{ readonly verdict: AutomationFleetVerdict, readonly counts: Record<AutomationHealthStatus, number>, readonly text: string }}
96
+ */
97
+ export function renderAutomationStatusReport(input) {
98
+ const groups = input.groups.map(normalizeGroup);
99
+ const verdict = computeAutomationFleetVerdict(groups);
100
+ const counts = countAutomationHealthStatuses(groups);
101
+ const lines = [
102
+ `Overall verdict: ${verdict}`,
103
+ `Counts: ${AUTOMATION_HEALTH_STATUSES.map(status => `${counts[status]} ${status}`).join(", ")}`,
104
+ ];
105
+
106
+ if (input.runtime) {
107
+ lines.push(`Runtime inspected: ${input.runtime}`);
108
+ }
109
+
110
+ if (input.generatedAt) {
111
+ lines.push(`Generated at: ${input.generatedAt}`);
112
+ }
113
+
114
+ for (const group of groups) {
115
+ lines.push("", `${group.id}. ${group.title}`);
116
+ if (group.items.length === 0) {
117
+ lines.push(
118
+ "- UNSUPPORTED empty-group: no automations expected in this group"
119
+ );
120
+ continue;
121
+ }
122
+
123
+ for (const item of group.items) {
124
+ lines.push(`- ${item.status} ${item.id}: ${item.summary}`);
125
+ if (item.expectedCadence || item.expectedCommand) {
126
+ const cadence = item.expectedCadence ?? "cadence unavailable";
127
+ const command = item.expectedCommand ?? "command unavailable";
128
+ lines.push(` Expected: ${cadence} -> ${command}`);
129
+ }
130
+ if (item.observed) {
131
+ lines.push(` Observed: ${item.observed}`);
132
+ }
133
+ if (item.remediation) {
134
+ lines.push(` Remediation: ${item.remediation}`);
135
+ }
136
+ }
137
+ }
138
+
139
+ return {
140
+ verdict,
141
+ counts,
142
+ text: `${lines.join("\n")}\n`,
143
+ };
144
+ }
145
+
146
+ /**
147
+ * @param {AutomationStatusGroup} group
148
+ * @returns {AutomationStatusGroup}
149
+ */
150
+ function normalizeGroup(group) {
151
+ return {
152
+ ...group,
153
+ items: group.items.map(normalizeItem),
154
+ };
155
+ }
156
+
157
+ /**
158
+ * @param {AutomationStatusItem} item
159
+ * @returns {AutomationStatusItem}
160
+ */
161
+ function normalizeItem(item) {
162
+ const normalizedStatus = AUTOMATION_HEALTH_STATUSES.includes(item.status)
163
+ ? item.status
164
+ : "FAILING";
165
+
166
+ return {
167
+ ...item,
168
+ status: normalizedStatus,
169
+ };
170
+ }
@@ -0,0 +1,75 @@
1
+ ---
2
+ name: automation-status
3
+ description: "Read-only operator surface for the current project's Lisa automation fleet. Resolves the expected recurring jobs from the same setup-automations contract Lisa uses to create them, inspects the active runtime scheduler (Codex automations or Claude /schedule), compares live command/cadence/queue arguments against the expected contract, and reports grouped fleet health such as healthy, missing, unsupported, drifted, stale, or failing with remediation guidance."
4
+ allowed-tools: ["Skill", "Bash", "Read"]
5
+ ---
6
+
7
+ # Automation Status: $ARGUMENTS
8
+
9
+ `/lisa:automation-status` is the operator-facing inspection surface for Lisa's unattended job fleet. It answers, for the **current repo only**, whether the recurring Lisa automations that should exist actually exist, still match Lisa's setup contract, and appear healthy based on the runtime metadata available.
10
+
11
+ This command is **read-only** in v1. It does not create, update, resume, rerun, pause, or delete automations. It complements `/lisa:setup-automations`, `/lisa:tear-down-automations`, `/lisa:intake`, `/lisa:repair-intake`, `doctor`, and `monitor`; it does not replace them.
12
+
13
+ ## Confirmation policy
14
+
15
+ Do **not** ask for confirmation once invoked. This skill inspects scheduler state and reports what it finds. There are no write-side effects in the v1 surface.
16
+
17
+ ## Scope
18
+
19
+ Inspect only the Lisa automation fleet for the current project:
20
+
21
+ - `intake-repair`
22
+ - `intake-prd`
23
+ - `intake-tickets`
24
+ - `exploratory-bugs` when the current stack supports `exploratory-qa`
25
+ - `exploratory-prds`
26
+
27
+ Resolve the expected project identifier, fleet naming prefix, queue arguments, cadence, and stack-support rules from the same contract used by `setup-automations` and `tear-down-automations`. Do **not** invent a second source of truth for fleet naming or queue resolution.
28
+
29
+ ## Runtime inspection
30
+
31
+ Branch on the active runtime and prefer the runtime's native automation listing surface:
32
+
33
+ - **Codex**: inspect Codex automations metadata first. Use backing-store files only as a fallback or to enrich timestamps when the runtime surface cannot provide enough status detail directly.
34
+ - **Claude**: inspect the `/schedule` listing surface and any exposed recency or failure metadata available there.
35
+ - **Other runtimes**: if no native recurring-task inspection exists, report that automation-status is unsupported in this runtime rather than guessing.
36
+
37
+ The report must stay repo-scoped: inspect only automations whose names belong to the current repo's Lisa fleet prefix, and do not absorb unrelated automations into the result.
38
+
39
+ ## What to report
40
+
41
+ For each expected automation, report:
42
+
43
+ 1. Whether it exists.
44
+ 2. Whether it is expected or intentionally unsupported.
45
+ 3. The configured command and cadence Lisa expects.
46
+ 4. Any detected drift in name, cadence, command shape, or queue arguments.
47
+ 5. Any available recent-run health signal such as stale last-run timing or repeated failure status.
48
+ 6. A concise remediation hint when attention is needed.
49
+
50
+ Emit an overall grouped fleet verdict such as `HEALTHY`, `ATTENTION_NEEDED`, or `PARTIAL_SUPPORT`, plus the runtime surface inspected.
51
+
52
+ Render the report in grouped sections using the shared `scripts/automation-status-report.mjs` contract:
53
+
54
+ ```text
55
+ Overall verdict: <VERDICT>
56
+ Counts: <n HEALTHY>, <n MISSING>, <n UNSUPPORTED>, <n DRIFTED>, <n STALE>, <n FAILING>
57
+ Runtime inspected: <runtime surface>
58
+ Generated at: <ISO timestamp>
59
+
60
+ 1. <group title>
61
+ - <STATUS> <automation-id>: <summary>
62
+ Expected: <cadence> -> <command>
63
+ Observed: <what the runtime exposed>
64
+ Remediation: <next step when attention is needed>
65
+ ```
66
+
67
+ Keep observable runtime facts separate from remediation guidance so operators can distinguish drift, unsupported jobs, and actual failures quickly.
68
+
69
+ ## Rules
70
+
71
+ - Stay **read-only**. Never create, update, delete, enable, disable, or rerun automations from this skill.
72
+ - Reuse `setup-automations` contract logic for expected fleet resolution, cadence, queue arguments, naming, and stack-specific support checks.
73
+ - Distinguish **unsupported** from **missing**. An exploratory job omitted because the current stack lacks `exploratory-qa` is not a failure.
74
+ - If the runtime cannot expose a field such as last-run timestamp or failure state, say that explicitly instead of implying health.
75
+ - Keep the output operational and repo-scoped so operators can tell whether Lisa's unattended surfaces are present, current, and healthy right now.