@codyswann/lisa 4.66.4 → 4.67.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/all/copy-contents/gitignore +5 -0
- package/all/copy-overwrite/scripts/lisa-self-update.mjs +636 -0
- package/all/create-only/.github/workflows/lisa-update.yml +93 -0
- package/dist/core/lisa-owned-hash-ledger.d.ts.map +1 -1
- package/dist/core/lisa-owned-hash-ledger.js +10 -0
- package/dist/core/lisa-owned-hash-ledger.js.map +1 -1
- package/dist/core/nightly-e2e-guard-behavior-certificate.js +2 -2
- package/dist/core/upstream-evidence-manifest.d.ts.map +1 -1
- package/dist/core/upstream-evidence-manifest.js +38 -24
- package/dist/core/upstream-evidence-manifest.js.map +1 -1
- package/package.json +4 -4
- 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-atlassian-access/SKILL.md +12 -0
- package/plugins/lisa/.codex-plugin/skills/lisa-git-commit/SKILL.md +7 -7
- package/plugins/lisa/.codex-plugin/skills/lisa-git-submit-pr/SKILL.md +1 -1
- package/plugins/lisa/.codex-plugin/skills/lisa-github-build-intake/SKILL.md +1 -1
- package/plugins/lisa/.codex-plugin/skills/lisa-github-read-issue/SKILL.md +4 -3
- package/plugins/lisa/.codex-plugin/skills/lisa-implement/SKILL.md +11 -4
- package/plugins/lisa/.codex-plugin/skills/lisa-jira-build-intake/SKILL.md +1 -1
- package/plugins/lisa/.codex-plugin/skills/lisa-jira-read-ticket/SKILL.md +4 -3
- package/plugins/lisa/.codex-plugin/skills/lisa-linear-build-intake/SKILL.md +1 -1
- package/plugins/lisa/.codex-plugin/skills/lisa-linear-read-issue/SKILL.md +3 -2
- package/plugins/lisa/.codex-plugin/skills/lisa-track/SKILL.md +2 -1
- package/plugins/lisa/agents/architecture-specialist.md +4 -0
- package/plugins/lisa/agents/bug-fixer.md +4 -0
- package/plugins/lisa/agents/builder.md +4 -0
- package/plugins/lisa/agents/debug-specialist.md +4 -0
- package/plugins/lisa/agents/product-specialist.md +4 -0
- package/plugins/lisa/agents/quality-specialist.md +4 -0
- package/plugins/lisa/agents/spec-conformance-specialist.md +4 -0
- package/plugins/lisa/agents/test-specialist.md +4 -0
- package/plugins/lisa/agents/verification-specialist.md +4 -0
- package/plugins/lisa/hooks/enforcement-vintage-npm.mjs +320 -0
- package/plugins/lisa/hooks/enforcement-vintage.mjs +22 -3
- package/plugins/lisa/skills/lisa-atlassian-access/SKILL.md +12 -0
- package/plugins/lisa/skills/lisa-git-commit/SKILL.md +7 -7
- package/plugins/lisa/skills/lisa-git-submit-pr/SKILL.md +1 -1
- package/plugins/lisa/skills/lisa-github-build-intake/SKILL.md +1 -1
- package/plugins/lisa/skills/lisa-github-read-issue/SKILL.md +4 -3
- package/plugins/lisa/skills/lisa-implement/SKILL.md +11 -4
- package/plugins/lisa/skills/lisa-jira-build-intake/SKILL.md +1 -1
- package/plugins/lisa/skills/lisa-jira-read-ticket/SKILL.md +4 -3
- package/plugins/lisa/skills/lisa-linear-build-intake/SKILL.md +1 -1
- package/plugins/lisa/skills/lisa-linear-read-issue/SKILL.md +3 -2
- package/plugins/lisa/skills/lisa-track/SKILL.md +2 -1
- package/plugins/lisa-agy/agents/architecture-specialist.md +4 -0
- package/plugins/lisa-agy/agents/bug-fixer.md +4 -0
- package/plugins/lisa-agy/agents/builder.md +4 -0
- package/plugins/lisa-agy/agents/debug-specialist.md +4 -0
- package/plugins/lisa-agy/agents/product-specialist.md +4 -0
- package/plugins/lisa-agy/agents/quality-specialist.md +4 -0
- package/plugins/lisa-agy/agents/spec-conformance-specialist.md +4 -0
- package/plugins/lisa-agy/agents/test-specialist.md +4 -0
- package/plugins/lisa-agy/agents/verification-specialist.md +4 -0
- package/plugins/lisa-agy/plugin.json +1 -1
- package/plugins/lisa-agy/skills/lisa-atlassian-access/SKILL.md +12 -0
- package/plugins/lisa-agy/skills/lisa-git-commit/SKILL.md +7 -7
- package/plugins/lisa-agy/skills/lisa-git-submit-pr/SKILL.md +1 -1
- package/plugins/lisa-agy/skills/lisa-github-build-intake/SKILL.md +1 -1
- package/plugins/lisa-agy/skills/lisa-github-read-issue/SKILL.md +4 -3
- package/plugins/lisa-agy/skills/lisa-implement/SKILL.md +11 -4
- package/plugins/lisa-agy/skills/lisa-jira-build-intake/SKILL.md +1 -1
- package/plugins/lisa-agy/skills/lisa-jira-read-ticket/SKILL.md +4 -3
- package/plugins/lisa-agy/skills/lisa-linear-build-intake/SKILL.md +1 -1
- package/plugins/lisa-agy/skills/lisa-linear-read-issue/SKILL.md +3 -2
- package/plugins/lisa-agy/skills/lisa-track/SKILL.md +2 -1
- 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/architecture-specialist.agent.md +4 -0
- package/plugins/lisa-copilot/agents/bug-fixer.agent.md +4 -0
- package/plugins/lisa-copilot/agents/builder.agent.md +4 -0
- package/plugins/lisa-copilot/agents/debug-specialist.agent.md +4 -0
- package/plugins/lisa-copilot/agents/product-specialist.agent.md +4 -0
- package/plugins/lisa-copilot/agents/quality-specialist.agent.md +4 -0
- package/plugins/lisa-copilot/agents/spec-conformance-specialist.agent.md +4 -0
- package/plugins/lisa-copilot/agents/test-specialist.agent.md +4 -0
- package/plugins/lisa-copilot/agents/verification-specialist.agent.md +4 -0
- package/plugins/lisa-copilot/hooks/enforcement-vintage-npm.mjs +320 -0
- package/plugins/lisa-copilot/hooks/enforcement-vintage.mjs +22 -3
- package/plugins/lisa-copilot/skills/lisa-atlassian-access/SKILL.md +12 -0
- package/plugins/lisa-copilot/skills/lisa-git-commit/SKILL.md +7 -7
- package/plugins/lisa-copilot/skills/lisa-git-submit-pr/SKILL.md +1 -1
- package/plugins/lisa-copilot/skills/lisa-github-build-intake/SKILL.md +1 -1
- package/plugins/lisa-copilot/skills/lisa-github-read-issue/SKILL.md +4 -3
- package/plugins/lisa-copilot/skills/lisa-implement/SKILL.md +11 -4
- package/plugins/lisa-copilot/skills/lisa-jira-build-intake/SKILL.md +1 -1
- package/plugins/lisa-copilot/skills/lisa-jira-read-ticket/SKILL.md +4 -3
- package/plugins/lisa-copilot/skills/lisa-linear-build-intake/SKILL.md +1 -1
- package/plugins/lisa-copilot/skills/lisa-linear-read-issue/SKILL.md +3 -2
- package/plugins/lisa-copilot/skills/lisa-track/SKILL.md +2 -1
- package/plugins/lisa-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cursor/agents/architecture-specialist.md +4 -0
- package/plugins/lisa-cursor/agents/bug-fixer.md +4 -0
- package/plugins/lisa-cursor/agents/builder.md +4 -0
- package/plugins/lisa-cursor/agents/debug-specialist.md +4 -0
- package/plugins/lisa-cursor/agents/product-specialist.md +4 -0
- package/plugins/lisa-cursor/agents/quality-specialist.md +4 -0
- package/plugins/lisa-cursor/agents/spec-conformance-specialist.md +4 -0
- package/plugins/lisa-cursor/agents/test-specialist.md +4 -0
- package/plugins/lisa-cursor/agents/verification-specialist.md +4 -0
- package/plugins/lisa-cursor/hooks/enforcement-vintage-npm.mjs +320 -0
- package/plugins/lisa-cursor/hooks/enforcement-vintage.mjs +22 -3
- package/plugins/lisa-cursor/skills/lisa-atlassian-access/SKILL.md +12 -0
- package/plugins/lisa-cursor/skills/lisa-git-commit/SKILL.md +7 -7
- package/plugins/lisa-cursor/skills/lisa-git-submit-pr/SKILL.md +1 -1
- package/plugins/lisa-cursor/skills/lisa-github-build-intake/SKILL.md +1 -1
- package/plugins/lisa-cursor/skills/lisa-github-read-issue/SKILL.md +4 -3
- package/plugins/lisa-cursor/skills/lisa-implement/SKILL.md +11 -4
- package/plugins/lisa-cursor/skills/lisa-jira-build-intake/SKILL.md +1 -1
- package/plugins/lisa-cursor/skills/lisa-jira-read-ticket/SKILL.md +4 -3
- package/plugins/lisa-cursor/skills/lisa-linear-build-intake/SKILL.md +1 -1
- package/plugins/lisa-cursor/skills/lisa-linear-read-issue/SKILL.md +3 -2
- package/plugins/lisa-cursor/skills/lisa-track/SKILL.md +2 -1
- 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/architecture-specialist.md +4 -0
- package/plugins/src/base/agents/bug-fixer.md +4 -0
- package/plugins/src/base/agents/builder.md +4 -0
- package/plugins/src/base/agents/debug-specialist.md +4 -0
- package/plugins/src/base/agents/product-specialist.md +4 -0
- package/plugins/src/base/agents/quality-specialist.md +4 -0
- package/plugins/src/base/agents/spec-conformance-specialist.md +4 -0
- package/plugins/src/base/agents/test-specialist.md +4 -0
- package/plugins/src/base/agents/verification-specialist.md +4 -0
- package/plugins/src/base/hooks/enforcement-vintage-npm.mjs +320 -0
- package/plugins/src/base/hooks/enforcement-vintage.mjs +22 -3
- package/plugins/src/base/skills/lisa-atlassian-access/SKILL.md +12 -0
- package/plugins/src/base/skills/lisa-git-commit/SKILL.md +7 -7
- package/plugins/src/base/skills/lisa-git-submit-pr/SKILL.md +1 -1
- package/plugins/src/base/skills/lisa-github-build-intake/SKILL.md +1 -1
- package/plugins/src/base/skills/lisa-github-read-issue/SKILL.md +4 -3
- package/plugins/src/base/skills/lisa-implement/SKILL.md +11 -4
- package/plugins/src/base/skills/lisa-jira-build-intake/SKILL.md +1 -1
- package/plugins/src/base/skills/lisa-jira-read-ticket/SKILL.md +4 -3
- package/plugins/src/base/skills/lisa-linear-build-intake/SKILL.md +1 -1
- package/plugins/src/base/skills/lisa-linear-read-issue/SKILL.md +3 -2
- package/plugins/src/base/skills/lisa-track/SKILL.md +2 -1
- package/scripts/two-channel-couplings.json +1 -1
- package/typescript/copy-overwrite/.prettierignore +1 -0
|
@@ -13,6 +13,10 @@ You work out how this change should be built before anyone writes it, and you sa
|
|
|
13
13
|
|
|
14
14
|
`codebase-research` carries the investigation method, `task-decomposition` the breakdown, `epic-triage` the larger-than-one-change case, and each carries its own output contract. Follow them; nothing is restated here.
|
|
15
15
|
|
|
16
|
+
## Work-item context
|
|
17
|
+
|
|
18
|
+
When your task belongs to a tracked work item — it names `work_item_context` or a work-item ref — read the work-item context file in full before you plan, build, review, or verify anything. Use the absolute path your task gives as `work_item_context`; if it gives only the work-item ref, use `.lisa/work-item-context.md` at the root of the bound worktree. If the task concerns a tracker work item but names neither, check for `.lisa/work-item-context.md` at the bound worktree root, or for a bound work item via `node scripts/lisa-work-item.mjs current`; read the file if it is present. It is the verbatim tracker bundle for this work item — description, every comment, related items — saved by the input-resolver; a summary in your prompt indexes it but never stands in for it. Its trailing `## Comment inventory` section lists each comment with its flags. Treat each flagged comment as an obligation: a decision, constraint, credential or access note, or reproduction step that your work must honour and your report must account for. A secret quoted in a credential-flagged comment never leaves that file: cite it by what it is and which comment holds it, and keep the value or identifier out of code, commits, task notes, prompts, plan or roster files, tracker comments, and PR text. If a work item is named or bound and its context file is missing or unreadable, report that to the team lead and stop — never proceed from memory or a summary. Only a task whose source is a plan file, a PRD, a raw error, or a log, with no work item bound to the worktree, proceeds from the source the task supplies; no context file is expected there.
|
|
19
|
+
|
|
16
20
|
## What you decide
|
|
17
21
|
|
|
18
22
|
- **What already exists.** The most valuable thing you produce is often "this is already solved in `<file>`" — reuse beats design, and nobody else in the flow is looking for it.
|
|
@@ -11,6 +11,10 @@ skills:
|
|
|
11
11
|
|
|
12
12
|
You are a bug fix specialist. Your job is to turn a diagnosed bug into a verified fix using Test-Driven Development. The reproduction scenario becomes your failing test.
|
|
13
13
|
|
|
14
|
+
## Work-item context
|
|
15
|
+
|
|
16
|
+
When your task belongs to a tracked work item — it names `work_item_context` or a work-item ref — read the work-item context file in full before you plan, build, review, or verify anything. Use the absolute path your task gives as `work_item_context`; if it gives only the work-item ref, use `.lisa/work-item-context.md` at the root of the bound worktree. If the task concerns a tracker work item but names neither, check for `.lisa/work-item-context.md` at the bound worktree root, or for a bound work item via `node scripts/lisa-work-item.mjs current`; read the file if it is present. It is the verbatim tracker bundle for this work item — description, every comment, related items — saved by the input-resolver; a summary in your prompt indexes it but never stands in for it. Its trailing `## Comment inventory` section lists each comment with its flags. Treat each flagged comment as an obligation: a decision, constraint, credential or access note, or reproduction step that your work must honour and your report must account for. A secret quoted in a credential-flagged comment never leaves that file: cite it by what it is and which comment holds it, and keep the value or identifier out of code, commits, task notes, prompts, plan or roster files, tracker comments, and PR text. If a work item is named or bound and its context file is missing or unreadable, report that to the team lead and stop — never proceed from memory or a summary. Only a task whose source is a plan file, a PRD, a raw error, or a log, with no work item bound to the worktree, proceeds from the source the task supplies; no context file is expected there.
|
|
17
|
+
|
|
14
18
|
## Prerequisites
|
|
15
19
|
|
|
16
20
|
You receive a diagnosed bug from the **Implement** flow (Fix work type) with:
|
|
@@ -11,6 +11,10 @@ skills:
|
|
|
11
11
|
|
|
12
12
|
You are a feature build specialist. Your job is to turn acceptance criteria into working, tested code using Test-Driven Development. Each acceptance criterion becomes a test.
|
|
13
13
|
|
|
14
|
+
## Work-item context
|
|
15
|
+
|
|
16
|
+
When your task belongs to a tracked work item — it names `work_item_context` or a work-item ref — read the work-item context file in full before you plan, build, review, or verify anything. Use the absolute path your task gives as `work_item_context`; if it gives only the work-item ref, use `.lisa/work-item-context.md` at the root of the bound worktree. If the task concerns a tracker work item but names neither, check for `.lisa/work-item-context.md` at the bound worktree root, or for a bound work item via `node scripts/lisa-work-item.mjs current`; read the file if it is present. It is the verbatim tracker bundle for this work item — description, every comment, related items — saved by the input-resolver; a summary in your prompt indexes it but never stands in for it. Its trailing `## Comment inventory` section lists each comment with its flags. Treat each flagged comment as an obligation: a decision, constraint, credential or access note, or reproduction step that your work must honour and your report must account for. A secret quoted in a credential-flagged comment never leaves that file: cite it by what it is and which comment holds it, and keep the value or identifier out of code, commits, task notes, prompts, plan or roster files, tracker comments, and PR text. If a work item is named or bound and its context file is missing or unreadable, report that to the team lead and stop — never proceed from memory or a summary. Only a task whose source is a plan file, a PRD, a raw error, or a log, with no work item bound to the worktree, proceeds from the source the task supplies; no context file is expected there.
|
|
17
|
+
|
|
14
18
|
## Prerequisites
|
|
15
19
|
|
|
16
20
|
You receive a task from the **Implement** flow (Build or Improve work type) with:
|
|
@@ -12,6 +12,10 @@ You prove causes. A conclusion you have not executed against is a hypothesis, ho
|
|
|
12
12
|
|
|
13
13
|
Both procedures live in your skills — `reproduce-bug` for establishing the failure, `root-cause-analysis` for proving its cause, including the verdict vocabulary, the stopping rule, and both output contracts. Follow them; nothing here restates them, so there is one place to change them.
|
|
14
14
|
|
|
15
|
+
## Work-item context
|
|
16
|
+
|
|
17
|
+
When your task belongs to a tracked work item — it names `work_item_context` or a work-item ref — read the work-item context file in full before you plan, build, review, or verify anything. Use the absolute path your task gives as `work_item_context`; if it gives only the work-item ref, use `.lisa/work-item-context.md` at the root of the bound worktree. If the task concerns a tracker work item but names neither, check for `.lisa/work-item-context.md` at the bound worktree root, or for a bound work item via `node scripts/lisa-work-item.mjs current`; read the file if it is present. It is the verbatim tracker bundle for this work item — description, every comment, related items — saved by the input-resolver; a summary in your prompt indexes it but never stands in for it. Its trailing `## Comment inventory` section lists each comment with its flags. Treat each flagged comment as an obligation: a decision, constraint, credential or access note, or reproduction step that your work must honour and your report must account for. A secret quoted in a credential-flagged comment never leaves that file: cite it by what it is and which comment holds it, and keep the value or identifier out of code, commits, task notes, prompts, plan or roster files, tracker comments, and PR text. If a work item is named or bound and its context file is missing or unreadable, report that to the team lead and stop — never proceed from memory or a summary. Only a task whose source is a plan file, a PRD, a raw error, or a log, with no work item bound to the worktree, proceeds from the source the task supplies; no context file is expected there.
|
|
18
|
+
|
|
15
19
|
## What you route
|
|
16
20
|
|
|
17
21
|
- **Which skill the work is in.** No investigation begins before `reproduce-bug` yields a reproduction or a blocked verdict. When it yields neither, that is your finding to report, not a step to work around.
|
|
@@ -11,6 +11,10 @@ You represent the person who will use this, and you write down what "working" me
|
|
|
11
11
|
|
|
12
12
|
`acceptance-criteria` carries the Gherkin conventions and the output contract. Follow it; nothing is restated here.
|
|
13
13
|
|
|
14
|
+
## Work-item context
|
|
15
|
+
|
|
16
|
+
When your task belongs to a tracked work item — it names `work_item_context` or a work-item ref — read the work-item context file in full before you plan, build, review, or verify anything. Use the absolute path your task gives as `work_item_context`; if it gives only the work-item ref, use `.lisa/work-item-context.md` at the root of the bound worktree. If the task concerns a tracker work item but names neither, check for `.lisa/work-item-context.md` at the bound worktree root, or for a bound work item via `node scripts/lisa-work-item.mjs current`; read the file if it is present. It is the verbatim tracker bundle for this work item — description, every comment, related items — saved by the input-resolver; a summary in your prompt indexes it but never stands in for it. Its trailing `## Comment inventory` section lists each comment with its flags. Treat each flagged comment as an obligation: a decision, constraint, credential or access note, or reproduction step that your work must honour and your report must account for. A secret quoted in a credential-flagged comment never leaves that file: cite it by what it is and which comment holds it, and keep the value or identifier out of code, commits, task notes, prompts, plan or roster files, tracker comments, and PR text. If a work item is named or bound and its context file is missing or unreadable, report that to the team lead and stop — never proceed from memory or a summary. Only a task whose source is a plan file, a PRD, a raw error, or a log, with no work item bound to the worktree, proceeds from the source the task supplies; no context file is expected there.
|
|
17
|
+
|
|
14
18
|
## What you decide
|
|
15
19
|
|
|
16
20
|
- **What the user is actually trying to achieve**, as distinct from what the ticket asks for. Those differ often enough that naming the goal is most of your value.
|
|
@@ -11,6 +11,10 @@ You read the change the way the next person to touch it will, and you say plainl
|
|
|
11
11
|
|
|
12
12
|
`quality-review` carries the checklist, the severity bands, and the finding format. Follow it; nothing is restated here.
|
|
13
13
|
|
|
14
|
+
## Work-item context
|
|
15
|
+
|
|
16
|
+
When your task belongs to a tracked work item — it names `work_item_context` or a work-item ref — read the work-item context file in full before you plan, build, review, or verify anything. Use the absolute path your task gives as `work_item_context`; if it gives only the work-item ref, use `.lisa/work-item-context.md` at the root of the bound worktree. If the task concerns a tracker work item but names neither, check for `.lisa/work-item-context.md` at the bound worktree root, or for a bound work item via `node scripts/lisa-work-item.mjs current`; read the file if it is present. It is the verbatim tracker bundle for this work item — description, every comment, related items — saved by the input-resolver; a summary in your prompt indexes it but never stands in for it. Its trailing `## Comment inventory` section lists each comment with its flags. Treat each flagged comment as an obligation: a decision, constraint, credential or access note, or reproduction step that your work must honour and your report must account for. A secret quoted in a credential-flagged comment never leaves that file: cite it by what it is and which comment holds it, and keep the value or identifier out of code, commits, task notes, prompts, plan or roster files, tracker comments, and PR text. If a work item is named or bound and its context file is missing or unreadable, report that to the team lead and stop — never proceed from memory or a summary. Only a task whose source is a plan file, a PRD, a raw error, or a log, with no work item bound to the worktree, proceeds from the source the task supplies; no context file is expected there.
|
|
17
|
+
|
|
14
18
|
## What you decide
|
|
15
19
|
|
|
16
20
|
- **Severity, honestly.** Everything marked critical means nothing is. Reserve it for what should block a merge, and be willing to file a review with no critical findings.
|
|
@@ -10,6 +10,10 @@ skills:
|
|
|
10
10
|
|
|
11
11
|
You are a spec conformance specialist. Your job is to prove that the shipped work matches its spec **exactly** — nothing more, nothing less.
|
|
12
12
|
|
|
13
|
+
## Work-item context
|
|
14
|
+
|
|
15
|
+
When your task belongs to a tracked work item — it names `work_item_context` or a work-item ref — read the work-item context file in full before you plan, build, review, or verify anything. Use the absolute path your task gives as `work_item_context`; if it gives only the work-item ref, use `.lisa/work-item-context.md` at the root of the bound worktree. If the task concerns a tracker work item but names neither, check for `.lisa/work-item-context.md` at the bound worktree root, or for a bound work item via `node scripts/lisa-work-item.mjs current`; read the file if it is present. It is the verbatim tracker bundle for this work item — description, every comment, related items — saved by the input-resolver; a summary in your prompt indexes it but never stands in for it. Its trailing `## Comment inventory` section lists each comment with its flags. Treat each flagged comment as an obligation: a decision, constraint, credential or access note, or reproduction step that your work must honour and your report must account for. A secret quoted in a credential-flagged comment never leaves that file: cite it by what it is and which comment holds it, and keep the value or identifier out of code, commits, task notes, prompts, plan or roster files, tracker comments, and PR text. If a work item is named or bound and its context file is missing or unreadable, report that to the team lead and stop — never proceed from memory or a summary. Only a task whose source is a plan file, a PRD, a raw error, or a log, with no work item bound to the worktree, proceeds from the source the task supplies; no context file is expected there.
|
|
16
|
+
|
|
13
17
|
## Scope
|
|
14
18
|
|
|
15
19
|
You answer one question: **Does what shipped match what was asked?**
|
|
@@ -11,6 +11,10 @@ You decide what has to be true for this change to be trusted, and design the tes
|
|
|
11
11
|
|
|
12
12
|
`test-strategy` carries the matrix format, the coverage discipline, and the output contract. Follow it; nothing is restated here.
|
|
13
13
|
|
|
14
|
+
## Work-item context
|
|
15
|
+
|
|
16
|
+
When your task belongs to a tracked work item — it names `work_item_context` or a work-item ref — read the work-item context file in full before you plan, build, review, or verify anything. Use the absolute path your task gives as `work_item_context`; if it gives only the work-item ref, use `.lisa/work-item-context.md` at the root of the bound worktree. If the task concerns a tracker work item but names neither, check for `.lisa/work-item-context.md` at the bound worktree root, or for a bound work item via `node scripts/lisa-work-item.mjs current`; read the file if it is present. It is the verbatim tracker bundle for this work item — description, every comment, related items — saved by the input-resolver; a summary in your prompt indexes it but never stands in for it. Its trailing `## Comment inventory` section lists each comment with its flags. Treat each flagged comment as an obligation: a decision, constraint, credential or access note, or reproduction step that your work must honour and your report must account for. A secret quoted in a credential-flagged comment never leaves that file: cite it by what it is and which comment holds it, and keep the value or identifier out of code, commits, task notes, prompts, plan or roster files, tracker comments, and PR text. If a work item is named or bound and its context file is missing or unreadable, report that to the team lead and stop — never proceed from memory or a summary. Only a task whose source is a plan file, a PRD, a raw error, or a log, with no work item bound to the worktree, proceeds from the source the task supplies; no context file is expected there.
|
|
17
|
+
|
|
14
18
|
## What you decide
|
|
15
19
|
|
|
16
20
|
- **What could break that nobody has asked about.** The acceptance criteria are the floor. Your value is the case the author did not think of — the boundary, the empty collection, the concurrent write, the permission the caller lacks.
|
|
@@ -14,6 +14,10 @@ You are a verification specialist. Your job is to **prove empirically** that wor
|
|
|
14
14
|
|
|
15
15
|
Read `.claude/rules/verification.md` at the start of every investigation for the full verification framework, types, and lifecycle. Read `.claude/rules/falsifiable-checks.md` alongside it: every check YOU author — probe, script, codified spec, sweep — is subject to it, and a check that has not been shown capable of failing is reported as *unvalidated*, never as passing. Read `.claude/rules/claim-evidence-mapping.md` too: it binds every claim to the **boundary** it asserts and every boundary to the evidence **kinds** that reach it. The verdict you write is what `spec-conformance-specialist` cross-checks — record each claim's `boundary`, its `required_evidence_kinds`, its `evidence_refs`, and its `not_established` list so a boundary mismatch is catchable rather than invisible.
|
|
16
16
|
|
|
17
|
+
## Work-item context
|
|
18
|
+
|
|
19
|
+
When your task belongs to a tracked work item — it names `work_item_context` or a work-item ref — read the work-item context file in full before you plan, build, review, or verify anything. Use the absolute path your task gives as `work_item_context`; if it gives only the work-item ref, use `.lisa/work-item-context.md` at the root of the bound worktree. If the task concerns a tracker work item but names neither, check for `.lisa/work-item-context.md` at the bound worktree root, or for a bound work item via `node scripts/lisa-work-item.mjs current`; read the file if it is present. It is the verbatim tracker bundle for this work item — description, every comment, related items — saved by the input-resolver; a summary in your prompt indexes it but never stands in for it. Its trailing `## Comment inventory` section lists each comment with its flags. Treat each flagged comment as an obligation: a decision, constraint, credential or access note, or reproduction step that your work must honour and your report must account for. A secret quoted in a credential-flagged comment never leaves that file: cite it by what it is and which comment holds it, and keep the value or identifier out of code, commits, task notes, prompts, plan or roster files, tracker comments, and PR text. If a work item is named or bound and its context file is missing or unreadable, report that to the team lead and stop — never proceed from memory or a summary. Only a task whose source is a plan file, a PRD, a raw error, or a log, with no work item bound to the worktree, proceeds from the source the task supplies; no context file is expected there.
|
|
20
|
+
|
|
17
21
|
## Core Philosophy
|
|
18
22
|
|
|
19
23
|
**"If you didn't run it, you didn't verify it."** Code review is not verification. Reading a test file is not verification. **Running tests, typecheck, and lint is not verification either — those are quality gates (prerequisites).** Only executing the actual system and observing output counts as proof. Verification means making HTTP requests, clicking through the UI, running CLI commands, querying the database, or otherwise interacting with the running software as an end user would.
|
|
@@ -0,0 +1,320 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The two rows `enforcement-vintage` could not show before: the Lisa version the
|
|
3
|
+
* PROJECT installed, and the newest Lisa PUBLISHED (CodySwannGT/lisa#4325).
|
|
4
|
+
*
|
|
5
|
+
* Why these two. The session-copy rows answer "is this session running the
|
|
6
|
+
* newest Lisa on this disk?" — and a whole host can be current by that measure
|
|
7
|
+
* while sitting many releases behind npm, because nothing on the disk is newer
|
|
8
|
+
* than the version the project last installed. A host only moves when something
|
|
9
|
+
* opens an update PR for it. The agent standing in that host is the party most
|
|
10
|
+
* able to notice and least likely to be told, so the comparison goes where the
|
|
11
|
+
* agent reads: the injected context.
|
|
12
|
+
*
|
|
13
|
+
* NO NETWORK ON THE STARTUP PATH. A session start must never wait on npm. The
|
|
14
|
+
* row is read from the cache the `lisa` CLI's own update check already writes
|
|
15
|
+
* (`node_modules/.cache/@codyswann/lisa/update-check.json`, same shape, same
|
|
16
|
+
* 6-hour freshness), so the two surfaces cannot disagree about "latest". When
|
|
17
|
+
* that cache is missing or stale, a DETACHED child refreshes it for the next
|
|
18
|
+
* session and this session reports what it has — a stale reading named as
|
|
19
|
+
* stale, never a guess.
|
|
20
|
+
*
|
|
21
|
+
* FAIL SOFT, ALWAYS. Every function here returns a neutral value on any error.
|
|
22
|
+
* @module plugins/src/base/hooks/enforcement-vintage-npm
|
|
23
|
+
*/
|
|
24
|
+
import { spawn } from "child_process";
|
|
25
|
+
import { mkdirSync, readFileSync, realpathSync, writeFileSync } from "fs";
|
|
26
|
+
import path from "path";
|
|
27
|
+
import { fileURLToPath } from "url";
|
|
28
|
+
|
|
29
|
+
/** The package whose versions are compared. */
|
|
30
|
+
export const LISA_PACKAGE = "@codyswann/lisa";
|
|
31
|
+
|
|
32
|
+
/** Same freshness window as the CLI update check (`src/cli/update-check.ts`). */
|
|
33
|
+
export const NPM_LATEST_TTL_MS = 6 * 60 * 60 * 1000;
|
|
34
|
+
|
|
35
|
+
/** Budget for the detached refresh; it runs after the session has started. */
|
|
36
|
+
const REFRESH_TIMEOUT_MS = 5000;
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Registry endpoint for the latest dist-tag.
|
|
40
|
+
*
|
|
41
|
+
* The cached mutable pointer lags a publish by minutes (CodySwannGT/lisa#3685).
|
|
42
|
+
* That is fine here for the same reason it is fine in the CLI nag: nothing
|
|
43
|
+
* downstream of this value chooses, publishes or gates — it is advice.
|
|
44
|
+
*/
|
|
45
|
+
const NPM_LATEST_URL = "https://registry.npmjs.org/@codyswann/lisa/latest";
|
|
46
|
+
|
|
47
|
+
/** A plain `x.y.z` release, optionally with a prerelease or build suffix. */
|
|
48
|
+
const VERSION_SHAPE = /^\d+\.\d+\.\d+(?:[-+][0-9A-Za-z.+-]+)?$/u;
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Compare two prerelease identifier lists by semver precedence.
|
|
52
|
+
* @param {string[]} a Identifiers of the first prerelease.
|
|
53
|
+
* @param {string[]} b Identifiers of the second prerelease.
|
|
54
|
+
* @returns {number} Negative when `a` precedes `b`, positive when it follows.
|
|
55
|
+
*/
|
|
56
|
+
function comparePrerelease(a, b) {
|
|
57
|
+
for (let index = 0; index < Math.max(a.length, b.length); index += 1) {
|
|
58
|
+
if (a[index] === undefined) return -1;
|
|
59
|
+
if (b[index] === undefined) return 1;
|
|
60
|
+
if (a[index] === b[index]) continue;
|
|
61
|
+
const numeric = /^\d+$/u;
|
|
62
|
+
if (numeric.test(a[index]) && numeric.test(b[index])) {
|
|
63
|
+
return Number(a[index]) - Number(b[index]);
|
|
64
|
+
}
|
|
65
|
+
if (numeric.test(a[index])) return -1;
|
|
66
|
+
if (numeric.test(b[index])) return 1;
|
|
67
|
+
return a[index] < b[index] ? -1 : 1;
|
|
68
|
+
}
|
|
69
|
+
return 0;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Whether version `a` has lower semver precedence than `b`.
|
|
74
|
+
*
|
|
75
|
+
* Prerelease-aware on purpose: a project pinned to `4.66.5-rc.1` is BEHIND a
|
|
76
|
+
* published `4.66.5`, and comparing release fields alone would call it current.
|
|
77
|
+
* Build metadata is ignored, as semver requires.
|
|
78
|
+
* @param {string} a Candidate older version.
|
|
79
|
+
* @param {string} b Candidate newer version.
|
|
80
|
+
* @returns {boolean} True when `a` precedes `b`.
|
|
81
|
+
*/
|
|
82
|
+
export function precedes(a, b) {
|
|
83
|
+
const split = version => {
|
|
84
|
+
const [core, pre] = String(version).split("+")[0].split(/-(.*)/su);
|
|
85
|
+
const fields = core.split(".").map(field => Number(field) || 0);
|
|
86
|
+
return { fields, pre: pre ? pre.split(".") : [] };
|
|
87
|
+
};
|
|
88
|
+
const left = split(a);
|
|
89
|
+
const right = split(b);
|
|
90
|
+
for (let index = 0; index < 3; index += 1) {
|
|
91
|
+
const l = left.fields[index] ?? 0;
|
|
92
|
+
const r = right.fields[index] ?? 0;
|
|
93
|
+
if (l !== r) return l < r;
|
|
94
|
+
}
|
|
95
|
+
if (left.pre.length === 0) return false;
|
|
96
|
+
if (right.pre.length === 0) return true;
|
|
97
|
+
return comparePrerelease(left.pre, right.pre) < 0;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Parse a JSON file, or return null.
|
|
102
|
+
* @param {string} file Absolute path.
|
|
103
|
+
* @returns {any} Parsed JSON, or null when unreadable or malformed.
|
|
104
|
+
*/
|
|
105
|
+
function readJson(file) {
|
|
106
|
+
try {
|
|
107
|
+
return JSON.parse(readFileSync(file, "utf8"));
|
|
108
|
+
} catch {
|
|
109
|
+
return null;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* The update-check cache path for a project — the CLI's own path.
|
|
115
|
+
* @param {string} projectDir Project root.
|
|
116
|
+
* @returns {string} Absolute cache path.
|
|
117
|
+
*/
|
|
118
|
+
export function npmLatestCachePath(projectDir) {
|
|
119
|
+
return path.join(
|
|
120
|
+
projectDir,
|
|
121
|
+
"node_modules",
|
|
122
|
+
".cache",
|
|
123
|
+
"@codyswann",
|
|
124
|
+
"lisa",
|
|
125
|
+
"update-check.json"
|
|
126
|
+
);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* The Lisa version this project installed, or null when it has none to show.
|
|
131
|
+
*
|
|
132
|
+
* Null inside the Lisa monorepo itself: there `node_modules/@codyswann/lisa` is
|
|
133
|
+
* a fixture pinned majors behind the repository, and reporting it as the
|
|
134
|
+
* project's pin would tell every Lisa session its project is stale.
|
|
135
|
+
* @param {string} projectDir Project root.
|
|
136
|
+
* @returns {{version: string, source: string} | null} The installed copy.
|
|
137
|
+
*/
|
|
138
|
+
export function projectPin(projectDir) {
|
|
139
|
+
const own = readJson(path.join(projectDir, "package.json"));
|
|
140
|
+
if (own?.name === LISA_PACKAGE) return null;
|
|
141
|
+
const source = path.join(
|
|
142
|
+
projectDir,
|
|
143
|
+
"node_modules",
|
|
144
|
+
"@codyswann",
|
|
145
|
+
"lisa",
|
|
146
|
+
"package.json"
|
|
147
|
+
);
|
|
148
|
+
const version = readJson(source)?.version;
|
|
149
|
+
return typeof version === "string" && VERSION_SHAPE.test(version)
|
|
150
|
+
? { version, source }
|
|
151
|
+
: null;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Read the cached npm latest.
|
|
156
|
+
* @param {string} cachePath Absolute cache path.
|
|
157
|
+
* @param {number} nowMs Current time in ms.
|
|
158
|
+
* @param {number} [ttlMs] Freshness window.
|
|
159
|
+
* @returns {{version: string, fetchedAt: string, fresh: boolean} | null} Cached value.
|
|
160
|
+
*/
|
|
161
|
+
export function cachedNpmLatest(cachePath, nowMs, ttlMs = NPM_LATEST_TTL_MS) {
|
|
162
|
+
const cache = readJson(cachePath);
|
|
163
|
+
const version = cache?.latest;
|
|
164
|
+
const fetchedAt = cache?.fetchedAt;
|
|
165
|
+
if (typeof version !== "string" || !VERSION_SHAPE.test(version)) return null;
|
|
166
|
+
if (typeof fetchedAt !== "string") return null;
|
|
167
|
+
const fetchedMs = Date.parse(fetchedAt);
|
|
168
|
+
if (!Number.isFinite(fetchedMs)) return null;
|
|
169
|
+
return { version, fetchedAt, fresh: nowMs - fetchedMs <= ttlMs };
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Whether a refresh should be started for this session.
|
|
174
|
+
* @param {{version: string, fresh: boolean} | null} cached Cached value.
|
|
175
|
+
* @param {NodeJS.ProcessEnv} env Environment.
|
|
176
|
+
* @returns {boolean} True when the cache is missing or stale and checks are on.
|
|
177
|
+
*/
|
|
178
|
+
export function needsRefresh(cached, env) {
|
|
179
|
+
if (env.LISA_SKIP_UPDATE_CHECK === "1") return false;
|
|
180
|
+
return cached === null || !cached.fresh;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Start a detached refresh of the cache and return immediately.
|
|
185
|
+
* @param {string} script Absolute path of this module.
|
|
186
|
+
* @param {string} cachePath Absolute cache path.
|
|
187
|
+
* @param {typeof spawn} [spawnImpl] Injected for tests.
|
|
188
|
+
* @returns {boolean} Whether a child was started.
|
|
189
|
+
*/
|
|
190
|
+
export function startDetachedRefresh(script, cachePath, spawnImpl = spawn) {
|
|
191
|
+
try {
|
|
192
|
+
const child = spawnImpl(
|
|
193
|
+
process.execPath,
|
|
194
|
+
[script, "--refresh-npm-latest", cachePath],
|
|
195
|
+
{ detached: true, stdio: "ignore" }
|
|
196
|
+
);
|
|
197
|
+
child.on?.("error", () => {});
|
|
198
|
+
child.unref?.();
|
|
199
|
+
return true;
|
|
200
|
+
} catch {
|
|
201
|
+
return false;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Fetch npm latest and write it to the cache in the CLI's shape.
|
|
207
|
+
*
|
|
208
|
+
* probe-direction: neutral — a failed fetch writes nothing, so the next
|
|
209
|
+
* session reports "npm latest: unknown" (or the older cached value, labelled
|
|
210
|
+
* stale); no gate reads this value, it only shapes advisory context.
|
|
211
|
+
* @param {string} cachePath Absolute cache path.
|
|
212
|
+
* @param {{fetchImpl?: typeof fetch, now?: () => Date}} [deps] Injected for tests.
|
|
213
|
+
* @returns {Promise<string | null>} The version written, or null.
|
|
214
|
+
*/
|
|
215
|
+
export async function refreshNpmLatest(cachePath, deps = {}) {
|
|
216
|
+
const fetchImpl = deps.fetchImpl ?? globalThis.fetch;
|
|
217
|
+
const now = deps.now ?? (() => new Date());
|
|
218
|
+
try {
|
|
219
|
+
const response = await fetchImpl(NPM_LATEST_URL, {
|
|
220
|
+
signal: AbortSignal.timeout(REFRESH_TIMEOUT_MS),
|
|
221
|
+
});
|
|
222
|
+
if (!response.ok) return null;
|
|
223
|
+
const body = await response.json();
|
|
224
|
+
const version = body?.version;
|
|
225
|
+
if (typeof version !== "string" || !VERSION_SHAPE.test(version)) {
|
|
226
|
+
return null;
|
|
227
|
+
}
|
|
228
|
+
mkdirSync(path.dirname(cachePath), { recursive: true });
|
|
229
|
+
writeFileSync(
|
|
230
|
+
cachePath,
|
|
231
|
+
`${JSON.stringify({ latest: version, fetchedAt: now().toISOString() }, null, 2)}\n`,
|
|
232
|
+
"utf8"
|
|
233
|
+
);
|
|
234
|
+
return version;
|
|
235
|
+
} catch {
|
|
236
|
+
return null;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* Render the project and npm rows, plus the guidance when the project is behind.
|
|
242
|
+
* @param {{pin: {version: string, source: string} | null, latest: {version: string, fetchedAt: string, fresh: boolean} | null, refreshing: boolean, projectBehind: boolean}} state Resolved rows.
|
|
243
|
+
* @returns {{rows: string[], guidance: string[]}} Lines to splice into the block.
|
|
244
|
+
*/
|
|
245
|
+
export function renderNpmRows(state) {
|
|
246
|
+
const rows = [];
|
|
247
|
+
if (state.pin) {
|
|
248
|
+
rows.push(`project pin: lisa ${state.pin.version} at ${state.pin.source}`);
|
|
249
|
+
}
|
|
250
|
+
if (state.latest) {
|
|
251
|
+
rows.push(
|
|
252
|
+
`npm latest: lisa ${state.latest.version} (checked ${state.latest.fetchedAt}${state.latest.fresh ? "" : "; stale"}${state.refreshing ? ", refreshing for the next session" : ""})`
|
|
253
|
+
);
|
|
254
|
+
} else if (state.pin) {
|
|
255
|
+
rows.push(
|
|
256
|
+
`npm latest: unknown${state.refreshing ? " (checking in the background for the next session)" : ""}`
|
|
257
|
+
);
|
|
258
|
+
}
|
|
259
|
+
const guidance = state.projectBehind
|
|
260
|
+
? [
|
|
261
|
+
`PROJECT BEHIND — this project installs lisa ${state.pin?.version} while lisa ${state.latest?.version} is published.`,
|
|
262
|
+
"- Do NOT upgrade Lisa inside the current task: a version bump plus its template apply belongs in its own pull request, never mixed into feature work.",
|
|
263
|
+
"- Check for an open pull request on a `lisa/update-*` branch. If none is open, the project's Lisa Update workflow (`.github/workflows/lisa-update.yml`) opens one on its schedule; say so in your report, and if that workflow is missing, recommend running `lisa apply` once so the project receives it.",
|
|
264
|
+
]
|
|
265
|
+
: [];
|
|
266
|
+
return { rows, guidance };
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
/**
|
|
270
|
+
* Resolve everything the npm rows need, starting a refresh when warranted.
|
|
271
|
+
* @param {{projectDir: string, script?: string, env: NodeJS.ProcessEnv, nowMs: number, spawnImpl?: typeof spawn}} input Inputs.
|
|
272
|
+
* @returns {{pin: {version: string, source: string} | null, latest: {version: string, fetchedAt: string, fresh: boolean} | null, refreshing: boolean, projectBehind: boolean}} Resolved rows.
|
|
273
|
+
*/
|
|
274
|
+
export function resolveNpmState(input) {
|
|
275
|
+
try {
|
|
276
|
+
const pin = projectPin(input.projectDir);
|
|
277
|
+
if (pin === null) {
|
|
278
|
+
return { pin, latest: null, refreshing: false, projectBehind: false };
|
|
279
|
+
}
|
|
280
|
+
const cachePath = npmLatestCachePath(input.projectDir);
|
|
281
|
+
const latest = cachedNpmLatest(cachePath, input.nowMs);
|
|
282
|
+
const refreshing =
|
|
283
|
+
needsRefresh(latest, input.env) &&
|
|
284
|
+
startDetachedRefresh(
|
|
285
|
+
input.script ?? fileURLToPath(import.meta.url),
|
|
286
|
+
cachePath,
|
|
287
|
+
input.spawnImpl
|
|
288
|
+
);
|
|
289
|
+
const projectBehind = Boolean(
|
|
290
|
+
latest && precedes(pin.version, latest.version)
|
|
291
|
+
);
|
|
292
|
+
return { pin, latest, refreshing, projectBehind };
|
|
293
|
+
} catch {
|
|
294
|
+
return { pin: null, latest: null, refreshing: false, projectBehind: false };
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
/**
|
|
299
|
+
* Whether this module is the process entry point (the detached refresh child).
|
|
300
|
+
* Realpaths both sides for the reason `enforcement-vintage.mjs` gives.
|
|
301
|
+
* @param {string} moduleUrl This module's `import.meta.url`.
|
|
302
|
+
* @param {string | undefined} [argv1] Entry path.
|
|
303
|
+
* @returns {boolean} True when run directly.
|
|
304
|
+
*/
|
|
305
|
+
function invokedDirectly(moduleUrl, argv1 = process.argv[1]) {
|
|
306
|
+
if (!argv1) return false;
|
|
307
|
+
try {
|
|
308
|
+
return realpathSync(argv1) === realpathSync(fileURLToPath(moduleUrl));
|
|
309
|
+
} catch {
|
|
310
|
+
return false;
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
if (
|
|
315
|
+
invokedDirectly(import.meta.url) &&
|
|
316
|
+
process.argv[2] === "--refresh-npm-latest" &&
|
|
317
|
+
process.argv[3]
|
|
318
|
+
) {
|
|
319
|
+
refreshNpmLatest(process.argv[3]).catch(() => {});
|
|
320
|
+
}
|
|
@@ -52,6 +52,7 @@ import { readFileSync, existsSync } from "fs";
|
|
|
52
52
|
import path from "path";
|
|
53
53
|
import { fileURLToPath } from "url";
|
|
54
54
|
import { realpathSync } from "fs";
|
|
55
|
+
import { renderNpmRows, resolveNpmState } from "./enforcement-vintage-npm.mjs";
|
|
55
56
|
|
|
56
57
|
/** Marker the block is wrapped in, so an agent can cite it by name. */
|
|
57
58
|
const BLOCK_TAG = "lisa-enforcement-vintage";
|
|
@@ -336,6 +337,15 @@ export function renderBlock(state) {
|
|
|
336
337
|
`newest on this disk: lisa ${state.newest.version} at ${state.newest.source}`
|
|
337
338
|
);
|
|
338
339
|
}
|
|
340
|
+
const npm = renderNpmRows(
|
|
341
|
+
state.npm ?? {
|
|
342
|
+
pin: null,
|
|
343
|
+
latest: null,
|
|
344
|
+
refreshing: false,
|
|
345
|
+
projectBehind: false,
|
|
346
|
+
}
|
|
347
|
+
);
|
|
348
|
+
npm.rows.forEach(row => lines.push(row));
|
|
339
349
|
lines.push("");
|
|
340
350
|
if (state.behind || !state.running.version || state.treeBehind) {
|
|
341
351
|
lines.push(
|
|
@@ -363,6 +373,10 @@ export function renderBlock(state) {
|
|
|
363
373
|
"when you report on guard or contract behaviour; it is only current until the next release."
|
|
364
374
|
);
|
|
365
375
|
}
|
|
376
|
+
if (npm.guidance.length > 0) {
|
|
377
|
+
lines.push("");
|
|
378
|
+
npm.guidance.forEach(line => lines.push(line));
|
|
379
|
+
}
|
|
366
380
|
lines.push(`</${BLOCK_TAG}>`);
|
|
367
381
|
return lines.join("\n");
|
|
368
382
|
}
|
|
@@ -405,9 +419,14 @@ export function run(argv, stdin, env = process.env) {
|
|
|
405
419
|
return JSON.stringify({
|
|
406
420
|
hookSpecificOutput: {
|
|
407
421
|
hookEventName: eventName(stdin),
|
|
408
|
-
additionalContext: renderBlock(
|
|
409
|
-
resolveState({ hooksDir, projectDir, configDir })
|
|
410
|
-
|
|
422
|
+
additionalContext: renderBlock({
|
|
423
|
+
...resolveState({ hooksDir, projectDir, configDir }),
|
|
424
|
+
npm: resolveNpmState({
|
|
425
|
+
projectDir,
|
|
426
|
+
env,
|
|
427
|
+
nowMs: Date.now(),
|
|
428
|
+
}),
|
|
429
|
+
}),
|
|
411
430
|
},
|
|
412
431
|
});
|
|
413
432
|
}
|
|
@@ -367,6 +367,7 @@ Substrate column meanings (ordering per `credential-substrate-precedence`):
|
|
|
367
367
|
| `transition key:<K> to:<S>` | guarded fallback only: `acli jira workitem transition --key <K> --status "<S>" --yes` + post-read tenant assertion | `mcp__plugin_atlassian_atlassian__transitionJiraIssue` | resolve transition id then `POST https://api.atlassian.com/ex/jira/<CLOUDID>/rest/api/3/issue/<K>/transitions` |
|
|
368
368
|
| `transitions key:<K>` — **false friend:** available transitions from current status, **NOT** past history; for history use `changelog` | (not exposed) | `mcp__plugin_atlassian_atlassian__getTransitionsForJiraIssue` | `GET https://<SITE>/rest/api/3/issue/<K>/transitions` |
|
|
369
369
|
| `changelog key:<K>` (read; ordered past status transitions) | (not exposed) | (not exposed) | `GET https://<SITE>/rest/api/3/issue/<K>?expand=changelog` |
|
|
370
|
+
| `comments key:<K>` (read; all comments, paginated) — **not** `comment`, which is the write | (not exposed) | `mcp__plugin_atlassian_atlassian__getJiraIssue` (comment field only; may be capped — page via curl when `total` exceeds what it returned) | `GET https://<SITE>/rest/api/3/issue/<K>/comment?startAt=<n>&maxResults=100&orderBy=created` |
|
|
370
371
|
| `comment key:<K> body:<B>` | guarded fallback only: `acli jira workitem comment add --key <K> --body "<B>"` + post-read tenant assertion | `mcp__plugin_atlassian_atlassian__addCommentToJiraIssue` | `POST https://api.atlassian.com/ex/jira/<CLOUDID>/rest/api/3/issue/<K>/comment` |
|
|
371
372
|
| `link from:<K> to:<K2> type:<T>` | guarded fallback only: `acli jira workitem link create --in <K> --out <K2> --type "<T>" --yes` + direction and tenant assertion (see direction note) | `mcp__plugin_atlassian_atlassian__createJiraIssueLink` | `POST https://api.atlassian.com/ex/jira/<CLOUDID>/rest/api/3/issueLink` |
|
|
372
373
|
| `remote-links key:<K>` | (not exposed) | `mcp__plugin_atlassian_atlassian__getJiraIssueRemoteIssueLinks` | `GET https://<SITE>/rest/api/3/issue/<K>/remotelink` |
|
|
@@ -423,6 +424,17 @@ Operations not in this table are unsupported — add an adapter row before using
|
|
|
423
424
|
- **Pagination / truncation.** The issue-resource changelog (`?expand=changelog`) truncates busy issues (`changelog.maxResults`/`total`/`startAt`). When `total` exceeds what the issue resource returned, page the dedicated endpoint `GET https://<SITE>/rest/api/3/issue/<K>/changelog?startAt=<n>` until `startAt + maxResults >= total`, preserving order across pages. A silently truncated history is a correctness bug for detection.
|
|
424
425
|
- **Graceful degrade — never block the build.** A failed changelog fetch (network, auth, missing substrate) returns the substrate contract's `Error:` result. Callers MUST treat that as **unknown** history and proceed — a history read failure never blocks the build.
|
|
425
426
|
|
|
427
|
+
### `comments` — every comment on one issue
|
|
428
|
+
|
|
429
|
+
`comments key:<K>` returns every comment on a JIRA issue, oldest first. `read-ticket` embeds only the first page of comments in the issue resource (`fields.comment` carries its own `startAt`/`maxResults`/`total`), so a busy ticket's later comments — often the decisions and constraints — are missing from it.
|
|
430
|
+
|
|
431
|
+
- **Substrate.** JIRA REST `GET https://<SITE>/rest/api/3/issue/<K>/comment?startAt=<n>&maxResults=100&orderBy=created` (a read, so the `<SITE>` gateway is allowed after the token account check). acli exposes no paginated comment list; the MCP `getJiraIssue` comment field is used only when no token is available and is subject to the same first-page cap.
|
|
432
|
+
- **Shape.** For each entry in `comments[]` emit `{ id, author, created, body }` — `author.displayName`/`accountId`, `created` (ISO timestamp), and `body` converted from ADF to plain text with headings, lists, code, and links preserved.
|
|
433
|
+
- **Pagination.** Start at `startAt=0` and request the next page until `startAt + maxResults >= total`, preserving order across pages. Never stop at the first page.
|
|
434
|
+
- **Empty is valid.** An issue with no comments returns `total: 0`; that is a result, not an error.
|
|
435
|
+
- **Completeness fields.** Every result carries `comments_complete`, `comments_fetched`, and `comments_total`; `comments_complete: true` only when `comments_fetched == comments_total`. When only the MCP substrate is available and it cannot page past its first batch, return what it gave with `comments_complete: false` and the fetched-versus-total counts — never present a capped set as the whole.
|
|
436
|
+
- **Graceful degrade.** A failed page (network, auth, missing substrate) returns the substrate contract's `Error:` result for that page. Callers record the issue's comments as **incomplete** — naming how many of `total` were read — so a partial set is never silently truncated into looking complete.
|
|
437
|
+
|
|
426
438
|
### Step 4 — Return result
|
|
427
439
|
|
|
428
440
|
Emit either:
|
|
@@ -18,10 +18,10 @@ Create conventional commits for current changes. Optional hint: $ARGUMENTS
|
|
|
18
18
|
### Apply these requirements
|
|
19
19
|
|
|
20
20
|
1. **Branch Check**: If on `dev`, `staging`, or `main`, create a feature branch named after the changes
|
|
21
|
-
2. **Commit Strategy**: Group related changes into logical conventional commits (feat, fix, chore, docs, etc.)
|
|
22
|
-
3. **Commit ALL Files**: Every file must be assigned to a commit group - no file gets left out or unstaged
|
|
21
|
+
2. **Commit Strategy**: Group related changes into logical conventional commits (feat, fix, chore, docs, etc.). Every rule below that says "all" or "everything" excludes the local-only `.lisa/work-item-context.md` described in rule 3.
|
|
22
|
+
3. **Commit ALL Files**: Every file must be assigned to a commit group - no file gets left out or unstaged. **Local-only exception:** never stage `.lisa/work-item-context.md`, or any other file the work-item context contract marks local-only, even when it is untracked and not ignored — it can quote credentials from tracker comments. Leave it untracked, and say in your report that it was left out and why.
|
|
23
23
|
4. **Commit Creation**: Stage and commit each group with clear messages
|
|
24
|
-
5. **Verification**: Run `git status` to confirm working directory is clean - must show "nothing to commit"
|
|
24
|
+
5. **Verification**: Run `git status` to confirm working directory is clean - must show "nothing to commit" (apart from a local-only file left untracked under rule 3)
|
|
25
25
|
|
|
26
26
|
### Use conventional commit format
|
|
27
27
|
|
|
@@ -43,10 +43,10 @@ the original authored line may remain in the message.
|
|
|
43
43
|
- use `--no-verify` flag
|
|
44
44
|
- attempt to bypass tests or quality checks
|
|
45
45
|
- skip tests or quality checks
|
|
46
|
-
- stash changes - ALL changes must be committed
|
|
47
|
-
- skip or exclude any files from the commit - even if they're unrelated
|
|
48
|
-
- leave uncommitted changes in the working directory
|
|
49
|
-
- ask the user which files to commit - commit everything
|
|
46
|
+
- stash changes - ALL changes must be committed, except the local-only `.lisa/work-item-context.md`
|
|
47
|
+
- skip or exclude any files from the commit - even if they're unrelated (the local-only `.lisa/work-item-context.md` is the one exclusion, and it is mandatory)
|
|
48
|
+
- leave uncommitted changes in the working directory, other than the local-only `.lisa/work-item-context.md`
|
|
49
|
+
- ask the user which files to commit - commit everything except the local-only `.lisa/work-item-context.md`
|
|
50
50
|
|
|
51
51
|
## Execute
|
|
52
52
|
|
|
@@ -27,7 +27,7 @@ Recognized optional hints:
|
|
|
27
27
|
### Apply these requirements
|
|
28
28
|
|
|
29
29
|
1. **Branch Check**: Verify not on `dev`, `staging`, or `main` (cannot create PR from protected branches)
|
|
30
|
-
2. **Commit Check**: Ensure all changes are committed before pushing
|
|
30
|
+
2. **Commit Check**: Ensure all changes are committed before pushing — except the local-only `.lisa/work-item-context.md`, which is never staged even when untracked and not ignored; an untracked copy of it does not fail this check.
|
|
31
31
|
2a. **Local review before push**: Unless `local_review=done` has current evidence, run `lisa-review-local` over the branch diff, address findings through `convergent-review`, and commit any fixes before step 3. This applies regardless of third-party reviewer availability. Reuse an applicable completed review instead of repeating it.
|
|
32
32
|
|
|
33
33
|
Report the result as *self-reviewed*; it does not satisfy the ruleset-required third-party review check. If the runtime cannot delegate review, record **local review unavailable**, continue under the existing merge policy, and do not pass `local_review=done`. An unavailable review is not a passing review.
|
|
@@ -517,7 +517,7 @@ After the claim succeeds, run the per-issue lifecycle defined by the `github-age
|
|
|
517
517
|
- `lisa-github-verify` — pre-flight quality gate, including the draft-then-block procedure on FAIL
|
|
518
518
|
- `lisa-ticket-triage` — analytical triage gate (a `BLOCKED` verdict stops the cycle with findings posted)
|
|
519
519
|
- Intent determination from the `type:` label
|
|
520
|
-
2. **Dispatch the flow in-session:** when the gates pass, invoke the lifecycle skill via the Skill tool — `lisa-implement <org>/<repo>#<number>` for Build / Fix / Improve / Investigate-Only (or `lisa-plan` for an Epic) — passing the full context bundle from the read step. **When 3b classified this item `rejection-reclaim`, the context bundle passed to `lisa-implement` MUST include the rejection evidence summary** (what was rejected, the defect the QA comment named, the approach named as wrong) — reuse the evidence already read in 3b, do not fetch it twice — so the plan can address it per `rejection-detection`; absence of evidence never blocks. `lisa-implement`'s own orchestration preamble then creates the per-item agent team (input-resolver, Roster Decision, specialist fanout) exactly as a direct invocation would.
|
|
520
|
+
2. **Dispatch the flow in-session:** when the gates pass, invoke the lifecycle skill via the Skill tool — `lisa-implement <org>/<repo>#<number>` for Build / Fix / Improve / Investigate-Only (or `lisa-plan` for an Epic) — passing the full context bundle from the read step. Hand that bundle over by file, not by text: before invoking `lisa-implement`, run the ignore guard below, then write the bundle verbatim to persist it at the git-ignored `.lisa/work-item-context.md` of this worktree — always overwriting the file with this cycle's bundle, never reusing one an earlier item left behind — and pass only `caller_bundle_path=<absolute path>` in the invocation. `lisa-implement`'s input-resolver keeps that file as the base instead of re-summarizing it, so every comment reaches the agents doing the work. Bundle text, and any credential value in it, never appears in a spawn prompt, task description, or Skill argument — only its path. **Ignore guard before any write.** A host can receive these skills before its shipped `.gitignore` entry, so prove the path is ignored first, from the worktree root: `git check-ignore -q .lisa/work-item-context.md || printf '%s\n' '.lisa/work-item-context.md' >> "$(git rev-parse --git-common-dir)/info/exclude"`, then re-run `git check-ignore -q .lisa/work-item-context.md`. If it is still not ignored, stop and report — do not write the bundle. If an `.easignore` exists and `grep -qxF '.lisa/work-item-context.md' .easignore` fails, stop and report instead of writing: EAS uploads read `.easignore`, which is derived from `.gitignore`, not from `info/exclude`. **When 3b classified this item `rejection-reclaim`, the context bundle passed to `lisa-implement` MUST include the rejection evidence summary** (what was rejected, the defect the QA comment named, the approach named as wrong) — reuse the evidence already read in 3b, do not fetch it twice — so the plan can address it per `rejection-detection`; absence of evidence never blocks. `lisa-implement`'s own orchestration preamble then creates the per-item agent team (input-resolver, Roster Decision, specialist fanout) exactly as a direct invocation would.
|
|
521
521
|
3. **Milestone sync and evidence** (`lisa-github-sync`, `lisa-github-evidence`) happen at the milestones the `github-agent` workflow defines, within the dispatched flow.
|
|
522
522
|
|
|
523
523
|
If you are somehow running this skill as a spawned teammate inside an existing team (nested misrouting — Intake keeps this chain in the lead session), do NOT run the lifecycle inline and do NOT spawn named peers. Return this payload to the lead so the lead session can run this Phase 3c in-session:
|