@codyswann/lisa 2.255.0 → 2.256.1
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/.codex-plugin/skills/lisa-github-validate-issue/SKILL.md +1 -1
- package/plugins/lisa/.codex-plugin/skills/lisa-github-write-issue/SKILL.md +9 -3
- package/plugins/lisa/.codex-plugin/skills/lisa-implement/SKILL.md +6 -2
- package/plugins/lisa/.codex-plugin/skills/lisa-jira-validate-ticket/SKILL.md +1 -1
- package/plugins/lisa/.codex-plugin/skills/lisa-jira-write-ticket/SKILL.md +9 -6
- package/plugins/lisa/.codex-plugin/skills/lisa-linear-validate-issue/SKILL.md +1 -1
- package/plugins/lisa/.codex-plugin/skills/lisa-linear-write-issue/SKILL.md +9 -3
- package/plugins/lisa/agents/github-agent.md +2 -2
- package/plugins/lisa/agents/jira-agent.md +2 -2
- package/plugins/lisa/agents/linear-agent.md +2 -2
- package/plugins/lisa/rules/eager/config-resolution.md +27 -8
- package/plugins/lisa/rules/eager/pre-flight-autofill.md +21 -7
- package/plugins/lisa/rules/reference/config-resolution.md +55 -16
- package/plugins/lisa/rules/reference/pre-flight-autofill.md +23 -8
- 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/skills/lisa-github-validate-issue/SKILL.md +1 -1
- package/plugins/lisa/skills/lisa-github-write-issue/SKILL.md +9 -3
- package/plugins/lisa/skills/lisa-implement/SKILL.md +6 -2
- package/plugins/lisa/skills/lisa-jira-validate-ticket/SKILL.md +1 -1
- package/plugins/lisa/skills/lisa-jira-write-ticket/SKILL.md +9 -6
- package/plugins/lisa/skills/lisa-linear-validate-issue/SKILL.md +1 -1
- package/plugins/lisa/skills/lisa-linear-write-issue/SKILL.md +9 -3
- package/plugins/lisa-agy/agents/github-agent.md +2 -2
- package/plugins/lisa-agy/agents/jira-agent.md +2 -2
- package/plugins/lisa-agy/agents/linear-agent.md +2 -2
- 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-agy/skills/lisa-github-validate-issue/SKILL.md +1 -1
- package/plugins/lisa-agy/skills/lisa-github-write-issue/SKILL.md +9 -3
- package/plugins/lisa-agy/skills/lisa-implement/SKILL.md +6 -2
- package/plugins/lisa-agy/skills/lisa-jira-validate-ticket/SKILL.md +1 -1
- package/plugins/lisa-agy/skills/lisa-jira-write-ticket/SKILL.md +9 -6
- package/plugins/lisa-agy/skills/lisa-linear-validate-issue/SKILL.md +1 -1
- package/plugins/lisa-agy/skills/lisa-linear-write-issue/SKILL.md +9 -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/agents/github-agent.agent.md +2 -2
- package/plugins/lisa-copilot/agents/jira-agent.agent.md +2 -2
- package/plugins/lisa-copilot/agents/linear-agent.agent.md +2 -2
- package/plugins/lisa-copilot/rules/eager/config-resolution.md +27 -8
- package/plugins/lisa-copilot/rules/eager/pre-flight-autofill.md +21 -7
- package/plugins/lisa-copilot/rules/reference/config-resolution.md +55 -16
- package/plugins/lisa-copilot/rules/reference/pre-flight-autofill.md +23 -8
- 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-copilot/skills/lisa-github-validate-issue/SKILL.md +1 -1
- package/plugins/lisa-copilot/skills/lisa-github-write-issue/SKILL.md +9 -3
- package/plugins/lisa-copilot/skills/lisa-implement/SKILL.md +6 -2
- package/plugins/lisa-copilot/skills/lisa-jira-validate-ticket/SKILL.md +1 -1
- package/plugins/lisa-copilot/skills/lisa-jira-write-ticket/SKILL.md +9 -6
- package/plugins/lisa-copilot/skills/lisa-linear-validate-issue/SKILL.md +1 -1
- package/plugins/lisa-copilot/skills/lisa-linear-write-issue/SKILL.md +9 -3
- package/plugins/lisa-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cursor/agents/github-agent.md +2 -2
- package/plugins/lisa-cursor/agents/jira-agent.md +2 -2
- package/plugins/lisa-cursor/agents/linear-agent.md +2 -2
- package/plugins/lisa-cursor/rules/config-resolution-reference.mdc +55 -16
- package/plugins/lisa-cursor/rules/config-resolution.mdc +27 -8
- package/plugins/lisa-cursor/rules/pre-flight-autofill-reference.mdc +23 -8
- package/plugins/lisa-cursor/rules/pre-flight-autofill.mdc +21 -7
- 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-cursor/skills/lisa-github-validate-issue/SKILL.md +1 -1
- package/plugins/lisa-cursor/skills/lisa-github-write-issue/SKILL.md +9 -3
- package/plugins/lisa-cursor/skills/lisa-implement/SKILL.md +6 -2
- package/plugins/lisa-cursor/skills/lisa-jira-validate-ticket/SKILL.md +1 -1
- package/plugins/lisa-cursor/skills/lisa-jira-write-ticket/SKILL.md +9 -6
- package/plugins/lisa-cursor/skills/lisa-linear-validate-issue/SKILL.md +1 -1
- package/plugins/lisa-cursor/skills/lisa-linear-write-issue/SKILL.md +9 -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/agents/github-agent.md +2 -2
- package/plugins/src/base/agents/jira-agent.md +2 -2
- package/plugins/src/base/agents/linear-agent.md +2 -2
- package/plugins/src/base/rules/eager/config-resolution.md +27 -8
- package/plugins/src/base/rules/eager/pre-flight-autofill.md +21 -7
- package/plugins/src/base/rules/reference/config-resolution.md +55 -16
- package/plugins/src/base/rules/reference/pre-flight-autofill.md +23 -8
- 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
- package/plugins/src/base/skills/lisa-github-validate-issue/SKILL.md +1 -1
- package/plugins/src/base/skills/lisa-github-write-issue/SKILL.md +9 -3
- package/plugins/src/base/skills/lisa-implement/SKILL.md +6 -2
- package/plugins/src/base/skills/lisa-jira-validate-ticket/SKILL.md +1 -1
- package/plugins/src/base/skills/lisa-jira-write-ticket/SKILL.md +9 -6
- package/plugins/src/base/skills/lisa-linear-validate-issue/SKILL.md +1 -1
- package/plugins/src/base/skills/lisa-linear-write-issue/SKILL.md +9 -3
|
@@ -21,13 +21,27 @@ information was already on the ticket; only the structure was missing).
|
|
|
21
21
|
Gherkin Acceptance Criteria (one scenario per fix), expected-vs-actual +
|
|
22
22
|
environment, Repository, Relationship Search (actually run the git+tracker
|
|
23
23
|
search — don't fabricate "none found"), Validation Journey **draft** (via the
|
|
24
|
-
vendor `*-add-journey` skill), Target Backend Environment.
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
24
|
+
vendor `*-add-journey` skill), Target Backend Environment. Preserve a bare
|
|
25
|
+
configured key or `Confirmed: <env>` as human-confirmed. Automation writes
|
|
26
|
+
`Inferred: <env> — evidence: <title|body|reproduction|hostname>` or
|
|
27
|
+
`Assumption: <env> — remote default branch <branch>`. Without a unique
|
|
28
|
+
reverse-map use `Assumption: remote default branch <branch>`; human confirmation
|
|
29
|
+
replaces the annotation with a bare key or `Confirmed: <env>`. For legacy bare
|
|
30
|
+
values, use managed draft markers and current ticket content only; provider
|
|
31
|
+
edit history is not required. A marker proves automation and requires
|
|
32
|
+
re-annotation; otherwise unknown provenance plus conflicting evidence stops.
|
|
33
|
+
Human-confirmed wins, then validated `Inferred:`
|
|
34
|
+
evidence. Otherwise use one unambiguous exact `deploy.branches` key from the
|
|
35
|
+
title, body, and reproduction steps or a URL hostname, excluding the complete
|
|
36
|
+
`Target Backend Environment` section and other machine-authored metadata/draft
|
|
37
|
+
blocks so annotations cannot become evidence. Evidence supersedes only
|
|
38
|
+
`Assumption:`. Normalize only built-in
|
|
39
|
+
`prod` ↔ `production` when exactly one is configured; no other aliases exist.
|
|
40
|
+
Never infer from arbitrary branch text, URL paths/query strings, or substrings.
|
|
41
|
+
Conflicting signals **stop** autofill. With no environment signal, use the
|
|
42
|
+
remote default and record the applicable `Assumption:` form; a non-unique
|
|
43
|
+
reverse-map alone never blocks. Require any selected mapping and remote branch.
|
|
44
|
+
Never overwrite human prose.
|
|
31
45
|
- **Tier B — irreducibly human:** real credentials/access that exist nowhere on
|
|
32
46
|
the item or in repo test-user docs; a genuine product/scoping decision with no
|
|
33
47
|
defensible default. Still propose a recommended default where one exists; ask
|
|
@@ -217,23 +217,47 @@ Declares **where this repo's LLM Wiki lives** so the query/ingest skills can res
|
|
|
217
217
|
|
|
218
218
|
### Env → base branch
|
|
219
219
|
|
|
220
|
-
Implementation flows resolve their PR base from the work item's
|
|
221
|
-
|
|
220
|
+
Implementation flows resolve their PR base from the work item's environment
|
|
221
|
+
evidence in the forward direction of `deploy.branches`.
|
|
222
222
|
For example, `{ "staging": "staging", "production": "main" }` means a staging
|
|
223
223
|
work item starts from `origin/staging` and opens its PR against `staging`. This
|
|
224
224
|
is the reverse/inverse of the env-keyed `done` inference that derives an
|
|
225
225
|
environment from a merged PR's base branch.
|
|
226
226
|
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
227
|
+
The field grammar records provenance durably: human-confirmed values are a bare
|
|
228
|
+
configured key or `Confirmed: <env>`; automated evidence is
|
|
229
|
+
`Inferred: <env> — evidence: <title|body|reproduction|hostname>`; an automated
|
|
230
|
+
fallback is `Assumption: <env> — remote default branch <branch>`. Human
|
|
231
|
+
fallback without a unique reverse-map is
|
|
232
|
+
`Assumption: remote default branch <branch>`. Human
|
|
233
|
+
confirmation replaces an automated annotation with a bare key or
|
|
234
|
+
`Confirmed: <env>`.
|
|
235
|
+
|
|
236
|
+
For legacy bare values created before this grammar, use managed draft markers
|
|
237
|
+
and current ticket content only; provider edit history is neither required nor
|
|
238
|
+
assumed. A managed marker proves automation and requires rewriting to
|
|
239
|
+
`Inferred:` or `Assumption:`. Without one, provenance remains unknown, so the
|
|
240
|
+
bare value is usable only if no conflicting evidence exists; a conflict stops
|
|
241
|
+
for confirmation.
|
|
242
|
+
|
|
243
|
+
Resolve it in this order: human-confirmed wins; validated `Inferred:` evidence
|
|
244
|
+
is next; otherwise accept one unambiguous exact `deploy.branches` key from the
|
|
245
|
+
human-authored title, body, and reproduction steps or a URL hostname. Exclude
|
|
246
|
+
the entire `Target Backend Environment` section and all other machine-authored
|
|
247
|
+
metadata/draft blocks from the evidence scan, so annotations never validate or
|
|
248
|
+
conflict with themselves. Evidence supersedes only
|
|
249
|
+
an `Assumption:`. Treat the reported bug environment as an example of this
|
|
250
|
+
all-work-type evidence rule, not a special case. Normalize only built-in
|
|
251
|
+
`prod` ↔ `production` when exactly one is configured; no other aliases exist.
|
|
252
|
+
Never infer from arbitrary branch text, URL paths/query strings, or substrings.
|
|
253
|
+
Multiple conflicting signals stop. With no signals, use the remote default
|
|
254
|
+
branch and record an assumption: include the environment only for a unique
|
|
255
|
+
reverse-map; otherwise use the branch-only form without inventing an environment
|
|
256
|
+
or blocking solely on the reverse-map.
|
|
257
|
+
|
|
258
|
+
Every selected environment must have a unique `deploy.branches` mapping and its
|
|
259
|
+
mapped branch must exist on the remote. If either validation fails, stop and
|
|
260
|
+
report it. Do not silently default to the integration branch.
|
|
237
261
|
|
|
238
262
|
For non-integration environment bugs, definition of done is two-step:
|
|
239
263
|
|
|
@@ -504,10 +528,25 @@ If a project's terminal state is the same regardless of env, set `done` to a str
|
|
|
504
528
|
|
|
505
529
|
`deploy.branches` is also read in the **forward** direction by the build flow (`lisa-implement`): the environment a work item targets determines the branch the work is built on and the branch the PR opens against.
|
|
506
530
|
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
531
|
+
The durable field forms are: bare configured key or `Confirmed: <env>` for a
|
|
532
|
+
human-confirmed value; `Inferred: <env> — evidence: <title|body|reproduction|hostname>`
|
|
533
|
+
for automation-backed evidence; and
|
|
534
|
+
`Assumption: <env> — remote default branch <branch>` for a generic fallback.
|
|
535
|
+
When the remote default has no unique environment reverse-map, the valid form is
|
|
536
|
+
`Assumption: remote default branch <branch>`.
|
|
537
|
+
Human confirmation replaces the automated annotation with a bare key or
|
|
538
|
+
`Confirmed: <env>`.
|
|
539
|
+
|
|
540
|
+
For a legacy bare value, use managed draft markers and current ticket content
|
|
541
|
+
only; do not require provider edit history. A marker proves automation and
|
|
542
|
+
requires re-annotation; otherwise unknown provenance plus conflicting evidence
|
|
543
|
+
stops for confirmation.
|
|
544
|
+
|
|
545
|
+
1. **Resolve provenance first.** Human-confirmed wins, then validated `Inferred:` evidence. Otherwise search the human-authored title, body, and reproduction steps or URL hostname for one unambiguous exact `deploy.branches` key. Exclude the complete `Target Backend Environment` section and other machine-authored metadata/draft blocks from the scan so annotations cannot become evidence. Evidence supersedes only an `Assumption:`.
|
|
546
|
+
2. **Normalize narrowly.** Normalize built-in `prod` ↔ `production` only when exactly one of those keys is configured. No other aliases exist. Never infer from arbitrary branch text, URL paths/query strings, or substrings.
|
|
547
|
+
3. **Handle absence and conflict explicitly.** Multiple conflicting signals stop. With no signals, use the remote default branch (`gh repo view --json defaultBranchRef`, or `origin/HEAD`) and record the env-bearing assumption only for a unique reverse-map; otherwise use the branch-only assumption without inventing an environment or blocking.
|
|
548
|
+
4. **Validate the destination.** The selected exact configured key must map uniquely and the mapped remote branch must exist; otherwise stop without guessing or falling back.
|
|
549
|
+
5. **Before any code is written**, `lisa-implement` fetches and **rebases the working branch onto `origin/<base>`, resolving conflicts**, then opens the PR against that same base (`target_branch=<base>`).
|
|
511
550
|
|
|
512
551
|
This is the exact inverse of the env-keyed `done` "Branch inference" above: `done` derives the env *from* the PR base branch (reverse); the build flow derives the base branch *from* the env (forward). Both use the one `deploy.branches` map, so the branch a PR targets and the `done` status it earns always agree.
|
|
513
552
|
|
|
@@ -49,14 +49,29 @@ spec.
|
|
|
49
49
|
- **Validation Journey (draft)** — run the vendor `*-add-journey` skill to draft
|
|
50
50
|
the click-path, markers, and viewports from the reproduction steps. This is a
|
|
51
51
|
draft for human approval, not the final ratified contract.
|
|
52
|
-
- **Target Backend Environment** —
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
`
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
52
|
+
- **Target Backend Environment** — preserve a bare configured key or
|
|
53
|
+
`Confirmed: <env>` as human-confirmed. Automated evidence must write
|
|
54
|
+
`Inferred: <env> — evidence: <title|body|reproduction|hostname>`; a generic
|
|
55
|
+
fallback must write `Assumption: <env> — remote default branch <branch>`.
|
|
56
|
+
If the default branch has no unique environment reverse-map, instead write
|
|
57
|
+
`Assumption: remote default branch <branch>` without inventing an environment.
|
|
58
|
+
Human confirmation replaces an automated annotation with a bare key or
|
|
59
|
+
`Confirmed: <env>`. For legacy bare values, use managed draft markers and
|
|
60
|
+
current ticket content only; provider edit history is not required. A marker
|
|
61
|
+
proves automation and requires re-annotation; otherwise unknown provenance
|
|
62
|
+
plus conflicting evidence stops for confirmation. A human-confirmed value wins, followed by validated
|
|
63
|
+
`Inferred:` evidence. Otherwise inspect the title, body, and reproduction
|
|
64
|
+
steps or a URL hostname for one unambiguous exact `deploy.branches` key,
|
|
65
|
+
excluding the complete `Target Backend Environment` section and all other
|
|
66
|
+
machine-authored metadata/draft blocks so annotations cannot become evidence.
|
|
67
|
+
Clear evidence supersedes only an `Assumption:` value. The sole normalization
|
|
68
|
+
is `prod` ↔ `production` when exactly one key is configured; no other aliases
|
|
69
|
+
exist. Never infer from arbitrary branch text, URL paths or query strings, or
|
|
70
|
+
substrings. Multiple conflicting signals **stop** autofill. With no
|
|
71
|
+
environment signal, use the remote default and record the applicable
|
|
72
|
+
`Assumption:` form; a missing/ambiguous reverse-map alone never blocks.
|
|
73
|
+
Require any selected environment mapping and remote branch. Never overwrite
|
|
74
|
+
human prose.
|
|
60
75
|
|
|
61
76
|
**Tier B — irreducibly human (cannot invent — but still propose a default):**
|
|
62
77
|
|
|
@@ -15,6 +15,10 @@ import {
|
|
|
15
15
|
createAutomationGroupBins,
|
|
16
16
|
renderAutomationGroups,
|
|
17
17
|
} from "./automation-status-expected-fleet.mjs";
|
|
18
|
+
import {
|
|
19
|
+
resolveAutomationRunDisplay,
|
|
20
|
+
resolveRecoveryEscalation,
|
|
21
|
+
} from "./automation-status-run-history.mjs";
|
|
18
22
|
|
|
19
23
|
const CLAUDE_RUNTIME_LABEL = "Claude /schedule";
|
|
20
24
|
const CLAUDE_ACTIVE_STATUSES = new Set([
|
|
@@ -51,9 +55,10 @@ const NEGATED_FAILURE_PATTERN =
|
|
|
51
55
|
* @param {{
|
|
52
56
|
* readonly expectedFleet: ExpectedFleet
|
|
53
57
|
* readonly scheduleListing?: string | readonly unknown[] | Record<string, unknown> | null
|
|
58
|
+
* readonly projectRoot?: string
|
|
54
59
|
* readonly now?: string | Date
|
|
55
60
|
* }} input
|
|
56
|
-
* @returns {{
|
|
61
|
+
* @returns {Promise<{
|
|
57
62
|
* readonly runtime: string
|
|
58
63
|
* readonly generatedAt: string
|
|
59
64
|
* readonly groups: readonly {
|
|
@@ -66,20 +71,27 @@ const NEGATED_FAILURE_PATTERN =
|
|
|
66
71
|
* readonly expectedCadence?: string
|
|
67
72
|
* readonly expectedCommand?: string
|
|
68
73
|
* readonly observed?: string
|
|
74
|
+
* readonly runbook?: string
|
|
75
|
+
* readonly lastOutcome?: { readonly ts: string, readonly outcome: string, readonly summary: string }
|
|
76
|
+
* readonly outcomeHistory?: readonly string[]
|
|
77
|
+
* readonly olderRecordCount?: number
|
|
69
78
|
* readonly remediation?: string
|
|
70
79
|
* }[]
|
|
71
80
|
* }[]
|
|
72
81
|
* readonly observedAutomations: readonly ObservedClaudeAutomation[]
|
|
73
|
-
* }}
|
|
82
|
+
* }>}
|
|
74
83
|
*/
|
|
75
|
-
export function inspectClaudeAutomationFleet(input) {
|
|
84
|
+
export async function inspectClaudeAutomationFleet(input) {
|
|
76
85
|
const expectedFleet = input.expectedFleet;
|
|
77
86
|
const now = normalizeDate(input.now);
|
|
87
|
+
const projectRoot = input.projectRoot ?? process.cwd();
|
|
78
88
|
const observedAutomations = listClaudeAutomations({
|
|
79
89
|
scheduleListing: input.scheduleListing,
|
|
80
90
|
automationPrefix: expectedFleet.automationPrefix,
|
|
81
91
|
});
|
|
82
92
|
|
|
93
|
+
const runDisplays = await resolveFleetRunDisplays(projectRoot, expectedFleet);
|
|
94
|
+
|
|
83
95
|
const expectedGroups = createAutomationGroupBins();
|
|
84
96
|
|
|
85
97
|
const comparisons = compareAutomationFleet({
|
|
@@ -96,17 +108,23 @@ export function inspectClaudeAutomationFleet(input) {
|
|
|
96
108
|
expected,
|
|
97
109
|
comparison,
|
|
98
110
|
now,
|
|
111
|
+
runDisplay: runDisplays.get(expected.id),
|
|
99
112
|
})
|
|
100
113
|
);
|
|
101
114
|
}
|
|
102
115
|
|
|
103
116
|
for (const unsupported of expectedFleet.unsupported) {
|
|
117
|
+
const runDisplay = runDisplays.get(unsupported.id);
|
|
104
118
|
assignToAutomationGroup(expectedGroups, unsupported.group, {
|
|
105
119
|
id: unsupported.automationId,
|
|
106
120
|
status: "UNSUPPORTED",
|
|
107
121
|
summary: unsupported.reason,
|
|
108
122
|
expectedCadence: unsupported.expectedCadence,
|
|
109
123
|
observed: "No automation is expected for this repo/runtime combination.",
|
|
124
|
+
runbook: runDisplay?.runbook,
|
|
125
|
+
lastOutcome: runDisplay?.lastOutcome,
|
|
126
|
+
outcomeHistory: runDisplay?.outcomeHistory,
|
|
127
|
+
olderRecordCount: runDisplay?.olderRecordCount,
|
|
110
128
|
});
|
|
111
129
|
}
|
|
112
130
|
|
|
@@ -195,15 +213,43 @@ function extractClaudeScheduleCadence(command) {
|
|
|
195
213
|
);
|
|
196
214
|
}
|
|
197
215
|
|
|
216
|
+
/**
|
|
217
|
+
* Read the read-only run-history display for every expected and unsupported
|
|
218
|
+
* loop up front, keyed by the loop's short id, so the per-entry item builder
|
|
219
|
+
* stays synchronous.
|
|
220
|
+
*
|
|
221
|
+
* @param {string} projectRoot
|
|
222
|
+
* @param {ExpectedFleet} expectedFleet
|
|
223
|
+
* @returns {Promise<Map<string, import("./automation-status-run-history.mjs").AutomationRunDisplay>>}
|
|
224
|
+
*/
|
|
225
|
+
async function resolveFleetRunDisplays(projectRoot, expectedFleet) {
|
|
226
|
+
const entries = [...expectedFleet.expected, ...expectedFleet.unsupported];
|
|
227
|
+
const displays = await Promise.all(
|
|
228
|
+
entries.map(entry =>
|
|
229
|
+
resolveAutomationRunDisplay({
|
|
230
|
+
projectRoot,
|
|
231
|
+
loopId: entry.id,
|
|
232
|
+
runbookPath: entry.runbookPath,
|
|
233
|
+
})
|
|
234
|
+
)
|
|
235
|
+
);
|
|
236
|
+
return new Map(entries.map((entry, index) => [entry.id, displays[index]]));
|
|
237
|
+
}
|
|
238
|
+
|
|
198
239
|
function createObservedStatusItem(input) {
|
|
199
240
|
const expected = input.expected;
|
|
200
241
|
const comparison = input.comparison;
|
|
201
242
|
const observed = comparison.observedAutomation;
|
|
243
|
+
const runDisplay = input.runDisplay;
|
|
202
244
|
const runSignal = classifyAutomationRunSignal({
|
|
203
245
|
expected,
|
|
204
246
|
observedAutomation: observed,
|
|
205
247
|
now: input.now,
|
|
206
248
|
});
|
|
249
|
+
// Three or more consecutive recorded recovery-required runs flip the loop to
|
|
250
|
+
// FAILING even when the /schedule entry looks fine — the fleet-health signal
|
|
251
|
+
// the scheduler surface cannot see. It wins over the scheduler run-signal.
|
|
252
|
+
const escalation = resolveRecoveryEscalation(runDisplay);
|
|
207
253
|
|
|
208
254
|
const observedDetails = [comparison.observed];
|
|
209
255
|
if (observed?.status) {
|
|
@@ -223,20 +269,30 @@ function createObservedStatusItem(input) {
|
|
|
223
269
|
}
|
|
224
270
|
|
|
225
271
|
const status =
|
|
272
|
+
escalation?.status ??
|
|
226
273
|
runSignal?.status ??
|
|
227
274
|
/** @type {"HEALTHY" | "MISSING" | "DRIFTED"} */ (comparison.status);
|
|
228
275
|
|
|
229
276
|
return {
|
|
230
277
|
id: expected.automationId,
|
|
231
278
|
status,
|
|
232
|
-
summary:
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
279
|
+
summary: escalation
|
|
280
|
+
? escalation.summary
|
|
281
|
+
: composeAutomationSummary({
|
|
282
|
+
comparison,
|
|
283
|
+
runSignal,
|
|
284
|
+
}),
|
|
236
285
|
expectedCadence: expected.expectedCadence,
|
|
237
286
|
expectedCommand: expected.expectedCommand,
|
|
238
287
|
observed: observedDetails.join(" "),
|
|
239
|
-
|
|
288
|
+
runbook: runDisplay?.runbook,
|
|
289
|
+
lastOutcome: runDisplay?.lastOutcome,
|
|
290
|
+
outcomeHistory: runDisplay?.outcomeHistory,
|
|
291
|
+
olderRecordCount: runDisplay?.olderRecordCount,
|
|
292
|
+
remediation:
|
|
293
|
+
escalation?.remediation ??
|
|
294
|
+
runSignal?.remediation ??
|
|
295
|
+
comparison.remediation,
|
|
240
296
|
};
|
|
241
297
|
}
|
|
242
298
|
|
|
@@ -22,6 +22,10 @@ import {
|
|
|
22
22
|
createAutomationGroupBins,
|
|
23
23
|
renderAutomationGroups,
|
|
24
24
|
} from "./automation-status-expected-fleet.mjs";
|
|
25
|
+
import {
|
|
26
|
+
resolveAutomationRunDisplay,
|
|
27
|
+
resolveRecoveryEscalation,
|
|
28
|
+
} from "./automation-status-run-history.mjs";
|
|
25
29
|
|
|
26
30
|
const CODEx_RUNTIME_LABEL = "Codex automations";
|
|
27
31
|
const RUN_TIMESTAMP_PATTERN = /20\d{2}-\d\d-\d\dT\d\d:\d\d:\d\d(?:\.\d+)?Z/;
|
|
@@ -132,6 +136,7 @@ async function execGitWithRetry(args, options, attempts = 4) {
|
|
|
132
136
|
* @param {{
|
|
133
137
|
* readonly expectedFleet: ExpectedFleet
|
|
134
138
|
* readonly automationsDir?: string
|
|
139
|
+
* readonly projectRoot?: string
|
|
135
140
|
* readonly now?: string | Date
|
|
136
141
|
* }} input
|
|
137
142
|
* @returns {Promise<{
|
|
@@ -147,6 +152,10 @@ async function execGitWithRetry(args, options, attempts = 4) {
|
|
|
147
152
|
* readonly expectedCadence?: string
|
|
148
153
|
* readonly expectedCommand?: string
|
|
149
154
|
* readonly observed?: string
|
|
155
|
+
* readonly runbook?: string
|
|
156
|
+
* readonly lastOutcome?: { readonly ts: string, readonly outcome: string, readonly summary: string }
|
|
157
|
+
* readonly outcomeHistory?: readonly string[]
|
|
158
|
+
* readonly olderRecordCount?: number
|
|
150
159
|
* readonly remediation?: string
|
|
151
160
|
* }[]
|
|
152
161
|
* }[]
|
|
@@ -156,11 +165,14 @@ async function execGitWithRetry(args, options, attempts = 4) {
|
|
|
156
165
|
export async function inspectCodexAutomationFleet(input) {
|
|
157
166
|
const expectedFleet = input.expectedFleet;
|
|
158
167
|
const now = normalizeDate(input.now);
|
|
168
|
+
const projectRoot = input.projectRoot ?? process.cwd();
|
|
159
169
|
const observedAutomations = await listCodexAutomations({
|
|
160
170
|
automationsDir: input.automationsDir,
|
|
161
171
|
automationPrefix: expectedFleet.automationPrefix,
|
|
162
172
|
});
|
|
163
173
|
|
|
174
|
+
const runDisplays = await resolveFleetRunDisplays(projectRoot, expectedFleet);
|
|
175
|
+
|
|
164
176
|
const expectedGroups = createAutomationGroupBins();
|
|
165
177
|
|
|
166
178
|
const comparisons = compareAutomationFleet({
|
|
@@ -177,17 +189,23 @@ export async function inspectCodexAutomationFleet(input) {
|
|
|
177
189
|
expected,
|
|
178
190
|
comparison,
|
|
179
191
|
now,
|
|
192
|
+
runDisplay: runDisplays.get(expected.id),
|
|
180
193
|
})
|
|
181
194
|
);
|
|
182
195
|
}
|
|
183
196
|
|
|
184
197
|
for (const unsupported of expectedFleet.unsupported) {
|
|
198
|
+
const runDisplay = runDisplays.get(unsupported.id);
|
|
185
199
|
assignToAutomationGroup(expectedGroups, unsupported.group, {
|
|
186
200
|
id: unsupported.automationId,
|
|
187
201
|
status: "UNSUPPORTED",
|
|
188
202
|
summary: unsupported.reason,
|
|
189
203
|
expectedCadence: unsupported.expectedCadence,
|
|
190
204
|
observed: "No automation is expected for this repo/runtime combination.",
|
|
205
|
+
runbook: runDisplay?.runbook,
|
|
206
|
+
lastOutcome: runDisplay?.lastOutcome,
|
|
207
|
+
outcomeHistory: runDisplay?.outcomeHistory,
|
|
208
|
+
olderRecordCount: runDisplay?.olderRecordCount,
|
|
191
209
|
});
|
|
192
210
|
}
|
|
193
211
|
|
|
@@ -374,15 +392,43 @@ async function readCodexAutomation(automationDir) {
|
|
|
374
392
|
};
|
|
375
393
|
}
|
|
376
394
|
|
|
395
|
+
/**
|
|
396
|
+
* Read the read-only run-history display for every expected and unsupported
|
|
397
|
+
* loop up front, keyed by the loop's short id, so the per-entry item builder
|
|
398
|
+
* stays synchronous.
|
|
399
|
+
*
|
|
400
|
+
* @param {string} projectRoot
|
|
401
|
+
* @param {ExpectedFleet} expectedFleet
|
|
402
|
+
* @returns {Promise<Map<string, import("./automation-status-run-history.mjs").AutomationRunDisplay>>}
|
|
403
|
+
*/
|
|
404
|
+
async function resolveFleetRunDisplays(projectRoot, expectedFleet) {
|
|
405
|
+
const entries = [...expectedFleet.expected, ...expectedFleet.unsupported];
|
|
406
|
+
const displays = await Promise.all(
|
|
407
|
+
entries.map(entry =>
|
|
408
|
+
resolveAutomationRunDisplay({
|
|
409
|
+
projectRoot,
|
|
410
|
+
loopId: entry.id,
|
|
411
|
+
runbookPath: entry.runbookPath,
|
|
412
|
+
})
|
|
413
|
+
)
|
|
414
|
+
);
|
|
415
|
+
return new Map(entries.map((entry, index) => [entry.id, displays[index]]));
|
|
416
|
+
}
|
|
417
|
+
|
|
377
418
|
function createObservedStatusItem(input) {
|
|
378
419
|
const expected = input.expected;
|
|
379
420
|
const comparison = input.comparison;
|
|
380
421
|
const observed = comparison.observedAutomation;
|
|
422
|
+
const runDisplay = input.runDisplay;
|
|
381
423
|
const runSignal = classifyAutomationRunSignal({
|
|
382
424
|
expected,
|
|
383
425
|
observedAutomation: observed,
|
|
384
426
|
now: input.now,
|
|
385
427
|
});
|
|
428
|
+
// Three or more consecutive recorded recovery-required runs flip the loop to
|
|
429
|
+
// FAILING even when the scheduler entry looks fine — the fleet-health signal
|
|
430
|
+
// the raw backing store cannot see. It wins over the scheduler run-signal.
|
|
431
|
+
const escalation = resolveRecoveryEscalation(runDisplay);
|
|
386
432
|
|
|
387
433
|
const observedDetails = [comparison.observed];
|
|
388
434
|
if (observed?.status) {
|
|
@@ -401,20 +447,30 @@ function createObservedStatusItem(input) {
|
|
|
401
447
|
}
|
|
402
448
|
|
|
403
449
|
const status =
|
|
450
|
+
escalation?.status ??
|
|
404
451
|
runSignal?.status ??
|
|
405
452
|
/** @type {"HEALTHY" | "MISSING" | "DRIFTED"} */ (comparison.status);
|
|
406
453
|
|
|
407
454
|
return {
|
|
408
455
|
id: expected.automationId,
|
|
409
456
|
status,
|
|
410
|
-
summary:
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
457
|
+
summary: escalation
|
|
458
|
+
? escalation.summary
|
|
459
|
+
: composeAutomationSummary({
|
|
460
|
+
comparison,
|
|
461
|
+
runSignal,
|
|
462
|
+
}),
|
|
414
463
|
expectedCadence: expected.expectedCadence,
|
|
415
464
|
expectedCommand: expected.expectedCommand,
|
|
416
465
|
observed: observedDetails.join(" "),
|
|
417
|
-
|
|
466
|
+
runbook: runDisplay?.runbook,
|
|
467
|
+
lastOutcome: runDisplay?.lastOutcome,
|
|
468
|
+
outcomeHistory: runDisplay?.outcomeHistory,
|
|
469
|
+
olderRecordCount: runDisplay?.olderRecordCount,
|
|
470
|
+
remediation:
|
|
471
|
+
escalation?.remediation ??
|
|
472
|
+
runSignal?.remediation ??
|
|
473
|
+
comparison.remediation,
|
|
418
474
|
};
|
|
419
475
|
}
|
|
420
476
|
|
|
@@ -26,12 +26,22 @@ export const AUTOMATION_FLEET_VERDICTS = [
|
|
|
26
26
|
* @typedef {"HEALTHY" | "PARTIAL_SUPPORT" | "ATTENTION_NEEDED"} AutomationFleetVerdict
|
|
27
27
|
*
|
|
28
28
|
* @typedef {{
|
|
29
|
+
* readonly ts: string
|
|
30
|
+
* readonly outcome: string
|
|
31
|
+
* readonly summary: string
|
|
32
|
+
* }} AutomationLastOutcome
|
|
33
|
+
*
|
|
34
|
+
* @typedef {{
|
|
29
35
|
* readonly id: string
|
|
30
36
|
* readonly status: AutomationHealthStatus
|
|
31
37
|
* readonly summary: string
|
|
32
38
|
* readonly expectedCadence?: string
|
|
33
39
|
* readonly expectedCommand?: string
|
|
34
40
|
* readonly observed?: string
|
|
41
|
+
* readonly runbook?: string
|
|
42
|
+
* readonly lastOutcome?: AutomationLastOutcome
|
|
43
|
+
* readonly outcomeHistory?: readonly string[]
|
|
44
|
+
* readonly olderRecordCount?: number
|
|
35
45
|
* readonly remediation?: string
|
|
36
46
|
* }} AutomationStatusItem
|
|
37
47
|
*
|
|
@@ -130,6 +140,26 @@ export function renderAutomationStatusReport(input) {
|
|
|
130
140
|
if (item.observed) {
|
|
131
141
|
lines.push(` Observed: ${item.observed}`);
|
|
132
142
|
}
|
|
143
|
+
// Contract + run-history block: observable facts about where the runbook
|
|
144
|
+
// lives and how recent runs ended, kept between Observed and Remediation
|
|
145
|
+
// so operators read the state before the fix. Every line degrades
|
|
146
|
+
// explicitly — an absent runbook or empty history is stated, never blank.
|
|
147
|
+
if (item.runbook !== undefined) {
|
|
148
|
+
lines.push(` Runbook: ${item.runbook}`);
|
|
149
|
+
lines.push(
|
|
150
|
+
item.lastOutcome
|
|
151
|
+
? ` Last run: ${item.lastOutcome.outcome} — ${item.lastOutcome.summary} (${item.lastOutcome.ts})`
|
|
152
|
+
: " Last run: no recorded runs yet"
|
|
153
|
+
);
|
|
154
|
+
if (item.outcomeHistory && item.outcomeHistory.length > 0) {
|
|
155
|
+
const historyLine = ` History: ${item.outcomeHistory.join(", ")} (newest first)`;
|
|
156
|
+
lines.push(
|
|
157
|
+
item.olderRecordCount && item.olderRecordCount > 0
|
|
158
|
+
? `${historyLine}; … and ${item.olderRecordCount} older records`
|
|
159
|
+
: historyLine
|
|
160
|
+
);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
133
163
|
if (item.remediation) {
|
|
134
164
|
lines.push(` Remediation: ${item.remediation}`);
|
|
135
165
|
}
|