@codyswann/lisa 2.150.1 → 2.151.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.
Files changed (74) hide show
  1. package/dist/codex/agent-installer.d.ts +5 -1
  2. package/dist/codex/agent-installer.d.ts.map +1 -1
  3. package/dist/codex/agent-installer.js +7 -2
  4. package/dist/codex/agent-installer.js.map +1 -1
  5. package/dist/core/lisa-skill-sources.d.ts +27 -1
  6. package/dist/core/lisa-skill-sources.d.ts.map +1 -1
  7. package/dist/core/lisa-skill-sources.js +33 -4
  8. package/dist/core/lisa-skill-sources.js.map +1 -1
  9. package/dist/core/lisa.d.ts +11 -7
  10. package/dist/core/lisa.d.ts.map +1 -1
  11. package/dist/core/lisa.js +30 -10
  12. package/dist/core/lisa.js.map +1 -1
  13. package/dist/opencode/agent-installer.d.ts +52 -0
  14. package/dist/opencode/agent-installer.d.ts.map +1 -0
  15. package/dist/opencode/agent-installer.js +120 -0
  16. package/dist/opencode/agent-installer.js.map +1 -0
  17. package/dist/opencode/agent-transformer.d.ts +52 -0
  18. package/dist/opencode/agent-transformer.d.ts.map +1 -0
  19. package/dist/opencode/agent-transformer.js +133 -0
  20. package/dist/opencode/agent-transformer.js.map +1 -0
  21. package/dist/opencode/command-installer.d.ts +47 -0
  22. package/dist/opencode/command-installer.d.ts.map +1 -0
  23. package/dist/opencode/command-installer.js +112 -0
  24. package/dist/opencode/command-installer.js.map +1 -0
  25. package/dist/opencode/command-transformer.d.ts +10 -0
  26. package/dist/opencode/command-transformer.d.ts.map +1 -0
  27. package/dist/opencode/command-transformer.js +74 -0
  28. package/dist/opencode/command-transformer.js.map +1 -0
  29. package/package.json +1 -1
  30. package/plugins/lisa/.claude-plugin/plugin.json +1 -1
  31. package/plugins/lisa/.codex-plugin/plugin.json +1 -1
  32. package/plugins/lisa-agy/plugin.json +1 -1
  33. package/plugins/lisa-cdk/.claude-plugin/plugin.json +1 -1
  34. package/plugins/lisa-cdk/.codex-plugin/plugin.json +1 -1
  35. package/plugins/lisa-cdk-agy/plugin.json +1 -1
  36. package/plugins/lisa-cdk-copilot/.claude-plugin/plugin.json +1 -1
  37. package/plugins/lisa-cdk-cursor/.claude-plugin/plugin.json +1 -1
  38. package/plugins/lisa-copilot/.claude-plugin/plugin.json +1 -1
  39. package/plugins/lisa-cursor/.claude-plugin/plugin.json +1 -1
  40. package/plugins/lisa-expo/.claude-plugin/plugin.json +1 -1
  41. package/plugins/lisa-expo/.codex-plugin/plugin.json +1 -1
  42. package/plugins/lisa-expo-agy/plugin.json +1 -1
  43. package/plugins/lisa-expo-copilot/.claude-plugin/plugin.json +1 -1
  44. package/plugins/lisa-expo-cursor/.claude-plugin/plugin.json +1 -1
  45. package/plugins/lisa-harper-fabric/.claude-plugin/plugin.json +1 -1
  46. package/plugins/lisa-harper-fabric/.codex-plugin/plugin.json +1 -1
  47. package/plugins/lisa-harper-fabric-agy/plugin.json +1 -1
  48. package/plugins/lisa-harper-fabric-copilot/.claude-plugin/plugin.json +1 -1
  49. package/plugins/lisa-harper-fabric-cursor/.claude-plugin/plugin.json +1 -1
  50. package/plugins/lisa-nestjs/.claude-plugin/plugin.json +1 -1
  51. package/plugins/lisa-nestjs/.codex-plugin/plugin.json +1 -1
  52. package/plugins/lisa-nestjs-agy/plugin.json +1 -1
  53. package/plugins/lisa-nestjs-copilot/.claude-plugin/plugin.json +1 -1
  54. package/plugins/lisa-nestjs-cursor/.claude-plugin/plugin.json +1 -1
  55. package/plugins/lisa-openclaw/.claude-plugin/plugin.json +1 -1
  56. package/plugins/lisa-openclaw/.codex-plugin/plugin.json +1 -1
  57. package/plugins/lisa-openclaw-agy/plugin.json +1 -1
  58. package/plugins/lisa-openclaw-copilot/.claude-plugin/plugin.json +1 -1
  59. package/plugins/lisa-openclaw-cursor/.claude-plugin/plugin.json +1 -1
  60. package/plugins/lisa-rails/.claude-plugin/plugin.json +1 -1
  61. package/plugins/lisa-rails/.codex-plugin/plugin.json +1 -1
  62. package/plugins/lisa-rails-agy/plugin.json +1 -1
  63. package/plugins/lisa-rails-copilot/.claude-plugin/plugin.json +1 -1
  64. package/plugins/lisa-rails-cursor/.claude-plugin/plugin.json +1 -1
  65. package/plugins/lisa-typescript/.claude-plugin/plugin.json +1 -1
  66. package/plugins/lisa-typescript/.codex-plugin/plugin.json +1 -1
  67. package/plugins/lisa-typescript-agy/plugin.json +1 -1
  68. package/plugins/lisa-typescript-copilot/.claude-plugin/plugin.json +1 -1
  69. package/plugins/lisa-typescript-cursor/.claude-plugin/plugin.json +1 -1
  70. package/plugins/lisa-wiki/.claude-plugin/plugin.json +1 -1
  71. package/plugins/lisa-wiki/.codex-plugin/plugin.json +1 -1
  72. package/plugins/lisa-wiki-agy/plugin.json +1 -1
  73. package/plugins/lisa-wiki-copilot/.claude-plugin/plugin.json +1 -1
  74. package/plugins/lisa-wiki-cursor/.claude-plugin/plugin.json +1 -1
@@ -0,0 +1,120 @@
1
+ /**
2
+ * Install Lisa-bundled agents into a host project's `.opencode/agents/`.
3
+ *
4
+ * Pipeline per agent:
5
+ * 1. Read the source `.md` from the Lisa plugin (discovered via the shared
6
+ * `discoverLisaAgents` walker, identical to the Codex overlay).
7
+ * 2. Transform Markdown + YAML frontmatter → OpenCode subagent Markdown
8
+ * (frontmatter `description` + `mode: subagent`; body is the prompt). This
9
+ * is a near-passthrough — OpenCode agents are Markdown like Claude's, so it
10
+ * is simpler than the Codex TOML transform.
11
+ * 3. Write the result to `.opencode/agents/lisa-<id>.md`.
12
+ *
13
+ * The `lisa-` filename prefix is the ownership boundary: OpenCode derives an
14
+ * agent's name from its filename and reads `.opencode/agents/` flat (verified on
15
+ * opencode 1.16.2 — `opencode agent list` surfaces files placed there), so a
16
+ * prefix — rather than a `lisa/` subdir as used for skills — is what keeps Lisa
17
+ * agents from colliding with host-authored agents and gives stale cleanup a safe
18
+ * scope. Host agents (any file NOT starting with `lisa-`) are never touched.
19
+ *
20
+ * Stale agents (in the previous manifest but no longer shipped by Lisa) are
21
+ * deleted so renames in the source tree don't leave orphans behind.
22
+ * @module opencode/agent-installer
23
+ */
24
+ import * as fse from "fs-extra";
25
+ import { readFile, unlink, writeFile } from "node:fs/promises";
26
+ import * as path from "node:path";
27
+ import { discoverLisaAgents, } from "../codex/agent-installer.js";
28
+ import { isHarnessVariantPlugin } from "../core/lisa-skill-sources.js";
29
+ import { transformAgentMarkdownToOpencode } from "./agent-transformer.js";
30
+ import { OPENCODE_CONFIG_DIR } from "./manifest.js";
31
+ export { discoverLisaAgents, } from "../codex/agent-installer.js";
32
+ /** Subdirectory inside `.opencode/` where Lisa-owned agents live */
33
+ export const LISA_AGENTS_SUBDIR = "agents";
34
+ /**
35
+ * Filename prefix marking an agent file as Lisa-owned. OpenCode reads
36
+ * `.opencode/agents/` flat, so the prefix (not a subdirectory) is the ownership
37
+ * boundary used for collision avoidance and stale cleanup.
38
+ */
39
+ export const LISA_AGENT_FILE_PREFIX = "lisa-";
40
+ /**
41
+ * Install all discovered agents into `<destDir>/.opencode/agents/`.
42
+ *
43
+ * Returns a result describing what was written and what stale files were
44
+ * deleted, so the caller can update the Lisa-managed manifest.
45
+ * @param sources - Agent sources from discoverLisaAgents
46
+ * @param destDir - Absolute path to the destination project root
47
+ * @param previousManagedFiles - Files Lisa managed on the previous run
48
+ * (relative to `.opencode/`); used to detect stale agents to delete
49
+ * @returns Result describing installed/deleted/managedFiles
50
+ */
51
+ export async function installAgents(sources, destDir, previousManagedFiles) {
52
+ const agentsDir = path.join(destDir, OPENCODE_CONFIG_DIR, LISA_AGENTS_SUBDIR);
53
+ await fse.ensureDir(agentsDir);
54
+ const installed = await Promise.all(sources.map(source => installSingleAgent(source, agentsDir)));
55
+ const managedFiles = installed.map(agent => agent.relativePath);
56
+ const deleted = await deleteStaleAgents(previousManagedFiles, managedFiles, destDir);
57
+ return {
58
+ installed: Object.freeze(installed),
59
+ deleted: Object.freeze(deleted),
60
+ managedFiles: Object.freeze(managedFiles),
61
+ };
62
+ }
63
+ /**
64
+ * Transform + write a single agent file.
65
+ * @param source - Discovered agent source (id, plugin, source path)
66
+ * @param agentsDir - Absolute path to `.opencode/agents/` in the host project
67
+ * @returns Result describing the installed file
68
+ */
69
+ async function installSingleAgent(source, agentsDir) {
70
+ const sourceContent = await readFile(source.sourcePath, "utf8");
71
+ const markdown = transformAgentMarkdownToOpencode(sourceContent);
72
+ const filename = `${LISA_AGENT_FILE_PREFIX}${source.id}.md`;
73
+ await writeFile(path.join(agentsDir, filename), markdown, "utf8");
74
+ return {
75
+ id: source.id,
76
+ relativePath: path.join(LISA_AGENTS_SUBDIR, filename),
77
+ };
78
+ }
79
+ /**
80
+ * Delete files that were Lisa-managed last run but aren't shipped this run.
81
+ * Only deletes files inside `.opencode/agents/` whose basename carries the
82
+ * `lisa-` prefix, so host-authored agents are never removed even if the
83
+ * previous manifest somehow references them.
84
+ * @param previousManagedFiles - Files Lisa managed on the previous run
85
+ * (relative to `.opencode/`)
86
+ * @param currentManagedFiles - Files Lisa is shipping this run (relative
87
+ * to `.opencode/`)
88
+ * @param destDir - Absolute path to the host project root
89
+ * @returns The list of relative paths that were deleted
90
+ */
91
+ async function deleteStaleAgents(previousManagedFiles, currentManagedFiles, destDir) {
92
+ const currentSet = new Set(currentManagedFiles);
93
+ const lisaAgentPrefix = `${LISA_AGENTS_SUBDIR}${path.sep}${LISA_AGENT_FILE_PREFIX}`;
94
+ const stale = previousManagedFiles.filter(file => !currentSet.has(file) && file.startsWith(lisaAgentPrefix));
95
+ await Promise.all(stale.map(async (file) => {
96
+ const absPath = path.join(destDir, OPENCODE_CONFIG_DIR, file);
97
+ if (await fse.pathExists(absPath)) {
98
+ await unlink(absPath);
99
+ }
100
+ }));
101
+ return Object.freeze(stale);
102
+ }
103
+ /**
104
+ * Convenience one-shot: discover Lisa agents from `lisaDir` and install them.
105
+ *
106
+ * Discovery is restricted to canonical plugins — the per-harness fanout variants
107
+ * (`*-agy`, `*-copilot`, `*-cursor`) are skipped. The copilot variants rename
108
+ * agents to `*.agent.md`, which would otherwise slip past id-dedup and ship a
109
+ * duplicate `lisa-<name>.agent` for every agent; the cursor/agy variants are
110
+ * just reformatted copies of the base agents.
111
+ * @param lisaDir - Absolute path to the Lisa repo / installed package
112
+ * @param destDir - Absolute path to the destination project root
113
+ * @param previousManagedFiles - Files Lisa managed on the previous run
114
+ * @returns Result describing installed/deleted/managedFiles
115
+ */
116
+ export async function discoverAndInstallAgents(lisaDir, destDir, previousManagedFiles) {
117
+ const sources = await discoverLisaAgents(lisaDir, name => !isHarnessVariantPlugin(name));
118
+ return installAgents(sources, destDir, previousManagedFiles);
119
+ }
120
+ //# sourceMappingURL=agent-installer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent-installer.js","sourceRoot":"","sources":["../../src/opencode/agent-installer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Transform a Claude Code-style agent definition (Markdown with YAML
3
+ * frontmatter) into an OpenCode subagent Markdown file.
4
+ *
5
+ * Claude Code agent shape:
6
+ * ```
7
+ * ---
8
+ * name: bug-fixer
9
+ * description: ...
10
+ * tools: Read, Bash # optional; preserved as compatibility context
11
+ * model: sonnet # optional; preserved as compatibility context
12
+ * skills: [skill-a, skill-b] # optional; preserved as context
13
+ * ---
14
+ * # Body becomes the agent prompt
15
+ * ```
16
+ *
17
+ * OpenCode agent shape (per https://opencode.ai/docs/agents):
18
+ * ```
19
+ * ---
20
+ * description: ...
21
+ * mode: subagent
22
+ * ---
23
+ * # Body is the agent prompt
24
+ * ```
25
+ *
26
+ * OpenCode agents are Markdown like Claude's, so — unlike the Codex TOML
27
+ * transform — this is a near-passthrough: the body is preserved verbatim and
28
+ * the only required reshape is the frontmatter. The agent NAME is derived by
29
+ * OpenCode from the destination filename (not a frontmatter field), so the
30
+ * installer owns naming; this transformer only owns the file contents.
31
+ *
32
+ * Claude-only metadata (`tools`, `model`, `skills`) is NOT emitted as OpenCode
33
+ * frontmatter — `model` expects a `provider/model` string that a Claude alias
34
+ * (`sonnet`) would violate, and `tools`/`skills` have no 1:1 frontmatter slot.
35
+ * Instead that metadata is preserved as a context block in the body so nothing
36
+ * is silently dropped, mirroring the Codex transformer's compatibility blocks.
37
+ * @module opencode/agent-transformer
38
+ */
39
+ import { type ParsedAgent } from "../codex/agent-transformer.js";
40
+ /**
41
+ * Transform a parsed Lisa agent into OpenCode subagent Markdown.
42
+ * @param parsed - Output of parseAgentMarkdown (frontmatter + body)
43
+ * @returns OpenCode agent Markdown (frontmatter + prompt body)
44
+ */
45
+ export declare function transformAgentToOpencodeMarkdown(parsed: ParsedAgent): string;
46
+ /**
47
+ * One-shot helper: parse + transform.
48
+ * @param source - Raw contents of an agent .md file
49
+ * @returns OpenCode agent Markdown
50
+ */
51
+ export declare function transformAgentMarkdownToOpencode(source: string): string;
52
+ //# sourceMappingURL=agent-transformer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent-transformer.d.ts","sourceRoot":"","sources":["../../src/opencode/agent-transformer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AACH,OAAO,EACL,KAAK,WAAW,EAEjB,MAAM,+BAA+B,CAAC;AAEvC;;;;GAIG;AACH,wBAAgB,gCAAgC,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,CAU5E;AAED;;;;GAIG;AACH,wBAAgB,gCAAgC,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAEvE"}
@@ -0,0 +1,133 @@
1
+ /**
2
+ * Transform a Claude Code-style agent definition (Markdown with YAML
3
+ * frontmatter) into an OpenCode subagent Markdown file.
4
+ *
5
+ * Claude Code agent shape:
6
+ * ```
7
+ * ---
8
+ * name: bug-fixer
9
+ * description: ...
10
+ * tools: Read, Bash # optional; preserved as compatibility context
11
+ * model: sonnet # optional; preserved as compatibility context
12
+ * skills: [skill-a, skill-b] # optional; preserved as context
13
+ * ---
14
+ * # Body becomes the agent prompt
15
+ * ```
16
+ *
17
+ * OpenCode agent shape (per https://opencode.ai/docs/agents):
18
+ * ```
19
+ * ---
20
+ * description: ...
21
+ * mode: subagent
22
+ * ---
23
+ * # Body is the agent prompt
24
+ * ```
25
+ *
26
+ * OpenCode agents are Markdown like Claude's, so — unlike the Codex TOML
27
+ * transform — this is a near-passthrough: the body is preserved verbatim and
28
+ * the only required reshape is the frontmatter. The agent NAME is derived by
29
+ * OpenCode from the destination filename (not a frontmatter field), so the
30
+ * installer owns naming; this transformer only owns the file contents.
31
+ *
32
+ * Claude-only metadata (`tools`, `model`, `skills`) is NOT emitted as OpenCode
33
+ * frontmatter — `model` expects a `provider/model` string that a Claude alias
34
+ * (`sonnet`) would violate, and `tools`/`skills` have no 1:1 frontmatter slot.
35
+ * Instead that metadata is preserved as a context block in the body so nothing
36
+ * is silently dropped, mirroring the Codex transformer's compatibility blocks.
37
+ * @module opencode/agent-transformer
38
+ */
39
+ import { parseAgentMarkdown, } from "../codex/agent-transformer.js";
40
+ /**
41
+ * Transform a parsed Lisa agent into OpenCode subagent Markdown.
42
+ * @param parsed - Output of parseAgentMarkdown (frontmatter + body)
43
+ * @returns OpenCode agent Markdown (frontmatter + prompt body)
44
+ */
45
+ export function transformAgentToOpencodeMarkdown(parsed) {
46
+ const frontmatter = [
47
+ "---",
48
+ `description: ${jsonScalar(parsed.frontmatter.description)}`,
49
+ "mode: subagent",
50
+ "---",
51
+ "",
52
+ ].join("\n");
53
+ const body = composeAgentBody(parsed);
54
+ return `${frontmatter}${body}\n`;
55
+ }
56
+ /**
57
+ * One-shot helper: parse + transform.
58
+ * @param source - Raw contents of an agent .md file
59
+ * @returns OpenCode agent Markdown
60
+ */
61
+ export function transformAgentMarkdownToOpencode(source) {
62
+ return transformAgentToOpencodeMarkdown(parseAgentMarkdown(source));
63
+ }
64
+ /**
65
+ * Build the OpenCode agent body. The original Claude body is preserved
66
+ * verbatim; any Claude-only metadata that has no OpenCode frontmatter slot is
67
+ * prepended as a context block so the information survives the transform.
68
+ * @param parsed - Output of parseAgentMarkdown for the source agent file
69
+ * @returns The composed Markdown body
70
+ */
71
+ function composeAgentBody(parsed) {
72
+ const compatibilityBlock = formatCompatibilityBlock(parsed);
73
+ const skillsBlock = formatSkillsBlock(parsed);
74
+ return [compatibilityBlock, skillsBlock, parsed.body.trimEnd()]
75
+ .filter(block => block.length > 0)
76
+ .join("\n\n");
77
+ }
78
+ /**
79
+ * Preserve Claude-only `model`/`tools` metadata as an OpenCode context block.
80
+ * OpenCode governs model and tool access through its own runtime/config, so
81
+ * these are advisory notes rather than enforced settings.
82
+ * @param parsed - Parsed source agent
83
+ * @returns Markdown compatibility block, or an empty string when unnecessary
84
+ */
85
+ function formatCompatibilityBlock(parsed) {
86
+ const { model, tools } = parsed.frontmatter;
87
+ const modelLines = model === undefined
88
+ ? []
89
+ : [
90
+ `- Claude requested model: \`${model}\`. OpenCode uses the active session model unless the host sets \`model\` on this agent.`,
91
+ ];
92
+ const toolLines = tools === undefined
93
+ ? []
94
+ : [
95
+ `- Claude allowed tools: \`${tools}\`. OpenCode tool access is governed by the active OpenCode runtime, \`permission\` settings, and project policy.`,
96
+ ];
97
+ const lines = [...modelLines, ...toolLines];
98
+ if (lines.length === 0) {
99
+ return "";
100
+ }
101
+ return ["## Claude Agent Compatibility", "", ...lines].join("\n");
102
+ }
103
+ /**
104
+ * Preserve the source agent's `skills:` list as a context block. OpenCode
105
+ * discovers these skills natively from `.opencode/skills/lisa/`, so this block
106
+ * just documents which ones the agent is expected to use.
107
+ * @param parsed - Parsed source agent
108
+ * @returns Markdown skills block, or an empty string when no skills are listed
109
+ */
110
+ function formatSkillsBlock(parsed) {
111
+ const skills = parsed.frontmatter.skills;
112
+ if (skills === undefined || skills.length === 0) {
113
+ return "";
114
+ }
115
+ return [
116
+ "## Available Lisa Skills",
117
+ "",
118
+ "This agent operates in a Lisa-managed OpenCode environment with access to the following skills:",
119
+ "",
120
+ ...skills.map(skill => `- ${skill}`),
121
+ ].join("\n");
122
+ }
123
+ /**
124
+ * Encode a string as a YAML-safe flow scalar. A JSON-encoded string is always a
125
+ * valid YAML double-quoted scalar, so this safely handles descriptions that
126
+ * contain colons, quotes, or other YAML-significant characters.
127
+ * @param value - The raw string to encode
128
+ * @returns A double-quoted YAML scalar
129
+ */
130
+ function jsonScalar(value) {
131
+ return JSON.stringify(value);
132
+ }
133
+ //# sourceMappingURL=agent-transformer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent-transformer.js","sourceRoot":"","sources":["../../src/opencode/agent-transformer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AACH,OAAO,EAEL,kBAAkB,GACnB,MAAM,+BAA+B,CAAC;AAEvC;;;;GAIG;AACH,MAAM,UAAU,gCAAgC,CAAC,MAAmB;IAClE,MAAM,WAAW,GAAG;QAClB,KAAK;QACL,gBAAgB,UAAU,CAAC,MAAM,CAAC,WAAW,CAAC,WAAW,CAAC,EAAE;QAC5D,gBAAgB;QAChB,KAAK;QACL,EAAE;KACH,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACb,MAAM,IAAI,GAAG,gBAAgB,CAAC,MAAM,CAAC,CAAC;IACtC,OAAO,GAAG,WAAW,GAAG,IAAI,IAAI,CAAC;AACnC,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,gCAAgC,CAAC,MAAc;IAC7D,OAAO,gCAAgC,CAAC,kBAAkB,CAAC,MAAM,CAAC,CAAC,CAAC;AACtE,CAAC;AAED;;;;;;GAMG;AACH,SAAS,gBAAgB,CAAC,MAAmB;IAC3C,MAAM,kBAAkB,GAAG,wBAAwB,CAAC,MAAM,CAAC,CAAC;IAC5D,MAAM,WAAW,GAAG,iBAAiB,CAAC,MAAM,CAAC,CAAC;IAC9C,OAAO,CAAC,kBAAkB,EAAE,WAAW,EAAE,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;SAC5D,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC;SACjC,IAAI,CAAC,MAAM,CAAC,CAAC;AAClB,CAAC;AAED;;;;;;GAMG;AACH,SAAS,wBAAwB,CAAC,MAAmB;IACnD,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,MAAM,CAAC,WAAW,CAAC;IAC5C,MAAM,UAAU,GACd,KAAK,KAAK,SAAS;QACjB,CAAC,CAAC,EAAE;QACJ,CAAC,CAAC;YACE,+BAA+B,KAAK,0FAA0F;SAC/H,CAAC;IACR,MAAM,SAAS,GACb,KAAK,KAAK,SAAS;QACjB,CAAC,CAAC,EAAE;QACJ,CAAC,CAAC;YACE,6BAA6B,KAAK,mHAAmH;SACtJ,CAAC;IACR,MAAM,KAAK,GAAG,CAAC,GAAG,UAAU,EAAE,GAAG,SAAS,CAAC,CAAC;IAC5C,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACvB,OAAO,EAAE,CAAC;IACZ,CAAC;IACD,OAAO,CAAC,+BAA+B,EAAE,EAAE,EAAE,GAAG,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACpE,CAAC;AAED;;;;;;GAMG;AACH,SAAS,iBAAiB,CAAC,MAAmB;IAC5C,MAAM,MAAM,GAAG,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC;IACzC,IAAI,MAAM,KAAK,SAAS,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAChD,OAAO,EAAE,CAAC;IACZ,CAAC;IACD,OAAO;QACL,0BAA0B;QAC1B,EAAE;QACF,iGAAiG;QACjG,EAAE;QACF,GAAG,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,KAAK,EAAE,CAAC;KACrC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACf,CAAC;AAED;;;;;;GAMG;AACH,SAAS,UAAU,CAAC,KAAa;IAC/B,OAAO,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;AAC/B,CAAC"}
@@ -0,0 +1,47 @@
1
+ import { type LisaCommandSource } from "../core/lisa-skill-sources.js";
2
+ export { type LisaCommandSource, discoverLisaCommands, } from "../core/lisa-skill-sources.js";
3
+ /** Subdirectory inside `.opencode/` where Lisa-owned commands live */
4
+ export declare const LISA_COMMANDS_SUBDIR = "commands";
5
+ /**
6
+ * Filename prefix marking a command file as Lisa-owned. The shared command
7
+ * discovery already names every command `lisa-<...>`, so this matches the
8
+ * basename of every file Lisa writes and scopes stale cleanup safely.
9
+ */
10
+ export declare const LISA_COMMAND_FILE_PREFIX = "lisa-";
11
+ /** Result of installing one command */
12
+ export interface InstalledCommand {
13
+ /** Command name (the `lisa-` prefixed, dash-joined skill name) */
14
+ readonly name: string;
15
+ /** Path written, relative to the destination project's `.opencode/` directory */
16
+ readonly relativePath: string;
17
+ }
18
+ /** Aggregated result of an install pass */
19
+ export interface CommandInstallResult {
20
+ readonly installed: readonly InstalledCommand[];
21
+ /** Stale command files deleted from `.opencode/commands/` (relative to `.opencode/`) */
22
+ readonly deleted: readonly string[];
23
+ /** Files written, relative to `.opencode/`. Used to update the manifest. */
24
+ readonly managedFiles: readonly string[];
25
+ }
26
+ /**
27
+ * Install all discovered commands into `<destDir>/.opencode/commands/`.
28
+ * @param sources - Command sources from discoverLisaCommands
29
+ * @param destDir - Absolute path to the destination project root
30
+ * @param previousManagedFiles - Files Lisa managed on the previous run
31
+ * (relative to `.opencode/`); used to detect stale commands to delete
32
+ * @returns Result describing installed/deleted/managedFiles
33
+ */
34
+ export declare function installCommands(sources: readonly LisaCommandSource[], destDir: string, previousManagedFiles: readonly string[]): Promise<CommandInstallResult>;
35
+ /**
36
+ * Convenience one-shot: discover Lisa commands from `lisaDir` and install them.
37
+ *
38
+ * Discovery is restricted to canonical plugins — the per-harness fanout variants
39
+ * (`*-agy`, `*-copilot`, `*-cursor`) are skipped so a reformatted variant copy
40
+ * of a command body never wins the last-wins dedup over the canonical source.
41
+ * @param lisaDir - Absolute path to the Lisa repo / installed package
42
+ * @param destDir - Absolute path to the destination project root
43
+ * @param previousManagedFiles - Files Lisa managed on the previous run
44
+ * @returns Result describing installed/deleted/managedFiles
45
+ */
46
+ export declare function discoverAndInstallCommands(lisaDir: string, destDir: string, previousManagedFiles: readonly string[]): Promise<CommandInstallResult>;
47
+ //# sourceMappingURL=command-installer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"command-installer.d.ts","sourceRoot":"","sources":["../../src/opencode/command-installer.ts"],"names":[],"mappings":"AAyBA,OAAO,EACL,KAAK,iBAAiB,EAGvB,MAAM,+BAA+B,CAAC;AAIvC,OAAO,EACL,KAAK,iBAAiB,EACtB,oBAAoB,GACrB,MAAM,+BAA+B,CAAC;AAEvC,sEAAsE;AACtE,eAAO,MAAM,oBAAoB,aAAa,CAAC;AAE/C;;;;GAIG;AACH,eAAO,MAAM,wBAAwB,UAAU,CAAC;AAEhD,uCAAuC;AACvC,MAAM,WAAW,gBAAgB;IAC/B,kEAAkE;IAClE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,iFAAiF;IACjF,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;CAC/B;AAED,2CAA2C;AAC3C,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,SAAS,EAAE,SAAS,gBAAgB,EAAE,CAAC;IAChD,wFAAwF;IACxF,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IACpC,4EAA4E;IAC5E,QAAQ,CAAC,YAAY,EAAE,SAAS,MAAM,EAAE,CAAC;CAC1C;AAED;;;;;;;GAOG;AACH,wBAAsB,eAAe,CACnC,OAAO,EAAE,SAAS,iBAAiB,EAAE,EACrC,OAAO,EAAE,MAAM,EACf,oBAAoB,EAAE,SAAS,MAAM,EAAE,GACtC,OAAO,CAAC,oBAAoB,CAAC,CA0B/B;AAyDD;;;;;;;;;;GAUG;AACH,wBAAsB,0BAA0B,CAC9C,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,EACf,oBAAoB,EAAE,SAAS,MAAM,EAAE,GACtC,OAAO,CAAC,oBAAoB,CAAC,CAM/B"}
@@ -0,0 +1,112 @@
1
+ /**
2
+ * Install Lisa commands as native OpenCode custom commands in
3
+ * `.opencode/commands/`.
4
+ *
5
+ * Pipeline per command:
6
+ * 1. Discover `plugins/<plugin>/commands/**\/*.md` via the shared
7
+ * `discoverLisaCommands` walker (identical discovery to the skills path).
8
+ * 2. Transform the command Markdown → OpenCode command Markdown (frontmatter
9
+ * `description`; body preserves `$ARGUMENTS` for native substitution).
10
+ * 3. Write the result to `.opencode/commands/<lisa-name>.md`, where the
11
+ * filename is the shared dash-joined `lisa-` prefixed name (e.g.
12
+ * `lisa-git-commit`), so the command surfaces as `/lisa-git-commit`.
13
+ *
14
+ * This is ADDITIVE and native-fidelity: Lisa commands already work on OpenCode
15
+ * as `lisa-` prefixed skills, so the lower-priority value here is exposing them
16
+ * through OpenCode's first-class command surface with native argument handling.
17
+ *
18
+ * The `lisa-` filename prefix (already baked into the shared command skill name)
19
+ * is the ownership boundary — host-authored commands (any file NOT starting with
20
+ * `lisa-`) are never touched, and stale cleanup is scoped to `lisa-` files only.
21
+ * @module opencode/command-installer
22
+ */
23
+ import * as fse from "fs-extra";
24
+ import { readFile, unlink, writeFile } from "node:fs/promises";
25
+ import * as path from "node:path";
26
+ import { discoverLisaCommands, isHarnessVariantPlugin, } from "../core/lisa-skill-sources.js";
27
+ import { transformCommandToOpencode } from "./command-transformer.js";
28
+ import { OPENCODE_CONFIG_DIR } from "./manifest.js";
29
+ export { discoverLisaCommands, } from "../core/lisa-skill-sources.js";
30
+ /** Subdirectory inside `.opencode/` where Lisa-owned commands live */
31
+ export const LISA_COMMANDS_SUBDIR = "commands";
32
+ /**
33
+ * Filename prefix marking a command file as Lisa-owned. The shared command
34
+ * discovery already names every command `lisa-<...>`, so this matches the
35
+ * basename of every file Lisa writes and scopes stale cleanup safely.
36
+ */
37
+ export const LISA_COMMAND_FILE_PREFIX = "lisa-";
38
+ /**
39
+ * Install all discovered commands into `<destDir>/.opencode/commands/`.
40
+ * @param sources - Command sources from discoverLisaCommands
41
+ * @param destDir - Absolute path to the destination project root
42
+ * @param previousManagedFiles - Files Lisa managed on the previous run
43
+ * (relative to `.opencode/`); used to detect stale commands to delete
44
+ * @returns Result describing installed/deleted/managedFiles
45
+ */
46
+ export async function installCommands(sources, destDir, previousManagedFiles) {
47
+ const commandsDir = path.join(destDir, OPENCODE_CONFIG_DIR, LISA_COMMANDS_SUBDIR);
48
+ await fse.ensureDir(commandsDir);
49
+ const installed = await Promise.all(sources.map(source => installSingleCommand(source, commandsDir)));
50
+ const managedFiles = installed.map(command => command.relativePath);
51
+ const deleted = await deleteStaleCommands(previousManagedFiles, managedFiles, destDir);
52
+ return {
53
+ installed: Object.freeze(installed),
54
+ deleted: Object.freeze(deleted),
55
+ managedFiles: Object.freeze(managedFiles),
56
+ };
57
+ }
58
+ /**
59
+ * Transform + write a single command file.
60
+ * @param source - Discovered command source (skill name, display name, path)
61
+ * @param commandsDir - Absolute path to `.opencode/commands/` in the host
62
+ * @returns Result describing the installed file
63
+ */
64
+ async function installSingleCommand(source, commandsDir) {
65
+ const sourceContent = await readFile(source.sourcePath, "utf8");
66
+ const markdown = transformCommandToOpencode(sourceContent, source.displayName);
67
+ const filename = `${source.skillName}.md`;
68
+ await writeFile(path.join(commandsDir, filename), markdown, "utf8");
69
+ return {
70
+ name: source.skillName,
71
+ relativePath: path.join(LISA_COMMANDS_SUBDIR, filename),
72
+ };
73
+ }
74
+ /**
75
+ * Delete files that were Lisa-managed last run but aren't shipped this run.
76
+ * Only deletes files inside `.opencode/commands/` whose basename carries the
77
+ * `lisa-` prefix, so host-authored commands are never removed.
78
+ * @param previousManagedFiles - Files Lisa managed on the previous run
79
+ * (relative to `.opencode/`)
80
+ * @param currentManagedFiles - Files Lisa is shipping this run (relative
81
+ * to `.opencode/`)
82
+ * @param destDir - Absolute path to the host project root
83
+ * @returns The list of relative paths that were deleted
84
+ */
85
+ async function deleteStaleCommands(previousManagedFiles, currentManagedFiles, destDir) {
86
+ const currentSet = new Set(currentManagedFiles);
87
+ const lisaCommandPrefix = `${LISA_COMMANDS_SUBDIR}${path.sep}${LISA_COMMAND_FILE_PREFIX}`;
88
+ const stale = previousManagedFiles.filter(file => !currentSet.has(file) && file.startsWith(lisaCommandPrefix));
89
+ await Promise.all(stale.map(async (file) => {
90
+ const absPath = path.join(destDir, OPENCODE_CONFIG_DIR, file);
91
+ if (await fse.pathExists(absPath)) {
92
+ await unlink(absPath);
93
+ }
94
+ }));
95
+ return Object.freeze(stale);
96
+ }
97
+ /**
98
+ * Convenience one-shot: discover Lisa commands from `lisaDir` and install them.
99
+ *
100
+ * Discovery is restricted to canonical plugins — the per-harness fanout variants
101
+ * (`*-agy`, `*-copilot`, `*-cursor`) are skipped so a reformatted variant copy
102
+ * of a command body never wins the last-wins dedup over the canonical source.
103
+ * @param lisaDir - Absolute path to the Lisa repo / installed package
104
+ * @param destDir - Absolute path to the destination project root
105
+ * @param previousManagedFiles - Files Lisa managed on the previous run
106
+ * @returns Result describing installed/deleted/managedFiles
107
+ */
108
+ export async function discoverAndInstallCommands(lisaDir, destDir, previousManagedFiles) {
109
+ const sources = await discoverLisaCommands(lisaDir, name => !isHarnessVariantPlugin(name));
110
+ return installCommands(sources, destDir, previousManagedFiles);
111
+ }
112
+ //# sourceMappingURL=command-installer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"command-installer.js","sourceRoot":"","sources":["../../src/opencode/command-installer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,OAAO,KAAK,GAAG,MAAM,UAAU,CAAC;AAChC,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC/D,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,EAEL,oBAAoB,EACpB,sBAAsB,GACvB,MAAM,+BAA+B,CAAC;AACvC,OAAO,EAAE,0BAA0B,EAAE,MAAM,0BAA0B,CAAC;AACtE,OAAO,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AAEpD,OAAO,EAEL,oBAAoB,GACrB,MAAM,+BAA+B,CAAC;AAEvC,sEAAsE;AACtE,MAAM,CAAC,MAAM,oBAAoB,GAAG,UAAU,CAAC;AAE/C;;;;GAIG;AACH,MAAM,CAAC,MAAM,wBAAwB,GAAG,OAAO,CAAC;AAmBhD;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,OAAqC,EACrC,OAAe,EACf,oBAAuC;IAEvC,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAC3B,OAAO,EACP,mBAAmB,EACnB,oBAAoB,CACrB,CAAC;IACF,MAAM,GAAG,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC;IAEjC,MAAM,SAAS,GAAgC,MAAM,OAAO,CAAC,GAAG,CAC9D,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,oBAAoB,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC,CACjE,CAAC;IACF,MAAM,YAAY,GAAsB,SAAS,CAAC,GAAG,CACnD,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,YAAY,CAChC,CAAC;IAEF,MAAM,OAAO,GAAG,MAAM,mBAAmB,CACvC,oBAAoB,EACpB,YAAY,EACZ,OAAO,CACR,CAAC;IAEF,OAAO;QACL,SAAS,EAAE,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC;QACnC,OAAO,EAAE,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC;QAC/B,YAAY,EAAE,MAAM,CAAC,MAAM,CAAC,YAAY,CAAC;KAC1C,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,KAAK,UAAU,oBAAoB,CACjC,MAAyB,EACzB,WAAmB;IAEnB,MAAM,aAAa,GAAG,MAAM,QAAQ,CAAC,MAAM,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC;IAChE,MAAM,QAAQ,GAAG,0BAA0B,CACzC,aAAa,EACb,MAAM,CAAC,WAAW,CACnB,CAAC;IACF,MAAM,QAAQ,GAAG,GAAG,MAAM,CAAC,SAAS,KAAK,CAAC;IAC1C,MAAM,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,QAAQ,CAAC,EAAE,QAAQ,EAAE,MAAM,CAAC,CAAC;IACpE,OAAO;QACL,IAAI,EAAE,MAAM,CAAC,SAAS;QACtB,YAAY,EAAE,IAAI,CAAC,IAAI,CAAC,oBAAoB,EAAE,QAAQ,CAAC;KACxD,CAAC;AACJ,CAAC;AAED;;;;;;;;;;GAUG;AACH,KAAK,UAAU,mBAAmB,CAChC,oBAAuC,EACvC,mBAAsC,EACtC,OAAe;IAEf,MAAM,UAAU,GAAG,IAAI,GAAG,CAAC,mBAAmB,CAAC,CAAC;IAChD,MAAM,iBAAiB,GAAG,GAAG,oBAAoB,GAAG,IAAI,CAAC,GAAG,GAAG,wBAAwB,EAAE,CAAC;IAC1F,MAAM,KAAK,GAAG,oBAAoB,CAAC,MAAM,CACvC,IAAI,CAAC,EAAE,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,UAAU,CAAC,iBAAiB,CAAC,CACpE,CAAC;IACF,MAAM,OAAO,CAAC,GAAG,CACf,KAAK,CAAC,GAAG,CAAC,KAAK,EAAC,IAAI,EAAC,EAAE;QACrB,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,mBAAmB,EAAE,IAAI,CAAC,CAAC;QAC9D,IAAI,MAAM,GAAG,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;YAClC,MAAM,MAAM,CAAC,OAAO,CAAC,CAAC;QACxB,CAAC;IACH,CAAC,CAAC,CACH,CAAC;IACF,OAAO,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAC9B,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,CAAC,KAAK,UAAU,0BAA0B,CAC9C,OAAe,EACf,OAAe,EACf,oBAAuC;IAEvC,MAAM,OAAO,GAAG,MAAM,oBAAoB,CACxC,OAAO,EACP,IAAI,CAAC,EAAE,CAAC,CAAC,sBAAsB,CAAC,IAAI,CAAC,CACtC,CAAC;IACF,OAAO,eAAe,CAAC,OAAO,EAAE,OAAO,EAAE,oBAAoB,CAAC,CAAC;AACjE,CAAC"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Pure transform: convert a Lisa command Markdown into an OpenCode command
3
+ * Markdown.
4
+ * @param commandSource - Raw contents of the command .md file
5
+ * @param displayName - Human-readable name used as a fallback description
6
+ * (e.g. "lisa:git:commit")
7
+ * @returns The OpenCode command Markdown content as a string
8
+ */
9
+ export declare function transformCommandToOpencode(commandSource: string, displayName: string): string;
10
+ //# sourceMappingURL=command-transformer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"command-transformer.d.ts","sourceRoot":"","sources":["../../src/opencode/command-transformer.ts"],"names":[],"mappings":"AAmCA;;;;;;;GAOG;AACH,wBAAgB,0BAA0B,CACxC,aAAa,EAAE,MAAM,EACrB,WAAW,EAAE,MAAM,GAClB,MAAM,CAoBR"}
@@ -0,0 +1,74 @@
1
+ /**
2
+ * Convert a Lisa command Markdown file into an OpenCode custom command.
3
+ *
4
+ * Lisa commands already work today on OpenCode as `lisa-` prefixed skills (see
5
+ * `opencode/skills-installer.ts`). This transformer is the additive, native
6
+ * path: OpenCode has a first-class command format
7
+ * (https://opencode.ai/docs/commands) with its own frontmatter and native
8
+ * `$ARGUMENTS` / `$1` / `@file` substitution.
9
+ *
10
+ * Claude command shape:
11
+ * ```
12
+ * ---
13
+ * description: ...
14
+ * argument-hint: "<x>" # optional
15
+ * ---
16
+ * Body with $ARGUMENTS
17
+ * ```
18
+ *
19
+ * OpenCode command shape:
20
+ * ```
21
+ * ---
22
+ * description: ...
23
+ * ---
24
+ * Body with $ARGUMENTS
25
+ * ```
26
+ *
27
+ * Unlike the command-to-SKILL conversion (which strips `$ARGUMENTS` because a
28
+ * skill has no argument channel), this PRESERVES `$ARGUMENTS` verbatim because
29
+ * OpenCode substitutes it natively (verified on opencode 1.16.2 — the resolved
30
+ * config keeps `$ARGUMENTS` in the command template). The body is otherwise
31
+ * passed through unchanged.
32
+ * @module opencode/command-transformer
33
+ */
34
+ import yaml from "js-yaml";
35
+ /**
36
+ * Pure transform: convert a Lisa command Markdown into an OpenCode command
37
+ * Markdown.
38
+ * @param commandSource - Raw contents of the command .md file
39
+ * @param displayName - Human-readable name used as a fallback description
40
+ * (e.g. "lisa:git:commit")
41
+ * @returns The OpenCode command Markdown content as a string
42
+ */
43
+ export function transformCommandToOpencode(commandSource, displayName) {
44
+ const match = /^---\r?\n([\s\S]*?)\r?\n---\r?\n?([\s\S]*)$/.exec(commandSource);
45
+ if (match === null || match[1] === undefined || match[2] === undefined) {
46
+ throw new Error(`Command source is missing YAML frontmatter for ${displayName}`);
47
+ }
48
+ const description = parseDescription(yaml.load(match[1]), displayName);
49
+ const body = match[2].trimStart().trimEnd();
50
+ const frontmatter = [
51
+ "---",
52
+ `description: ${JSON.stringify(description)}`,
53
+ "---",
54
+ "",
55
+ ].join("\n");
56
+ return `${frontmatter}${body}\n`;
57
+ }
58
+ /**
59
+ * Extract the command description from parsed frontmatter, falling back to the
60
+ * display name when none is present.
61
+ * @param parsed - Output of `yaml.load(rawFrontmatter)` (untrusted shape)
62
+ * @param displayName - Fallback used when no description is available
63
+ * @returns The description string
64
+ */
65
+ function parseDescription(parsed, displayName) {
66
+ if (parsed === null || typeof parsed !== "object") {
67
+ return displayName;
68
+ }
69
+ const obj = parsed;
70
+ return typeof obj.description === "string" && obj.description.length > 0
71
+ ? obj.description
72
+ : displayName;
73
+ }
74
+ //# sourceMappingURL=command-transformer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"command-transformer.js","sourceRoot":"","sources":["../../src/opencode/command-transformer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,OAAO,IAAI,MAAM,SAAS,CAAC;AAE3B;;;;;;;GAOG;AACH,MAAM,UAAU,0BAA0B,CACxC,aAAqB,EACrB,WAAmB;IAEnB,MAAM,KAAK,GAAG,6CAA6C,CAAC,IAAI,CAC9D,aAAa,CACd,CAAC;IACF,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,SAAS,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,SAAS,EAAE,CAAC;QACvE,MAAM,IAAI,KAAK,CACb,kDAAkD,WAAW,EAAE,CAChE,CAAC;IACJ,CAAC;IACD,MAAM,WAAW,GAAG,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,WAAW,CAAC,CAAC;IACvE,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,EAAE,CAAC,OAAO,EAAE,CAAC;IAE5C,MAAM,WAAW,GAAG;QAClB,KAAK;QACL,gBAAgB,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC,EAAE;QAC7C,KAAK;QACL,EAAE;KACH,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAEb,OAAO,GAAG,WAAW,GAAG,IAAI,IAAI,CAAC;AACnC,CAAC;AAED;;;;;;GAMG;AACH,SAAS,gBAAgB,CAAC,MAAe,EAAE,WAAmB;IAC5D,IAAI,MAAM,KAAK,IAAI,IAAI,OAAO,MAAM,KAAK,QAAQ,EAAE,CAAC;QAClD,OAAO,WAAW,CAAC;IACrB,CAAC;IACD,MAAM,GAAG,GAAG,MAAiC,CAAC;IAC9C,OAAO,OAAO,GAAG,CAAC,WAAW,KAAK,QAAQ,IAAI,GAAG,CAAC,WAAW,CAAC,MAAM,GAAG,CAAC;QACtE,CAAC,CAAC,GAAG,CAAC,WAAW;QACjB,CAAC,CAAC,WAAW,CAAC;AAClB,CAAC"}
package/package.json CHANGED
@@ -84,7 +84,7 @@
84
84
  "lodash": ">=4.18.1"
85
85
  },
86
86
  "name": "@codyswann/lisa",
87
- "version": "2.150.1",
87
+ "version": "2.151.0",
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": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa",
3
- "version": "2.150.1",
3
+ "version": "2.151.0",
4
4
  "description": "Universal governance — agents, skills, commands, hooks, and rules for all projects",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa",
3
- "version": "2.150.1",
3
+ "version": "2.151.0",
4
4
  "description": "Universal governance: agents, skills, commands, hooks, and rules for all projects.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa",
3
- "version": "2.150.1",
3
+ "version": "2.151.0",
4
4
  "description": "Universal governance — agents, skills, commands, hooks, and rules for all projects",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-cdk",
3
- "version": "2.150.1",
3
+ "version": "2.151.0",
4
4
  "description": "AWS CDK-specific plugin",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-cdk",
3
- "version": "2.150.1",
3
+ "version": "2.151.0",
4
4
  "description": "AWS CDK-specific Lisa plugin.",
5
5
  "author": {
6
6
  "name": "Cody Swann"