codiedev 0.9.66 → 0.9.67
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/captureSignals.d.ts +7 -0
- package/dist/captureSignals.js +23 -2
- package/dist/commands/pull.js +8 -3
- package/dist/commands/push.js +3 -1
- package/dist/mcp.js +5 -2
- package/dist/skillMarker.d.ts +6 -0
- package/dist/skillMarker.js +37 -0
- package/dist/subagents.js +7 -0
- package/package.json +1 -1
package/dist/captureSignals.d.ts
CHANGED
|
@@ -15,6 +15,13 @@ export type CaptureSignals = {
|
|
|
15
15
|
skill: string;
|
|
16
16
|
count: number;
|
|
17
17
|
}>;
|
|
18
|
+
/** Which skill ARTIFACT an invocation ran, when the loaded skill content
|
|
19
|
+
* carried a `codiedev:artifact=<id>` marker. Lets the server tell two
|
|
20
|
+
* authors' same-named skills apart. Absent when no marker was seen. */
|
|
21
|
+
skillInvocationArtifacts?: Array<{
|
|
22
|
+
skill: string;
|
|
23
|
+
artifactId: string;
|
|
24
|
+
}>;
|
|
18
25
|
skillPulls: string[];
|
|
19
26
|
toolCalls: Array<{
|
|
20
27
|
name: string;
|
package/dist/captureSignals.js
CHANGED
|
@@ -24,6 +24,17 @@ function parseCaptureSignals(content, source) {
|
|
|
24
24
|
let parsedRecords = 0, truncated = false;
|
|
25
25
|
let premiumRequests, nanoAiu;
|
|
26
26
|
let cursorSubagents;
|
|
27
|
+
// The skill content a harness loads after an invocation follows it in the
|
|
28
|
+
// transcript; a marker there names the artifact the invocation ran.
|
|
29
|
+
const artifacts = new Map();
|
|
30
|
+
let lastInvoked = null;
|
|
31
|
+
const marker = (text) => {
|
|
32
|
+
if (!lastInvoked || artifacts.has(lastInvoked))
|
|
33
|
+
return;
|
|
34
|
+
const m = text.match(/codiedev:artifact=([a-z0-9]{16,64})/i);
|
|
35
|
+
if (m && artifacts.size < LIMIT)
|
|
36
|
+
artifacts.set(lastInvoked, m[1]);
|
|
37
|
+
};
|
|
27
38
|
const addSkill = (set, value) => {
|
|
28
39
|
const key = skillKey(value);
|
|
29
40
|
if (!key || key.length > 200 || !/^[a-z0-9][a-z0-9_:/.-]*$/i.test(key))
|
|
@@ -33,8 +44,10 @@ function parseCaptureSignals(content, source) {
|
|
|
33
44
|
return;
|
|
34
45
|
}
|
|
35
46
|
set.add(key);
|
|
36
|
-
if (set === invocations)
|
|
47
|
+
if (set === invocations) {
|
|
37
48
|
invocationCounts.set(key, (invocationCounts.get(key) ?? 0) + 1);
|
|
49
|
+
lastInvoked = key;
|
|
50
|
+
}
|
|
38
51
|
};
|
|
39
52
|
const command = (value) => {
|
|
40
53
|
if (typeof value !== "string")
|
|
@@ -113,14 +126,19 @@ function parseCaptureSignals(content, source) {
|
|
|
113
126
|
for (const part of blocks) {
|
|
114
127
|
if (part?.type === "tool_use")
|
|
115
128
|
tool(part.name, part.id, part.input);
|
|
129
|
+
if (part?.type === "tool_result")
|
|
130
|
+
marker(typeof part.content === "string" ? part.content : JSON.stringify(part.content ?? ""));
|
|
116
131
|
if (part?.type === "text" && e.type === "user") {
|
|
117
132
|
for (const match of String(part.text ?? "").matchAll(/<command-name>\/?([a-z0-9:_-]+)<\/command-name>/gi))
|
|
118
133
|
addSkill(invocations, match[1]);
|
|
134
|
+
marker(String(part.text ?? ""));
|
|
119
135
|
}
|
|
120
136
|
}
|
|
121
|
-
if (typeof blocks === "string" && e.type === "user")
|
|
137
|
+
if (typeof blocks === "string" && e.type === "user") {
|
|
122
138
|
for (const match of blocks.matchAll(/<command-name>\/?([a-z0-9:_-]+)<\/command-name>/gi))
|
|
123
139
|
addSkill(invocations, match[1]);
|
|
140
|
+
marker(blocks);
|
|
141
|
+
}
|
|
124
142
|
if (e.type === "response_item" &&
|
|
125
143
|
["function_call", "custom_tool_call"].includes(e.payload?.type))
|
|
126
144
|
tool(e.payload.name, e.payload.call_id, e.payload.arguments ?? e.payload.input);
|
|
@@ -150,6 +168,9 @@ function parseCaptureSignals(content, source) {
|
|
|
150
168
|
skillInvocationCounts: [...invocationCounts]
|
|
151
169
|
.map(([skill, count]) => ({ skill, count }))
|
|
152
170
|
.sort((a, b) => a.skill.localeCompare(b.skill)),
|
|
171
|
+
...(artifacts.size
|
|
172
|
+
? { skillInvocationArtifacts: [...artifacts].map(([skill, artifactId]) => ({ skill, artifactId })).sort((a, b) => a.skill.localeCompare(b.skill)) }
|
|
173
|
+
: {}),
|
|
153
174
|
skillPulls: [...pulls].sort(),
|
|
154
175
|
toolCalls: [...tools]
|
|
155
176
|
.map(([name, calls]) => ({ name, calls }))
|
package/dist/commands/pull.js
CHANGED
|
@@ -38,6 +38,7 @@ exports.runPull = runPull;
|
|
|
38
38
|
const fs = __importStar(require("fs"));
|
|
39
39
|
const path = __importStar(require("path"));
|
|
40
40
|
const shared_1 = require("./shared");
|
|
41
|
+
const skillMarker_1 = require("../skillMarker");
|
|
41
42
|
function parseArgs(args) {
|
|
42
43
|
let key;
|
|
43
44
|
let version;
|
|
@@ -104,6 +105,10 @@ async function runPull(args) {
|
|
|
104
105
|
}
|
|
105
106
|
}
|
|
106
107
|
const a = res.artifact;
|
|
108
|
+
// A skill carries its identity onto disk so its runs attribute exactly
|
|
109
|
+
// (see skillMarker.ts). Docs are written verbatim.
|
|
110
|
+
const isSkill = a.kind ? a.kind === "skill" : (0, skillMarker_1.looksLikeSkill)(a.markdown);
|
|
111
|
+
const markdown = isSkill ? (0, skillMarker_1.stampSkillMarker)(a.markdown, a._id) : a.markdown;
|
|
107
112
|
(0, shared_1.recordAgentEvent)(config, {
|
|
108
113
|
tool: "codiedev_pull",
|
|
109
114
|
ok: true,
|
|
@@ -111,7 +116,7 @@ async function runPull(args) {
|
|
|
111
116
|
});
|
|
112
117
|
if (out) {
|
|
113
118
|
const absolute = path.isAbsolute(out) ? out : path.resolve(process.cwd(), out);
|
|
114
|
-
fs.writeFileSync(absolute,
|
|
119
|
+
fs.writeFileSync(absolute, markdown, "utf8");
|
|
115
120
|
console.log(`✓ Pulled ${a.key} v${a.version ?? 1} (${a.type}) → ${absolute}`);
|
|
116
121
|
console.log(` title: ${a.title}`);
|
|
117
122
|
console.log(` lifecycle: ${a.lifecycle ?? "draft"}`);
|
|
@@ -119,8 +124,8 @@ async function runPull(args) {
|
|
|
119
124
|
}
|
|
120
125
|
else {
|
|
121
126
|
// Stream to stdout — preserves shell pipes like `codiedev pull spec-214.md | less`.
|
|
122
|
-
process.stdout.write(
|
|
123
|
-
if (!
|
|
127
|
+
process.stdout.write(markdown);
|
|
128
|
+
if (!markdown.endsWith("\n"))
|
|
124
129
|
process.stdout.write("\n");
|
|
125
130
|
}
|
|
126
131
|
}
|
package/dist/commands/push.js
CHANGED
|
@@ -37,6 +37,7 @@ exports.parseArgs = parseArgs;
|
|
|
37
37
|
exports.pushFile = pushFile;
|
|
38
38
|
exports.runPush = runPush;
|
|
39
39
|
const fs = __importStar(require("fs"));
|
|
40
|
+
const skillMarker_1 = require("../skillMarker");
|
|
40
41
|
const path = __importStar(require("path"));
|
|
41
42
|
const shared = __importStar(require("./shared"));
|
|
42
43
|
const shared_1 = require("./shared");
|
|
@@ -120,7 +121,8 @@ function parseArgs(args) {
|
|
|
120
121
|
return { file, type, kind, tags, force, as, private: priv };
|
|
121
122
|
}
|
|
122
123
|
async function pushFile(config, opts) {
|
|
123
|
-
|
|
124
|
+
// Never upload another artifact's identity marker (skillMarker.ts).
|
|
125
|
+
const markdown = (0, skillMarker_1.stripSkillMarker)(fs.readFileSync(opts.absPath, "utf8"));
|
|
124
126
|
const gitRemoteUrl = (0, utils_1.getGitRemoteUrl)(process.cwd()) ?? undefined;
|
|
125
127
|
return shared.apiRequest("POST", "/api/cli/push", {
|
|
126
128
|
config,
|
package/dist/mcp.js
CHANGED
|
@@ -45,6 +45,7 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
45
45
|
})();
|
|
46
46
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
47
47
|
const index_js_1 = require("@modelcontextprotocol/sdk/server/index.js");
|
|
48
|
+
const skillMarker_1 = require("./skillMarker");
|
|
48
49
|
const stdio_js_1 = require("@modelcontextprotocol/sdk/server/stdio.js");
|
|
49
50
|
const types_js_1 = require("@modelcontextprotocol/sdk/types.js");
|
|
50
51
|
const fs = __importStar(require("fs"));
|
|
@@ -492,7 +493,7 @@ async function handlePush(args, config) {
|
|
|
492
493
|
}
|
|
493
494
|
const res = await (0, shared_1.apiRequest)("POST", "/api/cli/push", {
|
|
494
495
|
config,
|
|
495
|
-
body: { filename, markdown, type, kind, tags, force },
|
|
496
|
+
body: { filename, markdown: (0, skillMarker_1.stripSkillMarker)(markdown), type, kind, tags, force },
|
|
496
497
|
});
|
|
497
498
|
const tagSummary = res.tags && res.tags.length > 0 ? `, tags=[${res.tags.join(", ")}]` : "";
|
|
498
499
|
return {
|
|
@@ -524,7 +525,9 @@ async function handlePull(args, config) {
|
|
|
524
525
|
`**${kindLabel}** · v${a.version ?? 1} · ${a.lifecycle ?? "draft"}${tagSuffix} · ` +
|
|
525
526
|
`updated ${(0, shared_1.timeAgo)(a.updatedAt ?? a.createdAt)}\n\n---\n\n`;
|
|
526
527
|
return {
|
|
527
|
-
|
|
528
|
+
// A skill's text carries its identity marker, so a copy the agent writes
|
|
529
|
+
// to disk still attributes its runs exactly (skillMarker.ts).
|
|
530
|
+
content: [{ type: "text", text: header + (a.kind === "skill" || (!a.kind && (0, skillMarker_1.looksLikeSkill)(a.markdown)) ? (0, skillMarker_1.stampSkillMarker)(a.markdown, a._id) : a.markdown) }],
|
|
528
531
|
};
|
|
529
532
|
}
|
|
530
533
|
async function handleDelete(args, config) {
|
|
@@ -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.
|
|
3
|
+
"version": "0.9.67",
|
|
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",
|