codiedev 0.9.66 → 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,167 @@
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.AGENT_LEVELS = void 0;
37
+ exports.pluginVersion = pluginVersion;
38
+ exports.writeFileAtomic = writeFileAtomic;
39
+ exports.portableAgentContent = portableAgentContent;
40
+ exports.pluginFiles = pluginFiles;
41
+ exports.writePluginDir = writePluginDir;
42
+ exports.readRegistry = readRegistry;
43
+ exports.writeRegistry = writeRegistry;
44
+ exports.marketplaceDocument = marketplaceDocument;
45
+ exports.writeMarketplace = writeMarketplace;
46
+ // On-disk layout for installed packs: the Claude-format plugin dir, the local
47
+ // marketplace that every harness reads, and the installed.json registry.
48
+ const fs = __importStar(require("fs"));
49
+ const skillMarker_1 = require("../skillMarker");
50
+ const path = __importStar(require("path"));
51
+ const paths_1 = require("./paths");
52
+ function pluginVersion(version) {
53
+ return `${version}.0.0`;
54
+ }
55
+ /** Write a file via temp + rename so readers never see a partial file. */
56
+ function writeFileAtomic(file, content, mode = 0o644) {
57
+ fs.mkdirSync(path.dirname(file), { recursive: true });
58
+ const tmp = `${file}.${process.pid}.${Date.now()}.tmp`;
59
+ fs.writeFileSync(tmp, content, { encoding: "utf8", mode });
60
+ fs.renameSync(tmp, file);
61
+ }
62
+ exports.AGENT_LEVELS = new Set(["opus", "sonnet", "haiku"]);
63
+ /** Agent file for tools other than Claude Code: drop a `model:` line unless it
64
+ * is a full `provider/model` id (levels and `inherit` are Claude aliases). */
65
+ function portableAgentContent(content) {
66
+ const fm = content.match(/^(\uFEFF?---\r?\n)([\s\S]*?)(\r?\n---[ \t]*(?:\r?\n|$))/);
67
+ if (!fm)
68
+ return content;
69
+ const lines = fm[2].split(/\r?\n/);
70
+ const kept = lines.filter((line) => {
71
+ const m = line.match(/^model\s*:\s*["']?([^"'\r\n]*?)["']?\s*$/);
72
+ return !m || m[1].includes("/");
73
+ });
74
+ if (kept.length === lines.length)
75
+ return content;
76
+ return fm[1] + kept.join("\n") + fm[3] + content.slice(fm[0].length);
77
+ }
78
+ /** The full file set for a pack's plugin dir, relative path → content. */
79
+ function pluginFiles(manifest, options = {}) {
80
+ const files = {};
81
+ files[path.join(".claude-plugin", "plugin.json")] = JSON.stringify({
82
+ name: manifest.slug,
83
+ version: pluginVersion(manifest.version),
84
+ description: manifest.description || manifest.name,
85
+ }, null, 2) + "\n";
86
+ for (const skill of manifest.skills) {
87
+ // Identity marker so the skill's runs attribute to this exact artifact.
88
+ files[path.join("skills", skill.name, "SKILL.md")] = (0, skillMarker_1.stampSkillMarker)(skill.content, skill.artifactId);
89
+ }
90
+ for (const agent of manifest.agents) {
91
+ files[path.join("agents", `${agent.name}.md`)] = options.portable ? portableAgentContent(agent.content) : agent.content;
92
+ }
93
+ if (manifest.hooksJson) {
94
+ files[path.join("hooks", "hooks.json")] = manifest.hooksJson;
95
+ }
96
+ return files;
97
+ }
98
+ function assertInside(parent, child) {
99
+ const rel = path.relative(parent, child);
100
+ if (!rel || rel.startsWith("..") || path.isAbsolute(rel)) {
101
+ throw new Error(`refusing to write outside the pack dir: ${child}`);
102
+ }
103
+ }
104
+ /** Build the plugin dir in a sibling temp dir and swap it into place, so a
105
+ * failed write never leaves a half-updated plugin and stale files (a removed
106
+ * skill, hooks that were cleared) never linger. */
107
+ function writePluginDir(root, manifest, options = {}) {
108
+ const target = (0, paths_1.pluginDir)(root, manifest.slug);
109
+ const parent = (0, paths_1.pluginsDir)(root);
110
+ assertInside(parent, target);
111
+ fs.mkdirSync(parent, { recursive: true });
112
+ const stamp = `${process.pid}-${Date.now()}`;
113
+ const tmp = path.join(parent, `.${manifest.slug}.tmp-${stamp}`);
114
+ const old = path.join(parent, `.${manifest.slug}.old-${stamp}`);
115
+ try {
116
+ for (const [rel, content] of Object.entries(pluginFiles(manifest, options))) {
117
+ const file = path.join(tmp, rel);
118
+ assertInside(tmp, file);
119
+ fs.mkdirSync(path.dirname(file), { recursive: true });
120
+ fs.writeFileSync(file, content, "utf8");
121
+ }
122
+ if (fs.existsSync(target))
123
+ fs.renameSync(target, old);
124
+ fs.renameSync(tmp, target);
125
+ }
126
+ catch (error) {
127
+ fs.rmSync(tmp, { recursive: true, force: true });
128
+ if (!fs.existsSync(target) && fs.existsSync(old))
129
+ fs.renameSync(old, target);
130
+ throw error;
131
+ }
132
+ fs.rmSync(old, { recursive: true, force: true });
133
+ return target;
134
+ }
135
+ function readRegistry(root) {
136
+ try {
137
+ const parsed = JSON.parse(fs.readFileSync((0, paths_1.registryPath)(root), "utf8"));
138
+ if (parsed && typeof parsed === "object" && parsed.packs && typeof parsed.packs === "object") {
139
+ return { packs: parsed.packs };
140
+ }
141
+ }
142
+ catch {
143
+ // Missing or corrupt registry → start fresh.
144
+ }
145
+ return { packs: {} };
146
+ }
147
+ function writeRegistry(root, registry) {
148
+ writeFileAtomic((0, paths_1.registryPath)(root), JSON.stringify(registry, null, 2) + "\n");
149
+ }
150
+ function marketplaceDocument(entries) {
151
+ const sorted = [...entries].sort((a, b) => a.slug.localeCompare(b.slug));
152
+ return {
153
+ name: paths_1.MARKETPLACE_NAME,
154
+ owner: { name: "Codiedev" },
155
+ metadata: { description: "Codiedev team starter packs" },
156
+ plugins: sorted.map((entry) => ({
157
+ name: entry.slug,
158
+ source: `./plugins/${entry.slug}`,
159
+ description: entry.description || entry.slug,
160
+ version: pluginVersion(entry.version),
161
+ })),
162
+ };
163
+ }
164
+ /** Rewrite marketplace.json atomically with one entry per pack. */
165
+ function writeMarketplace(root, entries) {
166
+ writeFileAtomic((0, paths_1.marketplacePath)(root), JSON.stringify(marketplaceDocument(entries), null, 2) + "\n");
167
+ }
@@ -0,0 +1,40 @@
1
+ import { spawn as nodeSpawn } from "child_process";
2
+ export declare const SYNC_INTERVAL_MS: number;
3
+ /** CI mode: a pack-scoped CI key (`cdvci_…`) or CI=true. No auto-sync, no
4
+ * nudge, no server writes, no pruning — CI machines are ephemeral and CI keys
5
+ * can only read packs. */
6
+ export declare function isPackCiMode(env?: NodeJS.ProcessEnv): boolean;
7
+ export declare const NAG_INTERVAL_MS: number;
8
+ export declare const EMPTY_RECHECK_MS: number;
9
+ export interface StatusCache {
10
+ checkedAt: number;
11
+ available: number;
12
+ outdated: Array<{
13
+ slug: string;
14
+ name?: string;
15
+ }>;
16
+ }
17
+ export declare function readStatusCache(root: string): StatusCache | null;
18
+ export declare function writeStatusCache(root: string, cache: StatusCache): void;
19
+ export declare function autosyncDisabled(env: NodeJS.ProcessEnv): boolean;
20
+ export type SyncDecision = "spawn-install" | "spawn-check" | "throttled" | "no-packs";
21
+ /** Pure decision for the hourly background sync. */
22
+ export declare function decideSync(root: string, env: NodeJS.ProcessEnv, now: number): SyncDecision;
23
+ export declare function cliEntry(): string;
24
+ export interface SpawnSyncOptions {
25
+ env?: NodeJS.ProcessEnv;
26
+ home?: string;
27
+ now?: number;
28
+ spawn?: typeof nodeSpawn;
29
+ cli?: string;
30
+ connected?: boolean;
31
+ }
32
+ /** Called from session-start hooks. Never throws, never waits. */
33
+ export declare function maybeSpawnPackSync(options?: SpawnSyncOptions): SyncDecision | "error" | "not-connected" | "ci";
34
+ /** One-line nudge when the cached status shows an outdated pack, at most once
35
+ * a day. Returns null (and records nothing) when there's nothing to say. */
36
+ export declare function packNagLine(options?: {
37
+ env?: NodeJS.ProcessEnv;
38
+ home?: string;
39
+ now?: number;
40
+ }): string | null;
@@ -0,0 +1,190 @@
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.EMPTY_RECHECK_MS = exports.NAG_INTERVAL_MS = exports.SYNC_INTERVAL_MS = void 0;
37
+ exports.isPackCiMode = isPackCiMode;
38
+ exports.readStatusCache = readStatusCache;
39
+ exports.writeStatusCache = writeStatusCache;
40
+ exports.autosyncDisabled = autosyncDisabled;
41
+ exports.decideSync = decideSync;
42
+ exports.cliEntry = cliEntry;
43
+ exports.maybeSpawnPackSync = maybeSpawnPackSync;
44
+ exports.packNagLine = packNagLine;
45
+ // Background auto-update and the "pack has updates" nudge.
46
+ //
47
+ // Hot-path rule: maybeSpawnPackSync and packNagLine run inside session-start
48
+ // hooks and every `codiedev` command, so they only stat/read tiny local files
49
+ // and, at most once an hour, spawn a detached child. No network here, ever.
50
+ const fs = __importStar(require("fs"));
51
+ const os = __importStar(require("os"));
52
+ const path = __importStar(require("path"));
53
+ const child_process_1 = require("child_process");
54
+ const paths_1 = require("./paths");
55
+ const store_1 = require("./store");
56
+ exports.SYNC_INTERVAL_MS = 60 * 60 * 1000;
57
+ /** CI mode: a pack-scoped CI key (`cdvci_…`) or CI=true. No auto-sync, no
58
+ * nudge, no server writes, no pruning — CI machines are ephemeral and CI keys
59
+ * can only read packs. */
60
+ function isPackCiMode(env = process.env) {
61
+ const ci = (env.CI ?? "").trim().toLowerCase();
62
+ return (env.CODIEDEV_TOKEN ?? "").trim().startsWith("cdvci_") || ci === "true" || ci === "1";
63
+ }
64
+ exports.NAG_INTERVAL_MS = 24 * 60 * 60 * 1000;
65
+ // With nothing installed and a fresh "your team has no packs" answer, only
66
+ // re-ask once a day so a newly assigned pack still arrives.
67
+ exports.EMPTY_RECHECK_MS = 24 * 60 * 60 * 1000;
68
+ function readStatusCache(root) {
69
+ try {
70
+ const parsed = JSON.parse(fs.readFileSync((0, paths_1.statusCachePath)(root), "utf8"));
71
+ if (typeof parsed?.checkedAt !== "number")
72
+ return null;
73
+ return {
74
+ checkedAt: parsed.checkedAt,
75
+ available: typeof parsed.available === "number" ? parsed.available : 0,
76
+ outdated: Array.isArray(parsed.outdated) ? parsed.outdated.filter((o) => typeof o?.slug === "string") : [],
77
+ };
78
+ }
79
+ catch {
80
+ return null;
81
+ }
82
+ }
83
+ function writeStatusCache(root, cache) {
84
+ try {
85
+ (0, store_1.writeFileAtomic)((0, paths_1.statusCachePath)(root), JSON.stringify(cache) + "\n");
86
+ }
87
+ catch {
88
+ // best-effort
89
+ }
90
+ }
91
+ function mtime(file) {
92
+ try {
93
+ return fs.statSync(file).mtimeMs;
94
+ }
95
+ catch {
96
+ return null;
97
+ }
98
+ }
99
+ function registryNonEmpty(root) {
100
+ // installed.json is tiny; `{"packs":{}}` means nothing is installed.
101
+ try {
102
+ const parsed = JSON.parse(fs.readFileSync((0, paths_1.registryPath)(root), "utf8"));
103
+ return Boolean(parsed?.packs && Object.keys(parsed.packs).length > 0);
104
+ }
105
+ catch {
106
+ return false;
107
+ }
108
+ }
109
+ function autosyncDisabled(env) {
110
+ const v = (env.CODIEDEV_PACK_AUTOSYNC ?? "").trim().toLowerCase();
111
+ return v === "0" || v === "false" || v === "off" || v === "no";
112
+ }
113
+ /** Pure decision for the hourly background sync. */
114
+ function decideSync(root, env, now) {
115
+ const last = mtime((0, paths_1.lastSyncPath)(root));
116
+ if (last !== null && now - last < exports.SYNC_INTERVAL_MS && last <= now)
117
+ return "throttled";
118
+ if (!registryNonEmpty(root)) {
119
+ const cache = readStatusCache(root);
120
+ if (cache && cache.available === 0 && now - cache.checkedAt < exports.EMPTY_RECHECK_MS)
121
+ return "no-packs";
122
+ }
123
+ // Opted out of auto-install: still refresh the cached status (read-only,
124
+ // no install, no pruning) so the outdated nudge can tell them.
125
+ return autosyncDisabled(env) ? "spawn-check" : "spawn-install";
126
+ }
127
+ function cliEntry() {
128
+ // dist/packs/sync.js → dist/cli.js
129
+ return path.join(__dirname, "..", "cli.js");
130
+ }
131
+ /** Called from session-start hooks. Never throws, never waits. */
132
+ function maybeSpawnPackSync(options = {}) {
133
+ try {
134
+ if (options.connected === false)
135
+ return "not-connected";
136
+ const env = options.env ?? process.env;
137
+ if (isPackCiMode(env))
138
+ return "ci";
139
+ const root = (0, paths_1.packsRoot)(env, options.home ?? os.homedir());
140
+ const now = options.now ?? Date.now();
141
+ const decision = decideSync(root, env, now);
142
+ if (decision !== "spawn-install" && decision !== "spawn-check")
143
+ return decision;
144
+ // Stamp first so concurrent session starts don't each spawn a sync.
145
+ fs.mkdirSync(root, { recursive: true });
146
+ fs.writeFileSync((0, paths_1.lastSyncPath)(root), String(now));
147
+ const time = new Date(now);
148
+ fs.utimesSync((0, paths_1.lastSyncPath)(root), time, time);
149
+ const args = decision === "spawn-install"
150
+ ? ["pack", "install", "--quiet"]
151
+ : ["pack", "status", "--quiet", "--no-prune"];
152
+ const child = (options.spawn ?? child_process_1.spawn)(process.execPath, [options.cli ?? cliEntry(), ...args], {
153
+ detached: true,
154
+ stdio: "ignore",
155
+ env: { ...env, CODIEDEV_PACK_BACKGROUND: "1" },
156
+ });
157
+ child.on?.("error", () => { });
158
+ child.unref?.();
159
+ return decision;
160
+ }
161
+ catch {
162
+ return "error";
163
+ }
164
+ }
165
+ /** One-line nudge when the cached status shows an outdated pack, at most once
166
+ * a day. Returns null (and records nothing) when there's nothing to say. */
167
+ function packNagLine(options = {}) {
168
+ try {
169
+ const env = options.env ?? process.env;
170
+ if (env.CODIEDEV_PACK_BACKGROUND || isPackCiMode(env))
171
+ return null;
172
+ const root = (0, paths_1.packsRoot)(env, options.home ?? os.homedir());
173
+ const now = options.now ?? Date.now();
174
+ const cache = readStatusCache(root);
175
+ if (!cache || cache.outdated.length === 0)
176
+ return null;
177
+ const last = mtime((0, paths_1.lastNagPath)(root));
178
+ if (last !== null && now - last < exports.NAG_INTERVAL_MS && last <= now)
179
+ return null;
180
+ fs.writeFileSync((0, paths_1.lastNagPath)(root), String(now));
181
+ const time = new Date(now);
182
+ fs.utimesSync((0, paths_1.lastNagPath)(root), time, time);
183
+ const first = cache.outdated[0];
184
+ const more = cache.outdated.length > 1 ? ` (+${cache.outdated.length - 1} more)` : "";
185
+ return `Starter pack ${first.name || first.slug}${more} has updates. Run \`codiedev pack install\`.`;
186
+ }
187
+ catch {
188
+ return null;
189
+ }
190
+ }
@@ -0,0 +1,6 @@
1
+ /** Is this a SKILL.md-style file (frontmatter with name + description)? */
2
+ export declare function looksLikeSkill(markdown: string): boolean;
3
+ /** Remove every marker line (idempotent). */
4
+ export declare function stripSkillMarker(markdown: string): string;
5
+ /** Stamp (or re-stamp) the marker. Leaves the text alone for a bad id. */
6
+ export declare function stampSkillMarker(markdown: string, artifactId: string | undefined | null): string;
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+ // Skill identity marker. Two authors can each publish a skill with the same
3
+ // name ("/ticket"); a session's transcript only records the name it ran. A
4
+ // company skill written to disk therefore carries the artifact it came from:
5
+ //
6
+ // <!-- codiedev:artifact=<artifact id> -->
7
+ //
8
+ // appended after the body (frontmatter untouched, invisible when rendered).
9
+ // When the harness loads the skill, the marker lands in the transcript and
10
+ // parseCaptureSignals reports it as signals.skillInvocationArtifacts, so the
11
+ // portal attributes the run to the exact skill. `push` strips it, so a
12
+ // re-pushed copy never claims someone else's artifact id.
13
+ Object.defineProperty(exports, "__esModule", { value: true });
14
+ exports.looksLikeSkill = looksLikeSkill;
15
+ exports.stripSkillMarker = stripSkillMarker;
16
+ exports.stampSkillMarker = stampSkillMarker;
17
+ const ID = /^[a-z0-9]{16,64}$/i;
18
+ const LINE = /^[ \t]*<!--\s*codiedev:artifact=[a-z0-9]+\s*-->[ \t]*(?:\r?\n|$)/gim;
19
+ /** Is this a SKILL.md-style file (frontmatter with name + description)? */
20
+ function looksLikeSkill(markdown) {
21
+ const fm = markdown.match(/^?---\r?\n([\s\S]*?)\r?\n---/);
22
+ if (!fm)
23
+ return false;
24
+ return /^name\s*:/im.test(fm[1]) && /^description\s*:/im.test(fm[1]);
25
+ }
26
+ /** Remove every marker line (idempotent). */
27
+ function stripSkillMarker(markdown) {
28
+ return markdown.replace(LINE, "");
29
+ }
30
+ /** Stamp (or re-stamp) the marker. Leaves the text alone for a bad id. */
31
+ function stampSkillMarker(markdown, artifactId) {
32
+ if (!artifactId || !ID.test(artifactId))
33
+ return markdown;
34
+ const body = stripSkillMarker(markdown);
35
+ const sep = body.endsWith("\n") ? "" : "\n";
36
+ return `${body}${sep}<!-- codiedev:artifact=${artifactId} -->\n`;
37
+ }
package/dist/subagents.js CHANGED
@@ -87,10 +87,14 @@ function foldSubagentSignals(parent, subs, source) {
87
87
  const invocations = new Set(parent.skillInvocations);
88
88
  const pulls = new Set(parent.skillPulls);
89
89
  const tools = new Map(parent.toolCalls.map((t) => [t.name, t.calls]));
90
+ const artifacts = new Map((parent.skillInvocationArtifacts ?? []).map((a) => [a.skill, a.artifactId]));
90
91
  let truncated = parent.truncated;
91
92
  for (const content of subs.contents) {
92
93
  const s = (0, captureSignals_1.parseCaptureSignals)(content, source);
93
94
  add(s.skillInvocationCounts, s.skillInvocations);
95
+ for (const a of s.skillInvocationArtifacts ?? [])
96
+ if (!artifacts.has(a.skill))
97
+ artifacts.set(a.skill, a.artifactId);
94
98
  for (const k of s.skillInvocations)
95
99
  invocations.add(k);
96
100
  for (const k of s.skillPulls)
@@ -108,6 +112,9 @@ function foldSubagentSignals(parent, subs, source) {
108
112
  ...parent,
109
113
  skillInvocations: cap([...invocations].sort()),
110
114
  skillInvocationCounts: cap([...counts].map(([skill, count]) => ({ skill, count: Math.min(count, 10_000) })).sort((a, b) => a.skill.localeCompare(b.skill))),
115
+ ...(artifacts.size
116
+ ? { skillInvocationArtifacts: cap([...artifacts].map(([skill, artifactId]) => ({ skill, artifactId })).sort((a, b) => a.skill.localeCompare(b.skill))) }
117
+ : {}),
111
118
  skillPulls: cap([...pulls].sort()),
112
119
  toolCalls: cap([...tools].map(([name, calls]) => ({ name, calls })).sort((a, b) => a.name.localeCompare(b.name))),
113
120
  subagents: { count: subs.count, truncated: subs.truncated },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codiedev",
3
- "version": "0.9.66",
3
+ "version": "0.9.68",
4
4
  "description": "Connect Claude Code, Codex, Cursor, OpenCode, or VS Code Copilot to Codiedev for team session capture and artifact collaboration — and run the governed Codie harness",
5
5
  "bin": {
6
6
  "codiedev": "dist/cli.js",