codiedev 0.5.0 → 0.5.2

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/cli.js CHANGED
@@ -62,15 +62,26 @@ Other:
62
62
  codiedev docs Print the full usage guide
63
63
  codiedev version Show version
64
64
 
65
- Filename conventions:
66
- spec-*.md → spec review-*.md review
67
- decision-*.md → decision proposal-*.md → proposal
68
- bugfix-*.md → bugfix anything else → note
65
+ The 90% workflow:
66
+ 1. Name your file 'spec-<topic>.md' and push.
67
+ 2. Ping a teammate to pull review.
68
+ 3. They edit, push back. Versions stack. Done.
69
+
70
+ Other artifact types (rare — use the matching prefix):
71
+ review-*.md → review decision-*.md → decision
72
+ proposal-*.md → proposal bugfix-*.md → bugfix
73
+ anything else → note
74
+
75
+ Skills (slash commands):
76
+ Add 'name:' + 'description:' YAML frontmatter to any pushed file
77
+ and it shows up as /<name> in Claude Code / Codex. Filename
78
+ prefix doesn't matter — frontmatter is the signal.
69
79
 
70
80
  Examples:
71
- codiedev push docs/specs/spec-cart-clear.md
81
+ codiedev push spec-cart-clear.md # the typical case
82
+ codiedev push portal-design.md # with name:/description: → skill
72
83
  codiedev pull spec-cart-clear.md
73
- codiedev ping maya "thoughts on batch vs parallel?" --with spec-cart-clear.md
84
+ codiedev ping maya "thoughts?" --with spec-cart-clear.md
74
85
  codiedev inbox --unread
75
86
  codiedev note "idempotency key is worth a follow-up"
76
87
 
@@ -96,17 +107,23 @@ codiedev connect — link your agent CLI to CodieDev
96
107
  push: `
97
108
  codiedev push — author or update an artifact
98
109
 
99
- Usage:
100
- codiedev push <file.md> [--type spec|review|decision|proposal|bugfix|note]
110
+ Default path:
111
+ codiedev push spec-<topic>.md
101
112
 
102
- The file's basename becomes its key (unique per company). Pushing the
103
- same key again creates a new version — full history is preserved.
113
+ The file's basename becomes its key (unique per company). Pushing
114
+ the same key again versions it — full history is preserved.
104
115
 
105
- Type is inferred from the filename prefix unless you override with --type.
116
+ Other types: rename with the matching prefix (review-*, decision-*,
117
+ proposal-*, bugfix-*) or pass --type. Anything else lands as 'note'.
118
+
119
+ Skills (slash commands): add 'name:' + 'description:' YAML
120
+ frontmatter to the top of the file. It shows up as /<name> in
121
+ the Skills tab. Filename prefix doesn't matter for the skill role.
106
122
 
107
123
  Examples:
108
- codiedev push spec-cart-clear.md
109
- codiedev push docs/review-auth.md --type review
124
+ codiedev push spec-cart-clear.md # the typical case
125
+ codiedev push portal-design.md # with name:/description: → skill
126
+ codiedev push docs/review-auth.md
110
127
  codiedev push notes/random.md --type note
111
128
  `.trim(),
112
129
  pull: `
@@ -244,6 +261,25 @@ Artifacts have a status that auto-advances as PRs reference them:
244
261
  Artifacts stay editable at every stage, including after merge —
245
262
  lessons-learned and follow-up notes append as new versions.
246
263
 
264
+ ## Skills
265
+
266
+ Default path:
267
+
268
+ 1. Pick a name: e.g. portal-design
269
+ 2. Top the file with frontmatter:
270
+ ---
271
+ name: portal-design
272
+ description: Use when reviewing or building portal UI.
273
+ ---
274
+ # body...
275
+ 3. codiedev push portal-design.md
276
+
277
+ It's now /portal-design in Claude Code / Codex.
278
+
279
+ Filename prefix is irrelevant for skills — frontmatter is the only
280
+ signal. The stored artifact type still follows the filename rule
281
+ (so a skill in a spec file is both a 'spec' and a callable skill).
282
+
247
283
  ## Portal
248
284
 
249
285
  Everything you do in the CLI is visible at:
@@ -45,9 +45,13 @@ const VALID_TYPES = new Set([
45
45
  "review",
46
46
  "note",
47
47
  ]);
48
+ const VALID_KINDS = new Set(["doc", "skill"]);
48
49
  function parseArgs(args) {
49
50
  let file;
50
51
  let type;
52
+ let kind;
53
+ let force = false;
54
+ const tags = [];
51
55
  for (let i = 0; i < args.length; i++) {
52
56
  const a = args[i];
53
57
  if (a === "--type" && i + 1 < args.length) {
@@ -56,22 +60,41 @@ function parseArgs(args) {
56
60
  else if (a.startsWith("--type=")) {
57
61
  type = a.slice("--type=".length);
58
62
  }
63
+ else if (a === "--kind" && i + 1 < args.length) {
64
+ kind = args[++i];
65
+ }
66
+ else if (a.startsWith("--kind=")) {
67
+ kind = a.slice("--kind=".length);
68
+ }
69
+ else if (a === "--tag" && i + 1 < args.length) {
70
+ tags.push(args[++i]);
71
+ }
72
+ else if (a.startsWith("--tag=")) {
73
+ tags.push(a.slice("--tag=".length));
74
+ }
75
+ else if (a === "--force") {
76
+ force = true;
77
+ }
59
78
  else if (!a.startsWith("--") && !file) {
60
79
  file = a;
61
80
  }
62
81
  }
63
82
  if (!file) {
64
- console.error("Usage: codiedev push <file.md> [--type spec|bugfix|decision|proposal|review|note]");
83
+ console.error("Usage: codiedev push <file.md> [--kind doc|skill] [--tag <name>] [--force]");
65
84
  process.exit(1);
66
85
  }
67
86
  if (type && !VALID_TYPES.has(type)) {
68
87
  console.error(`Invalid --type. Valid types: ${[...VALID_TYPES].join(", ")}`);
69
88
  process.exit(1);
70
89
  }
71
- return { file, type };
90
+ if (kind && !VALID_KINDS.has(kind)) {
91
+ console.error(`Invalid --kind. Valid kinds: ${[...VALID_KINDS].join(", ")}`);
92
+ process.exit(1);
93
+ }
94
+ return { file, type, kind, tags, force };
72
95
  }
73
96
  async function runPush(args) {
74
- const { file, type } = parseArgs(args);
97
+ const { file, type, kind, tags, force } = parseArgs(args);
75
98
  const config = (0, shared_1.requireConfig)();
76
99
  let absolute = file;
77
100
  if (!path.isAbsolute(absolute)) {
@@ -90,12 +113,19 @@ async function runPush(args) {
90
113
  try {
91
114
  const res = await (0, shared_1.apiRequest)("POST", "/api/cli/push", {
92
115
  config,
93
- body: { filename, markdown, type },
116
+ body: {
117
+ filename,
118
+ markdown,
119
+ type,
120
+ kind,
121
+ tags: tags.length > 0 ? tags : undefined,
122
+ force,
123
+ },
94
124
  });
95
- console.log(`✓ Pushed ${filename}`);
96
- console.log(` type: ${res.type}`);
97
- console.log(` version: v${res.version}`);
98
- console.log(` id: ${res.artifactId}`);
125
+ const tagSummary = res.tags && res.tags.length > 0 ? ` tags=[${res.tags.join(", ")}]` : "";
126
+ console.log(`✓ Pushed ${filename} (kind=${res.kind}${tagSummary}).`);
127
+ console.log(` Visible under: ${res.destination}`);
128
+ console.log(` Pull with: codiedev pull ${filename}`);
99
129
  }
100
130
  catch (err) {
101
131
  console.error(`Push failed: ${err.message}`);
package/dist/mcp.js CHANGED
@@ -60,31 +60,56 @@ const PKG_VERSION = "0.5.0";
60
60
  const TOOLS = [
61
61
  {
62
62
  name: "codiedev_push",
63
- description: "Push a spec, review, decision, proposal, bugfix, or note to the " +
64
- "team's CodieDev artifact layer so teammates can see and discuss it. " +
65
- "Use when the user asks to share, push, save, or publish something " +
66
- "(e.g., 'push this spec', 'share the review with the team', 'save as " +
67
- "a decision'). Prefer passing the filename of a recently-edited local " +
68
- "file provide its current contents as `markdown`. Filename should " +
69
- "end in .md and start with the artifact type (spec-, review-, " +
70
- "decision-, proposal-, bugfix-, or note-).",
63
+ description: "Push any markdown artifact (doc or skill) to the team's CodieDev " +
64
+ "artifact layer so teammates can see, discuss, and run it. Works for " +
65
+ "specs, decisions, proposals, bugfixes, reviews, notes, AND " +
66
+ "Claude Code / Codex skills (files with SKILL.md frontmatter " +
67
+ "`name:` and `description:` keys). Just pass the filename + markdown " +
68
+ "— `kind` is auto-detected from the content (skill if frontmatter, " +
69
+ "otherwise doc). Use when the user asks to share, push, save, or " +
70
+ "publish something (e.g., 'push this spec', 'save as a skill', " +
71
+ "'share the review'). The response says where the artifact will " +
72
+ "appear so you can confirm to the user.",
71
73
  inputSchema: {
72
74
  type: "object",
73
75
  properties: {
74
76
  filename: {
75
77
  type: "string",
76
- description: "Basename of the artifact file, e.g. 'spec-214.md'. Becomes the " +
77
- "artifact's key for pulling and pinging.",
78
+ description: "Basename of the artifact file, e.g. 'spec-214.md' or " +
79
+ "'writing-emails.md'. Becomes the artifact's key for pulling " +
80
+ "and pinging.",
78
81
  },
79
82
  markdown: {
80
83
  type: "string",
81
84
  description: "Full markdown content of the artifact.",
82
85
  },
86
+ kind: {
87
+ type: "string",
88
+ enum: ["doc", "skill"],
89
+ description: "Top-level kind. Auto-detected from frontmatter — leave unset " +
90
+ "in the common case. Pass `skill` for files with SKILL.md " +
91
+ "frontmatter, `doc` for everything else. If you pass a value " +
92
+ "that disagrees with the detected kind the push fails unless " +
93
+ "`force: true` is also set.",
94
+ },
95
+ tags: {
96
+ type: "array",
97
+ items: { type: "string" },
98
+ description: "Optional free-form tags (e.g., ['spec', 'auth']). The legacy " +
99
+ "type prefix from the filename is added automatically — you " +
100
+ "don't need to repeat it.",
101
+ },
102
+ force: {
103
+ type: "boolean",
104
+ description: "Override the kind-mismatch guard. Only pass when the user " +
105
+ "explicitly wants to ignore the detected kind.",
106
+ },
83
107
  type: {
84
108
  type: "string",
85
109
  enum: ["spec", "bugfix", "decision", "proposal", "review", "note"],
86
- description: "Override the inferred type. Usually leave unset type is " +
87
- "inferred from filename prefix.",
110
+ description: "Legacy override for the doc-shape tag. Optionalinferred " +
111
+ "from the filename prefix when omitted. Prefer `tags` for new " +
112
+ "code.",
88
113
  },
89
114
  },
90
115
  required: ["filename", "markdown"],
@@ -522,20 +547,28 @@ async function handlePush(args, config) {
522
547
  const filename = asString(args.filename);
523
548
  const markdown = asString(args.markdown);
524
549
  const type = asStringOrUndefined(args.type);
550
+ const kind = asStringOrUndefined(args.kind);
551
+ const tags = asStringArrayOrUndefined(args.tags);
552
+ const force = asBoolOrUndefined(args.force);
525
553
  if (!filename)
526
554
  throw new Error("filename required");
527
555
  if (!markdown)
528
556
  throw new Error("markdown required");
557
+ if (kind && kind !== "doc" && kind !== "skill") {
558
+ throw new Error("kind must be 'doc' or 'skill' if provided");
559
+ }
529
560
  const res = await (0, shared_1.apiRequest)("POST", "/api/cli/push", {
530
561
  config,
531
- body: { filename, markdown, type },
562
+ body: { filename, markdown, type, kind, tags, force },
532
563
  });
564
+ const tagSummary = res.tags && res.tags.length > 0 ? `, tags=[${res.tags.join(", ")}]` : "";
533
565
  return {
534
566
  content: [
535
567
  {
536
568
  type: "text",
537
- text: `✓ Pushed ${filename} (type=${res.type}, version=v${res.version}, id=${res.artifactId}).\n` +
538
- `Teammates can now pull it with \`codiedev pull ${filename}\`.`,
569
+ text: `✓ Pushed ${filename} (kind=${res.kind}${tagSummary}, version=v${res.version}, id=${res.artifactId}).\n` +
570
+ ` Visible under: ${res.destination}\n` +
571
+ ` Pull with: \`codiedev pull ${filename}\``,
539
572
  },
540
573
  ],
541
574
  };
@@ -998,6 +1031,14 @@ function asStringOrUndefined(v) {
998
1031
  function asIntOrUndefined(v) {
999
1032
  return typeof v === "number" && Number.isInteger(v) ? v : undefined;
1000
1033
  }
1034
+ function asBoolOrUndefined(v) {
1035
+ return typeof v === "boolean" ? v : undefined;
1036
+ }
1037
+ function asStringArrayOrUndefined(v) {
1038
+ if (!Array.isArray(v))
1039
+ return undefined;
1040
+ return v.filter((x) => typeof x === "string");
1041
+ }
1001
1042
  // ─────────────────────────────────────────────────────────────────────────────
1002
1043
  // Main
1003
1044
  // ─────────────────────────────────────────────────────────────────────────────
package/dist/utils.js CHANGED
@@ -220,13 +220,22 @@ thought, use the \`codiedev\` CLI via Bash:**
220
220
  | "show my library" / "what artifacts exist?" | MCP tool \`codiedev_get_library\` |
221
221
  | "react 🛠 to that post" / "mark as used" | MCP tool \`codiedev_react\` |
222
222
 
223
- **Filename conventions (set artifact type automatically):**
224
- - \`spec-*.md\` spec
225
- - \`review-*.md\` → review
226
- - \`decision-*.md\` decision
227
- - \`proposal-*.md\`proposal
228
- - \`bugfix-*.md\` bugfix
229
- - anything else → note
223
+ **Just push the file we'll figure out where it goes.** Every artifact
224
+ is classified into one of two kinds at upload time:
225
+
226
+ - **skill** — the file has SKILL.md frontmatter (\`name:\` + \`description:\`
227
+ inside a \`---\` block). Lands under \`ArtifactsSkills tab\` and is
228
+ invokable as a slash command (\`/<name>\`).
229
+ - **doc** — everything else. Lands under \`Artifacts My artifacts\`.
230
+
231
+ Detection is content-based, not filename-based. The filename prefix
232
+ (\`spec-\` / \`decision-\` / \`proposal-\` / \`bugfix-\` / \`review-\` /
233
+ \`note-\`) is preserved as a *tag* you can filter by, but it never gates
234
+ visibility. A SKILL-frontmatter file named \`note-foo.md\` still becomes
235
+ a skill.
236
+
237
+ The \`codiedev push\` response always says where the artifact landed —
238
+ read it back to the user so they can confirm.
230
239
 
231
240
  **Resolving "the spec we just worked on":**
232
241
  - If a file was recently edited in this session matching the conventions
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codiedev",
3
- "version": "0.5.0",
3
+ "version": "0.5.2",
4
4
  "description": "Connect Claude Code or Codex to CodieDev for org-wide session capture and artifact collaboration",
5
5
  "bin": {
6
6
  "codiedev": "./dist/cli.js",