@instafy/cli 0.2.0 → 0.2.1
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/README.md +4 -0
- package/dist/cli.js +1537 -300
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -809,7 +809,7 @@ async function resolveOrg(controllerUrl, auth, options, retryCommand) {
|
|
|
809
809
|
}
|
|
810
810
|
const orgSlug = options.orgSlug?.trim() || null;
|
|
811
811
|
const orgName = options.orgName?.trim() || null;
|
|
812
|
-
const studioUrl = resolveConfiguredStudioUrl({ profile: options.profile ?? null }) ?? "https://
|
|
812
|
+
const studioUrl = resolveConfiguredStudioUrl({ profile: options.profile ?? null }) ?? "https://instafy.dev";
|
|
813
813
|
const studioOrgUrl = `${studioUrl.replace(/\/$/, "")}/studio?panel=settings`;
|
|
814
814
|
const allowInteractive = Boolean(
|
|
815
815
|
input2.isTTY && process.stdout.isTTY && options.json !== true && process.env.CI !== "true"
|
|
@@ -1276,7 +1276,7 @@ var org_exports = {};
|
|
|
1276
1276
|
__export(org_exports, {
|
|
1277
1277
|
listOrganizations: () => listOrganizations
|
|
1278
1278
|
});
|
|
1279
|
-
import
|
|
1279
|
+
import kleur17 from "kleur";
|
|
1280
1280
|
function getTeamDisplayName2(name) {
|
|
1281
1281
|
const trimmed = (name ?? "").trim();
|
|
1282
1282
|
if (!trimmed || trimmed === "Personal organization" || trimmed === "Personal team" || trimmed === "Personal workspace") {
|
|
@@ -1314,11 +1314,11 @@ async function listOrganizations(params) {
|
|
|
1314
1314
|
console.log(JSON.stringify(orgs, null, 2));
|
|
1315
1315
|
} else {
|
|
1316
1316
|
if (orgs.length === 0) {
|
|
1317
|
-
console.log(
|
|
1317
|
+
console.log(kleur17.yellow("No teams found for this account."));
|
|
1318
1318
|
} else {
|
|
1319
1319
|
for (const org of orgs) {
|
|
1320
1320
|
const role = org.role ? ` [${org.role}]` : "";
|
|
1321
|
-
console.log(`${
|
|
1321
|
+
console.log(`${kleur17.green(getTeamDisplayName2(org.name))} (${org.id}${role})`);
|
|
1322
1322
|
}
|
|
1323
1323
|
}
|
|
1324
1324
|
}
|
|
@@ -1348,9 +1348,9 @@ var init_hardwareProvider2 = __esm({
|
|
|
1348
1348
|
});
|
|
1349
1349
|
|
|
1350
1350
|
// ../instafy-sdk/src/hardwareNode.ts
|
|
1351
|
-
import
|
|
1351
|
+
import fs13 from "node:fs";
|
|
1352
1352
|
import os5 from "node:os";
|
|
1353
|
-
import
|
|
1353
|
+
import path14 from "node:path";
|
|
1354
1354
|
function uniqueStrings(values) {
|
|
1355
1355
|
const seen = /* @__PURE__ */ new Set();
|
|
1356
1356
|
const result = [];
|
|
@@ -1389,14 +1389,14 @@ function classifySerialPort(fileName, fullPath) {
|
|
|
1389
1389
|
return null;
|
|
1390
1390
|
}
|
|
1391
1391
|
function inspectPort(portPath) {
|
|
1392
|
-
const resolvedPath =
|
|
1392
|
+
const resolvedPath = path14.resolve(portPath);
|
|
1393
1393
|
let exists = false;
|
|
1394
1394
|
let readable = false;
|
|
1395
1395
|
let writable = false;
|
|
1396
1396
|
let isCharacterDevice = false;
|
|
1397
1397
|
let error = null;
|
|
1398
1398
|
try {
|
|
1399
|
-
const stat =
|
|
1399
|
+
const stat = fs13.statSync(resolvedPath);
|
|
1400
1400
|
exists = true;
|
|
1401
1401
|
isCharacterDevice = stat.isCharacterDevice();
|
|
1402
1402
|
} catch (caught) {
|
|
@@ -1404,13 +1404,13 @@ function inspectPort(portPath) {
|
|
|
1404
1404
|
}
|
|
1405
1405
|
if (exists) {
|
|
1406
1406
|
try {
|
|
1407
|
-
|
|
1407
|
+
fs13.accessSync(resolvedPath, fs13.constants.R_OK);
|
|
1408
1408
|
readable = true;
|
|
1409
1409
|
} catch {
|
|
1410
1410
|
readable = false;
|
|
1411
1411
|
}
|
|
1412
1412
|
try {
|
|
1413
|
-
|
|
1413
|
+
fs13.accessSync(resolvedPath, fs13.constants.W_OK);
|
|
1414
1414
|
writable = true;
|
|
1415
1415
|
} catch {
|
|
1416
1416
|
writable = false;
|
|
@@ -1432,12 +1432,12 @@ function listCandidates(scanDirs) {
|
|
|
1432
1432
|
for (const scanDir of scanDirs) {
|
|
1433
1433
|
let entries = [];
|
|
1434
1434
|
try {
|
|
1435
|
-
entries =
|
|
1435
|
+
entries = fs13.readdirSync(scanDir);
|
|
1436
1436
|
} catch {
|
|
1437
1437
|
continue;
|
|
1438
1438
|
}
|
|
1439
1439
|
for (const entry of entries) {
|
|
1440
|
-
const fullPath =
|
|
1440
|
+
const fullPath = path14.join(scanDir, entry);
|
|
1441
1441
|
const kind = classifySerialPort(entry, fullPath);
|
|
1442
1442
|
if (!kind) {
|
|
1443
1443
|
continue;
|
|
@@ -1445,7 +1445,7 @@ function listCandidates(scanDirs) {
|
|
|
1445
1445
|
candidates.push({
|
|
1446
1446
|
path: fullPath,
|
|
1447
1447
|
kind,
|
|
1448
|
-
displayName:
|
|
1448
|
+
displayName: path14.basename(fullPath)
|
|
1449
1449
|
});
|
|
1450
1450
|
}
|
|
1451
1451
|
}
|
|
@@ -1611,37 +1611,37 @@ __export(hardware_exports, {
|
|
|
1611
1611
|
hardwareSerialList: () => hardwareSerialList,
|
|
1612
1612
|
hardwareSerialProbe: () => hardwareSerialProbe
|
|
1613
1613
|
});
|
|
1614
|
-
import
|
|
1614
|
+
import kleur18 from "kleur";
|
|
1615
1615
|
function printSerialPorts(result) {
|
|
1616
1616
|
if (result.ports.length === 0) {
|
|
1617
|
-
console.log(
|
|
1617
|
+
console.log(kleur18.yellow("No local serial devices were discovered."));
|
|
1618
1618
|
return;
|
|
1619
1619
|
}
|
|
1620
|
-
console.log(
|
|
1620
|
+
console.log(kleur18.cyan(`Local serial devices (${result.platform}):`));
|
|
1621
1621
|
for (const port of result.ports) {
|
|
1622
|
-
const status = port.available ?
|
|
1622
|
+
const status = port.available ? kleur18.green("available") : kleur18.yellow("not ready");
|
|
1623
1623
|
console.log(`- ${port.path} (${port.kind}, ${status})`);
|
|
1624
1624
|
}
|
|
1625
1625
|
}
|
|
1626
1626
|
function printProbe(probe) {
|
|
1627
|
-
console.log(
|
|
1627
|
+
console.log(kleur18.cyan(`Serial device: ${probe.path}`));
|
|
1628
1628
|
console.log(`Exists: ${probe.exists ? "yes" : "no"}`);
|
|
1629
1629
|
console.log(`Readable: ${probe.readable ? "yes" : "no"}`);
|
|
1630
1630
|
console.log(`Writable: ${probe.writable ? "yes" : "no"}`);
|
|
1631
1631
|
console.log(`Character device: ${probe.isCharacterDevice ? "yes" : "no"}`);
|
|
1632
|
-
console.log(`Available: ${probe.available ?
|
|
1632
|
+
console.log(`Available: ${probe.available ? kleur18.green("yes") : kleur18.yellow("no")}`);
|
|
1633
1633
|
if (probe.error) {
|
|
1634
1634
|
console.log(`Detail: ${probe.error}`);
|
|
1635
1635
|
}
|
|
1636
1636
|
}
|
|
1637
1637
|
function printIoOpportunities(result) {
|
|
1638
1638
|
if (result.opportunities.length === 0) {
|
|
1639
|
-
console.log(
|
|
1639
|
+
console.log(kleur18.yellow("No local IO opportunities were discovered."));
|
|
1640
1640
|
return;
|
|
1641
1641
|
}
|
|
1642
|
-
console.log(
|
|
1642
|
+
console.log(kleur18.cyan(`Local IO opportunities (${result.platform}):`));
|
|
1643
1643
|
for (const opportunity of result.opportunities) {
|
|
1644
|
-
const status = opportunity.available ?
|
|
1644
|
+
const status = opportunity.available ? kleur18.green("available") : kleur18.yellow("not ready");
|
|
1645
1645
|
console.log(`- ${opportunity.title} (${status})`);
|
|
1646
1646
|
console.log(` Resource: ${opportunity.resource.path}`);
|
|
1647
1647
|
const available = opportunity.actions.filter((action) => action.status === "available").map((action) => action.id);
|
|
@@ -1655,8 +1655,8 @@ function printIoOpportunities(result) {
|
|
|
1655
1655
|
}
|
|
1656
1656
|
}
|
|
1657
1657
|
function printIoActionResult(result) {
|
|
1658
|
-
const status = result.ok ?
|
|
1659
|
-
console.log(
|
|
1658
|
+
const status = result.ok ? kleur18.green("ok") : kleur18.red("failed");
|
|
1659
|
+
console.log(kleur18.cyan(`Local IO action: ${result.actionId} (${status})`));
|
|
1660
1660
|
console.log(result.message);
|
|
1661
1661
|
if (result.serialProbe) {
|
|
1662
1662
|
printProbe(result.serialProbe);
|
|
@@ -1665,11 +1665,11 @@ function printIoActionResult(result) {
|
|
|
1665
1665
|
const exit = result.process.exitCode ?? result.process.signal ?? "unknown";
|
|
1666
1666
|
console.log(`Process exit: ${exit}`);
|
|
1667
1667
|
if (result.process.stdout.trim()) {
|
|
1668
|
-
console.log(
|
|
1668
|
+
console.log(kleur18.dim("stdout:"));
|
|
1669
1669
|
console.log(result.process.stdout.trimEnd());
|
|
1670
1670
|
}
|
|
1671
1671
|
if (result.process.stderr.trim()) {
|
|
1672
|
-
console.log(
|
|
1672
|
+
console.log(kleur18.dim("stderr:"));
|
|
1673
1673
|
console.log(result.process.stderr.trimEnd());
|
|
1674
1674
|
}
|
|
1675
1675
|
}
|
|
@@ -1732,7 +1732,7 @@ var init_hardware = __esm({
|
|
|
1732
1732
|
import { Command, Option } from "commander";
|
|
1733
1733
|
import { pathToFileURL as pathToFileURL2 } from "node:url";
|
|
1734
1734
|
import { createRequire as createRequire3 } from "node:module";
|
|
1735
|
-
import
|
|
1735
|
+
import kleur19 from "kleur";
|
|
1736
1736
|
|
|
1737
1737
|
// src/runtime.ts
|
|
1738
1738
|
import { spawn as spawn2, spawnSync } from "node:child_process";
|
|
@@ -3139,7 +3139,7 @@ async function isStudioHealthy(studioUrl, timeoutMs) {
|
|
|
3139
3139
|
}
|
|
3140
3140
|
}
|
|
3141
3141
|
async function resolveDefaultStudioUrl(controllerUrl) {
|
|
3142
|
-
const hosted = "https://
|
|
3142
|
+
const hosted = "https://instafy.dev";
|
|
3143
3143
|
if (isStagingCli2) {
|
|
3144
3144
|
return hosted;
|
|
3145
3145
|
}
|
|
@@ -3909,7 +3909,7 @@ function normalizeSecretRecord(input3) {
|
|
|
3909
3909
|
}
|
|
3910
3910
|
return out;
|
|
3911
3911
|
};
|
|
3912
|
-
const
|
|
3912
|
+
const toMaybeString2 = (value) => {
|
|
3913
3913
|
if (typeof value !== "string") {
|
|
3914
3914
|
return null;
|
|
3915
3915
|
}
|
|
@@ -3922,10 +3922,10 @@ function normalizeSecretRecord(input3) {
|
|
|
3922
3922
|
description,
|
|
3923
3923
|
agentIds: toStringArray(record["agentIds"]),
|
|
3924
3924
|
agentHandles: toStringArray(record["agentHandles"]),
|
|
3925
|
-
lastUsedAt:
|
|
3926
|
-
revokedAt:
|
|
3927
|
-
createdAt:
|
|
3928
|
-
updatedAt:
|
|
3925
|
+
lastUsedAt: toMaybeString2(record["lastUsedAt"]),
|
|
3926
|
+
revokedAt: toMaybeString2(record["revokedAt"]),
|
|
3927
|
+
createdAt: toMaybeString2(record["createdAt"]),
|
|
3928
|
+
updatedAt: toMaybeString2(record["updatedAt"])
|
|
3929
3929
|
};
|
|
3930
3930
|
}
|
|
3931
3931
|
function normalizeSecretList(payload) {
|
|
@@ -4160,6 +4160,8 @@ init_config();
|
|
|
4160
4160
|
init_controller_fetch();
|
|
4161
4161
|
init_errors();
|
|
4162
4162
|
init_project_manifest();
|
|
4163
|
+
import fs6 from "node:fs";
|
|
4164
|
+
import path7 from "node:path";
|
|
4163
4165
|
import kleur5 from "kleur";
|
|
4164
4166
|
var UUID_PATTERN2 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
4165
4167
|
function normalizeUuidParam(raw) {
|
|
@@ -4253,24 +4255,25 @@ function normalizeAutomationRecord(input3) {
|
|
|
4253
4255
|
if (!id || !name)
|
|
4254
4256
|
return null;
|
|
4255
4257
|
const toMaybeNumber = (value) => typeof value === "number" && Number.isFinite(value) ? value : null;
|
|
4256
|
-
const
|
|
4258
|
+
const toMaybeString2 = (value) => typeof value === "string" && value.trim() ? value.trim() : null;
|
|
4257
4259
|
return {
|
|
4258
4260
|
id,
|
|
4259
4261
|
name,
|
|
4260
4262
|
scheduleKind: typeof record.scheduleKind === "string" ? record.scheduleKind : "",
|
|
4261
|
-
runAt:
|
|
4263
|
+
runAt: toMaybeString2(record.runAt),
|
|
4262
4264
|
intervalHours: toMaybeNumber(record.intervalHours),
|
|
4263
4265
|
byDay: Array.isArray(record.byDay) ? record.byDay.filter((entry) => typeof entry === "string") : [],
|
|
4264
4266
|
byHour: toMaybeNumber(record.byHour),
|
|
4265
4267
|
byMinute: toMaybeNumber(record.byMinute),
|
|
4266
4268
|
timezone: typeof record.timezone === "string" ? record.timezone : "UTC",
|
|
4267
4269
|
runtimeMode: typeof record.runtimeMode === "string" ? record.runtimeMode : "auto",
|
|
4268
|
-
runtimeProvider:
|
|
4270
|
+
runtimeProvider: toMaybeString2(record.runtimeProvider),
|
|
4269
4271
|
silentWhenNothingToReport: record.silentWhenNothingToReport === true,
|
|
4272
|
+
resultVisibility: record.resultVisibility === "team" ? "team" : "private",
|
|
4270
4273
|
status: typeof record.status === "string" ? record.status : "active",
|
|
4271
|
-
nextRunAt:
|
|
4272
|
-
lastRunAt:
|
|
4273
|
-
lastError:
|
|
4274
|
+
nextRunAt: toMaybeString2(record.nextRunAt),
|
|
4275
|
+
lastRunAt: toMaybeString2(record.lastRunAt),
|
|
4276
|
+
lastError: toMaybeString2(record.lastError)
|
|
4274
4277
|
};
|
|
4275
4278
|
}
|
|
4276
4279
|
function listToRecords(payload) {
|
|
@@ -4369,9 +4372,10 @@ async function automationsList(options) {
|
|
|
4369
4372
|
const status = record.status === "paused" ? kleur5.gray("paused") : kleur5.green("active");
|
|
4370
4373
|
const next = record.nextRunAt ? kleur5.cyan(record.nextRunAt) : kleur5.gray("n/a");
|
|
4371
4374
|
const delivery = record.silentWhenNothingToReport ? " \xB7 findings only" : "";
|
|
4375
|
+
const sharing = record.resultVisibility === "team" ? ` \xB7 ${kleur5.cyan("team-visible")}` : "";
|
|
4372
4376
|
console.log(`${kleur5.bold(record.name)} ${kleur5.gray(record.id)}`);
|
|
4373
4377
|
console.log(
|
|
4374
|
-
` ${schedule} \xB7 ${record.runtimeMode}${delivery} \xB7 ${status} \xB7 next ${next}`
|
|
4378
|
+
` ${schedule} \xB7 ${record.runtimeMode}${delivery}${sharing} \xB7 ${status} \xB7 next ${next}`
|
|
4375
4379
|
);
|
|
4376
4380
|
if (record.lastError) {
|
|
4377
4381
|
console.log(` ${kleur5.red(record.lastError)}`);
|
|
@@ -4399,6 +4403,7 @@ async function automationsCreate(options) {
|
|
|
4399
4403
|
runtimeMode: options.runtimeMode ?? "auto",
|
|
4400
4404
|
runtimeProvider: options.runtimeProvider?.trim() || void 0,
|
|
4401
4405
|
silentWhenNothingToReport: options.silentWhenNothingToReport ?? false,
|
|
4406
|
+
resultVisibility: options.resultVisibility ?? void 0,
|
|
4402
4407
|
status: options.paused ? "paused" : "active"
|
|
4403
4408
|
};
|
|
4404
4409
|
if (scheduleKind === "once") {
|
|
@@ -4435,6 +4440,138 @@ async function automationsCreate(options) {
|
|
|
4435
4440
|
}
|
|
4436
4441
|
console.log(`${kleur5.green("Created")} ${kleur5.bold(record.name)} (${record.id})`);
|
|
4437
4442
|
}
|
|
4443
|
+
var SCHEDULE_KINDS = /* @__PURE__ */ new Set(["weekly", "hourly", "once"]);
|
|
4444
|
+
var RUNTIME_MODES = /* @__PURE__ */ new Set(["auto", "hosted", "existing"]);
|
|
4445
|
+
var UPDATE_FIELD_FLAGS = "--name, --prompt, --prompt-file, --schedule-kind, --run-at, --interval-hours, --days, --time, --timezone, --runtime-mode, --runtime-provider, --silent-when-nothing-to-report, --no-silent-when-nothing-to-report, --share-results, --no-share-results, --result-visibility";
|
|
4446
|
+
function readUpdatePrompt(options, cwd) {
|
|
4447
|
+
const hasPrompt = typeof options.prompt === "string";
|
|
4448
|
+
const hasPromptFile = typeof options.promptFile === "string";
|
|
4449
|
+
if (hasPrompt && hasPromptFile) {
|
|
4450
|
+
throw new Error("Pass either --prompt or --prompt-file, not both");
|
|
4451
|
+
}
|
|
4452
|
+
if (hasPromptFile) {
|
|
4453
|
+
const promptPath = path7.resolve(cwd, (options.promptFile ?? "").trim());
|
|
4454
|
+
let raw;
|
|
4455
|
+
try {
|
|
4456
|
+
raw = fs6.readFileSync(promptPath, "utf8");
|
|
4457
|
+
} catch (error) {
|
|
4458
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
4459
|
+
throw new Error(`Unable to read --prompt-file ${promptPath}: ${message}`);
|
|
4460
|
+
}
|
|
4461
|
+
const promptText = raw.trim();
|
|
4462
|
+
if (!promptText) {
|
|
4463
|
+
throw new Error(`--prompt-file ${promptPath} is empty`);
|
|
4464
|
+
}
|
|
4465
|
+
return promptText;
|
|
4466
|
+
}
|
|
4467
|
+
if (hasPrompt) {
|
|
4468
|
+
const promptText = (options.prompt ?? "").trim();
|
|
4469
|
+
if (!promptText) {
|
|
4470
|
+
throw new Error("--prompt must not be empty");
|
|
4471
|
+
}
|
|
4472
|
+
return promptText;
|
|
4473
|
+
}
|
|
4474
|
+
return void 0;
|
|
4475
|
+
}
|
|
4476
|
+
function buildAutomationUpdateBody(options, cwd) {
|
|
4477
|
+
const body = {};
|
|
4478
|
+
if (typeof options.name === "string") {
|
|
4479
|
+
const name = options.name.trim();
|
|
4480
|
+
if (!name) {
|
|
4481
|
+
throw new Error("--name must not be empty");
|
|
4482
|
+
}
|
|
4483
|
+
body.name = name;
|
|
4484
|
+
}
|
|
4485
|
+
const promptText = readUpdatePrompt(options, cwd);
|
|
4486
|
+
if (promptText !== void 0) {
|
|
4487
|
+
body.promptText = promptText;
|
|
4488
|
+
}
|
|
4489
|
+
if (typeof options.scheduleKind === "string") {
|
|
4490
|
+
const scheduleKind = options.scheduleKind.trim().toLowerCase();
|
|
4491
|
+
if (!SCHEDULE_KINDS.has(scheduleKind)) {
|
|
4492
|
+
throw new Error("--schedule-kind must be weekly, hourly, or once");
|
|
4493
|
+
}
|
|
4494
|
+
body.scheduleKind = scheduleKind;
|
|
4495
|
+
}
|
|
4496
|
+
if (typeof options.runAt === "string") {
|
|
4497
|
+
const runAt = options.runAt.trim();
|
|
4498
|
+
if (!runAt) {
|
|
4499
|
+
throw new Error("--run-at must not be empty");
|
|
4500
|
+
}
|
|
4501
|
+
body.runAt = runAt;
|
|
4502
|
+
}
|
|
4503
|
+
if (options.intervalHours !== void 0) {
|
|
4504
|
+
const interval = Number(options.intervalHours);
|
|
4505
|
+
if (!Number.isFinite(interval) || interval < 1) {
|
|
4506
|
+
throw new Error("--interval-hours must be >= 1");
|
|
4507
|
+
}
|
|
4508
|
+
body.intervalHours = interval;
|
|
4509
|
+
}
|
|
4510
|
+
if (typeof options.days === "string") {
|
|
4511
|
+
body.byDay = normalizeDays(options.days);
|
|
4512
|
+
}
|
|
4513
|
+
if (typeof options.time === "string") {
|
|
4514
|
+
const { hour, minute } = parseTime(options.time);
|
|
4515
|
+
body.byHour = hour;
|
|
4516
|
+
body.byMinute = minute;
|
|
4517
|
+
}
|
|
4518
|
+
if (typeof options.timezone === "string") {
|
|
4519
|
+
const timezone = options.timezone.trim();
|
|
4520
|
+
if (!timezone) {
|
|
4521
|
+
throw new Error("--timezone must not be empty");
|
|
4522
|
+
}
|
|
4523
|
+
body.timezone = timezone;
|
|
4524
|
+
}
|
|
4525
|
+
if (typeof options.runtimeMode === "string") {
|
|
4526
|
+
const runtimeMode = options.runtimeMode.trim().toLowerCase();
|
|
4527
|
+
if (!RUNTIME_MODES.has(runtimeMode)) {
|
|
4528
|
+
throw new Error("--runtime-mode must be auto, hosted, or existing");
|
|
4529
|
+
}
|
|
4530
|
+
body.runtimeMode = runtimeMode;
|
|
4531
|
+
}
|
|
4532
|
+
if (typeof options.runtimeProvider === "string") {
|
|
4533
|
+
const runtimeProvider = options.runtimeProvider.trim();
|
|
4534
|
+
if (!runtimeProvider) {
|
|
4535
|
+
throw new Error("--runtime-provider must not be empty");
|
|
4536
|
+
}
|
|
4537
|
+
body.runtimeProvider = runtimeProvider;
|
|
4538
|
+
}
|
|
4539
|
+
if (typeof options.silentWhenNothingToReport === "boolean") {
|
|
4540
|
+
body.silentWhenNothingToReport = options.silentWhenNothingToReport;
|
|
4541
|
+
}
|
|
4542
|
+
if (options.resultVisibility !== void 0) {
|
|
4543
|
+
body.resultVisibility = options.resultVisibility;
|
|
4544
|
+
}
|
|
4545
|
+
return body;
|
|
4546
|
+
}
|
|
4547
|
+
async function automationsUpdate(options) {
|
|
4548
|
+
const automationId = normalizeUuidParam(options.automationId);
|
|
4549
|
+
if (!automationId) {
|
|
4550
|
+
throw new Error("automationId must be a UUID");
|
|
4551
|
+
}
|
|
4552
|
+
const cwd = options.cwd ?? process.cwd();
|
|
4553
|
+
const body = buildAutomationUpdateBody(options, cwd);
|
|
4554
|
+
if (Object.keys(body).length === 0) {
|
|
4555
|
+
throw new Error(`Nothing to update. Pass at least one of ${UPDATE_FIELD_FLAGS}.`);
|
|
4556
|
+
}
|
|
4557
|
+
const auth = resolveControllerAuth2(options, "instafy login");
|
|
4558
|
+
const payload = await controllerJsonRequest2(auth, "instafy login", {
|
|
4559
|
+
method: "PATCH",
|
|
4560
|
+
path: `/automations/${automationId}`,
|
|
4561
|
+
body
|
|
4562
|
+
});
|
|
4563
|
+
if (options.json) {
|
|
4564
|
+
console.log(JSON.stringify(payload, null, 2));
|
|
4565
|
+
return;
|
|
4566
|
+
}
|
|
4567
|
+
const record = normalizeAutomationRecord(payload);
|
|
4568
|
+
if (!record) {
|
|
4569
|
+
console.log(kleur5.green("Automation updated."));
|
|
4570
|
+
return;
|
|
4571
|
+
}
|
|
4572
|
+
const sharing = record.resultVisibility === "team" ? " \xB7 results shared with the team" : record.resultVisibility === "private" ? " \xB7 results kept private" : "";
|
|
4573
|
+
console.log(`${kleur5.green("Updated")} ${kleur5.bold(record.name)} (${record.id})${sharing}`);
|
|
4574
|
+
}
|
|
4438
4575
|
async function automationsUpdateStatus(options) {
|
|
4439
4576
|
const auth = resolveControllerAuth2(options, "instafy login");
|
|
4440
4577
|
const automationId = normalizeUuidParam(options.automationId);
|
|
@@ -4485,13 +4622,375 @@ async function automationsDelete(options) {
|
|
|
4485
4622
|
console.log(kleur5.green("Deleted."));
|
|
4486
4623
|
}
|
|
4487
4624
|
|
|
4625
|
+
// src/credentials.ts
|
|
4626
|
+
init_config();
|
|
4627
|
+
init_controller_fetch();
|
|
4628
|
+
init_errors();
|
|
4629
|
+
import kleur6 from "kleur";
|
|
4630
|
+
var promptsModule2 = null;
|
|
4631
|
+
async function loadPrompts2() {
|
|
4632
|
+
promptsModule2 ??= import("@clack/prompts");
|
|
4633
|
+
return promptsModule2;
|
|
4634
|
+
}
|
|
4635
|
+
var RETRY_COMMAND = "instafy login";
|
|
4636
|
+
var SHORT_ID_LENGTH = 8;
|
|
4637
|
+
var TEST_OUTPUT_PREVIEW_CHARS = 300;
|
|
4638
|
+
var CREDENTIAL_TEST_TIMEOUT_MS = 9e4;
|
|
4639
|
+
function resolveControllerAuth3(options) {
|
|
4640
|
+
const cwd = options.cwd ?? process.cwd();
|
|
4641
|
+
const controllerUrl = resolveControllerUrl({
|
|
4642
|
+
controllerUrl: options.controllerUrl ?? null,
|
|
4643
|
+
cwd
|
|
4644
|
+
});
|
|
4645
|
+
const resolved = resolveUserAccessTokenWithSource({
|
|
4646
|
+
accessToken: options.accessToken ?? null,
|
|
4647
|
+
cwd
|
|
4648
|
+
});
|
|
4649
|
+
if (!resolved.token) {
|
|
4650
|
+
throw formatAuthRequiredError({
|
|
4651
|
+
retryCommand: RETRY_COMMAND,
|
|
4652
|
+
advancedHint: "pass --access-token, or set INSTAFY_ACCESS_TOKEN / SUPABASE_ACCESS_TOKEN"
|
|
4653
|
+
});
|
|
4654
|
+
}
|
|
4655
|
+
return {
|
|
4656
|
+
controllerUrl,
|
|
4657
|
+
accessToken: resolved.token,
|
|
4658
|
+
tokenSource: resolved.source,
|
|
4659
|
+
profile: resolved.profile,
|
|
4660
|
+
cwd
|
|
4661
|
+
};
|
|
4662
|
+
}
|
|
4663
|
+
async function controllerJsonRequest3(auth, params) {
|
|
4664
|
+
const url = `${auth.controllerUrl.replace(/\/$/, "")}${params.path}`;
|
|
4665
|
+
const headers = new Headers();
|
|
4666
|
+
headers.set("accept", "application/json");
|
|
4667
|
+
const init = { method: params.method, headers };
|
|
4668
|
+
if (params.timeoutMs !== void 0) {
|
|
4669
|
+
init.signal = AbortSignal.timeout(params.timeoutMs);
|
|
4670
|
+
}
|
|
4671
|
+
const response = (await fetchWithControllerAuth({
|
|
4672
|
+
url,
|
|
4673
|
+
init,
|
|
4674
|
+
accessToken: auth.accessToken,
|
|
4675
|
+
tokenSource: auth.tokenSource,
|
|
4676
|
+
profile: auth.profile,
|
|
4677
|
+
cwd: auth.cwd
|
|
4678
|
+
})).response;
|
|
4679
|
+
const text = await response.text().catch(() => "");
|
|
4680
|
+
if (response.status === 401 || response.status === 403) {
|
|
4681
|
+
throw formatAuthRejectedError({
|
|
4682
|
+
status: response.status,
|
|
4683
|
+
responseBody: text,
|
|
4684
|
+
retryCommand: RETRY_COMMAND,
|
|
4685
|
+
advancedHint: "run `instafy login`, or pass --access-token"
|
|
4686
|
+
});
|
|
4687
|
+
}
|
|
4688
|
+
if (!response.ok) {
|
|
4689
|
+
throw new Error(`Request failed (${response.status} ${response.statusText}): ${text}`);
|
|
4690
|
+
}
|
|
4691
|
+
return text ? JSON.parse(text) : null;
|
|
4692
|
+
}
|
|
4693
|
+
function credentialTestTimeoutMs() {
|
|
4694
|
+
const configured = Number(process.env["INSTAFY_HTTP_TIMEOUT_MS"]);
|
|
4695
|
+
const base = Number.isFinite(configured) && configured > 0 ? configured : 0;
|
|
4696
|
+
return Math.max(base, CREDENTIAL_TEST_TIMEOUT_MS);
|
|
4697
|
+
}
|
|
4698
|
+
function toMaybeString(value) {
|
|
4699
|
+
return typeof value === "string" && value.trim() ? value.trim() : null;
|
|
4700
|
+
}
|
|
4701
|
+
function normalizeCredentialRecord(input3) {
|
|
4702
|
+
if (!input3 || typeof input3 !== "object")
|
|
4703
|
+
return null;
|
|
4704
|
+
const record = input3;
|
|
4705
|
+
const id = toMaybeString(record.id);
|
|
4706
|
+
if (!id)
|
|
4707
|
+
return null;
|
|
4708
|
+
const metadata = record.metadata && typeof record.metadata === "object" ? record.metadata : {};
|
|
4709
|
+
return {
|
|
4710
|
+
id,
|
|
4711
|
+
kind: toMaybeString(record.kind) ?? "unknown",
|
|
4712
|
+
label: toMaybeString(record.label),
|
|
4713
|
+
provider: toMaybeString(metadata.provider),
|
|
4714
|
+
defaultModel: toMaybeString(metadata.default_model),
|
|
4715
|
+
isDefault: record.isDefault === true,
|
|
4716
|
+
lastUsedAt: toMaybeString(record.lastUsedAt),
|
|
4717
|
+
revokedAt: toMaybeString(record.revokedAt),
|
|
4718
|
+
createdAt: toMaybeString(record.createdAt),
|
|
4719
|
+
updatedAt: toMaybeString(record.updatedAt)
|
|
4720
|
+
};
|
|
4721
|
+
}
|
|
4722
|
+
function listToRecords2(payload) {
|
|
4723
|
+
if (!Array.isArray(payload))
|
|
4724
|
+
return [];
|
|
4725
|
+
const out = [];
|
|
4726
|
+
for (const item of payload) {
|
|
4727
|
+
const normalized = normalizeCredentialRecord(item);
|
|
4728
|
+
if (normalized)
|
|
4729
|
+
out.push(normalized);
|
|
4730
|
+
}
|
|
4731
|
+
return out;
|
|
4732
|
+
}
|
|
4733
|
+
function normalizeTestResult(payload) {
|
|
4734
|
+
const record = payload && typeof payload === "object" ? payload : {};
|
|
4735
|
+
const elapsed = record.elapsedMs;
|
|
4736
|
+
return {
|
|
4737
|
+
ok: record.ok === true,
|
|
4738
|
+
provider: toMaybeString(record.provider),
|
|
4739
|
+
model: toMaybeString(record.model),
|
|
4740
|
+
output: typeof record.output === "string" ? record.output : null,
|
|
4741
|
+
upstreamEndpoint: toMaybeString(record.upstreamEndpoint),
|
|
4742
|
+
elapsedMs: typeof elapsed === "number" && Number.isFinite(elapsed) ? elapsed : null
|
|
4743
|
+
};
|
|
4744
|
+
}
|
|
4745
|
+
async function fetchCredentialRecords(auth) {
|
|
4746
|
+
const payload = await controllerJsonRequest3(auth, {
|
|
4747
|
+
method: "GET",
|
|
4748
|
+
path: "/me/credentials"
|
|
4749
|
+
});
|
|
4750
|
+
return listToRecords2(payload);
|
|
4751
|
+
}
|
|
4752
|
+
function shortCredentialId(id) {
|
|
4753
|
+
return id.slice(0, SHORT_ID_LENGTH);
|
|
4754
|
+
}
|
|
4755
|
+
function describeCredential(record) {
|
|
4756
|
+
const parts = [shortCredentialId(record.id), record.kind];
|
|
4757
|
+
if (record.provider)
|
|
4758
|
+
parts.push(record.provider);
|
|
4759
|
+
if (record.label)
|
|
4760
|
+
parts.push(`"${record.label}"`);
|
|
4761
|
+
if (record.revokedAt)
|
|
4762
|
+
parts.push("revoked");
|
|
4763
|
+
return parts.join(" \xB7 ");
|
|
4764
|
+
}
|
|
4765
|
+
function resolveCredentialRecord(records, idOrPrefix) {
|
|
4766
|
+
const needle = idOrPrefix.trim().toLowerCase();
|
|
4767
|
+
if (!needle) {
|
|
4768
|
+
throw new Error("Credential id is required. Run `instafy credentials list` to see ids.");
|
|
4769
|
+
}
|
|
4770
|
+
const exact = records.find((record) => record.id.toLowerCase() === needle);
|
|
4771
|
+
if (exact)
|
|
4772
|
+
return exact;
|
|
4773
|
+
const matches = records.filter((record) => record.id.toLowerCase().startsWith(needle));
|
|
4774
|
+
const active = matches.filter((record) => !record.revokedAt);
|
|
4775
|
+
if (active.length === 1) {
|
|
4776
|
+
return active[0];
|
|
4777
|
+
}
|
|
4778
|
+
if (active.length > 1) {
|
|
4779
|
+
const candidates = active.map((record) => ` ${describeCredential(record)}`).join("\n");
|
|
4780
|
+
throw new Error(
|
|
4781
|
+
`Credential id prefix "${idOrPrefix}" is ambiguous; it matches ${active.length} credentials:
|
|
4782
|
+
${candidates}
|
|
4783
|
+
|
|
4784
|
+
Use a longer prefix or the full id.`
|
|
4785
|
+
);
|
|
4786
|
+
}
|
|
4787
|
+
if (matches.length > 0) {
|
|
4788
|
+
throw new Error(
|
|
4789
|
+
`Credential "${idOrPrefix}" only matches revoked credentials. Run \`instafy credentials list --all\` to see them.`
|
|
4790
|
+
);
|
|
4791
|
+
}
|
|
4792
|
+
throw new Error(
|
|
4793
|
+
`No credential matches "${idOrPrefix}". Run \`instafy credentials list\` to see ids.`
|
|
4794
|
+
);
|
|
4795
|
+
}
|
|
4796
|
+
async function resolveCredential(auth, idOrPrefix) {
|
|
4797
|
+
const records = await fetchCredentialRecords(auth);
|
|
4798
|
+
return resolveCredentialRecord(records, idOrPrefix);
|
|
4799
|
+
}
|
|
4800
|
+
async function resolveActiveCredential(auth, idOrPrefix, action) {
|
|
4801
|
+
const record = await resolveCredential(auth, idOrPrefix);
|
|
4802
|
+
if (record.revokedAt) {
|
|
4803
|
+
throw new Error(
|
|
4804
|
+
`Credential ${describeCredential(record)} is revoked and cannot be ${action}. Run \`instafy credentials list\` to see active ids.`
|
|
4805
|
+
);
|
|
4806
|
+
}
|
|
4807
|
+
return record;
|
|
4808
|
+
}
|
|
4809
|
+
function formatTimestamp(value) {
|
|
4810
|
+
if (!value)
|
|
4811
|
+
return "never";
|
|
4812
|
+
const parsed = new Date(value);
|
|
4813
|
+
if (Number.isNaN(parsed.getTime()))
|
|
4814
|
+
return value;
|
|
4815
|
+
return `${parsed.toISOString().slice(0, 16).replace("T", " ")}Z`;
|
|
4816
|
+
}
|
|
4817
|
+
function truncateOutput(output2, limit) {
|
|
4818
|
+
const singleLine = output2.replace(/\s+/g, " ").trim();
|
|
4819
|
+
if (singleLine.length <= limit)
|
|
4820
|
+
return singleLine;
|
|
4821
|
+
return `${singleLine.slice(0, limit)}\u2026`;
|
|
4822
|
+
}
|
|
4823
|
+
function renderTable(headers, rows) {
|
|
4824
|
+
const widths = headers.map(
|
|
4825
|
+
(header, index) => Math.max(header.length, ...rows.map((row) => row[index]?.length ?? 0))
|
|
4826
|
+
);
|
|
4827
|
+
const line = (cells) => cells.map((cell, index) => cell.padEnd(widths[index])).join(" ").trimEnd();
|
|
4828
|
+
return [kleur6.bold(line(headers)), ...rows.map(line)].join("\n");
|
|
4829
|
+
}
|
|
4830
|
+
async function credentialsList(options) {
|
|
4831
|
+
const auth = resolveControllerAuth3(options);
|
|
4832
|
+
const records = await fetchCredentialRecords(auth);
|
|
4833
|
+
const visible = options.all ? records : records.filter((record) => !record.revokedAt);
|
|
4834
|
+
const hiddenRevoked = records.length - visible.length;
|
|
4835
|
+
if (options.json) {
|
|
4836
|
+
console.log(JSON.stringify(visible, null, 2));
|
|
4837
|
+
return;
|
|
4838
|
+
}
|
|
4839
|
+
if (visible.length === 0) {
|
|
4840
|
+
console.log(kleur6.gray(records.length === 0 ? "No credentials." : "No active credentials."));
|
|
4841
|
+
if (hiddenRevoked > 0) {
|
|
4842
|
+
console.log(kleur6.gray(`${hiddenRevoked} revoked hidden (use --all to show).`));
|
|
4843
|
+
}
|
|
4844
|
+
return;
|
|
4845
|
+
}
|
|
4846
|
+
const rows = visible.map((record) => [
|
|
4847
|
+
shortCredentialId(record.id),
|
|
4848
|
+
record.kind,
|
|
4849
|
+
record.provider ?? "-",
|
|
4850
|
+
record.defaultModel ?? "-",
|
|
4851
|
+
record.label ?? "-",
|
|
4852
|
+
record.isDefault ? "*" : "",
|
|
4853
|
+
formatTimestamp(record.lastUsedAt),
|
|
4854
|
+
record.revokedAt ? formatTimestamp(record.revokedAt) : ""
|
|
4855
|
+
]);
|
|
4856
|
+
console.log(
|
|
4857
|
+
renderTable(
|
|
4858
|
+
["ID", "KIND", "PROVIDER", "MODEL", "LABEL", "DEFAULT", "LAST USED", "REVOKED"],
|
|
4859
|
+
rows
|
|
4860
|
+
)
|
|
4861
|
+
);
|
|
4862
|
+
if (hiddenRevoked > 0) {
|
|
4863
|
+
console.log(kleur6.gray(`${hiddenRevoked} revoked hidden (use --all to show).`));
|
|
4864
|
+
}
|
|
4865
|
+
if (!visible.some((record) => record.isDefault && !record.revokedAt)) {
|
|
4866
|
+
console.log(
|
|
4867
|
+
kleur6.yellow(
|
|
4868
|
+
"No default credential. Jobs cannot pick one automatically; run `instafy credentials default <id>`."
|
|
4869
|
+
)
|
|
4870
|
+
);
|
|
4871
|
+
}
|
|
4872
|
+
}
|
|
4873
|
+
async function credentialsTest(options) {
|
|
4874
|
+
const auth = resolveControllerAuth3(options);
|
|
4875
|
+
const record = await resolveActiveCredential(auth, options.idOrPrefix, "tested");
|
|
4876
|
+
if (!options.json) {
|
|
4877
|
+
console.log(
|
|
4878
|
+
kleur6.gray(
|
|
4879
|
+
`Testing ${describeCredential(record)} through the proxy (this calls the upstream provider and may take up to a minute)\u2026`
|
|
4880
|
+
)
|
|
4881
|
+
);
|
|
4882
|
+
}
|
|
4883
|
+
const payload = await controllerJsonRequest3(auth, {
|
|
4884
|
+
method: "POST",
|
|
4885
|
+
path: `/me/credentials/${encodeURIComponent(record.id)}/test`,
|
|
4886
|
+
timeoutMs: credentialTestTimeoutMs()
|
|
4887
|
+
});
|
|
4888
|
+
const result = normalizeTestResult(payload);
|
|
4889
|
+
if (options.json) {
|
|
4890
|
+
console.log(JSON.stringify({ credentialId: record.id, ...result }, null, 2));
|
|
4891
|
+
return result;
|
|
4892
|
+
}
|
|
4893
|
+
const status = result.ok ? kleur6.green("ok") : kleur6.red("failed");
|
|
4894
|
+
console.log(`${status} ${shortCredentialId(record.id)}`);
|
|
4895
|
+
console.log(` provider ${result.provider ?? "-"} \xB7 model ${result.model ?? "-"}`);
|
|
4896
|
+
if (result.upstreamEndpoint) {
|
|
4897
|
+
console.log(` upstream ${result.upstreamEndpoint}`);
|
|
4898
|
+
}
|
|
4899
|
+
if (result.elapsedMs !== null) {
|
|
4900
|
+
console.log(` elapsed ${result.elapsedMs} ms`);
|
|
4901
|
+
}
|
|
4902
|
+
if (result.output) {
|
|
4903
|
+
const preview = truncateOutput(result.output, TEST_OUTPUT_PREVIEW_CHARS);
|
|
4904
|
+
console.log(` output ${result.ok ? preview : kleur6.red(preview)}`);
|
|
4905
|
+
}
|
|
4906
|
+
return result;
|
|
4907
|
+
}
|
|
4908
|
+
async function credentialsSetDefault(options) {
|
|
4909
|
+
const auth = resolveControllerAuth3(options);
|
|
4910
|
+
const record = await resolveActiveCredential(auth, options.idOrPrefix, "made the default");
|
|
4911
|
+
const payload = await controllerJsonRequest3(auth, {
|
|
4912
|
+
method: "POST",
|
|
4913
|
+
path: `/me/credentials/${encodeURIComponent(record.id)}/default`
|
|
4914
|
+
});
|
|
4915
|
+
const response = payload && typeof payload === "object" ? payload : {};
|
|
4916
|
+
if (options.json) {
|
|
4917
|
+
console.log(
|
|
4918
|
+
JSON.stringify(
|
|
4919
|
+
{
|
|
4920
|
+
ok: true,
|
|
4921
|
+
credentialId: toMaybeString(response.credentialId) ?? record.id,
|
|
4922
|
+
kind: toMaybeString(response.kind) ?? record.kind,
|
|
4923
|
+
isDefault: response.isDefault !== false
|
|
4924
|
+
},
|
|
4925
|
+
null,
|
|
4926
|
+
2
|
|
4927
|
+
)
|
|
4928
|
+
);
|
|
4929
|
+
return;
|
|
4930
|
+
}
|
|
4931
|
+
console.log(`${kleur6.green("Default set:")} ${describeCredential(record)}`);
|
|
4932
|
+
}
|
|
4933
|
+
async function credentialsClearDefault(options) {
|
|
4934
|
+
const auth = resolveControllerAuth3(options);
|
|
4935
|
+
await controllerJsonRequest3(auth, {
|
|
4936
|
+
method: "DELETE",
|
|
4937
|
+
path: "/me/credentials/default"
|
|
4938
|
+
});
|
|
4939
|
+
if (options.json) {
|
|
4940
|
+
console.log(JSON.stringify({ ok: true, hasDefaultCredential: false }, null, 2));
|
|
4941
|
+
return;
|
|
4942
|
+
}
|
|
4943
|
+
console.log(kleur6.green("Default cleared."));
|
|
4944
|
+
console.log(kleur6.gray("Jobs will not pick a credential automatically until you set a new default."));
|
|
4945
|
+
}
|
|
4946
|
+
async function confirmRevoke(record, json) {
|
|
4947
|
+
const interactive = Boolean(
|
|
4948
|
+
process.stdin.isTTY && process.stdout.isTTY && json !== true && process.env.CI !== "true"
|
|
4949
|
+
);
|
|
4950
|
+
if (!interactive) {
|
|
4951
|
+
throw new Error(
|
|
4952
|
+
`Refusing to revoke ${describeCredential(record)} without confirmation. Re-run with --yes.`
|
|
4953
|
+
);
|
|
4954
|
+
}
|
|
4955
|
+
const { confirm, isCancel } = await loadPrompts2();
|
|
4956
|
+
console.log(kleur6.yellow(`Revoke ${describeCredential(record)} (${record.id})?`));
|
|
4957
|
+
console.log(kleur6.gray("Agents bound to this credential are disconnected and jobs stop using it."));
|
|
4958
|
+
const answer = await confirm({ message: "Revoke this credential?", initialValue: false });
|
|
4959
|
+
if (isCancel(answer) || !answer) {
|
|
4960
|
+
throw new Error("Cancelled.");
|
|
4961
|
+
}
|
|
4962
|
+
}
|
|
4963
|
+
async function credentialsRevoke(options) {
|
|
4964
|
+
const auth = resolveControllerAuth3(options);
|
|
4965
|
+
const record = await resolveActiveCredential(auth, options.idOrPrefix, "revoked again");
|
|
4966
|
+
if (!options.yes) {
|
|
4967
|
+
await confirmRevoke(record, options.json);
|
|
4968
|
+
}
|
|
4969
|
+
await controllerJsonRequest3(auth, {
|
|
4970
|
+
method: "DELETE",
|
|
4971
|
+
path: `/me/credentials/${encodeURIComponent(record.id)}`
|
|
4972
|
+
});
|
|
4973
|
+
if (options.json) {
|
|
4974
|
+
console.log(JSON.stringify({ ok: true, credentialId: record.id }, null, 2));
|
|
4975
|
+
return;
|
|
4976
|
+
}
|
|
4977
|
+
console.log(`${kleur6.green("Revoked:")} ${describeCredential(record)}`);
|
|
4978
|
+
if (record.isDefault) {
|
|
4979
|
+
console.log(
|
|
4980
|
+
kleur6.yellow(
|
|
4981
|
+
"This was the default credential. Set a new one with `instafy credentials default <id>`."
|
|
4982
|
+
)
|
|
4983
|
+
);
|
|
4984
|
+
}
|
|
4985
|
+
}
|
|
4986
|
+
|
|
4488
4987
|
// src/tunnel.ts
|
|
4489
|
-
import
|
|
4988
|
+
import fs7 from "node:fs";
|
|
4490
4989
|
import os4 from "node:os";
|
|
4491
|
-
import
|
|
4990
|
+
import path8 from "node:path";
|
|
4492
4991
|
import { spawn as spawn3 } from "node:child_process";
|
|
4493
4992
|
import { randomUUID } from "node:crypto";
|
|
4494
|
-
import
|
|
4993
|
+
import kleur7 from "kleur";
|
|
4495
4994
|
init_config();
|
|
4496
4995
|
init_errors();
|
|
4497
4996
|
init_controller_fetch();
|
|
@@ -4551,10 +5050,10 @@ function resolveRuntimeBoundControllerUrl(credential, selectedControllerUrl) {
|
|
|
4551
5050
|
}
|
|
4552
5051
|
|
|
4553
5052
|
// src/tunnel.ts
|
|
4554
|
-
var INSTAFY_DIR3 =
|
|
4555
|
-
var TUNNEL_STATE_FILE =
|
|
4556
|
-
var TUNNEL_LOG_DIR =
|
|
4557
|
-
var TUNNEL_WORKDIR_DIR =
|
|
5053
|
+
var INSTAFY_DIR3 = path8.join(os4.homedir(), ".instafy");
|
|
5054
|
+
var TUNNEL_STATE_FILE = path8.join(INSTAFY_DIR3, "cli-tunnel-state.json");
|
|
5055
|
+
var TUNNEL_LOG_DIR = path8.join(INSTAFY_DIR3, "cli-tunnel-logs");
|
|
5056
|
+
var TUNNEL_WORKDIR_DIR = path8.join(INSTAFY_DIR3, "cli-tunnel-workdirs");
|
|
4558
5057
|
var RATHOLE_ENVIRONMENT_KEYS = [
|
|
4559
5058
|
"PATH",
|
|
4560
5059
|
"HOME",
|
|
@@ -4636,7 +5135,7 @@ function resolveProject(opts) {
|
|
|
4636
5135
|
);
|
|
4637
5136
|
}
|
|
4638
5137
|
function writeProjectManifest(manifestPath, manifest) {
|
|
4639
|
-
|
|
5138
|
+
fs7.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2), "utf8");
|
|
4640
5139
|
}
|
|
4641
5140
|
function resolveTunnelAlias(opts, projectId) {
|
|
4642
5141
|
const name = normalizeTunnelPurpose(opts.name?.trim() ?? "") ?? "web";
|
|
@@ -4678,7 +5177,7 @@ function persistTunnelAliasResult(config, hostname, url) {
|
|
|
4678
5177
|
if (!config.manifestPath)
|
|
4679
5178
|
return;
|
|
4680
5179
|
try {
|
|
4681
|
-
const raw =
|
|
5180
|
+
const raw = fs7.readFileSync(config.manifestPath, "utf8");
|
|
4682
5181
|
const parsed = JSON.parse(raw);
|
|
4683
5182
|
if (!parsed?.tunnels || typeof parsed.tunnels !== "object") {
|
|
4684
5183
|
return;
|
|
@@ -4752,7 +5251,7 @@ function resolvePort(opts) {
|
|
|
4752
5251
|
return opts.port ?? (Number.isFinite(parsedEnv) ? parsedEnv : 3e3);
|
|
4753
5252
|
}
|
|
4754
5253
|
function ensureDir(dir) {
|
|
4755
|
-
|
|
5254
|
+
fs7.mkdirSync(dir, { recursive: true });
|
|
4756
5255
|
}
|
|
4757
5256
|
function safePathSegment(value) {
|
|
4758
5257
|
const trimmed = value.trim();
|
|
@@ -4762,15 +5261,15 @@ function safePathSegment(value) {
|
|
|
4762
5261
|
}
|
|
4763
5262
|
function writeStateFile(state) {
|
|
4764
5263
|
ensureDir(INSTAFY_DIR3);
|
|
4765
|
-
|
|
5264
|
+
fs7.writeFileSync(TUNNEL_STATE_FILE, JSON.stringify(state, null, 2), "utf8");
|
|
4766
5265
|
try {
|
|
4767
|
-
|
|
5266
|
+
fs7.chmodSync(TUNNEL_STATE_FILE, 384);
|
|
4768
5267
|
} catch {
|
|
4769
5268
|
}
|
|
4770
5269
|
}
|
|
4771
5270
|
function readStateFile() {
|
|
4772
5271
|
try {
|
|
4773
|
-
const raw =
|
|
5272
|
+
const raw = fs7.readFileSync(TUNNEL_STATE_FILE, "utf8");
|
|
4774
5273
|
const parsed = JSON.parse(raw);
|
|
4775
5274
|
if (!parsed || typeof parsed !== "object")
|
|
4776
5275
|
return { version: 1, tunnels: [] };
|
|
@@ -4934,8 +5433,8 @@ async function startTunnelSession(opts) {
|
|
|
4934
5433
|
env: process.env,
|
|
4935
5434
|
version: process.env.RATHOLE_VERSION ?? null,
|
|
4936
5435
|
cacheDir: process.env.RATHOLE_CACHE_DIR ?? null,
|
|
4937
|
-
logger: (message) => console.log(
|
|
4938
|
-
warn: (message) => console.warn(
|
|
5436
|
+
logger: (message) => console.log(kleur7.cyan(`[rathole] ${message}`)),
|
|
5437
|
+
warn: (message) => console.warn(kleur7.yellow(message))
|
|
4939
5438
|
});
|
|
4940
5439
|
if (!rathole) {
|
|
4941
5440
|
throw new Error(
|
|
@@ -4947,9 +5446,9 @@ async function startTunnelSession(opts) {
|
|
|
4947
5446
|
persistTunnelAliasResult(alias, grant.hostname, grant.url ?? `https://${grant.hostname}`);
|
|
4948
5447
|
const creds = grant.credentials && typeof grant.credentials === "object" ? grant.credentials : {};
|
|
4949
5448
|
const configBody = buildRatholeConfig(creds, port);
|
|
4950
|
-
const workdir =
|
|
4951
|
-
const configPath2 =
|
|
4952
|
-
|
|
5449
|
+
const workdir = fs7.mkdtempSync(path8.join(os4.tmpdir(), "instafy-cli-tunnel-"));
|
|
5450
|
+
const configPath2 = path8.join(workdir, "rathole.toml");
|
|
5451
|
+
fs7.writeFileSync(configPath2, configBody, { encoding: "utf8", mode: 384 });
|
|
4953
5452
|
const child = spawn3(rathole, ["-c", configPath2], {
|
|
4954
5453
|
stdio: "inherit",
|
|
4955
5454
|
cwd: workdir,
|
|
@@ -4961,11 +5460,11 @@ async function startTunnelSession(opts) {
|
|
|
4961
5460
|
cleanedUp = true;
|
|
4962
5461
|
child.kill("SIGTERM");
|
|
4963
5462
|
await revokeTunnel(controllerUrl, controllerToken, projectId, grant.tunnelId);
|
|
4964
|
-
|
|
5463
|
+
fs7.rmSync(workdir, { recursive: true, force: true });
|
|
4965
5464
|
};
|
|
4966
5465
|
child.on("exit", () => {
|
|
4967
5466
|
void cleanup().catch((error) => {
|
|
4968
|
-
console.warn(
|
|
5467
|
+
console.warn(kleur7.yellow(`Tunnel cleanup failed: ${String(error)}`));
|
|
4969
5468
|
});
|
|
4970
5469
|
});
|
|
4971
5470
|
return {
|
|
@@ -4978,7 +5477,7 @@ async function startTunnelSession(opts) {
|
|
|
4978
5477
|
async function runTunnelCommand(opts, options) {
|
|
4979
5478
|
const session = await startTunnelSession(opts);
|
|
4980
5479
|
console.log(
|
|
4981
|
-
|
|
5480
|
+
kleur7.green(`Tunnel ready: ${session.url} (tunnelId=${session.tunnelId})`)
|
|
4982
5481
|
);
|
|
4983
5482
|
const timeoutMs = options?.timeoutMs ?? null;
|
|
4984
5483
|
await new Promise((resolve) => {
|
|
@@ -5012,8 +5511,8 @@ async function startTunnelDetached(opts) {
|
|
|
5012
5511
|
env: process.env,
|
|
5013
5512
|
version: process.env.RATHOLE_VERSION ?? null,
|
|
5014
5513
|
cacheDir: process.env.RATHOLE_CACHE_DIR ?? null,
|
|
5015
|
-
logger: (message) => console.log(
|
|
5016
|
-
warn: (message) => console.warn(
|
|
5514
|
+
logger: (message) => console.log(kleur7.cyan(`[rathole] ${message}`)),
|
|
5515
|
+
warn: (message) => console.warn(kleur7.yellow(message))
|
|
5017
5516
|
});
|
|
5018
5517
|
if (!rathole) {
|
|
5019
5518
|
throw new Error(
|
|
@@ -5026,14 +5525,14 @@ async function startTunnelDetached(opts) {
|
|
|
5026
5525
|
ensureDir(TUNNEL_WORKDIR_DIR);
|
|
5027
5526
|
ensureDir(TUNNEL_LOG_DIR);
|
|
5028
5527
|
const tunnelIdSafe = safePathSegment(grant.tunnelId);
|
|
5029
|
-
const workdir =
|
|
5528
|
+
const workdir = path8.join(TUNNEL_WORKDIR_DIR, tunnelIdSafe);
|
|
5030
5529
|
ensureDir(workdir);
|
|
5031
5530
|
const creds = grant.credentials && typeof grant.credentials === "object" ? grant.credentials : {};
|
|
5032
5531
|
const configBody = buildRatholeConfig(creds, port);
|
|
5033
|
-
const configPath2 =
|
|
5034
|
-
|
|
5035
|
-
const logFile = opts.logFile?.trim() ?
|
|
5036
|
-
const logFd =
|
|
5532
|
+
const configPath2 = path8.join(workdir, "rathole.toml");
|
|
5533
|
+
fs7.writeFileSync(configPath2, configBody, { encoding: "utf8", mode: 384 });
|
|
5534
|
+
const logFile = opts.logFile?.trim() ? path8.resolve(opts.logFile.trim()) : path8.join(TUNNEL_LOG_DIR, `tunnel-${tunnelIdSafe}.log`);
|
|
5535
|
+
const logFd = fs7.openSync(logFile, "a");
|
|
5037
5536
|
const child = spawn3(rathole, ["-c", configPath2], {
|
|
5038
5537
|
stdio: ["ignore", logFd, logFd],
|
|
5039
5538
|
cwd: workdir,
|
|
@@ -5050,7 +5549,7 @@ async function startTunnelDetached(opts) {
|
|
|
5050
5549
|
if (exitedEarly || !isProcessAlive2(child.pid ?? -1)) {
|
|
5051
5550
|
const logTail = (() => {
|
|
5052
5551
|
try {
|
|
5053
|
-
const text =
|
|
5552
|
+
const text = fs7.readFileSync(logFile, "utf8");
|
|
5054
5553
|
const lines = text.split(/\r?\n/).filter(Boolean);
|
|
5055
5554
|
return lines.slice(-20).join("\n");
|
|
5056
5555
|
} catch {
|
|
@@ -5133,7 +5632,7 @@ async function stopTunnelSession(opts) {
|
|
|
5133
5632
|
throw error;
|
|
5134
5633
|
}
|
|
5135
5634
|
try {
|
|
5136
|
-
|
|
5635
|
+
fs7.rmSync(entry.workdir, { recursive: true, force: true });
|
|
5137
5636
|
} catch {
|
|
5138
5637
|
}
|
|
5139
5638
|
return { ok: true, tunnelId: entry.tunnelId };
|
|
@@ -5165,7 +5664,7 @@ async function tailTunnelLogs(options) {
|
|
|
5165
5664
|
return;
|
|
5166
5665
|
}
|
|
5167
5666
|
if (!follow) {
|
|
5168
|
-
const raw =
|
|
5667
|
+
const raw = fs7.existsSync(logFile) ? fs7.readFileSync(logFile, "utf8") : "";
|
|
5169
5668
|
const rows = raw.split(/\r?\n/);
|
|
5170
5669
|
const tail = rows.slice(Math.max(0, rows.length - lineCount));
|
|
5171
5670
|
console.log(tail.join("\n"));
|
|
@@ -5194,7 +5693,7 @@ async function tailTunnelLogs(options) {
|
|
|
5194
5693
|
// src/config-command.ts
|
|
5195
5694
|
init_config();
|
|
5196
5695
|
init_config();
|
|
5197
|
-
import
|
|
5696
|
+
import kleur8 from "kleur";
|
|
5198
5697
|
function normalizeKey(raw) {
|
|
5199
5698
|
const key = raw.trim().toLowerCase().replace(/_/g, "-");
|
|
5200
5699
|
if (key === "controller-url" || key === "controllerurl" || key === "server-url") {
|
|
@@ -5238,12 +5737,12 @@ function clearConfig(key) {
|
|
|
5238
5737
|
}
|
|
5239
5738
|
}
|
|
5240
5739
|
function configPath(options) {
|
|
5241
|
-
const
|
|
5740
|
+
const path15 = getInstafyConfigPath();
|
|
5242
5741
|
if (options?.json) {
|
|
5243
|
-
console.log(JSON.stringify({ path:
|
|
5742
|
+
console.log(JSON.stringify({ path: path15 }, null, 2));
|
|
5244
5743
|
return;
|
|
5245
5744
|
}
|
|
5246
|
-
console.log(
|
|
5745
|
+
console.log(path15);
|
|
5247
5746
|
}
|
|
5248
5747
|
function configList(options) {
|
|
5249
5748
|
const config = readInstafyCliConfig();
|
|
@@ -5260,13 +5759,13 @@ function configList(options) {
|
|
|
5260
5759
|
console.log(JSON.stringify(payload, null, 2));
|
|
5261
5760
|
return;
|
|
5262
5761
|
}
|
|
5263
|
-
console.log(
|
|
5762
|
+
console.log(kleur8.green("Instafy CLI config"));
|
|
5264
5763
|
console.log(`Path: ${payload.path}`);
|
|
5265
|
-
console.log(`controller-url: ${payload.controllerUrl ??
|
|
5764
|
+
console.log(`controller-url: ${payload.controllerUrl ?? kleur8.yellow("(not set)")}`);
|
|
5266
5765
|
console.log(`controller-url (effective): ${payload.effectiveControllerUrl}`);
|
|
5267
|
-
console.log(`studio-url: ${payload.studioUrl ??
|
|
5268
|
-
console.log(`access-token: ${payload.accessTokenSet ?
|
|
5269
|
-
console.log(`refresh-token: ${payload.refreshTokenSet ?
|
|
5766
|
+
console.log(`studio-url: ${payload.studioUrl ?? kleur8.yellow("(not set)")}`);
|
|
5767
|
+
console.log(`access-token: ${payload.accessTokenSet ? kleur8.green("(set)") : kleur8.yellow("(not set)")}`);
|
|
5768
|
+
console.log(`refresh-token: ${payload.refreshTokenSet ? kleur8.green("(set)") : kleur8.yellow("(not set)")}`);
|
|
5270
5769
|
if (payload.updatedAt) {
|
|
5271
5770
|
console.log(`updated-at: ${payload.updatedAt}`);
|
|
5272
5771
|
}
|
|
@@ -5295,7 +5794,7 @@ function configSet(params) {
|
|
|
5295
5794
|
console.log(JSON.stringify({ key, value, path: getInstafyConfigPath() }, null, 2));
|
|
5296
5795
|
return;
|
|
5297
5796
|
}
|
|
5298
|
-
console.log(
|
|
5797
|
+
console.log(kleur8.green(`Set ${key}`));
|
|
5299
5798
|
console.log(value);
|
|
5300
5799
|
}
|
|
5301
5800
|
function configUnset(params) {
|
|
@@ -5305,7 +5804,7 @@ function configUnset(params) {
|
|
|
5305
5804
|
console.log(JSON.stringify({ ok: true, key }, null, 2));
|
|
5306
5805
|
return;
|
|
5307
5806
|
}
|
|
5308
|
-
console.log(
|
|
5807
|
+
console.log(kleur8.green(`Unset ${key}`));
|
|
5309
5808
|
}
|
|
5310
5809
|
|
|
5311
5810
|
// src/index.ts
|
|
@@ -5314,28 +5813,28 @@ init_config();
|
|
|
5314
5813
|
// src/git-wrapper.ts
|
|
5315
5814
|
import { spawnSync as spawnSync4 } from "node:child_process";
|
|
5316
5815
|
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
5317
|
-
import
|
|
5318
|
-
import
|
|
5319
|
-
import
|
|
5816
|
+
import fs8 from "node:fs";
|
|
5817
|
+
import path9 from "node:path";
|
|
5818
|
+
import kleur9 from "kleur";
|
|
5320
5819
|
function pathExists(candidate) {
|
|
5321
5820
|
try {
|
|
5322
|
-
|
|
5821
|
+
fs8.statSync(candidate);
|
|
5323
5822
|
return true;
|
|
5324
5823
|
} catch {
|
|
5325
5824
|
return false;
|
|
5326
5825
|
}
|
|
5327
5826
|
}
|
|
5328
5827
|
function findInstafyGitContext(startDir) {
|
|
5329
|
-
let current =
|
|
5330
|
-
const root =
|
|
5828
|
+
let current = path9.resolve(startDir);
|
|
5829
|
+
const root = path9.parse(current).root;
|
|
5331
5830
|
while (true) {
|
|
5332
|
-
const gitDir =
|
|
5831
|
+
const gitDir = path9.join(current, ".instafy", ".git");
|
|
5333
5832
|
if (pathExists(gitDir)) {
|
|
5334
5833
|
return { workTree: current, gitDir };
|
|
5335
5834
|
}
|
|
5336
5835
|
if (current === root)
|
|
5337
5836
|
break;
|
|
5338
|
-
current =
|
|
5837
|
+
current = path9.dirname(current);
|
|
5339
5838
|
}
|
|
5340
5839
|
return null;
|
|
5341
5840
|
}
|
|
@@ -5382,9 +5881,9 @@ function validateGitArgs(userArgs) {
|
|
|
5382
5881
|
}
|
|
5383
5882
|
if (arg === "--git-dir" || arg.startsWith("--git-dir=") || arg === "--work-tree" || arg.startsWith("--work-tree=") || arg === "-C") {
|
|
5384
5883
|
throw new Error(
|
|
5385
|
-
`Unsupported argument "${arg}". Use ${
|
|
5884
|
+
`Unsupported argument "${arg}". Use ${kleur9.cyan(
|
|
5386
5885
|
"cd"
|
|
5387
|
-
)} instead; ${
|
|
5886
|
+
)} instead; ${kleur9.cyan("instafy git")} manages --git-dir/--work-tree automatically.`
|
|
5388
5887
|
);
|
|
5389
5888
|
}
|
|
5390
5889
|
if (arg === "-c" || arg === "--config-env" || arg === "--exec-path" || arg === "--namespace") {
|
|
@@ -5496,7 +5995,7 @@ function collectDirtyPaths(context, options) {
|
|
|
5496
5995
|
return unique;
|
|
5497
5996
|
}
|
|
5498
5997
|
function findEmbeddedGitDirs(context, pathSpecs) {
|
|
5499
|
-
const instafyGitDir =
|
|
5998
|
+
const instafyGitDir = path9.resolve(context.gitDir);
|
|
5500
5999
|
const seen = /* @__PURE__ */ new Set();
|
|
5501
6000
|
for (const rawPath of pathSpecs) {
|
|
5502
6001
|
const normalized = normalizePathSpec(rawPath).replace(/\/+$/, "");
|
|
@@ -5505,11 +6004,11 @@ function findEmbeddedGitDirs(context, pathSpecs) {
|
|
|
5505
6004
|
}
|
|
5506
6005
|
let cursor = normalized;
|
|
5507
6006
|
while (cursor && cursor !== ".") {
|
|
5508
|
-
const candidate =
|
|
5509
|
-
if (pathExists(candidate) &&
|
|
5510
|
-
seen.add(
|
|
6007
|
+
const candidate = path9.join(context.workTree, ...cursor.split("/"), ".git");
|
|
6008
|
+
if (pathExists(candidate) && path9.resolve(candidate) !== instafyGitDir) {
|
|
6009
|
+
seen.add(path9.resolve(candidate));
|
|
5511
6010
|
}
|
|
5512
|
-
const next =
|
|
6011
|
+
const next = path9.posix.dirname(cursor);
|
|
5513
6012
|
if (next === "." || next === cursor) {
|
|
5514
6013
|
break;
|
|
5515
6014
|
}
|
|
@@ -5518,8 +6017,8 @@ function findEmbeddedGitDirs(context, pathSpecs) {
|
|
|
5518
6017
|
}
|
|
5519
6018
|
const candidates = Array.from(seen);
|
|
5520
6019
|
candidates.sort((a, b) => {
|
|
5521
|
-
const depthA = a.split(
|
|
5522
|
-
const depthB = b.split(
|
|
6020
|
+
const depthA = a.split(path9.sep).length;
|
|
6021
|
+
const depthB = b.split(path9.sep).length;
|
|
5523
6022
|
return depthB - depthA;
|
|
5524
6023
|
});
|
|
5525
6024
|
return candidates;
|
|
@@ -5529,17 +6028,17 @@ function hideEmbeddedGitDirs(context, pathSpecs) {
|
|
|
5529
6028
|
if (candidates.length === 0) {
|
|
5530
6029
|
return [];
|
|
5531
6030
|
}
|
|
5532
|
-
const stagingBase =
|
|
5533
|
-
|
|
6031
|
+
const stagingBase = path9.join(context.workTree, ".instafy", "origin-staging", "embedded-git");
|
|
6032
|
+
fs8.mkdirSync(stagingBase, { recursive: true });
|
|
5534
6033
|
const renames = [];
|
|
5535
6034
|
for (const candidate of candidates) {
|
|
5536
|
-
let hidden =
|
|
6035
|
+
let hidden = path9.join(stagingBase, randomUUID2());
|
|
5537
6036
|
for (let attempt = 0; attempt < 8; attempt += 1) {
|
|
5538
6037
|
if (!pathExists(hidden))
|
|
5539
6038
|
break;
|
|
5540
|
-
hidden =
|
|
6039
|
+
hidden = path9.join(stagingBase, randomUUID2());
|
|
5541
6040
|
}
|
|
5542
|
-
|
|
6041
|
+
fs8.renameSync(candidate, hidden);
|
|
5543
6042
|
renames.push({ original: candidate, hidden });
|
|
5544
6043
|
}
|
|
5545
6044
|
return renames;
|
|
@@ -5550,7 +6049,7 @@ function restoreEmbeddedGitDirs(renames) {
|
|
|
5550
6049
|
if (!rename)
|
|
5551
6050
|
continue;
|
|
5552
6051
|
try {
|
|
5553
|
-
|
|
6052
|
+
fs8.renameSync(rename.hidden, rename.original);
|
|
5554
6053
|
} catch {
|
|
5555
6054
|
}
|
|
5556
6055
|
}
|
|
@@ -5620,15 +6119,15 @@ function runInstafyGit(userArgs, options) {
|
|
|
5620
6119
|
console.log("instafy git <git-args...>");
|
|
5621
6120
|
console.log("");
|
|
5622
6121
|
console.log(
|
|
5623
|
-
`Runs ${
|
|
6122
|
+
`Runs ${kleur9.cyan("git")} against the Instafy canonical repo at ${kleur9.cyan(
|
|
5624
6123
|
".instafy/.git"
|
|
5625
6124
|
)} (auto-detected by walking up from cwd).`
|
|
5626
6125
|
);
|
|
5627
6126
|
console.log("");
|
|
5628
6127
|
console.log("Example:");
|
|
5629
|
-
console.log(` ${
|
|
5630
|
-
console.log(` ${
|
|
5631
|
-
console.log(` ${
|
|
6128
|
+
console.log(` ${kleur9.cyan("instafy git status")}`);
|
|
6129
|
+
console.log(` ${kleur9.cyan("instafy git add -A")}`);
|
|
6130
|
+
console.log(` ${kleur9.cyan('instafy git commit -am "instafy: checkpoint"')}`);
|
|
5632
6131
|
return 0;
|
|
5633
6132
|
}
|
|
5634
6133
|
const context = findInstafyGitContext(cwd);
|
|
@@ -5638,8 +6137,8 @@ function runInstafyGit(userArgs, options) {
|
|
|
5638
6137
|
"No Instafy canonical git checkout found (expected .instafy/.git).",
|
|
5639
6138
|
"",
|
|
5640
6139
|
"Tips:",
|
|
5641
|
-
`- Run this inside a git-canonical workspace (where ${
|
|
5642
|
-
`- If you're trying to operate on a user repo, use normal ${
|
|
6140
|
+
`- Run this inside a git-canonical workspace (where ${kleur9.cyan(".instafy/.git")} exists).`,
|
|
6141
|
+
`- If you're trying to operate on a user repo, use normal ${kleur9.cyan("git")} (it uses .git).`
|
|
5643
6142
|
].join("\n")
|
|
5644
6143
|
);
|
|
5645
6144
|
}
|
|
@@ -5904,7 +6403,7 @@ async function runInstafyGitSync(args, options) {
|
|
|
5904
6403
|
}
|
|
5905
6404
|
} catch (error) {
|
|
5906
6405
|
const message = error instanceof Error ? error.message : String(error);
|
|
5907
|
-
console.warn(
|
|
6406
|
+
console.warn(kleur9.yellow(`[instafy git sync] ${message}; falling back to environment token.`));
|
|
5908
6407
|
}
|
|
5909
6408
|
}
|
|
5910
6409
|
if (!originToken) {
|
|
@@ -5952,7 +6451,7 @@ async function runInstafyGitSync(args, options) {
|
|
|
5952
6451
|
} catch (error) {
|
|
5953
6452
|
const message = error instanceof Error ? error.message : String(error);
|
|
5954
6453
|
console.warn(
|
|
5955
|
-
|
|
6454
|
+
kleur9.yellow(
|
|
5956
6455
|
`[instafy git sync] failed to recover from invalid origin token: ${message}`
|
|
5957
6456
|
)
|
|
5958
6457
|
);
|
|
@@ -5960,13 +6459,13 @@ async function runInstafyGitSync(args, options) {
|
|
|
5960
6459
|
}
|
|
5961
6460
|
if (!response.ok) {
|
|
5962
6461
|
const suffix = text.trim() ? `: ${text.trim()}` : "";
|
|
5963
|
-
console.error(
|
|
6462
|
+
console.error(kleur9.red(`Origin git sync failed (${response.status} ${response.statusText})${suffix}`));
|
|
5964
6463
|
return 1;
|
|
5965
6464
|
}
|
|
5966
6465
|
const payload = text.trim() ? JSON.parse(text) : null;
|
|
5967
6466
|
const rev = typeof payload?.rev === "string" ? payload.rev.trim() : "";
|
|
5968
6467
|
if (!rev) {
|
|
5969
|
-
console.error(
|
|
6468
|
+
console.error(kleur9.red("Origin git sync response missing rev field."));
|
|
5970
6469
|
return 1;
|
|
5971
6470
|
}
|
|
5972
6471
|
if (parsed.json) {
|
|
@@ -5981,7 +6480,7 @@ async function runInstafyGitSync(args, options) {
|
|
|
5981
6480
|
init_config();
|
|
5982
6481
|
init_errors();
|
|
5983
6482
|
init_controller_fetch();
|
|
5984
|
-
import
|
|
6483
|
+
import fs9 from "node:fs";
|
|
5985
6484
|
function normalizeUrl5(raw) {
|
|
5986
6485
|
const value = (raw ?? "").trim();
|
|
5987
6486
|
if (!value)
|
|
@@ -6060,7 +6559,7 @@ function parseHeader(raw) {
|
|
|
6060
6559
|
}
|
|
6061
6560
|
function parseJsonBody(options) {
|
|
6062
6561
|
if (options.jsonFile) {
|
|
6063
|
-
const raw =
|
|
6562
|
+
const raw = fs9.readFileSync(options.jsonFile, "utf8");
|
|
6064
6563
|
const parsed = JSON.parse(raw);
|
|
6065
6564
|
return JSON.stringify(parsed);
|
|
6066
6565
|
}
|
|
@@ -6298,9 +6797,9 @@ async function historyConversations(options) {
|
|
|
6298
6797
|
|
|
6299
6798
|
// src/hardware-bindings.ts
|
|
6300
6799
|
init_project_manifest();
|
|
6301
|
-
import
|
|
6302
|
-
import
|
|
6303
|
-
import
|
|
6800
|
+
import fs10 from "node:fs";
|
|
6801
|
+
import path10 from "node:path";
|
|
6802
|
+
import kleur10 from "kleur";
|
|
6304
6803
|
var SERIAL_HARDWARE_PROVIDER_ID = "hardware.serial";
|
|
6305
6804
|
var DEFAULT_SERIAL_CAPABILITIES = [
|
|
6306
6805
|
"hardware_serial_list",
|
|
@@ -6310,7 +6809,7 @@ var SUPPORTED_HARDWARE_CAPABILITIES = new Set(
|
|
|
6310
6809
|
DEFAULT_SERIAL_CAPABILITIES
|
|
6311
6810
|
);
|
|
6312
6811
|
function resolveHardwareBindingContext(startDir) {
|
|
6313
|
-
const lookup = findProjectManifest(
|
|
6812
|
+
const lookup = findProjectManifest(path10.resolve(startDir));
|
|
6314
6813
|
if (!lookup.manifest || !lookup.path) {
|
|
6315
6814
|
throw new Error(
|
|
6316
6815
|
"Linked space manifest required. Run `instafy space init` in this folder or pass --path <dir>."
|
|
@@ -6320,17 +6819,17 @@ function resolveHardwareBindingContext(startDir) {
|
|
|
6320
6819
|
if (!projectId) {
|
|
6321
6820
|
throw new Error("Linked space manifest is missing a spaceId.");
|
|
6322
6821
|
}
|
|
6323
|
-
const instafyDir =
|
|
6822
|
+
const instafyDir = path10.dirname(lookup.path);
|
|
6324
6823
|
return {
|
|
6325
|
-
bindingsPath:
|
|
6824
|
+
bindingsPath: path10.join(instafyDir, "hardware-bindings.json"),
|
|
6326
6825
|
projectId
|
|
6327
6826
|
};
|
|
6328
6827
|
}
|
|
6329
6828
|
function readHardwareBindingStore(bindingsPath) {
|
|
6330
|
-
if (!
|
|
6829
|
+
if (!fs10.existsSync(bindingsPath)) {
|
|
6331
6830
|
return { version: 1, bindings: {} };
|
|
6332
6831
|
}
|
|
6333
|
-
const raw = JSON.parse(
|
|
6832
|
+
const raw = JSON.parse(fs10.readFileSync(bindingsPath, "utf8"));
|
|
6334
6833
|
const bindings = raw && typeof raw.bindings === "object" && raw.bindings !== null ? raw.bindings : {};
|
|
6335
6834
|
return {
|
|
6336
6835
|
version: 1,
|
|
@@ -6338,8 +6837,8 @@ function readHardwareBindingStore(bindingsPath) {
|
|
|
6338
6837
|
};
|
|
6339
6838
|
}
|
|
6340
6839
|
function writeHardwareBindingStore(bindingsPath, store) {
|
|
6341
|
-
|
|
6342
|
-
|
|
6840
|
+
fs10.mkdirSync(path10.dirname(bindingsPath), { recursive: true });
|
|
6841
|
+
fs10.writeFileSync(bindingsPath, JSON.stringify(store, null, 2), "utf8");
|
|
6343
6842
|
}
|
|
6344
6843
|
function normalizeCapabilities(providerId, values) {
|
|
6345
6844
|
const requested = Array.isArray(values) && values.length > 0 ? values : providerId === SERIAL_HARDWARE_PROVIDER_ID ? DEFAULT_SERIAL_CAPABILITIES : [];
|
|
@@ -6367,18 +6866,18 @@ function normalizeDevices(values) {
|
|
|
6367
6866
|
if (!trimmed) {
|
|
6368
6867
|
continue;
|
|
6369
6868
|
}
|
|
6370
|
-
const resolved =
|
|
6869
|
+
const resolved = path10.resolve(trimmed);
|
|
6371
6870
|
unique.set(resolved, {
|
|
6372
6871
|
kind: "serial_device",
|
|
6373
6872
|
id: resolved,
|
|
6374
6873
|
path: resolved,
|
|
6375
|
-
displayName:
|
|
6874
|
+
displayName: path10.basename(resolved)
|
|
6376
6875
|
});
|
|
6377
6876
|
}
|
|
6378
6877
|
return [...unique.values()];
|
|
6379
6878
|
}
|
|
6380
6879
|
function printHardwareBinding(record) {
|
|
6381
|
-
console.log(
|
|
6880
|
+
console.log(kleur10.cyan(`Hardware provider: ${record.providerId}`));
|
|
6382
6881
|
console.log(`Status: ${record.status}`);
|
|
6383
6882
|
console.log(`Project: ${record.projectId}`);
|
|
6384
6883
|
console.log(`Capabilities: ${record.grantedCapabilities.join(", ") || "(none)"}`);
|
|
@@ -6424,10 +6923,10 @@ function showHardwareBinding(options) {
|
|
|
6424
6923
|
return;
|
|
6425
6924
|
}
|
|
6426
6925
|
if (bindings.length === 0) {
|
|
6427
|
-
console.log(
|
|
6926
|
+
console.log(kleur10.yellow("No hardware bindings recorded for this space."));
|
|
6428
6927
|
return;
|
|
6429
6928
|
}
|
|
6430
|
-
console.log(
|
|
6929
|
+
console.log(kleur10.cyan(`Hardware bindings for ${context.projectId}:`));
|
|
6431
6930
|
for (const record of bindings) {
|
|
6432
6931
|
console.log(`- ${record.providerId} (${record.status})`);
|
|
6433
6932
|
}
|
|
@@ -6460,9 +6959,9 @@ function grantHardwareBinding(options) {
|
|
|
6460
6959
|
console.log(JSON.stringify(record));
|
|
6461
6960
|
return;
|
|
6462
6961
|
}
|
|
6463
|
-
console.log(
|
|
6962
|
+
console.log(kleur10.green(`Hardware binding granted: ${providerId}`));
|
|
6464
6963
|
printHardwareBinding(record);
|
|
6465
|
-
console.log(
|
|
6964
|
+
console.log(kleur10.cyan(`Stored at ${context.bindingsPath}`));
|
|
6466
6965
|
}
|
|
6467
6966
|
function revokeHardwareBinding(options) {
|
|
6468
6967
|
const providerId = options.providerId.trim();
|
|
@@ -6481,12 +6980,12 @@ function revokeHardwareBinding(options) {
|
|
|
6481
6980
|
console.log(JSON.stringify({ revoked: true, providerId }));
|
|
6482
6981
|
return;
|
|
6483
6982
|
}
|
|
6484
|
-
console.log(
|
|
6485
|
-
console.log(
|
|
6983
|
+
console.log(kleur10.green(`Hardware binding revoked: ${providerId}`));
|
|
6984
|
+
console.log(kleur10.cyan(`Updated ${context.bindingsPath}`));
|
|
6486
6985
|
}
|
|
6487
6986
|
|
|
6488
6987
|
// src/agents.ts
|
|
6489
|
-
import
|
|
6988
|
+
import kleur11 from "kleur";
|
|
6490
6989
|
init_project_manifest();
|
|
6491
6990
|
var DEFAULT_CONTEXT_LIMIT = 50;
|
|
6492
6991
|
var MAX_CONTEXT_LIMIT = 200;
|
|
@@ -6597,16 +7096,16 @@ async function agentsList(options) {
|
|
|
6597
7096
|
return;
|
|
6598
7097
|
}
|
|
6599
7098
|
if (!agents.length) {
|
|
6600
|
-
console.log(
|
|
7099
|
+
console.log(kleur11.yellow("No agents found."));
|
|
6601
7100
|
return;
|
|
6602
7101
|
}
|
|
6603
|
-
console.log(
|
|
7102
|
+
console.log(kleur11.bold("Agents"));
|
|
6604
7103
|
for (const agent of agents) {
|
|
6605
7104
|
const provider = trimOrNull(agent.provider);
|
|
6606
7105
|
const model = trimOrNull(agent.model);
|
|
6607
7106
|
const details = [provider, model].filter(Boolean).join(" \xB7 ");
|
|
6608
7107
|
console.log(
|
|
6609
|
-
`- ${
|
|
7108
|
+
`- ${kleur11.cyan(`@${agent.handle}`)} ${displayName(agent)}${details ? ` (${details})` : ""}`
|
|
6610
7109
|
);
|
|
6611
7110
|
console.log(` id: ${agent.id}`);
|
|
6612
7111
|
}
|
|
@@ -6626,15 +7125,15 @@ async function agentContextsList(options) {
|
|
|
6626
7125
|
return;
|
|
6627
7126
|
}
|
|
6628
7127
|
if (!contexts.length) {
|
|
6629
|
-
console.log(
|
|
7128
|
+
console.log(kleur11.yellow("No agent context cards found."));
|
|
6630
7129
|
return;
|
|
6631
7130
|
}
|
|
6632
|
-
console.log(
|
|
7131
|
+
console.log(kleur11.bold("Agent context"));
|
|
6633
7132
|
for (const card of contexts) {
|
|
6634
7133
|
const title = trimOrNull(card.title);
|
|
6635
7134
|
const updatedAt = trimOrNull(card.updatedAt) ?? trimOrNull(card.updated_at);
|
|
6636
7135
|
console.log(
|
|
6637
|
-
`- ${
|
|
7136
|
+
`- ${kleur11.cyan(contextAgentLabel(card))} ${kleur11.gray(`[${contextScope(card)}]`)}${title ? ` ${title}` : ""}`
|
|
6638
7137
|
);
|
|
6639
7138
|
console.log(` ${summarize(card.context)}`);
|
|
6640
7139
|
if (updatedAt) {
|
|
@@ -6671,7 +7170,7 @@ async function agentContextPut(options) {
|
|
|
6671
7170
|
return;
|
|
6672
7171
|
}
|
|
6673
7172
|
console.log(
|
|
6674
|
-
`${
|
|
7173
|
+
`${kleur11.green("Saved")} ${kleur11.cyan(contextAgentLabel(saved))} context for ${kleur11.gray(contextScope(saved))}.`
|
|
6675
7174
|
);
|
|
6676
7175
|
}
|
|
6677
7176
|
function workerLabel(worker) {
|
|
@@ -6697,7 +7196,7 @@ async function agentPlanGroupStatus(options) {
|
|
|
6697
7196
|
console.log(JSON.stringify(status, null, 2));
|
|
6698
7197
|
return;
|
|
6699
7198
|
}
|
|
6700
|
-
console.log(
|
|
7199
|
+
console.log(kleur11.bold(`Plan group ${trimOrNull(status.groupId) ?? groupId}`));
|
|
6701
7200
|
const conversationId = trimOrNull(status.conversationId);
|
|
6702
7201
|
if (conversationId) {
|
|
6703
7202
|
console.log(` conversation: ${conversationId}`);
|
|
@@ -6707,13 +7206,13 @@ async function agentPlanGroupStatus(options) {
|
|
|
6707
7206
|
);
|
|
6708
7207
|
const workers = status.workers ?? [];
|
|
6709
7208
|
if (!workers.length) {
|
|
6710
|
-
console.log(
|
|
7209
|
+
console.log(kleur11.yellow("No worker jobs found."));
|
|
6711
7210
|
return;
|
|
6712
7211
|
}
|
|
6713
7212
|
for (const worker of workers) {
|
|
6714
7213
|
const marker = worker.terminal ? "terminal" : "running";
|
|
6715
7214
|
const details = [trimOrNull(worker.status) ?? "unknown", marker, trimOrNull(worker.outcome)].filter(Boolean).join(" \xB7 ");
|
|
6716
|
-
console.log(`- ${
|
|
7215
|
+
console.log(`- ${kleur11.cyan(workerLabel(worker))} ${kleur11.gray(`[${details}]`)}`);
|
|
6717
7216
|
const scope = trimOrNull(worker.scopeSummary);
|
|
6718
7217
|
if (scope) {
|
|
6719
7218
|
console.log(` scope: ${scope}`);
|
|
@@ -6724,7 +7223,7 @@ async function agentPlanGroupStatus(options) {
|
|
|
6724
7223
|
}
|
|
6725
7224
|
const errorMessage = trimOrNull(worker.errorMessage);
|
|
6726
7225
|
if (errorMessage) {
|
|
6727
|
-
console.log(` ${
|
|
7226
|
+
console.log(` ${kleur11.red(`error: ${summarize(errorMessage)}`)}`);
|
|
6728
7227
|
}
|
|
6729
7228
|
}
|
|
6730
7229
|
}
|
|
@@ -6751,11 +7250,11 @@ async function agentJobsCancel(options) {
|
|
|
6751
7250
|
const canceledJobs = result.canceledJobIds?.length ?? 0;
|
|
6752
7251
|
const canceledRuns = result.canceledRunIds?.length ?? 0;
|
|
6753
7252
|
if (!canceledJobs && !canceledRuns) {
|
|
6754
|
-
console.log(
|
|
7253
|
+
console.log(kleur11.yellow(`Nothing to cancel for ${target} (no queued or leased jobs).`));
|
|
6755
7254
|
return;
|
|
6756
7255
|
}
|
|
6757
7256
|
console.log(
|
|
6758
|
-
`${
|
|
7257
|
+
`${kleur11.green("Canceled")} ${canceledJobs} job(s) and ${canceledRuns} run(s) for ${target}.`
|
|
6759
7258
|
);
|
|
6760
7259
|
}
|
|
6761
7260
|
|
|
@@ -7071,7 +7570,7 @@ async function chatPrompt(options) {
|
|
|
7071
7570
|
|
|
7072
7571
|
// src/conversations.ts
|
|
7073
7572
|
init_project_manifest();
|
|
7074
|
-
import
|
|
7573
|
+
import kleur12 from "kleur";
|
|
7075
7574
|
var DEFAULT_CONVERSATION_LIMIT = 50;
|
|
7076
7575
|
var DEFAULT_MESSAGE_LIMIT = 80;
|
|
7077
7576
|
var MAX_LIMIT = 200;
|
|
@@ -7298,7 +7797,7 @@ async function buildSearchMatches(conversations, options) {
|
|
|
7298
7797
|
}));
|
|
7299
7798
|
}
|
|
7300
7799
|
function formatConversationMatch(match) {
|
|
7301
|
-
const lines = [`- ${
|
|
7800
|
+
const lines = [`- ${kleur12.green(match.title)} (${match.id})`];
|
|
7302
7801
|
const details = [];
|
|
7303
7802
|
if (match.matchedIn.length > 0) {
|
|
7304
7803
|
details.push(`match: ${match.matchedIn.join(", ")}`);
|
|
@@ -7310,7 +7809,7 @@ function formatConversationMatch(match) {
|
|
|
7310
7809
|
lines.push(` ${details.join(" \xB7 ")}`);
|
|
7311
7810
|
}
|
|
7312
7811
|
if (match.preview) {
|
|
7313
|
-
lines.push(` ${
|
|
7812
|
+
lines.push(` ${kleur12.gray(summarizeContent(match.preview))}`);
|
|
7314
7813
|
}
|
|
7315
7814
|
return lines.join("\n");
|
|
7316
7815
|
}
|
|
@@ -7369,16 +7868,16 @@ async function createConversation(options) {
|
|
|
7369
7868
|
console.log(JSON.stringify(payload, null, 2));
|
|
7370
7869
|
return;
|
|
7371
7870
|
}
|
|
7372
|
-
console.log(
|
|
7373
|
-
console.log(`${
|
|
7871
|
+
console.log(kleur12.green("Created conversation"));
|
|
7872
|
+
console.log(`${kleur12.gray("ID:")} ${conversationId}`);
|
|
7374
7873
|
if (title) {
|
|
7375
|
-
console.log(`${
|
|
7874
|
+
console.log(`${kleur12.gray("Title:")} ${title}`);
|
|
7376
7875
|
}
|
|
7377
7876
|
if (parentConversationId) {
|
|
7378
|
-
console.log(`${
|
|
7877
|
+
console.log(`${kleur12.gray("Parent:")} ${parentConversationId}`);
|
|
7379
7878
|
}
|
|
7380
7879
|
if (threadKind) {
|
|
7381
|
-
console.log(`${
|
|
7880
|
+
console.log(`${kleur12.gray("Thread kind:")} ${threadKind}`);
|
|
7382
7881
|
}
|
|
7383
7882
|
}
|
|
7384
7883
|
async function listConversations(options) {
|
|
@@ -7405,10 +7904,10 @@ async function listConversations(options) {
|
|
|
7405
7904
|
return;
|
|
7406
7905
|
}
|
|
7407
7906
|
if (items.length === 0) {
|
|
7408
|
-
console.log(
|
|
7907
|
+
console.log(kleur12.yellow("No conversations found for this space."));
|
|
7409
7908
|
return;
|
|
7410
7909
|
}
|
|
7411
|
-
console.log(
|
|
7910
|
+
console.log(kleur12.green(`Conversations (${items.length})`));
|
|
7412
7911
|
for (const item of items) {
|
|
7413
7912
|
console.log(formatConversationMatch({ ...item, score: 0, matchedIn: [] }));
|
|
7414
7913
|
}
|
|
@@ -7430,10 +7929,10 @@ async function searchConversations(options) {
|
|
|
7430
7929
|
return matches;
|
|
7431
7930
|
}
|
|
7432
7931
|
if (matches.length === 0) {
|
|
7433
|
-
console.log(
|
|
7932
|
+
console.log(kleur12.yellow(`No conversations matched "${options.query}".`));
|
|
7434
7933
|
return matches;
|
|
7435
7934
|
}
|
|
7436
|
-
console.log(
|
|
7935
|
+
console.log(kleur12.green(`Matches for "${options.query}"`));
|
|
7437
7936
|
for (const match of matches.slice(0, Math.min(limit, matches.length))) {
|
|
7438
7937
|
console.log(formatConversationMatch(match));
|
|
7439
7938
|
}
|
|
@@ -7517,35 +8016,35 @@ async function showConversation(options) {
|
|
|
7517
8016
|
);
|
|
7518
8017
|
return;
|
|
7519
8018
|
}
|
|
7520
|
-
console.log(
|
|
7521
|
-
console.log(`${
|
|
8019
|
+
console.log(kleur12.green(selected.title));
|
|
8020
|
+
console.log(`${kleur12.gray("ID:")} ${selected.id}`);
|
|
7522
8021
|
if (selected.updatedAt) {
|
|
7523
|
-
console.log(`${
|
|
8022
|
+
console.log(`${kleur12.gray("Updated:")} ${selected.updatedAt}`);
|
|
7524
8023
|
}
|
|
7525
8024
|
if (selected.preview) {
|
|
7526
|
-
console.log(`${
|
|
8025
|
+
console.log(`${kleur12.gray("Preview:")} ${summarizeContent(selected.preview, 240)}`);
|
|
7527
8026
|
}
|
|
7528
8027
|
console.log("");
|
|
7529
8028
|
if (messages.length === 0) {
|
|
7530
|
-
console.log(
|
|
8029
|
+
console.log(kleur12.yellow("No messages found in this conversation."));
|
|
7531
8030
|
return;
|
|
7532
8031
|
}
|
|
7533
8032
|
for (const message of messages.slice().reverse()) {
|
|
7534
8033
|
const role = (message.role ?? "unknown").trim().toLowerCase();
|
|
7535
8034
|
const createdAt = trimOrNull2(message.createdAt) ?? trimOrNull2(message.created_at);
|
|
7536
8035
|
const header = createdAt ? `${role} \xB7 ${createdAt}` : role;
|
|
7537
|
-
console.log(
|
|
8036
|
+
console.log(kleur12.cyan(`[${header}]`));
|
|
7538
8037
|
console.log(summarizeContent(message.content ?? "", 4e3));
|
|
7539
8038
|
console.log("");
|
|
7540
8039
|
}
|
|
7541
8040
|
}
|
|
7542
8041
|
|
|
7543
8042
|
// src/invitations.ts
|
|
7544
|
-
import
|
|
7545
|
-
import
|
|
8043
|
+
import kleur13 from "kleur";
|
|
8044
|
+
import path11 from "node:path";
|
|
7546
8045
|
init_project_manifest();
|
|
7547
8046
|
function resolveStartDir(rawPath) {
|
|
7548
|
-
return
|
|
8047
|
+
return path11.resolve(rawPath ?? process.cwd());
|
|
7549
8048
|
}
|
|
7550
8049
|
function trimOrNull3(value) {
|
|
7551
8050
|
const trimmed = value?.trim() ?? "";
|
|
@@ -7687,7 +8186,7 @@ async function inviteSpaceMember(options) {
|
|
|
7687
8186
|
return normalized;
|
|
7688
8187
|
}
|
|
7689
8188
|
const scopeLabel = orgName ? `${orgName}` : "this space";
|
|
7690
|
-
console.log(
|
|
8189
|
+
console.log(kleur13.green(`Invitation sent to ${normalized.email}`));
|
|
7691
8190
|
console.log(`Scope: ${scopeLabel}`);
|
|
7692
8191
|
console.log(`Role: ${normalized.role}`);
|
|
7693
8192
|
if (normalized.expiresAt) {
|
|
@@ -7747,7 +8246,7 @@ async function setSpaceMemberRole(options) {
|
|
|
7747
8246
|
return normalized;
|
|
7748
8247
|
}
|
|
7749
8248
|
console.log(
|
|
7750
|
-
|
|
8249
|
+
kleur13.green(
|
|
7751
8250
|
normalized.status === "updated" ? `Updated ${normalized.email} to ${normalized.role}` : `${normalized.email} already has role ${normalized.role}`
|
|
7752
8251
|
)
|
|
7753
8252
|
);
|
|
@@ -7786,7 +8285,7 @@ async function setSpaceMemberRole(options) {
|
|
|
7786
8285
|
return normalized;
|
|
7787
8286
|
}
|
|
7788
8287
|
console.log(
|
|
7789
|
-
|
|
8288
|
+
kleur13.green(
|
|
7790
8289
|
normalized.status === "updated" ? `Updated pending invite for ${normalized.email} to ${normalized.role}` : `Pending invite for ${normalized.email} already has role ${normalized.role}`
|
|
7791
8290
|
)
|
|
7792
8291
|
);
|
|
@@ -7832,14 +8331,446 @@ async function sendSpaceInvitation(options) {
|
|
|
7832
8331
|
};
|
|
7833
8332
|
}
|
|
7834
8333
|
|
|
8334
|
+
// src/team.ts
|
|
8335
|
+
init_config();
|
|
8336
|
+
init_controller_fetch();
|
|
8337
|
+
init_errors();
|
|
8338
|
+
import kleur14 from "kleur";
|
|
8339
|
+
var DEFAULT_STUDIO_URL = "https://instafy.dev";
|
|
8340
|
+
var ORG_ROLES = ["owner", "admin", "builder", "viewer"];
|
|
8341
|
+
var INVITE_LINK_ROLES = ["builder", "viewer"];
|
|
8342
|
+
var UUID_PATTERN3 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
8343
|
+
var ControllerRequestError = class extends Error {
|
|
8344
|
+
constructor(status, serverMessage, message) {
|
|
8345
|
+
super(message);
|
|
8346
|
+
this.name = "ControllerRequestError";
|
|
8347
|
+
this.status = status;
|
|
8348
|
+
this.serverMessage = serverMessage;
|
|
8349
|
+
}
|
|
8350
|
+
};
|
|
8351
|
+
function normalizeBaseUrl(value) {
|
|
8352
|
+
const trimmed = typeof value === "string" ? value.trim() : "";
|
|
8353
|
+
if (!trimmed)
|
|
8354
|
+
return null;
|
|
8355
|
+
return trimmed.replace(/\/$/, "");
|
|
8356
|
+
}
|
|
8357
|
+
function isUuid3(value) {
|
|
8358
|
+
return UUID_PATTERN3.test(value.trim());
|
|
8359
|
+
}
|
|
8360
|
+
function requireUuid(value, label) {
|
|
8361
|
+
const trimmed = value?.trim() ?? "";
|
|
8362
|
+
if (!trimmed) {
|
|
8363
|
+
throw new Error(`${label} is required.`);
|
|
8364
|
+
}
|
|
8365
|
+
if (!isUuid3(trimmed)) {
|
|
8366
|
+
throw new Error(`${label} must be a UUID.`);
|
|
8367
|
+
}
|
|
8368
|
+
return trimmed;
|
|
8369
|
+
}
|
|
8370
|
+
function normalizeRole2(value, allowed, label) {
|
|
8371
|
+
const resolved = (value ?? "").trim().toLowerCase();
|
|
8372
|
+
if (!resolved) {
|
|
8373
|
+
throw new Error(`${label} is required.`);
|
|
8374
|
+
}
|
|
8375
|
+
if (!allowed.includes(resolved)) {
|
|
8376
|
+
throw new Error(`${label} must be one of ${allowed.join(", ")}.`);
|
|
8377
|
+
}
|
|
8378
|
+
return resolved;
|
|
8379
|
+
}
|
|
8380
|
+
function resolveControllerAuth4(options, retryCommand) {
|
|
8381
|
+
const cwd = options.cwd ?? process.cwd();
|
|
8382
|
+
const controllerUrl = resolveControllerUrl({
|
|
8383
|
+
controllerUrl: options.controllerUrl ?? null,
|
|
8384
|
+
cwd
|
|
8385
|
+
});
|
|
8386
|
+
const resolved = resolveUserAccessTokenWithSource({
|
|
8387
|
+
accessToken: options.accessToken ?? null,
|
|
8388
|
+
cwd
|
|
8389
|
+
});
|
|
8390
|
+
if (!resolved.token) {
|
|
8391
|
+
throw formatAuthRequiredError({
|
|
8392
|
+
retryCommand,
|
|
8393
|
+
advancedHint: "pass --access-token, or set INSTAFY_ACCESS_TOKEN / SUPABASE_ACCESS_TOKEN"
|
|
8394
|
+
});
|
|
8395
|
+
}
|
|
8396
|
+
return {
|
|
8397
|
+
controllerUrl,
|
|
8398
|
+
accessToken: resolved.token,
|
|
8399
|
+
tokenSource: resolved.source,
|
|
8400
|
+
profile: resolved.profile,
|
|
8401
|
+
cwd
|
|
8402
|
+
};
|
|
8403
|
+
}
|
|
8404
|
+
async function controllerJson(auth, retryCommand, params) {
|
|
8405
|
+
const url = `${auth.controllerUrl.replace(/\/$/, "")}${params.path}`;
|
|
8406
|
+
const headers = new Headers();
|
|
8407
|
+
headers.set("accept", "application/json");
|
|
8408
|
+
let bodyText;
|
|
8409
|
+
if (params.body !== void 0) {
|
|
8410
|
+
headers.set("content-type", "application/json");
|
|
8411
|
+
bodyText = JSON.stringify(params.body);
|
|
8412
|
+
}
|
|
8413
|
+
const response = (await fetchWithControllerAuth({
|
|
8414
|
+
url,
|
|
8415
|
+
init: {
|
|
8416
|
+
method: params.method,
|
|
8417
|
+
headers,
|
|
8418
|
+
body: bodyText
|
|
8419
|
+
},
|
|
8420
|
+
accessToken: auth.accessToken,
|
|
8421
|
+
tokenSource: auth.tokenSource,
|
|
8422
|
+
profile: auth.profile,
|
|
8423
|
+
cwd: auth.cwd
|
|
8424
|
+
})).response;
|
|
8425
|
+
const text = await response.text().catch(() => "");
|
|
8426
|
+
if (response.status === 401 || response.status === 403) {
|
|
8427
|
+
throw formatAuthRejectedError({
|
|
8428
|
+
status: response.status,
|
|
8429
|
+
responseBody: text,
|
|
8430
|
+
retryCommand,
|
|
8431
|
+
advancedHint: "run `instafy login`, or pass --access-token"
|
|
8432
|
+
});
|
|
8433
|
+
}
|
|
8434
|
+
if (!response.ok) {
|
|
8435
|
+
const serverMessage = extractControllerErrorMessage(text);
|
|
8436
|
+
throw new ControllerRequestError(
|
|
8437
|
+
response.status,
|
|
8438
|
+
serverMessage,
|
|
8439
|
+
`Request failed (${response.status} ${response.statusText})${serverMessage ? `: ${serverMessage}` : ""}`
|
|
8440
|
+
);
|
|
8441
|
+
}
|
|
8442
|
+
return text ? JSON.parse(text) : null;
|
|
8443
|
+
}
|
|
8444
|
+
async function fetchOrgs(auth) {
|
|
8445
|
+
const payload = await controllerJson(auth, "instafy team list", {
|
|
8446
|
+
method: "GET",
|
|
8447
|
+
path: "/orgs"
|
|
8448
|
+
});
|
|
8449
|
+
return Array.isArray(payload?.orgs) ? payload.orgs : [];
|
|
8450
|
+
}
|
|
8451
|
+
async function resolveTeamId(auth, teamOpt) {
|
|
8452
|
+
const raw = teamOpt?.trim();
|
|
8453
|
+
if (raw && isUuid3(raw)) {
|
|
8454
|
+
return raw;
|
|
8455
|
+
}
|
|
8456
|
+
const orgs = await fetchOrgs(auth);
|
|
8457
|
+
if (raw) {
|
|
8458
|
+
const bySlug = orgs.find(
|
|
8459
|
+
(org) => (org.slug ?? "").toLowerCase() === raw.toLowerCase()
|
|
8460
|
+
);
|
|
8461
|
+
if (bySlug)
|
|
8462
|
+
return bySlug.id;
|
|
8463
|
+
const byId = orgs.find((org) => org.id === raw);
|
|
8464
|
+
if (byId)
|
|
8465
|
+
return byId.id;
|
|
8466
|
+
throw new Error(
|
|
8467
|
+
`No team matches "${raw}". Run \`instafy team list\` to see the teams you belong to.`
|
|
8468
|
+
);
|
|
8469
|
+
}
|
|
8470
|
+
if (orgs.length === 1) {
|
|
8471
|
+
return orgs[0].id;
|
|
8472
|
+
}
|
|
8473
|
+
if (orgs.length === 0) {
|
|
8474
|
+
throw new Error(
|
|
8475
|
+
"No teams found for this account. Run `instafy team list` to see your teams."
|
|
8476
|
+
);
|
|
8477
|
+
}
|
|
8478
|
+
throw new Error(
|
|
8479
|
+
"Multiple teams found. Pass --team-id <uuid|slug>. Run `instafy team list` to see the options."
|
|
8480
|
+
);
|
|
8481
|
+
}
|
|
8482
|
+
function resolveStudioBaseUrl(auth, studioUrlOption) {
|
|
8483
|
+
return normalizeBaseUrl(studioUrlOption ?? null) ?? normalizeBaseUrl(process.env["INSTAFY_STUDIO_URL"] ?? null) ?? normalizeBaseUrl(
|
|
8484
|
+
resolveConfiguredStudioUrl({ profile: auth.profile, cwd: auth.cwd })
|
|
8485
|
+
) ?? DEFAULT_STUDIO_URL;
|
|
8486
|
+
}
|
|
8487
|
+
function shortId(value) {
|
|
8488
|
+
const trimmed = value.trim();
|
|
8489
|
+
return trimmed.length > 8 ? trimmed.slice(0, 8) : trimmed;
|
|
8490
|
+
}
|
|
8491
|
+
function printTable(headers, rows) {
|
|
8492
|
+
const widths = headers.map(
|
|
8493
|
+
(header, index) => Math.max(header.length, ...rows.map((row) => (row[index] ?? "").length))
|
|
8494
|
+
);
|
|
8495
|
+
const format = (cells) => cells.map((cell, index) => (cell ?? "").padEnd(widths[index])).join(" ").trimEnd();
|
|
8496
|
+
console.log(kleur14.bold(format(headers)));
|
|
8497
|
+
for (const row of rows) {
|
|
8498
|
+
console.log(format(row));
|
|
8499
|
+
}
|
|
8500
|
+
}
|
|
8501
|
+
async function teamMembersList(options) {
|
|
8502
|
+
const auth = resolveControllerAuth4(options, "instafy team members");
|
|
8503
|
+
const orgId = await resolveTeamId(auth, options.teamId);
|
|
8504
|
+
const payload = await controllerJson(auth, "instafy team members", {
|
|
8505
|
+
method: "GET",
|
|
8506
|
+
path: `/orgs/${encodeURIComponent(orgId)}/members`
|
|
8507
|
+
});
|
|
8508
|
+
const members = Array.isArray(payload?.members) ? payload.members : [];
|
|
8509
|
+
if (options.json) {
|
|
8510
|
+
console.log(
|
|
8511
|
+
JSON.stringify(
|
|
8512
|
+
{
|
|
8513
|
+
members,
|
|
8514
|
+
nextCursor: payload?.nextCursor ?? null,
|
|
8515
|
+
hasMore: payload?.hasMore ?? false,
|
|
8516
|
+
total: payload?.total
|
|
8517
|
+
},
|
|
8518
|
+
null,
|
|
8519
|
+
2
|
|
8520
|
+
)
|
|
8521
|
+
);
|
|
8522
|
+
return;
|
|
8523
|
+
}
|
|
8524
|
+
if (members.length === 0) {
|
|
8525
|
+
console.log(kleur14.gray("No members."));
|
|
8526
|
+
return;
|
|
8527
|
+
}
|
|
8528
|
+
const rows = members.map((member) => [
|
|
8529
|
+
shortId(member.userId),
|
|
8530
|
+
(member.email ?? "").trim() || "-",
|
|
8531
|
+
(member.fullName ?? "").trim() || "-",
|
|
8532
|
+
member.role,
|
|
8533
|
+
(member.createdAt ?? "").trim() || "-"
|
|
8534
|
+
]);
|
|
8535
|
+
printTable(["ID", "EMAIL", "NAME", "ROLE", "JOINED"], rows);
|
|
8536
|
+
}
|
|
8537
|
+
async function teamInvite(options) {
|
|
8538
|
+
const auth = resolveControllerAuth4(options, "instafy team invite");
|
|
8539
|
+
const email = options.email?.trim() ?? "";
|
|
8540
|
+
if (!email) {
|
|
8541
|
+
throw new Error("An email address is required.");
|
|
8542
|
+
}
|
|
8543
|
+
const role = options.role !== void 0 ? normalizeRole2(options.role, ORG_ROLES, "--role") : void 0;
|
|
8544
|
+
const orgId = await resolveTeamId(auth, options.teamId);
|
|
8545
|
+
const body = { email };
|
|
8546
|
+
if (role)
|
|
8547
|
+
body.role = role;
|
|
8548
|
+
let payload;
|
|
8549
|
+
try {
|
|
8550
|
+
payload = await controllerJson(auth, "instafy team invite", {
|
|
8551
|
+
method: "POST",
|
|
8552
|
+
path: `/orgs/${encodeURIComponent(orgId)}/invitations`,
|
|
8553
|
+
body
|
|
8554
|
+
});
|
|
8555
|
+
} catch (error) {
|
|
8556
|
+
if (error instanceof ControllerRequestError && error.status >= 400 && error.status < 500 && /already a member|already exists|already has access/i.test(
|
|
8557
|
+
error.serverMessage ?? ""
|
|
8558
|
+
)) {
|
|
8559
|
+
throw new Error(
|
|
8560
|
+
`${error.serverMessage}
|
|
8561
|
+
|
|
8562
|
+
If they already have an Instafy account, add them directly with:
|
|
8563
|
+
instafy team add-member --user-id <uuid>${options.teamId ? ` --team-id ${options.teamId}` : ""}`
|
|
8564
|
+
);
|
|
8565
|
+
}
|
|
8566
|
+
throw error;
|
|
8567
|
+
}
|
|
8568
|
+
const invitation = payload?.invitation;
|
|
8569
|
+
if (!invitation?.id) {
|
|
8570
|
+
throw new Error("Invitation response missing invitation details.");
|
|
8571
|
+
}
|
|
8572
|
+
if (options.json) {
|
|
8573
|
+
console.log(
|
|
8574
|
+
JSON.stringify(
|
|
8575
|
+
{ invitation, acceptUrl: payload?.acceptUrl ?? null },
|
|
8576
|
+
null,
|
|
8577
|
+
2
|
|
8578
|
+
)
|
|
8579
|
+
);
|
|
8580
|
+
return;
|
|
8581
|
+
}
|
|
8582
|
+
console.log(kleur14.green(`Invitation sent to ${invitation.email}`));
|
|
8583
|
+
console.log(`Role: ${invitation.role}`);
|
|
8584
|
+
if (invitation.expiresAt) {
|
|
8585
|
+
console.log(`Expires: ${invitation.expiresAt}`);
|
|
8586
|
+
}
|
|
8587
|
+
console.log("");
|
|
8588
|
+
console.log(
|
|
8589
|
+
`${invitation.email} must sign in to Instafy with this email address to accept the invitation.`
|
|
8590
|
+
);
|
|
8591
|
+
}
|
|
8592
|
+
async function teamInviteLink(options) {
|
|
8593
|
+
const auth = resolveControllerAuth4(options, "instafy team invite-link");
|
|
8594
|
+
const role = options.role !== void 0 ? normalizeRole2(options.role, INVITE_LINK_ROLES, "--role") : void 0;
|
|
8595
|
+
const orgId = await resolveTeamId(auth, options.teamId);
|
|
8596
|
+
const body = {};
|
|
8597
|
+
if (role)
|
|
8598
|
+
body.role = role;
|
|
8599
|
+
const payload = await controllerJson(auth, "instafy team invite-link", {
|
|
8600
|
+
method: "POST",
|
|
8601
|
+
path: `/orgs/${encodeURIComponent(orgId)}/invite-links`,
|
|
8602
|
+
body
|
|
8603
|
+
});
|
|
8604
|
+
const inviteLink = payload?.inviteLink;
|
|
8605
|
+
if (!inviteLink?.token || !inviteLink.acceptPath) {
|
|
8606
|
+
throw new Error("Invite link response missing link details.");
|
|
8607
|
+
}
|
|
8608
|
+
const studioBase = resolveStudioBaseUrl(auth, options.studioUrl);
|
|
8609
|
+
const acceptUrl = typeof payload?.acceptUrl === "string" && payload.acceptUrl.trim() || `${studioBase}${inviteLink.acceptPath}`;
|
|
8610
|
+
if (options.json) {
|
|
8611
|
+
console.log(JSON.stringify({ inviteLink, acceptUrl }, null, 2));
|
|
8612
|
+
return;
|
|
8613
|
+
}
|
|
8614
|
+
console.log(kleur14.green("Shareable invite link created."));
|
|
8615
|
+
console.log(`Role: ${inviteLink.role}`);
|
|
8616
|
+
console.log(`Link: ${acceptUrl}`);
|
|
8617
|
+
console.log(`Token: ${inviteLink.token}`);
|
|
8618
|
+
if (inviteLink.expiresAt) {
|
|
8619
|
+
console.log(`Expires: ${inviteLink.expiresAt}`);
|
|
8620
|
+
}
|
|
8621
|
+
console.log("");
|
|
8622
|
+
console.log(
|
|
8623
|
+
"Anyone who opens this link and signs in (with any sign-in method) can join the team. Treat it like a shared secret."
|
|
8624
|
+
);
|
|
8625
|
+
}
|
|
8626
|
+
async function teamInvites(options) {
|
|
8627
|
+
const auth = resolveControllerAuth4(options, "instafy team invites");
|
|
8628
|
+
const orgId = await resolveTeamId(auth, options.teamId);
|
|
8629
|
+
const [invitationsPayload, linksPayload] = await Promise.all([
|
|
8630
|
+
controllerJson(auth, "instafy team invites", {
|
|
8631
|
+
method: "GET",
|
|
8632
|
+
path: `/orgs/${encodeURIComponent(orgId)}/invitations`
|
|
8633
|
+
}),
|
|
8634
|
+
controllerJson(auth, "instafy team invites", {
|
|
8635
|
+
method: "GET",
|
|
8636
|
+
path: `/orgs/${encodeURIComponent(orgId)}/invite-links`
|
|
8637
|
+
})
|
|
8638
|
+
]);
|
|
8639
|
+
const invitations = Array.isArray(invitationsPayload?.invitations) ? invitationsPayload.invitations : [];
|
|
8640
|
+
const inviteLinks = Array.isArray(linksPayload?.inviteLinks) ? linksPayload.inviteLinks : [];
|
|
8641
|
+
if (options.json) {
|
|
8642
|
+
console.log(JSON.stringify({ invitations, inviteLinks }, null, 2));
|
|
8643
|
+
return;
|
|
8644
|
+
}
|
|
8645
|
+
if (invitations.length === 0 && inviteLinks.length === 0) {
|
|
8646
|
+
console.log(kleur14.gray("No pending invitations or invite links."));
|
|
8647
|
+
return;
|
|
8648
|
+
}
|
|
8649
|
+
if (invitations.length > 0) {
|
|
8650
|
+
console.log(kleur14.bold("Email invitations"));
|
|
8651
|
+
const rows = invitations.map((invitation) => [
|
|
8652
|
+
shortId(invitation.id),
|
|
8653
|
+
invitation.email,
|
|
8654
|
+
invitation.role,
|
|
8655
|
+
(invitation.expiresAt ?? "").trim() || "-"
|
|
8656
|
+
]);
|
|
8657
|
+
printTable(["ID", "EMAIL", "ROLE", "EXPIRES"], rows);
|
|
8658
|
+
}
|
|
8659
|
+
if (inviteLinks.length > 0) {
|
|
8660
|
+
if (invitations.length > 0)
|
|
8661
|
+
console.log("");
|
|
8662
|
+
console.log(kleur14.bold("Invite links (shareable, grant join on sign-in)"));
|
|
8663
|
+
const rows = inviteLinks.map((link) => [
|
|
8664
|
+
shortId(link.id),
|
|
8665
|
+
link.role,
|
|
8666
|
+
(link.status ?? "").trim() || "-",
|
|
8667
|
+
(link.expiresAt ?? "").trim() || "-"
|
|
8668
|
+
]);
|
|
8669
|
+
printTable(["ID", "ROLE", "STATUS", "EXPIRES"], rows);
|
|
8670
|
+
}
|
|
8671
|
+
}
|
|
8672
|
+
async function teamAddMember(options) {
|
|
8673
|
+
const auth = resolveControllerAuth4(options, "instafy team add-member");
|
|
8674
|
+
const userId = requireUuid(options.userId, "--user-id");
|
|
8675
|
+
const role = options.role !== void 0 ? normalizeRole2(options.role, ORG_ROLES, "--role") : void 0;
|
|
8676
|
+
const orgId = await resolveTeamId(auth, options.teamId);
|
|
8677
|
+
const body = { userId };
|
|
8678
|
+
if (role)
|
|
8679
|
+
body.role = role;
|
|
8680
|
+
const payload = await controllerJson(auth, "instafy team add-member", {
|
|
8681
|
+
method: "POST",
|
|
8682
|
+
path: `/orgs/${encodeURIComponent(orgId)}/members`,
|
|
8683
|
+
body
|
|
8684
|
+
});
|
|
8685
|
+
const member = payload?.member;
|
|
8686
|
+
if (!member?.userId) {
|
|
8687
|
+
throw new Error("Add member response missing member details.");
|
|
8688
|
+
}
|
|
8689
|
+
if (options.json) {
|
|
8690
|
+
console.log(JSON.stringify({ member }, null, 2));
|
|
8691
|
+
return;
|
|
8692
|
+
}
|
|
8693
|
+
const label = (member.email ?? "").trim() || member.userId;
|
|
8694
|
+
console.log(kleur14.green(`Added ${label} as ${member.role}.`));
|
|
8695
|
+
}
|
|
8696
|
+
async function teamAccept(options) {
|
|
8697
|
+
const auth = resolveControllerAuth4(options, "instafy team accept");
|
|
8698
|
+
const token = requireUuid(options.token, "token");
|
|
8699
|
+
const payload = await controllerJson(auth, "instafy team accept", {
|
|
8700
|
+
method: "POST",
|
|
8701
|
+
path: "/org-invitations/accept",
|
|
8702
|
+
body: { token }
|
|
8703
|
+
});
|
|
8704
|
+
if (options.json) {
|
|
8705
|
+
console.log(JSON.stringify(payload ?? {}, null, 2));
|
|
8706
|
+
return;
|
|
8707
|
+
}
|
|
8708
|
+
const name = (payload?.orgName ?? "").trim() || payload?.orgSlug || payload?.orgId || "team";
|
|
8709
|
+
console.log(kleur14.green(`Joined ${name} as ${payload?.role ?? "member"}.`));
|
|
8710
|
+
}
|
|
8711
|
+
async function confirmDestructive(message, yes, json) {
|
|
8712
|
+
if (yes)
|
|
8713
|
+
return;
|
|
8714
|
+
const input3 = process.stdin;
|
|
8715
|
+
const interactive = Boolean(
|
|
8716
|
+
input3.isTTY && process.stdout.isTTY && json !== true && process.env["CI"] !== "true"
|
|
8717
|
+
);
|
|
8718
|
+
if (!interactive) {
|
|
8719
|
+
throw new Error("Refusing to continue without confirmation. Re-run with --yes.");
|
|
8720
|
+
}
|
|
8721
|
+
const { confirm, isCancel } = await import("@clack/prompts");
|
|
8722
|
+
const proceed = await confirm({ message, initialValue: false });
|
|
8723
|
+
if (isCancel(proceed) || !proceed) {
|
|
8724
|
+
throw new Error("Cancelled.");
|
|
8725
|
+
}
|
|
8726
|
+
}
|
|
8727
|
+
async function teamRevokeInvite(options) {
|
|
8728
|
+
const auth = resolveControllerAuth4(options, "instafy team revoke-invite");
|
|
8729
|
+
const invitationId = requireUuid(options.invitationId, "invitation id");
|
|
8730
|
+
const orgId = await resolveTeamId(auth, options.teamId);
|
|
8731
|
+
await confirmDestructive(
|
|
8732
|
+
`Revoke pending invitation ${shortId(invitationId)}?`,
|
|
8733
|
+
options.yes,
|
|
8734
|
+
options.json
|
|
8735
|
+
);
|
|
8736
|
+
await controllerJson(auth, "instafy team revoke-invite", {
|
|
8737
|
+
method: "DELETE",
|
|
8738
|
+
path: `/orgs/${encodeURIComponent(orgId)}/invitations/${encodeURIComponent(invitationId)}`
|
|
8739
|
+
});
|
|
8740
|
+
if (options.json) {
|
|
8741
|
+
console.log(JSON.stringify({ ok: true, invitationId }, null, 2));
|
|
8742
|
+
return;
|
|
8743
|
+
}
|
|
8744
|
+
console.log(kleur14.green(`Revoked invitation ${invitationId}.`));
|
|
8745
|
+
}
|
|
8746
|
+
async function teamRevokeLink(options) {
|
|
8747
|
+
const auth = resolveControllerAuth4(options, "instafy team revoke-link");
|
|
8748
|
+
const inviteLinkId = requireUuid(options.inviteLinkId, "invite link id");
|
|
8749
|
+
const orgId = await resolveTeamId(auth, options.teamId);
|
|
8750
|
+
await confirmDestructive(
|
|
8751
|
+
`Revoke invite link ${shortId(inviteLinkId)}?`,
|
|
8752
|
+
options.yes,
|
|
8753
|
+
options.json
|
|
8754
|
+
);
|
|
8755
|
+
await controllerJson(auth, "instafy team revoke-link", {
|
|
8756
|
+
method: "DELETE",
|
|
8757
|
+
path: `/orgs/${encodeURIComponent(orgId)}/invite-links/${encodeURIComponent(inviteLinkId)}`
|
|
8758
|
+
});
|
|
8759
|
+
if (options.json) {
|
|
8760
|
+
console.log(JSON.stringify({ ok: true, inviteLinkId }, null, 2));
|
|
8761
|
+
return;
|
|
8762
|
+
}
|
|
8763
|
+
console.log(kleur14.green(`Revoked invite link ${inviteLinkId}.`));
|
|
8764
|
+
}
|
|
8765
|
+
|
|
7835
8766
|
// src/provider-bindings.ts
|
|
7836
8767
|
init_project_manifest();
|
|
7837
|
-
import
|
|
7838
|
-
import
|
|
8768
|
+
import fs11 from "node:fs";
|
|
8769
|
+
import path12 from "node:path";
|
|
7839
8770
|
import { pathToFileURL } from "node:url";
|
|
7840
|
-
import
|
|
8771
|
+
import kleur15 from "kleur";
|
|
7841
8772
|
function resolveBindingContext(startDir) {
|
|
7842
|
-
const lookup = findProjectManifest(
|
|
8773
|
+
const lookup = findProjectManifest(path12.resolve(startDir));
|
|
7843
8774
|
if (!lookup.manifest || !lookup.path) {
|
|
7844
8775
|
throw new Error(
|
|
7845
8776
|
"Linked space manifest required. Run `instafy space init` in this folder or pass --path <dir>."
|
|
@@ -7849,19 +8780,19 @@ function resolveBindingContext(startDir) {
|
|
|
7849
8780
|
if (!projectId) {
|
|
7850
8781
|
throw new Error("Linked space manifest is missing a spaceId.");
|
|
7851
8782
|
}
|
|
7852
|
-
const instafyDir =
|
|
7853
|
-
const projectRoot =
|
|
8783
|
+
const instafyDir = path12.dirname(lookup.path);
|
|
8784
|
+
const projectRoot = path12.dirname(instafyDir);
|
|
7854
8785
|
return {
|
|
7855
|
-
bindingsPath:
|
|
8786
|
+
bindingsPath: path12.join(instafyDir, "provider-bindings.json"),
|
|
7856
8787
|
projectId,
|
|
7857
8788
|
projectRoot
|
|
7858
8789
|
};
|
|
7859
8790
|
}
|
|
7860
8791
|
function readBindingStore(bindingsPath) {
|
|
7861
|
-
if (!
|
|
8792
|
+
if (!fs11.existsSync(bindingsPath)) {
|
|
7862
8793
|
return { version: 1, bindings: {} };
|
|
7863
8794
|
}
|
|
7864
|
-
const raw = JSON.parse(
|
|
8795
|
+
const raw = JSON.parse(fs11.readFileSync(bindingsPath, "utf8"));
|
|
7865
8796
|
const bindings = raw && typeof raw.bindings === "object" && raw.bindings !== null ? raw.bindings : {};
|
|
7866
8797
|
return {
|
|
7867
8798
|
version: 1,
|
|
@@ -7869,8 +8800,8 @@ function readBindingStore(bindingsPath) {
|
|
|
7869
8800
|
};
|
|
7870
8801
|
}
|
|
7871
8802
|
function writeBindingStore(bindingsPath, store) {
|
|
7872
|
-
|
|
7873
|
-
|
|
8803
|
+
fs11.mkdirSync(path12.dirname(bindingsPath), { recursive: true });
|
|
8804
|
+
fs11.writeFileSync(bindingsPath, JSON.stringify(store, null, 2), "utf8");
|
|
7874
8805
|
}
|
|
7875
8806
|
function normalizeCapabilities2(values) {
|
|
7876
8807
|
const requested = Array.isArray(values) && values.length > 0 ? values : ["project_content_read", "project_content_write"];
|
|
@@ -7893,7 +8824,7 @@ function deriveStatus(capabilities) {
|
|
|
7893
8824
|
return "bound_read_only";
|
|
7894
8825
|
}
|
|
7895
8826
|
function printBinding(record) {
|
|
7896
|
-
console.log(
|
|
8827
|
+
console.log(kleur15.cyan(`Provider: ${record.providerId}`));
|
|
7897
8828
|
console.log(`Status: ${record.status}`);
|
|
7898
8829
|
console.log(`Project: ${record.projectId}`);
|
|
7899
8830
|
console.log(`Root URI: ${record.rootUri}`);
|
|
@@ -7935,10 +8866,10 @@ function showProviderBinding(options) {
|
|
|
7935
8866
|
return;
|
|
7936
8867
|
}
|
|
7937
8868
|
if (bindings.length === 0) {
|
|
7938
|
-
console.log(
|
|
8869
|
+
console.log(kleur15.yellow("No provider bindings recorded for this space."));
|
|
7939
8870
|
return;
|
|
7940
8871
|
}
|
|
7941
|
-
console.log(
|
|
8872
|
+
console.log(kleur15.cyan(`Bindings for ${context.projectId}:`));
|
|
7942
8873
|
for (const record of bindings) {
|
|
7943
8874
|
console.log(`- ${record.providerId} (${record.status})`);
|
|
7944
8875
|
}
|
|
@@ -7970,9 +8901,9 @@ function grantProviderBinding(options) {
|
|
|
7970
8901
|
console.log(JSON.stringify(record));
|
|
7971
8902
|
return;
|
|
7972
8903
|
}
|
|
7973
|
-
console.log(
|
|
8904
|
+
console.log(kleur15.green(`Provider binding granted: ${providerId}`));
|
|
7974
8905
|
printBinding(record);
|
|
7975
|
-
console.log(
|
|
8906
|
+
console.log(kleur15.cyan(`Stored at ${context.bindingsPath}`));
|
|
7976
8907
|
}
|
|
7977
8908
|
function revokeProviderBinding(options) {
|
|
7978
8909
|
const providerId = options.providerId.trim();
|
|
@@ -7991,12 +8922,12 @@ function revokeProviderBinding(options) {
|
|
|
7991
8922
|
console.log(JSON.stringify({ revoked: true, providerId }));
|
|
7992
8923
|
return;
|
|
7993
8924
|
}
|
|
7994
|
-
console.log(
|
|
7995
|
-
console.log(
|
|
8925
|
+
console.log(kleur15.green(`Provider binding revoked: ${providerId}`));
|
|
8926
|
+
console.log(kleur15.cyan(`Updated ${context.bindingsPath}`));
|
|
7996
8927
|
}
|
|
7997
8928
|
|
|
7998
8929
|
// src/providers.ts
|
|
7999
|
-
import
|
|
8930
|
+
import kleur16 from "kleur";
|
|
8000
8931
|
|
|
8001
8932
|
// ../provider-client/index.js
|
|
8002
8933
|
var DEFAULT_PROVIDER_HOST_BASE_URL = "http://127.0.0.1:8797";
|
|
@@ -8068,12 +8999,12 @@ function resolveFetchImplementation(fetchImpl) {
|
|
|
8068
8999
|
function createProviderHostClient(options = {}) {
|
|
8069
9000
|
const fetchImpl = resolveFetchImplementation(options.fetch);
|
|
8070
9001
|
const baseUrl = normalizeProviderHostBaseUrl(options.baseUrl);
|
|
8071
|
-
async function jsonRequest(
|
|
8072
|
-
const response = await fetchImpl(`${baseUrl}${
|
|
9002
|
+
async function jsonRequest(path15, init) {
|
|
9003
|
+
const response = await fetchImpl(`${baseUrl}${path15}`, init);
|
|
8073
9004
|
const json = await response.json();
|
|
8074
9005
|
if (!response.ok || json?.ok === false) {
|
|
8075
9006
|
throw new Error(
|
|
8076
|
-
json?.error || json?.stderr || `provider host request failed for ${
|
|
9007
|
+
json?.error || json?.stderr || `provider host request failed for ${path15}`
|
|
8077
9008
|
);
|
|
8078
9009
|
}
|
|
8079
9010
|
return json;
|
|
@@ -8166,7 +9097,7 @@ function formatProviderLabel(provider) {
|
|
|
8166
9097
|
return provider.title?.trim().length ? provider.title.trim() : provider.id;
|
|
8167
9098
|
}
|
|
8168
9099
|
function printProviderSummary(provider) {
|
|
8169
|
-
console.log(
|
|
9100
|
+
console.log(kleur16.green(formatProviderLabel(provider)));
|
|
8170
9101
|
console.log(` id: ${provider.id}`);
|
|
8171
9102
|
if (provider.description) {
|
|
8172
9103
|
console.log(` description: ${provider.description}`);
|
|
@@ -8178,7 +9109,7 @@ function printProviderSummary(provider) {
|
|
|
8178
9109
|
console.log(` type: ${provider.providerType}`);
|
|
8179
9110
|
}
|
|
8180
9111
|
console.log(
|
|
8181
|
-
` discoverable: ${provider.discoverable !== false ?
|
|
9112
|
+
` discoverable: ${provider.discoverable !== false ? kleur16.green("yes") : kleur16.yellow("no")}`
|
|
8182
9113
|
);
|
|
8183
9114
|
if (provider.capabilityIds?.length) {
|
|
8184
9115
|
console.log(` capabilities: ${provider.capabilityIds.join(", ")}`);
|
|
@@ -8190,7 +9121,7 @@ function printProviderSummary(provider) {
|
|
|
8190
9121
|
console.log(` resources: ${provider.resourceUris.join(", ")}`);
|
|
8191
9122
|
}
|
|
8192
9123
|
if (provider.error) {
|
|
8193
|
-
console.log(` error: ${
|
|
9124
|
+
console.log(` error: ${kleur16.yellow(provider.error)}`);
|
|
8194
9125
|
}
|
|
8195
9126
|
}
|
|
8196
9127
|
function parseCommandJson(commandJson) {
|
|
@@ -8210,10 +9141,10 @@ async function providersList(options = {}) {
|
|
|
8210
9141
|
});
|
|
8211
9142
|
return;
|
|
8212
9143
|
}
|
|
8213
|
-
console.log(
|
|
9144
|
+
console.log(kleur16.green("Local providers"));
|
|
8214
9145
|
console.log(`Host: ${providerHostUrl}`);
|
|
8215
9146
|
if (!result.providers.length) {
|
|
8216
|
-
console.log(
|
|
9147
|
+
console.log(kleur16.yellow("No providers discovered."));
|
|
8217
9148
|
return;
|
|
8218
9149
|
}
|
|
8219
9150
|
for (const provider of result.providers) {
|
|
@@ -8230,7 +9161,7 @@ async function providersDiscover(params) {
|
|
|
8230
9161
|
});
|
|
8231
9162
|
return;
|
|
8232
9163
|
}
|
|
8233
|
-
console.log(
|
|
9164
|
+
console.log(kleur16.green(`Provider discovery: ${params.providerId}`));
|
|
8234
9165
|
console.log(`Host: ${providerHostUrl}`);
|
|
8235
9166
|
console.log(JSON.stringify(result.provider ?? result, null, 2));
|
|
8236
9167
|
}
|
|
@@ -8244,10 +9175,10 @@ async function providersRead(params) {
|
|
|
8244
9175
|
});
|
|
8245
9176
|
return;
|
|
8246
9177
|
}
|
|
8247
|
-
console.log(
|
|
9178
|
+
console.log(kleur16.green(`Provider resource: ${params.uri}`));
|
|
8248
9179
|
console.log(`Host: ${providerHostUrl}`);
|
|
8249
9180
|
if (result.exists === false) {
|
|
8250
|
-
console.log(
|
|
9181
|
+
console.log(kleur16.yellow("Resource does not exist."));
|
|
8251
9182
|
return;
|
|
8252
9183
|
}
|
|
8253
9184
|
console.log(JSON.stringify(result.value ?? result, null, 2));
|
|
@@ -8273,7 +9204,7 @@ async function providersProbe(params) {
|
|
|
8273
9204
|
});
|
|
8274
9205
|
return;
|
|
8275
9206
|
}
|
|
8276
|
-
console.log(
|
|
9207
|
+
console.log(kleur16.green(`Provider transport probe: ${params.providerId}`));
|
|
8277
9208
|
console.log(`Host: ${providerHostUrl}`);
|
|
8278
9209
|
console.log(JSON.stringify(result, null, 2));
|
|
8279
9210
|
}
|
|
@@ -8479,8 +9410,8 @@ async function diagnosticsRunResult(options) {
|
|
|
8479
9410
|
}
|
|
8480
9411
|
|
|
8481
9412
|
// src/support.ts
|
|
8482
|
-
import
|
|
8483
|
-
import
|
|
9413
|
+
import fs12 from "node:fs";
|
|
9414
|
+
import path13 from "node:path";
|
|
8484
9415
|
init_project_manifest();
|
|
8485
9416
|
var MAX_SUMMARY_CHARS = 500;
|
|
8486
9417
|
var MAX_DETAILS_BYTES = 2e4;
|
|
@@ -8494,34 +9425,34 @@ function cleanText3(value) {
|
|
|
8494
9425
|
return typeof value === "string" && value.trim() ? value.trim() : null;
|
|
8495
9426
|
}
|
|
8496
9427
|
function readRegularFile(filePath, maxBytes, label) {
|
|
8497
|
-
const resolved =
|
|
9428
|
+
const resolved = path13.resolve(filePath);
|
|
8498
9429
|
const manifestPath = findProjectManifest(process.cwd()).path;
|
|
8499
|
-
const workspaceRoot = manifestPath ?
|
|
8500
|
-
const canonicalRoot =
|
|
8501
|
-
const canonicalParent =
|
|
8502
|
-
const canonicalTarget =
|
|
8503
|
-
const relativeTarget =
|
|
8504
|
-
if (relativeTarget === ".." || relativeTarget.startsWith(`..${
|
|
9430
|
+
const workspaceRoot = manifestPath ? path13.dirname(path13.dirname(manifestPath)) : process.cwd();
|
|
9431
|
+
const canonicalRoot = fs12.realpathSync(workspaceRoot);
|
|
9432
|
+
const canonicalParent = fs12.realpathSync(path13.dirname(resolved));
|
|
9433
|
+
const canonicalTarget = path13.join(canonicalParent, path13.basename(resolved));
|
|
9434
|
+
const relativeTarget = path13.relative(canonicalRoot, canonicalTarget);
|
|
9435
|
+
if (relativeTarget === ".." || relativeTarget.startsWith(`..${path13.sep}`) || path13.isAbsolute(relativeTarget)) {
|
|
8505
9436
|
throw new Error(`${label} must stay inside the active Instafy workspace.`);
|
|
8506
9437
|
}
|
|
8507
|
-
const initialStat =
|
|
9438
|
+
const initialStat = fs12.lstatSync(canonicalTarget);
|
|
8508
9439
|
if (initialStat.isSymbolicLink() || !initialStat.isFile()) {
|
|
8509
9440
|
throw new Error(`${label} must be a regular file, not a symlink.`);
|
|
8510
9441
|
}
|
|
8511
|
-
const noFollow = typeof
|
|
8512
|
-
const descriptor =
|
|
9442
|
+
const noFollow = typeof fs12.constants.O_NOFOLLOW === "number" ? fs12.constants.O_NOFOLLOW : 0;
|
|
9443
|
+
const descriptor = fs12.openSync(canonicalTarget, fs12.constants.O_RDONLY | noFollow);
|
|
8513
9444
|
try {
|
|
8514
|
-
const openedStat =
|
|
9445
|
+
const openedStat = fs12.fstatSync(descriptor);
|
|
8515
9446
|
if (!openedStat.isFile() || openedStat.dev !== initialStat.dev || openedStat.ino !== initialStat.ino || openedStat.size > maxBytes) {
|
|
8516
9447
|
throw new Error(`${label} must be a regular file no larger than ${maxBytes} bytes.`);
|
|
8517
9448
|
}
|
|
8518
|
-
const bytes =
|
|
9449
|
+
const bytes = fs12.readFileSync(descriptor);
|
|
8519
9450
|
if (bytes.length > maxBytes) {
|
|
8520
9451
|
throw new Error(`${label} must be ${maxBytes} bytes or smaller.`);
|
|
8521
9452
|
}
|
|
8522
9453
|
return bytes;
|
|
8523
9454
|
} finally {
|
|
8524
|
-
|
|
9455
|
+
fs12.closeSync(descriptor);
|
|
8525
9456
|
}
|
|
8526
9457
|
}
|
|
8527
9458
|
function readJsonFile(filePath, maxBytes, label) {
|
|
@@ -8597,7 +9528,7 @@ function resolveScreenshots(filePaths = []) {
|
|
|
8597
9528
|
);
|
|
8598
9529
|
}
|
|
8599
9530
|
return {
|
|
8600
|
-
fileName:
|
|
9531
|
+
fileName: path13.basename(filePath),
|
|
8601
9532
|
mediaType,
|
|
8602
9533
|
dataBase64: bytes.toString("base64"),
|
|
8603
9534
|
byteLength: bytes.length
|
|
@@ -8900,7 +9831,7 @@ program.command("login").description("Log in and save an access token for future
|
|
|
8900
9831
|
json: opts.json
|
|
8901
9832
|
});
|
|
8902
9833
|
} catch (error) {
|
|
8903
|
-
console.error(
|
|
9834
|
+
console.error(kleur19.red(String(error)));
|
|
8904
9835
|
process.exit(1);
|
|
8905
9836
|
}
|
|
8906
9837
|
});
|
|
@@ -8908,7 +9839,7 @@ program.command("logout").description("Clear the saved CLI access token").option
|
|
|
8908
9839
|
try {
|
|
8909
9840
|
await logout({ json: opts.json, profile: opts.profile });
|
|
8910
9841
|
} catch (error) {
|
|
8911
|
-
console.error(
|
|
9842
|
+
console.error(kleur19.red(String(error)));
|
|
8912
9843
|
process.exit(1);
|
|
8913
9844
|
}
|
|
8914
9845
|
});
|
|
@@ -8932,7 +9863,7 @@ chatCommand.option("--json", "Output JSON").action(async (promptParts, opts) =>
|
|
|
8932
9863
|
json: opts.json
|
|
8933
9864
|
});
|
|
8934
9865
|
} catch (error) {
|
|
8935
|
-
console.error(
|
|
9866
|
+
console.error(kleur19.red(String(error)));
|
|
8936
9867
|
process.exit(1);
|
|
8937
9868
|
}
|
|
8938
9869
|
});
|
|
@@ -8956,7 +9887,7 @@ function registerSpaceCommand(command) {
|
|
|
8956
9887
|
json: opts.json
|
|
8957
9888
|
});
|
|
8958
9889
|
} catch (error) {
|
|
8959
|
-
console.error(
|
|
9890
|
+
console.error(kleur19.red(String(error)));
|
|
8960
9891
|
process.exit(1);
|
|
8961
9892
|
}
|
|
8962
9893
|
});
|
|
@@ -8972,7 +9903,7 @@ function registerSpaceCommand(command) {
|
|
|
8972
9903
|
json: opts.json
|
|
8973
9904
|
});
|
|
8974
9905
|
} catch (error) {
|
|
8975
|
-
console.error(
|
|
9906
|
+
console.error(kleur19.red(String(error)));
|
|
8976
9907
|
process.exit(1);
|
|
8977
9908
|
}
|
|
8978
9909
|
});
|
|
@@ -8986,7 +9917,7 @@ function registerSpaceCommand(command) {
|
|
|
8986
9917
|
json: opts.json
|
|
8987
9918
|
});
|
|
8988
9919
|
} catch (error) {
|
|
8989
|
-
console.error(
|
|
9920
|
+
console.error(kleur19.red(String(error)));
|
|
8990
9921
|
process.exit(1);
|
|
8991
9922
|
}
|
|
8992
9923
|
});
|
|
@@ -9009,7 +9940,7 @@ function registerSpaceCommand(command) {
|
|
|
9009
9940
|
json: opts.json
|
|
9010
9941
|
});
|
|
9011
9942
|
} catch (error) {
|
|
9012
|
-
console.error(
|
|
9943
|
+
console.error(kleur19.red(String(error)));
|
|
9013
9944
|
process.exit(1);
|
|
9014
9945
|
}
|
|
9015
9946
|
});
|
|
@@ -9021,7 +9952,7 @@ function registerSpaceCommand(command) {
|
|
|
9021
9952
|
json: opts.json
|
|
9022
9953
|
});
|
|
9023
9954
|
} catch (error) {
|
|
9024
|
-
console.error(
|
|
9955
|
+
console.error(kleur19.red(String(error)));
|
|
9025
9956
|
process.exit(1);
|
|
9026
9957
|
}
|
|
9027
9958
|
});
|
|
@@ -9043,7 +9974,7 @@ function registerSpaceCommand(command) {
|
|
|
9043
9974
|
json: opts.json
|
|
9044
9975
|
});
|
|
9045
9976
|
} catch (error) {
|
|
9046
|
-
console.error(
|
|
9977
|
+
console.error(kleur19.red(String(error)));
|
|
9047
9978
|
process.exit(1);
|
|
9048
9979
|
}
|
|
9049
9980
|
});
|
|
@@ -9059,7 +9990,7 @@ function registerSpaceCommand(command) {
|
|
|
9059
9990
|
json: opts.json
|
|
9060
9991
|
});
|
|
9061
9992
|
} catch (error) {
|
|
9062
|
-
console.error(
|
|
9993
|
+
console.error(kleur19.red(String(error)));
|
|
9063
9994
|
process.exit(1);
|
|
9064
9995
|
}
|
|
9065
9996
|
});
|
|
@@ -9085,7 +10016,7 @@ function registerSpaceCommand(command) {
|
|
|
9085
10016
|
json: opts.json
|
|
9086
10017
|
});
|
|
9087
10018
|
} catch (error) {
|
|
9088
|
-
console.error(
|
|
10019
|
+
console.error(kleur19.red(String(error)));
|
|
9089
10020
|
process.exit(1);
|
|
9090
10021
|
}
|
|
9091
10022
|
});
|
|
@@ -9110,7 +10041,7 @@ function registerSpaceCommand(command) {
|
|
|
9110
10041
|
json: opts.json
|
|
9111
10042
|
});
|
|
9112
10043
|
} catch (error) {
|
|
9113
|
-
console.error(
|
|
10044
|
+
console.error(kleur19.red(String(error)));
|
|
9114
10045
|
process.exit(1);
|
|
9115
10046
|
}
|
|
9116
10047
|
});
|
|
@@ -9130,7 +10061,7 @@ hardwareBindingsCommand.command("show").description("Show hardware bindings for
|
|
|
9130
10061
|
json: opts.json
|
|
9131
10062
|
});
|
|
9132
10063
|
} catch (error) {
|
|
9133
|
-
console.error(
|
|
10064
|
+
console.error(kleur19.red(String(error)));
|
|
9134
10065
|
process.exit(1);
|
|
9135
10066
|
}
|
|
9136
10067
|
});
|
|
@@ -9150,7 +10081,7 @@ hardwareBindingsCommand.command("grant").description("Grant a local hardware pro
|
|
|
9150
10081
|
json: opts.json
|
|
9151
10082
|
});
|
|
9152
10083
|
} catch (error) {
|
|
9153
|
-
console.error(
|
|
10084
|
+
console.error(kleur19.red(String(error)));
|
|
9154
10085
|
process.exit(1);
|
|
9155
10086
|
}
|
|
9156
10087
|
});
|
|
@@ -9162,7 +10093,7 @@ hardwareBindingsCommand.command("revoke").description("Revoke a local hardware b
|
|
|
9162
10093
|
json: opts.json
|
|
9163
10094
|
});
|
|
9164
10095
|
} catch (error) {
|
|
9165
|
-
console.error(
|
|
10096
|
+
console.error(kleur19.red(String(error)));
|
|
9166
10097
|
process.exit(1);
|
|
9167
10098
|
}
|
|
9168
10099
|
});
|
|
@@ -9176,7 +10107,7 @@ hardwareSerialCommand.command("list").description("List local serial devices vis
|
|
|
9176
10107
|
scanDirs: opts.scanDir
|
|
9177
10108
|
});
|
|
9178
10109
|
} catch (error) {
|
|
9179
|
-
console.error(
|
|
10110
|
+
console.error(kleur19.red(String(error)));
|
|
9180
10111
|
process.exit(1);
|
|
9181
10112
|
}
|
|
9182
10113
|
});
|
|
@@ -9188,7 +10119,7 @@ hardwareSerialCommand.command("probe").description("Probe host permissions for o
|
|
|
9188
10119
|
json: opts.json
|
|
9189
10120
|
});
|
|
9190
10121
|
} catch (error) {
|
|
9191
|
-
console.error(
|
|
10122
|
+
console.error(kleur19.red(String(error)));
|
|
9192
10123
|
process.exit(1);
|
|
9193
10124
|
}
|
|
9194
10125
|
});
|
|
@@ -9200,7 +10131,7 @@ hardwareCommand.command("opportunities").description("List host-local IO opportu
|
|
|
9200
10131
|
scanDirs: opts.scanDir
|
|
9201
10132
|
});
|
|
9202
10133
|
} catch (error) {
|
|
9203
|
-
console.error(
|
|
10134
|
+
console.error(kleur19.red(String(error)));
|
|
9204
10135
|
process.exit(1);
|
|
9205
10136
|
}
|
|
9206
10137
|
});
|
|
@@ -9213,7 +10144,7 @@ hardwareCommand.command("run").description("Run one available host-local IO acti
|
|
|
9213
10144
|
json: opts.json
|
|
9214
10145
|
});
|
|
9215
10146
|
} catch (error) {
|
|
9216
|
-
console.error(
|
|
10147
|
+
console.error(kleur19.red(String(error)));
|
|
9217
10148
|
process.exit(1);
|
|
9218
10149
|
}
|
|
9219
10150
|
});
|
|
@@ -9228,7 +10159,7 @@ providersListCommand.option("--json", "Output JSON").action(async (opts) => {
|
|
|
9228
10159
|
json: opts.json
|
|
9229
10160
|
});
|
|
9230
10161
|
} catch (error) {
|
|
9231
|
-
console.error(
|
|
10162
|
+
console.error(kleur19.red(String(error)));
|
|
9232
10163
|
process.exit(1);
|
|
9233
10164
|
}
|
|
9234
10165
|
});
|
|
@@ -9242,7 +10173,7 @@ providersDiscoverCommand.option("--json", "Output JSON").action(async (providerI
|
|
|
9242
10173
|
json: opts.json
|
|
9243
10174
|
});
|
|
9244
10175
|
} catch (error) {
|
|
9245
|
-
console.error(
|
|
10176
|
+
console.error(kleur19.red(String(error)));
|
|
9246
10177
|
process.exit(1);
|
|
9247
10178
|
}
|
|
9248
10179
|
});
|
|
@@ -9257,7 +10188,7 @@ providersReadCommand.option("--json", "Output JSON").action(async (providerId, u
|
|
|
9257
10188
|
json: opts.json
|
|
9258
10189
|
});
|
|
9259
10190
|
} catch (error) {
|
|
9260
|
-
console.error(
|
|
10191
|
+
console.error(kleur19.red(String(error)));
|
|
9261
10192
|
process.exit(1);
|
|
9262
10193
|
}
|
|
9263
10194
|
});
|
|
@@ -9280,7 +10211,7 @@ providersProbeCommand.option("--json", "Output JSON").action(async (providerId,
|
|
|
9280
10211
|
json: opts.json
|
|
9281
10212
|
});
|
|
9282
10213
|
} catch (error) {
|
|
9283
|
-
console.error(
|
|
10214
|
+
console.error(kleur19.red(String(error)));
|
|
9284
10215
|
process.exit(1);
|
|
9285
10216
|
}
|
|
9286
10217
|
});
|
|
@@ -9302,7 +10233,7 @@ agentsListCommand.option("--json", "Output JSON").action(async (opts) => {
|
|
|
9302
10233
|
json: opts.json
|
|
9303
10234
|
});
|
|
9304
10235
|
} catch (error) {
|
|
9305
|
-
console.error(
|
|
10236
|
+
console.error(kleur19.red(String(error)));
|
|
9306
10237
|
process.exit(1);
|
|
9307
10238
|
}
|
|
9308
10239
|
});
|
|
@@ -9330,7 +10261,7 @@ agentsContextListCommand.option("--agent <handle>", "Filter by agent handle (for
|
|
|
9330
10261
|
json: opts.json
|
|
9331
10262
|
});
|
|
9332
10263
|
} catch (error) {
|
|
9333
|
-
console.error(
|
|
10264
|
+
console.error(kleur19.red(String(error)));
|
|
9334
10265
|
process.exit(1);
|
|
9335
10266
|
}
|
|
9336
10267
|
});
|
|
@@ -9356,7 +10287,7 @@ agentsContextPutCommand.action(async (contextParts, opts) => {
|
|
|
9356
10287
|
json: opts.json
|
|
9357
10288
|
});
|
|
9358
10289
|
} catch (error) {
|
|
9359
|
-
console.error(
|
|
10290
|
+
console.error(kleur19.red(String(error)));
|
|
9360
10291
|
process.exit(1);
|
|
9361
10292
|
}
|
|
9362
10293
|
});
|
|
@@ -9372,7 +10303,7 @@ agentsStatusCommand.option("--json", "Output JSON").action(async (groupId, opts)
|
|
|
9372
10303
|
json: opts.json
|
|
9373
10304
|
});
|
|
9374
10305
|
} catch (error) {
|
|
9375
|
-
console.error(
|
|
10306
|
+
console.error(kleur19.red(String(error)));
|
|
9376
10307
|
process.exit(1);
|
|
9377
10308
|
}
|
|
9378
10309
|
});
|
|
@@ -9390,7 +10321,7 @@ agentsCancelCommand.option("--json", "Output JSON").action(async (opts) => {
|
|
|
9390
10321
|
json: opts.json
|
|
9391
10322
|
});
|
|
9392
10323
|
} catch (error) {
|
|
9393
|
-
console.error(
|
|
10324
|
+
console.error(kleur19.red(String(error)));
|
|
9394
10325
|
process.exit(1);
|
|
9395
10326
|
}
|
|
9396
10327
|
});
|
|
@@ -9412,7 +10343,7 @@ secretsListCommand.option("--json", "Output JSON").action(async (opts) => {
|
|
|
9412
10343
|
json: opts.json
|
|
9413
10344
|
});
|
|
9414
10345
|
} catch (error) {
|
|
9415
|
-
console.error(
|
|
10346
|
+
console.error(kleur19.red(String(error)));
|
|
9416
10347
|
process.exit(1);
|
|
9417
10348
|
}
|
|
9418
10349
|
});
|
|
@@ -9433,7 +10364,7 @@ secretsGetCommand.option("--json", "Output JSON").action(async (nameOrId, opts)
|
|
|
9433
10364
|
json: opts.json
|
|
9434
10365
|
});
|
|
9435
10366
|
} catch (error) {
|
|
9436
|
-
console.error(
|
|
10367
|
+
console.error(kleur19.red(String(error)));
|
|
9437
10368
|
process.exit(1);
|
|
9438
10369
|
}
|
|
9439
10370
|
});
|
|
@@ -9458,7 +10389,7 @@ secretsPutCommand.option("--json", "Output JSON").action(async (name, opts) => {
|
|
|
9458
10389
|
json: opts.json
|
|
9459
10390
|
});
|
|
9460
10391
|
} catch (error) {
|
|
9461
|
-
console.error(
|
|
10392
|
+
console.error(kleur19.red(String(error)));
|
|
9462
10393
|
process.exit(1);
|
|
9463
10394
|
}
|
|
9464
10395
|
});
|
|
@@ -9479,10 +10410,24 @@ secretsRevokeCommand.option("--json", "Output JSON").action(async (nameOrId, opt
|
|
|
9479
10410
|
json: opts.json
|
|
9480
10411
|
});
|
|
9481
10412
|
} catch (error) {
|
|
9482
|
-
console.error(
|
|
10413
|
+
console.error(kleur19.red(String(error)));
|
|
9483
10414
|
process.exit(1);
|
|
9484
10415
|
}
|
|
9485
10416
|
});
|
|
10417
|
+
function resolveResultVisibilityFlag(opts) {
|
|
10418
|
+
if (opts.resultVisibility !== void 0) {
|
|
10419
|
+
const value = String(opts.resultVisibility).trim().toLowerCase();
|
|
10420
|
+
if (value !== "private" && value !== "team") {
|
|
10421
|
+
throw new Error("--result-visibility must be private or team");
|
|
10422
|
+
}
|
|
10423
|
+
return value;
|
|
10424
|
+
}
|
|
10425
|
+
if (opts.shareResults === true)
|
|
10426
|
+
return "team";
|
|
10427
|
+
if (opts.shareResults === false)
|
|
10428
|
+
return "private";
|
|
10429
|
+
return void 0;
|
|
10430
|
+
}
|
|
9486
10431
|
var automationsCommand = program.command("automations").description("Manage scheduled automations (run prompts on a schedule)");
|
|
9487
10432
|
failWithGroupHelp(automationsCommand);
|
|
9488
10433
|
var automationsListCommand = automationsCommand.command("list").description("List automations for this space");
|
|
@@ -9501,13 +10446,22 @@ automationsListCommand.option("--json", "Output JSON").action(async (opts) => {
|
|
|
9501
10446
|
json: opts.json
|
|
9502
10447
|
});
|
|
9503
10448
|
} catch (error) {
|
|
9504
|
-
console.error(
|
|
10449
|
+
console.error(kleur19.red(String(error)));
|
|
9505
10450
|
process.exit(1);
|
|
9506
10451
|
}
|
|
9507
10452
|
});
|
|
9508
10453
|
var automationsCreateCommand = automationsCommand.command("create").description("Create an automation").requiredOption("--name <name>", "Automation name").requiredOption("--prompt <text>", "Prompt to run on schedule").option("--schedule-kind <kind>", "weekly|hourly|once (default: weekly)").option("--run-at <datetime>", "Run time for once schedule (RFC3339 or YYYY-MM-DDTHH:MM[:SS])").option("--interval-hours <n>", "Interval hours (hourly schedule)", (value) => Number(value)).option("--days <list>", "Weekdays for weekly schedule (e.g. mo,tu,we,th,fr)").option("--time <hh:mm>", "Time for weekly schedule (24h, e.g. 09:00)").option("--timezone <tz>", "IANA timezone (e.g. America/New_York)").option("--runtime-mode <mode>", "auto|hosted|existing (default: auto)").option("--runtime-provider <id>", "Runtime provider id (optional)").option(
|
|
9509
10454
|
"--silent-when-nothing-to-report",
|
|
9510
10455
|
"Do not post a completion result or send a result notification when a successful run has no findings"
|
|
10456
|
+
).option(
|
|
10457
|
+
"--share-results",
|
|
10458
|
+
"Share this automation's result threads with your team (visible to anyone with space access)"
|
|
10459
|
+
).option(
|
|
10460
|
+
"--no-share-results",
|
|
10461
|
+
"Keep this automation's result threads private to you (default)"
|
|
10462
|
+
).option(
|
|
10463
|
+
"--result-visibility <private|team>",
|
|
10464
|
+
"Result-thread visibility (private|team); overrides --share-results"
|
|
9511
10465
|
).option("--paused", "Create paused");
|
|
9512
10466
|
addSpaceOption(
|
|
9513
10467
|
automationsCreateCommand,
|
|
@@ -9529,6 +10483,7 @@ automationsCreateCommand.option("--json", "Output JSON").action(async (opts) =>
|
|
|
9529
10483
|
runtimeMode: opts.runtimeMode,
|
|
9530
10484
|
runtimeProvider: opts.runtimeProvider,
|
|
9531
10485
|
silentWhenNothingToReport: Boolean(opts.silentWhenNothingToReport),
|
|
10486
|
+
resultVisibility: resolveResultVisibilityFlag(opts),
|
|
9532
10487
|
paused: Boolean(opts.paused),
|
|
9533
10488
|
project: resolveSpaceIdOption(opts),
|
|
9534
10489
|
controllerUrl: opts.serverUrl,
|
|
@@ -9536,7 +10491,53 @@ automationsCreateCommand.option("--json", "Output JSON").action(async (opts) =>
|
|
|
9536
10491
|
json: opts.json
|
|
9537
10492
|
});
|
|
9538
10493
|
} catch (error) {
|
|
9539
|
-
console.error(
|
|
10494
|
+
console.error(kleur19.red(String(error)));
|
|
10495
|
+
process.exit(1);
|
|
10496
|
+
}
|
|
10497
|
+
});
|
|
10498
|
+
var automationsUpdateCommand = automationsCommand.command("update").description(
|
|
10499
|
+
"Update an automation's name, prompt, schedule, runtime settings, or result-sharing visibility in place"
|
|
10500
|
+
).argument("<automation-id>", "Automation UUID").option("--name <name>", "New automation name").option("--prompt <text>", "New prompt to run on schedule").option("--prompt-file <path>", "Read the new prompt from a file").option("--schedule-kind <kind>", "weekly|hourly|once").option("--run-at <datetime>", "Run time for once schedule (RFC3339 or YYYY-MM-DDTHH:MM[:SS])").option("--interval-hours <n>", "Interval hours (hourly schedule)", (value) => Number(value)).option("--days <list>", "Weekdays for weekly schedule (e.g. mo,tu,we,th,fr)").option("--time <hh:mm>", "Time for weekly schedule (24h, e.g. 09:00)").option("--timezone <tz>", "IANA timezone (e.g. America/New_York)").option("--runtime-mode <mode>", "auto|hosted|existing").option("--runtime-provider <id>", "Runtime provider id").option(
|
|
10501
|
+
"--silent-when-nothing-to-report",
|
|
10502
|
+
"Do not post a completion result or send a result notification when a successful run has no findings"
|
|
10503
|
+
).option(
|
|
10504
|
+
"--no-silent-when-nothing-to-report",
|
|
10505
|
+
"Always post a completion result and send a result notification"
|
|
10506
|
+
).option(
|
|
10507
|
+
"--share-results",
|
|
10508
|
+
"Share this automation's result threads with your team (visible to anyone with space access)"
|
|
10509
|
+
).option(
|
|
10510
|
+
"--no-share-results",
|
|
10511
|
+
"Keep this automation's result threads private to you"
|
|
10512
|
+
).option(
|
|
10513
|
+
"--result-visibility <private|team>",
|
|
10514
|
+
"Result-thread visibility (private|team); overrides --share-results"
|
|
10515
|
+
);
|
|
10516
|
+
addServerUrlOptions(automationsUpdateCommand);
|
|
10517
|
+
addAccessTokenOptions(automationsUpdateCommand, "Instafy access token");
|
|
10518
|
+
automationsUpdateCommand.option("--json", "Output JSON").action(async (automationId, opts) => {
|
|
10519
|
+
try {
|
|
10520
|
+
await automationsUpdate({
|
|
10521
|
+
automationId,
|
|
10522
|
+
name: opts.name,
|
|
10523
|
+
prompt: opts.prompt,
|
|
10524
|
+
promptFile: opts.promptFile,
|
|
10525
|
+
scheduleKind: opts.scheduleKind,
|
|
10526
|
+
runAt: opts.runAt,
|
|
10527
|
+
intervalHours: opts.intervalHours,
|
|
10528
|
+
days: opts.days,
|
|
10529
|
+
time: opts.time,
|
|
10530
|
+
timezone: opts.timezone,
|
|
10531
|
+
runtimeMode: opts.runtimeMode,
|
|
10532
|
+
runtimeProvider: opts.runtimeProvider,
|
|
10533
|
+
silentWhenNothingToReport: opts.silentWhenNothingToReport,
|
|
10534
|
+
resultVisibility: resolveResultVisibilityFlag(opts),
|
|
10535
|
+
controllerUrl: opts.serverUrl,
|
|
10536
|
+
accessToken: opts.accessToken,
|
|
10537
|
+
json: opts.json
|
|
10538
|
+
});
|
|
10539
|
+
} catch (error) {
|
|
10540
|
+
console.error(kleur19.red(String(error)));
|
|
9540
10541
|
process.exit(1);
|
|
9541
10542
|
}
|
|
9542
10543
|
});
|
|
@@ -9553,7 +10554,7 @@ automationsPauseCommand.option("--json", "Output JSON").action(async (automation
|
|
|
9553
10554
|
json: opts.json
|
|
9554
10555
|
});
|
|
9555
10556
|
} catch (error) {
|
|
9556
|
-
console.error(
|
|
10557
|
+
console.error(kleur19.red(String(error)));
|
|
9557
10558
|
process.exit(1);
|
|
9558
10559
|
}
|
|
9559
10560
|
});
|
|
@@ -9570,7 +10571,7 @@ automationsResumeCommand.option("--json", "Output JSON").action(async (automatio
|
|
|
9570
10571
|
json: opts.json
|
|
9571
10572
|
});
|
|
9572
10573
|
} catch (error) {
|
|
9573
|
-
console.error(
|
|
10574
|
+
console.error(kleur19.red(String(error)));
|
|
9574
10575
|
process.exit(1);
|
|
9575
10576
|
}
|
|
9576
10577
|
});
|
|
@@ -9586,7 +10587,7 @@ automationsRunCommand.option("--json", "Output JSON").action(async (automationId
|
|
|
9586
10587
|
json: opts.json
|
|
9587
10588
|
});
|
|
9588
10589
|
} catch (error) {
|
|
9589
|
-
console.error(
|
|
10590
|
+
console.error(kleur19.red(String(error)));
|
|
9590
10591
|
process.exit(1);
|
|
9591
10592
|
}
|
|
9592
10593
|
});
|
|
@@ -9602,7 +10603,92 @@ automationsDeleteCommand.option("--json", "Output JSON").action(async (automatio
|
|
|
9602
10603
|
json: opts.json
|
|
9603
10604
|
});
|
|
9604
10605
|
} catch (error) {
|
|
9605
|
-
console.error(
|
|
10606
|
+
console.error(kleur19.red(String(error)));
|
|
10607
|
+
process.exit(1);
|
|
10608
|
+
}
|
|
10609
|
+
});
|
|
10610
|
+
var credentialsCommand = program.command("credentials").description("Inspect, verify and pick the AI provider credentials your jobs use");
|
|
10611
|
+
failWithGroupHelp(credentialsCommand);
|
|
10612
|
+
var credentialsListCommand = credentialsCommand.command("list").description("List your AI credentials (secret material is never shown)").option("--all", "Include revoked credentials");
|
|
10613
|
+
addServerUrlOptions(credentialsListCommand);
|
|
10614
|
+
addAccessTokenOptions(credentialsListCommand, "Instafy access token");
|
|
10615
|
+
credentialsListCommand.option("--json", "Output JSON").action(async (opts) => {
|
|
10616
|
+
try {
|
|
10617
|
+
await credentialsList({
|
|
10618
|
+
all: Boolean(opts.all),
|
|
10619
|
+
controllerUrl: opts.serverUrl,
|
|
10620
|
+
accessToken: opts.accessToken,
|
|
10621
|
+
json: opts.json
|
|
10622
|
+
});
|
|
10623
|
+
} catch (error) {
|
|
10624
|
+
console.error(kleur19.red(String(error)));
|
|
10625
|
+
process.exit(1);
|
|
10626
|
+
}
|
|
10627
|
+
});
|
|
10628
|
+
var credentialsTestCommand = credentialsCommand.command("test").description("Probe one credential through the proxy against its upstream provider (exit 1 on failure)").argument("<id-or-prefix>", "Credential UUID or unique id prefix");
|
|
10629
|
+
addServerUrlOptions(credentialsTestCommand);
|
|
10630
|
+
addAccessTokenOptions(credentialsTestCommand, "Instafy access token");
|
|
10631
|
+
credentialsTestCommand.option("--json", "Output JSON").action(async (idOrPrefix, opts) => {
|
|
10632
|
+
try {
|
|
10633
|
+
const result = await credentialsTest({
|
|
10634
|
+
idOrPrefix,
|
|
10635
|
+
controllerUrl: opts.serverUrl,
|
|
10636
|
+
accessToken: opts.accessToken,
|
|
10637
|
+
json: opts.json
|
|
10638
|
+
});
|
|
10639
|
+
if (!result.ok) {
|
|
10640
|
+
process.exitCode = 1;
|
|
10641
|
+
}
|
|
10642
|
+
} catch (error) {
|
|
10643
|
+
console.error(kleur19.red(String(error)));
|
|
10644
|
+
process.exit(1);
|
|
10645
|
+
}
|
|
10646
|
+
});
|
|
10647
|
+
var credentialsDefaultCommand = credentialsCommand.command("default").description("Set the default credential jobs use, or clear it with --clear").argument("[id-or-prefix]", "Credential UUID or unique id prefix").option("--clear", "Clear the default credential instead of setting one");
|
|
10648
|
+
addServerUrlOptions(credentialsDefaultCommand);
|
|
10649
|
+
addAccessTokenOptions(credentialsDefaultCommand, "Instafy access token");
|
|
10650
|
+
credentialsDefaultCommand.option("--json", "Output JSON").action(async (idOrPrefix, opts) => {
|
|
10651
|
+
try {
|
|
10652
|
+
const target = pickTrimmedString2(idOrPrefix);
|
|
10653
|
+
if (opts.clear && target) {
|
|
10654
|
+
throw new Error("Pass either a credential id or --clear, not both.");
|
|
10655
|
+
}
|
|
10656
|
+
if (!opts.clear && !target) {
|
|
10657
|
+
throw new Error("Provide a credential id (or unique prefix), or pass --clear.");
|
|
10658
|
+
}
|
|
10659
|
+
if (opts.clear) {
|
|
10660
|
+
await credentialsClearDefault({
|
|
10661
|
+
controllerUrl: opts.serverUrl,
|
|
10662
|
+
accessToken: opts.accessToken,
|
|
10663
|
+
json: opts.json
|
|
10664
|
+
});
|
|
10665
|
+
return;
|
|
10666
|
+
}
|
|
10667
|
+
await credentialsSetDefault({
|
|
10668
|
+
idOrPrefix: target,
|
|
10669
|
+
controllerUrl: opts.serverUrl,
|
|
10670
|
+
accessToken: opts.accessToken,
|
|
10671
|
+
json: opts.json
|
|
10672
|
+
});
|
|
10673
|
+
} catch (error) {
|
|
10674
|
+
console.error(kleur19.red(String(error)));
|
|
10675
|
+
process.exit(1);
|
|
10676
|
+
}
|
|
10677
|
+
});
|
|
10678
|
+
var credentialsRevokeCommand = credentialsCommand.command("revoke").description("Revoke a credential (asks for confirmation unless --yes)").argument("<id-or-prefix>", "Credential UUID or unique id prefix").option("--yes", "Skip the confirmation prompt (required when not running in a terminal)");
|
|
10679
|
+
addServerUrlOptions(credentialsRevokeCommand);
|
|
10680
|
+
addAccessTokenOptions(credentialsRevokeCommand, "Instafy access token");
|
|
10681
|
+
credentialsRevokeCommand.option("--json", "Output JSON").action(async (idOrPrefix, opts) => {
|
|
10682
|
+
try {
|
|
10683
|
+
await credentialsRevoke({
|
|
10684
|
+
idOrPrefix,
|
|
10685
|
+
yes: Boolean(opts.yes),
|
|
10686
|
+
controllerUrl: opts.serverUrl,
|
|
10687
|
+
accessToken: opts.accessToken,
|
|
10688
|
+
json: opts.json
|
|
10689
|
+
});
|
|
10690
|
+
} catch (error) {
|
|
10691
|
+
console.error(kleur19.red(String(error)));
|
|
9606
10692
|
process.exit(1);
|
|
9607
10693
|
}
|
|
9608
10694
|
});
|
|
@@ -9612,7 +10698,7 @@ configCommand.command("path").description("Print the config file path").option("
|
|
|
9612
10698
|
try {
|
|
9613
10699
|
configPath({ json: opts.json });
|
|
9614
10700
|
} catch (error) {
|
|
9615
|
-
console.error(
|
|
10701
|
+
console.error(kleur19.red(String(error)));
|
|
9616
10702
|
process.exit(1);
|
|
9617
10703
|
}
|
|
9618
10704
|
});
|
|
@@ -9620,7 +10706,7 @@ configCommand.command("list").description("List saved configuration").option("--
|
|
|
9620
10706
|
try {
|
|
9621
10707
|
configList({ json: opts.json });
|
|
9622
10708
|
} catch (error) {
|
|
9623
|
-
console.error(
|
|
10709
|
+
console.error(kleur19.red(String(error)));
|
|
9624
10710
|
process.exit(1);
|
|
9625
10711
|
}
|
|
9626
10712
|
});
|
|
@@ -9628,7 +10714,7 @@ configCommand.command("get").description("Get a config value (controller-url, st
|
|
|
9628
10714
|
try {
|
|
9629
10715
|
configGet({ key, json: opts.json });
|
|
9630
10716
|
} catch (error) {
|
|
9631
|
-
console.error(
|
|
10717
|
+
console.error(kleur19.red(String(error)));
|
|
9632
10718
|
process.exit(1);
|
|
9633
10719
|
}
|
|
9634
10720
|
});
|
|
@@ -9636,7 +10722,7 @@ configCommand.command("set").description("Set a config value (controller-url, st
|
|
|
9636
10722
|
try {
|
|
9637
10723
|
configSet({ key, value, json: opts.json });
|
|
9638
10724
|
} catch (error) {
|
|
9639
|
-
console.error(
|
|
10725
|
+
console.error(kleur19.red(String(error)));
|
|
9640
10726
|
process.exit(1);
|
|
9641
10727
|
}
|
|
9642
10728
|
});
|
|
@@ -9644,7 +10730,7 @@ configCommand.command("unset").description("Unset a config value (controller-url
|
|
|
9644
10730
|
try {
|
|
9645
10731
|
configUnset({ key, json: opts.json });
|
|
9646
10732
|
} catch (error) {
|
|
9647
|
-
console.error(
|
|
10733
|
+
console.error(kleur19.red(String(error)));
|
|
9648
10734
|
process.exit(1);
|
|
9649
10735
|
}
|
|
9650
10736
|
});
|
|
@@ -9664,7 +10750,7 @@ runtimeStartCommand.option("--supabase-access-token <token>", "Supabase session
|
|
|
9664
10750
|
controllerAccessToken: opts.accessToken
|
|
9665
10751
|
});
|
|
9666
10752
|
} catch (error) {
|
|
9667
|
-
console.error(
|
|
10753
|
+
console.error(kleur19.red(String(error)));
|
|
9668
10754
|
process.exit(1);
|
|
9669
10755
|
}
|
|
9670
10756
|
});
|
|
@@ -9672,7 +10758,7 @@ runtimeCommand.command("status").description("Show runtime health").option("--js
|
|
|
9672
10758
|
try {
|
|
9673
10759
|
await runtimeStatus({ json: opts.json });
|
|
9674
10760
|
} catch (error) {
|
|
9675
|
-
console.error(
|
|
10761
|
+
console.error(kleur19.red(String(error)));
|
|
9676
10762
|
process.exit(1);
|
|
9677
10763
|
}
|
|
9678
10764
|
});
|
|
@@ -9680,7 +10766,7 @@ runtimeCommand.command("stop").description("Stop the local Instafy runtime").opt
|
|
|
9680
10766
|
try {
|
|
9681
10767
|
await runtimeStop({ json: opts.json });
|
|
9682
10768
|
} catch (error) {
|
|
9683
|
-
console.error(
|
|
10769
|
+
console.error(kleur19.red(String(error)));
|
|
9684
10770
|
process.exit(1);
|
|
9685
10771
|
}
|
|
9686
10772
|
});
|
|
@@ -9706,7 +10792,7 @@ runtimeTokenCommand.option("--runtime-id <uuid>", "Runtime ID to bind token to")
|
|
|
9706
10792
|
json: opts.json
|
|
9707
10793
|
});
|
|
9708
10794
|
} catch (error) {
|
|
9709
|
-
console.error(
|
|
10795
|
+
console.error(kleur19.red(String(error)));
|
|
9710
10796
|
process.exit(1);
|
|
9711
10797
|
}
|
|
9712
10798
|
});
|
|
@@ -9728,7 +10814,7 @@ diagnosticsRuntimeEventsCommand.action(async (opts) => {
|
|
|
9728
10814
|
accessToken: opts.accessToken
|
|
9729
10815
|
});
|
|
9730
10816
|
} catch (error) {
|
|
9731
|
-
console.error(
|
|
10817
|
+
console.error(kleur19.red(String(error)));
|
|
9732
10818
|
process.exit(1);
|
|
9733
10819
|
}
|
|
9734
10820
|
});
|
|
@@ -9743,7 +10829,7 @@ diagnosticsRunResultCommand.action(async (runId, opts) => {
|
|
|
9743
10829
|
accessToken: opts.accessToken
|
|
9744
10830
|
});
|
|
9745
10831
|
} catch (error) {
|
|
9746
|
-
console.error(
|
|
10832
|
+
console.error(kleur19.red(String(error)));
|
|
9747
10833
|
process.exit(1);
|
|
9748
10834
|
}
|
|
9749
10835
|
});
|
|
@@ -9777,7 +10863,7 @@ supportReportCommand.action(async (summaryParts, opts) => {
|
|
|
9777
10863
|
json: opts.json
|
|
9778
10864
|
});
|
|
9779
10865
|
} catch (error) {
|
|
9780
|
-
console.error(
|
|
10866
|
+
console.error(kleur19.red(String(error)));
|
|
9781
10867
|
process.exit(1);
|
|
9782
10868
|
}
|
|
9783
10869
|
});
|
|
@@ -9796,7 +10882,7 @@ supportListCommand.action(async (opts) => {
|
|
|
9796
10882
|
json: opts.json
|
|
9797
10883
|
});
|
|
9798
10884
|
} catch (error) {
|
|
9799
|
-
console.error(
|
|
10885
|
+
console.error(kleur19.red(String(error)));
|
|
9800
10886
|
process.exit(1);
|
|
9801
10887
|
}
|
|
9802
10888
|
});
|
|
@@ -9812,7 +10898,7 @@ supportShowCommand.action(async (reportId, opts) => {
|
|
|
9812
10898
|
json: opts.json
|
|
9813
10899
|
});
|
|
9814
10900
|
} catch (error) {
|
|
9815
|
-
console.error(
|
|
10901
|
+
console.error(kleur19.red(String(error)));
|
|
9816
10902
|
process.exit(1);
|
|
9817
10903
|
}
|
|
9818
10904
|
});
|
|
@@ -9857,19 +10943,19 @@ tunnelStartCommand.option("--no-detach", "Run in foreground until interrupted").
|
|
|
9857
10943
|
console.log(JSON.stringify(started, null, 2));
|
|
9858
10944
|
return;
|
|
9859
10945
|
}
|
|
9860
|
-
console.log(
|
|
9861
|
-
console.log(
|
|
9862
|
-
console.log(
|
|
10946
|
+
console.log(kleur19.green(`Tunnel started: ${started.url} (tunnelId=${started.tunnelId})`));
|
|
10947
|
+
console.log(kleur19.gray(`pid=${started.pid} \xB7 port=${started.localPort}`));
|
|
10948
|
+
console.log(kleur19.gray(`log: ${started.logFile}`));
|
|
9863
10949
|
console.log("");
|
|
9864
10950
|
console.log("Next:");
|
|
9865
|
-
console.log(`- ${
|
|
9866
|
-
console.log(`- ${
|
|
9867
|
-
console.log(`- ${
|
|
10951
|
+
console.log(`- ${kleur19.cyan(`instafy tunnel list`)}`);
|
|
10952
|
+
console.log(`- ${kleur19.cyan(`instafy tunnel logs ${started.tunnelId} --follow`)}`);
|
|
10953
|
+
console.log(`- ${kleur19.cyan(`instafy tunnel stop ${started.tunnelId}`)}`);
|
|
9868
10954
|
if (process.platform !== "win32") {
|
|
9869
|
-
console.log(
|
|
10955
|
+
console.log(kleur19.gray(`(or) tail -n 200 -f ${started.logFile}`));
|
|
9870
10956
|
}
|
|
9871
10957
|
} catch (error) {
|
|
9872
|
-
console.error(
|
|
10958
|
+
console.error(kleur19.red(String(error)));
|
|
9873
10959
|
process.exit(1);
|
|
9874
10960
|
}
|
|
9875
10961
|
});
|
|
@@ -9881,14 +10967,14 @@ tunnelCommand.command("list").description("List local tunnel sessions started by
|
|
|
9881
10967
|
return;
|
|
9882
10968
|
}
|
|
9883
10969
|
if (tunnels.length === 0) {
|
|
9884
|
-
console.log(
|
|
10970
|
+
console.log(kleur19.yellow("No tunnels found."));
|
|
9885
10971
|
return;
|
|
9886
10972
|
}
|
|
9887
10973
|
for (const tunnel of tunnels) {
|
|
9888
10974
|
console.log(`${tunnel.tunnelId} \xB7 ${tunnel.url} \xB7 port=${tunnel.localPort} \xB7 pid=${tunnel.pid}`);
|
|
9889
10975
|
}
|
|
9890
10976
|
} catch (error) {
|
|
9891
|
-
console.error(
|
|
10977
|
+
console.error(kleur19.red(String(error)));
|
|
9892
10978
|
process.exit(1);
|
|
9893
10979
|
}
|
|
9894
10980
|
});
|
|
@@ -9904,9 +10990,9 @@ tunnelCommand.command("stop").description("Stop a local tunnel session and revok
|
|
|
9904
10990
|
console.log(JSON.stringify(result, null, 2));
|
|
9905
10991
|
return;
|
|
9906
10992
|
}
|
|
9907
|
-
console.log(
|
|
10993
|
+
console.log(kleur19.green(`Tunnel stopped: ${result.tunnelId}`));
|
|
9908
10994
|
} catch (error) {
|
|
9909
|
-
console.error(
|
|
10995
|
+
console.error(kleur19.red(String(error)));
|
|
9910
10996
|
process.exit(1);
|
|
9911
10997
|
}
|
|
9912
10998
|
});
|
|
@@ -9920,7 +11006,7 @@ tunnelCommand.command("logs").description("Show logs for a local tunnel session"
|
|
|
9920
11006
|
json: Boolean(opts.json)
|
|
9921
11007
|
});
|
|
9922
11008
|
} catch (error) {
|
|
9923
|
-
console.error(
|
|
11009
|
+
console.error(kleur19.red(String(error)));
|
|
9924
11010
|
process.exit(1);
|
|
9925
11011
|
}
|
|
9926
11012
|
});
|
|
@@ -9936,7 +11022,158 @@ orgListCommand.option("--access-token <token>", "Instafy or Supabase access toke
|
|
|
9936
11022
|
json: opts.json
|
|
9937
11023
|
});
|
|
9938
11024
|
} catch (error) {
|
|
9939
|
-
console.error(
|
|
11025
|
+
console.error(kleur19.red(String(error)));
|
|
11026
|
+
process.exit(1);
|
|
11027
|
+
}
|
|
11028
|
+
});
|
|
11029
|
+
function teamScopeCommandFactory(nameAndArgs, description) {
|
|
11030
|
+
const command = orgCommand.command(nameAndArgs).description(description);
|
|
11031
|
+
addServerUrlOptions(command);
|
|
11032
|
+
addAccessTokenOptions(command, "Instafy access token");
|
|
11033
|
+
command.option("--team-id <team>", "Team id (UUID) or slug (defaults to your only team)").option("--json", "Output JSON");
|
|
11034
|
+
return command;
|
|
11035
|
+
}
|
|
11036
|
+
var teamMembersCommand = teamScopeCommandFactory("members", "List members of a team");
|
|
11037
|
+
teamMembersCommand.action(async (opts) => {
|
|
11038
|
+
try {
|
|
11039
|
+
await teamMembersList({
|
|
11040
|
+
teamId: opts.teamId,
|
|
11041
|
+
controllerUrl: opts.serverUrl,
|
|
11042
|
+
accessToken: opts.accessToken,
|
|
11043
|
+
json: opts.json
|
|
11044
|
+
});
|
|
11045
|
+
} catch (error) {
|
|
11046
|
+
console.error(kleur19.red(String(error)));
|
|
11047
|
+
process.exit(1);
|
|
11048
|
+
}
|
|
11049
|
+
});
|
|
11050
|
+
var teamInviteCommand = teamScopeCommandFactory(
|
|
11051
|
+
"invite <email>",
|
|
11052
|
+
"Invite a teammate by email (they must sign in with that email to accept)"
|
|
11053
|
+
);
|
|
11054
|
+
teamInviteCommand.option("--role <role>", "owner, admin, builder, or viewer (default: builder)").action(async (email, opts) => {
|
|
11055
|
+
try {
|
|
11056
|
+
await teamInvite({
|
|
11057
|
+
email,
|
|
11058
|
+
role: opts.role,
|
|
11059
|
+
teamId: opts.teamId,
|
|
11060
|
+
controllerUrl: opts.serverUrl,
|
|
11061
|
+
accessToken: opts.accessToken,
|
|
11062
|
+
json: opts.json
|
|
11063
|
+
});
|
|
11064
|
+
} catch (error) {
|
|
11065
|
+
console.error(kleur19.red(String(error)));
|
|
11066
|
+
process.exit(1);
|
|
11067
|
+
}
|
|
11068
|
+
});
|
|
11069
|
+
var teamInviteLinkCommand = teamScopeCommandFactory(
|
|
11070
|
+
"invite-link",
|
|
11071
|
+
"Create a shareable invite link that works with any sign-in method"
|
|
11072
|
+
);
|
|
11073
|
+
teamInviteLinkCommand.option("--role <role>", "builder or viewer (default: builder)").option("--studio-url <url>", "Studio base URL for the accept link (default: https://instafy.dev)").action(async (opts) => {
|
|
11074
|
+
try {
|
|
11075
|
+
await teamInviteLink({
|
|
11076
|
+
role: opts.role,
|
|
11077
|
+
studioUrl: opts.studioUrl,
|
|
11078
|
+
teamId: opts.teamId,
|
|
11079
|
+
controllerUrl: opts.serverUrl,
|
|
11080
|
+
accessToken: opts.accessToken,
|
|
11081
|
+
json: opts.json
|
|
11082
|
+
});
|
|
11083
|
+
} catch (error) {
|
|
11084
|
+
console.error(kleur19.red(String(error)));
|
|
11085
|
+
process.exit(1);
|
|
11086
|
+
}
|
|
11087
|
+
});
|
|
11088
|
+
var teamInvitesCommand = teamScopeCommandFactory(
|
|
11089
|
+
"invites",
|
|
11090
|
+
"List pending email invitations and invite links"
|
|
11091
|
+
);
|
|
11092
|
+
teamInvitesCommand.action(async (opts) => {
|
|
11093
|
+
try {
|
|
11094
|
+
await teamInvites({
|
|
11095
|
+
teamId: opts.teamId,
|
|
11096
|
+
controllerUrl: opts.serverUrl,
|
|
11097
|
+
accessToken: opts.accessToken,
|
|
11098
|
+
json: opts.json
|
|
11099
|
+
});
|
|
11100
|
+
} catch (error) {
|
|
11101
|
+
console.error(kleur19.red(String(error)));
|
|
11102
|
+
process.exit(1);
|
|
11103
|
+
}
|
|
11104
|
+
});
|
|
11105
|
+
var teamAddMemberCommand = teamScopeCommandFactory(
|
|
11106
|
+
"add-member",
|
|
11107
|
+
"Add an existing Instafy account to a team by user id"
|
|
11108
|
+
);
|
|
11109
|
+
teamAddMemberCommand.requiredOption("--user-id <uuid>", "User id of an existing Instafy account").option("--role <role>", "owner, admin, builder, or viewer (default: builder)").action(async (opts) => {
|
|
11110
|
+
try {
|
|
11111
|
+
await teamAddMember({
|
|
11112
|
+
userId: opts.userId,
|
|
11113
|
+
role: opts.role,
|
|
11114
|
+
teamId: opts.teamId,
|
|
11115
|
+
controllerUrl: opts.serverUrl,
|
|
11116
|
+
accessToken: opts.accessToken,
|
|
11117
|
+
json: opts.json
|
|
11118
|
+
});
|
|
11119
|
+
} catch (error) {
|
|
11120
|
+
console.error(kleur19.red(String(error)));
|
|
11121
|
+
process.exit(1);
|
|
11122
|
+
}
|
|
11123
|
+
});
|
|
11124
|
+
var teamAcceptCommand = teamScopeCommandFactory(
|
|
11125
|
+
"accept <token>",
|
|
11126
|
+
"Accept a team invitation or invite link with the current account"
|
|
11127
|
+
);
|
|
11128
|
+
teamAcceptCommand.action(async (token, opts) => {
|
|
11129
|
+
try {
|
|
11130
|
+
await teamAccept({
|
|
11131
|
+
token,
|
|
11132
|
+
teamId: opts.teamId,
|
|
11133
|
+
controllerUrl: opts.serverUrl,
|
|
11134
|
+
accessToken: opts.accessToken,
|
|
11135
|
+
json: opts.json
|
|
11136
|
+
});
|
|
11137
|
+
} catch (error) {
|
|
11138
|
+
console.error(kleur19.red(String(error)));
|
|
11139
|
+
process.exit(1);
|
|
11140
|
+
}
|
|
11141
|
+
});
|
|
11142
|
+
var teamRevokeInviteCommand = teamScopeCommandFactory(
|
|
11143
|
+
"revoke-invite <invitation-id>",
|
|
11144
|
+
"Revoke a pending email invitation"
|
|
11145
|
+
);
|
|
11146
|
+
teamRevokeInviteCommand.option("--yes", "Skip the confirmation prompt").action(async (invitationId, opts) => {
|
|
11147
|
+
try {
|
|
11148
|
+
await teamRevokeInvite({
|
|
11149
|
+
invitationId,
|
|
11150
|
+
yes: opts.yes,
|
|
11151
|
+
teamId: opts.teamId,
|
|
11152
|
+
controllerUrl: opts.serverUrl,
|
|
11153
|
+
accessToken: opts.accessToken,
|
|
11154
|
+
json: opts.json
|
|
11155
|
+
});
|
|
11156
|
+
} catch (error) {
|
|
11157
|
+
console.error(kleur19.red(String(error)));
|
|
11158
|
+
process.exit(1);
|
|
11159
|
+
}
|
|
11160
|
+
});
|
|
11161
|
+
var teamRevokeLinkCommand = teamScopeCommandFactory(
|
|
11162
|
+
"revoke-link <invite-link-id>",
|
|
11163
|
+
"Revoke a shareable invite link"
|
|
11164
|
+
);
|
|
11165
|
+
teamRevokeLinkCommand.option("--yes", "Skip the confirmation prompt").action(async (inviteLinkId, opts) => {
|
|
11166
|
+
try {
|
|
11167
|
+
await teamRevokeLink({
|
|
11168
|
+
inviteLinkId,
|
|
11169
|
+
yes: opts.yes,
|
|
11170
|
+
teamId: opts.teamId,
|
|
11171
|
+
controllerUrl: opts.serverUrl,
|
|
11172
|
+
accessToken: opts.accessToken,
|
|
11173
|
+
json: opts.json
|
|
11174
|
+
});
|
|
11175
|
+
} catch (error) {
|
|
11176
|
+
console.error(kleur19.red(String(error)));
|
|
9940
11177
|
process.exit(1);
|
|
9941
11178
|
}
|
|
9942
11179
|
});
|
|
@@ -9961,17 +11198,17 @@ profileCommand.command("list").description("List saved CLI profiles").option("--
|
|
|
9961
11198
|
return;
|
|
9962
11199
|
}
|
|
9963
11200
|
if (profiles.length === 0) {
|
|
9964
|
-
console.log(
|
|
9965
|
-
console.log(`Create one with: ${
|
|
11201
|
+
console.log(kleur19.yellow("No profiles found."));
|
|
11202
|
+
console.log(`Create one with: ${kleur19.cyan("instafy login --profile <name>")}`);
|
|
9966
11203
|
return;
|
|
9967
11204
|
}
|
|
9968
|
-
console.log(
|
|
11205
|
+
console.log(kleur19.green("Instafy CLI profiles"));
|
|
9969
11206
|
for (const profile of profiles) {
|
|
9970
|
-
const token = profile.accessTokenSet ?
|
|
9971
|
-
console.log(`- ${
|
|
11207
|
+
const token = profile.accessTokenSet ? kleur19.green("token") : kleur19.yellow("no-token");
|
|
11208
|
+
console.log(`- ${kleur19.cyan(profile.name)} (${token})`);
|
|
9972
11209
|
}
|
|
9973
11210
|
} catch (error) {
|
|
9974
|
-
console.error(
|
|
11211
|
+
console.error(kleur19.red(String(error)));
|
|
9975
11212
|
process.exit(1);
|
|
9976
11213
|
}
|
|
9977
11214
|
});
|
|
@@ -9991,7 +11228,7 @@ historyMessagesCommand.option("--limit <n>", "Max messages to return (1-200, def
|
|
|
9991
11228
|
pretty: opts.pretty
|
|
9992
11229
|
});
|
|
9993
11230
|
} catch (error) {
|
|
9994
|
-
console.error(
|
|
11231
|
+
console.error(kleur19.red(String(error)));
|
|
9995
11232
|
process.exit(1);
|
|
9996
11233
|
}
|
|
9997
11234
|
});
|
|
@@ -10008,7 +11245,7 @@ historyRunsCommand.option("--limit <n>", "Max runs to return (1-200, default: 50
|
|
|
10008
11245
|
pretty: opts.pretty
|
|
10009
11246
|
});
|
|
10010
11247
|
} catch (error) {
|
|
10011
|
-
console.error(
|
|
11248
|
+
console.error(kleur19.red(String(error)));
|
|
10012
11249
|
process.exit(1);
|
|
10013
11250
|
}
|
|
10014
11251
|
});
|
|
@@ -10025,7 +11262,7 @@ historyConversationsCommand.option("--limit <n>", "Max conversations to return (
|
|
|
10025
11262
|
pretty: opts.pretty
|
|
10026
11263
|
});
|
|
10027
11264
|
} catch (error) {
|
|
10028
|
-
console.error(
|
|
11265
|
+
console.error(kleur19.red(String(error)));
|
|
10029
11266
|
process.exit(1);
|
|
10030
11267
|
}
|
|
10031
11268
|
});
|
|
@@ -10046,7 +11283,7 @@ conversationCreateCommand.action(async (opts) => {
|
|
|
10046
11283
|
json: opts.json
|
|
10047
11284
|
});
|
|
10048
11285
|
} catch (error) {
|
|
10049
|
-
console.error(
|
|
11286
|
+
console.error(kleur19.red(String(error)));
|
|
10050
11287
|
process.exit(1);
|
|
10051
11288
|
}
|
|
10052
11289
|
});
|
|
@@ -10064,7 +11301,7 @@ conversationListCommand.action(async (opts) => {
|
|
|
10064
11301
|
json: opts.json
|
|
10065
11302
|
});
|
|
10066
11303
|
} catch (error) {
|
|
10067
|
-
console.error(
|
|
11304
|
+
console.error(kleur19.red(String(error)));
|
|
10068
11305
|
process.exit(1);
|
|
10069
11306
|
}
|
|
10070
11307
|
});
|
|
@@ -10083,7 +11320,7 @@ conversationSearchCommand.action(async (queryParts, opts) => {
|
|
|
10083
11320
|
json: opts.json
|
|
10084
11321
|
});
|
|
10085
11322
|
} catch (error) {
|
|
10086
|
-
console.error(
|
|
11323
|
+
console.error(kleur19.red(String(error)));
|
|
10087
11324
|
process.exit(1);
|
|
10088
11325
|
}
|
|
10089
11326
|
});
|
|
@@ -10102,7 +11339,7 @@ conversationShowCommand.action(async (targetParts, opts) => {
|
|
|
10102
11339
|
json: opts.json
|
|
10103
11340
|
});
|
|
10104
11341
|
} catch (error) {
|
|
10105
|
-
console.error(
|
|
11342
|
+
console.error(kleur19.red(String(error)));
|
|
10106
11343
|
process.exit(1);
|
|
10107
11344
|
}
|
|
10108
11345
|
});
|