@dharta/cli 0.6.77 → 0.6.78

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 (293) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +215 -11
  3. package/dist/agent.js +3 -2
  4. package/dist/agent.js.map +1 -1
  5. package/dist/api-error.js +6 -6
  6. package/dist/api-error.js.map +1 -1
  7. package/dist/cli.d.ts +3 -0
  8. package/dist/cli.js +860 -149
  9. package/dist/cli.js.map +1 -1
  10. package/dist/command-tree.d.ts +3 -0
  11. package/dist/command-tree.js +10 -0
  12. package/dist/command-tree.js.map +1 -0
  13. package/dist/commands/agents.d.ts +54 -17
  14. package/dist/commands/agents.js +246 -136
  15. package/dist/commands/agents.js.map +1 -1
  16. package/dist/commands/analytics.js +6 -5
  17. package/dist/commands/analytics.js.map +1 -1
  18. package/dist/commands/api.js +71 -86
  19. package/dist/commands/api.js.map +1 -1
  20. package/dist/commands/appearance.js +5 -6
  21. package/dist/commands/appearance.js.map +1 -1
  22. package/dist/commands/artifact.js +7 -6
  23. package/dist/commands/artifact.js.map +1 -1
  24. package/dist/commands/audit-log.js +2 -1
  25. package/dist/commands/audit-log.js.map +1 -1
  26. package/dist/commands/auth.js +26 -6
  27. package/dist/commands/auth.js.map +1 -1
  28. package/dist/commands/caps.js +11 -15
  29. package/dist/commands/caps.js.map +1 -1
  30. package/dist/commands/deploy.js +25 -10
  31. package/dist/commands/deploy.js.map +1 -1
  32. package/dist/commands/dev.d.ts +10 -1
  33. package/dist/commands/dev.js +56 -25
  34. package/dist/commands/dev.js.map +1 -1
  35. package/dist/commands/doctor.d.ts +2 -0
  36. package/dist/commands/doctor.js +60 -0
  37. package/dist/commands/doctor.js.map +1 -1
  38. package/dist/commands/embed-keys.js +4 -13
  39. package/dist/commands/embed-keys.js.map +1 -1
  40. package/dist/commands/env.js +4 -7
  41. package/dist/commands/env.js.map +1 -1
  42. package/dist/commands/files.js +3 -4
  43. package/dist/commands/files.js.map +1 -1
  44. package/dist/commands/fleet.d.ts +129 -0
  45. package/dist/commands/fleet.js +408 -0
  46. package/dist/commands/fleet.js.map +1 -0
  47. package/dist/commands/genui.d.ts +2 -0
  48. package/dist/commands/genui.js +53 -0
  49. package/dist/commands/genui.js.map +1 -0
  50. package/dist/commands/git-credential.js +2 -3
  51. package/dist/commands/git-credential.js.map +1 -1
  52. package/dist/commands/kartas.d.ts +9 -0
  53. package/dist/commands/kartas.js +33 -11
  54. package/dist/commands/kartas.js.map +1 -1
  55. package/dist/commands/keys.d.ts +17 -18
  56. package/dist/commands/keys.js +108 -19
  57. package/dist/commands/keys.js.map +1 -1
  58. package/dist/commands/login.js +2 -1
  59. package/dist/commands/login.js.map +1 -1
  60. package/dist/commands/members.d.ts +10 -0
  61. package/dist/commands/members.js +20 -6
  62. package/dist/commands/members.js.map +1 -1
  63. package/dist/commands/model-connections.d.ts +44 -0
  64. package/dist/commands/model-connections.js +435 -0
  65. package/dist/commands/model-connections.js.map +1 -0
  66. package/dist/commands/open.d.ts +2 -2
  67. package/dist/commands/open.js +4 -3
  68. package/dist/commands/open.js.map +1 -1
  69. package/dist/commands/org.d.ts +9 -0
  70. package/dist/commands/org.js +42 -0
  71. package/dist/commands/org.js.map +1 -0
  72. package/dist/commands/organization.d.ts +16 -0
  73. package/dist/commands/organization.js +118 -0
  74. package/dist/commands/organization.js.map +1 -0
  75. package/dist/commands/parity.js +1 -3
  76. package/dist/commands/parity.js.map +1 -1
  77. package/dist/commands/repos.d.ts +4 -0
  78. package/dist/commands/repos.js +17 -0
  79. package/dist/commands/repos.js.map +1 -0
  80. package/dist/commands/rollback.js +2 -3
  81. package/dist/commands/rollback.js.map +1 -1
  82. package/dist/commands/schedules.js +26 -21
  83. package/dist/commands/schedules.js.map +1 -1
  84. package/dist/commands/scopes.js +8 -1
  85. package/dist/commands/scopes.js.map +1 -1
  86. package/dist/commands/sessions.js +9 -3
  87. package/dist/commands/sessions.js.map +1 -1
  88. package/dist/commands/setup.js +5 -4
  89. package/dist/commands/setup.js.map +1 -1
  90. package/dist/commands/update.d.ts +1 -0
  91. package/dist/commands/update.js +24 -11
  92. package/dist/commands/update.js.map +1 -1
  93. package/dist/commands/webhooks.d.ts +4 -1
  94. package/dist/commands/webhooks.js +21 -16
  95. package/dist/commands/webhooks.js.map +1 -1
  96. package/dist/completions.js +24 -13
  97. package/dist/completions.js.map +1 -1
  98. package/dist/config.d.ts +12 -0
  99. package/dist/config.js +121 -7
  100. package/dist/config.js.map +1 -1
  101. package/dist/context.d.ts +2 -0
  102. package/dist/context.js +23 -7
  103. package/dist/context.js.map +1 -1
  104. package/dist/docs/cli-reference.d.ts +2 -0
  105. package/dist/docs/cli-reference.js +191 -0
  106. package/dist/docs/cli-reference.js.map +1 -0
  107. package/dist/exit-codes.d.ts +25 -0
  108. package/dist/exit-codes.js +107 -0
  109. package/dist/exit-codes.js.map +1 -0
  110. package/dist/genui.d.ts +178 -0
  111. package/dist/genui.js +1130 -0
  112. package/dist/genui.js.map +1 -0
  113. package/dist/harnesses.js +2 -1
  114. package/dist/harnesses.js.map +1 -1
  115. package/dist/jq.d.ts +4 -0
  116. package/dist/jq.js +91 -0
  117. package/dist/jq.js.map +1 -0
  118. package/dist/login-offer.js +6 -2
  119. package/dist/login-offer.js.map +1 -1
  120. package/dist/manifest.d.ts +12 -0
  121. package/dist/manifest.js +126 -0
  122. package/dist/manifest.js.map +1 -1
  123. package/dist/model-auth.d.ts +29 -0
  124. package/dist/model-auth.js +117 -0
  125. package/dist/model-auth.js.map +1 -0
  126. package/dist/model-settings.d.ts +23 -0
  127. package/dist/model-settings.js +186 -0
  128. package/dist/model-settings.js.map +1 -0
  129. package/dist/money.js +2 -1
  130. package/dist/money.js.map +1 -1
  131. package/dist/output.d.ts +6 -0
  132. package/dist/output.js +54 -0
  133. package/dist/output.js.map +1 -1
  134. package/dist/runtime.d.ts +1 -1
  135. package/dist/runtime.js +1 -1
  136. package/dist/scaffold.js +2 -1
  137. package/dist/scaffold.js.map +1 -1
  138. package/dist/validators.js +17 -11
  139. package/dist/validators.js.map +1 -1
  140. package/dist/version-check.d.ts +1 -1
  141. package/dist/version-check.js +1 -1
  142. package/dist/version-check.js.map +1 -1
  143. package/node_modules/@dharta/contracts/LICENSE +21 -0
  144. package/node_modules/@dharta/contracts/README.md +45 -0
  145. package/node_modules/@dharta/contracts/artifact-runtime.json +750 -0
  146. package/node_modules/@dharta/contracts/dist/activity.d.ts +62 -0
  147. package/node_modules/@dharta/contracts/dist/activity.d.ts.map +1 -0
  148. package/node_modules/@dharta/contracts/dist/activity.js +178 -0
  149. package/node_modules/@dharta/contracts/dist/activity.js.map +1 -0
  150. package/node_modules/@dharta/contracts/dist/artifact-runtime-formats.d.ts +20 -0
  151. package/node_modules/@dharta/contracts/dist/artifact-runtime-formats.d.ts.map +1 -0
  152. package/node_modules/@dharta/contracts/dist/artifact-runtime-formats.js +53 -0
  153. package/node_modules/@dharta/contracts/dist/artifact-runtime-formats.js.map +1 -0
  154. package/node_modules/@dharta/contracts/dist/artifact-runtime-validators.generated.d.ts +37 -0
  155. package/node_modules/@dharta/contracts/dist/artifact-runtime-validators.generated.d.ts.map +1 -0
  156. package/node_modules/@dharta/contracts/dist/artifact-runtime-validators.generated.js +5107 -0
  157. package/node_modules/@dharta/contracts/dist/artifact-runtime-validators.generated.js.map +1 -0
  158. package/node_modules/@dharta/contracts/dist/artifact-runtime.d.ts +154 -0
  159. package/node_modules/@dharta/contracts/dist/artifact-runtime.d.ts.map +1 -0
  160. package/node_modules/@dharta/contracts/dist/artifact-runtime.generated.d.ts +1670 -0
  161. package/node_modules/@dharta/contracts/dist/artifact-runtime.generated.d.ts.map +1 -0
  162. package/node_modules/@dharta/contracts/dist/artifact-runtime.generated.js +1903 -0
  163. package/node_modules/@dharta/contracts/dist/artifact-runtime.generated.js.map +1 -0
  164. package/node_modules/@dharta/contracts/dist/artifact-runtime.js +377 -0
  165. package/node_modules/@dharta/contracts/dist/artifact-runtime.js.map +1 -0
  166. package/node_modules/@dharta/contracts/dist/index.d.ts +6 -0
  167. package/node_modules/@dharta/contracts/dist/index.d.ts.map +1 -0
  168. package/node_modules/@dharta/contracts/dist/index.js +6 -0
  169. package/node_modules/@dharta/contracts/dist/index.js.map +1 -0
  170. package/node_modules/@dharta/contracts/dist/model-auth.d.ts +31 -0
  171. package/node_modules/@dharta/contracts/dist/model-auth.d.ts.map +1 -0
  172. package/node_modules/@dharta/contracts/dist/model-auth.js +45 -0
  173. package/node_modules/@dharta/contracts/dist/model-auth.js.map +1 -0
  174. package/node_modules/@dharta/contracts/dist/tasks.d.ts +44 -0
  175. package/node_modules/@dharta/contracts/dist/tasks.d.ts.map +1 -0
  176. package/node_modules/@dharta/contracts/dist/tasks.js +127 -0
  177. package/node_modules/@dharta/contracts/dist/tasks.js.map +1 -0
  178. package/node_modules/@dharta/contracts/dist/wire-events.d.ts +71 -0
  179. package/node_modules/@dharta/contracts/dist/wire-events.d.ts.map +1 -0
  180. package/node_modules/@dharta/contracts/dist/wire-events.js +48 -0
  181. package/node_modules/@dharta/contracts/dist/wire-events.js.map +1 -0
  182. package/node_modules/@dharta/contracts/model-auth-capabilities-v1.json +168 -0
  183. package/node_modules/@dharta/contracts/model-auth-reasons-v1.json +38 -0
  184. package/node_modules/@dharta/contracts/package.json +44 -0
  185. package/node_modules/@dharta/contracts/src/activity.ts +215 -0
  186. package/node_modules/@dharta/contracts/src/artifact-runtime-formats.ts +54 -0
  187. package/node_modules/@dharta/contracts/src/artifact-runtime-validators.generated.ts +29 -0
  188. package/node_modules/@dharta/contracts/src/artifact-runtime.generated.ts +2093 -0
  189. package/node_modules/@dharta/contracts/src/artifact-runtime.ts +520 -0
  190. package/node_modules/@dharta/contracts/src/index.ts +5 -0
  191. package/node_modules/@dharta/contracts/src/model-auth.ts +82 -0
  192. package/node_modules/@dharta/contracts/src/tasks.ts +142 -0
  193. package/node_modules/@dharta/contracts/src/wire-events.ts +150 -0
  194. package/node_modules/@dharta/contracts/wire-events.json +29 -0
  195. package/node_modules/@dharta/sdk/LICENSE +1 -1
  196. package/node_modules/@dharta/sdk/README.md +22 -8
  197. package/node_modules/@dharta/sdk/dist/errors.d.ts +9 -7
  198. package/node_modules/@dharta/sdk/dist/errors.d.ts.map +1 -1
  199. package/node_modules/@dharta/sdk/dist/errors.js +36 -18
  200. package/node_modules/@dharta/sdk/dist/errors.js.map +1 -1
  201. package/node_modules/@dharta/sdk/dist/fleet.d.ts +69 -0
  202. package/node_modules/@dharta/sdk/dist/fleet.d.ts.map +1 -0
  203. package/node_modules/@dharta/sdk/dist/fleet.js +240 -0
  204. package/node_modules/@dharta/sdk/dist/fleet.js.map +1 -0
  205. package/node_modules/@dharta/sdk/dist/http.d.ts +6 -2
  206. package/node_modules/@dharta/sdk/dist/http.d.ts.map +1 -1
  207. package/node_modules/@dharta/sdk/dist/http.js +71 -12
  208. package/node_modules/@dharta/sdk/dist/http.js.map +1 -1
  209. package/node_modules/@dharta/sdk/dist/idempotency.d.ts +12 -0
  210. package/node_modules/@dharta/sdk/dist/idempotency.d.ts.map +1 -0
  211. package/node_modules/@dharta/sdk/dist/idempotency.js +72 -0
  212. package/node_modules/@dharta/sdk/dist/idempotency.js.map +1 -0
  213. package/node_modules/@dharta/sdk/dist/index.d.ts +20 -6
  214. package/node_modules/@dharta/sdk/dist/index.d.ts.map +1 -1
  215. package/node_modules/@dharta/sdk/dist/index.js +27 -4
  216. package/node_modules/@dharta/sdk/dist/index.js.map +1 -1
  217. package/node_modules/@dharta/sdk/dist/resources.d.ts +108 -13
  218. package/node_modules/@dharta/sdk/dist/resources.d.ts.map +1 -1
  219. package/node_modules/@dharta/sdk/dist/resources.js +403 -57
  220. package/node_modules/@dharta/sdk/dist/resources.js.map +1 -1
  221. package/node_modules/@dharta/sdk/dist/types.d.ts +436 -16
  222. package/node_modules/@dharta/sdk/dist/types.d.ts.map +1 -1
  223. package/node_modules/@dharta/sdk/dist/types.js +31 -2
  224. package/node_modules/@dharta/sdk/dist/types.js.map +1 -1
  225. package/node_modules/@dharta/sdk/package.json +9 -3
  226. package/node_modules/@dharta/sdk/src/errors.ts +41 -18
  227. package/node_modules/@dharta/sdk/src/fleet.ts +339 -0
  228. package/node_modules/@dharta/sdk/src/http.ts +110 -17
  229. package/node_modules/@dharta/sdk/src/idempotency.ts +101 -0
  230. package/node_modules/@dharta/sdk/src/index.ts +50 -11
  231. package/node_modules/@dharta/sdk/src/resources.ts +549 -68
  232. package/node_modules/@dharta/sdk/src/types.ts +629 -20
  233. package/package.json +16 -6
  234. package/src/agent.ts +3 -2
  235. package/src/api-error.ts +6 -5
  236. package/src/cli.ts +978 -163
  237. package/src/command-tree.ts +13 -0
  238. package/src/commands/agents.ts +365 -167
  239. package/src/commands/analytics.ts +6 -5
  240. package/src/commands/api.ts +73 -92
  241. package/src/commands/appearance.ts +5 -6
  242. package/src/commands/artifact.ts +7 -6
  243. package/src/commands/audit-log.ts +2 -1
  244. package/src/commands/auth.ts +25 -5
  245. package/src/commands/caps.ts +11 -15
  246. package/src/commands/deploy.ts +18 -4
  247. package/src/commands/dev.ts +86 -25
  248. package/src/commands/doctor.ts +69 -0
  249. package/src/commands/embed-keys.ts +4 -14
  250. package/src/commands/env.ts +4 -7
  251. package/src/commands/files.ts +3 -4
  252. package/src/commands/fleet.ts +672 -0
  253. package/src/commands/genui.ts +59 -0
  254. package/src/commands/git-credential.ts +2 -3
  255. package/src/commands/kartas.ts +45 -11
  256. package/src/commands/keys.ts +152 -35
  257. package/src/commands/login.ts +2 -1
  258. package/src/commands/members.ts +31 -6
  259. package/src/commands/model-connections.ts +547 -0
  260. package/src/commands/open.ts +5 -4
  261. package/src/commands/org.ts +57 -0
  262. package/src/commands/organization.ts +153 -0
  263. package/src/commands/parity.ts +1 -3
  264. package/src/commands/repos.ts +23 -0
  265. package/src/commands/rollback.ts +2 -3
  266. package/src/commands/schedules.ts +33 -22
  267. package/src/commands/scopes.ts +8 -1
  268. package/src/commands/sessions.ts +9 -3
  269. package/src/commands/setup.ts +5 -4
  270. package/src/commands/update.ts +28 -12
  271. package/src/commands/webhooks.ts +30 -19
  272. package/src/completions.ts +25 -13
  273. package/src/config.ts +141 -9
  274. package/src/context.ts +34 -7
  275. package/src/docs/cli-reference.ts +206 -0
  276. package/src/exit-codes.ts +122 -0
  277. package/src/genui.ts +1398 -0
  278. package/src/harnesses.ts +2 -1
  279. package/src/jq.ts +109 -0
  280. package/src/login-offer.ts +6 -2
  281. package/src/manifest.ts +134 -0
  282. package/src/model-auth.ts +173 -0
  283. package/src/model-settings.ts +222 -0
  284. package/src/money.ts +5 -1
  285. package/src/output.ts +60 -0
  286. package/src/runtime.ts +1 -1
  287. package/src/scaffold.ts +2 -1
  288. package/src/validators.ts +18 -11
  289. package/src/version-check.ts +1 -1
  290. package/dist/commands/model-keys.d.ts +0 -22
  291. package/dist/commands/model-keys.js +0 -222
  292. package/dist/commands/model-keys.js.map +0 -1
  293. package/src/commands/model-keys.ts +0 -278
package/src/harnesses.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import { existsSync } from "node:fs";
2
2
  import * as path from "node:path";
3
3
  import TOML from "@iarna/toml";
4
+ import { CliUsageError } from "./exit-codes.js";
4
5
  import { closestChoice, normalizeNonBlank } from "./validators.js";
5
6
 
6
7
  export const HARNESS_TYPES = ["claude-code", "opencode", "deepagents", "goose", "codex-cli"] as const;
@@ -38,7 +39,7 @@ export function parseHarnessType(value: string | undefined, label = "--harness")
38
39
  const normalized = normalizeNonBlank(value, label);
39
40
  if ((HARNESS_TYPES as readonly string[]).includes(normalized)) return normalized as HarnessType;
40
41
  const suggestion = closestChoice(normalized, HARNESS_TYPES);
41
- throw new Error(
42
+ throw new CliUsageError(
42
43
  `${label} must be one of ${HARNESS_TYPES.join(", ")}.` +
43
44
  (suggestion ? ` Did you mean ${suggestion}?` : ""),
44
45
  );
package/src/jq.ts ADDED
@@ -0,0 +1,109 @@
1
+ // `--jq <expr>` (RFC 0048 P5): filter the JSON a command would print, without
2
+ // making the user install jq. The filter runs in-process on a WebAssembly jq
3
+ // (jq-wasm), so `dharta … --jq` behaves the same on a developer laptop, a
4
+ // container, and the standalone tarball, and `dharta` keeps its single-binary
5
+ // promise.
6
+ //
7
+ // Package choice: jq-wasm, pinned to 3.0.0-jq-1.8.2 (the current line). It is
8
+ // the only maintained WebAssembly jq on npm that ships a prebuilt artifact - no
9
+ // node-gyp, no emscripten toolchain, no postinstall script - with TypeScript
10
+ // types and zero runtime dependencies. Its `engines.node >= 20` is below this
11
+ // package's own floor, which commander 15 sets at 22.12.
12
+
13
+ import { CliUsageError } from "./exit-codes.js";
14
+
15
+ interface JqResult {
16
+ stdout: string;
17
+ stderr: string;
18
+ exitCode: number;
19
+ }
20
+
21
+ // The input is handed over as JSON *text*, not as a live object: the binding
22
+ // rejects a null or scalar argument, and `dharta api` can legitimately print
23
+ // `null`, a number, or a bare string.
24
+ type JqRaw = (input: string, query: string, flags?: string[]) => Promise<JqResult>;
25
+
26
+ // -c only: one compact JSON value per line, so multiple results stay
27
+ // one-per-line for `while read`.
28
+ //
29
+ // jq's own -r is deliberately NOT used. jq-wasm trims the whole of stdout, so
30
+ // `--jq .v` over {"v":" padded "} would print `padded` and quietly lose the
31
+ // value's own whitespace. Compact JSON never carries leading or trailing
32
+ // whitespace, so the same trim is harmless here, and rawLine() below does what
33
+ // -r does: a result that is a string prints without quotes, so
34
+ // `--jq .name | xargs` works the way people expect from jq itself.
35
+ const JQ_FLAGS = ["-c"];
36
+ // jq's own exit code for a program that does not compile, as opposed to one
37
+ // that compiles and then fails on the data (5) or hits a system error (2).
38
+ const JQ_COMPILE_ERROR = 3;
39
+
40
+ let expression: string | null = null;
41
+ let jqRaw: JqRaw | null = null;
42
+
43
+ export function jqExpression(): string | null {
44
+ return expression;
45
+ }
46
+
47
+ // Load jq and compile the expression BEFORE the command does its work. A
48
+ // mistyped filter must not cost a mutation that then has nowhere to print.
49
+ export async function armJqFilter(expr: string | undefined): Promise<void> {
50
+ expression = null;
51
+ jqRaw = null;
52
+ if (expr === undefined) return;
53
+
54
+ const query = expr.trim();
55
+ if (!query) {
56
+ throw new CliUsageError("--jq needs an expression, for example --jq '.data[].id'.");
57
+ }
58
+
59
+ jqRaw = await loadJqRaw();
60
+ const probe = await jqRaw("null", query, JQ_FLAGS);
61
+ if (probe.exitCode === JQ_COMPILE_ERROR) {
62
+ throw new CliUsageError(`--jq expression did not compile.\n${probe.stderr.trim()}`);
63
+ }
64
+ expression = query;
65
+ }
66
+
67
+ // Reset between runs. Tests drive the program repeatedly in one process, and a
68
+ // leftover filter would silently rewrite the next command's output.
69
+ export function disarmJqFilter(): void {
70
+ expression = null;
71
+ jqRaw = null;
72
+ }
73
+
74
+ export async function applyJqFilter(payload: unknown): Promise<string> {
75
+ if (expression === null || jqRaw === null) {
76
+ throw new Error("applyJqFilter called with no armed --jq expression.");
77
+ }
78
+ const result = await jqRaw(JSON.stringify(payload) ?? "null", expression, JQ_FLAGS);
79
+ if (result.exitCode !== 0) {
80
+ // Every non-zero exit here is the expression's fault given this payload
81
+ // (`.a.b` on a string, `.[0]` on an object), so it reads as a usage error.
82
+ throw new CliUsageError(`--jq failed on the response.\n${result.stderr.trim()}`);
83
+ }
84
+ // jq terminates every result with a newline; console.log adds its own.
85
+ const stdout = result.stdout.replace(/\n$/, "");
86
+ if (stdout === "") return "";
87
+ // One compact JSON value per line, so splitting on newlines is safe: a
88
+ // newline inside a string is escaped until rawLine() unescapes it.
89
+ return stdout.split("\n").map(rawLine).join("\n");
90
+ }
91
+
92
+ // What jq's -r does, done here so the library's trim cannot reach inside a
93
+ // string. A line that is a JSON string prints as the string; anything else
94
+ // (object, array, number, boolean, null) prints as it came out.
95
+ function rawLine(line: string): string {
96
+ try {
97
+ const value: unknown = JSON.parse(line);
98
+ return typeof value === "string" ? value : line;
99
+ } catch {
100
+ return line;
101
+ }
102
+ }
103
+
104
+ // Imported lazily: the wasm build is about a megabyte, and a CLI run that never
105
+ // passes --jq should never pay to load it.
106
+ async function loadJqRaw(): Promise<JqRaw> {
107
+ const mod = (await import("jq-wasm")) as unknown as { raw: JqRaw };
108
+ return mod.raw;
109
+ }
@@ -4,7 +4,7 @@
4
4
  // (which does need auth). --login forces it; otherwise we only prompt an
5
5
  // interactive terminal. It never blocks setup.
6
6
 
7
- import { activeProfile } from "./config.js";
7
+ import { activeProfile, requestedProfileName } from "./config.js";
8
8
  import { login } from "./commands/login.js";
9
9
 
10
10
  export interface OfferLoginOptions {
@@ -35,7 +35,11 @@ export async function offerLogin(opts: OfferLoginOptions): Promise<OfferLoginOut
35
35
  return "skipped";
36
36
  }
37
37
 
38
- await (opts.runLogin ?? (() => login({ log: opts.log }).then(() => undefined)))();
38
+ // The global --profile names the profile this writes, the same as a bare
39
+ // `dharta login`: `dharta setup --login --profile staging` must not store the
40
+ // key as `default`.
41
+ await (opts.runLogin ??
42
+ (() => login({ log: opts.log, profile: requestedProfileName() }).then(() => undefined)))();
39
43
  return "completed";
40
44
  }
41
45
 
package/src/manifest.ts CHANGED
@@ -84,6 +84,30 @@ export function renderManifest(o: {
84
84
  '# setup = "scripts/setup.sh"',
85
85
  '# network = "full"',
86
86
  "",
87
+ "# --- Generative UI (RFC 0056) ----------------------------------------------",
88
+ "# Opt in to agent-driven UI in the embedded widget. No [genui] section = the",
89
+ "# agent answers in text only and pays no token cost for a catalog.",
90
+ "# catalog_id - stable id for this agent's component catalog.",
91
+ "# version - bump when the catalog changes (integer >= 1; 1.0 is a float",
92
+ "# and is rejected).",
93
+ "# components - every component the agent may render, with its trust tier:",
94
+ "# 1 = a Dharta builtin, 2 = your JavaScript in a Web Worker,",
95
+ "# 3 = your HTML in a sandboxed iframe. Tiers 2-3 need a bundle.",
96
+ "# bundle, bundle_sha256 - written by `dharta genui build`. Do not hand-edit",
97
+ "# the digest; the deploy verifies it against the bundle bytes.",
98
+ "# Run `dharta genui build --help` for the source layout it compiles.",
99
+ "# [genui]",
100
+ '# catalog_id = "support-bot-ui"',
101
+ "# version = 1",
102
+ '# components = [{ name = "Card", tier = 1 }, { name = "Pentagraph", tier = 2 }]',
103
+ '# bundle = "genui/bundle.json"',
104
+ '# bundle_sha256 = "<64 hex characters>"',
105
+ "",
106
+ "# Build-time only, never part of the release contract: where",
107
+ "# `dharta genui build` reads component sources from.",
108
+ "# [genui.build]",
109
+ '# source = "genui/components" # this is the default',
110
+ "",
87
111
  ].join("\n");
88
112
  }
89
113
 
@@ -119,6 +143,116 @@ export function patchScalar(src: string, key: string, literal: string): string {
119
143
  return (src.endsWith("\n") ? src : src + "\n") + line;
120
144
  }
121
145
 
146
+ // Locate ONE `[table]`'s own lines: from its header to the next line that
147
+ // starts a table. A multi-line inline array whose elements start a line with
148
+ // `[` would end the region early; an edit built on that produces invalid TOML,
149
+ // which the round-trip in `setGenuiBundleSha256` catches loudly rather than
150
+ // writing out. `table` is always a literal we control ("genui").
151
+ function tableRegion(lines: string[], table: string): { start: number; end: number } | null {
152
+ // `\r?` for the same reason assignmentPattern carries it: splitting a CRLF
153
+ // file on "\n" leaves the carriage return at the end of every line, and `.`
154
+ // never matches it, so `[genui] # comment\r` would not be recognized as a
155
+ // header and the whole table would read as absent.
156
+ const header = new RegExp(`^\\s*\\[\\s*${table}\\s*\\]\\s*(?:#.*?)?\\r?$`);
157
+ const start = lines.findIndex((line) => header.test(line));
158
+ if (start < 0) return null;
159
+ let end = lines.length;
160
+ for (let i = start + 1; i < lines.length; i++) {
161
+ if (/^\s*\[/.test(lines[i])) {
162
+ end = i;
163
+ break;
164
+ }
165
+ }
166
+ return { start, end };
167
+ }
168
+
169
+ // Anchored to a line start, so a commented `# key = ...` is never matched. The
170
+ // third group captures a CRLF file's carriage return, which lives at the end of
171
+ // each line once the text is split on "\n" and would otherwise be swallowed by
172
+ // the value group and dropped on replace, leaving one lone LF line in a CRLF
173
+ // manifest.
174
+ function assignmentPattern(key: string): RegExp {
175
+ return new RegExp(`^(\\s*${key}\\s*=)(.*?)(\\r?)$`);
176
+ }
177
+
178
+ /**
179
+ * The RAW right-hand side of `key` inside `[table]`, comment stripped, or null
180
+ * when the table or the key is not written in that plain form.
181
+ *
182
+ * Callers need the literal, not the parsed value, when TOML's type distinctions
183
+ * survive in Python and not in JavaScript: `version = 1.0` is a float to
184
+ * `tomllib` (and rejected by the data plane) but an indistinguishable `1` once
185
+ * `@iarna/toml` has handed it back as a JS number.
186
+ */
187
+ export function tableScalarLiteral(src: string, table: string, key: string): string | null {
188
+ const lines = src.split("\n");
189
+ const region = tableRegion(lines, table);
190
+ if (!region) return null;
191
+ const assignment = assignmentPattern(key);
192
+ for (let i = region.start + 1; i < region.end; i++) {
193
+ const match = lines[i].match(assignment);
194
+ if (match) return match[2].replace(/\s+#.*$/, "").trim();
195
+ }
196
+ return null;
197
+ }
198
+
199
+ // The same surgical edit as patchScalar, but scoped to ONE [table]: replace the
200
+ // key in place if the table already has it, else append it as the table's last
201
+ // key. `patchScalar` cannot do this - it deliberately stops at the first table
202
+ // header to keep top-level keys top-level.
203
+ //
204
+ // `table` and `key` are always literals we control ("genui", "bundle_sha256").
205
+ export function patchTableScalar(
206
+ src: string,
207
+ table: string,
208
+ key: string,
209
+ literal: string,
210
+ ): string {
211
+ const lines = src.split("\n");
212
+ const region = tableRegion(lines, table);
213
+ if (!region) throw new Error(`No [${table}] table to patch.`);
214
+ const { start, end } = region;
215
+
216
+ const assignment = assignmentPattern(key);
217
+ for (let i = start + 1; i < end; i++) {
218
+ if (assignment.test(lines[i])) {
219
+ lines[i] = lines[i].replace(assignment, `$1 ${literal}$3`);
220
+ return lines.join("\n");
221
+ }
222
+ }
223
+ // Not present: insert straight after the table's last real line. Trailing
224
+ // blanks and comments are skipped because they usually introduce the NEXT
225
+ // table (`# --- Environment ---` above `[env]`), and a key wedged in there
226
+ // reads as if it belonged to that section.
227
+ let insert = end;
228
+ while (insert > start + 1) {
229
+ const previous = lines[insert - 1].trim();
230
+ if (previous !== "" && !previous.startsWith("#")) break;
231
+ insert--;
232
+ }
233
+ const eol = src.includes("\r\n") ? "\r" : "";
234
+ lines.splice(insert, 0, `${key} = ${literal}${eol}`);
235
+ return lines.join("\n");
236
+ }
237
+
238
+ // Record a freshly built RFC 0056 component bundle's digest in [genui],
239
+ // preserving the manifest's comments and every other table. Round-trips through
240
+ // the parser and re-reads the value, so an exotic layout that patchTableScalar
241
+ // cannot edit correctly fails here instead of writing a manifest whose digest
242
+ // silently does not match the bundle.
243
+ export function setGenuiBundleSha256(src: string, digest: string): string {
244
+ const out = patchTableScalar(src, "genui", "bundle_sha256", JSON.stringify(digest));
245
+ const parsed = TOML.parse(out) as Record<string, unknown>; // throws on an invalid result
246
+ const genui = parsed.genui as Record<string, unknown> | undefined;
247
+ if (!genui || genui.bundle_sha256 !== digest) {
248
+ throw new Error(
249
+ "Could not record bundle_sha256 in the [genui] table of dharta.toml. " +
250
+ `Set \`bundle_sha256 = "${digest}"\` there by hand.`,
251
+ );
252
+ }
253
+ return out;
254
+ }
255
+
122
256
  function hasTopLevelScalar(src: string, key: string): boolean {
123
257
  const tbl = src.search(/^\s*\[/m);
124
258
  const top = tbl >= 0 ? src.slice(0, tbl) : src;
@@ -0,0 +1,173 @@
1
+ import { spawnSync } from "node:child_process";
2
+ import { createRequire } from "node:module";
3
+ import type { ModelAuthCapability, ModelAuthReason } from "@dharta/contracts";
4
+ import type { ModelConnectionProvider } from "@dharta/sdk";
5
+
6
+ const require = createRequire(import.meta.url);
7
+ const catalog = require("@dharta/contracts/model-auth-capabilities-v1.json") as {
8
+ capabilities: ModelAuthCapability[];
9
+ };
10
+ const reasonCatalog = require("@dharta/contracts/model-auth-reasons-v1.json") as {
11
+ reasons: ModelAuthReason[];
12
+ };
13
+
14
+ export const MODEL_AUTH_MISSING = modelAuthReason("model_auth_missing");
15
+ export const MODEL_AUTH_CAPABILITY_DISABLED = modelAuthReason("model_auth_capability_disabled");
16
+
17
+ export const DEV_MODEL_AUTH_VALUES = ["api-key", "claude"] as const;
18
+ export type DevModelAuth = (typeof DEV_MODEL_AUTH_VALUES)[number];
19
+
20
+ export const MODEL_CONNECTION_PROVIDERS = catalog.capabilities
21
+ .filter((capability) => capability.admission === "enabled" && capability.credential_kind === "api_key")
22
+ .map((capability) => capability.provider) as ModelConnectionProvider[];
23
+
24
+ const CAPABILITY_IDS: Record<DevModelAuth, string> = {
25
+ "api-key": "anthropic_api_key",
26
+ claude: "anthropic_claude_local_subscription",
27
+ };
28
+
29
+ export interface ClaudeAuthStatus {
30
+ installed: boolean;
31
+ authenticated: boolean;
32
+ detail?: string;
33
+ }
34
+
35
+ export interface CommandStatus {
36
+ status: number | null;
37
+ stdout?: string;
38
+ stderr?: string;
39
+ error?: Error;
40
+ }
41
+
42
+ export type RunCommandStatus = (command: string, args: string[], env: NodeJS.ProcessEnv) => CommandStatus;
43
+
44
+ const COPIED_PROVIDER_CREDENTIALS = ["ANTHROPIC_API_KEY", "ANTHROPIC_AUTH_TOKEN", "CLAUDE_CODE_OAUTH_TOKEN"] as const;
45
+
46
+ function withoutCopiedProviderCredentials(env: NodeJS.ProcessEnv): NodeJS.ProcessEnv {
47
+ const clean = { ...env };
48
+ for (const name of COPIED_PROVIDER_CREDENTIALS) delete clean[name];
49
+ return clean;
50
+ }
51
+
52
+ const runCommandStatus: RunCommandStatus = (command, args, env) => {
53
+ const result = spawnSync(command, args, { encoding: "utf8", env });
54
+ return {
55
+ status: result.status,
56
+ stdout: result.stdout,
57
+ stderr: result.stderr,
58
+ error: result.error,
59
+ };
60
+ };
61
+
62
+ export function checkClaudeAuth(
63
+ env: NodeJS.ProcessEnv = process.env,
64
+ run: RunCommandStatus = runCommandStatus,
65
+ ): ClaudeAuthStatus {
66
+ const result = run("claude", ["auth", "status"], withoutCopiedProviderCredentials(env));
67
+ if (result.error && (result.error as NodeJS.ErrnoException).code === "ENOENT") {
68
+ return { installed: false, authenticated: false, detail: "Claude client is not installed or is not on PATH." };
69
+ }
70
+ const detail = (result.stderr || result.stdout || result.error?.message || "").trim() || undefined;
71
+ return { installed: true, authenticated: result.status === 0, detail };
72
+ }
73
+
74
+ export interface ResolvedDevModelAuth {
75
+ selection: DevModelAuth;
76
+ capability: ModelAuthCapability;
77
+ env: NodeJS.ProcessEnv;
78
+ }
79
+
80
+ export function resolveDevModelAuth(
81
+ requested: DevModelAuth | undefined,
82
+ env: NodeJS.ProcessEnv = process.env,
83
+ run: RunCommandStatus = runCommandStatus,
84
+ ): ResolvedDevModelAuth {
85
+ const claude = requested === "api-key"
86
+ ? { installed: false, authenticated: false }
87
+ : checkClaudeAuth(env, run);
88
+ const apiKeyCapability = capabilityFor("api-key");
89
+ const claudeCapability = capabilityFor("claude");
90
+ const apiKeyPresent = Boolean(env.ANTHROPIC_API_KEY?.trim());
91
+ const apiKeyAvailable = apiKeyPresent && capabilityEnabled(apiKeyCapability, env);
92
+ const claudeAvailable = claude.authenticated && capabilityEnabled(claudeCapability, env);
93
+
94
+ let selection = requested;
95
+ if (!selection) {
96
+ const available: DevModelAuth[] = [];
97
+ if (apiKeyAvailable) available.push("api-key");
98
+ if (claudeAvailable) available.push("claude");
99
+ if (available.length > 1) {
100
+ throw new Error("Multiple Anthropic model authentication methods are ready. Choose one with `dharta dev --model-auth api-key` or `dharta dev --model-auth claude`.");
101
+ }
102
+ selection = available[0];
103
+ }
104
+
105
+ if (!selection) {
106
+ throw new Error(
107
+ `${MODEL_AUTH_MISSING}: No Anthropic model authentication is ready. Export ANTHROPIC_API_KEY and use \`--model-auth api-key\`, ` +
108
+ "or run `claude auth login` and use `--model-auth claude`.",
109
+ );
110
+ }
111
+ if (selection === "api-key" && !apiKeyPresent) {
112
+ throw new Error(`${MODEL_AUTH_MISSING}: \`--model-auth api-key\` requires ANTHROPIC_API_KEY in the dev environment.`);
113
+ }
114
+ if (selection === "claude" && !claude.authenticated) {
115
+ const prefix = claude.installed ? "Claude is not logged in." : "Claude client is not available.";
116
+ throw new Error(`${MODEL_AUTH_MISSING}: ${prefix} Run \`claude auth login\`, then retry \`dharta dev --model-auth claude\`.`);
117
+ }
118
+
119
+ const capability = selection === "api-key" ? apiKeyCapability : claudeCapability;
120
+ if (!capabilityEnabled(capability, env)) {
121
+ throw new Error(
122
+ `Model authentication capability ${capability.id} is disabled (${MODEL_AUTH_CAPABILITY_DISABLED}). ` +
123
+ `provider=${capability.provider}; credential-kind=${capability.credential_kind}; ` +
124
+ `funding=${capability.funding_source}; scope=${capability.execution_scopes.join(",") || "none"}.`,
125
+ );
126
+ }
127
+
128
+ const childEnv = { ...env };
129
+ delete childEnv.ANTHROPIC_AUTH_TOKEN;
130
+ delete childEnv.CLAUDE_CODE_OAUTH_TOKEN;
131
+ if (selection === "claude") delete childEnv.ANTHROPIC_API_KEY;
132
+ return { selection, capability, env: childEnv };
133
+ }
134
+
135
+ function capabilityEnabled(
136
+ capability: ModelAuthCapability,
137
+ env: NodeJS.ProcessEnv,
138
+ ): boolean {
139
+ return capability.admission === "enabled" && runtimeSwitchOpen(capability, env);
140
+ }
141
+
142
+ export function capabilityFor(selection: DevModelAuth): ModelAuthCapability {
143
+ const id = CAPABILITY_IDS[selection];
144
+ const capability = catalog.capabilities.find((entry) => entry.id === id);
145
+ if (!capability) throw new Error(`Model authentication catalog is missing capability ${id}.`);
146
+ return capability;
147
+ }
148
+
149
+ export function runtimeSwitchOpen(
150
+ capability: ModelAuthCapability,
151
+ env: NodeJS.ProcessEnv = process.env,
152
+ ): boolean {
153
+ const key = `DHARTA_MODEL_AUTH_${capability.runtime_switch.toUpperCase()}_ENABLED`;
154
+ const raw = env[key];
155
+ if (raw === undefined) return true;
156
+ const value = raw.trim().toLowerCase();
157
+ if (["1", "true", "yes", "on"].includes(value)) return true;
158
+ if (["0", "false", "no", "off"].includes(value)) return false;
159
+ throw new Error(`${key} must be true or false.`);
160
+ }
161
+
162
+ function modelAuthReason(code: string): string {
163
+ const reason = reasonCatalog.reasons.find((entry) => entry.code === code);
164
+ if (!reason) throw new Error(`Model authentication reason catalog is missing ${code}.`);
165
+ return reason.code;
166
+ }
167
+
168
+ export function formatModelAuthCapability(capability: ModelAuthCapability): string {
169
+ return (
170
+ `provider=${capability.provider}; credential-kind=${capability.credential_kind}; ` +
171
+ `funding=${capability.funding_source}; scope=${capability.execution_scopes.join(",") || "none"}`
172
+ );
173
+ }