@ksoftm/create-arc 1.0.5 → 1.1.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 (3) hide show
  1. package/README.md +11 -5
  2. package/bin/cli.js +123 -9
  3. package/package.json +3 -2
package/README.md CHANGED
@@ -3,12 +3,16 @@
3
3
  Scaffold and drive the **ARC framework** (Align → Refine → Construct) — plan-driven development for AI agents, in pure Markdown. Zero dependencies, any language, any agent.
4
4
 
5
5
  ```bash
6
- npx @ksoftm/create-arc init # scaffold ARC into the current project
7
- npx @ksoftm/create-arc new "Add per-key rate limit" # open and register a new unit of work
8
- npx @ksoftm/create-arc status # every arc at a glance
9
- npx @ksoftm/create-arc doctor # verify the registry is consistent
6
+ npm i -g @ksoftm/create-arc # install once, then use the short `arc` command
7
+ arc init # scaffold ARC into the current project
8
+ arc new "Add per-key rate limit" # open and register a new unit of work
9
+ arc status # every arc at a glance
10
+ arc doctor # verify the registry is consistent
11
+ arc agent-init # write /arc-* slash commands for your AI agent
10
12
  ```
11
13
 
14
+ No install? Use `npx @ksoftm/create-arc <command>`. Prefer pinning per-project? `npm i -D @ksoftm/create-arc` then `npx arc <command>`.
15
+
12
16
  ## What ARC is
13
17
 
14
18
  Every unit of development is an **arc**: one Markdown file under `.arc/` that holds its whole story — the user's raw instructions (verbatim, append-only), the current plan, a refinement log, a task list, a worklog, and a status. The agent plans before it builds, refines the plan when the ask changes, and logs every edit — so any later session resumes from the arc, not the chat history. Full concept and protocol: **https://github.com/KsoftmHub/arc-framework-v1**.
@@ -32,7 +36,9 @@ Requires Node ≥ 18.
32
36
  | `status [dir] [--json]` | Print a table (or JSON) of every arc: ID, status, plan version, task progress, and which to resume. |
33
37
  | `doctor [dir]` | Consistency checks — index ↔ file bijection, ID/`next_id` sanity, valid statuses. Exits non-zero on problems (CI-friendly). |
34
38
 
35
- Common options: `--owner NAME` (defaults to `git config user.name`); `--tags a,b` on `new`; `--json` on `status`; `--version`, `--help`.
39
+ Common options: `--owner NAME` (defaults to `git config user.name`); `--tags a,b` on `new`; `--json` on `status`; `--agents a,b` and `--force` on `agent-init`; `--version`, `--help`.
40
+
41
+ Installs two equivalent binaries: **`arc`** and **`create-arc`**.
36
42
 
37
43
  ## What `init` produces
38
44
 
package/bin/cli.js CHANGED
@@ -166,12 +166,41 @@ function cmdNew(title, flags) {
166
166
  index = index.replace(/^next_id:\s*ARC-\d+\s*$/m, `next_id: ARC-${String(num + 1).padStart(4, "0")}`);
167
167
  const row = `| ${id} | ${title} | draft | 1 | ${date} | — | [${filename}](${filename}) |`;
168
168
  const lines = index.split("\n");
169
+ const archivedIdx = lines.findIndex((l) => /^##\s+Archived/i.test(l));
170
+ const scanEnd = archivedIdx === -1 ? lines.length : archivedIdx;
171
+
172
+ // Preferred: insert right after the last existing "| ARC-…" row in the Active section.
169
173
  let insertAt = -1;
170
- for (let i = 0; i < lines.length; i++) {
171
- if (lines[i].startsWith("## Archived")) break;
174
+ for (let i = 0; i < scanEnd; i++) {
172
175
  if (/^\|\s*ARC-/.test(lines[i])) insertAt = i;
173
176
  }
174
- if (insertAt === -1) return fail("could not locate the Active table in INDEX.md");
177
+
178
+ if (insertAt === -1) {
179
+ // No arc rows yet (or a differently-shaped INDEX). Fall back, in order, to:
180
+ // the "## Active" heading's table separator, the heading itself, or next_id.
181
+ const activeIdx = lines.findIndex((l) => /^##\s+Active/i.test(l));
182
+ if (activeIdx !== -1) {
183
+ // find a markdown table separator (|---|) after the Active heading
184
+ let sep = -1;
185
+ for (let i = activeIdx + 1; i < scanEnd; i++) {
186
+ if (/^\|?\s*:?-{2,}/.test(lines[i]) || /^\|(\s*-+\s*\|)+/.test(lines[i])) { sep = i; break; }
187
+ if (/^\|\s*ID\s*\|/i.test(lines[i])) { sep = i + 1; } // header row → insert after its separator
188
+ }
189
+ insertAt = sep !== -1 ? sep : activeIdx; // after separator, else right after heading
190
+ } else {
191
+ // No Active section at all — synthesize one after next_id (or at top).
192
+ const nextIdIdx = lines.findIndex((l) => /^next_id:/.test(l));
193
+ const anchor = nextIdIdx !== -1 ? nextIdIdx : 0;
194
+ lines.splice(anchor + 1, 0,
195
+ "",
196
+ "## Active",
197
+ "",
198
+ "| ID | Title | Status | Plan v | Updated | Depends | File |",
199
+ "|---|---|---|---|---|---|---|");
200
+ insertAt = anchor + 5; // the separator line we just added
201
+ }
202
+ }
203
+
175
204
  lines.splice(insertAt + 1, 0, row);
176
205
  writeFileSync(indexPath, lines.join("\n"));
177
206
 
@@ -297,15 +326,99 @@ function cmdDoctor(target) {
297
326
 
298
327
  function fail(msg) { console.error(`error: ${msg}`); return 1; }
299
328
 
329
+ // Slash-commands generated for each supported agent. Each is a thin prompt that
330
+ // routes the agent through ARC.md; $ARGUMENTS / $1 carry the user's text.
331
+ const ARC_COMMANDS = {
332
+ "arc-new": {
333
+ desc: "ARC: capture a development instruction as a new arc (Align)",
334
+ body: `Read ./ARC.md, then run ARC Intake for this instruction:
335
+
336
+ "$ARGUMENTS"
337
+
338
+ Steps: read .arc/INDEX.md; if an open arc already covers this, append the instruction verbatim and refine its plan; otherwise create a new arc (use \`npx @ksoftm/create-arc new "<short title>"\`, or create the file from .arc/_TEMPLATE.md and register it in INDEX.md). Record the raw instruction verbatim, draft the Plan with checkable acceptance criteria, and list the Tasks. Do not start coding until the plan is acknowledged.`,
339
+ },
340
+ "arc-refine": {
341
+ desc: "ARC: fold a new instruction into an existing arc (Refine)",
342
+ body: `Read ./ARC.md, then refine the relevant arc with this instruction:
343
+
344
+ "$ARGUMENTS"
345
+
346
+ Append it verbatim as the next Raw Instruction, add a Refinement Log entry (new plan_version, what changed, task impact), rewrite the Plan to reflect only the current intent, and adjust the Tasks. Move dropped scope to "Out of scope". Never edit the append-only sections retroactively.`,
347
+ },
348
+ "arc-build": {
349
+ desc: "ARC: do the work for the active arc (Read Before / Update After Editing)",
350
+ body: `Read ./ARC.md. Before editing: read .arc/INDEX.md, fully read the arc(s) covering the files you'll touch, and read the real source files. Work the task list in order, marking one task in progress. After editing: advance task states, append a Worklog entry (tasks, files read, files changed, summary, decisions, follow-ups), update the arc frontmatter and its INDEX row, and reference the arc id in the commit. An edit without a worklog entry is unfinished.
351
+
352
+ Focus: $ARGUMENTS`,
353
+ },
354
+ "arc-status": {
355
+ desc: "ARC: summarize all arcs and what to resume",
356
+ body: `Run \`npx @ksoftm/create-arc status\` (or read .arc/INDEX.md and each arc). Report every arc's id, status, plan version, task progress, and which in-progress/refining arcs to resume — reading each one's Status Notes and last Worklog entry.`,
357
+ },
358
+ "arc-resume": {
359
+ desc: "ARC: pick up the in-progress arc cold",
360
+ body: `Read ./ARC.md. Read .arc/INDEX.md, find arcs in in-progress or refining, open them, read Status Notes and the last Worklog entry, then continue from the open tasks — after running Read Before Editing. If code and the arc disagree, the code is truth: note the drift in the Worklog and correct the arc.`,
361
+ },
362
+ };
363
+
364
+ // Where each agent looks for project-level slash commands, and how to render one.
365
+ const AGENT_TARGETS = {
366
+ claude: { dir: ".claude/commands", ext: ".md", fmt: md },
367
+ opencode: { dir: ".opencode/command", ext: ".md", fmt: md },
368
+ cursor: { dir: ".cursor/commands", ext: ".md", fmt: md },
369
+ codex: { dir: ".codex/prompts", ext: ".md", fmt: plain }, // Codex custom prompts
370
+ gemini: { dir: ".gemini/commands", ext: ".toml", fmt: toml },
371
+ };
372
+ const ALL_AGENTS = Object.keys(AGENT_TARGETS);
373
+
374
+ function md(name, c) { return `---\ndescription: ${c.desc}\n---\n\n${c.body}\n`; }
375
+ function plain(name, c) { return `${c.body}\n`; }
376
+ function toml(name, c) {
377
+ const b = c.body.replace(/\\/g, "\\\\").replace(/"""/g, '\\"\\"\\"');
378
+ return `description = ${JSON.stringify(c.desc)}\nprompt = """\n${b}\n"""\n`;
379
+ }
380
+
381
+ function cmdAgentInit(flags) {
382
+ const dir = resolve(flags.dir ?? ".");
383
+ // --agents=claude,opencode (default: all)
384
+ const agents = (flags.agents ? String(flags.agents).split(",") : ALL_AGENTS)
385
+ .map((a) => a.trim().toLowerCase()).filter(Boolean);
386
+ const unknown = agents.filter((a) => !AGENT_TARGETS[a]);
387
+ if (unknown.length) return fail(`unknown agent(s): ${unknown.join(", ")} (known: ${ALL_AGENTS.join(", ")})`);
388
+
389
+ let created = 0, skipped = 0;
390
+ for (const agent of agents) {
391
+ const { dir: rel, ext, fmt } = AGENT_TARGETS[agent];
392
+ const outDir = join(dir, rel);
393
+ mkdirSync(outDir, { recursive: true });
394
+ for (const [name, c] of Object.entries(ARC_COMMANDS)) {
395
+ const dest = join(outDir, name + ext);
396
+ if (existsSync(dest) && !flags.force) { skipped++; continue; }
397
+ writeFileSync(dest, fmt(name, c));
398
+ created++;
399
+ }
400
+ console.log(` ${agent.padEnd(9)} ${rel}/ (${Object.keys(ARC_COMMANDS).length} commands)`);
401
+ }
402
+ console.log(`\nAgent commands written (created ${created}, skipped ${skipped}${flags.force ? "" : "; use --force to overwrite"}).`);
403
+ console.log(`Type /arc-new, /arc-build, /arc-status, /arc-refine, /arc-resume in your agent.`);
404
+ return 0;
405
+ }
406
+
300
407
  function help() {
301
408
  console.log(`create-arc v${PKG.version} — ARC plan-driven development (Align → Refine → Construct)
409
+ (alias: \`arc\`)
302
410
 
303
411
  Usage:
304
- create-arc init [dir] [--owner=NAME] scaffold ARC.md + .arc/ (idempotent)
305
- create-arc new "Title" [--dir=.] [--tags=a,b] [--owner=NAME]
306
- create + register the next arc
307
- create-arc status [dir] [--json] status table across all arcs
308
- create-arc doctor [dir] consistency checks (exit 1 on problems)
412
+ arc init [dir] [--owner=NAME] scaffold ARC.md + .arc/ (idempotent)
413
+ arc new "Title" [--dir=.] [--tags=a,b] create + register the next arc
414
+ arc status [dir] [--json] status table across all arcs
415
+ arc doctor [dir] consistency checks (exit 1 on problems)
416
+ arc agent-init [--agents=a,b] [--force] write /slash commands for AI agents
417
+ (agents: ${ALL_AGENTS.join(", ")}; default: all)
418
+
419
+ Run with npx (no install): npx @ksoftm/create-arc <command>
420
+ Install globally: npm i -g @ksoftm/create-arc then: arc <command>
421
+ Project dev dependency: npm i -D @ksoftm/create-arc then: npx arc <command>
309
422
 
310
423
  Protocol reference: ARC.md in your project root after init.`);
311
424
  return 0;
@@ -321,6 +434,7 @@ else if (cmd === "init") code = cmdInit(pos[1], flags);
321
434
  else if (cmd === "new") code = cmdNew(pos.slice(1).join(" "), flags);
322
435
  else if (cmd === "status") code = cmdStatus(pos[1], flags);
323
436
  else if (cmd === "doctor") code = cmdDoctor(pos[1]);
324
- else code = fail(`unknown command '${cmd}' try: create-arc help`);
437
+ else if (cmd === "agent-init" || cmd === "agents") code = cmdAgentInit(flags);
438
+ else code = fail(`unknown command '${cmd}' — try: arc help`);
325
439
 
326
440
  process.exit(code);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ksoftm/create-arc",
3
- "version": "1.0.5",
3
+ "version": "1.1.0",
4
4
  "private": false,
5
5
  "description": "Scaffold and manage ARC — plan-driven development for AI agents (Align → Refine → Construct). Pure-Markdown plans, tasks, worklogs and statuses in .arc/, for any language and any agent.",
6
6
  "keywords": [
@@ -19,7 +19,8 @@
19
19
  "author": "Ksoftm (Kajalan)",
20
20
  "type": "module",
21
21
  "bin": {
22
- "create-arc": "bin/cli.js"
22
+ "create-arc": "bin/cli.js",
23
+ "arc": "bin/cli.js"
23
24
  },
24
25
  "files": [
25
26
  "bin",