@meistrari/tela-cli 0.7.47 → 0.7.48
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/index.js +174 -13
- package/package.json +1 -1
- package/skills/tela-cli/references/agent.md +4 -2
package/dist/index.js
CHANGED
|
@@ -6285,6 +6285,7 @@ var require_setup = __commonJS({
|
|
|
6285
6285
|
exports2.createGitSshKey = createGitSshKey;
|
|
6286
6286
|
exports2.resolveCloneRootPath = resolveCloneRootPath;
|
|
6287
6287
|
exports2.listDiscoveredSshPublicKeys = listDiscoveredSshPublicKeys;
|
|
6288
|
+
exports2.prepareAgentSetupSshKeys = prepareAgentSetupSshKeys;
|
|
6288
6289
|
exports2.prepareAgentSetup = prepareAgentSetup;
|
|
6289
6290
|
exports2.findAgentSetupOrganization = findAgentSetupOrganization;
|
|
6290
6291
|
exports2.validatePreparedAgentSetupInput = validatePreparedAgentSetupInput;
|
|
@@ -6296,7 +6297,9 @@ var require_setup = __commonJS({
|
|
|
6296
6297
|
var tela_local_config_1 = require_dist();
|
|
6297
6298
|
var agent_api_1 = require_agent_api();
|
|
6298
6299
|
var credentials_1 = require_credentials2();
|
|
6300
|
+
var errors_1 = require_errors();
|
|
6299
6301
|
var config_1 = require_config2();
|
|
6302
|
+
var process_1 = require_process();
|
|
6300
6303
|
function getHomeDir() {
|
|
6301
6304
|
return process.env.HOME || (0, node_os_1.homedir)();
|
|
6302
6305
|
}
|
|
@@ -6398,6 +6401,134 @@ var require_setup = __commonJS({
|
|
|
6398
6401
|
}
|
|
6399
6402
|
return (0, node_fs_1.readdirSync)(sshDirectory, { withFileTypes: true }).filter((entry) => entry.isFile() && entry.name.endsWith(".pub")).map((entry) => loadSshPublicKey((0, node_path_1.join)(sshDirectory, entry.name))).sort((left, right) => left.title.localeCompare(right.title) || left.path.localeCompare(right.path));
|
|
6400
6403
|
}
|
|
6404
|
+
function listDiscoveredSshKeyPairs(sshDirectory = getSshDirectory()) {
|
|
6405
|
+
return listDiscoveredSshPublicKeys(sshDirectory).map((key) => ({
|
|
6406
|
+
...key,
|
|
6407
|
+
privateKeyPath: inferSshPrivateKeyPath(key.path)
|
|
6408
|
+
})).filter((key) => (0, node_fs_1.existsSync)(key.privateKeyPath));
|
|
6409
|
+
}
|
|
6410
|
+
function toCreatedSshKey(key) {
|
|
6411
|
+
return {
|
|
6412
|
+
title: key.title,
|
|
6413
|
+
path: key.path,
|
|
6414
|
+
privateKeyPath: key.privateKeyPath
|
|
6415
|
+
};
|
|
6416
|
+
}
|
|
6417
|
+
function hasUsableSavedSshKey(setup) {
|
|
6418
|
+
const sshKey = setup?.gitSshKey;
|
|
6419
|
+
return Boolean(sshKey?.publicKeyPath && sshKey.privateKeyPath && (0, node_fs_1.existsSync)(sshKey.publicKeyPath) && (0, node_fs_1.existsSync)(sshKey.privateKeyPath));
|
|
6420
|
+
}
|
|
6421
|
+
function createSavedSshKeyOption(sshKey) {
|
|
6422
|
+
return {
|
|
6423
|
+
...loadSshPublicKey(sshKey.publicKeyPath),
|
|
6424
|
+
privateKeyPath: resolveSshPrivateKeyPath(sshKey.privateKeyPath)
|
|
6425
|
+
};
|
|
6426
|
+
}
|
|
6427
|
+
function includePreferredSshKeyOption(sshPublicKeys, preferredKey) {
|
|
6428
|
+
return [
|
|
6429
|
+
preferredKey,
|
|
6430
|
+
...sshPublicKeys.filter((key) => key.path !== preferredKey.path)
|
|
6431
|
+
];
|
|
6432
|
+
}
|
|
6433
|
+
function ensureSshDirectory(sshDirectory) {
|
|
6434
|
+
const exists = (0, node_fs_1.existsSync)(sshDirectory);
|
|
6435
|
+
if (!exists) {
|
|
6436
|
+
(0, node_fs_1.mkdirSync)(sshDirectory, { recursive: true, mode: 448 });
|
|
6437
|
+
}
|
|
6438
|
+
const stats = (0, node_fs_1.statSync)(sshDirectory);
|
|
6439
|
+
if (!stats.isDirectory()) {
|
|
6440
|
+
throw (0, errors_1.createUserFacingError)({
|
|
6441
|
+
code: "ssh_directory_invalid",
|
|
6442
|
+
summary: `SSH directory path is not a directory: ${sshDirectory}`,
|
|
6443
|
+
fixes: ["Move or remove that path, then retry Tela CLI setup."]
|
|
6444
|
+
});
|
|
6445
|
+
}
|
|
6446
|
+
if (!exists) {
|
|
6447
|
+
(0, node_fs_1.chmodSync)(sshDirectory, 448);
|
|
6448
|
+
}
|
|
6449
|
+
}
|
|
6450
|
+
function getAvailableGeneratedSshKeyPath(sshDirectory) {
|
|
6451
|
+
const basePath = (0, node_path_1.join)(sshDirectory, "tela_agent_ed25519");
|
|
6452
|
+
const maxAttempts = 1e3;
|
|
6453
|
+
for (let index = 0; index < maxAttempts; index += 1) {
|
|
6454
|
+
const privateKeyPath = index === 0 ? basePath : `${basePath}_${index + 1}`;
|
|
6455
|
+
const publicKeyPath = `${privateKeyPath}.pub`;
|
|
6456
|
+
if (!(0, node_fs_1.existsSync)(privateKeyPath) && !(0, node_fs_1.existsSync)(publicKeyPath)) {
|
|
6457
|
+
return privateKeyPath;
|
|
6458
|
+
}
|
|
6459
|
+
}
|
|
6460
|
+
throw (0, errors_1.createUserFacingError)({
|
|
6461
|
+
code: "ssh_key_path_unavailable",
|
|
6462
|
+
summary: `Could not find an available Tela SSH key path in ${sshDirectory}.`,
|
|
6463
|
+
fixes: ["Remove unused tela_agent_ed25519 key files or create an SSH key manually, then retry setup."]
|
|
6464
|
+
});
|
|
6465
|
+
}
|
|
6466
|
+
async function createGeneratedSshKey(sshDirectory, options) {
|
|
6467
|
+
ensureSshDirectory(sshDirectory);
|
|
6468
|
+
const sshKeygenPath = await options.resolveExecutableFn("ssh-keygen");
|
|
6469
|
+
if (!sshKeygenPath) {
|
|
6470
|
+
throw (0, errors_1.createUserFacingError)({
|
|
6471
|
+
code: "ssh_keygen_missing",
|
|
6472
|
+
summary: "Could not create an SSH key because ssh-keygen was not found.",
|
|
6473
|
+
fixes: ["Install OpenSSH tools or create an ed25519 SSH key manually, then retry Tela CLI setup."]
|
|
6474
|
+
});
|
|
6475
|
+
}
|
|
6476
|
+
const privateKeyPath = getAvailableGeneratedSshKeyPath(sshDirectory);
|
|
6477
|
+
const result = await options.runCommandFn([
|
|
6478
|
+
sshKeygenPath,
|
|
6479
|
+
"-t",
|
|
6480
|
+
"ed25519",
|
|
6481
|
+
"-N",
|
|
6482
|
+
"",
|
|
6483
|
+
"-C",
|
|
6484
|
+
"tela-agent",
|
|
6485
|
+
"-f",
|
|
6486
|
+
privateKeyPath
|
|
6487
|
+
], {
|
|
6488
|
+
allowFailure: true,
|
|
6489
|
+
timeoutMs: 15e3
|
|
6490
|
+
});
|
|
6491
|
+
if (result.exitCode !== 0) {
|
|
6492
|
+
const details = result.stderr.trim() || result.stdout.trim() || `ssh-keygen exited with code ${result.exitCode}.`;
|
|
6493
|
+
throw (0, errors_1.createUserFacingError)({
|
|
6494
|
+
code: "ssh_key_generation_failed",
|
|
6495
|
+
summary: "Could not create an SSH key for Tela CLI setup.",
|
|
6496
|
+
details,
|
|
6497
|
+
fixes: ["Create an ed25519 SSH key manually, then retry Tela CLI setup."]
|
|
6498
|
+
});
|
|
6499
|
+
}
|
|
6500
|
+
if (!(0, node_fs_1.existsSync)(privateKeyPath) || !(0, node_fs_1.existsSync)(`${privateKeyPath}.pub`)) {
|
|
6501
|
+
throw (0, errors_1.createUserFacingError)({
|
|
6502
|
+
code: "ssh_key_generation_missing_files",
|
|
6503
|
+
summary: "ssh-keygen completed but the expected SSH key files were not created.",
|
|
6504
|
+
fixes: ["Create an ed25519 SSH key manually, then retry Tela CLI setup."]
|
|
6505
|
+
});
|
|
6506
|
+
}
|
|
6507
|
+
(0, node_fs_1.chmodSync)(privateKeyPath, 384);
|
|
6508
|
+
return {
|
|
6509
|
+
...loadSshPublicKey(`${privateKeyPath}.pub`),
|
|
6510
|
+
privateKeyPath
|
|
6511
|
+
};
|
|
6512
|
+
}
|
|
6513
|
+
async function prepareAgentSetupSshKeys(options = {}) {
|
|
6514
|
+
const sshDirectory = options.sshDirectory ?? getSshDirectory();
|
|
6515
|
+
const existingSshPublicKeys = listDiscoveredSshKeyPairs(sshDirectory);
|
|
6516
|
+
if (existingSshPublicKeys.length > 0) {
|
|
6517
|
+
return {
|
|
6518
|
+
sshPublicKeys: existingSshPublicKeys,
|
|
6519
|
+
createdSshKey: null
|
|
6520
|
+
};
|
|
6521
|
+
}
|
|
6522
|
+
const created = await createGeneratedSshKey(sshDirectory, {
|
|
6523
|
+
runCommandFn: options.runCommandFn ?? process_1.runCommand,
|
|
6524
|
+
resolveExecutableFn: options.resolveExecutableFn ?? process_1.resolveExecutable
|
|
6525
|
+
});
|
|
6526
|
+
const sshPublicKeys = listDiscoveredSshKeyPairs(sshDirectory);
|
|
6527
|
+
return {
|
|
6528
|
+
sshPublicKeys,
|
|
6529
|
+
createdSshKey: toCreatedSshKey(sshPublicKeys.find((key) => key.path === created.path) ?? created)
|
|
6530
|
+
};
|
|
6531
|
+
}
|
|
6401
6532
|
function createSetupUser(credential, fallbackEmail) {
|
|
6402
6533
|
const raw = toObject(credential?.raw);
|
|
6403
6534
|
const rawUser = toObject(raw?.user);
|
|
@@ -6435,12 +6566,13 @@ var require_setup = __commonJS({
|
|
|
6435
6566
|
if (organizations.length === 0) {
|
|
6436
6567
|
throw new Error("No Agent API organizations are available for this Tela workspace. Ask the Tela team to register an organization, then try setup again.");
|
|
6437
6568
|
}
|
|
6438
|
-
const
|
|
6439
|
-
|
|
6440
|
-
|
|
6441
|
-
|
|
6442
|
-
|
|
6443
|
-
const
|
|
6569
|
+
const existingSshKey = hasUsableSavedSshKey(existingSetup) ? existingSetup?.gitSshKey ?? null : null;
|
|
6570
|
+
const { sshPublicKeys, createdSshKey } = existingSshKey ? {
|
|
6571
|
+
sshPublicKeys: includePreferredSshKeyOption(listDiscoveredSshKeyPairs(), createSavedSshKeyOption(existingSshKey)),
|
|
6572
|
+
createdSshKey: null
|
|
6573
|
+
} : await prepareAgentSetupSshKeys();
|
|
6574
|
+
const selectedSshPublicKeyPath = existingSshKey ? existingSshKey.publicKeyPath : sshPublicKeys[0]?.path ?? "";
|
|
6575
|
+
const selectedSshPrivateKeyPath = existingSshKey?.privateKeyPath ?? sshPublicKeys.find((key) => key.path === selectedSshPublicKeyPath)?.privateKeyPath ?? (selectedSshPublicKeyPath ? inferSshPrivateKeyPath(selectedSshPublicKeyPath) : "");
|
|
6444
6576
|
const selectedOrganizationId = existingSetup?.forgejoOrganization?.id ?? organizations[0]?.id ?? "";
|
|
6445
6577
|
return {
|
|
6446
6578
|
contextId: config.contextId,
|
|
@@ -6451,6 +6583,7 @@ var require_setup = __commonJS({
|
|
|
6451
6583
|
sshPublicKeys,
|
|
6452
6584
|
selectedSshPublicKeyPath,
|
|
6453
6585
|
selectedSshPrivateKeyPath,
|
|
6586
|
+
createdSshKey,
|
|
6454
6587
|
existingSetup
|
|
6455
6588
|
};
|
|
6456
6589
|
}
|
|
@@ -6469,10 +6602,19 @@ var require_setup = __commonJS({
|
|
|
6469
6602
|
throw new Error(`Unknown Agent API organization: ${selector}`);
|
|
6470
6603
|
}
|
|
6471
6604
|
function validatePreparedAgentSetupInput(prepared, input) {
|
|
6605
|
+
if (Boolean(input.sshPublicKeyPath) !== Boolean(input.sshPrivateKeyPath)) {
|
|
6606
|
+
throw (0, errors_1.createUserFacingError)({
|
|
6607
|
+
code: "setup_ssh_key_override_pair_required",
|
|
6608
|
+
summary: "SSH key override paths must be provided together.",
|
|
6609
|
+
fixes: ["Pass both --ssh-public-key and --ssh-private-key, or omit both to use the selected key."]
|
|
6610
|
+
});
|
|
6611
|
+
}
|
|
6472
6612
|
const organization = findAgentSetupOrganization(prepared.organizations, input.organization);
|
|
6473
6613
|
const cloneRoot = input.cloneRoot ? resolveCloneRootPath(input.cloneRoot) : resolveCloneRootPath(prepared.cloneRoot);
|
|
6474
|
-
const
|
|
6475
|
-
const
|
|
6614
|
+
const sshPublicKeyPath = input.sshPublicKeyPath || prepared.selectedSshPublicKeyPath;
|
|
6615
|
+
const sshPrivateKeyPathInput = input.sshPrivateKeyPath || prepared.selectedSshPrivateKeyPath;
|
|
6616
|
+
const sshKey = loadSshPublicKey(sshPublicKeyPath);
|
|
6617
|
+
const sshPrivateKeyPath = resolveSshPrivateKeyPath(sshPrivateKeyPathInput);
|
|
6476
6618
|
return {
|
|
6477
6619
|
contextId: prepared.contextId,
|
|
6478
6620
|
organization,
|
|
@@ -7095,9 +7237,7 @@ var require_cli = __commonJS({
|
|
|
7095
7237
|
function assertSetupRequiredOptions(options) {
|
|
7096
7238
|
const missing = [
|
|
7097
7239
|
options.contextId ? "" : "--context",
|
|
7098
|
-
options.organization ? "" : "--organization"
|
|
7099
|
-
options.sshPublicKeyPath ? "" : "--ssh-public-key",
|
|
7100
|
-
options.sshPrivateKeyPath ? "" : "--ssh-private-key"
|
|
7240
|
+
options.organization ? "" : "--organization"
|
|
7101
7241
|
].filter(Boolean);
|
|
7102
7242
|
if (missing.length > 0) {
|
|
7103
7243
|
throw (0, errors_1.createUserFacingError)({
|
|
@@ -7105,7 +7245,7 @@ var require_cli = __commonJS({
|
|
|
7105
7245
|
summary: `Missing required setup option${missing.length === 1 ? "" : "s"}: ${missing.join(", ")}`,
|
|
7106
7246
|
fixes: [
|
|
7107
7247
|
"Run `tela agent setup --list-options --context <context-id> --json` to inspect valid values.",
|
|
7108
|
-
"Pass
|
|
7248
|
+
"Pass the required context and organization flags for non-interactive setup."
|
|
7109
7249
|
]
|
|
7110
7250
|
});
|
|
7111
7251
|
}
|
|
@@ -7130,6 +7270,7 @@ var require_cli = __commonJS({
|
|
|
7130
7270
|
})),
|
|
7131
7271
|
selectedSshPublicKeyPath: preparation2.selectedSshPublicKeyPath,
|
|
7132
7272
|
selectedSshPrivateKeyPath: preparation2.selectedSshPrivateKeyPath,
|
|
7273
|
+
createdSshKey: preparation2.createdSshKey,
|
|
7133
7274
|
existingSetup: preparation2.existingSetup
|
|
7134
7275
|
};
|
|
7135
7276
|
if (options.json)
|
|
@@ -7142,6 +7283,12 @@ var require_cli = __commonJS({
|
|
|
7142
7283
|
{ label: "Clone root", value: result2.cloneRoot }
|
|
7143
7284
|
])),
|
|
7144
7285
|
(0, ui_1.section)("Organizations", result2.organizations.map((item) => `- ${item.name} (${item.id})`).join("\n")),
|
|
7286
|
+
...result2.createdSshKey ? [
|
|
7287
|
+
(0, ui_1.section)("Generated SSH key", (0, ui_1.kvList)([
|
|
7288
|
+
{ label: "Public key", value: result2.createdSshKey.path },
|
|
7289
|
+
{ label: "Private key", value: result2.createdSshKey.privateKeyPath }
|
|
7290
|
+
]))
|
|
7291
|
+
] : [],
|
|
7145
7292
|
(0, ui_1.section)("SSH keys", result2.sshPublicKeys.map((item) => `- ${item.title}: ${item.path}`).join("\n") || "<none>")
|
|
7146
7293
|
]));
|
|
7147
7294
|
}
|
|
@@ -7166,6 +7313,7 @@ var require_cli = __commonJS({
|
|
|
7166
7313
|
cloneRoot: validated.cloneRoot,
|
|
7167
7314
|
sshPublicKeyPath: validated.sshKey.path,
|
|
7168
7315
|
sshPrivateKeyPath: validated.sshPrivateKeyPath,
|
|
7316
|
+
createdSshKey: preparation.createdSshKey,
|
|
7169
7317
|
nextActions: ["Run the same setup command without `--dry-run` to provision Forgejo and save setup metadata."]
|
|
7170
7318
|
};
|
|
7171
7319
|
if (options.json)
|
|
@@ -7179,6 +7327,12 @@ var require_cli = __commonJS({
|
|
|
7179
7327
|
{ label: "SSH public key", value: result2.sshPublicKeyPath },
|
|
7180
7328
|
{ label: "SSH private key", value: result2.sshPrivateKeyPath }
|
|
7181
7329
|
])),
|
|
7330
|
+
...result2.createdSshKey ? [
|
|
7331
|
+
(0, ui_1.section)("Generated SSH key", (0, ui_1.kvList)([
|
|
7332
|
+
{ label: "Public key", value: result2.createdSshKey.path },
|
|
7333
|
+
{ label: "Private key", value: result2.createdSshKey.privateKeyPath }
|
|
7334
|
+
]))
|
|
7335
|
+
] : [],
|
|
7182
7336
|
(0, ui_1.nextActions)(result2.nextActions)
|
|
7183
7337
|
]));
|
|
7184
7338
|
}
|
|
@@ -7196,6 +7350,7 @@ var require_cli = __commonJS({
|
|
|
7196
7350
|
contextId: setup.contextId,
|
|
7197
7351
|
setup: setup.setup,
|
|
7198
7352
|
response: setup.response,
|
|
7353
|
+
createdSshKey: preparation.createdSshKey,
|
|
7199
7354
|
nextActions: ["Run `tela agent sync --all --dry-run --json` to inspect repository sync readiness."]
|
|
7200
7355
|
};
|
|
7201
7356
|
if (options.json)
|
|
@@ -7207,6 +7362,12 @@ var require_cli = __commonJS({
|
|
|
7207
7362
|
{ label: "Forgejo Organization", value: setup.setup.forgejoOrganization?.name ?? "<none>" },
|
|
7208
7363
|
{ label: "SSH key", value: setup.setup.gitSshKey?.title ?? "<none>" }
|
|
7209
7364
|
])),
|
|
7365
|
+
...result.createdSshKey ? [
|
|
7366
|
+
(0, ui_1.section)("Generated SSH key", (0, ui_1.kvList)([
|
|
7367
|
+
{ label: "Public key", value: result.createdSshKey.path },
|
|
7368
|
+
{ label: "Private key", value: result.createdSshKey.privateKeyPath }
|
|
7369
|
+
]))
|
|
7370
|
+
] : [],
|
|
7210
7371
|
(0, ui_1.nextActions)(result.nextActions)
|
|
7211
7372
|
]));
|
|
7212
7373
|
}
|
|
@@ -8629,7 +8790,7 @@ function writeHelp(io) {
|
|
|
8629
8790
|
writeLine(io, " agent run [--input <name=path>...] [--mode one-shot|chat] [--input-conflict fail|overwrite|rename] [--plain] [--json] [--verbose]");
|
|
8630
8791
|
writeLine(io, " agent push [--message <text>|--claude|--manual] [--dry-run] [--json] [--verbose]");
|
|
8631
8792
|
writeLine(io, " agent feedback [--list] [--apply all|select] [--feedback-id <id>...] [--json] [--verbose]");
|
|
8632
|
-
writeLine(io, " agent setup [--list-options]
|
|
8793
|
+
writeLine(io, " agent setup [--list-options] --context <context-id> --organization <id-or-name> [--clone-root <path>] [--ssh-public-key <path>] [--ssh-private-key <path>] [--dry-run] [--json]");
|
|
8633
8794
|
}
|
|
8634
8795
|
function getPackageVersion() {
|
|
8635
8796
|
const metadata = JSON.parse((0, import_node_fs2.readFileSync)((0, import_node_path2.join)(__dirname, "..", "package.json"), "utf8"));
|
package/package.json
CHANGED
|
@@ -18,12 +18,14 @@ tela agent setup \
|
|
|
18
18
|
--context production/foundation \
|
|
19
19
|
--organization acme \
|
|
20
20
|
--clone-root "$HOME/tela-agents" \
|
|
21
|
-
--ssh-public-key "$HOME/.ssh/id_ed25519.pub" \
|
|
22
|
-
--ssh-private-key "$HOME/.ssh/id_ed25519" \
|
|
23
21
|
--dry-run \
|
|
24
22
|
--json
|
|
25
23
|
```
|
|
26
24
|
|
|
25
|
+
Setup uses an existing SSH key pair from `~/.ssh`, or creates
|
|
26
|
+
`~/.ssh/tela_agent_ed25519` when no key pair exists. Pass `--ssh-public-key`
|
|
27
|
+
and `--ssh-private-key` only when overriding that default selection.
|
|
28
|
+
|
|
27
29
|
Complete setup by removing `--dry-run`. This provisions the Forgejo user and
|
|
28
30
|
saves Agent setup metadata in the shared Tela local config.
|
|
29
31
|
|