@codyswann/lisa 2.350.0 → 2.352.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-overwrite/scripts/lisa-hooks/block-instruction-file-edits.sh +1 -1
- package/all/copy-overwrite/scripts/lisa-hooks/block-shell-json-parsing.sh +1 -1
- package/all/create-only/.agents/rules/README.md +45 -0
- package/dist/cli/doctor-lisa-owned-artifacts.d.ts +18 -0
- package/dist/cli/doctor-lisa-owned-artifacts.d.ts.map +1 -0
- package/dist/cli/doctor-lisa-owned-artifacts.js +129 -0
- package/dist/cli/doctor-lisa-owned-artifacts.js.map +1 -0
- package/dist/cli/doctor.d.ts.map +1 -1
- package/dist/cli/doctor.js +2 -0
- package/dist/cli/doctor.js.map +1 -1
- package/dist/codex/scripts/_extract-edit-paths.sh +1 -1
- package/dist/codex/scripts/format-on-edit.sh +1 -1
- package/dist/codex/scripts/lint-on-edit.sh +1 -1
- package/dist/codex/scripts/rubocop-on-edit.sh +1 -1
- package/dist/codex/scripts/sg-scan-on-edit.sh +1 -1
- package/dist/configs/eslint/cdk.js +2 -2
- package/dist/configs/eslint/cdk.js.map +1 -1
- package/dist/configs/eslint/nestjs.js +2 -2
- package/dist/configs/eslint/nestjs.js.map +1 -1
- package/dist/configs/eslint/typescript.js +2 -2
- package/dist/configs/eslint/typescript.js.map +1 -1
- package/dist/core/host-rules-pointer.d.ts +33 -0
- package/dist/core/host-rules-pointer.d.ts.map +1 -0
- package/dist/core/host-rules-pointer.js +115 -0
- package/dist/core/host-rules-pointer.js.map +1 -0
- package/dist/core/instruction-files-migration.d.ts +3 -2
- package/dist/core/instruction-files-migration.d.ts.map +1 -1
- package/dist/core/instruction-files-migration.js +62 -64
- package/dist/core/instruction-files-migration.js.map +1 -1
- package/dist/core/learnings.d.ts +1 -1
- package/dist/core/learnings.d.ts.map +1 -1
- package/dist/core/learnings.js +1 -1
- package/dist/core/learnings.js.map +1 -1
- package/dist/core/lisa-owned-templates.d.ts +34 -0
- package/dist/core/lisa-owned-templates.d.ts.map +1 -0
- package/dist/core/lisa-owned-templates.js +41 -0
- package/dist/core/lisa-owned-templates.js.map +1 -0
- package/dist/core/lisa.d.ts.map +1 -1
- package/dist/core/lisa.js +5 -1
- package/dist/core/lisa.js.map +1 -1
- package/dist/core/project-config.d.ts +39 -9
- package/dist/core/project-config.d.ts.map +1 -1
- package/dist/core/project-config.js +37 -10
- package/dist/core/project-config.js.map +1 -1
- package/dist/core/upstream-evidence-manifest.d.ts.map +1 -1
- package/dist/core/upstream-evidence-manifest.js +73 -37
- package/dist/core/upstream-evidence-manifest.js.map +1 -1
- package/dist/opencode/plugin-templates/lisa-block-instruction-file-edits.ts +1 -1
- package/dist/strategies/copy-overwrite.d.ts +13 -6
- package/dist/strategies/copy-overwrite.d.ts.map +1 -1
- package/dist/strategies/copy-overwrite.js +16 -7
- package/dist/strategies/copy-overwrite.js.map +1 -1
- package/dist/sync/registry.d.ts.map +1 -1
- package/dist/sync/registry.js +0 -6
- package/dist/sync/registry.js.map +1 -1
- package/package.json +1 -1
- package/plugins/lisa/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa/.codex-plugin/skills/lisa-debrief/SKILL.md +1 -1
- package/plugins/lisa/.codex-plugin/skills/lisa-debrief-apply/SKILL.md +3 -3
- package/plugins/lisa/.codex-plugin/skills/lisa-doctor/SKILL.md +4 -1
- package/plugins/lisa/.codex-plugin/skills/lisa-github-read-issue/SKILL.md +1 -0
- package/plugins/lisa/.codex-plugin/skills/lisa-github-validate-issue/SKILL.md +22 -0
- package/plugins/lisa/.codex-plugin/skills/lisa-github-write-issue/SKILL.md +15 -0
- package/plugins/lisa/.codex-plugin/skills/lisa-implement/SKILL.md +6 -0
- package/plugins/lisa/.codex-plugin/skills/lisa-improve-harness/SKILL.md +2 -2
- package/plugins/lisa/.codex-plugin/skills/lisa-jira-validate-ticket/SKILL.md +22 -0
- package/plugins/lisa/.codex-plugin/skills/lisa-jira-write-ticket/SKILL.md +15 -0
- package/plugins/lisa/.codex-plugin/skills/lisa-learnings-audit/SKILL.md +6 -3
- package/plugins/lisa/.codex-plugin/skills/lisa-linear-access/SKILL.md +25 -3
- package/plugins/lisa/.codex-plugin/skills/lisa-linear-validate-issue/SKILL.md +22 -0
- package/plugins/lisa/.codex-plugin/skills/lisa-linear-write-issue/SKILL.md +15 -0
- package/plugins/lisa/.codex-plugin/skills/lisa-secrets-access/SKILL.md +20 -2
- package/plugins/lisa/.codex-plugin/skills/lisa-secrets-access/scripts/doctor-secrets.mjs +13 -9
- package/plugins/lisa/.codex-plugin/skills/lisa-secrets-access/scripts/note-format.mjs +179 -0
- package/plugins/lisa/.codex-plugin/skills/lisa-secrets-access/scripts/resolve-secret.mjs +32 -6
- package/plugins/lisa/.codex-plugin/skills/lisa-secrets-access/scripts/tools-from-notes.mjs +6 -2
- package/plugins/lisa/.codex-plugin/skills/lisa-setup-atlassian/SKILL.md +17 -0
- package/plugins/lisa/.codex-plugin/skills/lisa-setup-linear/SKILL.md +17 -0
- package/plugins/lisa/.codex-plugin/skills/lisa-setup-notion/SKILL.md +17 -0
- package/plugins/lisa/agents/learnings-synthesizer.md +1 -1
- package/plugins/lisa/agents/skill-evaluator.md +1 -1
- package/plugins/lisa/hooks/block-instruction-file-edits.sh +1 -1
- package/plugins/lisa/hooks/block-shell-json-parsing.sh +1 -1
- package/plugins/lisa/rules/eager/config-resolution.md +6 -3
- package/plugins/lisa/rules/eager/derived-branch-plan.md +45 -0
- package/plugins/lisa/rules/eager/project-learnings.md +3 -2
- package/plugins/lisa/rules/reference/config-resolution.md +26 -2
- package/plugins/lisa/rules/reference/derived-branch-plan.md +112 -0
- package/plugins/lisa/rules/reference/intent-routing.md +1 -1
- package/plugins/lisa/rules/reference/project-learnings.md +6 -4
- package/plugins/lisa/rules/reference/promotion-contract.md +2 -1
- package/plugins/lisa/skills/lisa-debrief/SKILL.md +1 -1
- package/plugins/lisa/skills/lisa-debrief-apply/SKILL.md +3 -3
- package/plugins/lisa/skills/lisa-doctor/SKILL.md +4 -1
- package/plugins/lisa/skills/lisa-github-read-issue/SKILL.md +1 -0
- package/plugins/lisa/skills/lisa-github-validate-issue/SKILL.md +22 -0
- package/plugins/lisa/skills/lisa-github-write-issue/SKILL.md +15 -0
- package/plugins/lisa/skills/lisa-implement/SKILL.md +6 -0
- package/plugins/lisa/skills/lisa-improve-harness/SKILL.md +2 -2
- package/plugins/lisa/skills/lisa-jira-validate-ticket/SKILL.md +22 -0
- package/plugins/lisa/skills/lisa-jira-write-ticket/SKILL.md +15 -0
- package/plugins/lisa/skills/lisa-learnings-audit/SKILL.md +6 -3
- package/plugins/lisa/skills/lisa-linear-access/SKILL.md +25 -3
- package/plugins/lisa/skills/lisa-linear-validate-issue/SKILL.md +22 -0
- package/plugins/lisa/skills/lisa-linear-write-issue/SKILL.md +15 -0
- package/plugins/lisa/skills/lisa-secrets-access/SKILL.md +20 -2
- package/plugins/lisa/skills/lisa-secrets-access/scripts/doctor-secrets.mjs +13 -9
- package/plugins/lisa/skills/lisa-secrets-access/scripts/note-format.mjs +179 -0
- package/plugins/lisa/skills/lisa-secrets-access/scripts/resolve-secret.mjs +32 -6
- package/plugins/lisa/skills/lisa-secrets-access/scripts/tools-from-notes.mjs +6 -2
- package/plugins/lisa/skills/lisa-setup-atlassian/SKILL.md +17 -0
- package/plugins/lisa/skills/lisa-setup-linear/SKILL.md +17 -0
- package/plugins/lisa/skills/lisa-setup-notion/SKILL.md +17 -0
- package/plugins/lisa-agy/agents/learnings-synthesizer.md +1 -1
- package/plugins/lisa-agy/agents/skill-evaluator.md +1 -1
- package/plugins/lisa-agy/hooks/block-instruction-file-edits.sh +1 -1
- package/plugins/lisa-agy/hooks/block-shell-json-parsing.sh +1 -1
- package/plugins/lisa-agy/plugin.json +1 -1
- package/plugins/lisa-agy/skills/lisa-debrief/SKILL.md +1 -1
- package/plugins/lisa-agy/skills/lisa-debrief-apply/SKILL.md +3 -3
- package/plugins/lisa-agy/skills/lisa-doctor/SKILL.md +4 -1
- package/plugins/lisa-agy/skills/lisa-github-read-issue/SKILL.md +1 -0
- package/plugins/lisa-agy/skills/lisa-github-validate-issue/SKILL.md +22 -0
- package/plugins/lisa-agy/skills/lisa-github-write-issue/SKILL.md +15 -0
- package/plugins/lisa-agy/skills/lisa-implement/SKILL.md +6 -0
- package/plugins/lisa-agy/skills/lisa-improve-harness/SKILL.md +2 -2
- package/plugins/lisa-agy/skills/lisa-jira-validate-ticket/SKILL.md +22 -0
- package/plugins/lisa-agy/skills/lisa-jira-write-ticket/SKILL.md +15 -0
- package/plugins/lisa-agy/skills/lisa-learnings-audit/SKILL.md +6 -3
- package/plugins/lisa-agy/skills/lisa-linear-access/SKILL.md +25 -3
- package/plugins/lisa-agy/skills/lisa-linear-validate-issue/SKILL.md +22 -0
- package/plugins/lisa-agy/skills/lisa-linear-write-issue/SKILL.md +15 -0
- package/plugins/lisa-agy/skills/lisa-secrets-access/SKILL.md +20 -2
- package/plugins/lisa-agy/skills/lisa-secrets-access/scripts/doctor-secrets.mjs +13 -9
- package/plugins/lisa-agy/skills/lisa-secrets-access/scripts/note-format.mjs +179 -0
- package/plugins/lisa-agy/skills/lisa-secrets-access/scripts/resolve-secret.mjs +32 -6
- package/plugins/lisa-agy/skills/lisa-secrets-access/scripts/tools-from-notes.mjs +6 -2
- package/plugins/lisa-agy/skills/lisa-setup-atlassian/SKILL.md +17 -0
- package/plugins/lisa-agy/skills/lisa-setup-linear/SKILL.md +17 -0
- package/plugins/lisa-agy/skills/lisa-setup-notion/SKILL.md +17 -0
- 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/learnings-synthesizer.agent.md +1 -1
- package/plugins/lisa-copilot/agents/skill-evaluator.agent.md +1 -1
- package/plugins/lisa-copilot/hooks/block-instruction-file-edits.sh +1 -1
- package/plugins/lisa-copilot/hooks/block-shell-json-parsing.sh +1 -1
- package/plugins/lisa-copilot/rules/eager/config-resolution.md +6 -3
- package/plugins/lisa-copilot/rules/eager/derived-branch-plan.md +45 -0
- package/plugins/lisa-copilot/rules/eager/project-learnings.md +3 -2
- package/plugins/lisa-copilot/rules/reference/config-resolution.md +26 -2
- package/plugins/lisa-copilot/rules/reference/derived-branch-plan.md +112 -0
- package/plugins/lisa-copilot/rules/reference/intent-routing.md +1 -1
- package/plugins/lisa-copilot/rules/reference/project-learnings.md +6 -4
- package/plugins/lisa-copilot/rules/reference/promotion-contract.md +2 -1
- package/plugins/lisa-copilot/skills/lisa-debrief/SKILL.md +1 -1
- package/plugins/lisa-copilot/skills/lisa-debrief-apply/SKILL.md +3 -3
- package/plugins/lisa-copilot/skills/lisa-doctor/SKILL.md +4 -1
- package/plugins/lisa-copilot/skills/lisa-github-read-issue/SKILL.md +1 -0
- package/plugins/lisa-copilot/skills/lisa-github-validate-issue/SKILL.md +22 -0
- package/plugins/lisa-copilot/skills/lisa-github-write-issue/SKILL.md +15 -0
- package/plugins/lisa-copilot/skills/lisa-implement/SKILL.md +6 -0
- package/plugins/lisa-copilot/skills/lisa-improve-harness/SKILL.md +2 -2
- package/plugins/lisa-copilot/skills/lisa-jira-validate-ticket/SKILL.md +22 -0
- package/plugins/lisa-copilot/skills/lisa-jira-write-ticket/SKILL.md +15 -0
- package/plugins/lisa-copilot/skills/lisa-learnings-audit/SKILL.md +6 -3
- package/plugins/lisa-copilot/skills/lisa-linear-access/SKILL.md +25 -3
- package/plugins/lisa-copilot/skills/lisa-linear-validate-issue/SKILL.md +22 -0
- package/plugins/lisa-copilot/skills/lisa-linear-write-issue/SKILL.md +15 -0
- package/plugins/lisa-copilot/skills/lisa-secrets-access/SKILL.md +20 -2
- package/plugins/lisa-copilot/skills/lisa-secrets-access/scripts/doctor-secrets.mjs +13 -9
- package/plugins/lisa-copilot/skills/lisa-secrets-access/scripts/note-format.mjs +179 -0
- package/plugins/lisa-copilot/skills/lisa-secrets-access/scripts/resolve-secret.mjs +32 -6
- package/plugins/lisa-copilot/skills/lisa-secrets-access/scripts/tools-from-notes.mjs +6 -2
- package/plugins/lisa-copilot/skills/lisa-setup-atlassian/SKILL.md +17 -0
- package/plugins/lisa-copilot/skills/lisa-setup-linear/SKILL.md +17 -0
- package/plugins/lisa-copilot/skills/lisa-setup-notion/SKILL.md +17 -0
- package/plugins/lisa-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cursor/agents/learnings-synthesizer.md +1 -1
- package/plugins/lisa-cursor/agents/skill-evaluator.md +1 -1
- package/plugins/lisa-cursor/hooks/block-instruction-file-edits.sh +1 -1
- package/plugins/lisa-cursor/hooks/block-shell-json-parsing.sh +1 -1
- package/plugins/lisa-cursor/rules/config-resolution-reference.mdc +26 -2
- package/plugins/lisa-cursor/rules/config-resolution.mdc +6 -3
- package/plugins/lisa-cursor/rules/derived-branch-plan-reference.mdc +117 -0
- package/plugins/lisa-cursor/rules/derived-branch-plan.mdc +50 -0
- package/plugins/lisa-cursor/rules/intent-routing-reference.mdc +1 -1
- package/plugins/lisa-cursor/rules/project-learnings-reference.mdc +6 -4
- package/plugins/lisa-cursor/rules/project-learnings.mdc +3 -2
- package/plugins/lisa-cursor/rules/promotion-contract-reference.mdc +2 -1
- package/plugins/lisa-cursor/skills/lisa-debrief/SKILL.md +1 -1
- package/plugins/lisa-cursor/skills/lisa-debrief-apply/SKILL.md +3 -3
- package/plugins/lisa-cursor/skills/lisa-doctor/SKILL.md +4 -1
- package/plugins/lisa-cursor/skills/lisa-github-read-issue/SKILL.md +1 -0
- package/plugins/lisa-cursor/skills/lisa-github-validate-issue/SKILL.md +22 -0
- package/plugins/lisa-cursor/skills/lisa-github-write-issue/SKILL.md +15 -0
- package/plugins/lisa-cursor/skills/lisa-implement/SKILL.md +6 -0
- package/plugins/lisa-cursor/skills/lisa-improve-harness/SKILL.md +2 -2
- package/plugins/lisa-cursor/skills/lisa-jira-validate-ticket/SKILL.md +22 -0
- package/plugins/lisa-cursor/skills/lisa-jira-write-ticket/SKILL.md +15 -0
- package/plugins/lisa-cursor/skills/lisa-learnings-audit/SKILL.md +6 -3
- package/plugins/lisa-cursor/skills/lisa-linear-access/SKILL.md +25 -3
- package/plugins/lisa-cursor/skills/lisa-linear-validate-issue/SKILL.md +22 -0
- package/plugins/lisa-cursor/skills/lisa-linear-write-issue/SKILL.md +15 -0
- package/plugins/lisa-cursor/skills/lisa-secrets-access/SKILL.md +20 -2
- package/plugins/lisa-cursor/skills/lisa-secrets-access/scripts/doctor-secrets.mjs +13 -9
- package/plugins/lisa-cursor/skills/lisa-secrets-access/scripts/note-format.mjs +179 -0
- package/plugins/lisa-cursor/skills/lisa-secrets-access/scripts/resolve-secret.mjs +32 -6
- package/plugins/lisa-cursor/skills/lisa-secrets-access/scripts/tools-from-notes.mjs +6 -2
- package/plugins/lisa-cursor/skills/lisa-setup-atlassian/SKILL.md +17 -0
- package/plugins/lisa-cursor/skills/lisa-setup-linear/SKILL.md +17 -0
- package/plugins/lisa-cursor/skills/lisa-setup-notion/SKILL.md +17 -0
- 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/hooks/block-suppress-directives.sh +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-copilot/hooks/block-suppress-directives.sh +1 -1
- package/plugins/lisa-typescript-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript-cursor/hooks/block-suppress-directives.sh +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/learnings-synthesizer.md +1 -1
- package/plugins/src/base/agents/skill-evaluator.md +1 -1
- package/plugins/src/base/hooks/block-instruction-file-edits.sh +1 -1
- package/plugins/src/base/hooks/block-shell-json-parsing.sh +1 -1
- package/plugins/src/base/rules/eager/config-resolution.md +6 -3
- package/plugins/src/base/rules/eager/derived-branch-plan.md +45 -0
- package/plugins/src/base/rules/eager/project-learnings.md +3 -2
- package/plugins/src/base/rules/reference/config-resolution.md +26 -2
- package/plugins/src/base/rules/reference/derived-branch-plan.md +112 -0
- package/plugins/src/base/rules/reference/intent-routing.md +1 -1
- package/plugins/src/base/rules/reference/project-learnings.md +6 -4
- package/plugins/src/base/rules/reference/promotion-contract.md +2 -1
- package/plugins/src/base/skills/lisa-debrief/SKILL.md +1 -1
- package/plugins/src/base/skills/lisa-debrief-apply/SKILL.md +3 -3
- package/plugins/src/base/skills/lisa-doctor/SKILL.md +4 -1
- package/plugins/src/base/skills/lisa-github-read-issue/SKILL.md +1 -0
- package/plugins/src/base/skills/lisa-github-validate-issue/SKILL.md +22 -0
- package/plugins/src/base/skills/lisa-github-write-issue/SKILL.md +15 -0
- package/plugins/src/base/skills/lisa-implement/SKILL.md +6 -0
- package/plugins/src/base/skills/lisa-improve-harness/SKILL.md +2 -2
- package/plugins/src/base/skills/lisa-jira-validate-ticket/SKILL.md +22 -0
- package/plugins/src/base/skills/lisa-jira-write-ticket/SKILL.md +15 -0
- package/plugins/src/base/skills/lisa-learnings-audit/SKILL.md +6 -3
- package/plugins/src/base/skills/lisa-linear-access/SKILL.md +25 -3
- package/plugins/src/base/skills/lisa-linear-validate-issue/SKILL.md +22 -0
- package/plugins/src/base/skills/lisa-linear-write-issue/SKILL.md +15 -0
- package/plugins/src/base/skills/lisa-secrets-access/SKILL.md +20 -2
- package/plugins/src/base/skills/lisa-secrets-access/scripts/doctor-secrets.mjs +13 -9
- package/plugins/src/base/skills/lisa-secrets-access/scripts/note-format.mjs +179 -0
- package/plugins/src/base/skills/lisa-secrets-access/scripts/resolve-secret.mjs +32 -6
- package/plugins/src/base/skills/lisa-secrets-access/scripts/tools-from-notes.mjs +6 -2
- package/plugins/src/base/skills/lisa-setup-atlassian/SKILL.md +17 -0
- package/plugins/src/base/skills/lisa-setup-linear/SKILL.md +17 -0
- package/plugins/src/base/skills/lisa-setup-notion/SKILL.md +17 -0
- package/plugins/src/typescript/hooks/block-suppress-directives.sh +1 -1
- package/scripts/github-status-check.sh +22 -7
- package/all/create-only/.claude/rules/PROJECT_RULES.md +0 -17
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
|
|
20
20
|
import { createHash } from "node:crypto";
|
|
21
21
|
|
|
22
|
+
import { validateNote } from "./note-format.mjs";
|
|
22
23
|
import { fetchAll, fetchRotatable } from "./providers.mjs";
|
|
23
24
|
import { readMaterialized } from "./resolve-secret.mjs";
|
|
24
25
|
import { readConfig } from "./surfaces.mjs";
|
|
@@ -118,20 +119,23 @@ export function checkNaming(provider, report) {
|
|
|
118
119
|
}
|
|
119
120
|
|
|
120
121
|
/**
|
|
121
|
-
* Assert every secret carries a usage note.
|
|
122
|
+
* Assert every secret carries a usage note in the documented format.
|
|
123
|
+
*
|
|
124
|
+
* This blocks rather than warns, and the promotion is the point. The contract
|
|
125
|
+
* has always said the note "must exist and be well-formed", enforced statically
|
|
126
|
+
* by `doctor` — but a warning enforces nothing, so a vault of empty notes
|
|
127
|
+
* reported clean and stayed empty. A check that never fails is a check nobody
|
|
128
|
+
* acts on.
|
|
129
|
+
*
|
|
130
|
+
* The grammar lives in `note-format.mjs` so this and `resolve-secret.mjs verify`
|
|
131
|
+
* cannot disagree about what a well-formed note is.
|
|
122
132
|
* @param {Map<string, object>} provider Provider view.
|
|
123
133
|
* @param {Function} report Finding collector.
|
|
124
134
|
*/
|
|
125
135
|
export function checkNotes(provider, report) {
|
|
126
136
|
for (const [name, entry] of provider) {
|
|
127
|
-
|
|
128
|
-
report(
|
|
129
|
-
"warn",
|
|
130
|
-
name,
|
|
131
|
-
"has no usage note. An agent cannot learn this credential's scope " +
|
|
132
|
-
"without one, and inferring it from the name is exactly the guess " +
|
|
133
|
-
"that writes to the wrong system"
|
|
134
|
-
);
|
|
137
|
+
for (const defect of validateNote(entry?.note)) {
|
|
138
|
+
report(defect.level, name, defect.message);
|
|
135
139
|
}
|
|
136
140
|
}
|
|
137
141
|
}
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Validate a credential's usage note against the format the contract documents.
|
|
3
|
+
*
|
|
4
|
+
* The contract states Rule A — "the note must exist and be well-formed",
|
|
5
|
+
* enforced statically by `verify` and by `doctor`. Only half of that was ever
|
|
6
|
+
* true. Both consumers tested the note for emptiness and nothing tested its
|
|
7
|
+
* shape, so a note that promised a scope and delivered a bare colon, or a
|
|
8
|
+
* `tool:` line naming a URL instead of a CLI, passed every check Lisa had. The
|
|
9
|
+
* prose described an enforcement that did not exist, which is worse than no
|
|
10
|
+
* rule: readers stopped checking because they believed something else was.
|
|
11
|
+
*
|
|
12
|
+
* This module is that missing half, and it lives in one place on purpose. The
|
|
13
|
+
* same argument the values file makes for keeping its writer and its parser
|
|
14
|
+
* together applies here: `tools-from-notes.mjs` decides what a `tool:` line
|
|
15
|
+
* *is*, and if this validator held a second copy of that pattern, a note could
|
|
16
|
+
* pass doctor and then be silently ignored at install time with nothing to
|
|
17
|
+
* reveal the disagreement. So the matcher is defined here once and imported
|
|
18
|
+
* there.
|
|
19
|
+
*
|
|
20
|
+
* Messages are written for the person who has to fix the vault, who is often
|
|
21
|
+
* not an engineer. Each one names the secret's defect and the edit that clears
|
|
22
|
+
* it, never only the rule that was broken.
|
|
23
|
+
* @module note-format
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* A `key: value` metadata line.
|
|
28
|
+
*
|
|
29
|
+
* The key must be a single bare lowercase token. That is what separates
|
|
30
|
+
* `scope: read-write` from prose that happens to contain a colon, such as
|
|
31
|
+
* "Attio CRM: system of record for sales" — a sentence has spaces before its
|
|
32
|
+
* colon, and a capitalised word opening a sentence is prose, not a field. The
|
|
33
|
+
* discriminator is deliberately generous: mistaking a field for prose only
|
|
34
|
+
* loosens a check, while mistaking prose for a field would fail a good note.
|
|
35
|
+
*/
|
|
36
|
+
const FIELD_LINE = /^[ \t]*([a-z][a-z0-9_-]*)[ \t]*:[ \t]*(.*)$/;
|
|
37
|
+
|
|
38
|
+
/** Matches `tool: name` or `tools: a, b`, case-insensitively, on one line. */
|
|
39
|
+
const TOOL_LINE_SINGLE = /^[ \t]*tools?[ \t]*:[ \t]*(.*)$/i;
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* The same matcher, global and multiline, for scanning a whole note.
|
|
43
|
+
*
|
|
44
|
+
* Derived from the single-line pattern rather than written out again, so the
|
|
45
|
+
* two can never disagree about what a tool line is.
|
|
46
|
+
*/
|
|
47
|
+
export const TOOL_LINE = new RegExp(TOOL_LINE_SINGLE.source, "gim");
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* A bare CLI name: what a `tool:` entry is permitted to be.
|
|
51
|
+
*
|
|
52
|
+
* Names are matched against Lisa's catalogue and never executed, so this is not
|
|
53
|
+
* the security boundary — the catalogue is. It is the check that tells an
|
|
54
|
+
* operator their entry will be silently dropped, which is the failure mode
|
|
55
|
+
* worth catching: a note asking for `sonar (for CI)` installs nothing, and the
|
|
56
|
+
* session fails much later for a reason that looks unrelated.
|
|
57
|
+
*/
|
|
58
|
+
const TOOL_NAME = /^[a-z0-9][a-z0-9._+-]*$/;
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Whether a line is structured metadata rather than a sentence.
|
|
62
|
+
* @param {string} line One line of a note.
|
|
63
|
+
* @returns {boolean} True when the line is a field or a tool line.
|
|
64
|
+
*/
|
|
65
|
+
function isMetadataLine(line) {
|
|
66
|
+
return FIELD_LINE.test(line) || TOOL_LINE_SINGLE.test(line);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Check the entries on one `tool:` / `tools:` line.
|
|
71
|
+
* @param {string} value The text after the colon.
|
|
72
|
+
* @param {object[]} defects Collector to append to.
|
|
73
|
+
*/
|
|
74
|
+
function checkToolLine(value, defects) {
|
|
75
|
+
if (!value.trim()) {
|
|
76
|
+
defects.push({
|
|
77
|
+
level: "error",
|
|
78
|
+
code: "empty-tool-line",
|
|
79
|
+
message:
|
|
80
|
+
"has a `tool:` line that names no tool. Either name the command-line " +
|
|
81
|
+
"tool this credential is for (for example `tool: sonar`) or delete " +
|
|
82
|
+
"the line — as written it asks for a tool and supplies none, so " +
|
|
83
|
+
"nothing gets installed",
|
|
84
|
+
});
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
for (const raw of value.split(",")) {
|
|
89
|
+
const entry = raw.trim();
|
|
90
|
+
if (!entry) {
|
|
91
|
+
// A trailing or doubled comma is sloppy punctuation, not a broken note:
|
|
92
|
+
// the reader drops the empty entry and installs the rest correctly.
|
|
93
|
+
// Blocking a vault over a comma would teach operators the check is noise.
|
|
94
|
+
defects.push({
|
|
95
|
+
level: "warn",
|
|
96
|
+
code: "stray-separator",
|
|
97
|
+
message:
|
|
98
|
+
"has a `tool:` line with a stray comma. Nothing breaks, but tidy it " +
|
|
99
|
+
"so the list reads as the tools it actually names",
|
|
100
|
+
});
|
|
101
|
+
continue;
|
|
102
|
+
}
|
|
103
|
+
if (!TOOL_NAME.test(entry.toLowerCase())) {
|
|
104
|
+
defects.push({
|
|
105
|
+
level: "error",
|
|
106
|
+
code: "bad-tool-name",
|
|
107
|
+
message:
|
|
108
|
+
`has a \`tool:\` entry that is not a tool name: "${entry}". Each ` +
|
|
109
|
+
"entry must be one plain name such as `sonar` or `gh`, separated by " +
|
|
110
|
+
"commas — no descriptions, links, versions, or punctuation. As " +
|
|
111
|
+
"written this entry is ignored, so the tool never gets installed",
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Report every way a usage note departs from the documented format.
|
|
119
|
+
*
|
|
120
|
+
* Returns defects rather than throwing so a caller can list a whole vault's
|
|
121
|
+
* problems in one pass. An operator fixing a vault wants every edit at once,
|
|
122
|
+
* not one error per run.
|
|
123
|
+
* @param {unknown} note The note text stored beside the secret.
|
|
124
|
+
* @returns {{level: string, code: string, message: string}[]} Defects found.
|
|
125
|
+
*/
|
|
126
|
+
export function validateNote(note) {
|
|
127
|
+
if (typeof note !== "string" || !note.trim()) {
|
|
128
|
+
// One cause, one instruction. Also accusing an absent note of lacking a
|
|
129
|
+
// first line would leave the operator guessing which fix comes first.
|
|
130
|
+
return [
|
|
131
|
+
{
|
|
132
|
+
level: "error",
|
|
133
|
+
code: "missing-note",
|
|
134
|
+
message:
|
|
135
|
+
"has no usage note. Write one in the secret's own description field " +
|
|
136
|
+
"in the vault: a first line saying what this credential is for and " +
|
|
137
|
+
"what it can reach, then `key: value` lines such as `scope:`, " +
|
|
138
|
+
"`owner:`, and `tool:`. Guessing a credential's purpose from its " +
|
|
139
|
+
"name is exactly the guess that writes to the wrong system",
|
|
140
|
+
},
|
|
141
|
+
];
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
const defects = [];
|
|
145
|
+
const lines = note.split(/\r?\n/);
|
|
146
|
+
const populated = lines.filter(line => line.trim());
|
|
147
|
+
|
|
148
|
+
if (!populated.some(line => !isMetadataLine(line))) {
|
|
149
|
+
defects.push({
|
|
150
|
+
level: "error",
|
|
151
|
+
code: "no-prose",
|
|
152
|
+
message:
|
|
153
|
+
"has no plain-language first line. Add a sentence at the top saying " +
|
|
154
|
+
"what this credential is for and what it can reach — the `key: value` " +
|
|
155
|
+
"lines below it list details, but they never say what the thing is",
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
for (const line of populated) {
|
|
160
|
+
const tool = TOOL_LINE_SINGLE.exec(line);
|
|
161
|
+
if (tool) {
|
|
162
|
+
checkToolLine(tool[1], defects);
|
|
163
|
+
continue;
|
|
164
|
+
}
|
|
165
|
+
const field = FIELD_LINE.exec(line);
|
|
166
|
+
if (field && !field[2].trim()) {
|
|
167
|
+
defects.push({
|
|
168
|
+
level: "error",
|
|
169
|
+
code: "empty-field",
|
|
170
|
+
message:
|
|
171
|
+
`has an empty \`${field[1]}:\` line. Either fill in the value or ` +
|
|
172
|
+
"delete the line — a field with nothing after the colon promises a " +
|
|
173
|
+
"fact the reader then cannot find anywhere",
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
return defects;
|
|
179
|
+
}
|
|
@@ -30,6 +30,7 @@
|
|
|
30
30
|
import { existsSync, readFileSync } from "node:fs";
|
|
31
31
|
|
|
32
32
|
import { parseEnv } from "./envfile.mjs";
|
|
33
|
+
import { validateNote } from "./note-format.mjs";
|
|
33
34
|
import { ENV_KEY, fetchAll } from "./providers.mjs";
|
|
34
35
|
import { materializedPaths, readConfig } from "./surfaces.mjs";
|
|
35
36
|
|
|
@@ -109,6 +110,19 @@ function sourceOf(name, provider, file) {
|
|
|
109
110
|
return " ";
|
|
110
111
|
}
|
|
111
112
|
|
|
113
|
+
/**
|
|
114
|
+
* Say what is wrong with a note, not merely that something is.
|
|
115
|
+
*
|
|
116
|
+
* "NO NOTE" against a note that exists but is malformed sends the operator
|
|
117
|
+
* looking for a missing field they already wrote.
|
|
118
|
+
* @param {object} [fault] The blocking defect, if any.
|
|
119
|
+
* @returns {string} A status label for the verify table.
|
|
120
|
+
*/
|
|
121
|
+
function noteStatus(fault) {
|
|
122
|
+
if (!fault) return "noted";
|
|
123
|
+
return fault.code === "missing-note" ? "NO NOTE" : `NOTE ${fault.code}`;
|
|
124
|
+
}
|
|
125
|
+
|
|
112
126
|
/**
|
|
113
127
|
* Verify every declared secret, mirroring the ladder's own order.
|
|
114
128
|
*
|
|
@@ -119,12 +133,20 @@ function sourceOf(name, provider, file) {
|
|
|
119
133
|
* This command is read-only. Proving that a rotating credential can actually be
|
|
120
134
|
* written back requires a write, so that check lives in the rotation path
|
|
121
135
|
* rather than here.
|
|
136
|
+
*
|
|
137
|
+
* The two views are parameters so a test can supply them. Reaching for the
|
|
138
|
+
* provider CLI is the one thing in here that cannot run in a test, and a check
|
|
139
|
+
* nobody can test is how the note rule stayed unenforced for so long.
|
|
122
140
|
* @param {object} cfg Resolved configuration.
|
|
141
|
+
* @param {Map<string, object>} [provider] Provider view.
|
|
142
|
+
* @param {Map<string, string>} [file] Materialized view.
|
|
123
143
|
* @returns {number} Count of secrets that failed.
|
|
124
144
|
*/
|
|
125
|
-
function verify(
|
|
126
|
-
|
|
127
|
-
|
|
145
|
+
export function verify(
|
|
146
|
+
cfg,
|
|
147
|
+
provider = fetchAll(cfg),
|
|
148
|
+
file = readMaterialized(cfg)
|
|
149
|
+
) {
|
|
128
150
|
const names = cfg.require ?? [
|
|
129
151
|
...new Set([...provider.keys(), ...file.keys()]),
|
|
130
152
|
];
|
|
@@ -139,13 +161,17 @@ function verify(cfg) {
|
|
|
139
161
|
provider.get(name)?.value
|
|
140
162
|
);
|
|
141
163
|
const named = ENV_KEY.test(name);
|
|
142
|
-
|
|
143
|
-
|
|
164
|
+
// Presence is not well-formedness. Testing `Boolean(note)` passed a note
|
|
165
|
+
// that was a single stray character, which is exactly the note an agent
|
|
166
|
+
// learns nothing from. Same validator doctor uses, so the two agree.
|
|
167
|
+
const defects = validateNote(provider.get(name)?.note);
|
|
168
|
+
const noteFault = defects.find(d => d.level === "error");
|
|
169
|
+
if (!resolves || !named || noteFault) bad += 1;
|
|
144
170
|
console.log(
|
|
145
171
|
` ${name.padEnd(30)} ${resolves ? "resolves" : "MISSING "} ` +
|
|
146
172
|
`${sourceOf(name, provider, file)} ` +
|
|
147
173
|
`${named ? "name ok" : "NAME NOT UPPER_SNAKE"} ` +
|
|
148
|
-
`${
|
|
174
|
+
`${noteStatus(noteFault)}` +
|
|
149
175
|
`${rotating.has(name) ? " rotating" : ""}`
|
|
150
176
|
);
|
|
151
177
|
}
|
|
@@ -21,11 +21,15 @@
|
|
|
21
21
|
* its note. Selecting from a known set means the worst a hostile note can do is
|
|
22
22
|
* ask for a CLI Lisa already ships a pinned, checksummed entry for — it can
|
|
23
23
|
* never introduce a URL, a version, or a command.
|
|
24
|
+
* The matcher itself lives in `note-format.mjs` alongside the validator that
|
|
25
|
+
* checks these lines, for the same reason the values file keeps its writer and
|
|
26
|
+
* its parser in one module: two copies of the pattern would let a note pass
|
|
27
|
+
* `doctor` and then be silently ignored here, with nothing to reveal the
|
|
28
|
+
* disagreement.
|
|
24
29
|
* @module tools-from-notes
|
|
25
30
|
*/
|
|
26
31
|
|
|
27
|
-
|
|
28
|
-
const TOOL_LINE = /^[ \t]*tools?[ \t]*:[ \t]*(.+)$/gim;
|
|
32
|
+
import { TOOL_LINE } from "./note-format.mjs";
|
|
29
33
|
|
|
30
34
|
/**
|
|
31
35
|
* Collect the tool names a set of notes asks for.
|
|
@@ -77,6 +77,23 @@ read_token() {
|
|
|
77
77
|
local slug=$(echo "$email" | tr '[:upper:]@.' '[:lower:]__')
|
|
78
78
|
local varname="ATLASSIAN_API_TOKEN_${slug}"
|
|
79
79
|
[ -n "${!varname}" ] && { echo "${!varname}"; return; }
|
|
80
|
+
# Preferred path: the single secrets chokepoint. It owns the one-store rule
|
|
81
|
+
# and the surface ladder, so anything it can answer must not be read out of an
|
|
82
|
+
# OS keychain here — a second reader is how the same credential ends up living
|
|
83
|
+
# in two places and drifting. Keep this identical to `atlassian-access`.
|
|
84
|
+
local resolver
|
|
85
|
+
for resolver in .claude/skills/lisa-secrets-access/scripts/resolve-secret.mjs \
|
|
86
|
+
.agents/skills/lisa-secrets-access/scripts/resolve-secret.mjs; do
|
|
87
|
+
if [ -f "$resolver" ]; then
|
|
88
|
+
local via_lisa
|
|
89
|
+
via_lisa=$(node "$resolver" get ATLASSIAN_API_TOKEN 2>/dev/null) \
|
|
90
|
+
&& [ -n "$via_lisa" ] && { echo "$via_lisa"; return; }
|
|
91
|
+
break
|
|
92
|
+
fi
|
|
93
|
+
done
|
|
94
|
+
# Legacy fallback: the OS keychain written by the guided flow below, for
|
|
95
|
+
# projects that have not adopted a credentials provider. Reached only when the
|
|
96
|
+
# chokepoint is absent or has no entry.
|
|
80
97
|
case "$(uname -s)" in
|
|
81
98
|
Darwin) security find-generic-password -s lisa-atlassian -a "$email" -w 2>/dev/null ;;
|
|
82
99
|
Linux) command -v secret-tool >/dev/null && secret-tool lookup service lisa-atlassian account "$email" 2>/dev/null ;;
|
|
@@ -89,6 +89,23 @@ read_linear_key() { # $1=workspace slug
|
|
|
89
89
|
local slug; slug=$(echo "$ws" | tr '[:upper:]-' '[:lower:]_')
|
|
90
90
|
local varname="LINEAR_API_KEY_${slug}"
|
|
91
91
|
[ -n "${!varname}" ] && { echo "${!varname}"; return; }
|
|
92
|
+
# Preferred path: the single secrets chokepoint. It owns the one-store rule
|
|
93
|
+
# and the surface ladder, so anything it can answer must not be read out of an
|
|
94
|
+
# OS keychain here — a second reader is how the same credential ends up living
|
|
95
|
+
# in two places and drifting. Keep this identical to `linear-access`.
|
|
96
|
+
local resolver
|
|
97
|
+
for resolver in .claude/skills/lisa-secrets-access/scripts/resolve-secret.mjs \
|
|
98
|
+
.agents/skills/lisa-secrets-access/scripts/resolve-secret.mjs; do
|
|
99
|
+
if [ -f "$resolver" ]; then
|
|
100
|
+
local via_lisa
|
|
101
|
+
via_lisa=$(node "$resolver" get LINEAR_API_KEY 2>/dev/null) \
|
|
102
|
+
&& [ -n "$via_lisa" ] && { echo "$via_lisa"; return; }
|
|
103
|
+
break
|
|
104
|
+
fi
|
|
105
|
+
done
|
|
106
|
+
# Legacy fallback: the OS keychain written by the guided flow below, for
|
|
107
|
+
# projects that have not adopted a credentials provider. Reached only when the
|
|
108
|
+
# chokepoint is absent or has no entry.
|
|
92
109
|
case "$(uname -s)" in
|
|
93
110
|
Darwin) security find-generic-password -s lisa-linear -a "$ws" -w 2>/dev/null ;;
|
|
94
111
|
Linux) command -v secret-tool >/dev/null && secret-tool lookup service lisa-linear account "$ws" 2>/dev/null ;;
|
|
@@ -164,6 +164,23 @@ read_notion_token() {
|
|
|
164
164
|
local slug=$(echo "$workspace" | tr '[:upper:]-' '[:lower:]_')
|
|
165
165
|
local varname="NOTION_API_TOKEN_${slug}"
|
|
166
166
|
[ -n "${!varname}" ] && { echo "${!varname}"; return; }
|
|
167
|
+
# Preferred path: the single secrets chokepoint. It owns the one-store rule
|
|
168
|
+
# and the surface ladder, so anything it can answer must not be read out of an
|
|
169
|
+
# OS keychain here — a second reader is how the same credential ends up living
|
|
170
|
+
# in two places and drifting. Keep this identical to `notion-access`.
|
|
171
|
+
local resolver
|
|
172
|
+
for resolver in .claude/skills/lisa-secrets-access/scripts/resolve-secret.mjs \
|
|
173
|
+
.agents/skills/lisa-secrets-access/scripts/resolve-secret.mjs; do
|
|
174
|
+
if [ -f "$resolver" ]; then
|
|
175
|
+
local via_lisa
|
|
176
|
+
via_lisa=$(node "$resolver" get NOTION_API_TOKEN 2>/dev/null) \
|
|
177
|
+
&& [ -n "$via_lisa" ] && { echo "$via_lisa"; return; }
|
|
178
|
+
break
|
|
179
|
+
fi
|
|
180
|
+
done
|
|
181
|
+
# Legacy fallback: the OS keychain written by the guided flow below, for
|
|
182
|
+
# projects that have not adopted a credentials provider. Reached only when the
|
|
183
|
+
# chokepoint is absent or has no entry.
|
|
167
184
|
case "$(uname -s)" in
|
|
168
185
|
Darwin) security find-generic-password -s lisa-notion -a "$workspace" -w 2>/dev/null ;;
|
|
169
186
|
Linux) command -v secret-tool >/dev/null && secret-tool lookup service lisa-notion account "$workspace" 2>/dev/null ;;
|
|
@@ -44,7 +44,7 @@ Map every finding to exactly one category. When a finding could fit two, pick th
|
|
|
44
44
|
|
|
45
45
|
A finding that does not fit any of the eight is itself a signal — surface it under an additional ad-hoc category `Uncategorized` with a note explaining why no category fit. Better to surface than to drop.
|
|
46
46
|
|
|
47
|
-
The destination column is a **hint for the human triaging the row**, not the routing decision: `lisa-debrief-apply` routes on the category, never on this column. Keep the hint honest anyway — a human decides Accept/Reject partly on where the learning will land. The three knowledge categories (recurring gotcha, process friction, convention drift) all land in the committed learnings ledger through the executable contract. Machine-local auto-memory (`project_*.md`, `MEMORY.md`),
|
|
47
|
+
The destination column is a **hint for the human triaging the row**, not the routing decision: `lisa-debrief-apply` routes on the category, never on this column. Keep the hint honest anyway — a human decides Accept/Reject partly on where the learning will land. The three knowledge categories (recurring gotcha, process friction, convention drift) all land in the committed learnings ledger through the executable contract. Machine-local auto-memory (`project_*.md`, `MEMORY.md`), the host-rules directory `.agents/rules/`, and `AGENTS.md` (whose `CLAUDE.md` is only a `@AGENTS.md` pointer) are **never** destinations — the first is invisible to cloud runs and teammates, and the latter two are human-authored surfaces that agents do not write.
|
|
48
48
|
|
|
49
49
|
## Dedupe rules
|
|
50
50
|
|
|
@@ -18,7 +18,7 @@ Rungs are ordered by context cost and enforcement strength. Decision vocabulary:
|
|
|
18
18
|
| Rung | Recommendation | Destination | Enters context | Admission policy |
|
|
19
19
|
| --- | --- | --- | --- | --- |
|
|
20
20
|
| 6 | EXECUTABLE-CONTROL | Lint / ast-grep / type / test / hook / `package.lisa.json` force | Never — diagnostic fires on violation | Mechanically decidable + stable + recurred |
|
|
21
|
-
| 5 | EAGER-RULE |
|
|
21
|
+
| 5 | EAGER-RULE | Host rules: `.agents/rules/` (project scope) · plugin `rules/eager/` (upstream scope) | Unconditionally, every session | **Earned by failure evidence** (repeated misses despite retrievability); demotion-biased |
|
|
22
22
|
| 4 | SKILL | `.claude/skills/<name>/SKILL.md` | Description eager; body on invoke | Procedural, complex, recognizable trigger |
|
|
23
23
|
| 3 | WIKI | Wiki page + index entry | Only when routed to | Durable reference knowledge |
|
|
24
24
|
| 2 | KEEP-IN-LEDGER | `PROJECT_LEARNINGS.md` (bounded contract projection) | Bounded projection only | Default landing zone; probationary, expiring |
|
|
@@ -117,7 +117,7 @@ WHERE IT GOES INSTEAD — take the first one that fits:
|
|
|
117
117
|
That is a project rule — but do not write it yourself. Capture it with
|
|
118
118
|
\`/lisa:persist-learning\` so it lands in the learnings ledger with provenance
|
|
119
119
|
and a confidence score. The gardener (\`/lisa:learnings:audit\`) then proposes
|
|
120
|
-
promotion into \`.
|
|
120
|
+
promotion into the host-rules directory \`.agents/rules/\` as a human-gated ticket.
|
|
121
121
|
|
|
122
122
|
2. It changes how an existing skill should behave. Edit that skill's SKILL.md.
|
|
123
123
|
Knowledge belongs next to the procedure it modifies, not in a global preamble.
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
# Text tools (grep/sed/cut/awk) break on valid JSON — multiline values, escaped
|
|
4
4
|
# quotes, reordered keys, nested objects — producing silently wrong output
|
|
5
5
|
# instead of errors. jq is the required tool for structural JSON reads and
|
|
6
|
-
# writes in shell. Promoted from
|
|
6
|
+
# writes in shell. Promoted from host-rules prose to an executable
|
|
7
7
|
# control by the learnings gardener (issue #1787).
|
|
8
8
|
#
|
|
9
9
|
# Precision-first: this hook fires only on high-confidence STRUCTURAL parsing
|
|
@@ -72,7 +72,7 @@ A markdown triage document at `./debrief/<initiative-slug>-<YYYY-MM-DD>.md` (or
|
|
|
72
72
|
- `Summary` — one sentence
|
|
73
73
|
- `Category`
|
|
74
74
|
- `Evidence` — links to the source ticket comment / PR comment / commit / test file (multiple allowed)
|
|
75
|
-
- `Recommended persistence destination` — the agent's best guess for where this should land if accepted (e.g., "Edge Case Brainstorm checklist → Navigation & URL state", "learnings ledger via the executable contract", "new tooling-gap ticket", "upstream Lisa issue"). Never name machine-local auto-memory,
|
|
75
|
+
- `Recommended persistence destination` — the agent's best guess for where this should land if accepted (e.g., "Edge Case Brainstorm checklist → Navigation & URL state", "learnings ledger via the executable contract", "new tooling-gap ticket", "upstream Lisa issue"). Never name machine-local auto-memory, the host-rules directory `.agents/rules/`, or `AGENTS.md` — those are not persistence destinations.
|
|
76
76
|
- `Disposition` — empty checkbox-style field the human will fill: `[ ] Accept` / `[ ] Reject` / `[ ] Defer` plus a free-text reason
|
|
77
77
|
4. **Source map** — appendix listing every work item and PR walked, so the human can verify completeness.
|
|
78
78
|
|
|
@@ -18,7 +18,7 @@ A path or URL to a Debrief triage document produced by `lisa-debrief`. The docum
|
|
|
18
18
|
|
|
19
19
|
1. **Verify the doc exists and parses.** If the file cannot be read or the expected sections are missing, stop and report — do not guess.
|
|
20
20
|
2. **Confirm dispositions exist.** If every row is unmarked, stop and ask the human to triage first. A pristine doc is a no-op, not an error to silently swallow.
|
|
21
|
-
3. **Identify the destination map.** Read the project's `.lisa.config.json` (or stack defaults) for: edge-case checklist file (default: `plugins/src/base/rules/intent-routing.md`'s Edge Case Brainstorm sub-flow), the committed learnings ledger path (resolve it — never hardcode — via `resolveProjectLearningsFile` from `@codyswann/lisa/learnings`: the `learnings.file` override, else the default `.lisa/PROJECT_LEARNINGS.md`), tracker for new tickets. The three knowledge categories (recurring gotcha, process friction, convention drift) all land in the ledger now; machine-local auto-memory and
|
|
21
|
+
3. **Identify the destination map.** Read the project's `.lisa.config.json` (or stack defaults) for: edge-case checklist file (default: `plugins/src/base/rules/intent-routing.md`'s Edge Case Brainstorm sub-flow), the committed learnings ledger path (resolve it — never hardcode — via `resolveProjectLearningsFile` from `@codyswann/lisa/learnings`: the `learnings.file` override, else the default `.lisa/PROJECT_LEARNINGS.md`), tracker for new tickets. The three knowledge categories (recurring gotcha, process friction, convention drift) all land in the ledger now; machine-local auto-memory and host rules (`.agents/rules/`) / `AGENTS.md` are no longer knowledge destinations (see [Ledger persistence](#ledger-persistence-knowledge-categories)).
|
|
22
22
|
|
|
23
23
|
## Routing rules
|
|
24
24
|
|
|
@@ -61,13 +61,13 @@ For each such Accepted row:
|
|
|
61
61
|
- `first_learned` = `last_confirmed` = today (ISO date; on consolidation keep the superseded entry's earliest `first_learned`).
|
|
62
62
|
- `confidence` = **`high`**. A human marking the row **Accept** is corroboration — an independent human judgement that the learning is real — so a debrief-accepted entry starts higher than the learner's single-occurrence auto-capture (which defaults to `low`). The writer re-asserts the entry and token budgets; an over-budget failure means consolidate harder or drop, never truncate by hand.
|
|
63
63
|
|
|
64
|
-
**Machine-local memory is no longer a knowledge destination.** Auto-memory (`project_*.md`, `MEMORY.md`) remains available only for the assistant's *personal* collaboration notes — it is invisible to cloud runs and to teammates, so it can never hold shared project knowledge. **`AGENTS.md` is human-authored** agent operating instruction — it is the source of truth, and `CLAUDE.md` is only a one-line `@AGENTS.md` pointer — and
|
|
64
|
+
**Machine-local memory is no longer a knowledge destination.** Auto-memory (`project_*.md`, `MEMORY.md`) remains available only for the assistant's *personal* collaboration notes — it is invisible to cloud runs and to teammates, so it can never hold shared project knowledge. **`AGENTS.md` is human-authored** agent operating instruction — it is the source of truth, and `CLAUDE.md` is only a one-line `@AGENTS.md` pointer — and the host-rules directory `.agents/rules/` is durable human-authored guidance; `apply` never writes to any of the three for these categories.
|
|
65
65
|
|
|
66
66
|
## Idempotency
|
|
67
67
|
|
|
68
68
|
`apply` is safe to re-run. Each Accepted row carries an evidence link that doubles as a fingerprint. Before writing, check whether the destination already cites that fingerprint:
|
|
69
69
|
|
|
70
|
-
- **Knowledge categories (gotcha, friction, drift) → ledger.** Parse the ledger once with `parseLearningsFile` from `@codyswann/lisa/learnings` and scan the entries' `provenance` for the row's evidence link. If any entry's provenance already contains it, the row is already persisted — skip the write. This replaces the old scattered-file greps (memory files,
|
|
70
|
+
- **Knowledge categories (gotcha, friction, drift) → ledger.** Parse the ledger once with `parseLearningsFile` from `@codyswann/lisa/learnings` and scan the entries' `provenance` for the row's evidence link. If any entry's provenance already contains it, the row is already persisted — skip the write. This replaces the old scattered-file greps (memory files, host rules, `AGENTS.md`): provenance in the single governed ledger is now the one fingerprint surface.
|
|
71
71
|
- **Other categories** keep their existing destination check (the tracker for the ticket marker, the PRD for the defect comment, `intent-routing.md` for the edge-case citation).
|
|
72
72
|
|
|
73
73
|
If the fingerprint is already present, skip the write and note the row as `already-applied` in the run summary. This lets the human triage a doc incrementally (mark a few, run apply, mark more, run apply again) without producing duplicates.
|
|
@@ -56,7 +56,10 @@ as applicable to the current repo:
|
|
|
56
56
|
and `source` only. If a required CLI, MCP surface, or auth context is unavailable in the current
|
|
57
57
|
runtime, report that explicitly instead of pretending the repo is ready.
|
|
58
58
|
4. **Runtime distribution surfaces** — confirm the command, skill, hook, and related distribution
|
|
59
|
-
surfaces relevant to this repo are present where Lisa expects them on the active runtime
|
|
59
|
+
surfaces relevant to this repo are present where Lisa expects them on the active runtime, and
|
|
60
|
+
that the Lisa-owned enforcement artifacts (`scripts/lisa-hooks/*`,
|
|
61
|
+
`scripts/lisa-enforcement-fallback.sh`) match the installed Lisa version rather than an older
|
|
62
|
+
copy. Present-but-stale is a finding: a guard whose fix never landed enforces the old behavior.
|
|
60
63
|
5. **Automation readiness** — inspect whether the configured queue source/tracker and scheduling
|
|
61
64
|
prerequisites are observable, but do **not** create, edit, or delete automations during doctor.
|
|
62
65
|
6. **Optional GitHub Project coordination** — when `github.projects.v2` is configured, delegate
|
|
@@ -48,6 +48,7 @@ Walk the markdown body and capture each top-level `## ` section by name. Standar
|
|
|
48
48
|
- `Acceptance Criteria` (preserve the Gherkin code-fence verbatim)
|
|
49
49
|
- `Out of Scope`
|
|
50
50
|
- `Target Backend Environment`
|
|
51
|
+
- `Branch Plan` (derived output per `derived-branch-plan` — parsed so callers can *compare* it against a recomputation, never so they can use it as the base branch)
|
|
51
52
|
- `Sign-in Required`
|
|
52
53
|
- `Repository`
|
|
53
54
|
- `Source Artifacts`
|
|
@@ -98,6 +98,7 @@ Per-type content requirements are defined once in the vendor-neutral `work-item-
|
|
|
98
98
|
| S16 Source Requirement traceability | `product-clarity` | true |
|
|
99
99
|
| S17 Improvement measurability | `acceptance-criteria` | true |
|
|
100
100
|
| S18 Stateless-pickup dry-run | `product-clarity` | true |
|
|
101
|
+
| S19 Branch Plan derivation | `technical` | false |
|
|
101
102
|
| F1 Issue type label exists in repo | `structural` | false |
|
|
102
103
|
| F2 Parent sub-issue exists and is the right type | `structural` | false |
|
|
103
104
|
| F3 Linked issues exist | `structural` | false |
|
|
@@ -299,6 +300,26 @@ The autonomy gate, run last, on every build-ready leaf (use the S15 classificati
|
|
|
299
300
|
|
|
300
301
|
Zero questions → PASS. Any question → FAIL, with each question listed verbatim as its own remediation line — these are exactly the clarifying comments the caller posts to the source. The structure gates are proxies; this gate checks the readiness property itself: `ready` means a stateless agent can drive this item to its terminal state with zero human clarification (see `work-item-definition-of-ready`).
|
|
301
302
|
|
|
303
|
+
#### S19 — Branch Plan derivation
|
|
304
|
+
|
|
305
|
+
Enforces the `derived-branch-plan` rule: the `## Branch Plan` section is **derived only** — recompute it from current config and compare; never trust the rendered branches or read them as input. Resolve the environment under the S8 grammar, map that exact configured key forward through `.lisa.config.json` `deploy.branches`, and require the mapped branch on the remote.
|
|
306
|
+
|
|
307
|
+
| Case | Verdict |
|
|
308
|
+
|---|---|
|
|
309
|
+
| `runtime_behavior_change = false` (doc-only / config-only / type-only) or an Epic/container, with no plan | `N/A` — absence is correct; never demand one |
|
|
310
|
+
| Exempt work **carrying** a `## Branch Plan` | **FAIL** — hand-authored branches on work that declared no runtime target |
|
|
311
|
+
| Plan matches the recomputed plan | PASS |
|
|
312
|
+
| Plan conflicts with the recomputed plan | **FAIL** |
|
|
313
|
+
| Plan missing the `Derived from:` provenance line and disagreeing | **FAIL** — treated as hand-authored |
|
|
314
|
+
| `Branch from` and `PR into` name two different branches | **FAIL** — malformed; they are the same branch by construction |
|
|
315
|
+
| Derivation hits a stop condition (env absent from `deploy.branches`, ambiguous / non-unique mapping, branch missing on the remote) | **FAIL** — the same stop `lisa-implement` takes; never default to `main` or the remote default |
|
|
316
|
+
| Proposed spec (pre-write) for applicable work with no plan | **FAIL** — `lisa-github-write-issue` must render it before the write |
|
|
317
|
+
| Live **legacy** issue for applicable work with no plan | `N/A` with a repair note — routed to claim time, where `lisa-implement` writes the derived assumption as a comment and proceeds |
|
|
318
|
+
|
|
319
|
+
Failing a proposed spec is free; failing every existing issue would turn a legacy queue red for a section no human had a way to add, so legacy absence is repaired at claim time instead.
|
|
320
|
+
|
|
321
|
+
FAIL names both plans (rendered and recomputed) and points the remediation at **the environment, never the branch** — e.g. `"Branch Plan conflicts with the environment mapping. Rendered 'Branch from: release/staging'; recomputed from Target Backend Environment 'production' via deploy.branches → 'main'. Correct the environment, not the branch — the branches are derived. Then re-render."` Never silently choose between the two plans.
|
|
322
|
+
|
|
302
323
|
### Feasibility Gates (require GitHub lookups; skip in `--spec-only`)
|
|
303
324
|
|
|
304
325
|
#### F1 — Issue type label exists in repo
|
|
@@ -455,6 +476,7 @@ Output is a single fenced text block. Callers parse it; do not add free-form pro
|
|
|
455
476
|
- [PASS|FAIL|N/A] S16 Source Requirement traceability — <one-line reason>
|
|
456
477
|
- [PASS|FAIL|N/A] S17 Improvement measurability — <one-line reason>
|
|
457
478
|
- [PASS|FAIL|N/A] S18 Stateless-pickup dry-run — <one-line reason>
|
|
479
|
+
- [PASS|FAIL|N/A] S19 Branch Plan derivation — <one-line reason>
|
|
458
480
|
|
|
459
481
|
### Feasibility Gates (omit this section when --spec-only)
|
|
460
482
|
- [PASS|FAIL|N/A] F1 Issue type label exists in repo — <one-line reason>
|
|
@@ -100,6 +100,21 @@ Scenario: <name>
|
|
|
100
100
|
Human confirmation replaces the automated annotation with a bare key or
|
|
101
101
|
`Confirmed: <env>`. Skip only for doc/config/type-only issues.]
|
|
102
102
|
|
|
103
|
+
## Branch Plan
|
|
104
|
+
[GENERATED, never hand-authored. Render only when the issue has a Target
|
|
105
|
+
Backend Environment; omit entirely when `runtime_behavior_change = false`
|
|
106
|
+
(doc-only / config-only / type-only) or for an Epic/container — absence is
|
|
107
|
+
correct there. Derive per the `derived-branch-plan` rule: resolve the
|
|
108
|
+
environment, map it forward through `.lisa.config.json` `deploy.branches`,
|
|
109
|
+
and prove the branch exists on the remote. Do not accept caller-supplied
|
|
110
|
+
branches; recompute them. Exactly three lines:
|
|
111
|
+
Branch from: <branch>
|
|
112
|
+
PR into: <branch>
|
|
113
|
+
Derived from: Target Backend Environment <env> via .lisa.config.json deploy.branches
|
|
114
|
+
Both fields name the same branch by construction. A missing, ambiguous, or
|
|
115
|
+
non-unique mapping, or a branch absent from the remote, STOPS the write —
|
|
116
|
+
never default to `main` or the remote default to keep the write alive.]
|
|
117
|
+
|
|
103
118
|
## Sign-in Required
|
|
104
119
|
[Include this section ONLY if the work touches authenticated surfaces.
|
|
105
120
|
Specify: the account/role, where to get the credentials (1Password item,
|
|
@@ -107,6 +107,12 @@ Using the general-purpose agent in Team Lead session, **determine the base branc
|
|
|
107
107
|
- The only normalization is built-in `prod` ↔ `production`, and only when exactly one of those keys exists in `deploy.branches`; normalize to that configured key. No other aliases exist.
|
|
108
108
|
- Never infer from arbitrary branch text, URL paths or query strings, or substrings inside other words or hostname labels. Multiple conflicting signals after normalization **stop** the flow. If there are no signals, resolve the remote default branch (`gh repo view --json defaultBranchRef -q .defaultBranchRef.name`, or `git remote set-head origin -a` then `origin/HEAD`). When it reverse-maps uniquely, write the env-bearing `Assumption:` form; when the reverse-map is not unique, write the branch-only form and continue on the remote default without inventing an environment or blocking solely for that ambiguity. Record the fallback assumption in the plan/tracker artifact.
|
|
109
109
|
2. **Map the resolved environment to a base branch** through `.lisa.config.json` `deploy.branches` — the forward direction of the env-keyed `done` resolution. The selected exact configured key must map uniquely, and the mapped branch must exist on the remote. A missing/ambiguous mapping or remote branch **stops** the flow; never guess or silently fall back.
|
|
110
|
+
- **Reconcile the ticket's `## Branch Plan` (`derived-branch-plan` rule).** The rendered plan is derived output, never input: **recompute** it here from current config and the remote — the mapping you just resolved — and compare. Four arms, no fifth:
|
|
111
|
+
- **Match** → proceed.
|
|
112
|
+
- **Legacy (no plan)** → derive it, **write the assumption onto the ticket as a comment**, then proceed. Visible prose plus a dedupe marker, e.g. ``Branch plan derived for this item: branch from `main`, PR into `main` (Target Backend Environment: production via .lisa.config.json deploy.branches).`` followed by `<!-- [lisa-branch-plan] key=<work-item-ref>::<branch> -->` (marker-dedupe on `<work-item-ref>::<branch>`, so a re-claim adds no duplicate; where a vendor cannot host an HTML comment the visible line alone carries it). **No silent guess** — if the comment cannot be written, that is a stop, because proceeding would make the inference invisible.
|
|
113
|
+
- **Conflict with a human-confirmed environment, or with an existing open PR's base** → **stop under the existing confirmation rules** below. A branch plan never overrides the environment and never supplies the confirmation itself.
|
|
114
|
+
- **Stale (config changed since the plan was rendered)** → current config wins: re-render the section onto the ticket, record the change, and never follow the stale plan. Staleness is output falling behind its input, not a conflict to escalate.
|
|
115
|
+
- Exempt work carries no plan and needs none: `runtime_behavior_change = false` (doc-only / config-only / type-only) and containers have no `## Target Backend Environment` to derive from, so **absence is correct** — never demand or invent one.
|
|
110
116
|
3. **Establish the feature branch off the latest base, conflict-free:**
|
|
111
117
|
- `git fetch origin`.
|
|
112
118
|
- Already on a feature branch with an **open PR** → reuse it. If the PR's base ≠ the resolved base branch, surface the mismatch and re-target only with confirmation — the ticket's environment is the source of truth.
|
|
@@ -341,7 +341,7 @@ Any durable lesson the loop produced is **submitted** to `lisa-persist-learning`
|
|
|
341
341
|
only write path per the `project-learnings` rule) as a candidate; its hostile-default judge — not
|
|
342
342
|
this skill, and not the caller — decides the disposition. A dropped candidate is recorded in
|
|
343
343
|
`Known limits`, never reported as routed or owned. This skill never writes the learnings file,
|
|
344
|
-
|
|
344
|
+
host rules (`.agents/rules/`), or `CLAUDE.md` itself, and never promotes a learning to a higher rung (that
|
|
345
345
|
is the gardener's ticket-gated job).
|
|
346
346
|
|
|
347
347
|
## Idempotency
|
|
@@ -483,5 +483,5 @@ its face, because a single-trajectory loop always has limits.
|
|
|
483
483
|
- **Bounded claims.** One trajectory supports one trajectory's claim. No comparative,
|
|
484
484
|
longitudinal, or population claims; `Known limits` is never empty.
|
|
485
485
|
- **One write path for learnings.** Durable lessons are submitted to `lisa-persist-learning` for
|
|
486
|
-
judgment; this skill never edits the learnings ledger
|
|
486
|
+
judgment; this skill never edits the learnings ledger or any rules tree (host `.agents/rules/` included),
|
|
487
487
|
and never promotes a learning to a higher rung.
|