@groundnuty/macf 0.2.0-rc.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/.build-info.json +4 -0
- package/dist/cli/build-info.d.ts +38 -0
- package/dist/cli/build-info.d.ts.map +1 -0
- package/dist/cli/build-info.js +119 -0
- package/dist/cli/build-info.js.map +1 -0
- package/dist/cli/claude-sh.d.ts +42 -0
- package/dist/cli/claude-sh.d.ts.map +1 -0
- package/dist/cli/claude-sh.js +247 -0
- package/dist/cli/claude-sh.js.map +1 -0
- package/dist/cli/commands/cd.d.ts +6 -0
- package/dist/cli/commands/cd.d.ts.map +1 -0
- package/dist/cli/commands/cd.js +17 -0
- package/dist/cli/commands/cd.js.map +1 -0
- package/dist/cli/commands/certs.d.ts +33 -0
- package/dist/cli/commands/certs.d.ts.map +1 -0
- package/dist/cli/commands/certs.js +233 -0
- package/dist/cli/commands/certs.js.map +1 -0
- package/dist/cli/commands/doctor.d.ts +91 -0
- package/dist/cli/commands/doctor.d.ts.map +1 -0
- package/dist/cli/commands/doctor.js +235 -0
- package/dist/cli/commands/doctor.js.map +1 -0
- package/dist/cli/commands/init.d.ts +37 -0
- package/dist/cli/commands/init.d.ts.map +1 -0
- package/dist/cli/commands/init.js +279 -0
- package/dist/cli/commands/init.js.map +1 -0
- package/dist/cli/commands/list.d.ts +5 -0
- package/dist/cli/commands/list.d.ts.map +1 -0
- package/dist/cli/commands/list.js +21 -0
- package/dist/cli/commands/list.js.map +1 -0
- package/dist/cli/commands/migrate-ca-key.d.ts +36 -0
- package/dist/cli/commands/migrate-ca-key.d.ts.map +1 -0
- package/dist/cli/commands/migrate-ca-key.js +92 -0
- package/dist/cli/commands/migrate-ca-key.js.map +1 -0
- package/dist/cli/commands/peers.d.ts +8 -0
- package/dist/cli/commands/peers.d.ts.map +1 -0
- package/dist/cli/commands/peers.js +45 -0
- package/dist/cli/commands/peers.js.map +1 -0
- package/dist/cli/commands/repo-init.d.ts +43 -0
- package/dist/cli/commands/repo-init.d.ts.map +1 -0
- package/dist/cli/commands/repo-init.js +304 -0
- package/dist/cli/commands/repo-init.js.map +1 -0
- package/dist/cli/commands/rules-refresh.d.ts +14 -0
- package/dist/cli/commands/rules-refresh.d.ts.map +1 -0
- package/dist/cli/commands/rules-refresh.js +67 -0
- package/dist/cli/commands/rules-refresh.js.map +1 -0
- package/dist/cli/commands/self-update.d.ts +14 -0
- package/dist/cli/commands/self-update.d.ts.map +1 -0
- package/dist/cli/commands/self-update.js +112 -0
- package/dist/cli/commands/self-update.js.map +1 -0
- package/dist/cli/commands/status.d.ts +9 -0
- package/dist/cli/commands/status.d.ts.map +1 -0
- package/dist/cli/commands/status.js +90 -0
- package/dist/cli/commands/status.js.map +1 -0
- package/dist/cli/commands/update.d.ts +25 -0
- package/dist/cli/commands/update.d.ts.map +1 -0
- package/dist/cli/commands/update.js +316 -0
- package/dist/cli/commands/update.js.map +1 -0
- package/dist/cli/config.d.ts +103 -0
- package/dist/cli/config.d.ts.map +1 -0
- package/dist/cli/config.js +224 -0
- package/dist/cli/config.js.map +1 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +245 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/plugin-fetcher.d.ts +20 -0
- package/dist/cli/plugin-fetcher.d.ts.map +1 -0
- package/dist/cli/plugin-fetcher.js +83 -0
- package/dist/cli/plugin-fetcher.js.map +1 -0
- package/dist/cli/prompt.d.ts +17 -0
- package/dist/cli/prompt.d.ts.map +1 -0
- package/dist/cli/prompt.js +109 -0
- package/dist/cli/prompt.js.map +1 -0
- package/dist/cli/registry-helper.d.ts +11 -0
- package/dist/cli/registry-helper.d.ts.map +1 -0
- package/dist/cli/registry-helper.js +18 -0
- package/dist/cli/registry-helper.js.map +1 -0
- package/dist/cli/rules.d.ts +39 -0
- package/dist/cli/rules.d.ts.map +1 -0
- package/dist/cli/rules.js +112 -0
- package/dist/cli/rules.js.map +1 -0
- package/dist/cli/settings-writer.d.ts +97 -0
- package/dist/cli/settings-writer.d.ts.map +1 -0
- package/dist/cli/settings-writer.js +270 -0
- package/dist/cli/settings-writer.js.map +1 -0
- package/dist/cli/version-resolver.d.ts +73 -0
- package/dist/cli/version-resolver.d.ts.map +1 -0
- package/dist/cli/version-resolver.js +238 -0
- package/dist/cli/version-resolver.js.map +1 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +22 -0
- package/dist/index.js.map +1 -0
- package/dist/plugin/bin/macf-plugin-cli.d.ts +13 -0
- package/dist/plugin/bin/macf-plugin-cli.d.ts.map +1 -0
- package/dist/plugin/bin/macf-plugin-cli.js +127 -0
- package/dist/plugin/bin/macf-plugin-cli.js.map +1 -0
- package/dist/plugin/lib/format.d.ts +40 -0
- package/dist/plugin/lib/format.d.ts.map +1 -0
- package/dist/plugin/lib/format.js +137 -0
- package/dist/plugin/lib/format.js.map +1 -0
- package/dist/plugin/lib/health.d.ts +2 -0
- package/dist/plugin/lib/health.d.ts.map +1 -0
- package/dist/plugin/lib/health.js +6 -0
- package/dist/plugin/lib/health.js.map +1 -0
- package/dist/plugin/lib/index.d.ts +7 -0
- package/dist/plugin/lib/index.d.ts.map +1 -0
- package/dist/plugin/lib/index.js +5 -0
- package/dist/plugin/lib/index.js.map +1 -0
- package/dist/plugin/lib/registry.d.ts +18 -0
- package/dist/plugin/lib/registry.d.ts.map +1 -0
- package/dist/plugin/lib/registry.js +17 -0
- package/dist/plugin/lib/registry.js.map +1 -0
- package/dist/plugin/lib/work.d.ts +13 -0
- package/dist/plugin/lib/work.d.ts.map +1 -0
- package/dist/plugin/lib/work.js +27 -0
- package/dist/plugin/lib/work.js.map +1 -0
- package/package.json +43 -0
- package/plugin/rules/coordination.md +224 -0
- package/scripts/check-gh-token.sh +102 -0
- package/scripts/macf-gh-token.sh +130 -0
- package/scripts/macf-whoami.sh +51 -0
- package/scripts/tmux-send-to-claude.sh +51 -0
- package/scripts/write-build-info.mjs +48 -0
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, writeFileSync } from 'node:fs';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { readAgentConfig, agentCertPath, agentKeyPath, caCertPath as caCertPathFor, caKeyPath as caKeyPathFor, caDir, tokenSourceFromConfig, } from '../config.js';
|
|
4
|
+
import { createCA, backupCAKey, recoverCAKey, loadCA } from '@groundnuty/macf-core';
|
|
5
|
+
import { generateAgentCert, generateClientCert } from '@groundnuty/macf-core';
|
|
6
|
+
import { createClientFromConfig } from '../registry-helper.js';
|
|
7
|
+
import { createRegistryFromConfig } from '@groundnuty/macf-core';
|
|
8
|
+
import { generateToken } from '@groundnuty/macf-core';
|
|
9
|
+
import { promptPassword, PromptCancelled } from '../prompt.js';
|
|
10
|
+
import { toVariableSegment } from '@groundnuty/macf-core';
|
|
11
|
+
const ROUTING_CLIENT_CN = 'routing-action';
|
|
12
|
+
const DEFAULT_VALIDITY_DAYS = 365;
|
|
13
|
+
const VALIDITY_WARN_DAYS = 730;
|
|
14
|
+
async function promptPassphrase(message) {
|
|
15
|
+
try {
|
|
16
|
+
return await promptPassword({ message });
|
|
17
|
+
}
|
|
18
|
+
catch (err) {
|
|
19
|
+
if (err instanceof PromptCancelled) {
|
|
20
|
+
console.error('\nCancelled.');
|
|
21
|
+
process.exit(130); // 128 + SIGINT
|
|
22
|
+
}
|
|
23
|
+
throw err;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
function getVariablesClient(config, token) {
|
|
27
|
+
if (!config)
|
|
28
|
+
throw new Error('No macf-agent.json found. Run `macf init` first.');
|
|
29
|
+
return createClientFromConfig(config.registry, token);
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* macf certs init: create CA, upload cert + encrypted key to registry
|
|
33
|
+
*/
|
|
34
|
+
export async function certsInit(projectDir) {
|
|
35
|
+
const config = readAgentConfig(projectDir);
|
|
36
|
+
if (!config) {
|
|
37
|
+
console.error('No macf-agent.json found. Run `macf init` first.');
|
|
38
|
+
process.exitCode = 1;
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
const token = await generateToken(tokenSourceFromConfig(projectDir, config));
|
|
42
|
+
const client = getVariablesClient(config, token);
|
|
43
|
+
// Per-project CA paths. mkdir with 0o700 — CA key is the most sensitive secret.
|
|
44
|
+
const projectCaDir = caDir(config.project);
|
|
45
|
+
mkdirSync(projectCaDir, { recursive: true, mode: 0o700 });
|
|
46
|
+
const caCertP = caCertPathFor(config.project);
|
|
47
|
+
const caKeyP = caKeyPathFor(config.project);
|
|
48
|
+
console.log(`Creating CA for project "${config.project}"...`);
|
|
49
|
+
const ca = await createCA({
|
|
50
|
+
project: config.project,
|
|
51
|
+
certPath: caCertP,
|
|
52
|
+
keyPath: caKeyP,
|
|
53
|
+
client,
|
|
54
|
+
});
|
|
55
|
+
console.log(` CA cert: ${caCertP}`);
|
|
56
|
+
console.log(` CA key: ${caKeyP}`);
|
|
57
|
+
console.log(` CA cert uploaded to registry as ${toVariableSegment(config.project)}_CA_CERT`);
|
|
58
|
+
// Encrypted backup
|
|
59
|
+
const passphrase = await promptPassphrase('Enter passphrase for CA key backup: ');
|
|
60
|
+
if (!passphrase) {
|
|
61
|
+
console.warn('No passphrase provided — skipping encrypted backup.');
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
await backupCAKey({
|
|
65
|
+
project: config.project,
|
|
66
|
+
keyPem: ca.keyPem,
|
|
67
|
+
passphrase,
|
|
68
|
+
client,
|
|
69
|
+
});
|
|
70
|
+
console.log(` Encrypted CA key backed up to registry as ${toVariableSegment(config.project)}_CA_KEY_ENCRYPTED`);
|
|
71
|
+
console.log('\nCA initialization complete.');
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* macf certs recover: download and decrypt CA key from registry
|
|
75
|
+
*/
|
|
76
|
+
export async function certsRecover(projectDir) {
|
|
77
|
+
const config = readAgentConfig(projectDir);
|
|
78
|
+
if (!config) {
|
|
79
|
+
console.error('No macf-agent.json found. Run `macf init` first.');
|
|
80
|
+
process.exitCode = 1;
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
const token = await generateToken(tokenSourceFromConfig(projectDir, config));
|
|
84
|
+
const client = getVariablesClient(config, token);
|
|
85
|
+
const passphrase = await promptPassphrase('Enter passphrase for CA key recovery: ');
|
|
86
|
+
if (!passphrase) {
|
|
87
|
+
console.error('Passphrase is required for recovery.');
|
|
88
|
+
process.exitCode = 1;
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
// Per-project CA paths. mkdir with 0o700.
|
|
92
|
+
mkdirSync(caDir(config.project), { recursive: true, mode: 0o700 });
|
|
93
|
+
const caKeyP = caKeyPathFor(config.project);
|
|
94
|
+
console.log('Recovering CA key from registry...');
|
|
95
|
+
await recoverCAKey({
|
|
96
|
+
project: config.project,
|
|
97
|
+
passphrase,
|
|
98
|
+
keyPath: caKeyP,
|
|
99
|
+
client,
|
|
100
|
+
});
|
|
101
|
+
console.log(` CA key recovered to: ${caKeyP}`);
|
|
102
|
+
console.log('Recovery complete.');
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* macf certs rotate: regenerate agent cert with existing CA
|
|
106
|
+
*/
|
|
107
|
+
export async function certsRotate(projectDir) {
|
|
108
|
+
const config = readAgentConfig(projectDir);
|
|
109
|
+
if (!config) {
|
|
110
|
+
console.error('No macf-agent.json found. Run `macf init` first.');
|
|
111
|
+
process.exitCode = 1;
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
const caCertP = caCertPathFor(config.project);
|
|
115
|
+
const caKeyP = caKeyPathFor(config.project);
|
|
116
|
+
if (!existsSync(caCertP) || !existsSync(caKeyP)) {
|
|
117
|
+
console.error('CA cert or key not found. Run `macf certs init` or `macf certs recover` first.');
|
|
118
|
+
process.exitCode = 1;
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
const ca = loadCA(caCertP, caKeyP);
|
|
122
|
+
const certP = agentCertPath(projectDir);
|
|
123
|
+
const keyP = agentKeyPath(projectDir);
|
|
124
|
+
console.log(`Rotating certificate for "${config.agent_name}"...`);
|
|
125
|
+
await generateAgentCert({
|
|
126
|
+
agentName: config.agent_name,
|
|
127
|
+
caCertPem: ca.certPem,
|
|
128
|
+
caKeyPem: ca.keyPem,
|
|
129
|
+
// Flow the advertised host into the cert SAN so TLS hostname
|
|
130
|
+
// verification succeeds when an off-box consumer (routing Action,
|
|
131
|
+
// sibling agent) connects over the network. macf#178 Gap 3.
|
|
132
|
+
...(config.advertise_host !== undefined ? { advertiseHost: config.advertise_host } : {}),
|
|
133
|
+
certPath: certP,
|
|
134
|
+
keyPath: keyP,
|
|
135
|
+
});
|
|
136
|
+
console.log(` Cert: ${certP}`);
|
|
137
|
+
console.log(` Key: ${keyP}`);
|
|
138
|
+
console.log('Rotation complete.');
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* macf certs issue-routing-client: mint a CA-signed client cert with
|
|
142
|
+
* CN=routing-action for use by the macf-actions routing workflow
|
|
143
|
+
* (mTLS variant, macf-actions#8). The routing Action presents this
|
|
144
|
+
* cert when POSTing to each agent's /notify endpoint.
|
|
145
|
+
*
|
|
146
|
+
* Requires the CA key on disk — this command is local-only, never
|
|
147
|
+
* driven from the registry-encrypted backup. The resulting cert/key
|
|
148
|
+
* is meant to be pasted into the consumer repo's GHA secrets; the
|
|
149
|
+
* operator is expected to handle the paste securely (not commit it).
|
|
150
|
+
*
|
|
151
|
+
* If --out-dir is omitted, both PEMs are printed to stdout along with
|
|
152
|
+
* single-line base64 blobs for easy GHA-secret paste. If --out-dir
|
|
153
|
+
* is provided, files are written to disk at 0o600 / 0o644.
|
|
154
|
+
*/
|
|
155
|
+
export async function issueRoutingClient(projectDir, opts = {}) {
|
|
156
|
+
const config = readAgentConfig(projectDir);
|
|
157
|
+
if (!config) {
|
|
158
|
+
console.error('No macf-agent.json found. Run `macf init` first.');
|
|
159
|
+
process.exitCode = 1;
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
const validityDays = opts.validityDays ?? DEFAULT_VALIDITY_DAYS;
|
|
163
|
+
if (!Number.isInteger(validityDays) || validityDays < 1) {
|
|
164
|
+
console.error(`--validity-days must be a positive integer (got "${opts.validityDays}")`);
|
|
165
|
+
process.exitCode = 1;
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
if (validityDays > VALIDITY_WARN_DAYS) {
|
|
169
|
+
console.warn(`Warning: validity of ${validityDays} days exceeds ${VALIDITY_WARN_DAYS} days. ` +
|
|
170
|
+
`Long-lived client certs increase blast radius if the key leaks; ` +
|
|
171
|
+
`consider a shorter rotation cadence.`);
|
|
172
|
+
}
|
|
173
|
+
const caCertP = caCertPathFor(config.project);
|
|
174
|
+
const caKeyP = caKeyPathFor(config.project);
|
|
175
|
+
if (!existsSync(caCertP) || !existsSync(caKeyP)) {
|
|
176
|
+
console.error('CA cert or key not found on disk. This command requires a local CA key — ' +
|
|
177
|
+
'run `macf certs init` (first time) or `macf certs recover` (if CA lives in registry only).');
|
|
178
|
+
process.exitCode = 1;
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
const ca = loadCA(caCertP, caKeyP);
|
|
182
|
+
// Collision guard: refuse if an existing agent is registered under
|
|
183
|
+
// the routing-client CN. Prevents accidental overlap with a real
|
|
184
|
+
// agent named `routing-action`.
|
|
185
|
+
const token = await generateToken(tokenSourceFromConfig(projectDir, config));
|
|
186
|
+
const registry = createRegistryFromConfig(config.registry, config.project, token);
|
|
187
|
+
const existing = await registry.get(ROUTING_CLIENT_CN);
|
|
188
|
+
if (existing !== null) {
|
|
189
|
+
console.error(`An agent named "${ROUTING_CLIENT_CN}" is already registered. ` +
|
|
190
|
+
`Rename or remove that agent before issuing the routing-client cert, or ` +
|
|
191
|
+
`coordinate CN separation via a follow-up issue.`);
|
|
192
|
+
process.exitCode = 1;
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
console.log(`Issuing routing-client cert for project "${config.project}"...`);
|
|
196
|
+
console.log(` CN: ${ROUTING_CLIENT_CN}`);
|
|
197
|
+
console.log(` Validity: ${validityDays} days`);
|
|
198
|
+
const result = await generateClientCert({
|
|
199
|
+
commonName: ROUTING_CLIENT_CN,
|
|
200
|
+
validityDays,
|
|
201
|
+
caCertPem: ca.certPem,
|
|
202
|
+
caKeyPem: ca.keyPem,
|
|
203
|
+
});
|
|
204
|
+
if (opts.outDir) {
|
|
205
|
+
mkdirSync(opts.outDir, { recursive: true, mode: 0o700 });
|
|
206
|
+
const certOut = join(opts.outDir, 'routing-action-cert.pem');
|
|
207
|
+
const keyOut = join(opts.outDir, 'routing-action-key.pem');
|
|
208
|
+
writeFileSync(certOut, result.certPem, { mode: 0o644 });
|
|
209
|
+
writeFileSync(keyOut, result.keyPem, { mode: 0o600 });
|
|
210
|
+
console.log(` Cert written: ${certOut}`);
|
|
211
|
+
console.log(` Key written: ${keyOut}`);
|
|
212
|
+
console.log('');
|
|
213
|
+
console.log('GHA-secret paste format (for your consumer repo):');
|
|
214
|
+
console.log(' ROUTING_CLIENT_CERT = ' + Buffer.from(result.certPem).toString('base64'));
|
|
215
|
+
console.log(' ROUTING_CLIENT_KEY = ' + Buffer.from(result.keyPem).toString('base64'));
|
|
216
|
+
}
|
|
217
|
+
else {
|
|
218
|
+
console.log('');
|
|
219
|
+
console.log('─── routing-action cert (PEM) ───');
|
|
220
|
+
console.log(result.certPem);
|
|
221
|
+
console.log('─── routing-action key (PEM, KEEP SECRET) ───');
|
|
222
|
+
console.log(result.keyPem);
|
|
223
|
+
console.log('─── GHA-secret paste format ───');
|
|
224
|
+
console.log('ROUTING_CLIENT_CERT = ' + Buffer.from(result.certPem).toString('base64'));
|
|
225
|
+
console.log('ROUTING_CLIENT_KEY = ' + Buffer.from(result.keyPem).toString('base64'));
|
|
226
|
+
}
|
|
227
|
+
console.log('');
|
|
228
|
+
console.log('Next steps (see macf-actions#8):');
|
|
229
|
+
console.log(' 1. Paste ROUTING_CLIENT_CERT and ROUTING_CLIENT_KEY into your consumer repo\'s GHA secrets');
|
|
230
|
+
console.log(' 2. Upgrade the caller workflow to macf-actions @v2.x when available');
|
|
231
|
+
console.log(' 3. Remove the AGENT_SSH_KEY secret once mTLS transport is proven');
|
|
232
|
+
}
|
|
233
|
+
//# sourceMappingURL=certs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"certs.js","sourceRoot":"","sources":["../../../src/cli/commands/certs.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* One required permission entry from DR-019.
|
|
3
|
+
*/
|
|
4
|
+
export interface RequiredPermission {
|
|
5
|
+
readonly name: string;
|
|
6
|
+
readonly level: 'read' | 'write';
|
|
7
|
+
readonly why: string;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* DR-019 permission doctrine. Keep in sync with
|
|
11
|
+
* design/decisions/DR-019-app-permissions.md and
|
|
12
|
+
* templates/macf-app-manifest.json.
|
|
13
|
+
*
|
|
14
|
+
* Names here are GitHub's CANONICAL API names (as returned by
|
|
15
|
+
* `GET /app/installations/:id` in the `permissions` field), which
|
|
16
|
+
* differ from the App settings UI labels for some entries — notably
|
|
17
|
+
* Variables → `actions_variables`. We use canonical names everywhere
|
|
18
|
+
* to avoid false negatives (an installation with `actions_variables`
|
|
19
|
+
* would be flagged as missing `variables` if we used the UI label).
|
|
20
|
+
*/
|
|
21
|
+
export declare const MACF_REQUIRED_PERMISSIONS: readonly RequiredPermission[];
|
|
22
|
+
export interface DoctorFinding {
|
|
23
|
+
/** Missing: the token has no entry at all for this permission. */
|
|
24
|
+
readonly missing: readonly RequiredPermission[];
|
|
25
|
+
/** Present but at a lower level than required (`read` where we want `write`). */
|
|
26
|
+
readonly insufficient: readonly {
|
|
27
|
+
readonly required: RequiredPermission;
|
|
28
|
+
readonly actual: string;
|
|
29
|
+
}[];
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Pure comparison: given the actual permission map from a token response,
|
|
33
|
+
* return what's missing or insufficient against MACF_REQUIRED_PERMISSIONS.
|
|
34
|
+
*/
|
|
35
|
+
export declare function diffPermissions(actual: Readonly<Record<string, string>>): DoctorFinding;
|
|
36
|
+
/**
|
|
37
|
+
* Symbol + label for the output table. Exported so tests can assert on it.
|
|
38
|
+
*/
|
|
39
|
+
export declare function formatPermissionRow(req: RequiredPermission, actual: string | undefined): string;
|
|
40
|
+
/**
|
|
41
|
+
* Result of the sandbox-filesystem check (macf#202). PASS iff the
|
|
42
|
+
* workspace's `.claude/settings.json` has `/proc/self/fd` in
|
|
43
|
+
* `sandbox.filesystem.allowRead`. FAIL if absent, or if reading the
|
|
44
|
+
* file threw (malformed JSON → we don't silently report PASS).
|
|
45
|
+
*
|
|
46
|
+
* Note: an earlier CLI version wrote `/proc/self/fd/**` (glob) which
|
|
47
|
+
* the sandbox treated as a literal — silently didn't match; macf#208
|
|
48
|
+
* corrected the pattern to bare `/proc/self/fd`.
|
|
49
|
+
*/
|
|
50
|
+
export interface SandboxFdCheck {
|
|
51
|
+
readonly status: 'PASS' | 'FAIL';
|
|
52
|
+
/** Human-readable diagnostic — e.g. JSON parse error message. Empty on PASS. */
|
|
53
|
+
readonly detail: string;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Pure check: does this workspace's `.claude/settings.json` contain
|
|
57
|
+
* the `/proc/self/fd` sandbox pattern? See macf#200 for why this
|
|
58
|
+
* matters (without it every Bash tool call fails on the harness fd),
|
|
59
|
+
* and macf#208 for why the pattern is bare (not a glob).
|
|
60
|
+
*
|
|
61
|
+
* Uses `getSandboxAllowRead` from `settings-writer.ts` so the JSON-
|
|
62
|
+
* read + deep-narrow logic lives in one place. Malformed JSON
|
|
63
|
+
* surfaces as a FAIL with the parse error in `detail` — operator
|
|
64
|
+
* still needs to see what broke.
|
|
65
|
+
*/
|
|
66
|
+
export declare function checkSandboxFdAllowRead(workspaceDir: string): SandboxFdCheck;
|
|
67
|
+
/**
|
|
68
|
+
* Format a non-leaking error message when `gh token generate --jwt` returns
|
|
69
|
+
* output that doesn't look like a JWT. Shows only the first 6 characters
|
|
70
|
+
* plus length — enough to distinguish empty / error-message / binary-garbage
|
|
71
|
+
* / genuinely-wrong-prefix, without exposing credential material if the
|
|
72
|
+
* branch fires on a genuinely-valid JWT due to a locale/whitespace/plugin
|
|
73
|
+
* edge case. See #86. Exported for unit tests.
|
|
74
|
+
*/
|
|
75
|
+
export declare function describeNonJwtOutput(jwt: string): string;
|
|
76
|
+
/**
|
|
77
|
+
* Fetch the installation's GRANTED permissions by querying
|
|
78
|
+
* `GET /app/installations/:id` with an App JWT. We do NOT use the
|
|
79
|
+
* install-token response's `permissions` field here — it doesn't
|
|
80
|
+
* surface all granted permissions (verified empirically: an App with
|
|
81
|
+
* `actions_variables: write` may report an incomplete set in the
|
|
82
|
+
* install-token response but the full set via JWT query). See
|
|
83
|
+
* discussion on issue #74 for the evidence.
|
|
84
|
+
*/
|
|
85
|
+
export declare function fetchInstallationPermissions(appId: string, installId: string, keyPath: string): Promise<Record<string, string>>;
|
|
86
|
+
/**
|
|
87
|
+
* Main entry for `macf doctor`. Returns the shell exit code: 0 if all
|
|
88
|
+
* required permissions are present, 1 if any are missing or insufficient.
|
|
89
|
+
*/
|
|
90
|
+
export declare function runDoctor(projectDir: string): Promise<number>;
|
|
91
|
+
//# sourceMappingURL=doctor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/doctor.ts"],"names":[],"mappings":"AAoBA;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC;IACjC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;CACtB;AAED;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,yBAAyB,EAAE,SAAS,kBAAkB,EAQlE,CAAC;AAEF,MAAM,WAAW,aAAa;IAC5B,kEAAkE;IAClE,QAAQ,CAAC,OAAO,EAAE,SAAS,kBAAkB,EAAE,CAAC;IAChD,iFAAiF;IACjF,QAAQ,CAAC,YAAY,EAAE,SAAS;QAC9B,QAAQ,CAAC,QAAQ,EAAE,kBAAkB,CAAC;QACtC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;KACzB,EAAE,CAAC;CACL;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,GAAG,aAAa,CAgBvF;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CACjC,GAAG,EAAE,kBAAkB,EACvB,MAAM,EAAE,MAAM,GAAG,SAAS,GACzB,MAAM,CAWR;AAED;;;;;;;;;GASG;AACH,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC;IACjC,gFAAgF;IAChF,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,uBAAuB,CAAC,YAAY,EAAE,MAAM,GAAG,cAAc,CAc5E;AAED;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAMxD;AAED;;;;;;;;GAQG;AACH,wBAAsB,4BAA4B,CAChD,KAAK,EAAE,MAAM,EACb,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CA6CjC;AAED;;;GAGG;AACH,wBAAsB,SAAS,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAsEnE"}
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* macf doctor — verify the workspace's bot token satisfies the MACF App
|
|
3
|
+
* permission doctrine (DR-019).
|
|
4
|
+
*
|
|
5
|
+
* GitHub's installation-token response body includes the permissions
|
|
6
|
+
* granted to the installation, so we don't need to probe individual
|
|
7
|
+
* endpoints: one `gh token generate` (without --token-only) gives us
|
|
8
|
+
* the full permission map. Compare against the required set; print a
|
|
9
|
+
* formatted checklist; exit 0 if satisfied, 1 if not.
|
|
10
|
+
*
|
|
11
|
+
* This is the automated counterpart to DR-019's manual verification
|
|
12
|
+
* section. Run at onboarding time or whenever routing breaks for a
|
|
13
|
+
* reason that smells like a missing permission (401 on a specific
|
|
14
|
+
* endpoint while others work — see coordination.md Token & Git Hygiene
|
|
15
|
+
* for the attribution-trap class this prevents).
|
|
16
|
+
*/
|
|
17
|
+
import { execFileSync } from 'node:child_process';
|
|
18
|
+
import { readAgentConfig, tokenSourceFromConfig } from '../config.js';
|
|
19
|
+
import { getSandboxAllowRead, SANDBOX_FD_READ_PATTERN } from '../settings-writer.js';
|
|
20
|
+
/**
|
|
21
|
+
* DR-019 permission doctrine. Keep in sync with
|
|
22
|
+
* design/decisions/DR-019-app-permissions.md and
|
|
23
|
+
* templates/macf-app-manifest.json.
|
|
24
|
+
*
|
|
25
|
+
* Names here are GitHub's CANONICAL API names (as returned by
|
|
26
|
+
* `GET /app/installations/:id` in the `permissions` field), which
|
|
27
|
+
* differ from the App settings UI labels for some entries — notably
|
|
28
|
+
* Variables → `actions_variables`. We use canonical names everywhere
|
|
29
|
+
* to avoid false negatives (an installation with `actions_variables`
|
|
30
|
+
* would be flagged as missing `variables` if we used the UI label).
|
|
31
|
+
*/
|
|
32
|
+
export const MACF_REQUIRED_PERMISSIONS = [
|
|
33
|
+
{ name: 'metadata', level: 'read', why: 'Mandatory by GitHub — cannot be omitted' },
|
|
34
|
+
{ name: 'contents', level: 'write', why: 'Push commits, PRs to feature branches' },
|
|
35
|
+
{ name: 'issues', level: 'write', why: 'Comment, label, edit issues — primary coordination surface' },
|
|
36
|
+
{ name: 'pull_requests', level: 'write', why: 'Create/merge PRs, submit reviews' },
|
|
37
|
+
{ name: 'actions_variables', level: 'write', why: 'Agent registry lives in repo/org/user variables (UI label: Variables)' },
|
|
38
|
+
{ name: 'workflows', level: 'write', why: 'macf repo-init writes .github/workflows/' },
|
|
39
|
+
{ name: 'actions', level: 'read', why: 'gh run list / view --log-failed for self-debug' },
|
|
40
|
+
];
|
|
41
|
+
/**
|
|
42
|
+
* Pure comparison: given the actual permission map from a token response,
|
|
43
|
+
* return what's missing or insufficient against MACF_REQUIRED_PERMISSIONS.
|
|
44
|
+
*/
|
|
45
|
+
export function diffPermissions(actual) {
|
|
46
|
+
const missing = [];
|
|
47
|
+
const insufficient = [];
|
|
48
|
+
for (const req of MACF_REQUIRED_PERMISSIONS) {
|
|
49
|
+
const actualLevel = actual[req.name];
|
|
50
|
+
if (!actualLevel) {
|
|
51
|
+
missing.push(req);
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
// 'write' required but only 'read' granted is a gap; the reverse
|
|
55
|
+
// ('read' required with 'write' granted) is fine — user exceeds.
|
|
56
|
+
if (req.level === 'write' && actualLevel === 'read') {
|
|
57
|
+
insufficient.push({ required: req, actual: actualLevel });
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return { missing, insufficient };
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Symbol + label for the output table. Exported so tests can assert on it.
|
|
64
|
+
*/
|
|
65
|
+
export function formatPermissionRow(req, actual) {
|
|
66
|
+
const name = req.name.padEnd(15);
|
|
67
|
+
const required = `${req.level}`.padEnd(6);
|
|
68
|
+
if (!actual) {
|
|
69
|
+
return `✗ ${name} required=${required} actual=MISSING — ${req.why}`;
|
|
70
|
+
}
|
|
71
|
+
const actualStr = actual.padEnd(6);
|
|
72
|
+
if (req.level === 'write' && actual === 'read') {
|
|
73
|
+
return `⚠ ${name} required=${required} actual=${actualStr} — need write, have read`;
|
|
74
|
+
}
|
|
75
|
+
return `✓ ${name} required=${required} actual=${actualStr}`;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Pure check: does this workspace's `.claude/settings.json` contain
|
|
79
|
+
* the `/proc/self/fd` sandbox pattern? See macf#200 for why this
|
|
80
|
+
* matters (without it every Bash tool call fails on the harness fd),
|
|
81
|
+
* and macf#208 for why the pattern is bare (not a glob).
|
|
82
|
+
*
|
|
83
|
+
* Uses `getSandboxAllowRead` from `settings-writer.ts` so the JSON-
|
|
84
|
+
* read + deep-narrow logic lives in one place. Malformed JSON
|
|
85
|
+
* surfaces as a FAIL with the parse error in `detail` — operator
|
|
86
|
+
* still needs to see what broke.
|
|
87
|
+
*/
|
|
88
|
+
export function checkSandboxFdAllowRead(workspaceDir) {
|
|
89
|
+
let allowRead;
|
|
90
|
+
try {
|
|
91
|
+
allowRead = getSandboxAllowRead(workspaceDir);
|
|
92
|
+
}
|
|
93
|
+
catch (err) {
|
|
94
|
+
return { status: 'FAIL', detail: err instanceof Error ? err.message : String(err) };
|
|
95
|
+
}
|
|
96
|
+
if (allowRead.includes(SANDBOX_FD_READ_PATTERN)) {
|
|
97
|
+
return { status: 'PASS', detail: '' };
|
|
98
|
+
}
|
|
99
|
+
return {
|
|
100
|
+
status: 'FAIL',
|
|
101
|
+
detail: `allowRead does not contain ${SANDBOX_FD_READ_PATTERN} — run \`macf update\` to refresh`,
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Format a non-leaking error message when `gh token generate --jwt` returns
|
|
106
|
+
* output that doesn't look like a JWT. Shows only the first 6 characters
|
|
107
|
+
* plus length — enough to distinguish empty / error-message / binary-garbage
|
|
108
|
+
* / genuinely-wrong-prefix, without exposing credential material if the
|
|
109
|
+
* branch fires on a genuinely-valid JWT due to a locale/whitespace/plugin
|
|
110
|
+
* edge case. See #86. Exported for unit tests.
|
|
111
|
+
*/
|
|
112
|
+
export function describeNonJwtOutput(jwt) {
|
|
113
|
+
const safePrefix = jwt.length > 0 ? jwt.slice(0, 6) : '(empty)';
|
|
114
|
+
return (`gh token generate --jwt returned unexpected output ` +
|
|
115
|
+
`(prefix='${safePrefix}', length=${jwt.length})`);
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Fetch the installation's GRANTED permissions by querying
|
|
119
|
+
* `GET /app/installations/:id` with an App JWT. We do NOT use the
|
|
120
|
+
* install-token response's `permissions` field here — it doesn't
|
|
121
|
+
* surface all granted permissions (verified empirically: an App with
|
|
122
|
+
* `actions_variables: write` may report an incomplete set in the
|
|
123
|
+
* install-token response but the full set via JWT query). See
|
|
124
|
+
* discussion on issue #74 for the evidence.
|
|
125
|
+
*/
|
|
126
|
+
export async function fetchInstallationPermissions(appId, installId, keyPath) {
|
|
127
|
+
// Get a JWT signed with the App's private key. `gh token generate --jwt`
|
|
128
|
+
// does the RS256 signing for us, avoiding a Node crypto reimplementation.
|
|
129
|
+
let jwt;
|
|
130
|
+
try {
|
|
131
|
+
jwt = execFileSync('gh', [
|
|
132
|
+
'token', 'generate',
|
|
133
|
+
'--app-id', appId,
|
|
134
|
+
'--key', keyPath,
|
|
135
|
+
'--jwt',
|
|
136
|
+
'--token-only',
|
|
137
|
+
], {
|
|
138
|
+
encoding: 'utf-8',
|
|
139
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
140
|
+
}).trim();
|
|
141
|
+
}
|
|
142
|
+
catch (err) {
|
|
143
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
144
|
+
throw new Error(`gh token generate --jwt failed: ${msg}. ` +
|
|
145
|
+
`See coordination.md Token & Git Hygiene for diagnostics.`, { cause: err });
|
|
146
|
+
}
|
|
147
|
+
if (!jwt.startsWith('eyJ')) {
|
|
148
|
+
throw new Error(describeNonJwtOutput(jwt));
|
|
149
|
+
}
|
|
150
|
+
const response = await fetch(`https://api.github.com/app/installations/${installId}`, {
|
|
151
|
+
headers: {
|
|
152
|
+
Authorization: `Bearer ${jwt}`,
|
|
153
|
+
Accept: 'application/vnd.github+json',
|
|
154
|
+
'X-GitHub-Api-Version': '2022-11-28',
|
|
155
|
+
},
|
|
156
|
+
});
|
|
157
|
+
if (!response.ok) {
|
|
158
|
+
const body = await response.text().catch(() => '<no body>');
|
|
159
|
+
throw new Error(`GET /app/installations/${installId} returned ${response.status}: ${body.slice(0, 200)}`);
|
|
160
|
+
}
|
|
161
|
+
const parsed = (await response.json());
|
|
162
|
+
if (!parsed.permissions || typeof parsed.permissions !== 'object') {
|
|
163
|
+
throw new Error('/app/installations/:id response missing `permissions` field');
|
|
164
|
+
}
|
|
165
|
+
return parsed.permissions;
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Main entry for `macf doctor`. Returns the shell exit code: 0 if all
|
|
169
|
+
* required permissions are present, 1 if any are missing or insufficient.
|
|
170
|
+
*/
|
|
171
|
+
export async function runDoctor(projectDir) {
|
|
172
|
+
const config = readAgentConfig(projectDir);
|
|
173
|
+
if (!config) {
|
|
174
|
+
console.error('No macf-agent.json found. Run `macf init` first.');
|
|
175
|
+
return 1;
|
|
176
|
+
}
|
|
177
|
+
const source = tokenSourceFromConfig(projectDir, config);
|
|
178
|
+
let permissions;
|
|
179
|
+
try {
|
|
180
|
+
permissions = await fetchInstallationPermissions(source.appId, source.installId, source.keyPath);
|
|
181
|
+
}
|
|
182
|
+
catch (err) {
|
|
183
|
+
console.error(`Error: ${err instanceof Error ? err.message : String(err)}`);
|
|
184
|
+
return 1;
|
|
185
|
+
}
|
|
186
|
+
const finding = diffPermissions(permissions);
|
|
187
|
+
console.log('MACF doctor report');
|
|
188
|
+
console.log('──────────────────────────────────────────────────────────────');
|
|
189
|
+
for (const req of MACF_REQUIRED_PERMISSIONS) {
|
|
190
|
+
console.log(` ${formatPermissionRow(req, permissions[req.name])}`);
|
|
191
|
+
}
|
|
192
|
+
console.log('');
|
|
193
|
+
const totalRequired = MACF_REQUIRED_PERMISSIONS.length;
|
|
194
|
+
const satisfied = totalRequired - finding.missing.length - finding.insufficient.length;
|
|
195
|
+
const status = finding.missing.length === 0 && finding.insufficient.length === 0
|
|
196
|
+
? '✓ all required permissions present'
|
|
197
|
+
: `✗ ${finding.missing.length + finding.insufficient.length} of ${totalRequired} required permissions missing or insufficient`;
|
|
198
|
+
console.log(` ${status} (${satisfied}/${totalRequired} satisfied)`);
|
|
199
|
+
if (finding.missing.length > 0) {
|
|
200
|
+
console.log('');
|
|
201
|
+
console.log('Missing:');
|
|
202
|
+
for (const req of finding.missing) {
|
|
203
|
+
console.log(` - ${req.name}: ${req.level} — ${req.why}`);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
if (finding.insufficient.length > 0) {
|
|
207
|
+
console.log('');
|
|
208
|
+
console.log('Insufficient:');
|
|
209
|
+
for (const { required, actual } of finding.insufficient) {
|
|
210
|
+
console.log(` - ${required.name}: have ${actual}, need ${required.level} — ${required.why}`);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
if (finding.missing.length > 0 || finding.insufficient.length > 0) {
|
|
214
|
+
console.log('');
|
|
215
|
+
console.log('See design/decisions/DR-019-app-permissions.md for the full doctrine,');
|
|
216
|
+
console.log('and GitHub → Settings → Developer settings → GitHub Apps → <your App> → Permissions');
|
|
217
|
+
console.log('to update the App. Users with the App installed must accept the new permissions.');
|
|
218
|
+
}
|
|
219
|
+
console.log('');
|
|
220
|
+
console.log('Sandbox filesystem (macf#200)');
|
|
221
|
+
console.log('──────────────────────────────────────────────────────────────');
|
|
222
|
+
const sandboxCheck = checkSandboxFdAllowRead(projectDir);
|
|
223
|
+
if (sandboxCheck.status === 'PASS') {
|
|
224
|
+
console.log(` ✓ sandbox.filesystem.allowRead contains ${SANDBOX_FD_READ_PATTERN} [PASS]`);
|
|
225
|
+
}
|
|
226
|
+
else {
|
|
227
|
+
console.log(` ✗ sandbox.filesystem.allowRead missing ${SANDBOX_FD_READ_PATTERN} [FAIL — run \`macf update\` to fix]`);
|
|
228
|
+
if (sandboxCheck.detail)
|
|
229
|
+
console.log(` ${sandboxCheck.detail}`);
|
|
230
|
+
}
|
|
231
|
+
const permissionsFailed = finding.missing.length > 0 || finding.insufficient.length > 0;
|
|
232
|
+
const sandboxFailed = sandboxCheck.status === 'FAIL';
|
|
233
|
+
return permissionsFailed || sandboxFailed ? 1 : 0;
|
|
234
|
+
}
|
|
235
|
+
//# sourceMappingURL=doctor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"doctor.js","sourceRoot":"","sources":["../../../src/cli/commands/doctor.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
export interface InitOptions {
|
|
2
|
+
readonly project: string;
|
|
3
|
+
readonly role: string;
|
|
4
|
+
readonly name?: string;
|
|
5
|
+
readonly type?: string;
|
|
6
|
+
readonly appId: string;
|
|
7
|
+
readonly installId: string;
|
|
8
|
+
readonly keyPath: string;
|
|
9
|
+
readonly registryType?: string;
|
|
10
|
+
readonly registryOrg?: string;
|
|
11
|
+
readonly registryUser?: string;
|
|
12
|
+
readonly registryRepo?: string;
|
|
13
|
+
/**
|
|
14
|
+
* Host the channel server advertises to the registry + includes in
|
|
15
|
+
* its mTLS cert SAN. When unset, launcher falls back to 127.0.0.1
|
|
16
|
+
* (matches plugin default). Operators routing to agents over the
|
|
17
|
+
* network (Tailscale IP / DNS) must set this. See macf#178.
|
|
18
|
+
*/
|
|
19
|
+
readonly advertiseHost?: string;
|
|
20
|
+
/**
|
|
21
|
+
* Tmux session + (optional) window for the on-notify wake path
|
|
22
|
+
* (macf#185). When set, the channel server's onNotify shells out
|
|
23
|
+
* to tmux-send-to-claude.sh to inject the notification prompt
|
|
24
|
+
* into a running Claude TUI. When unset, the server auto-detects
|
|
25
|
+
* from $TMUX if launched inside a tmux pane.
|
|
26
|
+
*/
|
|
27
|
+
readonly tmuxSession?: string;
|
|
28
|
+
readonly tmuxWindow?: string;
|
|
29
|
+
readonly cliVersion?: string;
|
|
30
|
+
readonly pluginVersion?: string;
|
|
31
|
+
readonly actionsVersion?: string;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Set up a project directory for an agent.
|
|
35
|
+
*/
|
|
36
|
+
export declare function initAgent(projectDir: string, opts: InitOptions): Promise<void>;
|
|
37
|
+
//# sourceMappingURL=init.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/init.ts"],"names":[],"mappings":"AAqBA,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAC/B;;;;;OAKG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAChC;;;;;;OAMG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;CAClC;AA4GD;;GAEG;AACH,wBAAsB,SAAS,CAAC,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CA0JpF"}
|