@codyswann/lisa 2.328.3 → 2.328.5

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 (131) hide show
  1. package/dist/core/upstream-evidence-manifest.d.ts.map +1 -1
  2. package/dist/core/upstream-evidence-manifest.js +20 -12
  3. package/dist/core/upstream-evidence-manifest.js.map +1 -1
  4. package/dist/sync/lifecycle-defaults.d.ts +12 -3
  5. package/dist/sync/lifecycle-defaults.d.ts.map +1 -1
  6. package/dist/sync/lifecycle-defaults.js +13 -4
  7. package/dist/sync/lifecycle-defaults.js.map +1 -1
  8. package/package.json +1 -1
  9. package/plugins/lisa/.claude-plugin/plugin.json +1 -1
  10. package/plugins/lisa/.codex-plugin/plugin.json +1 -1
  11. package/plugins/lisa/.codex-plugin/skills/lisa-detect-tooling/SKILL.md +32 -2
  12. package/plugins/lisa/.codex-plugin/skills/lisa-detect-tooling/scripts/commands.mjs +479 -0
  13. package/plugins/lisa/.codex-plugin/skills/lisa-detect-tooling/scripts/detect-tooling.mjs +170 -4
  14. package/plugins/lisa/.codex-plugin/skills/lisa-linear-build-intake/SKILL.md +8 -8
  15. package/plugins/lisa/.codex-plugin/skills/lisa-linear-claim/SKILL.md +5 -4
  16. package/plugins/lisa/.codex-plugin/skills/lisa-linear-sync/SKILL.md +19 -19
  17. package/plugins/lisa/.codex-plugin/skills/lisa-linear-validate-issue/SKILL.md +5 -5
  18. package/plugins/lisa/.codex-plugin/skills/lisa-linear-write-issue/SKILL.md +2 -2
  19. package/plugins/lisa/.codex-plugin/skills/lisa-setup-linear/SKILL.md +2 -2
  20. package/plugins/lisa/agents/linear-agent.md +2 -2
  21. package/plugins/lisa/agents/linear-build-intake.md +13 -13
  22. package/plugins/lisa/rules/reference/config-resolution.md +5 -3
  23. package/plugins/lisa/scripts/queue-contract-resolution.mjs +20 -8
  24. package/plugins/lisa/skills/lisa-detect-tooling/SKILL.md +33 -3
  25. package/plugins/lisa/skills/lisa-detect-tooling/scripts/commands.mjs +479 -0
  26. package/plugins/lisa/skills/lisa-detect-tooling/scripts/detect-tooling.mjs +170 -4
  27. package/plugins/lisa/skills/lisa-linear-build-intake/SKILL.md +8 -8
  28. package/plugins/lisa/skills/lisa-linear-claim/SKILL.md +6 -5
  29. package/plugins/lisa/skills/lisa-linear-sync/SKILL.md +19 -19
  30. package/plugins/lisa/skills/lisa-linear-validate-issue/SKILL.md +5 -5
  31. package/plugins/lisa/skills/lisa-linear-write-issue/SKILL.md +2 -2
  32. package/plugins/lisa/skills/lisa-setup-linear/SKILL.md +2 -2
  33. package/plugins/lisa-agy/agents/linear-agent.md +2 -2
  34. package/plugins/lisa-agy/agents/linear-build-intake.md +13 -13
  35. package/plugins/lisa-agy/plugin.json +1 -1
  36. package/plugins/lisa-agy/scripts/queue-contract-resolution.mjs +20 -8
  37. package/plugins/lisa-agy/skills/lisa-detect-tooling/SKILL.md +33 -3
  38. package/plugins/lisa-agy/skills/lisa-detect-tooling/scripts/commands.mjs +479 -0
  39. package/plugins/lisa-agy/skills/lisa-detect-tooling/scripts/detect-tooling.mjs +170 -4
  40. package/plugins/lisa-agy/skills/lisa-linear-build-intake/SKILL.md +8 -8
  41. package/plugins/lisa-agy/skills/lisa-linear-claim/SKILL.md +6 -5
  42. package/plugins/lisa-agy/skills/lisa-linear-sync/SKILL.md +19 -19
  43. package/plugins/lisa-agy/skills/lisa-linear-validate-issue/SKILL.md +5 -5
  44. package/plugins/lisa-agy/skills/lisa-linear-write-issue/SKILL.md +2 -2
  45. package/plugins/lisa-agy/skills/lisa-setup-linear/SKILL.md +2 -2
  46. package/plugins/lisa-cdk/.claude-plugin/plugin.json +1 -1
  47. package/plugins/lisa-cdk/.codex-plugin/plugin.json +1 -1
  48. package/plugins/lisa-cdk-agy/plugin.json +1 -1
  49. package/plugins/lisa-cdk-copilot/.claude-plugin/plugin.json +1 -1
  50. package/plugins/lisa-cdk-cursor/.claude-plugin/plugin.json +1 -1
  51. package/plugins/lisa-copilot/.claude-plugin/plugin.json +1 -1
  52. package/plugins/lisa-copilot/agents/linear-agent.agent.md +2 -2
  53. package/plugins/lisa-copilot/agents/linear-build-intake.agent.md +13 -13
  54. package/plugins/lisa-copilot/rules/reference/config-resolution.md +5 -3
  55. package/plugins/lisa-copilot/scripts/queue-contract-resolution.mjs +20 -8
  56. package/plugins/lisa-copilot/skills/lisa-detect-tooling/SKILL.md +33 -3
  57. package/plugins/lisa-copilot/skills/lisa-detect-tooling/scripts/commands.mjs +479 -0
  58. package/plugins/lisa-copilot/skills/lisa-detect-tooling/scripts/detect-tooling.mjs +170 -4
  59. package/plugins/lisa-copilot/skills/lisa-linear-build-intake/SKILL.md +8 -8
  60. package/plugins/lisa-copilot/skills/lisa-linear-claim/SKILL.md +6 -5
  61. package/plugins/lisa-copilot/skills/lisa-linear-sync/SKILL.md +19 -19
  62. package/plugins/lisa-copilot/skills/lisa-linear-validate-issue/SKILL.md +5 -5
  63. package/plugins/lisa-copilot/skills/lisa-linear-write-issue/SKILL.md +2 -2
  64. package/plugins/lisa-copilot/skills/lisa-setup-linear/SKILL.md +2 -2
  65. package/plugins/lisa-cursor/.claude-plugin/plugin.json +1 -1
  66. package/plugins/lisa-cursor/agents/linear-agent.md +2 -2
  67. package/plugins/lisa-cursor/agents/linear-build-intake.md +13 -13
  68. package/plugins/lisa-cursor/rules/config-resolution-reference.mdc +5 -3
  69. package/plugins/lisa-cursor/scripts/queue-contract-resolution.mjs +20 -8
  70. package/plugins/lisa-cursor/skills/lisa-detect-tooling/SKILL.md +33 -3
  71. package/plugins/lisa-cursor/skills/lisa-detect-tooling/scripts/commands.mjs +479 -0
  72. package/plugins/lisa-cursor/skills/lisa-detect-tooling/scripts/detect-tooling.mjs +170 -4
  73. package/plugins/lisa-cursor/skills/lisa-linear-build-intake/SKILL.md +8 -8
  74. package/plugins/lisa-cursor/skills/lisa-linear-claim/SKILL.md +6 -5
  75. package/plugins/lisa-cursor/skills/lisa-linear-sync/SKILL.md +19 -19
  76. package/plugins/lisa-cursor/skills/lisa-linear-validate-issue/SKILL.md +5 -5
  77. package/plugins/lisa-cursor/skills/lisa-linear-write-issue/SKILL.md +2 -2
  78. package/plugins/lisa-cursor/skills/lisa-setup-linear/SKILL.md +2 -2
  79. package/plugins/lisa-expo/.claude-plugin/plugin.json +1 -1
  80. package/plugins/lisa-expo/.codex-plugin/plugin.json +1 -1
  81. package/plugins/lisa-expo-agy/plugin.json +1 -1
  82. package/plugins/lisa-expo-copilot/.claude-plugin/plugin.json +1 -1
  83. package/plugins/lisa-expo-cursor/.claude-plugin/plugin.json +1 -1
  84. package/plugins/lisa-harper-fabric/.claude-plugin/plugin.json +1 -1
  85. package/plugins/lisa-harper-fabric/.codex-plugin/plugin.json +1 -1
  86. package/plugins/lisa-harper-fabric-agy/plugin.json +1 -1
  87. package/plugins/lisa-harper-fabric-copilot/.claude-plugin/plugin.json +1 -1
  88. package/plugins/lisa-harper-fabric-cursor/.claude-plugin/plugin.json +1 -1
  89. package/plugins/lisa-nestjs/.claude-plugin/plugin.json +1 -1
  90. package/plugins/lisa-nestjs/.codex-plugin/plugin.json +1 -1
  91. package/plugins/lisa-nestjs-agy/plugin.json +1 -1
  92. package/plugins/lisa-nestjs-copilot/.claude-plugin/plugin.json +1 -1
  93. package/plugins/lisa-nestjs-cursor/.claude-plugin/plugin.json +1 -1
  94. package/plugins/lisa-openclaw/.claude-plugin/plugin.json +1 -1
  95. package/plugins/lisa-openclaw/.codex-plugin/plugin.json +1 -1
  96. package/plugins/lisa-openclaw-agy/plugin.json +1 -1
  97. package/plugins/lisa-openclaw-copilot/.claude-plugin/plugin.json +1 -1
  98. package/plugins/lisa-openclaw-cursor/.claude-plugin/plugin.json +1 -1
  99. package/plugins/lisa-phaser/.claude-plugin/plugin.json +1 -1
  100. package/plugins/lisa-phaser/.codex-plugin/plugin.json +1 -1
  101. package/plugins/lisa-phaser-agy/plugin.json +1 -1
  102. package/plugins/lisa-phaser-copilot/.claude-plugin/plugin.json +1 -1
  103. package/plugins/lisa-phaser-cursor/.claude-plugin/plugin.json +1 -1
  104. package/plugins/lisa-rails/.claude-plugin/plugin.json +1 -1
  105. package/plugins/lisa-rails/.codex-plugin/plugin.json +1 -1
  106. package/plugins/lisa-rails-agy/plugin.json +1 -1
  107. package/plugins/lisa-rails-copilot/.claude-plugin/plugin.json +1 -1
  108. package/plugins/lisa-rails-cursor/.claude-plugin/plugin.json +1 -1
  109. package/plugins/lisa-typescript/.claude-plugin/plugin.json +1 -1
  110. package/plugins/lisa-typescript/.codex-plugin/plugin.json +1 -1
  111. package/plugins/lisa-typescript-agy/plugin.json +1 -1
  112. package/plugins/lisa-typescript-copilot/.claude-plugin/plugin.json +1 -1
  113. package/plugins/lisa-typescript-cursor/.claude-plugin/plugin.json +1 -1
  114. package/plugins/lisa-wiki/.claude-plugin/plugin.json +1 -1
  115. package/plugins/lisa-wiki/.codex-plugin/plugin.json +1 -1
  116. package/plugins/lisa-wiki-agy/plugin.json +1 -1
  117. package/plugins/lisa-wiki-copilot/.claude-plugin/plugin.json +1 -1
  118. package/plugins/lisa-wiki-cursor/.claude-plugin/plugin.json +1 -1
  119. package/plugins/src/base/agents/linear-agent.md +2 -2
  120. package/plugins/src/base/agents/linear-build-intake.md +13 -13
  121. package/plugins/src/base/rules/reference/config-resolution.md +5 -3
  122. package/plugins/src/base/scripts/queue-contract-resolution.mjs +20 -8
  123. package/plugins/src/base/skills/lisa-detect-tooling/SKILL.md +33 -3
  124. package/plugins/src/base/skills/lisa-detect-tooling/scripts/commands.mjs +479 -0
  125. package/plugins/src/base/skills/lisa-detect-tooling/scripts/detect-tooling.mjs +170 -4
  126. package/plugins/src/base/skills/lisa-linear-build-intake/SKILL.md +8 -8
  127. package/plugins/src/base/skills/lisa-linear-claim/SKILL.md +6 -5
  128. package/plugins/src/base/skills/lisa-linear-sync/SKILL.md +19 -19
  129. package/plugins/src/base/skills/lisa-linear-validate-issue/SKILL.md +5 -5
  130. package/plugins/src/base/skills/lisa-linear-write-issue/SKILL.md +2 -2
  131. package/plugins/src/base/skills/lisa-setup-linear/SKILL.md +2 -2
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: linear-build-intake
3
- description: Linear build-intake agent. Runs one build-intake cycle against a Linear team — claims Issues carrying the configured `ready` build label, dispatches each to the linear-agent build flow, relabels to the configured (env-aware) `done` label on success. Symmetric counterpart of jira-build-intake and github-build-intake. Designed to be invoked manually via /linear-build-intake or autonomously via a scheduled cron.
3
+ description: Linear build-intake agent. Runs one build-intake cycle against a Linear team — claims Issues in the configured `ready` workflow state, dispatches each to the linear-agent build flow, transitions to the configured (env-aware) `done` state on success. Symmetric counterpart of jira-build-intake and github-build-intake. Designed to be invoked manually via /linear-build-intake or autonomously via a scheduled cron.
4
4
  skills:
5
5
  - linear-build-intake
6
6
  - linear-read-issue
@@ -15,21 +15,21 @@ skills:
15
15
 
16
16
  # Linear Build Intake Agent
17
17
 
18
- You are a Linear build-intake agent. Your single job is to run one cycle against a Linear team — find Issues carrying the configured `ready` build label, dispatch each through the build flow, relabel successful builds to the configured (env-aware) `done` label — then report what happened.
18
+ You are a Linear build-intake agent. Your single job is to run one cycle against a Linear team — find Issues in the configured `ready` workflow STATE, dispatch each through the build flow, transition successful builds to the configured (env-aware) `done` state — then report what happened.
19
19
 
20
- Build-lifecycle role names (`ready`, `claimed`, `review`, `blocked`, `done`) are resolved from `.lisa.config.json` `linear.workflow.*` by the `linear-build-intake` skill, and name native **workflow states**, not labels. Defaults: `Todo`, `In Progress`, `In Review`, `Blocked`, env-keyed `{ dev: "On Dev", staging: "On Stg", production: "Done" }`.
20
+ Build-lifecycle role names (`ready`, `claimed`, `review`, `blocked`, `done`) are resolved from `.lisa.config.json` `linear.workflow.*` by the `linear-build-intake` skill, and name native **workflow states**, not labels. Defaults: `Ready`, `In Progress`, `In Review`, `Blocked`, env-keyed `{ dev: "On Dev", staging: "On Stg", production: "Done" }`. `ready` is a DEDICATED state, never the team default (`Todo`) — mapping it to the default makes every untouched backlog item claimable.
21
21
 
22
22
  ## Confirmation policy
23
23
 
24
- Once you have a team key, RUN. Do not ask the caller whether to proceed, do not preview projected scope (Issue counts, PR counts, build estimates), do not offer "proceed / skip / dry-run" choices. The caller has already authorized the run by invoking you. The pre-flight configured `blocked` label outcome owned by `linear-agent` is a valid terminal state of the per-Issue lifecycle, not a failure mode — large queues and complex Issues are exactly what this skill is for. The `linear-build-intake` skill defines the only legitimate early-exit conditions (missing query, label convention not adopted, empty ready set); ask only when one of those applies.
24
+ Once you have a team key, RUN. Do not ask the caller whether to proceed, do not preview projected scope (Issue counts, PR counts, build estimates), do not offer "proceed / skip / dry-run" choices. The caller has already authorized the run by invoking you. The pre-flight configured `blocked` state outcome owned by `linear-agent` is a valid terminal state of the per-Issue lifecycle, not a failure mode — large queues and complex Issues are exactly what this skill is for. The `linear-build-intake` skill defines the only legitimate early-exit conditions (missing query, workflow states not adopted, empty ready set); ask only when one of those applies.
25
25
 
26
26
  ## Workflow
27
27
 
28
28
  ### 1. Receive the query
29
29
 
30
- The invoking caller (a slash command, a scheduled cron, or a parent agent) hands you a Linear team key (e.g. `ENG`) or the literal token `linear` (which falls back to `linear.teamKey` in `.lisa.config.json`). You do not pick the team yourself. Lifecycle label names are read from `linear.workflow.*` and are not your concern at this layer.
30
+ The invoking caller (a slash command, a scheduled cron, or a parent agent) hands you a Linear team key (e.g. `ENG`) or the literal token `linear` (which falls back to `linear.teamKey` in `.lisa.config.json`). You do not pick the team yourself. Lifecycle state names are read from `linear.workflow.*` and are not your concern at this layer.
31
31
 
32
- If no query is provided AND no `linear.teamKey` is configured, stop and ask. Never run intake against a default scope without explicit configuration — the side effects (label transitions, PRs opened, builds running) are too high to act without an explicit target.
32
+ If no query is provided AND no `linear.teamKey` is configured, stop and ask. Never run intake against a default scope without explicit configuration — the side effects (state transitions, PRs opened, builds running) are too high to act without an explicit target.
33
33
 
34
34
  ### 2. Run the intake skill
35
35
 
@@ -42,23 +42,23 @@ The skill runs the linear-agent workflow in-session per Issue — read full grap
42
42
  Pass the skill's summary block through to the caller verbatim. The caller needs the structured record:
43
43
 
44
44
  - Total processed
45
- - Per-Issue outcomes (configured `done` label → which PR; configured `blocked` label by verify → which gate; `Held` by triage → which ambiguities; Errors → reason)
45
+ - Per-Issue outcomes (configured `done` state → which PR; configured `blocked` state by verify → which gate; `Held` by triage → which ambiguities; Errors → reason)
46
46
  - PR count
47
47
 
48
- If the cycle errored before processing any Issues (e.g. label convention not adopted — the configured `ready` label doesn't exist on the team), surface the cause in plain language and stop. Do NOT attempt to invent labels.
48
+ If the cycle errored before processing any Issues (e.g. workflow states not adopted — the configured `ready` state doesn't exist on the team), surface the cause in plain language and stop. Do NOT attempt to invent states: a workflow state carries a `type` and a board position, and guessing either puts an Issue somewhere no human sanctioned. Point at `/lisa:setup:linear`.
49
49
 
50
50
  ### 4. Suggest next actions when warranted
51
51
 
52
- After a successful cycle, if any Issues ended at the configured `done` label, mention whether the vendor skill also performed terminal native completion. This skill does not own anything past `done`, except that `linear-build-intake` moves the native Issue state to Done / Completed when `done` is the true terminal value per `leaf-only-lifecycle`.
52
+ After a successful cycle, if any Issues ended at the configured `done` state, note which env rung they reached. Terminal closure needs no separate step now: only the production/final `done` state is typed `completed`, so reaching it IS the native closure, while the intermediate env rungs are typed `started` and correctly leave the Issue open.
53
53
 
54
- If any Issues ended at the configured `blocked` label (pre-flight verify failed) or `Held` (triage found ambiguities), point that out so the caller knows which Issues need human attention before they can be re-claimed. The blocked ones were transitioned by `linear-agent`'s gate logic — that is correct and expected.
54
+ If any Issues ended at the configured `blocked` state (pre-flight verify failed) or `Held` (triage found ambiguities), point that out so the caller knows which Issues need human attention before they can be re-claimed. The blocked ones were transitioned by `linear-agent`'s gate logic — that is correct and expected.
55
55
 
56
56
  ## Rules
57
57
 
58
58
  - **Never run a cycle without an explicit query or configured `linear.teamKey`.** Side effects too high to default.
59
- - **Never modify the lifecycle**: only the configured `ready → claimed → done` transitions and terminal-only native Issue completion. Never touch the configured `blocked` label (owned by `linear-agent`) or any other label. (Exception: the configured `review` label is set by `linear-evidence` mid-flow — that's not your concern.)
59
+ - **Never modify the lifecycle**: only the configured `ready → claimed → done` state transitions. Never move an Issue to the configured `blocked` state (owned by `linear-agent`) or to any state outside those three. (Exception: the configured `review` state is set by `linear-evidence` mid-flow — that's not your concern.)
60
60
  - **Never bypass `linear-agent` to do build work directly.** The intake skill dispatches; `linear-agent` builds. Skipping the dispatch produces broken work.
61
- - **Never invent labels.** Names live in `.lisa.config.json` `linear.workflow.*` (canonical) — the setup skill writes them. If a team hasn't adopted them yet, the skill exits with an adoption hint. Don't guess label names.
61
+ - **Never invent states.** Names live in `.lisa.config.json` `linear.workflow.*` (canonical) — the setup skill writes them. If a team hasn't adopted them yet, the skill exits with an adoption hint. Don't guess state names.
62
62
  - **Never start a second cycle while one is in flight against an overlapping team.** Serial execution. Scheduling layer (when added) is responsible for not double-firing.
63
63
  - **Stop and surface failures rather than retry-loop.** If `linear-agent` returns an unexpected response or an error, the skill records it under "Errors" — pass that through. Do not auto-retry.
64
- - **Pre-flight failures are not your problem to fix.** If an Issue fails `linear-verify` (missing Validation Journey, sign-in, etc.), `linear-agent` transitions it to the configured `blocked` label and reassigns to the creator. Surface the count and move on. Do NOT try to add the missing pieces from this agent.
64
+ - **Pre-flight failures are not your problem to fix.** If an Issue fails `linear-verify` (missing Validation Journey, sign-in, etc.), `linear-agent` transitions it to the configured `blocked` state and reassigns to the creator. Surface the count and move on. Do NOT try to add the missing pieces from this agent.
@@ -344,7 +344,7 @@ When `github.projects.v2` is present, later setup/doctor and writer preflight va
344
344
  |-------|---------------|-------|
345
345
  | `linear.workspace` | `tracker = "linear"`, `source = "linear"`, or any `linear-*` skill is invoked | Linear workspace slug (e.g. `acme`). |
346
346
  | `linear.teamKey` | `tracker = "linear"` | Linear team key (e.g. `ENG`). The team owns the destination Issues. For source mode, projects are workspace-scoped or team-scoped per the URL passed. |
347
- | `linear.workflow` | `tracker = "linear"` | Workflow **state** name per build lifecycle role — the Linear analogue of `jira.workflow`, not of `github.labels`. Defaults `{ ready: "Todo", claimed: "In Progress", review: "In Review", blocked: "Blocked", done: { dev: "On Dev", staging: "On Stg", production: "Done" } }`. Resolve and verify with `/lisa:setup:linear`. |
347
+ | `linear.workflow` | `tracker = "linear"` | Workflow **state** name per build lifecycle role — the Linear analogue of `jira.workflow`, not of `github.labels`. Defaults `{ ready: "Ready", claimed: "In Progress", review: "In Review", blocked: "Blocked", done: { dev: "On Dev", staging: "On Stg", production: "Done" } }`. **`ready` is a dedicated state, never the team's default** — see below. Resolve and verify with `/lisa:setup:linear`. |
348
348
  | `linear.labels` | `tracker = "linear"` or `source = "linear"` | **Markers and the PRD lane only.** `build.human_needed` (default `human-needed`) and the `prd.*` map. The build lifecycle does **not** live here — see `linear.workflow`. |
349
349
 
350
350
  ##### Why Linear uses states, not labels
@@ -429,7 +429,7 @@ Every lifecycle skill operates on a fixed set of **roles** (`ready`, `claimed`,
429
429
 
430
430
  | Role | What it means | JIRA default | Linear default | GitHub default |
431
431
  |---|---|---|---|---|
432
- | `ready` | Human signal "this is buildable; agent may claim" | `Ready` (status) | `Todo` (state) | `status:ready` (label) |
432
+ | `ready` | Human signal "this is buildable; agent may claim" | `Ready` (status) | `Ready` (state) | `status:ready` (label) |
433
433
  | `claimed` | Agent has picked the item up | `In Progress` (status) | `In Progress` (state) | `status:in-progress` (label) |
434
434
  | `review` | Optional post-build review hold, when a tracker/project still uses one | `Code Review` (status) | `In Review` (state) | no default review label |
435
435
  | `blocked` | Agent stopped on triage ambiguities or external blocker | `Blocked` (status) | `Blocked` (state) | `status:blocked` (label) |
@@ -439,7 +439,9 @@ Every lifecycle skill operates on a fixed set of **roles** (`ready`, `claimed`,
439
439
 
440
440
  `review` is optional. GitHub build intake skips it by default and moves successful builds directly from `claimed` to the configured `done` label. Linear and JIRA projects that still use a post-build review hold can configure `review`; projects that keep the ticket in `claimed` until terminal can omit it and lifecycle skills will skip the intermediate transition.
441
441
 
442
- **Linear state resolution is `type`-aware.** When a configured name is missing, a lifecycle skill may fall back to the team's states by `type` `ready` the lowest-position `unstarted`, `claimed` the lowest-position `started`, terminal `done` `completed` but only to *read*; it must never invent a state to write into. Missing states are a setup defect, repaired by `/lisa:setup:linear`, not papered over at runtime.
442
+ **`ready` must never resolve to the team's DEFAULT state.** `Todo` is where Linear puts a brand-new issue, so using it for `ready` inverts the gate: the lane stops meaning "a human flipped this to build-ready" and starts meaning "nobody has touched this". Measured on the first team migrated: 20 issues in the lane, only 8 ever explicitly marked ready. JIRA avoids this because `jira.workflow.ready` is a dedicated `Ready` status while a fresh ticket lands in the project default.
443
+
444
+ **Linear state resolution is `type`-aware.** When a configured name is missing, a lifecycle skill may fall back to the team's states by `type` — `claimed`/`review` → the lowest-position `started`, `blocked` → `started` or `unstarted`, terminal `done` → `completed` — but only to *read*. **`ready` has no fallback on purpose:** every candidate would be the team's default unstarted state, which is exactly the inversion described above. A missing `ready` state is reported, never guessed; it must never invent a state to write into. Missing states are a setup defect, repaired by `/lisa:setup:linear`, not papered over at runtime.
443
445
 
444
446
  `blocked` is what every vendor agent flips to when triage finds unresolved ambiguities or the build path is blocked by something the agent can't resolve. Different from `claimed` because it explicitly signals "human attention required."
445
447
 
@@ -23,6 +23,15 @@ const DEFAULT_JIRA_BUILD_DONE = {
23
23
  production: "Done",
24
24
  };
25
25
 
26
+ // Linear shares JIRA's env rung NAMES but is a separate constant on purpose:
27
+ // the two vocabularies are independently configurable and a shared object would
28
+ // silently couple them.
29
+ const DEFAULT_LINEAR_BUILD_DONE = {
30
+ dev: "On Dev",
31
+ staging: "On Stg",
32
+ production: "Done",
33
+ };
34
+
26
35
  const DEFAULT_GITHUB_LINEAR_PRD_ROLES = {
27
36
  draft: "prd-draft",
28
37
  ready: "prd-ready",
@@ -290,18 +299,21 @@ export function resolveBuildLifecycleRoles(
290
299
  },
291
300
  };
292
301
  case "linear":
302
+ // Linear resolves BUILD roles to native workflow states, like JIRA — not
303
+ // to labels like GitHub, which has no workflow-state field to use. The
304
+ // `kind` matters to callers: it tells them whether a transition is a
305
+ // state move or a label swap.
293
306
  return {
294
307
  vendor: "linear",
295
- kind: "labels",
308
+ kind: "workflow",
296
309
  roles: {
297
- ready: config.linear?.labels?.build?.ready || "status:ready",
298
- claimed:
299
- config.linear?.labels?.build?.claimed || "status:in-progress",
300
- review: config.linear?.labels?.build?.review || "status:code-review",
301
- blocked: config.linear?.labels?.build?.blocked || "status:blocked",
310
+ ready: config.linear?.workflow?.ready || "Ready",
311
+ claimed: config.linear?.workflow?.claimed || "In Progress",
312
+ review: config.linear?.workflow?.review || "In Review",
313
+ blocked: config.linear?.workflow?.blocked || "Blocked",
302
314
  done:
303
- config.linear?.labels?.build?.done ||
304
- structuredClone(DEFAULT_GITHUB_BUILD_DONE),
315
+ config.linear?.workflow?.done ||
316
+ structuredClone(DEFAULT_LINEAR_BUILD_DONE),
305
317
  },
306
318
  };
307
319
  case "jira":
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: lisa-detect-tooling
3
- description: "Find the command-line tools a project needs but never declares, and propose pinned manifest entries for them. Reads npm scripts, MCP servers, credential usage notes and quality configuration, subtracts whatever remoteEnv.tools already covers, and prints proposals with evidence. Writes nothing and installs nothing — a tool reaches a machine only when a human has reviewed a pinned, checksummed entry. Invoked by lisa-setup-remote-env before provisioning, and runnable on its own."
3
+ description: "Find the command-line tools a project needs but never declares, and propose pinned manifest entries for them. Reads git hooks and npm scripts for what the project actually RUNS — discovering tools no list mentions — plus MCP servers, credential usage notes and quality configuration. Subtracts whatever remoteEnv.tools, node_modules and the workstation layer already cover, and prints proposals with evidence. Writes nothing and installs nothing — a tool reaches a machine only when a human has reviewed a pinned, checksummed entry. Invoked by lisa-setup-remote-env before provisioning, and runnable on its own."
4
4
  allowed-tools: ["Bash", "Read", "AskUserQuestion"]
5
5
  ---
6
6
 
@@ -20,15 +20,45 @@ Nothing populates that last row. So a project can ship scripts that invoke `maes
20
20
 
21
21
  That is the same failure this repository has now paid for twice: `gh` was declared nowhere and a cloud session could not commit; `tar` was needed by an install method and asserted by nothing.
22
22
 
23
+ ## Discovery, not recognition
24
+
25
+ The first version of this could only find tools it had been told about: it matched script bodies against a fixed `KNOWN_TOOLS` list. That makes the detector useful for exactly the set that needs it least — the tools someone already thought of.
26
+
27
+ An Expo project invoking `eas` from **eight** npm scripts and six CI steps produced no proposal, because `eas` was not on the list. `gitleaks`, which runs on every commit in every one of these repositories, produced no proposal either.
28
+
29
+ So the question asked of executable sources is now the open one — *what does this project actually run* — and everything already provided is subtracted afterwards:
30
+
31
+ - what `remoteEnv.tools` declares
32
+ - what `node_modules/.bin` provides (a dependency's binary never needs to be on PATH)
33
+ - what `lisa-setup-workstation` owns (coding agents belong to the machine, not the checkout)
34
+
35
+ The curated list stays, because a vetted `why` is worth more than an observed one — proposals say which they are, `[curated]` or `[discovered]`.
36
+
23
37
  ## What it does
24
38
 
25
- Reads four signals, subtracts what `remoteEnv.tools` already declares, and prints what is left with the evidence for each:
39
+ Reads six signals, subtracts what is already covered, and prints what is left with the evidence for each:
40
+
41
+ - **git hooks** (`.husky/*`, `.git/hooks/*`) that invoke a binary. The **strongest** signal available, stronger than an npm script: a hook runs on every commit and push whether anyone asked or not, so a machine without the tool cannot commit at all.
26
42
 
27
- - **npm scripts** that invoke a binary. The strongest signal there is a script running `maestro test` is the project stating a dependency in executable form. Matched on the script *body*, not its name, because the name is a label.
43
+ A `command -v` guard counts as evidence rather than as "optional", because the guarded shape is the worse one. Lisa's pre-commit hook wraps its secret scan in `command -v gitleaks`, so on a machine without gitleaks the scan is **skipped silently** — the hook passes, the commit succeeds, and nothing was scanned. A guard makes the absence invisible precisely where it matters.
44
+
45
+ - **npm scripts** that invoke a binary — a script running `maestro test` is the project stating a dependency in executable form. Read from the script *body*, not its name, because the name is a label.
28
46
  - **MCP servers with a CLI equivalent.** An MCP server is not a substitute for the binary: several authenticate by browser OAuth, which a container cannot do, so a project relying on one remotely has *no* integration rather than a degraded one. Do not infer a CLI for access layers that already define their own headless substrate; Linear is handled by `lisa-linear-access` through `LINEAR_API_KEY` + GraphQL when MCP OAuth is unavailable.
29
47
  - **Credential usage notes.** A note explaining what a token is for usually names the program that consumes it. `lisa-secrets-access` already exposes these without touching a value, which makes them a first-class input rather than a trick.
30
48
  - **Quality configuration**, where a threshold implies the tool that produces it.
31
49
 
50
+ ## Reading shell is the hard part
51
+
52
+ Discovery only works if "what does this run" can be answered from shell text without inventing commands. Three things had to be right, each found by running it against real repositories:
53
+
54
+ **Only the first word of a command position counts.** Word-scanning this repo's own hooks proposed `ltrimstr`, `map` and `select` (jq filter internals), `console.log` and `process.exit` (embedded JavaScript), and `load_audit_cves` (a function the hook defines three lines up). Reading only where a command can actually start removes all of them without a denylist entry for any.
55
+
56
+ **Quoting and commenting nest, so neither can be stripped independently.** The comment on line 9 of `pre-push.local` ends `...the script's exit code)`. That lone apostrophe pairs with the next real quote 28 lines later, blanks everything between, and leaks a `node -e` payload's JavaScript into the results. Stripping comments first does not fix it, because a `#` inside a quoted string is not a comment. One character scanner tracking both is the only correct shape.
57
+
58
+ **`$( )` restarts the quoting context.** In `"$(printf '%s' "$JSON" | node -e '…')"`, quotes inside the substitution pair among themselves. A flat scanner falls out of phase on the first one and starts reporting the payload's own string literals.
59
+
60
+ Against Lisa and the three TunnlAI repositories, what survives is `gitleaks`, `jq`, `gtimeout` and `eas` — every one a real, undeclared invocation, with no false positives.
61
+
32
62
  ## What it will not do
33
63
 
34
64
  **It writes nothing and installs nothing.** Output is a proposal with `<pin>`, `<release url>` and `<sha256>` left for a human.