codiedev 0.9.67 → 0.9.68

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.
@@ -0,0 +1,45 @@
1
+ export interface CodiePackConfig {
2
+ skillPaths: string[];
3
+ agents: Record<string, {
4
+ description: string;
5
+ prompt: string;
6
+ mode: "subagent";
7
+ model?: string;
8
+ }>;
9
+ plugins: string[];
10
+ notes: string[];
11
+ }
12
+ /** A model the account approves, as Codie's catalog lists it. */
13
+ export interface LevelCatalogModel {
14
+ id: string;
15
+ name?: string;
16
+ cost?: {
17
+ input: number;
18
+ output: number;
19
+ };
20
+ tier?: string;
21
+ level?: string;
22
+ }
23
+ /** Resolve an agent level (opus = Strongest, sonnet = Balanced, haiku =
24
+ * Fastest) to one of the account's approved models:
25
+ * 1. explicit tier/level metadata on the catalog entry, when the gateway sends it
26
+ * 2. the same model family by name (e.g. a "claude-opus-…" model), newest first
27
+ * 3. by price: Strongest = priciest, Fastest = cheapest, Balanced = in between
28
+ * Otherwise undefined → Codie's governed default. Only catalog ids are returned. */
29
+ export declare function levelToModel(level: string, catalog: LevelCatalogModel[]): {
30
+ model?: string;
31
+ how: string;
32
+ };
33
+ /** Map a Claude agent `model:` to an OpenCode model id, or undefined to let
34
+ * Codie's governed default apply. */
35
+ export declare function mapAgentModel(value: string | undefined, approved?: Set<string>, catalog?: LevelCatalogModel[]): {
36
+ model?: string;
37
+ note?: string;
38
+ };
39
+ export declare function codiePackConfig(root: string, options?: {
40
+ approvedModels?: Set<string>;
41
+ catalog?: LevelCatalogModel[];
42
+ }): CodiePackConfig;
43
+ /** Merge pack config into an OpenCode config without clobbering anything the
44
+ * user or Codie already set: existing skill paths, agents and plugins win. */
45
+ export declare function mergeCodiePackConfig(existing: Record<string, any>, packs: CodiePackConfig): Record<string, any>;
@@ -0,0 +1,197 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.levelToModel = levelToModel;
37
+ exports.mapAgentModel = mapAgentModel;
38
+ exports.codiePackConfig = codiePackConfig;
39
+ exports.mergeCodiePackConfig = mergeCodiePackConfig;
40
+ // Codie (our OpenCode launcher) installs nothing: at launch it reads
41
+ // installed.json and injects the packs into OPENCODE_CONFIG_CONTENT.
42
+ const fs = __importStar(require("fs"));
43
+ const path = __importStar(require("path"));
44
+ const url_1 = require("url");
45
+ const manifest_1 = require("./manifest");
46
+ const paths_1 = require("./paths");
47
+ const shim_1 = require("./shim");
48
+ const store_1 = require("./store");
49
+ const LEVEL_LABEL = { opus: "Strongest", sonnet: "Balanced", haiku: "Fastest" };
50
+ function newestFirst(a, b) {
51
+ return b.id.localeCompare(a.id, undefined, { numeric: true });
52
+ }
53
+ /** Resolve an agent level (opus = Strongest, sonnet = Balanced, haiku =
54
+ * Fastest) to one of the account's approved models:
55
+ * 1. explicit tier/level metadata on the catalog entry, when the gateway sends it
56
+ * 2. the same model family by name (e.g. a "claude-opus-…" model), newest first
57
+ * 3. by price: Strongest = priciest, Fastest = cheapest, Balanced = in between
58
+ * Otherwise undefined → Codie's governed default. Only catalog ids are returned. */
59
+ function levelToModel(level, catalog) {
60
+ const key = level.toLowerCase();
61
+ const tierNames = {
62
+ opus: ["strongest", "opus", "high", "max"],
63
+ sonnet: ["balanced", "sonnet", "medium", "default"],
64
+ haiku: ["fastest", "haiku", "low", "fast"],
65
+ };
66
+ const tiered = catalog.filter((m) => [m.tier, m.level].some((t) => typeof t === "string" && tierNames[key].includes(t.toLowerCase())));
67
+ if (tiered.length)
68
+ return { model: [...tiered].sort(newestFirst)[0].id, how: "tier" };
69
+ const family = catalog.filter((m) => new RegExp(`(^|[^a-z])${key}([^a-z]|$)`, "i").test(m.id));
70
+ if (family.length)
71
+ return { model: [...family].sort(newestFirst)[0].id, how: "family" };
72
+ const priced = catalog
73
+ .filter((m) => m.cost && Number.isFinite(m.cost.input) && Number.isFinite(m.cost.output))
74
+ .sort((a, b) => a.cost.input + a.cost.output - (b.cost.input + b.cost.output) || a.id.localeCompare(b.id));
75
+ if (priced.length) {
76
+ const index = key === "haiku" ? 0 : key === "opus" ? priced.length - 1 : Math.floor((priced.length - 1) / 2);
77
+ return { model: priced[index].id, how: "price" };
78
+ }
79
+ return { how: "none" };
80
+ }
81
+ /** Map a Claude agent `model:` to an OpenCode model id, or undefined to let
82
+ * Codie's governed default apply. */
83
+ function mapAgentModel(value, approved, catalog) {
84
+ const model = (value ?? "").trim();
85
+ if (!model || model === "inherit")
86
+ return {};
87
+ const key = model.toLowerCase();
88
+ if (LEVEL_LABEL[key]) {
89
+ const usable = (catalog ?? []).filter((m) => !approved || approved.has(m.id.replace(/^codiedev\//, "")));
90
+ const picked = levelToModel(key, usable);
91
+ if (!picked.model) {
92
+ return { note: `level ${LEVEL_LABEL[key]} (${model}): no matching approved model, using the governed default` };
93
+ }
94
+ return { model: picked.model, note: `level ${LEVEL_LABEL[key]} (${model}) → ${picked.model} (by ${picked.how})` };
95
+ }
96
+ if (!model.includes("/"))
97
+ return { note: `unknown level "${model}", using the governed default` };
98
+ if (approved) {
99
+ const bare = model.replace(/^codiedev\//, "");
100
+ if (!approved.has(bare))
101
+ return { note: `dropped model "${model}" (not approved for this Codiedev account)` };
102
+ }
103
+ return { model };
104
+ }
105
+ function codiePackConfig(root, options = {}) {
106
+ const registry = (0, store_1.readRegistry)(root);
107
+ const result = { skillPaths: [], agents: {}, plugins: [], notes: [] };
108
+ for (const [slug, entry] of Object.entries(registry.packs).sort(([a], [b]) => a.localeCompare(b))) {
109
+ if (!(0, manifest_1.isSafeSegment)(slug) || !Array.isArray(entry.harnesses) || !entry.harnesses.includes("codie"))
110
+ continue;
111
+ const dir = typeof entry.dir === "string" ? entry.dir : "";
112
+ if (!dir || !fs.existsSync(dir))
113
+ continue;
114
+ try {
115
+ const hooks = JSON.parse(fs.readFileSync(path.join(dir, "hooks", "hooks.json"), "utf8"))?.hooks;
116
+ const skipped = (0, shim_1.unsupportedShimEvents)([{ slug, root: dir, hooks: hooks ?? {} }]).get(slug);
117
+ if (skipped?.length)
118
+ result.notes.push(`pack ${slug}: hooks Codie can't run were skipped: ${skipped.join(", ")}`);
119
+ }
120
+ catch {
121
+ // no hooks
122
+ }
123
+ const skills = path.join(dir, "skills");
124
+ if (fs.existsSync(skills))
125
+ result.skillPaths.push(skills);
126
+ const agentsDir = path.join(dir, "agents");
127
+ let agentFiles = [];
128
+ try {
129
+ agentFiles = fs.readdirSync(agentsDir).filter((f) => f.endsWith(".md")).sort();
130
+ }
131
+ catch {
132
+ agentFiles = [];
133
+ }
134
+ for (const file of agentFiles) {
135
+ const fallbackName = file.slice(0, -3);
136
+ let content;
137
+ try {
138
+ content = fs.readFileSync(path.join(agentsDir, file), "utf8");
139
+ }
140
+ catch {
141
+ continue;
142
+ }
143
+ const { data, body } = (0, manifest_1.parseFrontmatter)(content);
144
+ const name = (0, manifest_1.isSafeSegment)(data.name) ? data.name : fallbackName;
145
+ if (result.agents[name]) {
146
+ result.notes.push(`agent "${name}" from pack ${slug} skipped (already defined by another pack)`);
147
+ continue;
148
+ }
149
+ const mapped = mapAgentModel(data.model, options.approvedModels, options.catalog);
150
+ if (mapped.note)
151
+ result.notes.push(`agent "${name}" (${slug}): ${mapped.note}`);
152
+ result.agents[name] = {
153
+ description: data.description || `${name} (from starter pack ${slug})`,
154
+ prompt: body.trim(),
155
+ mode: "subagent",
156
+ ...(mapped.model ? { model: mapped.model } : {}),
157
+ };
158
+ }
159
+ }
160
+ // The shim only exists while some installed pack has hooks.
161
+ const shim = (0, paths_1.shimPath)(root);
162
+ const anyCodie = Object.values(registry.packs).some((e) => Array.isArray(e.harnesses) && e.harnesses.includes("codie"));
163
+ if (anyCodie && fs.existsSync(shim))
164
+ result.plugins.push((0, url_1.pathToFileURL)(shim).href);
165
+ return result;
166
+ }
167
+ /** Merge pack config into an OpenCode config without clobbering anything the
168
+ * user or Codie already set: existing skill paths, agents and plugins win. */
169
+ function mergeCodiePackConfig(existing, packs) {
170
+ const next = { ...existing };
171
+ if (packs.skillPaths.length) {
172
+ // `skills` must be the object form; the array form is rejected by the engine.
173
+ const current = existing.skills;
174
+ const base = Array.isArray(current)
175
+ ? { paths: current.filter((p) => typeof p === "string") }
176
+ : current && typeof current === "object"
177
+ ? { ...current }
178
+ : {};
179
+ const paths = Array.isArray(base.paths) ? [...base.paths] : [];
180
+ for (const p of packs.skillPaths)
181
+ if (!paths.includes(p))
182
+ paths.push(p);
183
+ next.skills = { ...base, paths };
184
+ }
185
+ if (Object.keys(packs.agents).length) {
186
+ const current = existing.agent && typeof existing.agent === "object" ? existing.agent : {};
187
+ next.agent = { ...packs.agents, ...current };
188
+ }
189
+ if (packs.plugins.length) {
190
+ const current = Array.isArray(existing.plugin) ? [...existing.plugin] : [];
191
+ for (const p of packs.plugins)
192
+ if (!current.includes(p))
193
+ current.push(p);
194
+ next.plugin = current;
195
+ }
196
+ return next;
197
+ }
@@ -0,0 +1,71 @@
1
+ import { PackManifest } from "./manifest";
2
+ import { RegistryEntry } from "./store";
3
+ export declare const HARNESSES: readonly ["claude", "copilot", "codex", "cursor", "codie"];
4
+ export type HarnessName = (typeof HARNESSES)[number];
5
+ export interface RunResult {
6
+ status: number | null;
7
+ stdout: string;
8
+ stderr: string;
9
+ error?: string;
10
+ }
11
+ export type Runner = (command: string, args: string[], options?: {
12
+ cwd?: string;
13
+ }) => RunResult;
14
+ export declare function defaultRunner(env: NodeJS.ProcessEnv): Runner;
15
+ /** True when `bin` is an executable file on `env.PATH`. */
16
+ export declare function onPath(bin: string, env: NodeJS.ProcessEnv): boolean;
17
+ export interface AdapterContext {
18
+ root: string;
19
+ env: NodeJS.ProcessEnv;
20
+ home: string;
21
+ run: Runner;
22
+ manifest: PackManifest;
23
+ pluginDir: string;
24
+ /** Same plugin without agent model levels (Codex, Copilot, Cursor). */
25
+ portablePluginDir: string;
26
+ previous?: RegistryEntry;
27
+ }
28
+ export interface AdapterResult {
29
+ harness: HarnessName;
30
+ status: "ok" | "skipped" | "failed" | "dry-run";
31
+ detail: string;
32
+ /** Debug-level notes (printed with CODIEDEV_DEBUG; always in --json). */
33
+ notes?: string[];
34
+ }
35
+ export interface Adapter {
36
+ name: HarnessName;
37
+ detect(ctx: Omit<AdapterContext, "manifest" | "pluginDir" | "portablePluginDir" | "previous">): boolean;
38
+ /** Returns a short success detail; throws on failure. */
39
+ install(ctx: AdapterContext): string;
40
+ /** Human-readable description of what install would do (for --dry-run). */
41
+ plan(ctx: AdapterContext): string;
42
+ /** Remove the pack from this tool. Returns a detail; throws on failure. */
43
+ uninstall(ctx: UninstallContext): string;
44
+ }
45
+ export interface UninstallContext {
46
+ root: string;
47
+ env: NodeJS.ProcessEnv;
48
+ home: string;
49
+ run: Runner;
50
+ slug: string;
51
+ }
52
+ export declare const claudeAdapter: Adapter;
53
+ export declare const copilotAdapter: Adapter;
54
+ export declare const codexAdapter: Adapter;
55
+ export declare const CURSOR_MARKER = ".codiedev-pack";
56
+ /** Fallback: copy skills to ~/.cursor/skills/<name>/, never overwriting a
57
+ * skill dir Codiedev didn't write, and pruning ones this pack no longer has. */
58
+ export declare function copyCursorSkills(home: string, manifest: PackManifest, pluginDirPath: string): string[];
59
+ /** Remove every ~/.cursor/skills dir this pack's fallback copy wrote. */
60
+ export declare function removeCursorSkills(home: string, slug: string): number;
61
+ export declare function cursorLocalPluginsDir(home: string): string;
62
+ export declare function cursorPluginDir(home: string, slug: string): string;
63
+ /** Copy the plugin dir into place via a sibling temp dir + rename. Refuses to
64
+ * replace a dir that doesn't carry our marker for this pack. */
65
+ export declare function installCursorPlugin(home: string, slug: string, sourceDir: string): string;
66
+ /** Remove our copy (only when it carries our marker). */
67
+ export declare function removeCursorPlugin(home: string, slug: string): boolean;
68
+ export declare const cursorAdapter: Adapter;
69
+ export declare const codieAdapter: Adapter;
70
+ export declare const ADAPTERS: Adapter[];
71
+ export declare function parseHarnessList(value: string | undefined): HarnessName[] | undefined;