@songsid/agend 2.1.6-beta.1 → 2.1.6-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/apply-job.d.ts +114 -0
- package/dist/apply-job.js +214 -0
- package/dist/apply-job.js.map +1 -0
- package/dist/backend/credential-profile.d.ts +114 -0
- package/dist/backend/credential-profile.js +242 -0
- package/dist/backend/credential-profile.js.map +1 -0
- package/dist/backend/kiro-auth-store.d.ts +25 -0
- package/dist/backend/kiro-auth-store.js +61 -0
- package/dist/backend/kiro-auth-store.js.map +1 -0
- package/dist/backend/kiro.d.ts +8 -0
- package/dist/backend/kiro.js +31 -2
- package/dist/backend/kiro.js.map +1 -1
- package/dist/cli.js +113 -0
- package/dist/cli.js.map +1 -1
- package/dist/config-validator.js +21 -0
- package/dist/config-validator.js.map +1 -1
- package/dist/daemon.d.ts +10 -0
- package/dist/daemon.js +27 -1
- package/dist/daemon.js.map +1 -1
- package/dist/fleet-level-config.d.ts +42 -0
- package/dist/fleet-level-config.js +78 -0
- package/dist/fleet-level-config.js.map +1 -0
- package/dist/fleet-lock.d.ts +21 -0
- package/dist/fleet-lock.js +42 -8
- package/dist/fleet-lock.js.map +1 -1
- package/dist/fleet-manager.d.ts +122 -1
- package/dist/fleet-manager.js +537 -83
- package/dist/fleet-manager.js.map +1 -1
- package/dist/general-knowledge/skills/credential-profiles/SKILL.md +121 -0
- package/dist/instance-config-impact.d.ts +55 -0
- package/dist/instance-config-impact.js +152 -0
- package/dist/instance-config-impact.js.map +1 -0
- package/dist/locale.js +2 -0
- package/dist/locale.js.map +1 -1
- package/dist/outbound-handlers.d.ts +5 -1
- package/dist/outbound-handlers.js +179 -1
- package/dist/outbound-handlers.js.map +1 -1
- package/dist/outbound-schemas.d.ts +6 -5
- package/dist/outbound-schemas.js +1 -0
- package/dist/outbound-schemas.js.map +1 -1
- package/dist/provider-probe.d.ts +45 -0
- package/dist/provider-probe.js +111 -0
- package/dist/provider-probe.js.map +1 -0
- package/dist/quickstart-api.d.ts +161 -0
- package/dist/quickstart-api.js +340 -0
- package/dist/quickstart-api.js.map +1 -0
- package/dist/quickstart.js +23 -50
- package/dist/quickstart.js.map +1 -1
- package/dist/self-restart-limit.d.ts +21 -0
- package/dist/self-restart-limit.js +129 -0
- package/dist/self-restart-limit.js.map +1 -0
- package/dist/settings-api.d.ts +15 -0
- package/dist/settings-api.js +126 -1
- package/dist/settings-api.js.map +1 -1
- package/dist/setup-auth.d.ts +113 -0
- package/dist/setup-auth.js +181 -0
- package/dist/setup-auth.js.map +1 -0
- package/dist/setup-form.d.ts +18 -0
- package/dist/setup-form.js +315 -0
- package/dist/setup-form.js.map +1 -0
- package/dist/setup-host.d.ts +162 -0
- package/dist/setup-host.js +496 -0
- package/dist/setup-host.js.map +1 -0
- package/dist/setup-marker.d.ts +8 -0
- package/dist/setup-marker.js +39 -0
- package/dist/setup-marker.js.map +1 -0
- package/dist/setup-tunnel-consent.d.ts +53 -0
- package/dist/setup-tunnel-consent.js +82 -0
- package/dist/setup-tunnel-consent.js.map +1 -0
- package/dist/tips.js +1 -1
- package/dist/tips.js.map +1 -1
- package/dist/transcript-sources.d.ts +12 -1
- package/dist/transcript-sources.js +19 -3
- package/dist/transcript-sources.js.map +1 -1
- package/dist/tunnel/cloudflared.d.ts +71 -0
- package/dist/tunnel/cloudflared.js +447 -0
- package/dist/tunnel/cloudflared.js.map +1 -0
- package/dist/tunnel/lease.d.ts +75 -0
- package/dist/tunnel/lease.js +209 -0
- package/dist/tunnel/lease.js.map +1 -0
- package/dist/tunnel/manager.d.ts +56 -0
- package/dist/tunnel/manager.js +167 -0
- package/dist/tunnel/manager.js.map +1 -0
- package/dist/tunnel/types.d.ts +119 -0
- package/dist/tunnel/types.js +33 -0
- package/dist/tunnel/types.js.map +1 -0
- package/dist/ui/dashboard.html +4 -3
- package/dist/ui/settings.html +640 -153
- package/dist/usage/providers.d.ts +16 -13
- package/dist/usage/providers.js +79 -53
- package/dist/usage/providers.js.map +1 -1
- package/dist/web-api.js +6 -4
- package/dist/web-api.js.map +1 -1
- package/dist/web-auth.d.ts +75 -0
- package/dist/web-auth.js +208 -2
- package/dist/web-auth.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
/** How long a finished job stays answerable, and how long a key is honoured. */
|
|
2
|
+
export declare const APPLY_JOB_RETENTION_MS: number;
|
|
3
|
+
/**
|
|
4
|
+
* Wall clock, not a step count: the user is looking at a spinner, and the thing
|
|
5
|
+
* they need to be told is that it has been N seconds, not which internal phase
|
|
6
|
+
* it is in. Generous — a reconcile that restarts several agents on a loaded
|
|
7
|
+
* machine is slow but fine.
|
|
8
|
+
*/
|
|
9
|
+
export declare const APPLY_JOB_DEADLINE_MS = 120000;
|
|
10
|
+
/** Outcome of asking the fleet to restart itself for a Settings change. */
|
|
11
|
+
export type SelfRestartResult = {
|
|
12
|
+
ok: true;
|
|
13
|
+
jobId: string;
|
|
14
|
+
reused?: boolean;
|
|
15
|
+
} | {
|
|
16
|
+
ok: false;
|
|
17
|
+
status: 409 | 429 | 503;
|
|
18
|
+
error: string;
|
|
19
|
+
retryAfterSeconds?: number;
|
|
20
|
+
};
|
|
21
|
+
/** The row for the fleet process itself, as opposed to one of its agents. */
|
|
22
|
+
export declare const APPLY_FLEET_TARGET = "fleet";
|
|
23
|
+
export type ApplyTargetKind = "hot" | "restart";
|
|
24
|
+
/**
|
|
25
|
+
* `restart-required` is a terminal state, not a stalled one: the change is saved
|
|
26
|
+
* and valid, and a running fleet process cannot adopt it. Reporting it as done
|
|
27
|
+
* would tell the user AgEnD is on the new configuration when it is not.
|
|
28
|
+
*/
|
|
29
|
+
export type ApplyTargetStatus = "pending" | "running" | "done" | "failed" | "restart-required";
|
|
30
|
+
export type ApplyJobStatus = "running" | "done" | "failed";
|
|
31
|
+
export interface ApplyTarget {
|
|
32
|
+
/** Instance name, or `fleet` for the process-level row. */
|
|
33
|
+
target: string;
|
|
34
|
+
kind: ApplyTargetKind;
|
|
35
|
+
status: ApplyTargetStatus;
|
|
36
|
+
error?: string;
|
|
37
|
+
/**
|
|
38
|
+
* Who finished the row, when it was not this job's own work:
|
|
39
|
+
* `fleet-restart` — a process restart applied it;
|
|
40
|
+
* `no-change` — the plan expected work the reconcile found unnecessary.
|
|
41
|
+
*/
|
|
42
|
+
settled_by?: "fleet-restart" | "no-change";
|
|
43
|
+
}
|
|
44
|
+
export interface ApplyJob {
|
|
45
|
+
id: string;
|
|
46
|
+
/** The client's idempotency key. */
|
|
47
|
+
key: string;
|
|
48
|
+
status: ApplyJobStatus;
|
|
49
|
+
startedAt: number;
|
|
50
|
+
finishedAt?: number;
|
|
51
|
+
targets: ApplyTarget[];
|
|
52
|
+
/** Deadline for "still working" messaging; it never cancels the work. */
|
|
53
|
+
deadlineMs: number;
|
|
54
|
+
/** The process that created the job, so a restart is detectable. */
|
|
55
|
+
pid: number;
|
|
56
|
+
error?: string;
|
|
57
|
+
/**
|
|
58
|
+
* The idempotency key of the self-restart this job's fleet row was consumed
|
|
59
|
+
* by. Stored on the job rather than in memory because the process it belongs
|
|
60
|
+
* to is about to be replaced — a retry after the restart has to find it.
|
|
61
|
+
*/
|
|
62
|
+
restart_key?: string;
|
|
63
|
+
}
|
|
64
|
+
/** Everything a caller needs to render, computed rather than stored so it stays
|
|
65
|
+
* true while the job is being read long after the last write. */
|
|
66
|
+
export interface ApplyJobView extends ApplyJob {
|
|
67
|
+
elapsed_ms: number;
|
|
68
|
+
/** Past the deadline and still working — say so instead of spinning silently. */
|
|
69
|
+
overdue: boolean;
|
|
70
|
+
/** Human sentence for the overdue case; empty otherwise. */
|
|
71
|
+
message: string;
|
|
72
|
+
}
|
|
73
|
+
export declare function viewOf(job: ApplyJob, now?: number): ApplyJobView;
|
|
74
|
+
/**
|
|
75
|
+
* The jobs file. Small, rewritten whole on every transition — a settings apply
|
|
76
|
+
* happens at human speed, so the simplest durable thing is the right one.
|
|
77
|
+
*/
|
|
78
|
+
/** Just enough of a logger for the one thing this module has to report. */
|
|
79
|
+
export interface ApplyJobLogger {
|
|
80
|
+
warn(data: unknown, message: string): void;
|
|
81
|
+
}
|
|
82
|
+
export declare class ApplyJobStore {
|
|
83
|
+
private readonly dataDir;
|
|
84
|
+
private readonly now;
|
|
85
|
+
private readonly logger?;
|
|
86
|
+
private jobs;
|
|
87
|
+
constructor(dataDir: string, now?: () => number, logger?: ApplyJobLogger | undefined);
|
|
88
|
+
private path;
|
|
89
|
+
private read;
|
|
90
|
+
private write;
|
|
91
|
+
private prune;
|
|
92
|
+
/**
|
|
93
|
+
* A job created in an earlier process cannot still be running in this one.
|
|
94
|
+
*
|
|
95
|
+
* The restart is what applied the config: every agent came up from the saved
|
|
96
|
+
* file. So rows left pending or running are done — recorded as settled by the
|
|
97
|
+
* restart rather than by the job, because "who finished this" is exactly what
|
|
98
|
+
* the user is trying to find out.
|
|
99
|
+
*/
|
|
100
|
+
settleAfterRestart(): ApplyJob[];
|
|
101
|
+
get(id: string): ApplyJob | null;
|
|
102
|
+
/** The job whose fleet row a given self-restart key already consumed. */
|
|
103
|
+
findByRestartKey(key: string): ApplyJob | null;
|
|
104
|
+
/** The live job for a key, if the client is retrying rather than re-applying. */
|
|
105
|
+
findByKey(key: string): ApplyJob | null;
|
|
106
|
+
create(key: string, targets: Array<Pick<ApplyTarget, "target" | "kind">>, deadlineMs?: number): ApplyJob;
|
|
107
|
+
/** Mutate one job and persist. Every transition hits the disk, because the
|
|
108
|
+
* transition we care most about is the last one before the process dies. */
|
|
109
|
+
update(id: string, mutate: (job: ApplyJob) => void): ApplyJob | null;
|
|
110
|
+
setTargetStatus(id: string, target: string, status: ApplyTargetStatus, error?: string): void;
|
|
111
|
+
finish(id: string, error?: string): void;
|
|
112
|
+
/** Test/introspection seam. */
|
|
113
|
+
all(): ApplyJob[];
|
|
114
|
+
}
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A Settings "Apply" that the user can watch, and that survives the restart it
|
|
3
|
+
* asks for.
|
|
4
|
+
*
|
|
5
|
+
* The old path was `POST /api/settings/reload` → SIGHUP → nothing. The page said
|
|
6
|
+
* "changes applied" the moment the signal was sent, while the reconcile was
|
|
7
|
+
* still stopping and starting agents behind it, and a change that restarts AgEnD
|
|
8
|
+
* itself killed the only place the answer lived.
|
|
9
|
+
*
|
|
10
|
+
* Two properties carry the whole design:
|
|
11
|
+
*
|
|
12
|
+
* 1. **The job is on disk, not in the process.** A fleet-impact change takes the
|
|
13
|
+
* fleet process down with it. An in-memory job dies there, `GET` starts
|
|
14
|
+
* answering 404, and the page shows "restarting…" forever (#722/#748 are the
|
|
15
|
+
* same shape). The replacement process reads the marker, settles whatever was
|
|
16
|
+
* still in flight, and can answer for a job it never started.
|
|
17
|
+
* 2. **The client owns the idempotency key.** A server-minted job id cannot stop
|
|
18
|
+
* a duplicate: on a phone the POST leaves, the answer never arrives, and the
|
|
19
|
+
* retry is a second request the server has no way to recognise. A key the
|
|
20
|
+
* client generates before the first attempt makes the retry identifiable, so
|
|
21
|
+
* it returns the original job instead of applying everything twice.
|
|
22
|
+
*/
|
|
23
|
+
import { readFileSync, renameSync, unlinkSync, writeFileSync } from "node:fs";
|
|
24
|
+
import { randomUUID } from "node:crypto";
|
|
25
|
+
import { join } from "node:path";
|
|
26
|
+
const FILE = "settings-apply-jobs.json";
|
|
27
|
+
/** How long a finished job stays answerable, and how long a key is honoured. */
|
|
28
|
+
export const APPLY_JOB_RETENTION_MS = 30 * 60_000;
|
|
29
|
+
/**
|
|
30
|
+
* Wall clock, not a step count: the user is looking at a spinner, and the thing
|
|
31
|
+
* they need to be told is that it has been N seconds, not which internal phase
|
|
32
|
+
* it is in. Generous — a reconcile that restarts several agents on a loaded
|
|
33
|
+
* machine is slow but fine.
|
|
34
|
+
*/
|
|
35
|
+
export const APPLY_JOB_DEADLINE_MS = 120_000;
|
|
36
|
+
/** At most this many jobs are kept, newest first. */
|
|
37
|
+
const MAX_JOBS = 20;
|
|
38
|
+
/** The row for the fleet process itself, as opposed to one of its agents. */
|
|
39
|
+
export const APPLY_FLEET_TARGET = "fleet";
|
|
40
|
+
function isTerminal(status) {
|
|
41
|
+
return status === "done" || status === "failed";
|
|
42
|
+
}
|
|
43
|
+
export function viewOf(job, now = Date.now()) {
|
|
44
|
+
const elapsed = Math.max(0, (job.finishedAt ?? now) - job.startedAt);
|
|
45
|
+
const overdue = !isTerminal(job.status) && elapsed > job.deadlineMs;
|
|
46
|
+
return {
|
|
47
|
+
...job,
|
|
48
|
+
elapsed_ms: elapsed,
|
|
49
|
+
overdue,
|
|
50
|
+
message: overdue ? `Still restarting (${Math.round(elapsed / 1000)}s)` : "",
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
export class ApplyJobStore {
|
|
54
|
+
dataDir;
|
|
55
|
+
now;
|
|
56
|
+
logger;
|
|
57
|
+
jobs = [];
|
|
58
|
+
constructor(dataDir, now = Date.now, logger) {
|
|
59
|
+
this.dataDir = dataDir;
|
|
60
|
+
this.now = now;
|
|
61
|
+
this.logger = logger;
|
|
62
|
+
this.jobs = this.read();
|
|
63
|
+
}
|
|
64
|
+
path() {
|
|
65
|
+
return join(this.dataDir, FILE);
|
|
66
|
+
}
|
|
67
|
+
read() {
|
|
68
|
+
try {
|
|
69
|
+
const parsed = JSON.parse(readFileSync(this.path(), "utf-8"));
|
|
70
|
+
if (!Array.isArray(parsed.jobs))
|
|
71
|
+
return [];
|
|
72
|
+
return parsed.jobs.filter(job => typeof job?.id === "string"
|
|
73
|
+
&& typeof job?.key === "string"
|
|
74
|
+
&& typeof job?.startedAt === "number"
|
|
75
|
+
&& Array.isArray(job?.targets));
|
|
76
|
+
}
|
|
77
|
+
catch {
|
|
78
|
+
// Missing or corrupt: an unreadable history must not stop the user from
|
|
79
|
+
// applying settings.
|
|
80
|
+
return [];
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
write() {
|
|
84
|
+
const path = this.path();
|
|
85
|
+
const temp = `${path}.${process.pid}.${this.now()}.tmp`;
|
|
86
|
+
try {
|
|
87
|
+
writeFileSync(temp, JSON.stringify({ jobs: this.jobs }), { mode: 0o600 });
|
|
88
|
+
renameSync(temp, path);
|
|
89
|
+
}
|
|
90
|
+
catch (err) {
|
|
91
|
+
try {
|
|
92
|
+
unlinkSync(temp);
|
|
93
|
+
}
|
|
94
|
+
catch { /* never created */ }
|
|
95
|
+
// A full or read-only data dir means this job will not survive a restart.
|
|
96
|
+
// Swallowing that silently is how the symptom becomes "progress just
|
|
97
|
+
// vanished" with nothing to look at.
|
|
98
|
+
this.logger?.warn({ err, path }, "Settings apply job could not be persisted");
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
prune() {
|
|
102
|
+
const cutoff = this.now() - APPLY_JOB_RETENTION_MS;
|
|
103
|
+
this.jobs = this.jobs
|
|
104
|
+
.filter(job => (job.finishedAt ?? job.startedAt) >= cutoff)
|
|
105
|
+
.slice(0, MAX_JOBS);
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* A job created in an earlier process cannot still be running in this one.
|
|
109
|
+
*
|
|
110
|
+
* The restart is what applied the config: every agent came up from the saved
|
|
111
|
+
* file. So rows left pending or running are done — recorded as settled by the
|
|
112
|
+
* restart rather than by the job, because "who finished this" is exactly what
|
|
113
|
+
* the user is trying to find out.
|
|
114
|
+
*/
|
|
115
|
+
settleAfterRestart() {
|
|
116
|
+
const settled = [];
|
|
117
|
+
for (const job of this.jobs) {
|
|
118
|
+
if (isTerminal(job.status))
|
|
119
|
+
continue;
|
|
120
|
+
// Only a job from another process. The health server accepts requests a
|
|
121
|
+
// little before startup finishes, so an apply started seconds ago in THIS
|
|
122
|
+
// process would otherwise be declared finished by a restart that already
|
|
123
|
+
// happened. (A recycled pid would leave such a job running until its
|
|
124
|
+
// deadline reports it — the harmless direction.)
|
|
125
|
+
if (job.pid === process.pid)
|
|
126
|
+
continue;
|
|
127
|
+
for (const row of job.targets) {
|
|
128
|
+
if (row.status === "done" || row.status === "failed")
|
|
129
|
+
continue;
|
|
130
|
+
row.status = "done";
|
|
131
|
+
row.settled_by = "fleet-restart";
|
|
132
|
+
}
|
|
133
|
+
job.status = "done";
|
|
134
|
+
job.finishedAt = this.now();
|
|
135
|
+
settled.push(job);
|
|
136
|
+
}
|
|
137
|
+
if (settled.length)
|
|
138
|
+
this.write();
|
|
139
|
+
return settled;
|
|
140
|
+
}
|
|
141
|
+
get(id) {
|
|
142
|
+
return this.jobs.find(job => job.id === id) ?? null;
|
|
143
|
+
}
|
|
144
|
+
/** The job whose fleet row a given self-restart key already consumed. */
|
|
145
|
+
findByRestartKey(key) {
|
|
146
|
+
return this.jobs.find(job => job.restart_key === key) ?? null;
|
|
147
|
+
}
|
|
148
|
+
/** The live job for a key, if the client is retrying rather than re-applying. */
|
|
149
|
+
findByKey(key) {
|
|
150
|
+
const cutoff = this.now() - APPLY_JOB_RETENTION_MS;
|
|
151
|
+
return this.jobs.find(job => job.key === key && (job.finishedAt ?? job.startedAt) >= cutoff) ?? null;
|
|
152
|
+
}
|
|
153
|
+
create(key, targets, deadlineMs = APPLY_JOB_DEADLINE_MS) {
|
|
154
|
+
const job = {
|
|
155
|
+
id: randomUUID(),
|
|
156
|
+
key,
|
|
157
|
+
status: "running",
|
|
158
|
+
startedAt: this.now(),
|
|
159
|
+
targets: targets.map(row => ({ ...row, status: "pending" })),
|
|
160
|
+
deadlineMs,
|
|
161
|
+
pid: process.pid,
|
|
162
|
+
};
|
|
163
|
+
this.jobs.unshift(job);
|
|
164
|
+
this.prune();
|
|
165
|
+
this.write();
|
|
166
|
+
return job;
|
|
167
|
+
}
|
|
168
|
+
/** Mutate one job and persist. Every transition hits the disk, because the
|
|
169
|
+
* transition we care most about is the last one before the process dies. */
|
|
170
|
+
update(id, mutate) {
|
|
171
|
+
const job = this.get(id);
|
|
172
|
+
if (!job)
|
|
173
|
+
return null;
|
|
174
|
+
mutate(job);
|
|
175
|
+
this.write();
|
|
176
|
+
return job;
|
|
177
|
+
}
|
|
178
|
+
setTargetStatus(id, target, status, error) {
|
|
179
|
+
this.update(id, job => {
|
|
180
|
+
const row = job.targets.find(item => item.target === target);
|
|
181
|
+
if (!row)
|
|
182
|
+
return;
|
|
183
|
+
row.status = status;
|
|
184
|
+
if (error)
|
|
185
|
+
row.error = error;
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
finish(id, error) {
|
|
189
|
+
this.update(id, job => {
|
|
190
|
+
for (const row of job.targets) {
|
|
191
|
+
if (row.status !== "pending" && row.status !== "running")
|
|
192
|
+
continue;
|
|
193
|
+
if (error) {
|
|
194
|
+
row.status = "failed";
|
|
195
|
+
row.error = error;
|
|
196
|
+
continue;
|
|
197
|
+
}
|
|
198
|
+
// The plan forecast work the reconcile then found unnecessary. Saying
|
|
199
|
+
// plain "done" would read as "this agent was restarted".
|
|
200
|
+
row.status = "done";
|
|
201
|
+
row.settled_by = "no-change";
|
|
202
|
+
}
|
|
203
|
+
job.status = error ? "failed" : job.targets.some(row => row.status === "failed") ? "failed" : "done";
|
|
204
|
+
job.finishedAt = this.now();
|
|
205
|
+
if (error)
|
|
206
|
+
job.error = error;
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
/** Test/introspection seam. */
|
|
210
|
+
all() {
|
|
211
|
+
return this.jobs;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
//# sourceMappingURL=apply-job.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"apply-job.js","sourceRoot":"","sources":["../src/apply-job.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
export interface CredentialHomeSpec {
|
|
2
|
+
/** The variable that moves the credential home, prepended at launch. */
|
|
3
|
+
env: string;
|
|
4
|
+
/** The shared home this backend uses when the variable is unset. */
|
|
5
|
+
sharedRoot(): string;
|
|
6
|
+
/**
|
|
7
|
+
* Where under the root the backend's own files live. `XDG_DATA_HOME` points
|
|
8
|
+
* at a directory of many programs' data, so kiro's store is one level down;
|
|
9
|
+
* a backend whose variable points straight at its own home leaves this "".
|
|
10
|
+
*/
|
|
11
|
+
storeSubdir: string;
|
|
12
|
+
/**
|
|
13
|
+
* Entries that must be real files in the profile. Everything the login is
|
|
14
|
+
* made of, plus anything the store cannot be separated from.
|
|
15
|
+
*/
|
|
16
|
+
isolate: readonly string[];
|
|
17
|
+
/**
|
|
18
|
+
* Entries linked back to the shared home when they exist there. Only
|
|
19
|
+
* content-addressed runtimes and caches belong here — things that are
|
|
20
|
+
* expensive to duplicate and carry no identity.
|
|
21
|
+
*/
|
|
22
|
+
share: readonly string[];
|
|
23
|
+
/**
|
|
24
|
+
* Whether this store holds a login, given its store directory.
|
|
25
|
+
*
|
|
26
|
+
* A profile nobody has logged into is not an empty session — the CLI stops at
|
|
27
|
+
* an interactive sign-in prompt and waits there, so an agent pointed at one
|
|
28
|
+
* never starts. A backend that cannot answer this omits it, and the switch is
|
|
29
|
+
* allowed rather than blocked on a check that does not exist.
|
|
30
|
+
*/
|
|
31
|
+
hasLogin?: (storeHome: string) => boolean;
|
|
32
|
+
/** The subcommand that logs a store in, for telling the user what to run. */
|
|
33
|
+
loginSubcommand: string;
|
|
34
|
+
}
|
|
35
|
+
/** Backends that can hold more than one login. Codex and Claude come later. */
|
|
36
|
+
export declare const CREDENTIAL_HOMES: Readonly<Record<string, CredentialHomeSpec>>;
|
|
37
|
+
export declare function credentialHomeSpec(backendName: string): CredentialHomeSpec | null;
|
|
38
|
+
/**
|
|
39
|
+
* The profile a backend was asked for, or null for "behave exactly as before".
|
|
40
|
+
*
|
|
41
|
+
* Null is the whole backward-compatibility story: no profile means no variable
|
|
42
|
+
* is prepended and no directory is created, so an instance that does not opt in
|
|
43
|
+
* cannot be affected by this feature at all.
|
|
44
|
+
*/
|
|
45
|
+
export declare function resolveCredentialProfile(backendOptions: Record<string, unknown> | undefined): string | null;
|
|
46
|
+
/**
|
|
47
|
+
* Where a profile lives: under the fleet's data directory, not an instance's.
|
|
48
|
+
*
|
|
49
|
+
* A subscription is shared by however many agents the user points at it, so the
|
|
50
|
+
* directory belongs to the fleet. Putting it under an instance would make
|
|
51
|
+
* "these three agents use the work account" impossible to express.
|
|
52
|
+
*/
|
|
53
|
+
export declare function credentialProfileHome(dataDir: string, backendName: string, profile: string): string;
|
|
54
|
+
/**
|
|
55
|
+
* Create the profile home and link the shareable parts back.
|
|
56
|
+
*
|
|
57
|
+
* Idempotent: it only ever adds links that are missing, and never replaces
|
|
58
|
+
* anything that already exists in the profile — a real directory there is
|
|
59
|
+
* someone's data, and this is not the code that decides to delete it.
|
|
60
|
+
*/
|
|
61
|
+
export declare function prepareCredentialProfileHome(spec: CredentialHomeSpec, profileHome: string): void;
|
|
62
|
+
/**
|
|
63
|
+
* The profiles a fleet is configured to use for one backend, in a stable order.
|
|
64
|
+
*
|
|
65
|
+
* Read from the configuration rather than from the directories on disk: the
|
|
66
|
+
* config is what the fleet will actually launch, a directory can linger after a
|
|
67
|
+
* profile is removed, and a profile configured but never started has no
|
|
68
|
+
* directory yet. Instances sharing a profile name collapse into one entry,
|
|
69
|
+
* because they share one login and one quota.
|
|
70
|
+
*/
|
|
71
|
+
export declare function listConfiguredProfiles(config: {
|
|
72
|
+
instances?: Record<string, {
|
|
73
|
+
backend?: string;
|
|
74
|
+
backend_options?: Record<string, Record<string, unknown>>;
|
|
75
|
+
}>;
|
|
76
|
+
defaults?: {
|
|
77
|
+
backend?: string;
|
|
78
|
+
backend_options?: Record<string, Record<string, unknown>>;
|
|
79
|
+
};
|
|
80
|
+
} | null, backendName: string): string[];
|
|
81
|
+
/**
|
|
82
|
+
* The directory the backend's own files sit in, for one profile.
|
|
83
|
+
*
|
|
84
|
+
* One level below the profile home whenever the relocating variable points at a
|
|
85
|
+
* directory of many programs' data — `XDG_DATA_HOME/kiro-cli`, not
|
|
86
|
+
* `XDG_DATA_HOME`. Everything that reads a profile's store (the usage panel,
|
|
87
|
+
* the transcript reader, the login check) must agree on this path, so it is
|
|
88
|
+
* computed here rather than reassembled at each call site.
|
|
89
|
+
*/
|
|
90
|
+
export declare function credentialProfileStoreHome(dataDir: string, backendName: string, profile: string): string;
|
|
91
|
+
/**
|
|
92
|
+
* Whether a profile can be started, and what to run if it cannot.
|
|
93
|
+
*
|
|
94
|
+
* `unknown` is not a failure: a backend with no login probe, or a profile on a
|
|
95
|
+
* backend that has no credential home at all, is simply not something this can
|
|
96
|
+
* speak about, and a caller must not treat silence as a refusal.
|
|
97
|
+
*/
|
|
98
|
+
export type CredentialProfileLogin = {
|
|
99
|
+
readonly state: "logged-in";
|
|
100
|
+
} | {
|
|
101
|
+
readonly state: "signed-out";
|
|
102
|
+
readonly loginCommand: string;
|
|
103
|
+
} | {
|
|
104
|
+
readonly state: "unknown";
|
|
105
|
+
};
|
|
106
|
+
export declare function credentialProfileLogin(dataDir: string, backendName: string, profile: string): CredentialProfileLogin;
|
|
107
|
+
/** The profile one instance runs under, or null for the shared login. */
|
|
108
|
+
export declare function instanceCredentialProfile(instance: {
|
|
109
|
+
backend_options?: Record<string, Record<string, unknown>>;
|
|
110
|
+
} | undefined, defaults: {
|
|
111
|
+
backend_options?: Record<string, Record<string, unknown>>;
|
|
112
|
+
} | undefined, backendName: string): string | null;
|
|
113
|
+
/** Entries that are real (not links) in a prepared profile — for tests and doctor. */
|
|
114
|
+
export declare function profilePrivateEntries(spec: CredentialHomeSpec, profileHome: string): string[];
|