@codyswann/lisa 2.147.7 → 2.149.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/codex/command-skill-transformer.d.ts +4 -2
- package/dist/codex/command-skill-transformer.d.ts.map +1 -1
- package/dist/codex/command-skill-transformer.js +10 -7
- package/dist/codex/command-skill-transformer.js.map +1 -1
- package/dist/codex/skills-installer.d.ts +1 -2
- package/dist/codex/skills-installer.d.ts.map +1 -1
- package/dist/codex/skills-installer.js +9 -176
- package/dist/codex/skills-installer.js.map +1 -1
- package/dist/core/config.d.ts +4 -3
- package/dist/core/config.d.ts.map +1 -1
- package/dist/core/config.js +1 -0
- package/dist/core/config.js.map +1 -1
- package/dist/core/lisa-skill-sources.d.ts +63 -0
- package/dist/core/lisa-skill-sources.d.ts.map +1 -0
- package/dist/core/lisa-skill-sources.js +197 -0
- package/dist/core/lisa-skill-sources.js.map +1 -0
- package/dist/core/lisa.d.ts +12 -0
- package/dist/core/lisa.d.ts.map +1 -1
- package/dist/core/lisa.js +33 -0
- package/dist/core/lisa.js.map +1 -1
- package/dist/migrations/ensure-jest-rn-mock-accessibility-manager.d.ts +38 -0
- package/dist/migrations/ensure-jest-rn-mock-accessibility-manager.d.ts.map +1 -0
- package/dist/migrations/ensure-jest-rn-mock-accessibility-manager.js +110 -0
- package/dist/migrations/ensure-jest-rn-mock-accessibility-manager.js.map +1 -0
- package/dist/migrations/index.d.ts +1 -0
- package/dist/migrations/index.d.ts.map +1 -1
- package/dist/migrations/index.js +3 -0
- package/dist/migrations/index.js.map +1 -1
- package/dist/opencode/manifest.d.ts +26 -0
- package/dist/opencode/manifest.d.ts.map +1 -0
- package/dist/opencode/manifest.js +94 -0
- package/dist/opencode/manifest.js.map +1 -0
- package/dist/opencode/skills-installer.d.ts +32 -0
- package/dist/opencode/skills-installer.d.ts.map +1 -0
- package/dist/opencode/skills-installer.js +159 -0
- package/dist/opencode/skills-installer.js.map +1 -0
- package/expo/copy-overwrite/knip.json +1 -0
- package/expo/package-lisa/package.lisa.json +0 -2
- 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/rules/reference/leaf-only-lifecycle.md +9 -4
- package/plugins/lisa/skills/github-build-intake/SKILL.md +10 -0
- package/plugins/lisa/skills/jira-build-intake/SKILL.md +10 -0
- package/plugins/lisa/skills/linear-build-intake/SKILL.md +10 -0
- package/plugins/lisa-agy/plugin.json +1 -1
- package/plugins/lisa-agy/skills/github-build-intake/SKILL.md +10 -0
- package/plugins/lisa-agy/skills/jira-build-intake/SKILL.md +10 -0
- package/plugins/lisa-agy/skills/linear-build-intake/SKILL.md +10 -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/rules/reference/leaf-only-lifecycle.md +9 -4
- package/plugins/lisa-copilot/skills/github-build-intake/SKILL.md +10 -0
- package/plugins/lisa-copilot/skills/jira-build-intake/SKILL.md +10 -0
- package/plugins/lisa-copilot/skills/linear-build-intake/SKILL.md +10 -0
- package/plugins/lisa-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cursor/rules/leaf-only-lifecycle-reference.mdc +9 -4
- package/plugins/lisa-cursor/skills/github-build-intake/SKILL.md +10 -0
- package/plugins/lisa-cursor/skills/jira-build-intake/SKILL.md +10 -0
- package/plugins/lisa-cursor/skills/linear-build-intake/SKILL.md +10 -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-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/rules/reference/leaf-only-lifecycle.md +9 -4
- package/plugins/src/base/skills/github-build-intake/SKILL.md +10 -0
- package/plugins/src/base/skills/jira-build-intake/SKILL.md +10 -0
- package/plugins/src/base/skills/linear-build-intake/SKILL.md +10 -0
- package/scripts/internal-opencode-skill-policy.json +3 -0
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { Migration, MigrationContext, MigrationResult } from "./migration.interface.js";
|
|
2
2
|
export type { Migration, MigrationAction, MigrationContext, MigrationResult, } from "./migration.interface.js";
|
|
3
3
|
export { EnsureAuditIgnoreLocalExclusionsMigration } from "./ensure-audit-ignore-local-exclusions.js";
|
|
4
|
+
export { EnsureJestRnMockAccessibilityManagerMigration } from "./ensure-jest-rn-mock-accessibility-manager.js";
|
|
4
5
|
export { EnsureLisaPostinstallMigration } from "./ensure-lisa-postinstall.js";
|
|
5
6
|
export { EnsureTsconfigLocalFilesFallbackMigration } from "./ensure-tsconfig-local-files-fallback.js";
|
|
6
7
|
export { EnsureTsconfigLocalIncludesMigration } from "./ensure-tsconfig-local-includes.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/migrations/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/migrations/index.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EACV,SAAS,EACT,gBAAgB,EAChB,eAAe,EAChB,MAAM,0BAA0B,CAAC;AAElC,YAAY,EACV,SAAS,EACT,eAAe,EACf,gBAAgB,EAChB,eAAe,GAChB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAE,yCAAyC,EAAE,MAAM,2CAA2C,CAAC;AACtG,OAAO,EAAE,6CAA6C,EAAE,MAAM,gDAAgD,CAAC;AAC/G,OAAO,EAAE,8BAA8B,EAAE,MAAM,8BAA8B,CAAC;AAC9E,OAAO,EAAE,yCAAyC,EAAE,MAAM,2CAA2C,CAAC;AACtG,OAAO,EAAE,oCAAoC,EAAE,MAAM,qCAAqC,CAAC;AAE3F;;GAEG;AACH,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAuB;IAElD;;;OAGG;gBACS,UAAU,CAAC,EAAE,SAAS,SAAS,EAAE;IAU7C;;;OAGG;IACH,MAAM,IAAI,SAAS,SAAS,EAAE;IAI9B;;;;OAIG;IACG,mBAAmB,CAAC,GAAG,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC;IAQ/D;;;;OAIG;IACG,MAAM,CAAC,GAAG,EAAE,gBAAgB,GAAG,OAAO,CAAC,SAAS,eAAe,EAAE,CAAC;CAazE;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,IAAI,iBAAiB,CAE3D"}
|
package/dist/migrations/index.js
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { EnsureAuditIgnoreLocalExclusionsMigration } from "./ensure-audit-ignore-local-exclusions.js";
|
|
2
|
+
import { EnsureJestRnMockAccessibilityManagerMigration } from "./ensure-jest-rn-mock-accessibility-manager.js";
|
|
2
3
|
import { EnsureLisaPostinstallMigration } from "./ensure-lisa-postinstall.js";
|
|
3
4
|
import { EnsureTsconfigLocalFilesFallbackMigration } from "./ensure-tsconfig-local-files-fallback.js";
|
|
4
5
|
import { EnsureTsconfigLocalIncludesMigration } from "./ensure-tsconfig-local-includes.js";
|
|
5
6
|
export { EnsureAuditIgnoreLocalExclusionsMigration } from "./ensure-audit-ignore-local-exclusions.js";
|
|
7
|
+
export { EnsureJestRnMockAccessibilityManagerMigration } from "./ensure-jest-rn-mock-accessibility-manager.js";
|
|
6
8
|
export { EnsureLisaPostinstallMigration } from "./ensure-lisa-postinstall.js";
|
|
7
9
|
export { EnsureTsconfigLocalFilesFallbackMigration } from "./ensure-tsconfig-local-files-fallback.js";
|
|
8
10
|
export { EnsureTsconfigLocalIncludesMigration } from "./ensure-tsconfig-local-includes.js";
|
|
@@ -20,6 +22,7 @@ export class MigrationRegistry {
|
|
|
20
22
|
new EnsureTsconfigLocalIncludesMigration(),
|
|
21
23
|
new EnsureTsconfigLocalFilesFallbackMigration(),
|
|
22
24
|
new EnsureAuditIgnoreLocalExclusionsMigration(),
|
|
25
|
+
new EnsureJestRnMockAccessibilityManagerMigration(),
|
|
23
26
|
new EnsureLisaPostinstallMigration(),
|
|
24
27
|
];
|
|
25
28
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/migrations/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,yCAAyC,EAAE,MAAM,2CAA2C,CAAC;AACtG,OAAO,EAAE,8BAA8B,EAAE,MAAM,8BAA8B,CAAC;AAC9E,OAAO,EAAE,yCAAyC,EAAE,MAAM,2CAA2C,CAAC;AACtG,OAAO,EAAE,oCAAoC,EAAE,MAAM,qCAAqC,CAAC;AAa3F,OAAO,EAAE,yCAAyC,EAAE,MAAM,2CAA2C,CAAC;AACtG,OAAO,EAAE,8BAA8B,EAAE,MAAM,8BAA8B,CAAC;AAC9E,OAAO,EAAE,yCAAyC,EAAE,MAAM,2CAA2C,CAAC;AACtG,OAAO,EAAE,oCAAoC,EAAE,MAAM,qCAAqC,CAAC;AAE3F;;GAEG;AACH,MAAM,OAAO,iBAAiB;IACX,UAAU,CAAuB;IAElD;;;OAGG;IACH,YAAY,UAAiC;QAC3C,IAAI,CAAC,UAAU,GAAG,UAAU,IAAI;YAC9B,IAAI,oCAAoC,EAAE;YAC1C,IAAI,yCAAyC,EAAE;YAC/C,IAAI,yCAAyC,EAAE;YAC/C,IAAI,8BAA8B,EAAE;SACrC,CAAC;IACJ,CAAC;IAED;;;OAGG;IACH,MAAM;QACJ,OAAO,IAAI,CAAC,UAAU,CAAC;IACzB,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,mBAAmB,CAAC,GAAqB;QAC7C,KAAK,MAAM,SAAS,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;YACxC,IAAI,SAAS,CAAC,gBAAgB,EAAE,CAAC;gBAC/B,MAAM,SAAS,CAAC,gBAAgB,CAAC,GAAG,CAAC,CAAC;YACxC,CAAC;QACH,CAAC;IACH,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,MAAM,CAAC,GAAqB;QAChC,MAAM,OAAO,GAAsB,EAAE,CAAC;QACtC,KAAK,MAAM,SAAS,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;YACxC,MAAM,SAAS,GAAG,MAAM,SAAS,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;YAC/C,IAAI,CAAC,SAAS,EAAE,CAAC;gBACf,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC,CAAC;gBAC1D,SAAS;YACX,CAAC;YACD,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;YAC1C,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACvB,CAAC;QACD,OAAO,OAAO,CAAC;IACjB,CAAC;CACF;AAED;;;GAGG;AACH,MAAM,UAAU,uBAAuB;IACrC,OAAO,IAAI,iBAAiB,EAAE,CAAC;AACjC,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/migrations/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,yCAAyC,EAAE,MAAM,2CAA2C,CAAC;AACtG,OAAO,EAAE,6CAA6C,EAAE,MAAM,gDAAgD,CAAC;AAC/G,OAAO,EAAE,8BAA8B,EAAE,MAAM,8BAA8B,CAAC;AAC9E,OAAO,EAAE,yCAAyC,EAAE,MAAM,2CAA2C,CAAC;AACtG,OAAO,EAAE,oCAAoC,EAAE,MAAM,qCAAqC,CAAC;AAa3F,OAAO,EAAE,yCAAyC,EAAE,MAAM,2CAA2C,CAAC;AACtG,OAAO,EAAE,6CAA6C,EAAE,MAAM,gDAAgD,CAAC;AAC/G,OAAO,EAAE,8BAA8B,EAAE,MAAM,8BAA8B,CAAC;AAC9E,OAAO,EAAE,yCAAyC,EAAE,MAAM,2CAA2C,CAAC;AACtG,OAAO,EAAE,oCAAoC,EAAE,MAAM,qCAAqC,CAAC;AAE3F;;GAEG;AACH,MAAM,OAAO,iBAAiB;IACX,UAAU,CAAuB;IAElD;;;OAGG;IACH,YAAY,UAAiC;QAC3C,IAAI,CAAC,UAAU,GAAG,UAAU,IAAI;YAC9B,IAAI,oCAAoC,EAAE;YAC1C,IAAI,yCAAyC,EAAE;YAC/C,IAAI,yCAAyC,EAAE;YAC/C,IAAI,6CAA6C,EAAE;YACnD,IAAI,8BAA8B,EAAE;SACrC,CAAC;IACJ,CAAC;IAED;;;OAGG;IACH,MAAM;QACJ,OAAO,IAAI,CAAC,UAAU,CAAC;IACzB,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,mBAAmB,CAAC,GAAqB;QAC7C,KAAK,MAAM,SAAS,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;YACxC,IAAI,SAAS,CAAC,gBAAgB,EAAE,CAAC;gBAC/B,MAAM,SAAS,CAAC,gBAAgB,CAAC,GAAG,CAAC,CAAC;YACxC,CAAC;QACH,CAAC;IACH,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,MAAM,CAAC,GAAqB;QAChC,MAAM,OAAO,GAAsB,EAAE,CAAC;QACtC,KAAK,MAAM,SAAS,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;YACxC,MAAM,SAAS,GAAG,MAAM,SAAS,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;YAC/C,IAAI,CAAC,SAAS,EAAE,CAAC;gBACf,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC,CAAC;gBAC1D,SAAS;YACX,CAAC;YACD,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;YAC1C,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACvB,CAAC;QACD,OAAO,OAAO,CAAC;IACjB,CAAC;CACF;AAED;;;GAGG;AACH,MAAM,UAAU,uBAAuB;IACrC,OAAO,IAAI,iBAAiB,EAAE,CAAC;AACjC,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/** Config directory OpenCode reads project-scope artifacts from */
|
|
2
|
+
export declare const OPENCODE_CONFIG_DIR = ".opencode";
|
|
3
|
+
/** Filename of the Lisa-managed manifest, relative to `.opencode/` */
|
|
4
|
+
export declare const LISA_MANAGED_MANIFEST_FILENAME = ".lisa-managed.json";
|
|
5
|
+
/** Schema of `.opencode/.lisa-managed.json` */
|
|
6
|
+
export interface LisaManagedManifest {
|
|
7
|
+
/**
|
|
8
|
+
* Paths of files Lisa wrote, relative to the `.opencode/` directory.
|
|
9
|
+
* Used to identify which files to delete when they stop being shipped.
|
|
10
|
+
*/
|
|
11
|
+
readonly files: readonly string[];
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Read the Lisa-managed manifest from `<destDir>/.opencode/.lisa-managed.json`.
|
|
15
|
+
* Returns an empty manifest if the file doesn't exist.
|
|
16
|
+
* @param destDir - Absolute path to the destination project root.
|
|
17
|
+
* @returns Parsed manifest (with empty file list if absent).
|
|
18
|
+
*/
|
|
19
|
+
export declare function readManagedManifest(destDir: string): Promise<LisaManagedManifest>;
|
|
20
|
+
/**
|
|
21
|
+
* Write the Lisa-managed manifest to disk, replacing any existing content.
|
|
22
|
+
* @param destDir - Absolute path to the destination project root.
|
|
23
|
+
* @param files - List of relative-to-`.opencode/` file paths Lisa shipped.
|
|
24
|
+
*/
|
|
25
|
+
export declare function writeManagedManifest(destDir: string, files: readonly string[]): Promise<void>;
|
|
26
|
+
//# sourceMappingURL=manifest.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../../src/opencode/manifest.ts"],"names":[],"mappings":"AAmBA,mEAAmE;AACnE,eAAO,MAAM,mBAAmB,cAAc,CAAC;AAE/C,sEAAsE;AACtE,eAAO,MAAM,8BAA8B,uBAAuB,CAAC;AAEnE,+CAA+C;AAC/C,MAAM,WAAW,mBAAmB;IAClC;;;OAGG;IACH,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;CACnC;AAED;;;;;GAKG;AACH,wBAAsB,mBAAmB,CACvC,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,mBAAmB,CAAC,CAY9B;AAED;;;;GAIG;AACH,wBAAsB,oBAAoB,CACxC,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,SAAS,MAAM,EAAE,GACvB,OAAO,CAAC,IAAI,CAAC,CAYf"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tracking manifest for Lisa-managed OpenCode artifacts.
|
|
3
|
+
*
|
|
4
|
+
* When Lisa emits files into a host project's `.opencode/` directory, it needs
|
|
5
|
+
* a way to identify those files on the next run so:
|
|
6
|
+
* 1. Stale files (skills Lisa stopped shipping) can be cleaned up.
|
|
7
|
+
* 2. Host-authored files (custom skills/agents the user added) are never
|
|
8
|
+
* accidentally overwritten or deleted.
|
|
9
|
+
*
|
|
10
|
+
* The manifest lives at `.opencode/.lisa-managed.json` in the destination
|
|
11
|
+
* project. It is checked into the host repo so the cleanup behavior is
|
|
12
|
+
* deterministic across machines. This mirrors `src/codex/manifest.ts`; the only
|
|
13
|
+
* difference is the config directory (`.opencode/` vs `.codex/`).
|
|
14
|
+
* @module opencode/manifest
|
|
15
|
+
*/
|
|
16
|
+
import * as fse from "fs-extra";
|
|
17
|
+
import { readFile, writeFile } from "node:fs/promises";
|
|
18
|
+
import * as path from "node:path";
|
|
19
|
+
/** Config directory OpenCode reads project-scope artifacts from */
|
|
20
|
+
export const OPENCODE_CONFIG_DIR = ".opencode";
|
|
21
|
+
/** Filename of the Lisa-managed manifest, relative to `.opencode/` */
|
|
22
|
+
export const LISA_MANAGED_MANIFEST_FILENAME = ".lisa-managed.json";
|
|
23
|
+
/**
|
|
24
|
+
* Read the Lisa-managed manifest from `<destDir>/.opencode/.lisa-managed.json`.
|
|
25
|
+
* Returns an empty manifest if the file doesn't exist.
|
|
26
|
+
* @param destDir - Absolute path to the destination project root.
|
|
27
|
+
* @returns Parsed manifest (with empty file list if absent).
|
|
28
|
+
*/
|
|
29
|
+
export async function readManagedManifest(destDir) {
|
|
30
|
+
const manifestPath = path.join(destDir, OPENCODE_CONFIG_DIR, LISA_MANAGED_MANIFEST_FILENAME);
|
|
31
|
+
if (!(await fse.pathExists(manifestPath))) {
|
|
32
|
+
return { files: [] };
|
|
33
|
+
}
|
|
34
|
+
const raw = await readFile(manifestPath, "utf8");
|
|
35
|
+
const parsed = JSON.parse(raw);
|
|
36
|
+
return validateManifest(parsed, manifestPath);
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Write the Lisa-managed manifest to disk, replacing any existing content.
|
|
40
|
+
* @param destDir - Absolute path to the destination project root.
|
|
41
|
+
* @param files - List of relative-to-`.opencode/` file paths Lisa shipped.
|
|
42
|
+
*/
|
|
43
|
+
export async function writeManagedManifest(destDir, files) {
|
|
44
|
+
const configDir = path.join(destDir, OPENCODE_CONFIG_DIR);
|
|
45
|
+
await fse.ensureDir(configDir);
|
|
46
|
+
const manifestPath = path.join(configDir, LISA_MANAGED_MANIFEST_FILENAME);
|
|
47
|
+
const manifest = {
|
|
48
|
+
files: [...files].sort((a, b) => a.localeCompare(b)),
|
|
49
|
+
};
|
|
50
|
+
await writeFile(manifestPath, `${JSON.stringify(manifest, null, 2)}\n`, "utf8");
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Type-guard validator. Throws on shape errors so a corrupted manifest is
|
|
54
|
+
* surfaced rather than silently producing data loss.
|
|
55
|
+
* @param parsed - Untrusted JSON value.
|
|
56
|
+
* @param manifestPath - Path used in error messages.
|
|
57
|
+
* @returns Validated manifest.
|
|
58
|
+
*/
|
|
59
|
+
function validateManifest(parsed, manifestPath) {
|
|
60
|
+
if (parsed === null || typeof parsed !== "object") {
|
|
61
|
+
throw new Error(`Invalid Lisa-managed manifest at ${manifestPath}: expected JSON object`);
|
|
62
|
+
}
|
|
63
|
+
const obj = parsed;
|
|
64
|
+
if (!Array.isArray(obj.files)) {
|
|
65
|
+
throw new Error(`Invalid Lisa-managed manifest at ${manifestPath}: expected "files" array`);
|
|
66
|
+
}
|
|
67
|
+
const files = obj.files.map((file, index) => validateManifestPath(file, index, manifestPath));
|
|
68
|
+
return { files: Object.freeze(files) };
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Validate one manifest entry is a normalized, in-tree relative path.
|
|
72
|
+
*
|
|
73
|
+
* The manifest drives stale-file deletion, so a traversal or absolute entry
|
|
74
|
+
* (`../../etc`, `/abs`, mixed `\` separators) could expand the delete scope
|
|
75
|
+
* beyond the Lisa skill boundary. Reject those here so no consumer ever acts on
|
|
76
|
+
* an unsafe path.
|
|
77
|
+
* @param file - Untrusted entry from the parsed `files` array.
|
|
78
|
+
* @param index - Position in the array (for error messages).
|
|
79
|
+
* @param manifestPath - Path used in error messages.
|
|
80
|
+
* @returns The validated, forward-slash-normalized relative path.
|
|
81
|
+
*/
|
|
82
|
+
function validateManifestPath(file, index, manifestPath) {
|
|
83
|
+
if (typeof file !== "string") {
|
|
84
|
+
throw new Error(`Invalid Lisa-managed manifest at ${manifestPath}: "files[${index}]" must be a string`);
|
|
85
|
+
}
|
|
86
|
+
const normalized = file.replaceAll("\\", "/");
|
|
87
|
+
const segments = normalized.split("/");
|
|
88
|
+
if (path.posix.isAbsolute(normalized) ||
|
|
89
|
+
segments.some(seg => seg === "" || seg === "." || seg === "..")) {
|
|
90
|
+
throw new Error(`Invalid Lisa-managed manifest at ${manifestPath}: "files[${index}]" must be a normalized relative path`);
|
|
91
|
+
}
|
|
92
|
+
return normalized;
|
|
93
|
+
}
|
|
94
|
+
//# sourceMappingURL=manifest.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manifest.js","sourceRoot":"","sources":["../../src/opencode/manifest.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/** Subdirectory inside `.opencode/skills/` where Lisa-owned skills live */
|
|
2
|
+
export declare const LISA_SKILLS_SUBDIR: string;
|
|
3
|
+
/** Result of one skill copy */
|
|
4
|
+
export interface InstalledSkill {
|
|
5
|
+
/** Skill name (matches the SKILL.md `name` frontmatter) */
|
|
6
|
+
readonly name: string;
|
|
7
|
+
/** Source kind: bundled skill folder or generated from command */
|
|
8
|
+
readonly source: "bundled" | "command";
|
|
9
|
+
/** Path written, relative to `.opencode/` */
|
|
10
|
+
readonly relativePath: string;
|
|
11
|
+
}
|
|
12
|
+
/** Aggregated result */
|
|
13
|
+
export interface SkillsInstallResult {
|
|
14
|
+
readonly installed: readonly InstalledSkill[];
|
|
15
|
+
readonly managedFiles: readonly string[];
|
|
16
|
+
/** Skill directories deleted because Lisa stopped shipping them */
|
|
17
|
+
readonly deleted: readonly string[];
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Install all Lisa-bundled skills + command-derived skills into
|
|
21
|
+
* `.opencode/skills/lisa/`.
|
|
22
|
+
*
|
|
23
|
+
* Stale skills (in the previous manifest but no longer in Lisa's catalog) are
|
|
24
|
+
* deleted so renames in the source tree don't leave orphan directories behind.
|
|
25
|
+
* @param lisaDir - Absolute path to the Lisa repo root.
|
|
26
|
+
* @param destDir - Absolute path to the host project root.
|
|
27
|
+
* @param previousManagedFiles - Files Lisa managed on the previous run
|
|
28
|
+
* (relative to `.opencode/`); used to detect stale skill directories.
|
|
29
|
+
* @returns Result describing installed skills + managed files + deletions.
|
|
30
|
+
*/
|
|
31
|
+
export declare function installSkills(lisaDir: string, destDir: string, previousManagedFiles: readonly string[]): Promise<SkillsInstallResult>;
|
|
32
|
+
//# sourceMappingURL=skills-installer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skills-installer.d.ts","sourceRoot":"","sources":["../../src/opencode/skills-installer.ts"],"names":[],"mappings":"AAsCA,2EAA2E;AAC3E,eAAO,MAAM,kBAAkB,QAA8B,CAAC;AAW9D,+BAA+B;AAC/B,MAAM,WAAW,cAAc;IAC7B,2DAA2D;IAC3D,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,kEAAkE;IAClE,QAAQ,CAAC,MAAM,EAAE,SAAS,GAAG,SAAS,CAAC;IACvC,6CAA6C;IAC7C,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;CAC/B;AAED,wBAAwB;AACxB,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,SAAS,EAAE,SAAS,cAAc,EAAE,CAAC;IAC9C,QAAQ,CAAC,YAAY,EAAE,SAAS,MAAM,EAAE,CAAC;IACzC,mEAAmE;IACnE,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;CACrC;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,aAAa,CACjC,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,EACf,oBAAoB,EAAE,SAAS,MAAM,EAAE,GACtC,OAAO,CAAC,mBAAmB,CAAC,CA6C9B"}
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Install Lisa-bundled skills into a host project's `.opencode/skills/lisa/`.
|
|
3
|
+
*
|
|
4
|
+
* OpenCode discovers skills (the open Agent Skills format: SKILL.md + optional
|
|
5
|
+
* siblings) natively from `.opencode/skills/<name>/`, walking up from the cwd to
|
|
6
|
+
* the git worktree (see opencode.ai/docs/skills). It ALSO reads `.claude/skills`
|
|
7
|
+
* and `.agents/skills`, but Lisa writes into the OpenCode-owned `.opencode/`
|
|
8
|
+
* tree so its artifacts never collide with a Claude install on the same machine
|
|
9
|
+
* (OpenCode dedupes duplicate skill names with a warning — verified-by-run on
|
|
10
|
+
* opencode 1.16.2).
|
|
11
|
+
*
|
|
12
|
+
* What this installs:
|
|
13
|
+
* 1. Lisa-bundled skill folders from `plugins/<p>/skills/<n>/` copied verbatim
|
|
14
|
+
* to `.opencode/skills/lisa/<n>/` (OpenCode reads SKILL.md verbatim — no
|
|
15
|
+
* transform needed, unlike the Codex TOML/openai.yaml path).
|
|
16
|
+
* 2. Lisa commands converted to skills with a `lisa-` prefix, since the safest
|
|
17
|
+
* cross-runtime carrier for a Lisa command is a self-complete skill.
|
|
18
|
+
*
|
|
19
|
+
* Source discovery (walking the plugin tree, dedup, denylist) is shared with the
|
|
20
|
+
* Codex overlay via `core/lisa-skill-sources`.
|
|
21
|
+
* @module opencode/skills-installer
|
|
22
|
+
*/
|
|
23
|
+
import * as fse from "fs-extra";
|
|
24
|
+
import { mkdir, copyFile, readFile, rm, writeFile } from "node:fs/promises";
|
|
25
|
+
import * as path from "node:path";
|
|
26
|
+
import { discoverBundledSkills, discoverLisaCommands, loadSkillDenylist, } from "../core/lisa-skill-sources.js";
|
|
27
|
+
import { convertCommandToSkill } from "../codex/command-skill-transformer.js";
|
|
28
|
+
import { OPENCODE_CONFIG_DIR } from "./manifest.js";
|
|
29
|
+
/** Runtime label threaded into generated command-as-skill compatibility notes */
|
|
30
|
+
const OPENCODE_RUNTIME_LABEL = "OpenCode";
|
|
31
|
+
/** Subdirectory inside `.opencode/skills/` where Lisa-owned skills live */
|
|
32
|
+
export const LISA_SKILLS_SUBDIR = path.join("skills", "lisa");
|
|
33
|
+
/** Filename of the skill manifest at the root of every skill folder */
|
|
34
|
+
const SKILL_MD_FILENAME = "SKILL.md";
|
|
35
|
+
/** Path to the OpenCode skill distribution policy, relative to the Lisa root */
|
|
36
|
+
const INTERNAL_OPENCODE_SKILL_POLICY_RELATIVE_PATH = path.join("scripts", "internal-opencode-skill-policy.json");
|
|
37
|
+
/**
|
|
38
|
+
* Install all Lisa-bundled skills + command-derived skills into
|
|
39
|
+
* `.opencode/skills/lisa/`.
|
|
40
|
+
*
|
|
41
|
+
* Stale skills (in the previous manifest but no longer in Lisa's catalog) are
|
|
42
|
+
* deleted so renames in the source tree don't leave orphan directories behind.
|
|
43
|
+
* @param lisaDir - Absolute path to the Lisa repo root.
|
|
44
|
+
* @param destDir - Absolute path to the host project root.
|
|
45
|
+
* @param previousManagedFiles - Files Lisa managed on the previous run
|
|
46
|
+
* (relative to `.opencode/`); used to detect stale skill directories.
|
|
47
|
+
* @returns Result describing installed skills + managed files + deletions.
|
|
48
|
+
*/
|
|
49
|
+
export async function installSkills(lisaDir, destDir, previousManagedFiles) {
|
|
50
|
+
const skillsDir = path.join(destDir, OPENCODE_CONFIG_DIR, LISA_SKILLS_SUBDIR);
|
|
51
|
+
await fse.ensureDir(skillsDir);
|
|
52
|
+
const denylistedSkills = await loadSkillDenylist(lisaDir, INTERNAL_OPENCODE_SKILL_POLICY_RELATIVE_PATH);
|
|
53
|
+
// Step 1: bundled skills
|
|
54
|
+
const bundled = await discoverBundledSkills(lisaDir, denylistedSkills);
|
|
55
|
+
const bundledInstalls = await Promise.all(bundled.map(source => copyBundledSkill(source, skillsDir)));
|
|
56
|
+
const bundledFiles = bundled.flatMap(source => source.files.map(file => path.join(LISA_SKILLS_SUBDIR, source.skillName, file)));
|
|
57
|
+
// Step 2: command-as-skill conversions
|
|
58
|
+
const commandSkills = await discoverLisaCommands(lisaDir);
|
|
59
|
+
const commandInstalls = await Promise.all(commandSkills.map(cmd => emitCommandAsSkill(cmd, skillsDir)));
|
|
60
|
+
const commandFiles = commandInstalls.map(install => path.join(LISA_SKILLS_SUBDIR, install.name, SKILL_MD_FILENAME));
|
|
61
|
+
const installed = [
|
|
62
|
+
...bundledInstalls,
|
|
63
|
+
...commandInstalls,
|
|
64
|
+
];
|
|
65
|
+
// Step 3: delete stale skill directories
|
|
66
|
+
const deleted = await deleteStaleSkills(previousManagedFiles, new Set(installed.map(s => s.name)), destDir);
|
|
67
|
+
return {
|
|
68
|
+
installed: Object.freeze(installed),
|
|
69
|
+
managedFiles: Object.freeze([...bundledFiles, ...commandFiles]),
|
|
70
|
+
deleted: Object.freeze(deleted),
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Delete skill directories that were Lisa-managed last run but aren't shipped
|
|
75
|
+
* this run. Identifies skill names from the previous manifest by looking for
|
|
76
|
+
* paths inside `.opencode/skills/lisa/<name>/...`.
|
|
77
|
+
*
|
|
78
|
+
* Whole directories are removed (not individual files) so siblings the host
|
|
79
|
+
* accidentally added inside a Lisa skill folder also disappear — Lisa owns the
|
|
80
|
+
* directory boundary, not just specific files.
|
|
81
|
+
* @param previousManagedFiles - Files Lisa managed on the previous run
|
|
82
|
+
* (relative to `.opencode/`).
|
|
83
|
+
* @param currentSkillNames - Skill names Lisa is shipping this run.
|
|
84
|
+
* @param destDir - Absolute path to the host project root.
|
|
85
|
+
* @returns Sorted list of stale skill names that were deleted.
|
|
86
|
+
*/
|
|
87
|
+
async function deleteStaleSkills(previousManagedFiles, currentSkillNames, destDir) {
|
|
88
|
+
const lisaSkillsPrefix = `${LISA_SKILLS_SUBDIR}${path.sep}`;
|
|
89
|
+
const previousSkillNames = extractPreviousSkillNames(previousManagedFiles, lisaSkillsPrefix);
|
|
90
|
+
const stale = previousSkillNames.filter(name => !currentSkillNames.has(name));
|
|
91
|
+
await Promise.all(stale.map(async (name) => {
|
|
92
|
+
const absPath = path.join(destDir, OPENCODE_CONFIG_DIR, LISA_SKILLS_SUBDIR, name);
|
|
93
|
+
if (await fse.pathExists(absPath)) {
|
|
94
|
+
await rm(absPath, { recursive: true, force: true });
|
|
95
|
+
}
|
|
96
|
+
}));
|
|
97
|
+
return Object.freeze([...stale].sort((a, b) => a.localeCompare(b)));
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Pick the unique skill-folder names out of the previous manifest's file list —
|
|
101
|
+
* every path inside `.opencode/skills/lisa/<name>/...` contributes `<name>`.
|
|
102
|
+
* @param previousManagedFiles - Files Lisa managed on the previous run.
|
|
103
|
+
* @param lisaSkillsPrefix - The path prefix that identifies Lisa skill files.
|
|
104
|
+
* @returns Unique skill names extracted from those paths.
|
|
105
|
+
*/
|
|
106
|
+
function extractPreviousSkillNames(previousManagedFiles, lisaSkillsPrefix) {
|
|
107
|
+
const names = previousManagedFiles
|
|
108
|
+
.filter(file => file.startsWith(lisaSkillsPrefix))
|
|
109
|
+
.map(file => file.slice(lisaSkillsPrefix.length).split(path.sep)[0])
|
|
110
|
+
.filter((name) => Boolean(name));
|
|
111
|
+
return Array.from(new Set(names));
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Copy one bundled skill folder verbatim into `.opencode/skills/lisa/`.
|
|
115
|
+
* @param source - Bundled-skill source to copy.
|
|
116
|
+
* @param skillsDir - Absolute path to `<destDir>/.opencode/skills/lisa/`.
|
|
117
|
+
* @returns Result describing the installed skill.
|
|
118
|
+
*/
|
|
119
|
+
async function copyBundledSkill(source, skillsDir) {
|
|
120
|
+
const destSkillDir = path.join(skillsDir, source.skillName);
|
|
121
|
+
// Clean-replace the Lisa-owned skill folder before copying so files removed
|
|
122
|
+
// from the source between releases don't linger inside a surviving skill.
|
|
123
|
+
// Lisa owns this directory boundary (host customizations belong outside it).
|
|
124
|
+
await rm(destSkillDir, { recursive: true, force: true });
|
|
125
|
+
await fse.ensureDir(destSkillDir);
|
|
126
|
+
await Promise.all(source.files.map(async (file) => {
|
|
127
|
+
const srcPath = path.join(source.sourceDir, file);
|
|
128
|
+
const destPath = path.join(destSkillDir, file);
|
|
129
|
+
await mkdir(path.dirname(destPath), { recursive: true });
|
|
130
|
+
await copyFile(srcPath, destPath);
|
|
131
|
+
}));
|
|
132
|
+
return {
|
|
133
|
+
name: source.skillName,
|
|
134
|
+
source: "bundled",
|
|
135
|
+
relativePath: path.join(LISA_SKILLS_SUBDIR, source.skillName),
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Convert a Lisa command Markdown file into an OpenCode skill.
|
|
140
|
+
*
|
|
141
|
+
* The command body becomes the skill body, with `$ARGUMENTS` replaced by an
|
|
142
|
+
* explicit instruction to use the user's surrounding request as arguments.
|
|
143
|
+
* @param cmd - Discovered command source.
|
|
144
|
+
* @param skillsDir - Absolute path to `<destDir>/.opencode/skills/lisa/`.
|
|
145
|
+
* @returns Result describing the installed (command-derived) skill.
|
|
146
|
+
*/
|
|
147
|
+
async function emitCommandAsSkill(cmd, skillsDir) {
|
|
148
|
+
const sourceContent = await readFile(cmd.sourcePath, "utf8");
|
|
149
|
+
const skillContent = convertCommandToSkill(sourceContent, cmd.skillName, cmd.displayName, OPENCODE_RUNTIME_LABEL);
|
|
150
|
+
const destSkillDir = path.join(skillsDir, cmd.skillName);
|
|
151
|
+
await fse.ensureDir(destSkillDir);
|
|
152
|
+
await writeFile(path.join(destSkillDir, SKILL_MD_FILENAME), skillContent, "utf8");
|
|
153
|
+
return {
|
|
154
|
+
name: cmd.skillName,
|
|
155
|
+
source: "command",
|
|
156
|
+
relativePath: path.join(LISA_SKILLS_SUBDIR, cmd.skillName),
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
//# sourceMappingURL=skills-installer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skills-installer.js","sourceRoot":"","sources":["../../src/opencode/skills-installer.ts"],"names":[],"mappings":"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"}
|
|
@@ -119,8 +119,6 @@
|
|
|
119
119
|
"@legendapp/motion": "^2.4.0",
|
|
120
120
|
"@react-native-async-storage/async-storage": "2.2.0",
|
|
121
121
|
"@react-native-masked-view/masked-view": "^0.3.2",
|
|
122
|
-
"@react-navigation/drawer": "^7.5.0",
|
|
123
|
-
"@react-navigation/elements": "^1.3.31",
|
|
124
122
|
"@sentry/react-native": "~7.11.0",
|
|
125
123
|
"@shopify/flash-list": "2.0.2",
|
|
126
124
|
"@shopify/react-native-skia": "2.6.2",
|
package/package.json
CHANGED
|
@@ -84,7 +84,7 @@
|
|
|
84
84
|
"lodash": ">=4.18.1"
|
|
85
85
|
},
|
|
86
86
|
"name": "@codyswann/lisa",
|
|
87
|
-
"version": "2.
|
|
87
|
+
"version": "2.149.1",
|
|
88
88
|
"description": "Claude Code governance framework that applies guardrails, guidance, and automated enforcement to projects",
|
|
89
89
|
"main": "dist/index.js",
|
|
90
90
|
"exports": {
|
|
@@ -58,7 +58,7 @@ So the exception is narrow only at the top: childlessness promotes every type **
|
|
|
58
58
|
|
|
59
59
|
## Parent status rollup (the state machine)
|
|
60
60
|
|
|
61
|
-
A parent/container never sets its own lifecycle state; it **derives** it from the roll-up of its children's states. Rollup is evaluated whenever a child transitions (or when intake observes the child set
|
|
61
|
+
A parent/container never sets its own lifecycle state; it **derives** it from the roll-up of its children's states. Rollup is evaluated whenever a child transitions — the **forward** arm runs in each `*-build-intake` done step the moment a leaf reaches `done`, walking the leaf's ancestor chain (see Citation → Rollup) — or when intake observes the child set, with `repair-intake` as the **recovery** net for parents left un-rolled. Using the canonical build-lifecycle roles from `config-resolution` (`ready`, `claimed`, `review`, `blocked`, `done`):
|
|
62
62
|
|
|
63
63
|
Evaluate over the **env ladder** `in-progress < dev < staging < production` — the ordered keys of the project's env-keyed `done` map, with `claimed`/`review` as the rung below the first env (a single-environment project has only the `production` rung). Take the **first** match:
|
|
64
64
|
|
|
@@ -114,9 +114,14 @@ Skills that enforce this invariant or perform rollup cite this rule by slug (the
|
|
|
114
114
|
- **Decomposition / write** (`*-to-tracker`, `*-write-*`) — apply the `ready` role to leaves only; never to containers.
|
|
115
115
|
- **Validate** (`*-validate-*`) — FAIL a container carrying the build-ready role; FAIL a childless **Epic** marked build-ready (a childless Story/Spike is a valid leaf and passes).
|
|
116
116
|
- **Build intake** (`*-build-intake`, `tracker-build-intake`) — dispatch leaves only; move or safe-block containers with stale build-ready roles according to vendor lifecycle semantics.
|
|
117
|
-
- **Rollup** — derive parent state from children per the state machine above.
|
|
118
|
-
|
|
119
|
-
|
|
117
|
+
- **Rollup** — derive parent state from children per the state machine above. The **forward**
|
|
118
|
+
rollup fires the moment a leaf transitions to `done`: each `*-build-intake` done step (`3d.1`)
|
|
119
|
+
walks the leaf's ancestor chain and invokes `*-sync --rollup`, so a parent advances/closes as
|
|
120
|
+
soon as its last required child ships rather than waiting on a cron. `*-sync --rollup` is the
|
|
121
|
+
single rollup implementation; `repair-intake` calls the same path as the **recovery** net,
|
|
122
|
+
closing out parent/container rollups that were left open after every required child became
|
|
123
|
+
terminal — e.g. children closed outside the Lisa flow (external automation), or completed while
|
|
124
|
+
no forward `*-build-intake` cycle ran.
|
|
120
125
|
- **Terminal native closure** (`*-build-intake`, `repair-intake`, terminal helpers) — after a leaf
|
|
121
126
|
or all-terminal rollup parent reaches the true terminal `done` role, finalize it through the
|
|
122
127
|
provider's native close / complete / resolve mechanism where available; never do this for
|
|
@@ -300,6 +300,16 @@ This close is idempotent: if the issue is already closed, record that native clo
|
|
|
300
300
|
|
|
301
301
|
For any non-Success outcome, do NOT transition. The issue sits in `$CLAIMED` (or wherever `lisa:github-agent` left it) — humans take it from there.
|
|
302
302
|
|
|
303
|
+
#### 3d.1 Roll up the parent chain (forward rollup)
|
|
304
|
+
|
|
305
|
+
Run this **only after a successful `$DONE` transition in 3d** (the leaf actually reached an env — intermediate or terminal). This is the **forward** arm of the `leaf-only-lifecycle` rule's *"rollup is evaluated whenever a child transitions"* requirement: a leaf reaching `$DONE` is exactly such a transition, so its parent's derived state may now have changed — the last open child of a Story just shipped, so the Story rolls up to `$DONE` and closes, which may in turn complete its Epic. Without this step a fully-built parent stays open until the recovery `lisa:repair-intake` cron happens to run.
|
|
306
|
+
|
|
307
|
+
1. Resolve the leaf's parent using the same hierarchy `lisa:github-read-issue` uses — native sub-issue parent first (GraphQL `parent`), then body parentage (`Parent: #<n>` / `Parent Epic: #<n>`). If the leaf has no parent, skip — nothing to roll up.
|
|
308
|
+
2. Walk **up the ancestor chain bottom-up**: for the immediate parent, then its parent, and so on, invoke `lisa:github-sync <org>/<repo>#<ancestor> --rollup`. That skill derives the ancestor's `status:*` from its children per `leaf-only-lifecycle`, applies it only when it differs (never `status:ready`), and performs terminal native closure (`gh issue close --reason completed`) when the derived env is the production/terminal `$DONE`. It is idempotent and safe-defaults (suggests, does not guess) when the rolled state is ambiguous.
|
|
309
|
+
3. Stop walking up when an ancestor has no parent, or when `--rollup` reports no change (a higher ancestor cannot advance past an unchanged child). Record each rolled-up ancestor and its derived state in the summary.
|
|
310
|
+
|
|
311
|
+
This does not re-implement the state machine — it delegates to `lisa:github-sync --rollup`, the single rollup implementation `lisa:repair-intake` also uses, so the forward and recovery paths can never drift. Children closed **outside** this flow (e.g. by external automation) are not observed here; `lisa:repair-intake` remains the recovery net for those.
|
|
312
|
+
|
|
303
313
|
#### 3e. Stop
|
|
304
314
|
|
|
305
315
|
Stop immediately after the first claimed, skipped, blocked, held, or errored issue. Later scheduler invocations process the remaining ready issues.
|
|
@@ -218,6 +218,16 @@ If `lisa:jira-agent` returned Success:
|
|
|
218
218
|
|
|
219
219
|
For any non-Success outcome, do NOT transition. The ticket sits in `$CLAIMED` (or wherever `lisa:jira-agent` left it for the Blocked case) — the cycle's job is done; humans take it from there.
|
|
220
220
|
|
|
221
|
+
#### 3d.1 Roll up the parent chain (forward rollup)
|
|
222
|
+
|
|
223
|
+
Run this **only after a successful `$DONE` transition in 3d**. This is the **forward** arm of the `leaf-only-lifecycle` rule's *"rollup is evaluated whenever a child transitions"* requirement: a leaf reaching `$DONE` may complete its parent Story, which may in turn complete its Epic. Without this step a fully-built parent stays open until the recovery `lisa:repair-intake` cron happens to run.
|
|
224
|
+
|
|
225
|
+
1. Resolve the ticket's parent using the same hierarchy `lisa:jira-read-ticket` uses — the native Epic → Story → Sub-task parentage (parent field / Epic link). If the ticket has no parent, skip — nothing to roll up.
|
|
226
|
+
2. Walk **up the ancestor chain bottom-up** (Sub-task → Story → Epic): for each ancestor invoke `lisa:jira-sync <ANCESTOR-KEY> --rollup`. That skill derives the ancestor's status from its children per `leaf-only-lifecycle`, applies it via `lisa:atlassian-access` `operation: transition` only when it differs (never the build-ready status), and performs terminal native resolution (`statusCategory = Done` with a resolution when the workflow requires one) when the derived env is the terminal `$DONE`. It is idempotent and safe-defaults (suggests, does not guess) when the rolled state is ambiguous.
|
|
227
|
+
3. Stop walking up when an ancestor has no parent, or when `--rollup` reports no change. Record each rolled-up ancestor and its derived state in the summary.
|
|
228
|
+
|
|
229
|
+
This does not re-implement the state machine — it delegates to `lisa:jira-sync --rollup`, the single rollup implementation `lisa:repair-intake` also uses, so the forward and recovery paths can never drift. Children closed **outside** this flow are not observed here; `lisa:repair-intake` remains the recovery net for those.
|
|
230
|
+
|
|
221
231
|
#### 3e. Stop
|
|
222
232
|
|
|
223
233
|
Stop immediately after the first claimed, skipped, blocked, held, or errored ticket. Later scheduler invocations process the remaining ready tickets.
|
|
@@ -228,6 +228,16 @@ If `lisa:linear-agent` returned Success:
|
|
|
228
228
|
|
|
229
229
|
For any non-Success outcome, do NOT transition. The Issue sits where the agent left it — humans take it from there.
|
|
230
230
|
|
|
231
|
+
#### 3d.1 Roll up the parent chain (forward rollup)
|
|
232
|
+
|
|
233
|
+
Run this **only after a successful `$DONE` transition in 3d**. This is the **forward** arm of the `leaf-only-lifecycle` rule's *"rollup is evaluated whenever a child transitions"* requirement: a leaf reaching `$DONE` may complete its parent Issue, which may in turn complete its Project. Without this step a fully-built parent stays open until the recovery `lisa:repair-intake` cron happens to run.
|
|
234
|
+
|
|
235
|
+
1. Resolve the Issue's parent using the same hierarchy `lisa:linear-read-issue` uses — native parentage: a sub-issue's `parentId`, and Project membership via `projectId` for the Epic-equivalent. If the Issue has no parent, skip — nothing to roll up.
|
|
236
|
+
2. Walk **up the ancestor chain bottom-up** (sub-issue → parent Issue → Project): for each ancestor invoke `lisa:linear-sync <ANCESTOR-ID> --rollup`. That skill derives the ancestor's `status:*` from its children per `leaf-only-lifecycle`, applies it via `mcp__linear-server__save_issue` only when it differs (never `status:ready`), and moves the native Linear `state` to the configured Done / Completed state when the derived env is the terminal `$DONE`. It is idempotent and safe-defaults (suggests, does not guess) when the rolled state is ambiguous.
|
|
237
|
+
3. Stop walking up when an ancestor has no parent, or when `--rollup` reports no change. Record each rolled-up ancestor and its derived state in the summary.
|
|
238
|
+
|
|
239
|
+
This does not re-implement the state machine — it delegates to `lisa:linear-sync --rollup`, the single rollup implementation `lisa:repair-intake` also uses, so the forward and recovery paths can never drift. Children closed **outside** this flow are not observed here; `lisa:repair-intake` remains the recovery net for those.
|
|
240
|
+
|
|
231
241
|
#### 3e. Stop
|
|
232
242
|
|
|
233
243
|
Stop immediately after the first claimed, skipped, blocked, held, or errored Issue. Later scheduler invocations process the remaining ready Issues.
|
|
@@ -300,6 +300,16 @@ This close is idempotent: if the issue is already closed, record that native clo
|
|
|
300
300
|
|
|
301
301
|
For any non-Success outcome, do NOT transition. The issue sits in `$CLAIMED` (or wherever `lisa:github-agent` left it) — humans take it from there.
|
|
302
302
|
|
|
303
|
+
#### 3d.1 Roll up the parent chain (forward rollup)
|
|
304
|
+
|
|
305
|
+
Run this **only after a successful `$DONE` transition in 3d** (the leaf actually reached an env — intermediate or terminal). This is the **forward** arm of the `leaf-only-lifecycle` rule's *"rollup is evaluated whenever a child transitions"* requirement: a leaf reaching `$DONE` is exactly such a transition, so its parent's derived state may now have changed — the last open child of a Story just shipped, so the Story rolls up to `$DONE` and closes, which may in turn complete its Epic. Without this step a fully-built parent stays open until the recovery `lisa:repair-intake` cron happens to run.
|
|
306
|
+
|
|
307
|
+
1. Resolve the leaf's parent using the same hierarchy `lisa:github-read-issue` uses — native sub-issue parent first (GraphQL `parent`), then body parentage (`Parent: #<n>` / `Parent Epic: #<n>`). If the leaf has no parent, skip — nothing to roll up.
|
|
308
|
+
2. Walk **up the ancestor chain bottom-up**: for the immediate parent, then its parent, and so on, invoke `lisa:github-sync <org>/<repo>#<ancestor> --rollup`. That skill derives the ancestor's `status:*` from its children per `leaf-only-lifecycle`, applies it only when it differs (never `status:ready`), and performs terminal native closure (`gh issue close --reason completed`) when the derived env is the production/terminal `$DONE`. It is idempotent and safe-defaults (suggests, does not guess) when the rolled state is ambiguous.
|
|
309
|
+
3. Stop walking up when an ancestor has no parent, or when `--rollup` reports no change (a higher ancestor cannot advance past an unchanged child). Record each rolled-up ancestor and its derived state in the summary.
|
|
310
|
+
|
|
311
|
+
This does not re-implement the state machine — it delegates to `lisa:github-sync --rollup`, the single rollup implementation `lisa:repair-intake` also uses, so the forward and recovery paths can never drift. Children closed **outside** this flow (e.g. by external automation) are not observed here; `lisa:repair-intake` remains the recovery net for those.
|
|
312
|
+
|
|
303
313
|
#### 3e. Stop
|
|
304
314
|
|
|
305
315
|
Stop immediately after the first claimed, skipped, blocked, held, or errored issue. Later scheduler invocations process the remaining ready issues.
|
|
@@ -218,6 +218,16 @@ If `lisa:jira-agent` returned Success:
|
|
|
218
218
|
|
|
219
219
|
For any non-Success outcome, do NOT transition. The ticket sits in `$CLAIMED` (or wherever `lisa:jira-agent` left it for the Blocked case) — the cycle's job is done; humans take it from there.
|
|
220
220
|
|
|
221
|
+
#### 3d.1 Roll up the parent chain (forward rollup)
|
|
222
|
+
|
|
223
|
+
Run this **only after a successful `$DONE` transition in 3d**. This is the **forward** arm of the `leaf-only-lifecycle` rule's *"rollup is evaluated whenever a child transitions"* requirement: a leaf reaching `$DONE` may complete its parent Story, which may in turn complete its Epic. Without this step a fully-built parent stays open until the recovery `lisa:repair-intake` cron happens to run.
|
|
224
|
+
|
|
225
|
+
1. Resolve the ticket's parent using the same hierarchy `lisa:jira-read-ticket` uses — the native Epic → Story → Sub-task parentage (parent field / Epic link). If the ticket has no parent, skip — nothing to roll up.
|
|
226
|
+
2. Walk **up the ancestor chain bottom-up** (Sub-task → Story → Epic): for each ancestor invoke `lisa:jira-sync <ANCESTOR-KEY> --rollup`. That skill derives the ancestor's status from its children per `leaf-only-lifecycle`, applies it via `lisa:atlassian-access` `operation: transition` only when it differs (never the build-ready status), and performs terminal native resolution (`statusCategory = Done` with a resolution when the workflow requires one) when the derived env is the terminal `$DONE`. It is idempotent and safe-defaults (suggests, does not guess) when the rolled state is ambiguous.
|
|
227
|
+
3. Stop walking up when an ancestor has no parent, or when `--rollup` reports no change. Record each rolled-up ancestor and its derived state in the summary.
|
|
228
|
+
|
|
229
|
+
This does not re-implement the state machine — it delegates to `lisa:jira-sync --rollup`, the single rollup implementation `lisa:repair-intake` also uses, so the forward and recovery paths can never drift. Children closed **outside** this flow are not observed here; `lisa:repair-intake` remains the recovery net for those.
|
|
230
|
+
|
|
221
231
|
#### 3e. Stop
|
|
222
232
|
|
|
223
233
|
Stop immediately after the first claimed, skipped, blocked, held, or errored ticket. Later scheduler invocations process the remaining ready tickets.
|
|
@@ -228,6 +228,16 @@ If `lisa:linear-agent` returned Success:
|
|
|
228
228
|
|
|
229
229
|
For any non-Success outcome, do NOT transition. The Issue sits where the agent left it — humans take it from there.
|
|
230
230
|
|
|
231
|
+
#### 3d.1 Roll up the parent chain (forward rollup)
|
|
232
|
+
|
|
233
|
+
Run this **only after a successful `$DONE` transition in 3d**. This is the **forward** arm of the `leaf-only-lifecycle` rule's *"rollup is evaluated whenever a child transitions"* requirement: a leaf reaching `$DONE` may complete its parent Issue, which may in turn complete its Project. Without this step a fully-built parent stays open until the recovery `lisa:repair-intake` cron happens to run.
|
|
234
|
+
|
|
235
|
+
1. Resolve the Issue's parent using the same hierarchy `lisa:linear-read-issue` uses — native parentage: a sub-issue's `parentId`, and Project membership via `projectId` for the Epic-equivalent. If the Issue has no parent, skip — nothing to roll up.
|
|
236
|
+
2. Walk **up the ancestor chain bottom-up** (sub-issue → parent Issue → Project): for each ancestor invoke `lisa:linear-sync <ANCESTOR-ID> --rollup`. That skill derives the ancestor's `status:*` from its children per `leaf-only-lifecycle`, applies it via `mcp__linear-server__save_issue` only when it differs (never `status:ready`), and moves the native Linear `state` to the configured Done / Completed state when the derived env is the terminal `$DONE`. It is idempotent and safe-defaults (suggests, does not guess) when the rolled state is ambiguous.
|
|
237
|
+
3. Stop walking up when an ancestor has no parent, or when `--rollup` reports no change. Record each rolled-up ancestor and its derived state in the summary.
|
|
238
|
+
|
|
239
|
+
This does not re-implement the state machine — it delegates to `lisa:linear-sync --rollup`, the single rollup implementation `lisa:repair-intake` also uses, so the forward and recovery paths can never drift. Children closed **outside** this flow are not observed here; `lisa:repair-intake` remains the recovery net for those.
|
|
240
|
+
|
|
231
241
|
#### 3e. Stop
|
|
232
242
|
|
|
233
243
|
Stop immediately after the first claimed, skipped, blocked, held, or errored Issue. Later scheduler invocations process the remaining ready Issues.
|