@kya-os/cli 1.7.0 → 2.0.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 (161) hide show
  1. package/dist/commands/build.js +2 -2
  2. package/dist/commands/build.js.map +1 -1
  3. package/dist/commands/check.js +3 -3
  4. package/dist/commands/check.js.map +1 -1
  5. package/dist/commands/checkpoint-init.d.ts +32 -0
  6. package/dist/commands/checkpoint-init.d.ts.map +1 -0
  7. package/dist/commands/checkpoint-init.js +521 -0
  8. package/dist/commands/checkpoint-init.js.map +1 -0
  9. package/dist/commands/claim.js +2 -2
  10. package/dist/commands/claim.js.map +1 -1
  11. package/dist/commands/dco.d.ts +38 -1
  12. package/dist/commands/dco.d.ts.map +1 -1
  13. package/dist/commands/dco.js +180 -7
  14. package/dist/commands/dco.js.map +1 -1
  15. package/dist/commands/dev.js +1 -1
  16. package/dist/commands/dev.js.map +1 -1
  17. package/dist/commands/doctor.d.ts.map +1 -1
  18. package/dist/commands/doctor.js +18 -24
  19. package/dist/commands/doctor.js.map +1 -1
  20. package/dist/commands/env.js +6 -6
  21. package/dist/commands/env.js.map +1 -1
  22. package/dist/commands/identity.js +3 -3
  23. package/dist/commands/identity.js.map +1 -1
  24. package/dist/commands/init.d.ts.map +1 -1
  25. package/dist/commands/init.js +103 -65
  26. package/dist/commands/init.js.map +1 -1
  27. package/dist/commands/register.d.ts +1 -1
  28. package/dist/commands/register.d.ts.map +1 -1
  29. package/dist/commands/register.js +35 -7
  30. package/dist/commands/register.js.map +1 -1
  31. package/dist/commands/rotate.js +4 -4
  32. package/dist/commands/rotate.js.map +1 -1
  33. package/dist/commands/start.js +3 -3
  34. package/dist/commands/start.js.map +1 -1
  35. package/dist/commands/status.js +1 -1
  36. package/dist/commands/status.js.map +1 -1
  37. package/dist/commands/verify.js +6 -6
  38. package/dist/commands/verify.js.map +1 -1
  39. package/dist/dco.d.ts +4 -0
  40. package/dist/dco.d.ts.map +1 -0
  41. package/dist/dco.js +21 -0
  42. package/dist/dco.js.map +1 -0
  43. package/dist/index.js +18 -15
  44. package/dist/utils/checkpoint-api.d.ts +86 -0
  45. package/dist/utils/checkpoint-api.d.ts.map +1 -0
  46. package/dist/utils/checkpoint-api.js +196 -0
  47. package/dist/utils/checkpoint-api.js.map +1 -0
  48. package/dist/utils/checkpoint-env.d.ts +23 -0
  49. package/dist/utils/checkpoint-env.d.ts.map +1 -0
  50. package/dist/utils/checkpoint-env.js +59 -0
  51. package/dist/utils/checkpoint-env.js.map +1 -0
  52. package/dist/utils/checkpoint-scaffold.d.ts +61 -0
  53. package/dist/utils/checkpoint-scaffold.d.ts.map +1 -0
  54. package/dist/utils/checkpoint-scaffold.js +268 -0
  55. package/dist/utils/checkpoint-scaffold.js.map +1 -0
  56. package/dist/utils/cli-kit/browser.d.ts +24 -0
  57. package/dist/utils/cli-kit/browser.d.ts.map +1 -0
  58. package/dist/utils/cli-kit/browser.js +58 -0
  59. package/dist/utils/cli-kit/browser.js.map +1 -0
  60. package/dist/utils/cli-kit/claim-polling.d.ts +18 -0
  61. package/dist/utils/cli-kit/claim-polling.d.ts.map +1 -0
  62. package/dist/utils/{claim-polling.js → cli-kit/claim-polling.js} +19 -26
  63. package/dist/utils/cli-kit/claim-polling.js.map +1 -0
  64. package/dist/utils/cli-kit/diagnostics.d.ts +9 -0
  65. package/dist/utils/cli-kit/diagnostics.d.ts.map +1 -0
  66. package/dist/utils/cli-kit/diagnostics.js +11 -0
  67. package/dist/utils/cli-kit/diagnostics.js.map +1 -0
  68. package/dist/utils/cli-kit/fs-safe.d.ts +14 -0
  69. package/dist/utils/cli-kit/fs-safe.d.ts.map +1 -0
  70. package/dist/utils/cli-kit/fs-safe.js +20 -0
  71. package/dist/utils/cli-kit/fs-safe.js.map +1 -0
  72. package/dist/utils/cli-kit/index.d.ts +15 -0
  73. package/dist/utils/cli-kit/index.d.ts.map +1 -0
  74. package/dist/utils/cli-kit/index.js +10 -0
  75. package/dist/utils/cli-kit/index.js.map +1 -0
  76. package/dist/utils/cli-kit/json-file.d.ts +21 -0
  77. package/dist/utils/cli-kit/json-file.d.ts.map +1 -0
  78. package/dist/utils/cli-kit/json-file.js +51 -0
  79. package/dist/utils/cli-kit/json-file.js.map +1 -0
  80. package/dist/utils/cli-kit/marker-block.d.ts +26 -0
  81. package/dist/utils/cli-kit/marker-block.d.ts.map +1 -0
  82. package/dist/utils/cli-kit/marker-block.js +61 -0
  83. package/dist/utils/cli-kit/marker-block.js.map +1 -0
  84. package/dist/utils/cli-kit/paths.d.ts +15 -0
  85. package/dist/utils/cli-kit/paths.d.ts.map +1 -0
  86. package/dist/utils/cli-kit/paths.js +21 -0
  87. package/dist/utils/cli-kit/paths.js.map +1 -0
  88. package/dist/utils/cli-kit/secure-storage.d.ts +14 -0
  89. package/dist/utils/cli-kit/secure-storage.d.ts.map +1 -0
  90. package/dist/utils/cli-kit/secure-storage.js +20 -0
  91. package/dist/utils/cli-kit/secure-storage.js.map +1 -0
  92. package/dist/utils/cli-kit/step-report.d.ts +16 -0
  93. package/dist/utils/cli-kit/step-report.d.ts.map +1 -0
  94. package/dist/utils/cli-kit/step-report.js +36 -0
  95. package/dist/utils/cli-kit/step-report.js.map +1 -0
  96. package/dist/utils/dco/agent-metadata.d.ts +1 -1
  97. package/dist/utils/dco/agent-metadata.js +1 -1
  98. package/dist/utils/dco/agent-metadata.js.map +1 -1
  99. package/dist/utils/dco/claude-config.d.ts +18 -8
  100. package/dist/utils/dco/claude-config.d.ts.map +1 -1
  101. package/dist/utils/dco/claude-config.js +33 -79
  102. package/dist/utils/dco/claude-config.js.map +1 -1
  103. package/dist/utils/dco/dispatch.d.ts +59 -0
  104. package/dist/utils/dco/dispatch.d.ts.map +1 -0
  105. package/dist/utils/dco/dispatch.js +332 -0
  106. package/dist/utils/dco/dispatch.js.map +1 -0
  107. package/dist/utils/dco/git-config.d.ts.map +1 -1
  108. package/dist/utils/dco/git-config.js +5 -3
  109. package/dist/utils/dco/git-config.js.map +1 -1
  110. package/dist/utils/dco/github.d.ts +8 -0
  111. package/dist/utils/dco/github.d.ts.map +1 -1
  112. package/dist/utils/dco/github.js +11 -0
  113. package/dist/utils/dco/github.js.map +1 -1
  114. package/dist/utils/dco/paths.d.ts +1 -8
  115. package/dist/utils/dco/paths.d.ts.map +1 -1
  116. package/dist/utils/dco/paths.js +3 -12
  117. package/dist/utils/dco/paths.js.map +1 -1
  118. package/dist/utils/dco/render.d.ts +1 -1
  119. package/dist/utils/dco/render.d.ts.map +1 -1
  120. package/dist/utils/dco/render.js +4 -21
  121. package/dist/utils/dco/render.js.map +1 -1
  122. package/dist/utils/dco/resolve-agent.d.ts +54 -0
  123. package/dist/utils/dco/resolve-agent.d.ts.map +1 -0
  124. package/dist/utils/dco/resolve-agent.js +164 -0
  125. package/dist/utils/dco/resolve-agent.js.map +1 -0
  126. package/dist/utils/dco/setup.d.ts +10 -7
  127. package/dist/utils/dco/setup.d.ts.map +1 -1
  128. package/dist/utils/dco/setup.js +304 -202
  129. package/dist/utils/dco/setup.js.map +1 -1
  130. package/dist/utils/dco/ssh-key.d.ts +13 -0
  131. package/dist/utils/dco/ssh-key.d.ts.map +1 -1
  132. package/dist/utils/dco/ssh-key.js +21 -0
  133. package/dist/utils/dco/ssh-key.js.map +1 -1
  134. package/dist/utils/dco/status.d.ts +1 -1
  135. package/dist/utils/dco/status.d.ts.map +1 -1
  136. package/dist/utils/dco/status.js +3 -3
  137. package/dist/utils/dco/status.js.map +1 -1
  138. package/dist/utils/dco/verify.d.ts +114 -0
  139. package/dist/utils/dco/verify.d.ts.map +1 -0
  140. package/dist/utils/dco/verify.js +383 -0
  141. package/dist/utils/dco/verify.js.map +1 -0
  142. package/dist/utils/gitignore.d.ts +17 -0
  143. package/dist/utils/gitignore.d.ts.map +1 -0
  144. package/dist/utils/gitignore.js +40 -0
  145. package/dist/utils/gitignore.js.map +1 -0
  146. package/dist/utils/identity-heal.d.ts +16 -0
  147. package/dist/utils/identity-heal.d.ts.map +1 -0
  148. package/dist/utils/identity-heal.js +37 -0
  149. package/dist/utils/identity-heal.js.map +1 -0
  150. package/dist/utils/poll.d.ts +50 -0
  151. package/dist/utils/poll.d.ts.map +1 -0
  152. package/dist/utils/poll.js +73 -0
  153. package/dist/utils/poll.js.map +1 -0
  154. package/package.json +4 -3
  155. package/dist/utils/claim-polling.d.ts +0 -21
  156. package/dist/utils/claim-polling.d.ts.map +0 -1
  157. package/dist/utils/claim-polling.js.map +0 -1
  158. package/dist/utils/dco/fs-safe.d.ts +0 -14
  159. package/dist/utils/dco/fs-safe.d.ts.map +0 -1
  160. package/dist/utils/dco/fs-safe.js +0 -20
  161. package/dist/utils/dco/fs-safe.js.map +0 -1
@@ -0,0 +1,51 @@
1
+ import { existsSync, mkdirSync, readFileSync } from "fs";
2
+ import { dirname } from "path";
3
+ import { writeFileAtomicSafe } from "./fs-safe.js";
4
+ /**
5
+ * Merge `patch` into a JSON file at `path`, preserving every other key.
6
+ *
7
+ * A file we cannot parse (or that doesn't hold a plain object) is left
8
+ * untouched and reported "skipped-invalid": clobbering a caller's existing
9
+ * config is worse than leaving the patch unapplied. Already-applied patches
10
+ * report "unchanged" without writing.
11
+ *
12
+ * `path` is used as given, with no containment check against a base
13
+ * directory (unlike `upsertMarkerBlock`, this function takes a fully
14
+ * resolved path, not a `cwd` + relative segment) — resolving it safely is
15
+ * the caller's responsibility.
16
+ */
17
+ export function mergeJsonFile(path, patch, options = {}) {
18
+ if (existsSync(path)) {
19
+ let settings;
20
+ try {
21
+ const parsed = JSON.parse(readFileSync(path, "utf-8"));
22
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
23
+ return { result: "skipped-invalid", path };
24
+ }
25
+ settings = parsed;
26
+ }
27
+ catch {
28
+ return { result: "skipped-invalid", path };
29
+ }
30
+ const alreadyApplied = Object.entries(patch).every(([key, value]) => settings[key] === value);
31
+ if (alreadyApplied) {
32
+ return { result: "unchanged", path };
33
+ }
34
+ if (options.dryRun) {
35
+ return { result: "would-change", path };
36
+ }
37
+ Object.assign(settings, patch);
38
+ writeFileAtomicSafe(path, JSON.stringify(settings, null, 2) + "\n");
39
+ return { result: "updated", path };
40
+ }
41
+ if (options.dryRun) {
42
+ return { result: "would-change", path };
43
+ }
44
+ const dir = dirname(path);
45
+ if (!existsSync(dir)) {
46
+ mkdirSync(dir, { recursive: true });
47
+ }
48
+ writeFileAtomicSafe(path, JSON.stringify(patch, null, 2) + "\n");
49
+ return { result: "created", path };
50
+ }
51
+ //# sourceMappingURL=json-file.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"json-file.js","sourceRoot":"","sources":["../../../src/utils/cli-kit/json-file.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,IAAI,CAAC;AACzD,OAAO,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAC/B,OAAO,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AASnD;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,aAAa,CAC3B,IAAY,EACZ,KAA8B,EAC9B,UAAgC,EAAE;IAElC,IAAI,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;QACrB,IAAI,QAAiC,CAAC;QACtC,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC;YACvD,IAAI,CAAC,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;gBACnE,OAAO,EAAE,MAAM,EAAE,iBAAiB,EAAE,IAAI,EAAE,CAAC;YAC7C,CAAC;YACD,QAAQ,GAAG,MAAiC,CAAC;QAC/C,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,EAAE,MAAM,EAAE,iBAAiB,EAAE,IAAI,EAAE,CAAC;QAC7C,CAAC;QAED,MAAM,cAAc,GAAG,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,KAAK,CAChD,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,KAAK,CAC1C,CAAC;QACF,IAAI,cAAc,EAAE,CAAC;YACnB,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC;QACvC,CAAC;QACD,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;YACnB,OAAO,EAAE,MAAM,EAAE,cAAc,EAAE,IAAI,EAAE,CAAC;QAC1C,CAAC;QACD,MAAM,CAAC,MAAM,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;QAC/B,mBAAmB,CAAC,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;QACpE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;IACrC,CAAC;IAED,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;QACnB,OAAO,EAAE,MAAM,EAAE,cAAc,EAAE,IAAI,EAAE,CAAC;IAC1C,CAAC;IACD,MAAM,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1B,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QACrB,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACtC,CAAC;IACD,mBAAmB,CAAC,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;IACjE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;AACrC,CAAC"}
@@ -0,0 +1,26 @@
1
+ export type UpsertResult = "created" | "updated" | "unchanged" | "would-change";
2
+ /**
3
+ * Insert or replace a delimited block in a file, generalized over the
4
+ * target file, the start/end markers, and the block content — so a
5
+ * consumer can manage its own marker pair (e.g. `<!-- mcpi:dco:start -->`)
6
+ * in its own target file (e.g. `CLAUDE.md`) without duplicating this
7
+ * splice/append logic.
8
+ *
9
+ * Creates the file with just the block when missing, replaces an existing
10
+ * managed block in place, or appends with a blank-line separator when no
11
+ * managed block exists yet. A no-op write (content already matches) is
12
+ * reported as "unchanged" rather than touching the file.
13
+ *
14
+ * `relativePath` must never carry attacker- or config-file-influenced
15
+ * segments without validation upstream: it's resolved against `cwd` and
16
+ * rejected if it would escape it (e.g. `../../.ssh/authorized_keys`),
17
+ * but a crafted value that stays inside `cwd` (e.g. overwriting an
18
+ * unrelated tracked file) is still the caller's responsibility to guard.
19
+ */
20
+ export declare function upsertMarkerBlock(cwd: string, relativePath: string, startMarker: string, endMarker: string, block: string, options?: {
21
+ dryRun?: boolean;
22
+ }): {
23
+ result: UpsertResult;
24
+ path: string;
25
+ };
26
+ //# sourceMappingURL=marker-block.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"marker-block.d.ts","sourceRoot":"","sources":["../../../src/utils/cli-kit/marker-block.ts"],"names":[],"mappings":"AAIA,MAAM,MAAM,YAAY,GAAG,SAAS,GAAG,SAAS,GAAG,WAAW,GAAG,cAAc,CAAC;AAEhF;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,iBAAiB,CAC/B,GAAG,EAAE,MAAM,EACX,YAAY,EAAE,MAAM,EACpB,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,MAAM,EACb,OAAO,GAAE;IAAE,MAAM,CAAC,EAAE,OAAO,CAAA;CAAO,GACjC;IAAE,MAAM,EAAE,YAAY,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CA2CxC"}
@@ -0,0 +1,61 @@
1
+ import { existsSync, mkdirSync, readFileSync } from "fs";
2
+ import { dirname, resolve, sep } from "path";
3
+ import { writeFileAtomicSafe } from "./fs-safe.js";
4
+ /**
5
+ * Insert or replace a delimited block in a file, generalized over the
6
+ * target file, the start/end markers, and the block content — so a
7
+ * consumer can manage its own marker pair (e.g. `<!-- mcpi:dco:start -->`)
8
+ * in its own target file (e.g. `CLAUDE.md`) without duplicating this
9
+ * splice/append logic.
10
+ *
11
+ * Creates the file with just the block when missing, replaces an existing
12
+ * managed block in place, or appends with a blank-line separator when no
13
+ * managed block exists yet. A no-op write (content already matches) is
14
+ * reported as "unchanged" rather than touching the file.
15
+ *
16
+ * `relativePath` must never carry attacker- or config-file-influenced
17
+ * segments without validation upstream: it's resolved against `cwd` and
18
+ * rejected if it would escape it (e.g. `../../.ssh/authorized_keys`),
19
+ * but a crafted value that stays inside `cwd` (e.g. overwriting an
20
+ * unrelated tracked file) is still the caller's responsibility to guard.
21
+ */
22
+ export function upsertMarkerBlock(cwd, relativePath, startMarker, endMarker, block, options = {}) {
23
+ const resolvedCwd = resolve(cwd);
24
+ const path = resolve(resolvedCwd, relativePath);
25
+ if (path !== resolvedCwd && !path.startsWith(resolvedCwd + sep)) {
26
+ throw new Error(`Invalid relativePath "${relativePath}": resolves outside cwd "${cwd}"`);
27
+ }
28
+ if (!existsSync(path)) {
29
+ if (options.dryRun) {
30
+ return { result: "would-change", path };
31
+ }
32
+ const dir = dirname(path);
33
+ if (!existsSync(dir)) {
34
+ mkdirSync(dir, { recursive: true });
35
+ }
36
+ writeFileAtomicSafe(path, block + "\n");
37
+ return { result: "created", path };
38
+ }
39
+ const existing = readFileSync(path, "utf-8");
40
+ const startIdx = existing.indexOf(startMarker);
41
+ const endIdx = existing.indexOf(endMarker);
42
+ let next;
43
+ if (startIdx !== -1 && endIdx !== -1 && endIdx > startIdx) {
44
+ const before = existing.slice(0, startIdx);
45
+ const after = existing.slice(endIdx + endMarker.length);
46
+ next = before + block + after;
47
+ }
48
+ else {
49
+ const separator = existing.endsWith("\n") ? "\n" : "\n\n";
50
+ next = existing + separator + block + "\n";
51
+ }
52
+ if (next === existing) {
53
+ return { result: "unchanged", path };
54
+ }
55
+ if (options.dryRun) {
56
+ return { result: "would-change", path };
57
+ }
58
+ writeFileAtomicSafe(path, next);
59
+ return { result: "updated", path };
60
+ }
61
+ //# sourceMappingURL=marker-block.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"marker-block.js","sourceRoot":"","sources":["../../../src/utils/cli-kit/marker-block.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,IAAI,CAAC;AACzD,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,MAAM,CAAC;AAC7C,OAAO,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AAInD;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,UAAU,iBAAiB,CAC/B,GAAW,EACX,YAAoB,EACpB,WAAmB,EACnB,SAAiB,EACjB,KAAa,EACb,UAAgC,EAAE;IAElC,MAAM,WAAW,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;IACjC,MAAM,IAAI,GAAG,OAAO,CAAC,WAAW,EAAE,YAAY,CAAC,CAAC;IAChD,IAAI,IAAI,KAAK,WAAW,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,WAAW,GAAG,GAAG,CAAC,EAAE,CAAC;QAChE,MAAM,IAAI,KAAK,CACb,yBAAyB,YAAY,4BAA4B,GAAG,GAAG,CACxE,CAAC;IACJ,CAAC;IAED,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;QACtB,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;YACnB,OAAO,EAAE,MAAM,EAAE,cAAc,EAAE,IAAI,EAAE,CAAC;QAC1C,CAAC;QACD,MAAM,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;QAC1B,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;YACrB,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACtC,CAAC;QACD,mBAAmB,CAAC,IAAI,EAAE,KAAK,GAAG,IAAI,CAAC,CAAC;QACxC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;IACrC,CAAC;IAED,MAAM,QAAQ,GAAG,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IAC7C,MAAM,QAAQ,GAAG,QAAQ,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;IAC/C,MAAM,MAAM,GAAG,QAAQ,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAE3C,IAAI,IAAY,CAAC;IACjB,IAAI,QAAQ,KAAK,CAAC,CAAC,IAAI,MAAM,KAAK,CAAC,CAAC,IAAI,MAAM,GAAG,QAAQ,EAAE,CAAC;QAC1D,MAAM,MAAM,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC;QAC3C,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,MAAM,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC;QACxD,IAAI,GAAG,MAAM,GAAG,KAAK,GAAG,KAAK,CAAC;IAChC,CAAC;SAAM,CAAC;QACN,MAAM,SAAS,GAAG,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC;QAC1D,IAAI,GAAG,QAAQ,GAAG,SAAS,GAAG,KAAK,GAAG,IAAI,CAAC;IAC7C,CAAC;IAED,IAAI,IAAI,KAAK,QAAQ,EAAE,CAAC;QACtB,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC;IACvC,CAAC;IACD,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;QACnB,OAAO,EAAE,MAAM,EAAE,cAAc,EAAE,IAAI,EAAE,CAAC;IAC1C,CAAC;IACD,mBAAmB,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IAChC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;AACrC,CAAC"}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Slugs are often sourced from a file or env var an untrusted cloned repo
3
+ * can influence, and become a path segment under a state directory, so
4
+ * every source must pass this same shape check.
5
+ */
6
+ export declare const SLUG_PATTERN: RegExp;
7
+ export declare function isValidSlug(slug: string): boolean;
8
+ /**
9
+ * Absolute path to a namespaced state directory under the user's home,
10
+ * e.g. `stateDir("mcpi", "keys")` -> `~/.mcpi/keys`. Each CLI (mcpi,
11
+ * kya-id, ...) picks its own namespace so their on-disk state never
12
+ * collides.
13
+ */
14
+ export declare function stateDir(namespace: string, ...segments: string[]): string;
15
+ //# sourceMappingURL=paths.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../../../src/utils/cli-kit/paths.ts"],"names":[],"mappings":"AAGA;;;;GAIG;AACH,eAAO,MAAM,YAAY,QAAyB,CAAC;AAEnD,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEjD;AAED;;;;;GAKG;AACH,wBAAgB,QAAQ,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,QAAQ,EAAE,MAAM,EAAE,GAAG,MAAM,CAEzE"}
@@ -0,0 +1,21 @@
1
+ import { homedir } from "os";
2
+ import { join, resolve } from "path";
3
+ /**
4
+ * Slugs are often sourced from a file or env var an untrusted cloned repo
5
+ * can influence, and become a path segment under a state directory, so
6
+ * every source must pass this same shape check.
7
+ */
8
+ export const SLUG_PATTERN = /^[a-z0-9][a-z0-9-]*$/;
9
+ export function isValidSlug(slug) {
10
+ return SLUG_PATTERN.test(slug);
11
+ }
12
+ /**
13
+ * Absolute path to a namespaced state directory under the user's home,
14
+ * e.g. `stateDir("mcpi", "keys")` -> `~/.mcpi/keys`. Each CLI (mcpi,
15
+ * kya-id, ...) picks its own namespace so their on-disk state never
16
+ * collides.
17
+ */
18
+ export function stateDir(namespace, ...segments) {
19
+ return resolve(join(homedir(), `.${namespace}`, ...segments));
20
+ }
21
+ //# sourceMappingURL=paths.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"paths.js","sourceRoot":"","sources":["../../../src/utils/cli-kit/paths.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,IAAI,CAAC;AAC7B,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAErC;;;;GAIG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,sBAAsB,CAAC;AAEnD,MAAM,UAAU,WAAW,CAAC,IAAY;IACtC,OAAO,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACjC,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,QAAQ,CAAC,SAAiB,EAAE,GAAG,QAAkB;IAC/D,OAAO,OAAO,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,IAAI,SAAS,EAAE,EAAE,GAAG,QAAQ,CAAC,CAAC,CAAC;AAChE,CAAC"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Create (or reuse) a directory with 0700 permissions, recursively.
3
+ */
4
+ export declare function ensureSecureDir(path: string, mode?: number): void;
5
+ /**
6
+ * Write credential/key material with 0600 permissions.
7
+ *
8
+ * The mode is set on write to avoid any window where the file exists with
9
+ * looser permissions, then re-asserted with chmod: the write-time mode
10
+ * option is ignored when the file already exists, so a pre-existing file
11
+ * with looser permissions would otherwise keep them.
12
+ */
13
+ export declare function writeSecureFile(path: string, content: string, mode?: number): void;
14
+ //# sourceMappingURL=secure-storage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"secure-storage.d.ts","sourceRoot":"","sources":["../../../src/utils/cli-kit/secure-storage.ts"],"names":[],"mappings":"AAEA;;GAEG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,SAAQ,GAAG,IAAI,CAEhE;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAC7B,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,IAAI,SAAQ,GACX,IAAI,CAGN"}
@@ -0,0 +1,20 @@
1
+ import { chmodSync, mkdirSync, writeFileSync } from "fs";
2
+ /**
3
+ * Create (or reuse) a directory with 0700 permissions, recursively.
4
+ */
5
+ export function ensureSecureDir(path, mode = 0o700) {
6
+ mkdirSync(path, { recursive: true, mode });
7
+ }
8
+ /**
9
+ * Write credential/key material with 0600 permissions.
10
+ *
11
+ * The mode is set on write to avoid any window where the file exists with
12
+ * looser permissions, then re-asserted with chmod: the write-time mode
13
+ * option is ignored when the file already exists, so a pre-existing file
14
+ * with looser permissions would otherwise keep them.
15
+ */
16
+ export function writeSecureFile(path, content, mode = 0o600) {
17
+ writeFileSync(path, content, { mode });
18
+ chmodSync(path, mode);
19
+ }
20
+ //# sourceMappingURL=secure-storage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"secure-storage.js","sourceRoot":"","sources":["../../../src/utils/cli-kit/secure-storage.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,IAAI,CAAC;AAEzD;;GAEG;AACH,MAAM,UAAU,eAAe,CAAC,IAAY,EAAE,IAAI,GAAG,KAAK;IACxD,SAAS,CAAC,IAAI,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;AAC7C,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,eAAe,CAC7B,IAAY,EACZ,OAAe,EACf,IAAI,GAAG,KAAK;IAEZ,aAAa,CAAC,IAAI,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;IACvC,SAAS,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;AACxB,CAAC"}
@@ -0,0 +1,16 @@
1
+ export type StepStatus = "done" | "skipped" | "failed" | "action-required" | "would-change";
2
+ export interface StepResult {
3
+ id: string;
4
+ title: string;
5
+ status: StepStatus;
6
+ detail?: string;
7
+ }
8
+ export declare function statusLabel(status: StepStatus): string;
9
+ /**
10
+ * Render a step-report list as aligned `title status` lines, with a
11
+ * detail line under any step that isn't "done" or "skipped". Returns
12
+ * lines rather than printing them, so a consumer composes its own
13
+ * header/footer around the shared body.
14
+ */
15
+ export declare function renderSteps(steps: StepResult[]): string[];
16
+ //# sourceMappingURL=step-report.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"step-report.d.ts","sourceRoot":"","sources":["../../../src/utils/cli-kit/step-report.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,UAAU,GAClB,MAAM,GACN,SAAS,GACT,QAAQ,GACR,iBAAiB,GACjB,cAAc,CAAC;AAEnB,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,UAAU,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,wBAAgB,WAAW,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,CAatD;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,UAAU,EAAE,GAAG,MAAM,EAAE,CAazD"}
@@ -0,0 +1,36 @@
1
+ import chalk from "chalk";
2
+ export function statusLabel(status) {
3
+ switch (status) {
4
+ case "done":
5
+ return chalk.green("done");
6
+ case "skipped":
7
+ return chalk.gray("skipped");
8
+ case "would-change":
9
+ return chalk.cyan("would change");
10
+ case "action-required":
11
+ return chalk.yellow("action required");
12
+ case "failed":
13
+ return chalk.red("failed");
14
+ }
15
+ }
16
+ /**
17
+ * Render a step-report list as aligned `title status` lines, with a
18
+ * detail line under any step that isn't "done" or "skipped". Returns
19
+ * lines rather than printing them, so a consumer composes its own
20
+ * header/footer around the shared body.
21
+ */
22
+ export function renderSteps(steps) {
23
+ if (steps.length === 0) {
24
+ return [];
25
+ }
26
+ const width = Math.max(...steps.map((s) => s.title.length));
27
+ const lines = [];
28
+ for (const step of steps) {
29
+ lines.push(` ${step.title.padEnd(width)} ${statusLabel(step.status)}`);
30
+ if (step.detail && step.status !== "done" && step.status !== "skipped") {
31
+ lines.push(` ${" ".repeat(width)} ${chalk.gray(step.detail)}`);
32
+ }
33
+ }
34
+ return lines;
35
+ }
36
+ //# sourceMappingURL=step-report.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"step-report.js","sourceRoot":"","sources":["../../../src/utils/cli-kit/step-report.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAgB1B,MAAM,UAAU,WAAW,CAAC,MAAkB;IAC5C,QAAQ,MAAM,EAAE,CAAC;QACf,KAAK,MAAM;YACT,OAAO,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;QAC7B,KAAK,SAAS;YACZ,OAAO,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QAC/B,KAAK,cAAc;YACjB,OAAO,KAAK,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;QACpC,KAAK,iBAAiB;YACpB,OAAO,KAAK,CAAC,MAAM,CAAC,iBAAiB,CAAC,CAAC;QACzC,KAAK,QAAQ;YACX,OAAO,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IAC/B,CAAC;AACH,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,WAAW,CAAC,KAAmB;IAC7C,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACvB,OAAO,EAAE,CAAC;IACZ,CAAC;IACD,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC;IAC5D,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,KAAK,CAAC,IAAI,CAAC,KAAK,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,WAAW,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QACzE,IAAI,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,MAAM,KAAK,MAAM,IAAI,IAAI,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;YACvE,KAAK,CAAC,IAAI,CAAC,KAAK,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QACnE,CAAC;IACH,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC"}
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Persistent agent metadata written at registration time so later commands
3
- * (notably `mcpi dco setup`) know the agent's public name, slug, and URL
3
+ * (notably `dco setup`) know the agent's public name, slug, and URL
4
4
  * without another API round trip. Lives next to identity.json but contains
5
5
  * no key material (claimUrl may embed a short-lived claim capability; the
6
6
  * whole .mcpi directory is gitignored).
@@ -1,6 +1,6 @@
1
1
  import { existsSync, mkdirSync, readFileSync } from "fs";
2
2
  import { join } from "path";
3
- import { writeFileAtomicSafe } from "./fs-safe.js";
3
+ import { writeFileAtomicSafe } from "../cli-kit/index.js";
4
4
  const AGENT_METADATA_FILE = "agent.json";
5
5
  function agentMetadataPath(cwd) {
6
6
  return join(cwd, ".mcpi", AGENT_METADATA_FILE);
@@ -1 +1 @@
1
- {"version":3,"file":"agent-metadata.js","sourceRoot":"","sources":["../../../src/utils/dco/agent-metadata.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,IAAI,CAAC;AACzD,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AAmBnD,MAAM,mBAAmB,GAAG,YAAY,CAAC;AAEzC,SAAS,iBAAiB,CAAC,GAAW;IACpC,OAAO,IAAI,CAAC,GAAG,EAAE,OAAO,EAAE,mBAAmB,CAAC,CAAC;AACjD,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,GAAW;IAC3C,MAAM,IAAI,GAAG,iBAAiB,CAAC,GAAG,CAAC,CAAC;IACpC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;QACtB,OAAO,IAAI,CAAC;IACd,CAAC;IACD,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC;QACvD,IAAI,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;YACnE,OAAO,MAAuB,CAAC;QACjC,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,kBAAkB,CAAC,GAAW,EAAE,IAAmB;IACjE,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;IAC/B,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QACrB,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACtC,CAAC;IACD,MAAM,QAAQ,GAAG,iBAAiB,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC;IAC9C,MAAM,MAAM,GAAkB,EAAE,GAAG,QAAQ,EAAE,CAAC;IAC9C,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;QAChD,sEAAsE;QACtE,mEAAmE;QACnE,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,EAAE,EAAE,CAAC;YACvC,MAAkC,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;QACnD,CAAC;IACH,CAAC;IACD,uEAAuE;IACvE,mBAAmB,CACjB,iBAAiB,CAAC,GAAG,CAAC,EACtB,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,CACvC,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"agent-metadata.js","sourceRoot":"","sources":["../../../src/utils/dco/agent-metadata.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,IAAI,CAAC;AACzD,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAmB1D,MAAM,mBAAmB,GAAG,YAAY,CAAC;AAEzC,SAAS,iBAAiB,CAAC,GAAW;IACpC,OAAO,IAAI,CAAC,GAAG,EAAE,OAAO,EAAE,mBAAmB,CAAC,CAAC;AACjD,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,GAAW;IAC3C,MAAM,IAAI,GAAG,iBAAiB,CAAC,GAAG,CAAC,CAAC;IACpC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;QACtB,OAAO,IAAI,CAAC;IACd,CAAC;IACD,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC;QACvD,IAAI,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;YACnE,OAAO,MAAuB,CAAC;QACjC,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,kBAAkB,CAAC,GAAW,EAAE,IAAmB;IACjE,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;IAC/B,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QACrB,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACtC,CAAC;IACD,MAAM,QAAQ,GAAG,iBAAiB,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC;IAC9C,MAAM,MAAM,GAAkB,EAAE,GAAG,QAAQ,EAAE,CAAC;IAC9C,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;QAChD,sEAAsE;QACtE,mEAAmE;QACnE,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,EAAE,EAAE,CAAC;YACvC,MAAkC,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;QACnD,CAAC;IACH,CAAC;IACD,uEAAuE;IACvE,mBAAmB,CACjB,iBAAiB,CAAC,GAAG,CAAC,EACtB,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,CACvC,CAAC;AACJ,CAAC"}
@@ -1,3 +1,4 @@
1
+ import { type MergeJsonResult, type UpsertResult as CliKitUpsertResult } from "../cli-kit/index.js";
1
2
  /**
2
3
  * Claude Code integration: a managed block in CLAUDE.md instructs the agent
3
4
  * harness to attribute PRs to the registered agent, and .claude/settings.json
@@ -6,31 +7,40 @@
6
7
  * The PR byline can only be influenced through instructions because the PR
7
8
  * body is composed by the model at PR time; commit trailers are enforced
8
9
  * mechanically by the git hook instead (see git-config.ts).
10
+ *
11
+ * The block used to interpolate a specific agent's name/URL/DID as literal
12
+ * strings. That was wrong for any repo that receives dispatched work from
13
+ * more than one agent: CLAUDE.md is committed, so the literal values only
14
+ * ever reflected whichever agent happened to run `dco setup` first, and
15
+ * every other agent's PRs in that repo would carry a false attribution with
16
+ * no way to correct it short of re-running `dco setup` (which a dispatch
17
+ * flow generally can't do per task). The block below is agent-agnostic
18
+ * instead: it tells the agent to run `dco whoami` and use whatever
19
+ * that reports, so the byline is always whichever identity is actually
20
+ * configured in the current checkout. See resolve-agent.ts.
9
21
  */
10
22
  export declare const CLAUDE_MD_START = "<!-- mcpi:dco:start -->";
11
23
  export declare const CLAUDE_MD_END = "<!-- mcpi:dco:end -->";
12
24
  export interface AttributionBlockParams {
13
- agentName: string;
14
- agentUrl: string;
15
25
  /**
16
26
  * When the git hook could not be installed (foreign hook, unsafe
17
27
  * core.hooksPath, or install failure), trailer duty falls back to
18
28
  * instructions.
19
29
  */
20
30
  includeTrailerInstructions?: boolean;
21
- humanName?: string;
22
- humanEmail?: string;
23
- agentEmail?: string;
24
31
  }
25
- export declare function buildAttributionBlock(params: AttributionBlockParams): string;
26
- export type UpsertResult = "created" | "updated" | "unchanged" | "would-change";
32
+ export declare const DID_PATTERN: RegExp;
33
+ export declare const MAX_DID_LENGTH = 200;
34
+ export declare function isValidDid(value: string): boolean;
35
+ export declare function buildAttributionBlock(params?: AttributionBlockParams): string;
36
+ export type UpsertResult = CliKitUpsertResult;
27
37
  export declare function upsertClaudeMdBlock(cwd: string, block: string, options?: {
28
38
  dryRun?: boolean;
29
39
  }): {
30
40
  result: UpsertResult;
31
41
  path: string;
32
42
  };
33
- export type SettingsResult = "created" | "updated" | "unchanged" | "skipped-invalid" | "would-change";
43
+ export type SettingsResult = MergeJsonResult;
34
44
  /**
35
45
  * Set includeCoAuthoredBy: false in .claude/settings.json, preserving every
36
46
  * other key. A file we cannot parse is left untouched: clobbering a user's
@@ -1 +1 @@
1
- {"version":3,"file":"claude-config.d.ts","sourceRoot":"","sources":["../../../src/utils/dco/claude-config.ts"],"names":[],"mappings":"AAIA;;;;;;;;GAQG;AAEH,eAAO,MAAM,eAAe,4BAA4B,CAAC;AACzD,eAAO,MAAM,aAAa,0BAA0B,CAAC;AAErD,MAAM,WAAW,sBAAsB;IACrC,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB;;;;OAIG;IACH,0BAA0B,CAAC,EAAE,OAAO,CAAC;IACrC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAaD,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,sBAAsB,GAAG,MAAM,CAoB5E;AAED,MAAM,MAAM,YAAY,GAAG,SAAS,GAAG,SAAS,GAAG,WAAW,GAAG,cAAc,CAAC;AAEhF,wBAAgB,mBAAmB,CACjC,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,MAAM,EACb,OAAO,GAAE;IAAE,MAAM,CAAC,EAAE,OAAO,CAAA;CAAO,GACjC;IAAE,MAAM,EAAE,YAAY,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAiCxC;AAED,MAAM,MAAM,cAAc,GACtB,SAAS,GACT,SAAS,GACT,WAAW,GACX,iBAAiB,GACjB,cAAc,CAAC;AAEnB;;;;GAIG;AACH,wBAAgB,oBAAoB,CAClC,GAAG,EAAE,MAAM,EACX,OAAO,GAAE;IAAE,MAAM,CAAC,EAAE,OAAO,CAAA;CAAO,GACjC;IAAE,MAAM,EAAE,cAAc,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAqC1C"}
1
+ {"version":3,"file":"claude-config.d.ts","sourceRoot":"","sources":["../../../src/utils/dco/claude-config.ts"],"names":[],"mappings":"AACA,OAAO,EAGL,KAAK,eAAe,EACpB,KAAK,YAAY,IAAI,kBAAkB,EACxC,MAAM,qBAAqB,CAAC;AAE7B;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,eAAO,MAAM,eAAe,4BAA4B,CAAC;AACzD,eAAO,MAAM,aAAa,0BAA0B,CAAC;AAErD,MAAM,WAAW,sBAAsB;IACrC;;;;OAIG;IACH,0BAA0B,CAAC,EAAE,OAAO,CAAC;CACtC;AAQD,eAAO,MAAM,WAAW,QAAuC,CAAC;AAChE,eAAO,MAAM,cAAc,MAAM,CAAC;AAElC,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAEjD;AAED,wBAAgB,qBAAqB,CAAC,MAAM,GAAE,sBAA2B,GAAG,MAAM,CAqBjF;AAED,MAAM,MAAM,YAAY,GAAG,kBAAkB,CAAC;AAE9C,wBAAgB,mBAAmB,CACjC,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,MAAM,EACb,OAAO,GAAE;IAAE,MAAM,CAAC,EAAE,OAAO,CAAA;CAAO,GACjC;IAAE,MAAM,EAAE,YAAY,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CASxC;AAED,MAAM,MAAM,cAAc,GAAG,eAAe,CAAC;AAE7C;;;;GAIG;AACH,wBAAgB,oBAAoB,CAClC,GAAG,EAAE,MAAM,EACX,OAAO,GAAE;IAAE,MAAM,CAAC,EAAE,OAAO,CAAA;CAAO,GACjC;IAAE,MAAM,EAAE,cAAc,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAG1C"}
@@ -1,6 +1,5 @@
1
- import { existsSync, mkdirSync, readFileSync } from "fs";
2
1
  import { join } from "path";
3
- import { writeFileAtomicSafe } from "./fs-safe.js";
2
+ import { mergeJsonFile, upsertMarkerBlock, } from "../cli-kit/index.js";
4
3
  /**
5
4
  * Claude Code integration: a managed block in CLAUDE.md instructs the agent
6
5
  * harness to attribute PRs to the registered agent, and .claude/settings.json
@@ -9,66 +8,51 @@ import { writeFileAtomicSafe } from "./fs-safe.js";
9
8
  * The PR byline can only be influenced through instructions because the PR
10
9
  * body is composed by the model at PR time; commit trailers are enforced
11
10
  * mechanically by the git hook instead (see git-config.ts).
11
+ *
12
+ * The block used to interpolate a specific agent's name/URL/DID as literal
13
+ * strings. That was wrong for any repo that receives dispatched work from
14
+ * more than one agent: CLAUDE.md is committed, so the literal values only
15
+ * ever reflected whichever agent happened to run `dco setup` first, and
16
+ * every other agent's PRs in that repo would carry a false attribution with
17
+ * no way to correct it short of re-running `dco setup` (which a dispatch
18
+ * flow generally can't do per task). The block below is agent-agnostic
19
+ * instead: it tells the agent to run `dco whoami` and use whatever
20
+ * that reports, so the byline is always whichever identity is actually
21
+ * configured in the current checkout. See resolve-agent.ts.
12
22
  */
13
23
  export const CLAUDE_MD_START = "<!-- mcpi:dco:start -->";
14
24
  export const CLAUDE_MD_END = "<!-- mcpi:dco:end -->";
15
- /**
16
- * Values interpolated into the managed block come from .mcpi/agent.json and
17
- * git config, both attacker-influenceable in a cloned repo. Clamp everything
18
- * to a single line with no control characters so crafted metadata cannot
19
- * inject extra instructions into a block the harness treats as trusted.
20
- */
21
- function singleLine(value) {
22
- // eslint-disable-next-line no-control-regex
23
- return value.replace(/[\u0000-\u001f\u007f]+/g, " ").trim();
25
+ // did:key / did:web / etc: a lowercase method name, then method-specific-id
26
+ // drawn from the DID spec's idchar set. No backtick, "<", "!", or whitespace
27
+ // can appear in a matching value. Exported for verify.ts, which validates a
28
+ // DID claimed in a PR body against this same shape before ever resolving
29
+ // it, and for resolve-agent.ts, which validates the DID read from
30
+ // .mcpi/identity.json before it's ever printed by `dco whoami`.
31
+ export const DID_PATTERN = /^did:[a-z0-9]+:[A-Za-z0-9.\-_:%]+$/;
32
+ export const MAX_DID_LENGTH = 200;
33
+ export function isValidDid(value) {
34
+ return value.length <= MAX_DID_LENGTH && DID_PATTERN.test(value);
24
35
  }
25
- export function buildAttributionBlock(params) {
26
- const agentName = singleLine(params.agentName);
27
- const agentUrl = singleLine(params.agentUrl);
36
+ export function buildAttributionBlock(params = {}) {
28
37
  const lines = [
29
38
  CLAUDE_MD_START,
30
- "## Agent attribution (managed by `mcpi dco setup`)",
39
+ "## Agent attribution (managed by `dco setup`)",
31
40
  "",
32
- "- When creating pull requests, end the PR description with exactly this byline:",
33
- ` \`Generated with [${agentName}](${agentUrl})\``,
41
+ "- Before creating a pull request, run `dco whoami --json` in this repo to find the agent identity configured in this checkout.",
42
+ '- If it reports `"configured": true`, end the PR description with exactly these two lines, filled in from that command\'s `name`, `url`, and `did` fields (curly braces mark what to fill in; every other character, including the square/round brackets and the angle brackets around the DID line, is literal):',
43
+ " `Generated with [{name}]({url})`",
44
+ " `Agent DID: {did}`",
45
+ '- If it reports `"configured": false`, do not add a "Generated with" or "Agent DID" line at all.',
34
46
  '- Never add "Generated with Claude Code" or any other tool byline to PR descriptions or commit messages.',
35
47
  ];
36
48
  if (params.includeTrailerInstructions) {
37
- lines.push("- End every commit message with these trailers:", ` \`Signed-off-by: ${singleLine(params.humanName ?? "")} <${singleLine(params.humanEmail ?? "")}>\``, ` \`Co-authored-by: ${agentName} <${singleLine(params.agentEmail ?? "")}>\``);
49
+ lines.push("- End every commit message with these trailers. Resolve the first line from `git config user.name` / `git config user.email`, and the second from `dco whoami --json`'s `name` and `email` fields (omit this line entirely if `configured` is false). Curly braces mark what to fill in; the angle brackets around each email are literal characters git trailers require, keep them:", " `Signed-off-by: {your name} <{your email}>`", " `Co-authored-by: {agent name} <{agent email}>`");
38
50
  }
39
51
  lines.push(CLAUDE_MD_END);
40
52
  return lines.join("\n");
41
53
  }
42
54
  export function upsertClaudeMdBlock(cwd, block, options = {}) {
43
- const path = join(cwd, "CLAUDE.md");
44
- if (!existsSync(path)) {
45
- if (options.dryRun) {
46
- return { result: "would-change", path };
47
- }
48
- writeFileAtomicSafe(path, block + "\n");
49
- return { result: "created", path };
50
- }
51
- const existing = readFileSync(path, "utf-8");
52
- const startIdx = existing.indexOf(CLAUDE_MD_START);
53
- const endIdx = existing.indexOf(CLAUDE_MD_END);
54
- let next;
55
- if (startIdx !== -1 && endIdx !== -1 && endIdx > startIdx) {
56
- const before = existing.slice(0, startIdx);
57
- const after = existing.slice(endIdx + CLAUDE_MD_END.length);
58
- next = before + block + after;
59
- }
60
- else {
61
- const separator = existing.endsWith("\n") ? "\n" : "\n\n";
62
- next = existing + separator + block + "\n";
63
- }
64
- if (next === existing) {
65
- return { result: "unchanged", path };
66
- }
67
- if (options.dryRun) {
68
- return { result: "would-change", path };
69
- }
70
- writeFileAtomicSafe(path, next);
71
- return { result: "updated", path };
55
+ return upsertMarkerBlock(cwd, "CLAUDE.md", CLAUDE_MD_START, CLAUDE_MD_END, block, options);
72
56
  }
73
57
  /**
74
58
  * Set includeCoAuthoredBy: false in .claude/settings.json, preserving every
@@ -76,37 +60,7 @@ export function upsertClaudeMdBlock(cwd, block, options = {}) {
76
60
  * settings is worse than leaving the stock byline on.
77
61
  */
78
62
  export function updateClaudeSettings(cwd, options = {}) {
79
- const dir = join(cwd, ".claude");
80
- const path = join(dir, "settings.json");
81
- let settings = {};
82
- if (existsSync(path)) {
83
- try {
84
- const parsed = JSON.parse(readFileSync(path, "utf-8"));
85
- if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
86
- return { result: "skipped-invalid", path };
87
- }
88
- settings = parsed;
89
- }
90
- catch {
91
- return { result: "skipped-invalid", path };
92
- }
93
- if (settings.includeCoAuthoredBy === false) {
94
- return { result: "unchanged", path };
95
- }
96
- if (options.dryRun) {
97
- return { result: "would-change", path };
98
- }
99
- settings.includeCoAuthoredBy = false;
100
- writeFileAtomicSafe(path, JSON.stringify(settings, null, 2) + "\n");
101
- return { result: "updated", path };
102
- }
103
- if (options.dryRun) {
104
- return { result: "would-change", path };
105
- }
106
- if (!existsSync(dir)) {
107
- mkdirSync(dir, { recursive: true });
108
- }
109
- writeFileAtomicSafe(path, JSON.stringify({ includeCoAuthoredBy: false }, null, 2) + "\n");
110
- return { result: "created", path };
63
+ const path = join(cwd, ".claude", "settings.json");
64
+ return mergeJsonFile(path, { includeCoAuthoredBy: false }, options);
111
65
  }
112
66
  //# sourceMappingURL=claude-config.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"claude-config.js","sourceRoot":"","sources":["../../../src/utils/dco/claude-config.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"claude-config.js","sourceRoot":"","sources":["../../../src/utils/dco/claude-config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,EACL,aAAa,EACb,iBAAiB,GAGlB,MAAM,qBAAqB,CAAC;AAE7B;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,MAAM,CAAC,MAAM,eAAe,GAAG,yBAAyB,CAAC;AACzD,MAAM,CAAC,MAAM,aAAa,GAAG,uBAAuB,CAAC;AAWrD,4EAA4E;AAC5E,6EAA6E;AAC7E,4EAA4E;AAC5E,yEAAyE;AACzE,kEAAkE;AAClE,gEAAgE;AAChE,MAAM,CAAC,MAAM,WAAW,GAAG,oCAAoC,CAAC;AAChE,MAAM,CAAC,MAAM,cAAc,GAAG,GAAG,CAAC;AAElC,MAAM,UAAU,UAAU,CAAC,KAAa;IACtC,OAAO,KAAK,CAAC,MAAM,IAAI,cAAc,IAAI,WAAW,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AACnE,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,SAAiC,EAAE;IACvE,MAAM,KAAK,GAAG;QACZ,eAAe;QACf,+CAA+C;QAC/C,EAAE;QACF,gIAAgI;QAChI,mTAAmT;QACnT,oCAAoC;QACpC,sBAAsB;QACtB,kGAAkG;QAClG,0GAA0G;KAC3G,CAAC;IACF,IAAI,MAAM,CAAC,0BAA0B,EAAE,CAAC;QACtC,KAAK,CAAC,IAAI,CACR,uXAAuX,EACvX,+CAA+C,EAC/C,kDAAkD,CACnD,CAAC;IACJ,CAAC;IACD,KAAK,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;IAC1B,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAID,MAAM,UAAU,mBAAmB,CACjC,GAAW,EACX,KAAa,EACb,UAAgC,EAAE;IAElC,OAAO,iBAAiB,CACtB,GAAG,EACH,WAAW,EACX,eAAe,EACf,aAAa,EACb,KAAK,EACL,OAAO,CACR,CAAC;AACJ,CAAC;AAID;;;;GAIG;AACH,MAAM,UAAU,oBAAoB,CAClC,GAAW,EACX,UAAgC,EAAE;IAElC,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,EAAE,SAAS,EAAE,eAAe,CAAC,CAAC;IACnD,OAAO,aAAa,CAAC,IAAI,EAAE,EAAE,mBAAmB,EAAE,KAAK,EAAE,EAAE,OAAO,CAAC,CAAC;AACtE,CAAC"}
@@ -0,0 +1,59 @@
1
+ /**
2
+ * `dco dispatch` — ship a real, agent-signed PR in one command: branch,
3
+ * signed commit, push, `gh pr create` with an `Agent DID:` line, then verify
4
+ * the attribution the same way `dco verify` would.
5
+ *
6
+ * This is the command form of the quickstart runbook's Step 2 block
7
+ * (docs/runbook-mcpi-dco-quickstart.md), including its cold-start
8
+ * self-heal: a repo with no commits gets an initial commit, a repo with
9
+ * no `origin` gets a private GitHub repo created for it.
10
+ */
11
+ export interface DcoDispatchResult {
12
+ ok: boolean;
13
+ /** Human-readable description of the step that failed, when !ok. */
14
+ failure?: string;
15
+ agent?: {
16
+ name: string;
17
+ slug: string;
18
+ };
19
+ did?: string;
20
+ /** PR title (and commit-subject source); echoed back for --json callers. */
21
+ title?: string;
22
+ branch?: string;
23
+ commitSha?: string;
24
+ signed?: boolean;
25
+ /** Set when the cold-start self-heal had to create a GitHub repo. */
26
+ createdRemote?: string;
27
+ prUrl?: string;
28
+ verified?: boolean;
29
+ }
30
+ export interface DcoDispatchOptions {
31
+ /**
32
+ * Dispatch as this existing agent instead of the checkout's `.mcpi/`
33
+ * identity: sign with `~/.mcpi/keys/<slug>` via per-invocation git config,
34
+ * so it works from any repo and ignores conflicting repo signing config.
35
+ */
36
+ agent?: string;
37
+ /**
38
+ * PR title (and the source for the commit subject). Defaults to the
39
+ * description's first line, truncated to MAX_TITLE_LENGTH.
40
+ */
41
+ title?: string;
42
+ }
43
+ /**
44
+ * Resolve the PR title: the explicit `--title`, or the description's first
45
+ * NON-EMPTY line when omitted (a description that opens with a blank line,
46
+ * e.g. "\n\nActual title", must not yield an empty title). Either way it's
47
+ * truncated to a safe length, since the title also seeds the commit subject
48
+ * and a raw description can run long.
49
+ */
50
+ export declare function deriveDispatchTitle(description: string, explicitTitle?: string): string;
51
+ /**
52
+ * Lowercase subject on purpose: commitlint `subject-case` hooks reject an
53
+ * uppercase one, and lowercase passes everywhere. Truncated separately from
54
+ * the title (after the "docs: " prefix) so a title near MAX_TITLE_LENGTH
55
+ * still yields a commit subject well inside commitlint's own length rule.
56
+ */
57
+ export declare function buildDispatchCommitSubject(title: string): string;
58
+ export declare function runDcoDispatch(cwd: string, description: string, options?: DcoDispatchOptions): Promise<DcoDispatchResult>;
59
+ //# sourceMappingURL=dispatch.d.ts.map