crewly 1.20.123 → 1.20.124
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/backend/backend/src/constants.d.ts +118 -0
- package/dist/backend/backend/src/constants.d.ts.map +1 -1
- package/dist/backend/backend/src/constants.js +118 -0
- package/dist/backend/backend/src/constants.js.map +1 -1
- package/dist/backend/backend/src/controllers/harness/harness.controller.d.ts +54 -0
- package/dist/backend/backend/src/controllers/harness/harness.controller.d.ts.map +1 -0
- package/dist/backend/backend/src/controllers/harness/harness.controller.js +204 -0
- package/dist/backend/backend/src/controllers/harness/harness.controller.js.map +1 -0
- package/dist/backend/backend/src/controllers/harness/harness.routes.d.ts +27 -0
- package/dist/backend/backend/src/controllers/harness/harness.routes.d.ts.map +1 -0
- package/dist/backend/backend/src/controllers/harness/harness.routes.js +43 -0
- package/dist/backend/backend/src/controllers/harness/harness.routes.js.map +1 -0
- package/dist/backend/backend/src/routes/api.routes.d.ts.map +1 -1
- package/dist/backend/backend/src/routes/api.routes.js +4 -0
- package/dist/backend/backend/src/routes/api.routes.js.map +1 -1
- package/dist/backend/backend/src/services/agent/agent-registration.service.d.ts +5 -0
- package/dist/backend/backend/src/services/agent/agent-registration.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/agent/agent-registration.service.js +7 -0
- package/dist/backend/backend/src/services/agent/agent-registration.service.js.map +1 -1
- package/dist/backend/backend/src/services/cloud/cloud-client.service.d.ts +2 -1
- package/dist/backend/backend/src/services/cloud/cloud-client.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/cloud/cloud-client.service.js +4 -3
- package/dist/backend/backend/src/services/cloud/cloud-client.service.js.map +1 -1
- package/dist/backend/backend/src/services/cloud/mobile-api-relay.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/cloud/mobile-api-relay.service.js +14 -0
- package/dist/backend/backend/src/services/cloud/mobile-api-relay.service.js.map +1 -1
- package/dist/backend/backend/src/services/harness/claude-config.utils.d.ts +67 -0
- package/dist/backend/backend/src/services/harness/claude-config.utils.d.ts.map +1 -0
- package/dist/backend/backend/src/services/harness/claude-config.utils.js +118 -0
- package/dist/backend/backend/src/services/harness/claude-config.utils.js.map +1 -0
- package/dist/backend/backend/src/services/harness/harness-api-key.service.d.ts +99 -0
- package/dist/backend/backend/src/services/harness/harness-api-key.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/harness/harness-api-key.service.js +157 -0
- package/dist/backend/backend/src/services/harness/harness-api-key.service.js.map +1 -0
- package/dist/backend/backend/src/services/harness/harness-credentials.store.d.ts +135 -0
- package/dist/backend/backend/src/services/harness/harness-credentials.store.d.ts.map +1 -0
- package/dist/backend/backend/src/services/harness/harness-credentials.store.js +208 -0
- package/dist/backend/backend/src/services/harness/harness-credentials.store.js.map +1 -0
- package/dist/backend/backend/src/services/harness/harness-exec.utils.d.ts +85 -0
- package/dist/backend/backend/src/services/harness/harness-exec.utils.d.ts.map +1 -0
- package/dist/backend/backend/src/services/harness/harness-exec.utils.js +183 -0
- package/dist/backend/backend/src/services/harness/harness-exec.utils.js.map +1 -0
- package/dist/backend/backend/src/services/harness/harness-install.service.d.ts +106 -0
- package/dist/backend/backend/src/services/harness/harness-install.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/harness/harness-install.service.js +205 -0
- package/dist/backend/backend/src/services/harness/harness-install.service.js.map +1 -0
- package/dist/backend/backend/src/services/harness/harness-registry.d.ts +86 -0
- package/dist/backend/backend/src/services/harness/harness-registry.d.ts.map +1 -0
- package/dist/backend/backend/src/services/harness/harness-registry.js +121 -0
- package/dist/backend/backend/src/services/harness/harness-registry.js.map +1 -0
- package/dist/backend/backend/src/services/harness/harness-status.service.d.ts +173 -0
- package/dist/backend/backend/src/services/harness/harness-status.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/harness/harness-status.service.js +324 -0
- package/dist/backend/backend/src/services/harness/harness-status.service.js.map +1 -0
- package/dist/backend/backend/src/services/harness/harness.service.d.ts +146 -0
- package/dist/backend/backend/src/services/harness/harness.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/harness/harness.service.js +193 -0
- package/dist/backend/backend/src/services/harness/harness.service.js.map +1 -0
- package/dist/backend/backend/src/services/harness/harness.types.d.ts +138 -0
- package/dist/backend/backend/src/services/harness/harness.types.d.ts.map +1 -0
- package/dist/backend/backend/src/services/harness/harness.types.js +51 -0
- package/dist/backend/backend/src/services/harness/harness.types.js.map +1 -0
- package/dist/backend/backend/src/services/harness/login-broker.service.d.ts +238 -0
- package/dist/backend/backend/src/services/harness/login-broker.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/harness/login-broker.service.js +495 -0
- package/dist/backend/backend/src/services/harness/login-broker.service.js.map +1 -0
- package/dist/backend/backend/src/services/harness/login-rules.d.ts +162 -0
- package/dist/backend/backend/src/services/harness/login-rules.d.ts.map +1 -0
- package/dist/backend/backend/src/services/harness/login-rules.js +344 -0
- package/dist/backend/backend/src/services/harness/login-rules.js.map +1 -0
- package/dist/backend/backend/src/services/harness/orc-harness.store.d.ts +59 -0
- package/dist/backend/backend/src/services/harness/orc-harness.store.d.ts.map +1 -0
- package/dist/backend/backend/src/services/harness/orc-harness.store.js +108 -0
- package/dist/backend/backend/src/services/harness/orc-harness.store.js.map +1 -0
- package/dist/backend/build-info.json +2 -2
- package/dist/cli/backend/src/constants.d.ts +118 -0
- package/dist/cli/backend/src/constants.d.ts.map +1 -1
- package/dist/cli/backend/src/constants.js +118 -0
- package/dist/cli/backend/src/constants.js.map +1 -1
- package/dist/cli/backend/src/services/agent/agent-registration.service.d.ts +5 -0
- package/dist/cli/backend/src/services/agent/agent-registration.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/agent/agent-registration.service.js +7 -0
- package/dist/cli/backend/src/services/agent/agent-registration.service.js.map +1 -1
- package/dist/cli/backend/src/services/cloud/cloud-client.service.d.ts +2 -1
- package/dist/cli/backend/src/services/cloud/cloud-client.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/cloud/cloud-client.service.js +4 -3
- package/dist/cli/backend/src/services/cloud/cloud-client.service.js.map +1 -1
- package/dist/cli/backend/src/services/harness/claude-config.utils.d.ts +67 -0
- package/dist/cli/backend/src/services/harness/claude-config.utils.d.ts.map +1 -0
- package/dist/cli/backend/src/services/harness/claude-config.utils.js +118 -0
- package/dist/cli/backend/src/services/harness/claude-config.utils.js.map +1 -0
- package/dist/cli/backend/src/services/harness/harness-api-key.service.d.ts +99 -0
- package/dist/cli/backend/src/services/harness/harness-api-key.service.d.ts.map +1 -0
- package/dist/cli/backend/src/services/harness/harness-api-key.service.js +157 -0
- package/dist/cli/backend/src/services/harness/harness-api-key.service.js.map +1 -0
- package/dist/cli/backend/src/services/harness/harness-credentials.store.d.ts +135 -0
- package/dist/cli/backend/src/services/harness/harness-credentials.store.d.ts.map +1 -0
- package/dist/cli/backend/src/services/harness/harness-credentials.store.js +208 -0
- package/dist/cli/backend/src/services/harness/harness-credentials.store.js.map +1 -0
- package/dist/cli/backend/src/services/harness/harness-exec.utils.d.ts +85 -0
- package/dist/cli/backend/src/services/harness/harness-exec.utils.d.ts.map +1 -0
- package/dist/cli/backend/src/services/harness/harness-exec.utils.js +183 -0
- package/dist/cli/backend/src/services/harness/harness-exec.utils.js.map +1 -0
- package/dist/cli/backend/src/services/harness/harness-install.service.d.ts +106 -0
- package/dist/cli/backend/src/services/harness/harness-install.service.d.ts.map +1 -0
- package/dist/cli/backend/src/services/harness/harness-install.service.js +205 -0
- package/dist/cli/backend/src/services/harness/harness-install.service.js.map +1 -0
- package/dist/cli/backend/src/services/harness/harness-registry.d.ts +86 -0
- package/dist/cli/backend/src/services/harness/harness-registry.d.ts.map +1 -0
- package/dist/cli/backend/src/services/harness/harness-registry.js +121 -0
- package/dist/cli/backend/src/services/harness/harness-registry.js.map +1 -0
- package/dist/cli/backend/src/services/harness/harness-status.service.d.ts +173 -0
- package/dist/cli/backend/src/services/harness/harness-status.service.d.ts.map +1 -0
- package/dist/cli/backend/src/services/harness/harness-status.service.js +324 -0
- package/dist/cli/backend/src/services/harness/harness-status.service.js.map +1 -0
- package/dist/cli/backend/src/services/harness/harness.service.d.ts +146 -0
- package/dist/cli/backend/src/services/harness/harness.service.d.ts.map +1 -0
- package/dist/cli/backend/src/services/harness/harness.service.js +193 -0
- package/dist/cli/backend/src/services/harness/harness.service.js.map +1 -0
- package/dist/cli/backend/src/services/harness/harness.types.d.ts +138 -0
- package/dist/cli/backend/src/services/harness/harness.types.d.ts.map +1 -0
- package/dist/cli/backend/src/services/harness/harness.types.js +51 -0
- package/dist/cli/backend/src/services/harness/harness.types.js.map +1 -0
- package/dist/cli/backend/src/services/harness/login-broker.service.d.ts +238 -0
- package/dist/cli/backend/src/services/harness/login-broker.service.d.ts.map +1 -0
- package/dist/cli/backend/src/services/harness/login-broker.service.js +495 -0
- package/dist/cli/backend/src/services/harness/login-broker.service.js.map +1 -0
- package/dist/cli/backend/src/services/harness/login-rules.d.ts +162 -0
- package/dist/cli/backend/src/services/harness/login-rules.d.ts.map +1 -0
- package/dist/cli/backend/src/services/harness/login-rules.js +344 -0
- package/dist/cli/backend/src/services/harness/login-rules.js.map +1 -0
- package/dist/cli/backend/src/services/harness/orc-harness.store.d.ts +59 -0
- package/dist/cli/backend/src/services/harness/orc-harness.store.d.ts.map +1 -0
- package/dist/cli/backend/src/services/harness/orc-harness.store.js +108 -0
- package/dist/cli/backend/src/services/harness/orc-harness.store.js.map +1 -0
- package/dist/cli/cli/src/commands/harness-setup.d.ts +159 -0
- package/dist/cli/cli/src/commands/harness-setup.d.ts.map +1 -0
- package/dist/cli/cli/src/commands/harness-setup.js +377 -0
- package/dist/cli/cli/src/commands/harness-setup.js.map +1 -0
- package/dist/cli/cli/src/commands/harness.d.ts +56 -0
- package/dist/cli/cli/src/commands/harness.d.ts.map +1 -0
- package/dist/cli/cli/src/commands/harness.js +97 -0
- package/dist/cli/cli/src/commands/harness.js.map +1 -0
- package/dist/cli/cli/src/commands/onboard.d.ts +108 -50
- package/dist/cli/cli/src/commands/onboard.d.ts.map +1 -1
- package/dist/cli/cli/src/commands/onboard.js +200 -191
- package/dist/cli/cli/src/commands/onboard.js.map +1 -1
- package/dist/cli/cli/src/constants.d.ts +18 -0
- package/dist/cli/cli/src/constants.d.ts.map +1 -1
- package/dist/cli/cli/src/constants.js +18 -0
- package/dist/cli/cli/src/constants.js.map +1 -1
- package/dist/cli/cli/src/index.js +22 -3
- package/dist/cli/cli/src/index.js.map +1 -1
- package/dist/cli/cli/src/utils/harness-engine.d.ts +99 -0
- package/dist/cli/cli/src/utils/harness-engine.d.ts.map +1 -0
- package/dist/cli/cli/src/utils/harness-engine.js +143 -0
- package/dist/cli/cli/src/utils/harness-engine.js.map +1 -0
- package/dist/cli/cli/src/utils/prompt-io.d.ts +25 -0
- package/dist/cli/cli/src/utils/prompt-io.d.ts.map +1 -0
- package/dist/cli/cli/src/utils/prompt-io.js +47 -0
- package/dist/cli/cli/src/utils/prompt-io.js.map +1 -0
- package/frontend/dist/assets/{index-8327e63e.css → index-0a2f783c.css} +1 -1
- package/frontend/dist/assets/{index-daf43f1a.js → index-aaf65055.js} +309 -309
- package/frontend/dist/index.html +2 -2
- package/package.json +1 -1
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Harness service — the one engine behind both setup front ends.
|
|
3
|
+
*
|
|
4
|
+
* The REST API (`/api/harness`, used by the web setup page) and the `crewly`
|
|
5
|
+
* CLI (`crewly onboard`, `crewly login`, `crewly harness`) both call this
|
|
6
|
+
* facade, so detection, install, orc choice and login behave identically.
|
|
7
|
+
* The backend uses the process-wide {@link getHarnessService}; the CLI builds
|
|
8
|
+
* its own instance with {@link createHarnessService} (silent logger, no
|
|
9
|
+
* backend running required).
|
|
10
|
+
*
|
|
11
|
+
* @module services/harness/harness.service
|
|
12
|
+
*/
|
|
13
|
+
import { LoggerService } from '../core/logger.service.js';
|
|
14
|
+
import { HarnessApiKeyService } from './harness-api-key.service.js';
|
|
15
|
+
import { HarnessInstallService } from './harness-install.service.js';
|
|
16
|
+
import { getHarnessDefinition } from './harness-registry.js';
|
|
17
|
+
import { HarnessStatusService } from './harness-status.service.js';
|
|
18
|
+
import { SILENT_HARNESS_LOGGER, isHarnessId, } from './harness.types.js';
|
|
19
|
+
import { LoginBrokerService } from './login-broker.service.js';
|
|
20
|
+
import { OrcHarnessStore } from './orc-harness.store.js';
|
|
21
|
+
/** Error for an id that is not a harness (REST: 404). */
|
|
22
|
+
export class UnknownHarnessError extends Error {
|
|
23
|
+
id;
|
|
24
|
+
/**
|
|
25
|
+
* @param id - The id that was asked for
|
|
26
|
+
*/
|
|
27
|
+
constructor(id) {
|
|
28
|
+
super(`Unknown harness: ${id}`);
|
|
29
|
+
this.id = id;
|
|
30
|
+
this.name = 'UnknownHarnessError';
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
/** Facade over status, install, orc choice, broker login and API-key login. */
|
|
34
|
+
export class HarnessService {
|
|
35
|
+
status;
|
|
36
|
+
install;
|
|
37
|
+
broker;
|
|
38
|
+
apiKeys;
|
|
39
|
+
orc;
|
|
40
|
+
/**
|
|
41
|
+
* @param parts - Service parts
|
|
42
|
+
*/
|
|
43
|
+
constructor(parts) {
|
|
44
|
+
this.status = parts.status;
|
|
45
|
+
this.install = parts.install;
|
|
46
|
+
this.broker = parts.broker;
|
|
47
|
+
this.apiKeys = parts.apiKeys;
|
|
48
|
+
this.orc = parts.orc;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Validate a harness id.
|
|
52
|
+
*
|
|
53
|
+
* @param id - Candidate
|
|
54
|
+
* @returns The id, typed
|
|
55
|
+
* @throws UnknownHarnessError for an unknown id
|
|
56
|
+
*/
|
|
57
|
+
requireHarnessId(id) {
|
|
58
|
+
if (!isHarnessId(id))
|
|
59
|
+
throw new UnknownHarnessError(id);
|
|
60
|
+
return id;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Everything the setup screen needs.
|
|
64
|
+
*
|
|
65
|
+
* @returns Harness statuses, the orc harness and system tools
|
|
66
|
+
*/
|
|
67
|
+
async getOverview() {
|
|
68
|
+
const [harnesses, orcHarness] = await Promise.all([this.status.listStatuses(), this.orc.get()]);
|
|
69
|
+
return { harnesses, orcHarness, systemTools: this.status.getSystemTools() };
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Status of one harness.
|
|
73
|
+
*
|
|
74
|
+
* @param id - Harness id
|
|
75
|
+
* @returns The status
|
|
76
|
+
* @throws UnknownHarnessError for an unknown id
|
|
77
|
+
*/
|
|
78
|
+
async getStatus(id) {
|
|
79
|
+
return this.status.getStatus(this.requireHarnessId(id));
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Start installing (or updating) a harness.
|
|
83
|
+
*
|
|
84
|
+
* @param id - Harness id
|
|
85
|
+
* @returns The install job
|
|
86
|
+
* @throws UnknownHarnessError for an unknown id
|
|
87
|
+
*/
|
|
88
|
+
startInstall(id) {
|
|
89
|
+
return this.install.startInstall(this.requireHarnessId(id));
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Read an install job.
|
|
93
|
+
*
|
|
94
|
+
* @param jobId - Job id
|
|
95
|
+
* @returns The job
|
|
96
|
+
* @throws HarnessInstallError job_not_found
|
|
97
|
+
*/
|
|
98
|
+
getInstallJob(jobId) {
|
|
99
|
+
return this.install.getJob(jobId);
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Set the orchestrator's harness.
|
|
103
|
+
*
|
|
104
|
+
* @param id - Harness id
|
|
105
|
+
* @returns The recorded harness id
|
|
106
|
+
* @throws UnknownHarnessError for an unknown id
|
|
107
|
+
*/
|
|
108
|
+
async setOrcHarness(id) {
|
|
109
|
+
return this.orc.set(this.requireHarnessId(id));
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Start a broker login.
|
|
113
|
+
*
|
|
114
|
+
* @param id - Harness id
|
|
115
|
+
* @param method - Broker login method
|
|
116
|
+
* @returns The login session
|
|
117
|
+
* @throws UnknownHarnessError | LoginBrokerError
|
|
118
|
+
*/
|
|
119
|
+
startLogin(id, method) {
|
|
120
|
+
return this.broker.start(this.requireHarnessId(id), method);
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Store an API key for a harness and return its fresh status.
|
|
124
|
+
*
|
|
125
|
+
* @param id - Harness id
|
|
126
|
+
* @param key - The key (never echoed)
|
|
127
|
+
* @returns The harness status after login
|
|
128
|
+
* @throws UnknownHarnessError | HarnessApiKeyError
|
|
129
|
+
*/
|
|
130
|
+
async submitApiKey(id, key) {
|
|
131
|
+
const harnessId = this.requireHarnessId(id);
|
|
132
|
+
await this.apiKeys.submit(harnessId, key);
|
|
133
|
+
return this.status.getStatus(harnessId);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Build a harness service with real dependencies.
|
|
138
|
+
*
|
|
139
|
+
* Codex broker logins are confirmed with `codex login status` through the
|
|
140
|
+
* status service.
|
|
141
|
+
*
|
|
142
|
+
* @param options - Logger, settings updater, env
|
|
143
|
+
* @returns A new service
|
|
144
|
+
*
|
|
145
|
+
* @example
|
|
146
|
+
* ```ts
|
|
147
|
+
* const harness = createHarnessService({ logger: SILENT_HARNESS_LOGGER });
|
|
148
|
+
* const overview = await harness.getOverview();
|
|
149
|
+
* ```
|
|
150
|
+
*/
|
|
151
|
+
export function createHarnessService(options = {}) {
|
|
152
|
+
const logger = options.logger ?? SILENT_HARNESS_LOGGER;
|
|
153
|
+
const env = options.env ?? process.env;
|
|
154
|
+
const status = new HarnessStatusService({ logger, env });
|
|
155
|
+
const install = new HarnessInstallService({ logger, env });
|
|
156
|
+
const broker = new LoginBrokerService({
|
|
157
|
+
logger,
|
|
158
|
+
env,
|
|
159
|
+
verify: async (harnessId) => {
|
|
160
|
+
const def = getHarnessDefinition(harnessId);
|
|
161
|
+
if (!def)
|
|
162
|
+
return false;
|
|
163
|
+
const installed = await status.getInstalledInfo(def);
|
|
164
|
+
const login = await status.getLoginInfo(def, installed.path);
|
|
165
|
+
return login.loginState === 'logged_in';
|
|
166
|
+
},
|
|
167
|
+
});
|
|
168
|
+
const apiKeys = new HarnessApiKeyService({ logger, env });
|
|
169
|
+
const orc = new OrcHarnessStore(options.updateDefaultRuntime ? { updateDefaultRuntime: options.updateDefaultRuntime } : {});
|
|
170
|
+
return new HarnessService({ status, install, broker, apiKeys, orc });
|
|
171
|
+
}
|
|
172
|
+
/** Backend singleton. */
|
|
173
|
+
let backendInstance = null;
|
|
174
|
+
/**
|
|
175
|
+
* The backend's harness service (logs through LoggerService).
|
|
176
|
+
*
|
|
177
|
+
* @returns The singleton
|
|
178
|
+
*/
|
|
179
|
+
export function getHarnessService() {
|
|
180
|
+
if (!backendInstance) {
|
|
181
|
+
backendInstance = createHarnessService({ logger: LoggerService.getInstance().createComponentLogger('Harness') });
|
|
182
|
+
}
|
|
183
|
+
return backendInstance;
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Replace or clear the backend singleton (tests).
|
|
187
|
+
*
|
|
188
|
+
* @param service - Service to use, or null to clear
|
|
189
|
+
*/
|
|
190
|
+
export function setHarnessServiceForTesting(service) {
|
|
191
|
+
backendInstance = service;
|
|
192
|
+
}
|
|
193
|
+
//# sourceMappingURL=harness.service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"harness.service.js","sourceRoot":"","sources":["../../../../../../backend/src/services/harness/harness.service.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Harness onboarding types — the shapes shared by the backend REST API
|
|
3
|
+
* (`/api/harness`), the `crewly` CLI and the web setup page.
|
|
4
|
+
*
|
|
5
|
+
* A "harness" is an agent CLI Crewly drives in a PTY: Claude Code, Codex or
|
|
6
|
+
* Gemini CLI. See specs/onboarding-harness-login.md for the contract.
|
|
7
|
+
*
|
|
8
|
+
* @module services/harness/harness.types
|
|
9
|
+
*/
|
|
10
|
+
import { HARNESS_CONSTANTS } from '../../constants.js';
|
|
11
|
+
/** Harness id — equal to the matching `RuntimeType` value. */
|
|
12
|
+
export type HarnessId = (typeof HARNESS_CONSTANTS.IDS)[keyof typeof HARNESS_CONSTANTS.IDS];
|
|
13
|
+
/** Every harness id, in display order. */
|
|
14
|
+
export declare const HARNESS_IDS: readonly HarnessId[];
|
|
15
|
+
/** How the owner can log in to a harness. */
|
|
16
|
+
export type LoginMethodId = 'subscription' | 'api_key' | 'device';
|
|
17
|
+
/** Every login method id. */
|
|
18
|
+
export declare const LOGIN_METHOD_IDS: readonly LoginMethodId[];
|
|
19
|
+
/**
|
|
20
|
+
* How a front end drives a login method.
|
|
21
|
+
* - `broker`: Crewly runs the harness's login command in a PTY (login broker)
|
|
22
|
+
* - `api_key`: the owner pastes a key
|
|
23
|
+
*/
|
|
24
|
+
export type LoginMethodKind = 'broker' | 'api_key';
|
|
25
|
+
/** A login method as exposed over the API. */
|
|
26
|
+
export interface HarnessLoginMethod {
|
|
27
|
+
id: LoginMethodId;
|
|
28
|
+
label: string;
|
|
29
|
+
kind: LoginMethodKind;
|
|
30
|
+
}
|
|
31
|
+
/** Login state reported for a harness. */
|
|
32
|
+
export type LoginState = 'logged_in' | 'logged_out' | 'unknown';
|
|
33
|
+
/** Status of one harness (`GET /api/harness`). */
|
|
34
|
+
export interface HarnessStatus {
|
|
35
|
+
id: HarnessId;
|
|
36
|
+
displayName: string;
|
|
37
|
+
installed: boolean;
|
|
38
|
+
version: string | null;
|
|
39
|
+
latestVersion: string | null;
|
|
40
|
+
updateAvailable: boolean;
|
|
41
|
+
loginState: LoginState;
|
|
42
|
+
/** Where the login was found (never a secret), e.g. `crewly-subscription`, `macos-keychain` */
|
|
43
|
+
loginSource: string | null;
|
|
44
|
+
loginMethods: HarnessLoginMethod[];
|
|
45
|
+
}
|
|
46
|
+
/** A required system tool (only jq today). */
|
|
47
|
+
export interface SystemToolStatus {
|
|
48
|
+
id: string;
|
|
49
|
+
installed: boolean;
|
|
50
|
+
installHint: string;
|
|
51
|
+
}
|
|
52
|
+
/** Body of `GET /api/harness`. */
|
|
53
|
+
export interface HarnessOverview {
|
|
54
|
+
harnesses: HarnessStatus[];
|
|
55
|
+
orcHarness: string | null;
|
|
56
|
+
systemTools: SystemToolStatus[];
|
|
57
|
+
}
|
|
58
|
+
/** State of an install job. */
|
|
59
|
+
export type InstallJobState = 'running' | 'succeeded' | 'failed';
|
|
60
|
+
/** An install job (`GET /api/harness/install/:jobId`). */
|
|
61
|
+
export interface InstallJob {
|
|
62
|
+
jobId: string;
|
|
63
|
+
harnessId: HarnessId;
|
|
64
|
+
state: InstallJobState;
|
|
65
|
+
log: string;
|
|
66
|
+
usedUserPrefix: boolean;
|
|
67
|
+
}
|
|
68
|
+
/** State of a login broker session. */
|
|
69
|
+
export type LoginSessionState = 'starting' | 'awaiting_user' | 'verifying' | 'succeeded' | 'failed' | 'timed_out' | 'cancelled';
|
|
70
|
+
/** Terminal login states: the PTY is gone and the session no longer changes. */
|
|
71
|
+
export declare const TERMINAL_LOGIN_STATES: readonly LoginSessionState[];
|
|
72
|
+
/** A login broker session as exposed to front ends. Never contains a secret. */
|
|
73
|
+
export interface LoginSession {
|
|
74
|
+
id: string;
|
|
75
|
+
harnessId: HarnessId;
|
|
76
|
+
method: LoginMethodId;
|
|
77
|
+
state: LoginSessionState;
|
|
78
|
+
url: string | null;
|
|
79
|
+
userCode: string | null;
|
|
80
|
+
/** True when the harness waits for the user to type/paste something (e.g. Claude's code) */
|
|
81
|
+
needsInput: boolean;
|
|
82
|
+
message: string | null;
|
|
83
|
+
/** Tail of the normalized terminal text, secrets redacted */
|
|
84
|
+
screen: string;
|
|
85
|
+
startedAt: string;
|
|
86
|
+
updatedAt: string;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Whether a value is a known harness id.
|
|
90
|
+
*
|
|
91
|
+
* @param value - Candidate
|
|
92
|
+
* @returns True for `claude-code`, `codex-cli` or `gemini-cli`
|
|
93
|
+
*/
|
|
94
|
+
export declare function isHarnessId(value: unknown): value is HarnessId;
|
|
95
|
+
/**
|
|
96
|
+
* Whether a value is a known login method id.
|
|
97
|
+
*
|
|
98
|
+
* @param value - Candidate
|
|
99
|
+
* @returns True for `subscription`, `api_key` or `device`
|
|
100
|
+
*/
|
|
101
|
+
export declare function isLoginMethodId(value: unknown): value is LoginMethodId;
|
|
102
|
+
/**
|
|
103
|
+
* Whether a login state is terminal (the session will not change again).
|
|
104
|
+
*
|
|
105
|
+
* @param state - Login session state
|
|
106
|
+
* @returns True for succeeded / failed / timed_out / cancelled
|
|
107
|
+
*/
|
|
108
|
+
export declare function isTerminalLoginState(state: LoginSessionState): boolean;
|
|
109
|
+
/** Minimal logger the harness services accept (the CLI passes a silent one). */
|
|
110
|
+
export interface HarnessLogger {
|
|
111
|
+
info(message: string, context?: Record<string, unknown>): void;
|
|
112
|
+
warn(message: string, context?: Record<string, unknown>): void;
|
|
113
|
+
error(message: string, context?: Record<string, unknown>): void;
|
|
114
|
+
debug(message: string, context?: Record<string, unknown>): void;
|
|
115
|
+
}
|
|
116
|
+
/** A logger that drops everything (CLI default, tests). */
|
|
117
|
+
export declare const SILENT_HARNESS_LOGGER: HarnessLogger;
|
|
118
|
+
/** Result of running a command to completion. */
|
|
119
|
+
export interface CommandResult {
|
|
120
|
+
/** Exit code; null when the process could not be started or was killed */
|
|
121
|
+
code: number | null;
|
|
122
|
+
stdout: string;
|
|
123
|
+
stderr: string;
|
|
124
|
+
/** Spawn error message (ENOENT, timeout), when there was one */
|
|
125
|
+
error?: string;
|
|
126
|
+
}
|
|
127
|
+
/** Options for {@link RunCommand}. */
|
|
128
|
+
export interface RunCommandOptions {
|
|
129
|
+
env?: NodeJS.ProcessEnv;
|
|
130
|
+
timeoutMs?: number;
|
|
131
|
+
/** Written to the child's stdin, then stdin is closed (used for API keys; never argv) */
|
|
132
|
+
stdin?: string;
|
|
133
|
+
/** Streaming output callback (install log) */
|
|
134
|
+
onOutput?: (chunk: string) => void;
|
|
135
|
+
}
|
|
136
|
+
/** Runs a command without a shell and resolves when it exits. Never rejects. */
|
|
137
|
+
export type RunCommand = (command: string, args: readonly string[], options?: RunCommandOptions) => Promise<CommandResult>;
|
|
138
|
+
//# sourceMappingURL=harness.types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"harness.types.d.ts","sourceRoot":"","sources":["../../../../../../backend/src/services/harness/harness.types.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Harness onboarding types — the shapes shared by the backend REST API
|
|
3
|
+
* (`/api/harness`), the `crewly` CLI and the web setup page.
|
|
4
|
+
*
|
|
5
|
+
* A "harness" is an agent CLI Crewly drives in a PTY: Claude Code, Codex or
|
|
6
|
+
* Gemini CLI. See specs/onboarding-harness-login.md for the contract.
|
|
7
|
+
*
|
|
8
|
+
* @module services/harness/harness.types
|
|
9
|
+
*/
|
|
10
|
+
import { HARNESS_CONSTANTS } from '../../constants.js';
|
|
11
|
+
/** Every harness id, in display order. */
|
|
12
|
+
export const HARNESS_IDS = Object.values(HARNESS_CONSTANTS.IDS);
|
|
13
|
+
/** Every login method id. */
|
|
14
|
+
export const LOGIN_METHOD_IDS = ['subscription', 'api_key', 'device'];
|
|
15
|
+
/** Terminal login states: the PTY is gone and the session no longer changes. */
|
|
16
|
+
export const TERMINAL_LOGIN_STATES = ['succeeded', 'failed', 'timed_out', 'cancelled'];
|
|
17
|
+
/**
|
|
18
|
+
* Whether a value is a known harness id.
|
|
19
|
+
*
|
|
20
|
+
* @param value - Candidate
|
|
21
|
+
* @returns True for `claude-code`, `codex-cli` or `gemini-cli`
|
|
22
|
+
*/
|
|
23
|
+
export function isHarnessId(value) {
|
|
24
|
+
return typeof value === 'string' && HARNESS_IDS.includes(value);
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Whether a value is a known login method id.
|
|
28
|
+
*
|
|
29
|
+
* @param value - Candidate
|
|
30
|
+
* @returns True for `subscription`, `api_key` or `device`
|
|
31
|
+
*/
|
|
32
|
+
export function isLoginMethodId(value) {
|
|
33
|
+
return typeof value === 'string' && LOGIN_METHOD_IDS.includes(value);
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Whether a login state is terminal (the session will not change again).
|
|
37
|
+
*
|
|
38
|
+
* @param state - Login session state
|
|
39
|
+
* @returns True for succeeded / failed / timed_out / cancelled
|
|
40
|
+
*/
|
|
41
|
+
export function isTerminalLoginState(state) {
|
|
42
|
+
return TERMINAL_LOGIN_STATES.includes(state);
|
|
43
|
+
}
|
|
44
|
+
/** A logger that drops everything (CLI default, tests). */
|
|
45
|
+
export const SILENT_HARNESS_LOGGER = {
|
|
46
|
+
info: () => undefined,
|
|
47
|
+
warn: () => undefined,
|
|
48
|
+
error: () => undefined,
|
|
49
|
+
debug: () => undefined,
|
|
50
|
+
};
|
|
51
|
+
//# sourceMappingURL=harness.types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"harness.types.js","sourceRoot":"","sources":["../../../../../../backend/src/services/harness/harness.types.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAKvD,0CAA0C;AAC1C,MAAM,CAAC,MAAM,WAAW,GAAyB,MAAM,CAAC,MAAM,CAAC,iBAAiB,CAAC,GAAG,CAAC,CAAC;AAKtF,6BAA6B;AAC7B,MAAM,CAAC,MAAM,gBAAgB,GAA6B,CAAC,cAAc,EAAE,SAAS,EAAE,QAAQ,CAAC,CAAC;AAqEhG,gFAAgF;AAChF,MAAM,CAAC,MAAM,qBAAqB,GAAiC,CAAC,WAAW,EAAE,QAAQ,EAAE,WAAW,EAAE,WAAW,CAAC,CAAC;AAmBrH;;;;;GAKG;AACH,MAAM,UAAU,WAAW,CAAC,KAAc;IACzC,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAK,WAAiC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;AACxF,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,eAAe,CAAC,KAAc;IAC7C,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAK,gBAAsC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;AAC7F,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,oBAAoB,CAAC,KAAwB;IAC5D,OAAO,qBAAqB,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;AAC9C,CAAC;AAUD,2DAA2D;AAC3D,MAAM,CAAC,MAAM,qBAAqB,GAAkB;IACnD,IAAI,EAAE,GAAG,EAAE,CAAC,SAAS;IACrB,IAAI,EAAE,GAAG,EAAE,CAAC,SAAS;IACrB,KAAK,EAAE,GAAG,EAAE,CAAC,SAAS;IACtB,KAAK,EAAE,GAAG,EAAE,CAAC,SAAS;CACtB,CAAC"}
|
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Login broker — runs a harness's own login command in a PTY and relays it.
|
|
3
|
+
*
|
|
4
|
+
* The broker knows nothing about harness APIs. It spawns the login command
|
|
5
|
+
* (`claude setup-token`, `codex login --device-auth`) in a very wide PTY,
|
|
6
|
+
* normalizes the screen and applies the harness's rule set (login-rules.ts)
|
|
7
|
+
* to find the sign-in URL, a one-time code, a "paste the code" prompt,
|
|
8
|
+
* success and failure. Front ends read the resulting {@link LoginSession}
|
|
9
|
+
* and send the user's reply back with {@link LoginBrokerService.input}.
|
|
10
|
+
*
|
|
11
|
+
* Front ends are consumers of the same events: the REST API polls
|
|
12
|
+
* {@link LoginBrokerService.get}, the CLI awaits
|
|
13
|
+
* {@link LoginBrokerService.waitForCompletion}, and Phase 2 (re-login over
|
|
14
|
+
* Slack DM) subscribes to the `update` / `finished` events.
|
|
15
|
+
*
|
|
16
|
+
* Secrets: Claude's long-lived token is captured from the screen, stored with
|
|
17
|
+
* {@link HarnessCredentialsStore.setClaudeOauthToken}, redacted from every
|
|
18
|
+
* exposed screen and scrubbed from the raw buffer. It is never logged or
|
|
19
|
+
* emitted.
|
|
20
|
+
*
|
|
21
|
+
* State machine:
|
|
22
|
+
* `starting` → `awaiting_user` (URL / code / prompt seen) → `verifying`
|
|
23
|
+
* (input sent, or the command reported success and is being confirmed) →
|
|
24
|
+
* `succeeded` | `failed`; any live state → `timed_out` (15 min) | `cancelled`.
|
|
25
|
+
* A prompt that reappears after input returns the session to `awaiting_user`.
|
|
26
|
+
*
|
|
27
|
+
* @module services/harness/login-broker.service
|
|
28
|
+
*/
|
|
29
|
+
import { EventEmitter } from 'events';
|
|
30
|
+
import { HarnessCredentialsStore } from './harness-credentials.store.js';
|
|
31
|
+
import { type HarnessId, type HarnessLogger, type LoginSession } from './harness.types.js';
|
|
32
|
+
/** The slice of a PTY the broker uses (node-pty's IPty satisfies it). */
|
|
33
|
+
export interface BrokerPty {
|
|
34
|
+
onData(listener: (data: string) => void): unknown;
|
|
35
|
+
onExit(listener: (event: {
|
|
36
|
+
exitCode: number;
|
|
37
|
+
signal?: number;
|
|
38
|
+
}) => void): unknown;
|
|
39
|
+
write(data: string): void;
|
|
40
|
+
kill(signal?: string): void;
|
|
41
|
+
}
|
|
42
|
+
/** Spawns a PTY. */
|
|
43
|
+
export type BrokerPtySpawner = (file: string, args: string[], options: {
|
|
44
|
+
cols: number;
|
|
45
|
+
rows: number;
|
|
46
|
+
cwd: string;
|
|
47
|
+
env: Record<string, string>;
|
|
48
|
+
}) => BrokerPty;
|
|
49
|
+
/** Events emitted by the broker. Listeners receive a {@link LoginSession} (never a secret). */
|
|
50
|
+
export declare const LOGIN_BROKER_EVENTS: {
|
|
51
|
+
/** Any change to a session */
|
|
52
|
+
readonly UPDATE: "update";
|
|
53
|
+
/** A session reached a terminal state */
|
|
54
|
+
readonly FINISHED: "finished";
|
|
55
|
+
};
|
|
56
|
+
/** Error codes the REST layer maps to HTTP statuses. */
|
|
57
|
+
export type LoginBrokerErrorCode = 'unknown_harness' | 'unsupported_method' | 'not_installed' | 'spawn_failed' | 'not_found' | 'not_active';
|
|
58
|
+
/** Broker error with a machine-readable code. */
|
|
59
|
+
export declare class LoginBrokerError extends Error {
|
|
60
|
+
readonly code: LoginBrokerErrorCode;
|
|
61
|
+
/**
|
|
62
|
+
* @param code - Machine-readable code
|
|
63
|
+
* @param message - Human-readable message (never contains a secret)
|
|
64
|
+
*/
|
|
65
|
+
constructor(code: LoginBrokerErrorCode, message: string);
|
|
66
|
+
}
|
|
67
|
+
/** Injectable dependencies. */
|
|
68
|
+
export interface LoginBrokerDeps {
|
|
69
|
+
spawnPty?: BrokerPtySpawner;
|
|
70
|
+
/** PATH lookup for the login command */
|
|
71
|
+
resolveCommand?: (command: string, envPath: string) => string | null;
|
|
72
|
+
env?: NodeJS.ProcessEnv;
|
|
73
|
+
homeDir?: string;
|
|
74
|
+
credentials?: HarnessCredentialsStore;
|
|
75
|
+
/** Confirms a login with the harness's own status command (Codex) */
|
|
76
|
+
verify?: (harnessId: HarnessId) => Promise<boolean>;
|
|
77
|
+
/** Records Claude's first-run answers after a Claude login */
|
|
78
|
+
prepareClaudeConfig?: () => void;
|
|
79
|
+
now?: () => number;
|
|
80
|
+
idFactory?: () => string;
|
|
81
|
+
logger?: HarnessLogger;
|
|
82
|
+
timeoutMs?: number;
|
|
83
|
+
}
|
|
84
|
+
/** Runs harness login commands in PTYs and tracks their sessions. */
|
|
85
|
+
export declare class LoginBrokerService extends EventEmitter {
|
|
86
|
+
private readonly spawnPty;
|
|
87
|
+
private readonly resolveCommand;
|
|
88
|
+
private readonly env;
|
|
89
|
+
private readonly homeDir;
|
|
90
|
+
private readonly credentials;
|
|
91
|
+
private readonly verify;
|
|
92
|
+
private readonly prepareClaudeConfig;
|
|
93
|
+
private readonly now;
|
|
94
|
+
private readonly idFactory;
|
|
95
|
+
private readonly logger;
|
|
96
|
+
private readonly timeoutMs;
|
|
97
|
+
private readonly sessions;
|
|
98
|
+
/** Sessions whose verification is in flight. */
|
|
99
|
+
private readonly verifying;
|
|
100
|
+
/**
|
|
101
|
+
* @param deps - Injectable dependencies (all optional)
|
|
102
|
+
*/
|
|
103
|
+
constructor(deps?: LoginBrokerDeps);
|
|
104
|
+
/**
|
|
105
|
+
* Environment for the login PTY: the harness PATH, no owner API token, no
|
|
106
|
+
* nested-Claude-session markers, and a no-op BROWSER so the harness does
|
|
107
|
+
* not try to open a browser on the server.
|
|
108
|
+
*
|
|
109
|
+
* @returns String-only env map
|
|
110
|
+
*/
|
|
111
|
+
buildEnv(): Record<string, string>;
|
|
112
|
+
/**
|
|
113
|
+
* Start a login session, or return the live one for this harness.
|
|
114
|
+
*
|
|
115
|
+
* @param harnessId - Harness id
|
|
116
|
+
* @param method - Broker login method (`subscription`, `device`)
|
|
117
|
+
* @returns The session
|
|
118
|
+
* @throws LoginBrokerError unknown_harness | unsupported_method | not_installed | spawn_failed
|
|
119
|
+
*/
|
|
120
|
+
start(harnessId: string, method: string): LoginSession;
|
|
121
|
+
/**
|
|
122
|
+
* Read a session.
|
|
123
|
+
*
|
|
124
|
+
* @param sessionId - Session id
|
|
125
|
+
* @returns The session
|
|
126
|
+
* @throws LoginBrokerError not_found
|
|
127
|
+
*/
|
|
128
|
+
get(sessionId: string): LoginSession;
|
|
129
|
+
/**
|
|
130
|
+
* The live (non-terminal) session for a harness, if any.
|
|
131
|
+
*
|
|
132
|
+
* @param harnessId - Harness id
|
|
133
|
+
* @returns The session, or null
|
|
134
|
+
*/
|
|
135
|
+
getActiveSession(harnessId: string): LoginSession | null;
|
|
136
|
+
/**
|
|
137
|
+
* Type the user's reply into the PTY, followed by Enter.
|
|
138
|
+
*
|
|
139
|
+
* @param sessionId - Session id
|
|
140
|
+
* @param text - What the user typed (e.g. the code from platform.claude.com)
|
|
141
|
+
* @returns The session
|
|
142
|
+
* @throws LoginBrokerError not_found | not_active
|
|
143
|
+
*/
|
|
144
|
+
input(sessionId: string, text: string): LoginSession;
|
|
145
|
+
/**
|
|
146
|
+
* Cancel a session (kills the PTY). Cancelling a finished session is a no-op.
|
|
147
|
+
*
|
|
148
|
+
* @param sessionId - Session id
|
|
149
|
+
* @returns The session
|
|
150
|
+
* @throws LoginBrokerError not_found
|
|
151
|
+
*/
|
|
152
|
+
cancel(sessionId: string): LoginSession;
|
|
153
|
+
/**
|
|
154
|
+
* Resolve when the session reaches a terminal state.
|
|
155
|
+
*
|
|
156
|
+
* @param sessionId - Session id
|
|
157
|
+
* @returns The final session
|
|
158
|
+
* @throws LoginBrokerError not_found
|
|
159
|
+
*/
|
|
160
|
+
waitForCompletion(sessionId: string): Promise<LoginSession>;
|
|
161
|
+
/** Cancel every live session (backend shutdown, CLI exit). */
|
|
162
|
+
shutdown(): void;
|
|
163
|
+
/**
|
|
164
|
+
* Session record or a not_found error.
|
|
165
|
+
*
|
|
166
|
+
* @param sessionId - Session id
|
|
167
|
+
* @returns The record
|
|
168
|
+
* @throws LoginBrokerError not_found
|
|
169
|
+
*/
|
|
170
|
+
private requireRecord;
|
|
171
|
+
/**
|
|
172
|
+
* Append PTY output and re-evaluate the rules.
|
|
173
|
+
*
|
|
174
|
+
* @param record - Session record
|
|
175
|
+
* @param data - Output chunk
|
|
176
|
+
*/
|
|
177
|
+
private handleData;
|
|
178
|
+
/**
|
|
179
|
+
* Apply the rule set to the current screen and move the state machine.
|
|
180
|
+
*
|
|
181
|
+
* @param record - Session record
|
|
182
|
+
* @param final - The process has exited
|
|
183
|
+
*/
|
|
184
|
+
private evaluate;
|
|
185
|
+
/**
|
|
186
|
+
* Handle a reported success: store the secret (Claude) or confirm (Codex).
|
|
187
|
+
*
|
|
188
|
+
* @param record - Session record
|
|
189
|
+
* @param secret - Captured credential, when the rule set has one
|
|
190
|
+
*/
|
|
191
|
+
private complete;
|
|
192
|
+
/**
|
|
193
|
+
* Confirm a login with the harness's status command.
|
|
194
|
+
*
|
|
195
|
+
* @param record - Session record
|
|
196
|
+
*/
|
|
197
|
+
private confirm;
|
|
198
|
+
/**
|
|
199
|
+
* Save a captured credential. Never logs it.
|
|
200
|
+
*
|
|
201
|
+
* @param record - Session record
|
|
202
|
+
* @param secret - The credential
|
|
203
|
+
*/
|
|
204
|
+
private storeSecret;
|
|
205
|
+
/**
|
|
206
|
+
* The login command exited.
|
|
207
|
+
*
|
|
208
|
+
* @param record - Session record
|
|
209
|
+
* @param exitCode - Process exit code
|
|
210
|
+
*/
|
|
211
|
+
private handleExit;
|
|
212
|
+
/**
|
|
213
|
+
* Move a session to a terminal state and release the PTY.
|
|
214
|
+
*
|
|
215
|
+
* @param record - Session record
|
|
216
|
+
* @param state - Terminal state
|
|
217
|
+
* @param message - Message for the user
|
|
218
|
+
*/
|
|
219
|
+
private finish;
|
|
220
|
+
/**
|
|
221
|
+
* Apply a patch, bump `updatedAt` and emit `update`.
|
|
222
|
+
*
|
|
223
|
+
* @param record - Session record
|
|
224
|
+
* @param patch - Fields to change
|
|
225
|
+
*/
|
|
226
|
+
private update;
|
|
227
|
+
/**
|
|
228
|
+
* Tail of the screen, secrets redacted.
|
|
229
|
+
*
|
|
230
|
+
* @param record - Session record
|
|
231
|
+
* @param text - Normalized text
|
|
232
|
+
* @returns Exposed screen text
|
|
233
|
+
*/
|
|
234
|
+
private exposedScreen;
|
|
235
|
+
/** Forget finished sessions older than the retention window. */
|
|
236
|
+
private prune;
|
|
237
|
+
}
|
|
238
|
+
//# sourceMappingURL=login-broker.service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"login-broker.service.d.ts","sourceRoot":"","sources":["../../../../../../backend/src/services/harness/login-broker.service.ts"],"names":[],"mappings":"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"}
|