@dharta/cli 0.6.77
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +167 -0
- package/dist/agent.d.ts +17 -0
- package/dist/agent.js +134 -0
- package/dist/agent.js.map +1 -0
- package/dist/api-error.d.ts +3 -0
- package/dist/api-error.js +80 -0
- package/dist/api-error.js.map +1 -0
- package/dist/browser.d.ts +1 -0
- package/dist/browser.js +19 -0
- package/dist/browser.js.map +1 -0
- package/dist/cli.d.ts +5 -0
- package/dist/cli.js +1978 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/agents.d.ts +131 -0
- package/dist/commands/agents.js +439 -0
- package/dist/commands/agents.js.map +1 -0
- package/dist/commands/analytics.d.ts +25 -0
- package/dist/commands/analytics.js +166 -0
- package/dist/commands/analytics.js.map +1 -0
- package/dist/commands/api.d.ts +19 -0
- package/dist/commands/api.js +278 -0
- package/dist/commands/api.js.map +1 -0
- package/dist/commands/appearance.d.ts +19 -0
- package/dist/commands/appearance.js +63 -0
- package/dist/commands/appearance.js.map +1 -0
- package/dist/commands/artifact.d.ts +33 -0
- package/dist/commands/artifact.js +235 -0
- package/dist/commands/artifact.js.map +1 -0
- package/dist/commands/audit-log.d.ts +32 -0
- package/dist/commands/audit-log.js +102 -0
- package/dist/commands/audit-log.js.map +1 -0
- package/dist/commands/auth.d.ts +47 -0
- package/dist/commands/auth.js +117 -0
- package/dist/commands/auth.js.map +1 -0
- package/dist/commands/caps.d.ts +82 -0
- package/dist/commands/caps.js +213 -0
- package/dist/commands/caps.js.map +1 -0
- package/dist/commands/create.d.ts +22 -0
- package/dist/commands/create.js +76 -0
- package/dist/commands/create.js.map +1 -0
- package/dist/commands/deploy.d.ts +45 -0
- package/dist/commands/deploy.js +892 -0
- package/dist/commands/deploy.js.map +1 -0
- package/dist/commands/dev.d.ts +33 -0
- package/dist/commands/dev.js +655 -0
- package/dist/commands/dev.js.map +1 -0
- package/dist/commands/directories.d.ts +60 -0
- package/dist/commands/directories.js +83 -0
- package/dist/commands/directories.js.map +1 -0
- package/dist/commands/doctor.d.ts +13 -0
- package/dist/commands/doctor.js +123 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/commands/embed-keys.d.ts +61 -0
- package/dist/commands/embed-keys.js +165 -0
- package/dist/commands/embed-keys.js.map +1 -0
- package/dist/commands/env.d.ts +59 -0
- package/dist/commands/env.js +300 -0
- package/dist/commands/env.js.map +1 -0
- package/dist/commands/files.d.ts +14 -0
- package/dist/commands/files.js +84 -0
- package/dist/commands/files.js.map +1 -0
- package/dist/commands/git-credential.d.ts +1 -0
- package/dist/commands/git-credential.js +70 -0
- package/dist/commands/git-credential.js.map +1 -0
- package/dist/commands/kartas.d.ts +101 -0
- package/dist/commands/kartas.js +289 -0
- package/dist/commands/kartas.js.map +1 -0
- package/dist/commands/keys.d.ts +33 -0
- package/dist/commands/keys.js +141 -0
- package/dist/commands/keys.js.map +1 -0
- package/dist/commands/login.d.ts +22 -0
- package/dist/commands/login.js +78 -0
- package/dist/commands/login.js.map +1 -0
- package/dist/commands/logs.d.ts +14 -0
- package/dist/commands/logs.js +89 -0
- package/dist/commands/logs.js.map +1 -0
- package/dist/commands/members.d.ts +32 -0
- package/dist/commands/members.js +77 -0
- package/dist/commands/members.js.map +1 -0
- package/dist/commands/model-keys.d.ts +22 -0
- package/dist/commands/model-keys.js +222 -0
- package/dist/commands/model-keys.js.map +1 -0
- package/dist/commands/open.d.ts +29 -0
- package/dist/commands/open.js +119 -0
- package/dist/commands/open.js.map +1 -0
- package/dist/commands/parity.d.ts +15 -0
- package/dist/commands/parity.js +73 -0
- package/dist/commands/parity.js.map +1 -0
- package/dist/commands/rollback.d.ts +21 -0
- package/dist/commands/rollback.js +26 -0
- package/dist/commands/rollback.js.map +1 -0
- package/dist/commands/schedules.d.ts +52 -0
- package/dist/commands/schedules.js +231 -0
- package/dist/commands/schedules.js.map +1 -0
- package/dist/commands/scopes.d.ts +3 -0
- package/dist/commands/scopes.js +21 -0
- package/dist/commands/scopes.js.map +1 -0
- package/dist/commands/sessions.d.ts +53 -0
- package/dist/commands/sessions.js +142 -0
- package/dist/commands/sessions.js.map +1 -0
- package/dist/commands/setup.d.ts +28 -0
- package/dist/commands/setup.js +949 -0
- package/dist/commands/setup.js.map +1 -0
- package/dist/commands/status.d.ts +19 -0
- package/dist/commands/status.js +63 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/commands/update.d.ts +14 -0
- package/dist/commands/update.js +120 -0
- package/dist/commands/update.js.map +1 -0
- package/dist/commands/usage.d.ts +3 -0
- package/dist/commands/usage.js +37 -0
- package/dist/commands/usage.js.map +1 -0
- package/dist/commands/webhooks.d.ts +47 -0
- package/dist/commands/webhooks.js +156 -0
- package/dist/commands/webhooks.js.map +1 -0
- package/dist/commands/whoami.d.ts +7 -0
- package/dist/commands/whoami.js +17 -0
- package/dist/commands/whoami.js.map +1 -0
- package/dist/completions.d.ts +13 -0
- package/dist/completions.js +120 -0
- package/dist/completions.js.map +1 -0
- package/dist/config.d.ts +20 -0
- package/dist/config.js +98 -0
- package/dist/config.js.map +1 -0
- package/dist/context.d.ts +14 -0
- package/dist/context.js +38 -0
- package/dist/context.js.map +1 -0
- package/dist/device-flow.d.ts +9 -0
- package/dist/device-flow.js +127 -0
- package/dist/device-flow.js.map +1 -0
- package/dist/harness-preflight.d.ts +24 -0
- package/dist/harness-preflight.js +252 -0
- package/dist/harness-preflight.js.map +1 -0
- package/dist/harnesses.d.ts +11 -0
- package/dist/harnesses.js +112 -0
- package/dist/harnesses.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -0
- package/dist/login-offer.d.ts +9 -0
- package/dist/login-offer.js +36 -0
- package/dist/login-offer.js.map +1 -0
- package/dist/manifest.d.ts +15 -0
- package/dist/manifest.js +142 -0
- package/dist/manifest.js.map +1 -0
- package/dist/money.d.ts +1 -0
- package/dist/money.js +16 -0
- package/dist/money.js.map +1 -0
- package/dist/output.d.ts +2 -0
- package/dist/output.js +20 -0
- package/dist/output.js.map +1 -0
- package/dist/runtime.d.ts +19 -0
- package/dist/runtime.js +95 -0
- package/dist/runtime.js.map +1 -0
- package/dist/scaffold.d.ts +16 -0
- package/dist/scaffold.js +74 -0
- package/dist/scaffold.js.map +1 -0
- package/dist/setup-scan.d.ts +21 -0
- package/dist/setup-scan.js +127 -0
- package/dist/setup-scan.js.map +1 -0
- package/dist/templates.d.ts +14 -0
- package/dist/templates.js +65 -0
- package/dist/templates.js.map +1 -0
- package/dist/validators.d.ts +10 -0
- package/dist/validators.js +116 -0
- package/dist/validators.js.map +1 -0
- package/dist/version-check.d.ts +25 -0
- package/dist/version-check.js +68 -0
- package/dist/version-check.js.map +1 -0
- package/node_modules/@dharta/sdk/LICENSE +21 -0
- package/node_modules/@dharta/sdk/README.md +87 -0
- package/node_modules/@dharta/sdk/dist/errors.d.ts +20 -0
- package/node_modules/@dharta/sdk/dist/errors.d.ts.map +1 -0
- package/node_modules/@dharta/sdk/dist/errors.js +51 -0
- package/node_modules/@dharta/sdk/dist/errors.js.map +1 -0
- package/node_modules/@dharta/sdk/dist/http.d.ts +26 -0
- package/node_modules/@dharta/sdk/dist/http.d.ts.map +1 -0
- package/node_modules/@dharta/sdk/dist/http.js +136 -0
- package/node_modules/@dharta/sdk/dist/http.js.map +1 -0
- package/node_modules/@dharta/sdk/dist/index.d.ts +15 -0
- package/node_modules/@dharta/sdk/dist/index.d.ts.map +1 -0
- package/node_modules/@dharta/sdk/dist/index.js +21 -0
- package/node_modules/@dharta/sdk/dist/index.js.map +1 -0
- package/node_modules/@dharta/sdk/dist/resources.d.ts +48 -0
- package/node_modules/@dharta/sdk/dist/resources.d.ts.map +1 -0
- package/node_modules/@dharta/sdk/dist/resources.js +150 -0
- package/node_modules/@dharta/sdk/dist/resources.js.map +1 -0
- package/node_modules/@dharta/sdk/dist/types.d.ts +94 -0
- package/node_modules/@dharta/sdk/dist/types.d.ts.map +1 -0
- package/node_modules/@dharta/sdk/dist/types.js +59 -0
- package/node_modules/@dharta/sdk/dist/types.js.map +1 -0
- package/node_modules/@dharta/sdk/package.json +32 -0
- package/node_modules/@dharta/sdk/src/errors.ts +58 -0
- package/node_modules/@dharta/sdk/src/http.ts +166 -0
- package/node_modules/@dharta/sdk/src/index.ts +36 -0
- package/node_modules/@dharta/sdk/src/resources.ts +197 -0
- package/node_modules/@dharta/sdk/src/types.ts +179 -0
- package/package.json +38 -0
- package/src/agent.ts +147 -0
- package/src/api-error.ts +88 -0
- package/src/browser.ts +20 -0
- package/src/cli.ts +2339 -0
- package/src/commands/agents.ts +635 -0
- package/src/commands/analytics.ts +181 -0
- package/src/commands/api.ts +297 -0
- package/src/commands/appearance.ts +79 -0
- package/src/commands/artifact.ts +331 -0
- package/src/commands/audit-log.ts +125 -0
- package/src/commands/auth.ts +186 -0
- package/src/commands/caps.ts +302 -0
- package/src/commands/create.ts +114 -0
- package/src/commands/deploy.ts +1122 -0
- package/src/commands/dev.ts +792 -0
- package/src/commands/directories.ts +136 -0
- package/src/commands/doctor.ts +138 -0
- package/src/commands/embed-keys.ts +237 -0
- package/src/commands/env.ts +369 -0
- package/src/commands/files.ts +124 -0
- package/src/commands/git-credential.ts +78 -0
- package/src/commands/kartas.ts +439 -0
- package/src/commands/keys.ts +206 -0
- package/src/commands/login.ts +115 -0
- package/src/commands/logs.ts +111 -0
- package/src/commands/members.ts +109 -0
- package/src/commands/model-keys.ts +278 -0
- package/src/commands/open.ts +173 -0
- package/src/commands/parity.ts +96 -0
- package/src/commands/rollback.ts +45 -0
- package/src/commands/schedules.ts +290 -0
- package/src/commands/scopes.ts +22 -0
- package/src/commands/sessions.ts +225 -0
- package/src/commands/setup.ts +1176 -0
- package/src/commands/status.ts +94 -0
- package/src/commands/update.ts +157 -0
- package/src/commands/usage.ts +41 -0
- package/src/commands/webhooks.ts +200 -0
- package/src/commands/whoami.ts +24 -0
- package/src/completions.ts +168 -0
- package/src/config.ts +143 -0
- package/src/context.ts +59 -0
- package/src/device-flow.ts +174 -0
- package/src/harness-preflight.ts +293 -0
- package/src/harnesses.ts +117 -0
- package/src/index.ts +3 -0
- package/src/login-offer.ts +49 -0
- package/src/manifest.ts +153 -0
- package/src/money.ts +15 -0
- package/src/output.ts +22 -0
- package/src/runtime.ts +127 -0
- package/src/scaffold.ts +102 -0
- package/src/setup-scan.ts +154 -0
- package/src/templates.ts +85 -0
- package/src/validators.ts +124 -0
- package/src/version-check.ts +75 -0
- package/templates/blank/CLAUDE.md +21 -0
- package/templates/blank/dharta.toml +11 -0
- package/templates/faq-agent/CLAUDE.md +51 -0
- package/templates/faq-agent/dharta.toml +11 -0
|
@@ -0,0 +1,300 @@
|
|
|
1
|
+
// `dharta env list|set|unset|pull|diff` (RFC 0013 CLI-8): the prod half
|
|
2
|
+
// of declare-or-bind. Declarations live in dharta.toml [env]; .env binds
|
|
3
|
+
// locally; these verbs manage the prod bindings and report drift.
|
|
4
|
+
import { promises as fs } from "node:fs";
|
|
5
|
+
import * as path from "node:path";
|
|
6
|
+
import { randomUUID } from "node:crypto";
|
|
7
|
+
import TOML from "@iarna/toml";
|
|
8
|
+
import { inferAgentSlug, validateAgentSelectorOptions } from "../agent.js";
|
|
9
|
+
import { table } from "../output.js";
|
|
10
|
+
import { normalizeNonBlank } from "../validators.js";
|
|
11
|
+
// Env values routinely hold credentials the setter never flagged `--secret`
|
|
12
|
+
// (a GitHub PAT, a webhook signing key). `list` therefore masks EVERY value by
|
|
13
|
+
// default - a routine listing must never dump a live secret to the terminal or
|
|
14
|
+
// CI logs. A short tail is kept so an operator can still tell two bindings
|
|
15
|
+
// apart (matching how `whoami`/model keys show only a tail); `--reveal` prints
|
|
16
|
+
// the full value for the rare time it is actually needed.
|
|
17
|
+
export function maskEnvValue(v, reveal) {
|
|
18
|
+
if (reveal)
|
|
19
|
+
return v.value ?? "";
|
|
20
|
+
if (v.secret)
|
|
21
|
+
return "•••••• (secret)";
|
|
22
|
+
const val = v.value ?? "";
|
|
23
|
+
if (val === "")
|
|
24
|
+
return "";
|
|
25
|
+
return val.length > 4 ? `…${val.slice(-4)}` : "••••";
|
|
26
|
+
}
|
|
27
|
+
export async function envListData(ctx, opts = {}) {
|
|
28
|
+
const slug = await inferAgentSlug(opts);
|
|
29
|
+
const body = await ctx.http.request({
|
|
30
|
+
path: `/api/agents/${encodeURIComponent(slug)}/env`,
|
|
31
|
+
});
|
|
32
|
+
return { slug, env: body.env };
|
|
33
|
+
}
|
|
34
|
+
export async function envList(ctx, opts = {}) {
|
|
35
|
+
const { slug, env } = await envListData(ctx, opts);
|
|
36
|
+
if (env.length === 0) {
|
|
37
|
+
return `No env vars set for ${slug}. Bind one with: dharta env set NAME=value`;
|
|
38
|
+
}
|
|
39
|
+
return table(env.map((v) => ({
|
|
40
|
+
name: v.name,
|
|
41
|
+
value: maskEnvValue(v, opts.reveal === true),
|
|
42
|
+
updated: v.updated_at ?? "",
|
|
43
|
+
})));
|
|
44
|
+
}
|
|
45
|
+
export async function envSetData(ctx, assignment, opts = {}) {
|
|
46
|
+
const { name, value } = parseEnvAssignment(assignment);
|
|
47
|
+
const slug = await inferAgentSlug(opts);
|
|
48
|
+
const body = { value };
|
|
49
|
+
if (opts.secret)
|
|
50
|
+
body.secret = true;
|
|
51
|
+
await ctx.http.request({
|
|
52
|
+
method: "PUT",
|
|
53
|
+
path: `/api/agents/${encodeURIComponent(slug)}/env/${encodeURIComponent(name)}`,
|
|
54
|
+
body,
|
|
55
|
+
headers: { "Idempotency-Key": randomUUID() },
|
|
56
|
+
});
|
|
57
|
+
return { slug, name, secret: !!opts.secret };
|
|
58
|
+
}
|
|
59
|
+
export function validateEnvAssignment(assignment) {
|
|
60
|
+
parseEnvAssignment(assignment);
|
|
61
|
+
}
|
|
62
|
+
export function validateEnvName(name) {
|
|
63
|
+
normalizeEnvName(name);
|
|
64
|
+
}
|
|
65
|
+
function parseEnvAssignment(assignment) {
|
|
66
|
+
const eq = assignment.indexOf("=");
|
|
67
|
+
if (eq <= 0) {
|
|
68
|
+
throw new Error("Usage: dharta env set NAME=value [--secret]");
|
|
69
|
+
}
|
|
70
|
+
const name = normalizeEnvName(assignment.slice(0, eq));
|
|
71
|
+
const value = assignment.slice(eq + 1);
|
|
72
|
+
return { name, value };
|
|
73
|
+
}
|
|
74
|
+
export async function envSet(ctx, assignment, opts = {}) {
|
|
75
|
+
const { slug, name, secret } = await envSetData(ctx, assignment, opts);
|
|
76
|
+
return (`Set ${name}${secret ? " (secret)" : ""} on ${slug}. ` +
|
|
77
|
+
"The next build picks it up; redeploy with git push dharta main if needed.");
|
|
78
|
+
}
|
|
79
|
+
export async function envUnsetData(ctx, name, opts = {}) {
|
|
80
|
+
const normalizedName = normalizeEnvName(name);
|
|
81
|
+
const slug = await inferAgentSlug(opts);
|
|
82
|
+
await ctx.http.request({
|
|
83
|
+
method: "DELETE",
|
|
84
|
+
path: `/api/agents/${encodeURIComponent(slug)}/env/${encodeURIComponent(normalizedName)}`,
|
|
85
|
+
headers: { "Idempotency-Key": randomUUID() },
|
|
86
|
+
});
|
|
87
|
+
return { slug, name: normalizedName, removed: true };
|
|
88
|
+
}
|
|
89
|
+
export async function envUnset(ctx, name, opts = {}) {
|
|
90
|
+
const { slug, name: removed } = await envUnsetData(ctx, name, opts);
|
|
91
|
+
return `Removed ${removed} from ${slug}.`;
|
|
92
|
+
}
|
|
93
|
+
// Hydrate .env from prod (D6): secret-marked values are excluded unless
|
|
94
|
+
// --include-secrets (bounded env:secrets:read key);
|
|
95
|
+
// every pull is audited server-side.
|
|
96
|
+
export async function envPullData(ctx, opts = {}) {
|
|
97
|
+
const dir = path.resolve(opts.dir ?? process.cwd());
|
|
98
|
+
const target = path.join(dir, ".env");
|
|
99
|
+
await validateEnvPullOptions(opts);
|
|
100
|
+
const slug = await inferAgentSlug(opts);
|
|
101
|
+
const body = await ctx.http.request({
|
|
102
|
+
method: "POST",
|
|
103
|
+
path: `/api/agents/${encodeURIComponent(slug)}/env/pull`,
|
|
104
|
+
body: { include_secrets: !!opts.includeSecrets },
|
|
105
|
+
headers: { "Idempotency-Key": randomUUID() },
|
|
106
|
+
});
|
|
107
|
+
const bound = body.env.filter((v) => !v.withheld);
|
|
108
|
+
const lines = bound.map((v) => `${v.name}=${quoteIfNeeded(v.value ?? "")}`);
|
|
109
|
+
const withheld = body.env.filter((v) => v.withheld).map((v) => v.name);
|
|
110
|
+
await writeEnvFile(target, `# Pulled from ${slug} by dharta env pull - do not commit.\n${lines.join("\n")}\n`);
|
|
111
|
+
return { slug, path: target, written: bound.map((v) => v.name), withheld };
|
|
112
|
+
}
|
|
113
|
+
export async function envPull(ctx, opts = {}) {
|
|
114
|
+
const res = await envPullData(ctx, opts);
|
|
115
|
+
const n = res.written.length;
|
|
116
|
+
let out = `Wrote ${n} value${n === 1 ? "" : "s"} to ${res.path}.`;
|
|
117
|
+
if (res.withheld.length > 0) {
|
|
118
|
+
out +=
|
|
119
|
+
`\n${res.withheld.length} secret value${res.withheld.length === 1 ? "" : "s"} withheld (${res.withheld.join(", ")}). ` +
|
|
120
|
+
"Re-run with --include-secrets using a key with env:secrets:read to fetch them (audited).";
|
|
121
|
+
}
|
|
122
|
+
return out;
|
|
123
|
+
}
|
|
124
|
+
// Local (.env) vs prod drift, plus the dharta.toml [env] declarations -
|
|
125
|
+
// the report half of declare-or-bind (dev warns, build fails, diff
|
|
126
|
+
// explains).
|
|
127
|
+
export async function envDiffData(ctx, opts = {}) {
|
|
128
|
+
const dir = path.resolve(opts.dir ?? process.cwd());
|
|
129
|
+
await validateEnvDiffOptions(opts);
|
|
130
|
+
const slug = await inferAgentSlug(opts);
|
|
131
|
+
const local = parseDotenvFile(await readOptionalLocalFile(path.join(dir, ".env"), ".env"));
|
|
132
|
+
const declared = await declaredEnvNames(dir);
|
|
133
|
+
const body = await ctx.http.request({
|
|
134
|
+
path: `/api/agents/${encodeURIComponent(slug)}/env`,
|
|
135
|
+
});
|
|
136
|
+
const prod = new Map(body.env.map((v) => [v.name, v]));
|
|
137
|
+
const drift = [];
|
|
138
|
+
for (const [name, entry] of prod) {
|
|
139
|
+
if (!(name in local)) {
|
|
140
|
+
drift.push({ kind: "prod-only", name, secret: entry.secret });
|
|
141
|
+
}
|
|
142
|
+
else if (!entry.secret && entry.value !== local[name]) {
|
|
143
|
+
drift.push({ kind: "value-differs", name });
|
|
144
|
+
}
|
|
145
|
+
else if (entry.secret) {
|
|
146
|
+
drift.push({ kind: "secret", name, secret: true });
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
for (const name of Object.keys(local)) {
|
|
150
|
+
if (!prod.has(name))
|
|
151
|
+
drift.push({ kind: "local-only", name });
|
|
152
|
+
}
|
|
153
|
+
for (const name of declared) {
|
|
154
|
+
if (!prod.has(name) && !(name in local))
|
|
155
|
+
drift.push({ kind: "declared-only", name });
|
|
156
|
+
}
|
|
157
|
+
return { slug, drift };
|
|
158
|
+
}
|
|
159
|
+
export async function envDiff(ctx, opts = {}) {
|
|
160
|
+
const { slug, drift } = await envDiffData(ctx, opts);
|
|
161
|
+
if (drift.length === 0)
|
|
162
|
+
return `No drift: .env and ${slug}'s prod bindings agree.`;
|
|
163
|
+
return drift.map(formatDrift).join("\n");
|
|
164
|
+
}
|
|
165
|
+
function formatDrift(d) {
|
|
166
|
+
switch (d.kind) {
|
|
167
|
+
case "prod-only":
|
|
168
|
+
return `prod only ${d.name}${d.secret ? " (secret)" : ""} - add to .env (dharta env pull)`;
|
|
169
|
+
case "value-differs":
|
|
170
|
+
return `value differs ${d.name} - local .env and prod disagree`;
|
|
171
|
+
case "secret":
|
|
172
|
+
return `secret ${d.name} - prod value not comparable`;
|
|
173
|
+
case "local-only":
|
|
174
|
+
return `local only ${d.name} - bind in prod with: dharta env set ${d.name}=...`;
|
|
175
|
+
case "declared-only":
|
|
176
|
+
return `declared only ${d.name} - in dharta.toml [env] but bound nowhere`;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
async function declaredEnvNames(dir) {
|
|
180
|
+
const raw = await readOptionalLocalFile(path.join(dir, "dharta.toml"), "dharta.toml");
|
|
181
|
+
if (!raw)
|
|
182
|
+
return [];
|
|
183
|
+
try {
|
|
184
|
+
const parsed = TOML.parse(raw);
|
|
185
|
+
const env = parsed.env;
|
|
186
|
+
return env && typeof env === "object" ? Object.keys(env) : [];
|
|
187
|
+
}
|
|
188
|
+
catch {
|
|
189
|
+
return [];
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
export function parseDotenvFile(content) {
|
|
193
|
+
const vars = {};
|
|
194
|
+
if (!content)
|
|
195
|
+
return vars;
|
|
196
|
+
for (const raw of content.split("\n")) {
|
|
197
|
+
let line = raw.trim();
|
|
198
|
+
if (line.startsWith("export "))
|
|
199
|
+
line = line.slice("export ".length).trim();
|
|
200
|
+
if (!line || line.startsWith("#") || !line.includes("="))
|
|
201
|
+
continue;
|
|
202
|
+
const idx = line.indexOf("=");
|
|
203
|
+
const name = line.slice(0, idx).trim();
|
|
204
|
+
let value = line.slice(idx + 1).trim();
|
|
205
|
+
if (value.length >= 2 && (value[0] === '"' || value[0] === "'") && value.endsWith(value[0])) {
|
|
206
|
+
value = value.slice(1, -1);
|
|
207
|
+
}
|
|
208
|
+
else {
|
|
209
|
+
value = value.split(" #", 1)[0].trim();
|
|
210
|
+
}
|
|
211
|
+
vars[name] = value;
|
|
212
|
+
}
|
|
213
|
+
return vars;
|
|
214
|
+
}
|
|
215
|
+
function quoteIfNeeded(value) {
|
|
216
|
+
return /[\s#"']/.test(value) ? JSON.stringify(value) : value;
|
|
217
|
+
}
|
|
218
|
+
function normalizeEnvName(name) {
|
|
219
|
+
return normalizeNonBlank(name, "env var name");
|
|
220
|
+
}
|
|
221
|
+
export async function validateEnvPullOptions(opts = {}) {
|
|
222
|
+
validateAgentSelectorOptions({ agent: opts.agent, project: opts.project, dir: opts.dir });
|
|
223
|
+
const dir = path.resolve(opts.dir ?? process.cwd());
|
|
224
|
+
await validateEnvPullTarget(dir, path.join(dir, ".env"), !!opts.force);
|
|
225
|
+
}
|
|
226
|
+
export async function validateEnvDiffOptions(opts = {}) {
|
|
227
|
+
validateAgentSelectorOptions({ agent: opts.agent, project: opts.project, dir: opts.dir });
|
|
228
|
+
await validateEnvReadDir(path.resolve(opts.dir ?? process.cwd()));
|
|
229
|
+
}
|
|
230
|
+
async function readOptionalLocalFile(file, label) {
|
|
231
|
+
try {
|
|
232
|
+
return await fs.readFile(file, "utf8");
|
|
233
|
+
}
|
|
234
|
+
catch (error) {
|
|
235
|
+
const code = error.code;
|
|
236
|
+
if (code === "ENOENT")
|
|
237
|
+
return null;
|
|
238
|
+
if (code === "EISDIR")
|
|
239
|
+
throw new Error(`Cannot read ${label} at ${file}: expected a file, got a directory.`);
|
|
240
|
+
throw new Error(`Cannot read ${label} at ${file}: ${error.message}`);
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
async function validateEnvReadDir(dir) {
|
|
244
|
+
let stat;
|
|
245
|
+
try {
|
|
246
|
+
stat = await fs.stat(dir);
|
|
247
|
+
}
|
|
248
|
+
catch (error) {
|
|
249
|
+
const code = error.code;
|
|
250
|
+
if (code === "ENOENT")
|
|
251
|
+
throw new Error(`Cannot read env files in ${dir}: directory does not exist.`);
|
|
252
|
+
throw new Error(`Cannot read env files in ${dir}: ${error.message}`);
|
|
253
|
+
}
|
|
254
|
+
if (!stat.isDirectory()) {
|
|
255
|
+
throw new Error(`Cannot read env files in ${dir}: expected a directory.`);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
async function validateEnvPullTarget(dir, target, force) {
|
|
259
|
+
let dirStat;
|
|
260
|
+
try {
|
|
261
|
+
dirStat = await fs.stat(dir);
|
|
262
|
+
}
|
|
263
|
+
catch (error) {
|
|
264
|
+
const code = error.code;
|
|
265
|
+
if (code === "ENOENT")
|
|
266
|
+
throw new Error(`Cannot write .env in ${dir}: directory does not exist.`);
|
|
267
|
+
throw new Error(`Cannot write .env in ${dir}: ${error.message}`);
|
|
268
|
+
}
|
|
269
|
+
if (!dirStat.isDirectory()) {
|
|
270
|
+
throw new Error(`Cannot write .env in ${dir}: expected a directory.`);
|
|
271
|
+
}
|
|
272
|
+
try {
|
|
273
|
+
const targetStat = await fs.stat(target);
|
|
274
|
+
if (targetStat.isDirectory()) {
|
|
275
|
+
throw new Error(`Cannot write .env to ${target}: expected a file, got a directory.`);
|
|
276
|
+
}
|
|
277
|
+
if (!force) {
|
|
278
|
+
throw new Error(`${target} already exists. Re-run with --force to overwrite it (local-only keys are lost).`);
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
catch (error) {
|
|
282
|
+
if (error.code === "ENOENT")
|
|
283
|
+
return;
|
|
284
|
+
throw error;
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
async function writeEnvFile(target, content) {
|
|
288
|
+
try {
|
|
289
|
+
await fs.writeFile(target, content, { mode: 0o600 });
|
|
290
|
+
}
|
|
291
|
+
catch (error) {
|
|
292
|
+
const code = error.code;
|
|
293
|
+
if (code === "ENOENT")
|
|
294
|
+
throw new Error(`Cannot write .env to ${target}: parent directory does not exist.`);
|
|
295
|
+
if (code === "EISDIR")
|
|
296
|
+
throw new Error(`Cannot write .env to ${target}: expected a file, got a directory.`);
|
|
297
|
+
throw new Error(`Cannot write .env to ${target}: ${error.message}`);
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
//# sourceMappingURL=env.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"env.js","sourceRoot":"","sources":["../../src/commands/env.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { CliContext } from "../context.js";
|
|
2
|
+
export interface WorkspaceEntry {
|
|
3
|
+
path: string;
|
|
4
|
+
kind: string;
|
|
5
|
+
size: number;
|
|
6
|
+
mode: number;
|
|
7
|
+
}
|
|
8
|
+
export interface WorkspaceListing {
|
|
9
|
+
snapshot: string;
|
|
10
|
+
entries: WorkspaceEntry[];
|
|
11
|
+
}
|
|
12
|
+
export declare function filesLsData(ctx: CliContext, agent: string, instance: string): Promise<WorkspaceListing>;
|
|
13
|
+
export declare function filesLs(ctx: CliContext, agent: string, instance: string): Promise<string>;
|
|
14
|
+
export declare function filesGet(ctx: CliContext, agent: string, instance: string, path: string, out?: string): Promise<string | null>;
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { HttpClient } from "@dharta/sdk";
|
|
2
|
+
import { randomUUID } from "node:crypto";
|
|
3
|
+
import { writeFile } from "node:fs/promises";
|
|
4
|
+
import { cliFormatError, cliFormatNetworkError, cliFormatRawError } from "../api-error.js";
|
|
5
|
+
import { table } from "../output.js";
|
|
6
|
+
import { validateAgentSlug } from "../agent.js";
|
|
7
|
+
async function mintFilesToken(ctx, agent, instance) {
|
|
8
|
+
const res = await ctx.http.request({
|
|
9
|
+
method: "POST",
|
|
10
|
+
path: `/api/agents/${encodeURIComponent(agent)}/workspace_tokens`,
|
|
11
|
+
headers: { "Idempotency-Key": randomUUID() },
|
|
12
|
+
body: { instance, scope: "workspace_read" },
|
|
13
|
+
});
|
|
14
|
+
if (!res.token) {
|
|
15
|
+
throw new Error("The Dharta server did not return a workspace token.");
|
|
16
|
+
}
|
|
17
|
+
if (!res.files_url) {
|
|
18
|
+
throw new Error("This Dharta server does not expose the files API (files_url missing). Upgrade the server (RFC 0060).");
|
|
19
|
+
}
|
|
20
|
+
return { token: res.token, files_url: res.files_url };
|
|
21
|
+
}
|
|
22
|
+
// A data-plane HttpClient bound to the files host, authenticated with the minted token.
|
|
23
|
+
// Returns the client plus the base path from `files_url` (`/workspace/<agent>/<karta>`).
|
|
24
|
+
function filesClient(ctx, mint) {
|
|
25
|
+
const url = new URL(mint.files_url);
|
|
26
|
+
const http = new HttpClient({
|
|
27
|
+
apiKey: mint.token,
|
|
28
|
+
baseUrl: url.origin,
|
|
29
|
+
fetch: ctx.fetch,
|
|
30
|
+
formatError: cliFormatError,
|
|
31
|
+
formatNetworkError: cliFormatNetworkError,
|
|
32
|
+
});
|
|
33
|
+
return { http, basePath: url.pathname };
|
|
34
|
+
}
|
|
35
|
+
function normalizeInstance(instance) {
|
|
36
|
+
const trimmed = instance.trim();
|
|
37
|
+
if (!trimmed)
|
|
38
|
+
throw new Error("A dharta id is required.");
|
|
39
|
+
return trimmed;
|
|
40
|
+
}
|
|
41
|
+
export async function filesLsData(ctx, agent, instance) {
|
|
42
|
+
const slug = validateAgentSlug(agent, "agent slug");
|
|
43
|
+
const karta = normalizeInstance(instance);
|
|
44
|
+
const mint = await mintFilesToken(ctx, slug, karta);
|
|
45
|
+
const { http, basePath } = filesClient(ctx, mint);
|
|
46
|
+
const listing = await http.request({ path: basePath });
|
|
47
|
+
return {
|
|
48
|
+
snapshot: typeof listing.snapshot === "string" ? listing.snapshot : "",
|
|
49
|
+
entries: Array.isArray(listing.entries) ? listing.entries : [],
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
export async function filesLs(ctx, agent, instance) {
|
|
53
|
+
const listing = await filesLsData(ctx, agent, instance);
|
|
54
|
+
if (listing.entries.length === 0) {
|
|
55
|
+
return `No files in ${agent}/${instance} (snapshot ${listing.snapshot || "—"}).`;
|
|
56
|
+
}
|
|
57
|
+
const rows = [...listing.entries]
|
|
58
|
+
.sort((a, b) => a.path.localeCompare(b.path))
|
|
59
|
+
.map((e) => ({ path: e.path, size: String(e.size) }));
|
|
60
|
+
return table(rows);
|
|
61
|
+
}
|
|
62
|
+
// Fetch one file's bytes. Writes to `out` (a status line is returned) or, when `out` is
|
|
63
|
+
// omitted, streams the raw bytes to stdout (returns null so nothing else is printed - a
|
|
64
|
+
// trailing newline would corrupt binary output).
|
|
65
|
+
export async function filesGet(ctx, agent, instance, path, out) {
|
|
66
|
+
const slug = validateAgentSlug(agent, "agent slug");
|
|
67
|
+
const karta = normalizeInstance(instance);
|
|
68
|
+
const filePath = path.trim();
|
|
69
|
+
if (!filePath)
|
|
70
|
+
throw new Error("A file path is required.");
|
|
71
|
+
const mint = await mintFilesToken(ctx, slug, karta);
|
|
72
|
+
const { http, basePath } = filesClient(ctx, mint);
|
|
73
|
+
const res = await http.raw(`${basePath}/file?path=${encodeURIComponent(filePath)}`);
|
|
74
|
+
if (!res.ok)
|
|
75
|
+
throw await cliFormatRawError(res);
|
|
76
|
+
const bytes = Buffer.from(await res.arrayBuffer());
|
|
77
|
+
if (out) {
|
|
78
|
+
await writeFile(out, bytes);
|
|
79
|
+
return `Wrote ${bytes.length} bytes to ${out}.`;
|
|
80
|
+
}
|
|
81
|
+
process.stdout.write(bytes);
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
84
|
+
//# sourceMappingURL=files.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"files.js","sourceRoot":"","sources":["../../src/commands/files.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function gitCredential(operation: string, stdin: string): Promise<string>;
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { HttpClient } from "@dharta/sdk";
|
|
2
|
+
import { randomUUID } from "node:crypto";
|
|
3
|
+
import { activeProfile } from "../config.js";
|
|
4
|
+
// `dharta git-credential <operation>` - a git credential helper in the protocol sense,
|
|
5
|
+
// wired by `dharta login` via `credential.<git host>.helper = !dharta git-credential`.
|
|
6
|
+
//
|
|
7
|
+
// Two hosts, two auth models (RFC 0043 D8):
|
|
8
|
+
// - the RFC 0011 PUSH host (git_base_url): answer with the stored API key (the server
|
|
9
|
+
// ignores the username, "dharta" by convention).
|
|
10
|
+
// - the workspace CLONE host (workspace_git_base_url, the DATA PLANE): mint a per-clone
|
|
11
|
+
// read-only token OUT OF BAND (a metadata call to the control plane) and answer with
|
|
12
|
+
// it, so the clone bytes flow only from the data plane and never through the control
|
|
13
|
+
// plane. `dharta login` sets `useHttpPath=true` for this host so git passes the repo
|
|
14
|
+
// path, from which we read the karta id.
|
|
15
|
+
//
|
|
16
|
+
// store/erase are no-ops: the API key already lives in ~/.dharta/config.toml and the
|
|
17
|
+
// minted token is short-lived (git never persists this secret).
|
|
18
|
+
export async function gitCredential(operation, stdin) {
|
|
19
|
+
if (operation !== "get")
|
|
20
|
+
return "";
|
|
21
|
+
const profile = await activeProfile();
|
|
22
|
+
const attrs = new Map();
|
|
23
|
+
for (const line of stdin.split("\n")) {
|
|
24
|
+
const idx = line.indexOf("=");
|
|
25
|
+
if (idx > 0)
|
|
26
|
+
attrs.set(line.slice(0, idx), line.slice(idx + 1));
|
|
27
|
+
}
|
|
28
|
+
const protocol = attrs.get("protocol");
|
|
29
|
+
if (protocol !== "https" && protocol !== "http")
|
|
30
|
+
return "";
|
|
31
|
+
const host = attrs.get("host");
|
|
32
|
+
if (!host)
|
|
33
|
+
return "";
|
|
34
|
+
const wsBase = profile.workspace_git_base_url;
|
|
35
|
+
if (wsBase && host === new URL(wsBase).host) {
|
|
36
|
+
const token = await mintWorkspaceToken(profile, attrs.get("path") ?? "");
|
|
37
|
+
return token ? `username=karta\npassword=${token}\n` : "";
|
|
38
|
+
}
|
|
39
|
+
if (profile.git_base_url && host === new URL(profile.git_base_url).host) {
|
|
40
|
+
return `username=karta\npassword=${profile.api_key}\n`;
|
|
41
|
+
}
|
|
42
|
+
return "";
|
|
43
|
+
}
|
|
44
|
+
// Mint a read-only workspace token for the karta named by the request path. With
|
|
45
|
+
// `useHttpPath=true`, git passes a path like `git/<agent>/<karta>` (no leading slash,
|
|
46
|
+
// possibly with extra segments we ignore). Returns null on any failure - git then falls
|
|
47
|
+
// back to its normal prompt/deny, never a crash.
|
|
48
|
+
async function mintWorkspaceToken(profile, path) {
|
|
49
|
+
const m = path.replace(/^\/+/, "").match(/^git\/([^/]+)\/([^/]+)/);
|
|
50
|
+
if (!m)
|
|
51
|
+
return null;
|
|
52
|
+
const [, agent, instance] = m;
|
|
53
|
+
const http = new HttpClient({
|
|
54
|
+
apiKey: profile.api_key,
|
|
55
|
+
baseUrl: profile.base_url,
|
|
56
|
+
});
|
|
57
|
+
try {
|
|
58
|
+
const res = await http.request({
|
|
59
|
+
method: "POST",
|
|
60
|
+
path: `/api/agents/${encodeURIComponent(agent)}/workspace_tokens`,
|
|
61
|
+
headers: { "Idempotency-Key": randomUUID() },
|
|
62
|
+
body: { instance },
|
|
63
|
+
});
|
|
64
|
+
return res.token ?? null;
|
|
65
|
+
}
|
|
66
|
+
catch {
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=git-credential.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"git-credential.js","sourceRoot":"","sources":["../../src/commands/git-credential.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import type { CliContext } from "../context.js";
|
|
2
|
+
export interface KartaMember {
|
|
3
|
+
id: string | number;
|
|
4
|
+
email: string;
|
|
5
|
+
role: string;
|
|
6
|
+
joined_at: string;
|
|
7
|
+
}
|
|
8
|
+
export interface KartaRecord {
|
|
9
|
+
id: string;
|
|
10
|
+
name: string | null;
|
|
11
|
+
vanity_slug: string | null;
|
|
12
|
+
access_audience: string | null;
|
|
13
|
+
access_model: string;
|
|
14
|
+
state: string;
|
|
15
|
+
agent: {
|
|
16
|
+
id: string | number;
|
|
17
|
+
slug: string;
|
|
18
|
+
name: string;
|
|
19
|
+
} | null;
|
|
20
|
+
url: string | null;
|
|
21
|
+
members?: KartaMember[];
|
|
22
|
+
}
|
|
23
|
+
export interface KartaConfigureOptions {
|
|
24
|
+
name?: string;
|
|
25
|
+
slug?: string;
|
|
26
|
+
access?: string;
|
|
27
|
+
}
|
|
28
|
+
export interface KartaListOptions {
|
|
29
|
+
agent?: string;
|
|
30
|
+
named?: boolean;
|
|
31
|
+
archived?: boolean;
|
|
32
|
+
}
|
|
33
|
+
export interface KartaNameOptions {
|
|
34
|
+
name?: string;
|
|
35
|
+
slug?: string;
|
|
36
|
+
}
|
|
37
|
+
export interface KartaCreateOptions {
|
|
38
|
+
agent?: string;
|
|
39
|
+
slug?: string;
|
|
40
|
+
access?: string;
|
|
41
|
+
members?: string[];
|
|
42
|
+
memberRole?: string;
|
|
43
|
+
}
|
|
44
|
+
export declare function validateKartaCreateOptions(name: string, options: KartaCreateOptions): void;
|
|
45
|
+
export declare function kartasCreateData(ctx: CliContext, name: string, options: KartaCreateOptions): Promise<{
|
|
46
|
+
karta: KartaRecord;
|
|
47
|
+
}>;
|
|
48
|
+
export declare function kartasCreate(ctx: CliContext, name: string, options: KartaCreateOptions): Promise<string>;
|
|
49
|
+
export declare function kartasListData(ctx: CliContext, options?: KartaListOptions): Promise<KartaRecord[]>;
|
|
50
|
+
export declare function kartasList(ctx: CliContext, options?: KartaListOptions): Promise<string>;
|
|
51
|
+
export declare function kartasShowData(ctx: CliContext, id: string): Promise<KartaRecord>;
|
|
52
|
+
export declare function kartasShow(ctx: CliContext, id: string): Promise<string>;
|
|
53
|
+
export declare function validateKartaConfigureOptions(options: KartaConfigureOptions): void;
|
|
54
|
+
export declare function validateKartaNameOptions(options: KartaNameOptions): void;
|
|
55
|
+
export declare function kartasNameData(ctx: CliContext, id: string, options: KartaNameOptions): Promise<{
|
|
56
|
+
karta: KartaRecord;
|
|
57
|
+
}>;
|
|
58
|
+
export declare function kartasName(ctx: CliContext, id: string, options: KartaNameOptions): Promise<string>;
|
|
59
|
+
export declare function kartasConfigureData(ctx: CliContext, id: string, options: KartaConfigureOptions): Promise<{
|
|
60
|
+
karta: KartaRecord;
|
|
61
|
+
}>;
|
|
62
|
+
export declare function kartasConfigure(ctx: CliContext, id: string, options: KartaConfigureOptions): Promise<string>;
|
|
63
|
+
export declare function kartasArchiveData(ctx: CliContext, id: string): Promise<{
|
|
64
|
+
karta: KartaRecord;
|
|
65
|
+
}>;
|
|
66
|
+
export declare function kartasArchive(ctx: CliContext, id: string): Promise<string>;
|
|
67
|
+
export declare function kartasRestoreData(ctx: CliContext, id: string): Promise<{
|
|
68
|
+
karta: KartaRecord;
|
|
69
|
+
}>;
|
|
70
|
+
export declare function kartasRestore(ctx: CliContext, id: string): Promise<string>;
|
|
71
|
+
export declare function kartaMembersGrantData(ctx: CliContext, id: string, email: string, role: string): Promise<{
|
|
72
|
+
member: KartaMember;
|
|
73
|
+
}>;
|
|
74
|
+
export declare function kartaMembersGrant(ctx: CliContext, id: string, email: string, role: string): Promise<string>;
|
|
75
|
+
export declare function kartaMembersSetRoleData(ctx: CliContext, id: string, membershipId: string, role: string): Promise<{
|
|
76
|
+
member: KartaMember;
|
|
77
|
+
}>;
|
|
78
|
+
export declare function kartaMembersSetRole(ctx: CliContext, id: string, membershipId: string, role: string): Promise<string>;
|
|
79
|
+
export declare function kartaMembersRevokeData(ctx: CliContext, id: string, membershipId: string): Promise<{
|
|
80
|
+
id: string;
|
|
81
|
+
membership_id: string;
|
|
82
|
+
revoked: true;
|
|
83
|
+
}>;
|
|
84
|
+
export declare function kartaMembersRevoke(ctx: CliContext, id: string, membershipId: string): Promise<string>;
|
|
85
|
+
export interface KartaEnvRecord {
|
|
86
|
+
name: string;
|
|
87
|
+
secret: boolean;
|
|
88
|
+
value?: string | null;
|
|
89
|
+
updated_at?: string;
|
|
90
|
+
updated_by?: string;
|
|
91
|
+
}
|
|
92
|
+
export declare function kartaEnvListData(ctx: CliContext, agent: string, karta: string): Promise<KartaEnvRecord[]>;
|
|
93
|
+
export declare function kartaEnvList(ctx: CliContext, agent: string, karta: string): Promise<string>;
|
|
94
|
+
export declare function kartaEnvSetData(ctx: CliContext, agent: string, karta: string, name: string, value: string, options?: {
|
|
95
|
+
secret?: boolean;
|
|
96
|
+
}): Promise<KartaEnvRecord>;
|
|
97
|
+
export declare function kartaEnvSet(ctx: CliContext, agent: string, karta: string, name: string, value: string, options?: {
|
|
98
|
+
secret?: boolean;
|
|
99
|
+
}): Promise<string>;
|
|
100
|
+
export declare function kartaEnvUnsetData(ctx: CliContext, agent: string, karta: string, name: string): Promise<void>;
|
|
101
|
+
export declare function kartaEnvUnset(ctx: CliContext, agent: string, karta: string, name: string): Promise<string>;
|