@craftspace/cli 0.4.2 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +278 -254
- package/dist/machine.d.ts +2 -1
- package/dist/machine.js +88 -11
- package/dist/probe.d.ts +0 -1
- package/dist/probe.js +3 -66
- package/dist/setup.d.ts +4 -5
- package/dist/setup.js +32 -81
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -4632,8 +4632,8 @@ var BIGINT_FORMAT_RANGES = {
|
|
|
4632
4632
|
};
|
|
4633
4633
|
function pick(schema, mask) {
|
|
4634
4634
|
const currDef = schema._zod.def;
|
|
4635
|
-
const
|
|
4636
|
-
const hasChecks =
|
|
4635
|
+
const checks2 = currDef.checks;
|
|
4636
|
+
const hasChecks = checks2 && checks2.length > 0;
|
|
4637
4637
|
if (hasChecks) {
|
|
4638
4638
|
throw new Error(".pick() cannot be used on object schemas containing refinements");
|
|
4639
4639
|
}
|
|
@@ -4657,8 +4657,8 @@ function pick(schema, mask) {
|
|
|
4657
4657
|
}
|
|
4658
4658
|
function omit(schema, mask) {
|
|
4659
4659
|
const currDef = schema._zod.def;
|
|
4660
|
-
const
|
|
4661
|
-
const hasChecks =
|
|
4660
|
+
const checks2 = currDef.checks;
|
|
4661
|
+
const hasChecks = checks2 && checks2.length > 0;
|
|
4662
4662
|
if (hasChecks) {
|
|
4663
4663
|
throw new Error(".omit() cannot be used on object schemas containing refinements");
|
|
4664
4664
|
}
|
|
@@ -4684,8 +4684,8 @@ function extend(schema, shape) {
|
|
|
4684
4684
|
if (!isPlainObject(shape)) {
|
|
4685
4685
|
throw new Error("Invalid input to extend: expected a plain object");
|
|
4686
4686
|
}
|
|
4687
|
-
const
|
|
4688
|
-
const hasChecks =
|
|
4687
|
+
const checks2 = schema._zod.def.checks;
|
|
4688
|
+
const hasChecks = checks2 && checks2.length > 0;
|
|
4689
4689
|
if (hasChecks) {
|
|
4690
4690
|
const existingShape = schema._zod.def.shape;
|
|
4691
4691
|
for (const key in shape) {
|
|
@@ -4735,8 +4735,8 @@ function merge(a, b) {
|
|
|
4735
4735
|
}
|
|
4736
4736
|
function partial(Class2, schema, mask) {
|
|
4737
4737
|
const currDef = schema._zod.def;
|
|
4738
|
-
const
|
|
4739
|
-
const hasChecks =
|
|
4738
|
+
const checks2 = currDef.checks;
|
|
4739
|
+
const hasChecks = checks2 && checks2.length > 0;
|
|
4740
4740
|
if (hasChecks) {
|
|
4741
4741
|
throw new Error(".partial() cannot be used on object schemas containing refinements");
|
|
4742
4742
|
}
|
|
@@ -5238,10 +5238,10 @@ var nanoid = /^[a-zA-Z0-9_-]{21}$/;
|
|
|
5238
5238
|
var duration = /^P(?:(\d+W)|(?!.*W)(?=\d|T\d)(\d+Y)?(\d+M)?(\d+D)?(T(?=\d)(\d+H)?(\d+M)?(\d+([.,]\d+)?S)?)?)$/;
|
|
5239
5239
|
var extendedDuration = /^[-+]?P(?!$)(?:(?:[-+]?\d+Y)|(?:[-+]?\d+[.,]\d+Y$))?(?:(?:[-+]?\d+M)|(?:[-+]?\d+[.,]\d+M$))?(?:(?:[-+]?\d+W)|(?:[-+]?\d+[.,]\d+W$))?(?:(?:[-+]?\d+D)|(?:[-+]?\d+[.,]\d+D$))?(?:T(?=[\d+-])(?:(?:[-+]?\d+H)|(?:[-+]?\d+[.,]\d+H$))?(?:(?:[-+]?\d+M)|(?:[-+]?\d+[.,]\d+M$))?(?:[-+]?\d+(?:[.,]\d+)?S)?)??$/;
|
|
5240
5240
|
var guid = /^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$/;
|
|
5241
|
-
var uuid = (
|
|
5242
|
-
if (!
|
|
5241
|
+
var uuid = (version2) => {
|
|
5242
|
+
if (!version2)
|
|
5243
5243
|
return /^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$/;
|
|
5244
|
-
return new RegExp(`^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-${
|
|
5244
|
+
return new RegExp(`^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-${version2}[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$`);
|
|
5245
5245
|
};
|
|
5246
5246
|
var uuid4 = /* @__PURE__ */ uuid(4);
|
|
5247
5247
|
var uuid6 = /* @__PURE__ */ uuid(6);
|
|
@@ -5923,25 +5923,25 @@ var $ZodType = /* @__PURE__ */ $constructor("$ZodType", (inst, def) => {
|
|
|
5923
5923
|
inst._zod.def = def;
|
|
5924
5924
|
inst._zod.bag = inst._zod.bag || {};
|
|
5925
5925
|
inst._zod.version = version;
|
|
5926
|
-
const
|
|
5926
|
+
const checks2 = [...inst._zod.def.checks ?? []];
|
|
5927
5927
|
if (inst._zod.traits.has("$ZodCheck")) {
|
|
5928
|
-
|
|
5928
|
+
checks2.unshift(inst);
|
|
5929
5929
|
}
|
|
5930
|
-
for (const ch of
|
|
5930
|
+
for (const ch of checks2) {
|
|
5931
5931
|
for (const fn of ch._zod.onattach) {
|
|
5932
5932
|
fn(inst);
|
|
5933
5933
|
}
|
|
5934
5934
|
}
|
|
5935
|
-
if (
|
|
5935
|
+
if (checks2.length === 0) {
|
|
5936
5936
|
(_a3 = inst._zod).deferred ?? (_a3.deferred = []);
|
|
5937
5937
|
inst._zod.deferred?.push(() => {
|
|
5938
5938
|
inst._zod.run = inst._zod.parse;
|
|
5939
5939
|
});
|
|
5940
5940
|
} else {
|
|
5941
|
-
const runChecks = (payload,
|
|
5941
|
+
const runChecks = (payload, checks3, ctx) => {
|
|
5942
5942
|
let isAborted = aborted(payload);
|
|
5943
5943
|
let asyncResult;
|
|
5944
|
-
for (const ch of
|
|
5944
|
+
for (const ch of checks3) {
|
|
5945
5945
|
if (ch._zod.def.when) {
|
|
5946
5946
|
if (explicitlyAborted(payload))
|
|
5947
5947
|
continue;
|
|
@@ -5985,7 +5985,7 @@ var $ZodType = /* @__PURE__ */ $constructor("$ZodType", (inst, def) => {
|
|
|
5985
5985
|
canary.aborted = true;
|
|
5986
5986
|
return canary;
|
|
5987
5987
|
}
|
|
5988
|
-
const checkResult = runChecks(payload,
|
|
5988
|
+
const checkResult = runChecks(payload, checks2, ctx);
|
|
5989
5989
|
if (checkResult instanceof Promise) {
|
|
5990
5990
|
if (ctx.async === false)
|
|
5991
5991
|
throw new $ZodAsyncError();
|
|
@@ -6010,9 +6010,9 @@ var $ZodType = /* @__PURE__ */ $constructor("$ZodType", (inst, def) => {
|
|
|
6010
6010
|
if (result instanceof Promise) {
|
|
6011
6011
|
if (ctx.async === false)
|
|
6012
6012
|
throw new $ZodAsyncError();
|
|
6013
|
-
return result.then((result2) => runChecks(result2,
|
|
6013
|
+
return result.then((result2) => runChecks(result2, checks2, ctx));
|
|
6014
6014
|
}
|
|
6015
|
-
return runChecks(result,
|
|
6015
|
+
return runChecks(result, checks2, ctx);
|
|
6016
6016
|
};
|
|
6017
6017
|
}
|
|
6018
6018
|
defineLazy(inst, "~standard", () => ({
|
|
@@ -18117,10 +18117,10 @@ function fromJSONSchema(schema, params) {
|
|
|
18117
18117
|
} catch {
|
|
18118
18118
|
throw new Error("fromJSONSchema input is not valid JSON (possibly cyclic); use $defs/$ref for recursive schemas");
|
|
18119
18119
|
}
|
|
18120
|
-
const
|
|
18120
|
+
const version2 = detectVersion(normalized, params?.defaultTarget);
|
|
18121
18121
|
const defs = normalized.$defs || normalized.definitions || {};
|
|
18122
18122
|
const ctx = {
|
|
18123
|
-
version:
|
|
18123
|
+
version: version2,
|
|
18124
18124
|
defs,
|
|
18125
18125
|
refs: /* @__PURE__ */ new Map(),
|
|
18126
18126
|
processing: /* @__PURE__ */ new Set(),
|
|
@@ -18710,6 +18710,16 @@ var GUS_MODELS = [
|
|
|
18710
18710
|
reasoning: true,
|
|
18711
18711
|
harness: GusHarness.OpenCode
|
|
18712
18712
|
},
|
|
18713
|
+
{
|
|
18714
|
+
id: "deepseek/deepseek-v4.1-flash",
|
|
18715
|
+
label: "DeepSeek V4.1 Flash",
|
|
18716
|
+
blurb: "The V4 Flash refresh. Same pennies, steadier across a long tool run.",
|
|
18717
|
+
inputUsdPerMillion: 0.08,
|
|
18718
|
+
outputUsdPerMillion: 0.18,
|
|
18719
|
+
contextWindow: 1048576,
|
|
18720
|
+
reasoning: true,
|
|
18721
|
+
harness: GusHarness.OpenCode
|
|
18722
|
+
},
|
|
18713
18723
|
{
|
|
18714
18724
|
id: "deepseek/deepseek-v4-pro-0813",
|
|
18715
18725
|
label: "DeepSeek V4 Pro",
|
|
@@ -19310,7 +19320,8 @@ var OAuthCallbackQuerySchema = external_exports.object({
|
|
|
19310
19320
|
});
|
|
19311
19321
|
var ListConnectionsResponseSchema = external_exports.object({
|
|
19312
19322
|
connections: external_exports.array(ConnectionSchema),
|
|
19313
|
-
canManage: external_exports.boolean()
|
|
19323
|
+
canManage: external_exports.boolean(),
|
|
19324
|
+
egressIp: external_exports.string()
|
|
19314
19325
|
});
|
|
19315
19326
|
var CONNECTION_CATEGORIES = [
|
|
19316
19327
|
"Sales & support",
|
|
@@ -19751,6 +19762,10 @@ var GUS_MAX_TURN_MS = 45 * 60 * 1e3;
|
|
|
19751
19762
|
// ../../shared/dist/gus/workstation.js
|
|
19752
19763
|
var WORKSTATION_CORES = 2;
|
|
19753
19764
|
var WORKSTATION_RECIPE_MAX_CHARS = 8e3;
|
|
19765
|
+
var WORKSTATION_MAX_STEPS = 20;
|
|
19766
|
+
var WORKSTATION_STEP_NAME_MAX_CHARS = 60;
|
|
19767
|
+
var WORKSTATION_STEP_DETAIL_MAX_CHARS = 600;
|
|
19768
|
+
var WORKSTATION_MAX_REPOS = 20;
|
|
19754
19769
|
var WORKSTATION_ALLOWLIST_MAX_HOSTS = 50;
|
|
19755
19770
|
var WORKSTATION_HOST_MAX_CHARS = 200;
|
|
19756
19771
|
var SANDBOX_BROWSERS_PATH = "/vercel/sandbox/.cache/ms-playwright";
|
|
@@ -19762,14 +19777,53 @@ var WORKSTATION_SPECS = {
|
|
|
19762
19777
|
};
|
|
19763
19778
|
var PLAYWRIGHT_VERSION = "1.49.1";
|
|
19764
19779
|
var WORKSTATION_BASE_RECIPE = [
|
|
19765
|
-
"# Craftspace base
|
|
19780
|
+
"# Craftspace base v3: a headless browser, ready to use.",
|
|
19781
|
+
`export PLAYWRIGHT_BROWSERS_PATH=${SANDBOX_BROWSERS_PATH}`,
|
|
19766
19782
|
"sudo dnf install -y nss nspr atk at-spi2-atk at-spi2-core cups-libs libdrm libxkbcommon \\",
|
|
19767
19783
|
" libXcomposite libXdamage libXrandr libXfixes libXrender mesa-libgbm pango alsa-lib >/dev/null",
|
|
19768
|
-
`
|
|
19784
|
+
`npx --yes playwright@${PLAYWRIGHT_VERSION} install chromium`
|
|
19769
19785
|
].join("\n");
|
|
19770
19786
|
var HostSchema = external_exports.string().trim().min(1).max(WORKSTATION_HOST_MAX_CHARS).regex(/^[A-Za-z0-9*._:-]+$/, "A host is a domain, optionally with a leading *. and a :port.");
|
|
19787
|
+
var WorkstationStepSchema = external_exports.object({
|
|
19788
|
+
id: external_exports.string().min(1).max(64),
|
|
19789
|
+
name: external_exports.string().trim().min(1).max(WORKSTATION_STEP_NAME_MAX_CHARS),
|
|
19790
|
+
script: external_exports.string().max(WORKSTATION_RECIPE_MAX_CHARS)
|
|
19791
|
+
});
|
|
19792
|
+
var WorkstationRepoSchema = external_exports.object({
|
|
19793
|
+
name: external_exports.string().trim().min(3).max(200).regex(/^[A-Za-z0-9._-]+\/[A-Za-z0-9._-]+$/, "A repo is owner/name."),
|
|
19794
|
+
ref: external_exports.string().trim().min(1).max(200)
|
|
19795
|
+
});
|
|
19796
|
+
var WORKSTATION_SEED_STEPS = [
|
|
19797
|
+
{ id: "step_claude_code", name: "Claude Code", script: "npm install -g @anthropic-ai/claude-code" },
|
|
19798
|
+
{ id: "step_codex", name: "Codex", script: "npm install -g @openai/codex" },
|
|
19799
|
+
{
|
|
19800
|
+
id: "step_github_cli",
|
|
19801
|
+
name: "GitHub CLI",
|
|
19802
|
+
script: [
|
|
19803
|
+
"if command -v gh >/dev/null; then exit 0; fi",
|
|
19804
|
+
"if command -v brew >/dev/null; then brew install gh",
|
|
19805
|
+
"elif command -v dnf >/dev/null; then sudo -n dnf install -y gh",
|
|
19806
|
+
"elif command -v apt-get >/dev/null; then sudo -n apt-get install -y gh",
|
|
19807
|
+
'else echo "no package manager here, install the GitHub CLI by hand" >&2; exit 1',
|
|
19808
|
+
"fi"
|
|
19809
|
+
].join("\n")
|
|
19810
|
+
},
|
|
19811
|
+
{
|
|
19812
|
+
id: "step_chrome",
|
|
19813
|
+
name: "Chrome for Playwright",
|
|
19814
|
+
script: `npx --yes playwright@${PLAYWRIGHT_VERSION} install chromium`
|
|
19815
|
+
}
|
|
19816
|
+
];
|
|
19817
|
+
var WorkstationStepResultSchema = external_exports.object({
|
|
19818
|
+
id: external_exports.string().min(1).max(64),
|
|
19819
|
+
name: external_exports.string().max(WORKSTATION_STEP_NAME_MAX_CHARS),
|
|
19820
|
+
ok: external_exports.boolean(),
|
|
19821
|
+
detail: external_exports.string().max(WORKSTATION_STEP_DETAIL_MAX_CHARS),
|
|
19822
|
+
ms: external_exports.number().int().nonnegative()
|
|
19823
|
+
});
|
|
19771
19824
|
var WorkstationSchema = external_exports.object({
|
|
19772
|
-
|
|
19825
|
+
steps: external_exports.array(WorkstationStepSchema),
|
|
19826
|
+
repos: external_exports.array(WorkstationRepoSchema),
|
|
19773
19827
|
allowlist: external_exports.array(external_exports.string()),
|
|
19774
19828
|
templateId: external_exports.string().nullable(),
|
|
19775
19829
|
publicKey: external_exports.string(),
|
|
@@ -19777,13 +19831,14 @@ var WorkstationSchema = external_exports.object({
|
|
|
19777
19831
|
updatedByName: external_exports.string().nullable()
|
|
19778
19832
|
});
|
|
19779
19833
|
var SaveWorkstationBodySchema = external_exports.object({
|
|
19780
|
-
|
|
19834
|
+
steps: external_exports.array(WorkstationStepSchema).max(WORKSTATION_MAX_STEPS),
|
|
19835
|
+
repos: external_exports.array(WorkstationRepoSchema).max(WORKSTATION_MAX_REPOS),
|
|
19781
19836
|
allowlist: external_exports.array(HostSchema).max(WORKSTATION_ALLOWLIST_MAX_HOSTS)
|
|
19782
19837
|
});
|
|
19783
19838
|
var WorkstationResponseSchema = external_exports.object({ workstation: WorkstationSchema });
|
|
19784
19839
|
|
|
19785
19840
|
// ../../shared/dist/machines/machine.js
|
|
19786
|
-
var CLI_VERSION = "0.
|
|
19841
|
+
var CLI_VERSION = "0.5.0";
|
|
19787
19842
|
var CLI_PACKAGE = "@craftspace/cli";
|
|
19788
19843
|
var CLI_INSTALL = `npm i -g ${CLI_PACKAGE}`;
|
|
19789
19844
|
var MACHINE_BEAT_INTERVAL_MS = 15e3;
|
|
@@ -19804,7 +19859,7 @@ var MachineAuthorizedKeySchema = external_exports.object({
|
|
|
19804
19859
|
addedByName: external_exports.string(),
|
|
19805
19860
|
addedAt: external_exports.coerce.date()
|
|
19806
19861
|
});
|
|
19807
|
-
var MACHINE_TOOLS = ["brain", "
|
|
19862
|
+
var MACHINE_TOOLS = ["brain", "ssh"];
|
|
19808
19863
|
var MachineToolIdSchema = external_exports.enum(MACHINE_TOOLS);
|
|
19809
19864
|
var MachineToolSchema = external_exports.object({
|
|
19810
19865
|
id: MachineToolIdSchema,
|
|
@@ -19832,6 +19887,8 @@ var MachineSchema = external_exports.object({
|
|
|
19832
19887
|
state: MachineStateSchema,
|
|
19833
19888
|
sessions: external_exports.array(MachineSessionSchema),
|
|
19834
19889
|
tools: external_exports.array(MachineToolSchema),
|
|
19890
|
+
environment: external_exports.array(WorkstationStepResultSchema),
|
|
19891
|
+
templateId: external_exports.string().nullable(),
|
|
19835
19892
|
authorizedKeys: external_exports.array(MachineAuthorizedKeySchema),
|
|
19836
19893
|
lastBeatAt: external_exports.coerce.date().nullable(),
|
|
19837
19894
|
lastAskedAt: external_exports.coerce.date().nullable(),
|
|
@@ -19894,12 +19951,19 @@ var MachineBeatBodySchema = external_exports.object({
|
|
|
19894
19951
|
sessions: external_exports.array(MachineSessionSchema).max(50),
|
|
19895
19952
|
runs: external_exports.array(MachineRunReportSchema).max(20).default([]),
|
|
19896
19953
|
tools: external_exports.array(MachineToolSchema).max(10).default([]),
|
|
19954
|
+
environment: external_exports.array(WorkstationStepResultSchema).max(WORKSTATION_MAX_STEPS).default([]),
|
|
19955
|
+
templateId: external_exports.string().max(64).nullable().default(null),
|
|
19897
19956
|
sshUser: external_exports.string().min(1).max(64).optional()
|
|
19898
19957
|
});
|
|
19958
|
+
var MachineEnvironmentSchema = external_exports.object({
|
|
19959
|
+
templateId: external_exports.string().nullable(),
|
|
19960
|
+
steps: external_exports.array(WorkstationStepSchema)
|
|
19961
|
+
});
|
|
19899
19962
|
var MachineBeatResponseSchema = external_exports.object({
|
|
19900
19963
|
cli: external_exports.object({ version: external_exports.string(), url: external_exports.string(), sha256: external_exports.string() }).nullable(),
|
|
19901
19964
|
work: external_exports.array(MachineWorkSchema),
|
|
19902
|
-
authorizedKeys: external_exports.array(external_exports.string())
|
|
19965
|
+
authorizedKeys: external_exports.array(external_exports.string()),
|
|
19966
|
+
environment: MachineEnvironmentSchema
|
|
19903
19967
|
});
|
|
19904
19968
|
var AddMachineKeyBodySchema = external_exports.object({
|
|
19905
19969
|
key: external_exports.string().min(60).max(4e3),
|
|
@@ -20251,11 +20315,11 @@ var MemberActivityListResponse = external_exports.object({
|
|
|
20251
20315
|
});
|
|
20252
20316
|
|
|
20253
20317
|
// dist/machine.js
|
|
20254
|
-
import { execFile as
|
|
20318
|
+
import { execFile as execFile3, spawn as spawn2 } from "node:child_process";
|
|
20255
20319
|
import { mkdir, readFile as readFile2, readdir, rm, writeFile } from "node:fs/promises";
|
|
20256
20320
|
import os5 from "node:os";
|
|
20257
20321
|
import path4 from "node:path";
|
|
20258
|
-
import { promisify as
|
|
20322
|
+
import { promisify as promisify2 } from "node:util";
|
|
20259
20323
|
|
|
20260
20324
|
// ../../../node_modules/@inquirer/core/dist/lib/key.js
|
|
20261
20325
|
var keybindings = ["emacs", "vim"];
|
|
@@ -22121,9 +22185,50 @@ var dist_default6 = createPrompt((config2, done) => {
|
|
|
22121
22185
|
return `${lines}${cursorHide}`;
|
|
22122
22186
|
});
|
|
22123
22187
|
|
|
22188
|
+
// dist/probe.js
|
|
22189
|
+
import net from "node:net";
|
|
22190
|
+
import { readFile } from "node:fs/promises";
|
|
22191
|
+
import os from "node:os";
|
|
22192
|
+
import path2 from "node:path";
|
|
22193
|
+
var probe = {
|
|
22194
|
+
async tools({ mcpPath = path2.join(os.homedir(), ".mcp.json") } = {}) {
|
|
22195
|
+
return Promise.all([brainWired(mcpPath), sshListening()]);
|
|
22196
|
+
}
|
|
22197
|
+
};
|
|
22198
|
+
async function brainWired(mcpPath) {
|
|
22199
|
+
const raw = await readFile(mcpPath, "utf8").catch(() => null);
|
|
22200
|
+
if (raw === null)
|
|
22201
|
+
return { id: "brain", ok: false, detail: `no ${short(mcpPath)} on this machine` };
|
|
22202
|
+
const parsed = JSON.parse(raw);
|
|
22203
|
+
const servers = parsed?.mcpServers;
|
|
22204
|
+
const wired = servers !== void 0 && servers !== null && "craftspace" in servers;
|
|
22205
|
+
return {
|
|
22206
|
+
id: "brain",
|
|
22207
|
+
ok: wired,
|
|
22208
|
+
detail: wired ? short(mcpPath) : `${short(mcpPath)} has no craftspace entry`
|
|
22209
|
+
};
|
|
22210
|
+
}
|
|
22211
|
+
function sshListening() {
|
|
22212
|
+
return new Promise((resolve) => {
|
|
22213
|
+
const socket = net.connect({ host: "127.0.0.1", port: 22 });
|
|
22214
|
+
const answer = (ok, detail) => {
|
|
22215
|
+
socket.destroy();
|
|
22216
|
+
resolve({ id: "ssh", ok, detail });
|
|
22217
|
+
};
|
|
22218
|
+
socket.setTimeout(SSH_PROBE_TIMEOUT_MS);
|
|
22219
|
+
socket.on("connect", () => answer(true, "sshd is listening on port 22"));
|
|
22220
|
+
socket.on("timeout", () => answer(false, "nothing answered on port 22"));
|
|
22221
|
+
socket.on("error", () => answer(false, "sshd is not running, so nobody can open a terminal here"));
|
|
22222
|
+
});
|
|
22223
|
+
}
|
|
22224
|
+
function short(target) {
|
|
22225
|
+
return target.startsWith(os.homedir()) ? `~${target.slice(os.homedir().length)}` : target;
|
|
22226
|
+
}
|
|
22227
|
+
var SSH_PROBE_TIMEOUT_MS = 1500;
|
|
22228
|
+
|
|
22124
22229
|
// dist/run.js
|
|
22125
22230
|
import { spawn } from "node:child_process";
|
|
22126
|
-
import
|
|
22231
|
+
import os2 from "node:os";
|
|
22127
22232
|
var runner = {
|
|
22128
22233
|
attended(argv) {
|
|
22129
22234
|
return new Promise((resolve) => {
|
|
@@ -22162,7 +22267,7 @@ var runner = {
|
|
|
22162
22267
|
const code = await new Promise((resolve) => {
|
|
22163
22268
|
const child = spawn(argv[0], argv.slice(1), {
|
|
22164
22269
|
stdio: ["ignore", "pipe", "pipe"],
|
|
22165
|
-
cwd:
|
|
22270
|
+
cwd: os2.homedir(),
|
|
22166
22271
|
env: {
|
|
22167
22272
|
...process.env,
|
|
22168
22273
|
TERM: process.env.TERM ?? "xterm-256color",
|
|
@@ -22259,112 +22364,9 @@ function parseJson(line) {
|
|
|
22259
22364
|
}
|
|
22260
22365
|
|
|
22261
22366
|
// dist/setup.js
|
|
22262
|
-
import { execFile
|
|
22367
|
+
import { execFile } from "node:child_process";
|
|
22263
22368
|
import os4 from "node:os";
|
|
22264
22369
|
import path3 from "node:path";
|
|
22265
|
-
import { promisify as promisify2 } from "node:util";
|
|
22266
|
-
|
|
22267
|
-
// dist/probe.js
|
|
22268
|
-
import { execFile } from "node:child_process";
|
|
22269
|
-
import net from "node:net";
|
|
22270
|
-
import { access, readFile } from "node:fs/promises";
|
|
22271
|
-
import os2 from "node:os";
|
|
22272
|
-
import path2 from "node:path";
|
|
22273
|
-
import { promisify } from "node:util";
|
|
22274
|
-
var run = promisify(execFile);
|
|
22275
|
-
var probe = {
|
|
22276
|
-
async tools({ mcpPath = path2.join(os2.homedir(), ".mcp.json") } = {}) {
|
|
22277
|
-
const [brain, claude, codex, git, chrome, ssh] = await Promise.all([
|
|
22278
|
-
brainWired(mcpPath),
|
|
22279
|
-
version2({ id: "claude", command: "claude" }),
|
|
22280
|
-
version2({ id: "codex", command: "codex" }),
|
|
22281
|
-
gitAndGithub(),
|
|
22282
|
-
chromeInstalled(),
|
|
22283
|
-
sshListening()
|
|
22284
|
-
]);
|
|
22285
|
-
return [brain, claude, codex, git, chrome, ssh];
|
|
22286
|
-
}
|
|
22287
|
-
};
|
|
22288
|
-
async function brainWired(mcpPath) {
|
|
22289
|
-
const raw = await readFile(mcpPath, "utf8").catch(() => null);
|
|
22290
|
-
if (raw === null)
|
|
22291
|
-
return { id: "brain", ok: false, detail: `no ${short(mcpPath)} on this machine` };
|
|
22292
|
-
const parsed = JSON.parse(raw);
|
|
22293
|
-
const servers = parsed?.mcpServers;
|
|
22294
|
-
const wired = servers !== void 0 && servers !== null && "craftspace" in servers;
|
|
22295
|
-
return {
|
|
22296
|
-
id: "brain",
|
|
22297
|
-
ok: wired,
|
|
22298
|
-
detail: wired ? short(mcpPath) : `${short(mcpPath)} has no craftspace entry`
|
|
22299
|
-
};
|
|
22300
|
-
}
|
|
22301
|
-
async function version2({ id, command }) {
|
|
22302
|
-
const found = await firstLine(command, ["--version"]);
|
|
22303
|
-
if (found.ran)
|
|
22304
|
-
return { id, ok: true, detail: found.line };
|
|
22305
|
-
return { id, ok: false, detail: found.why === "absent" ? "not installed" : "installed, but it will not report a version" };
|
|
22306
|
-
}
|
|
22307
|
-
async function gitAndGithub() {
|
|
22308
|
-
const git = await firstLine("git", ["--version"]);
|
|
22309
|
-
if (!git.ran)
|
|
22310
|
-
return { id: "git", ok: false, detail: "git is not installed" };
|
|
22311
|
-
const gh = await firstLine("gh", ["--version"]);
|
|
22312
|
-
if (!gh.ran)
|
|
22313
|
-
return { id: "git", ok: false, detail: `${git.line} \xB7 the GitHub CLI is not installed yet` };
|
|
22314
|
-
const account = await githubAccount();
|
|
22315
|
-
return {
|
|
22316
|
-
id: "git",
|
|
22317
|
-
ok: account !== null,
|
|
22318
|
-
detail: account === null ? `${git.line} \xB7 ${gh.line}, run gh auth login on this machine` : `${git.line} \xB7 ${gh.line}, signed in as ${account}`
|
|
22319
|
-
};
|
|
22320
|
-
}
|
|
22321
|
-
async function githubAccount() {
|
|
22322
|
-
const raw = await readFile(path2.join(os2.homedir(), ".config", "gh", "hosts.yml"), "utf8").catch(() => null);
|
|
22323
|
-
return raw === null ? null : githubUser(raw);
|
|
22324
|
-
}
|
|
22325
|
-
function githubUser(hostsYml) {
|
|
22326
|
-
return /^ {4}user: *(\S+) *$/m.exec(hostsYml)?.[1] ?? null;
|
|
22327
|
-
}
|
|
22328
|
-
async function chromeInstalled() {
|
|
22329
|
-
for (const command of [...MAC_CHROME, ...LINUX_CHROME]) {
|
|
22330
|
-
const found = await firstLine(command, ["--version"]);
|
|
22331
|
-
if (found.ran)
|
|
22332
|
-
return { id: "chrome", ok: true, detail: found.line };
|
|
22333
|
-
}
|
|
22334
|
-
return { id: "chrome", ok: false, detail: "not installed yet, so browser runs will fail" };
|
|
22335
|
-
}
|
|
22336
|
-
function sshListening() {
|
|
22337
|
-
return new Promise((resolve) => {
|
|
22338
|
-
const socket = net.connect({ host: "127.0.0.1", port: 22 });
|
|
22339
|
-
const answer = (ok, detail) => {
|
|
22340
|
-
socket.destroy();
|
|
22341
|
-
resolve({ id: "ssh", ok, detail });
|
|
22342
|
-
};
|
|
22343
|
-
socket.setTimeout(SSH_PROBE_TIMEOUT_MS);
|
|
22344
|
-
socket.on("connect", () => answer(true, "sshd is listening on port 22"));
|
|
22345
|
-
socket.on("timeout", () => answer(false, "nothing answered on port 22"));
|
|
22346
|
-
socket.on("error", () => answer(false, "sshd is not running, so nobody can ssh in"));
|
|
22347
|
-
});
|
|
22348
|
-
}
|
|
22349
|
-
async function firstLine(command, args) {
|
|
22350
|
-
if (command.includes("/")) {
|
|
22351
|
-
const reachable = await access(command).then(() => true, () => false);
|
|
22352
|
-
if (!reachable)
|
|
22353
|
-
return { ran: false, why: "absent" };
|
|
22354
|
-
}
|
|
22355
|
-
const answer = await run(command, args, { timeout: PROBE_TIMEOUT_MS }).catch((thrown) => thrown);
|
|
22356
|
-
if (answer instanceof Error)
|
|
22357
|
-
return { ran: false, why: answer.code === "ENOENT" ? "absent" : "broken" };
|
|
22358
|
-
const line = answer.stdout.split("\n")[0]?.trim() ?? "";
|
|
22359
|
-
return line === "" ? { ran: false, why: "broken" } : { ran: true, line: line.slice(0, 200) };
|
|
22360
|
-
}
|
|
22361
|
-
function short(target) {
|
|
22362
|
-
return target.startsWith(os2.homedir()) ? `~${target.slice(os2.homedir().length)}` : target;
|
|
22363
|
-
}
|
|
22364
|
-
var MAC_CHROME = ["/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"];
|
|
22365
|
-
var LINUX_CHROME = ["google-chrome", "google-chrome-stable", "chromium"];
|
|
22366
|
-
var PROBE_TIMEOUT_MS = 5e3;
|
|
22367
|
-
var SSH_PROBE_TIMEOUT_MS = 1500;
|
|
22368
22370
|
|
|
22369
22371
|
// node_modules/chalk/source/vendor/ansi-styles/index.js
|
|
22370
22372
|
var ANSI_BACKGROUND_OFFSET = 10;
|
|
@@ -22650,10 +22652,10 @@ function _supportsColor(haveStream, { streamIsTTY, sniffFlags = true } = {}) {
|
|
|
22650
22652
|
return 3;
|
|
22651
22653
|
}
|
|
22652
22654
|
if ("TERM_PROGRAM" in env) {
|
|
22653
|
-
const
|
|
22655
|
+
const version2 = Number.parseInt((env.TERM_PROGRAM_VERSION || "").split(".")[0], 10);
|
|
22654
22656
|
switch (env.TERM_PROGRAM) {
|
|
22655
22657
|
case "iTerm.app": {
|
|
22656
|
-
return
|
|
22658
|
+
return version2 >= 3 ? 3 : 2;
|
|
22657
22659
|
}
|
|
22658
22660
|
case "Apple_Terminal": {
|
|
22659
22661
|
return 2;
|
|
@@ -22929,7 +22931,6 @@ var LABEL_WIDTH = 13;
|
|
|
22929
22931
|
var BAR_CELLS = 10;
|
|
22930
22932
|
|
|
22931
22933
|
// dist/setup.js
|
|
22932
|
-
var run2 = promisify2(execFile2);
|
|
22933
22934
|
var setup = {
|
|
22934
22935
|
widenPath() {
|
|
22935
22936
|
const current = (process.env.PATH ?? "").split(path3.delimiter).filter((entry) => entry !== "");
|
|
@@ -22937,44 +22938,34 @@ var setup = {
|
|
|
22937
22938
|
if (missing.length > 0)
|
|
22938
22939
|
process.env.PATH = [...current, ...missing].join(path3.delimiter);
|
|
22939
22940
|
},
|
|
22940
|
-
async
|
|
22941
|
-
const
|
|
22942
|
-
|
|
22943
|
-
|
|
22944
|
-
|
|
22945
|
-
|
|
22946
|
-
|
|
22947
|
-
|
|
22948
|
-
let ready = 0;
|
|
22949
|
-
for (const [index, tool] of broken.entries()) {
|
|
22950
|
-
const repair = repairs[tool.id];
|
|
22951
|
-
if (repair === void 0)
|
|
22952
|
-
continue;
|
|
22953
|
-
say?.(ui.progress({ name: repair.name, done: index, total: broken.length }));
|
|
22954
|
-
tried.set(tool.id, Date.now());
|
|
22955
|
-
const failed = await repair.fix().then(() => null, (error51) => firstLine2(error51.message));
|
|
22956
|
-
if (failed === null)
|
|
22957
|
-
reasons.delete(tool.id);
|
|
22958
|
-
else
|
|
22959
|
-
reasons.set(tool.id, failed);
|
|
22960
|
-
if (failed === null)
|
|
22961
|
-
ready += 1;
|
|
22962
|
-
say?.(`${ui.clear()}${failed === null ? ui.ok(repair.name) : ui.bad(repair.name, failed)}`);
|
|
22941
|
+
async runSteps({ steps, say }) {
|
|
22942
|
+
const results = [];
|
|
22943
|
+
for (const [index, step] of steps.entries()) {
|
|
22944
|
+
say?.(ui.progress({ name: step.name, done: index, total: steps.length }));
|
|
22945
|
+
const startedAt = Date.now();
|
|
22946
|
+
const outcome = await runScript(step.script);
|
|
22947
|
+
results.push({ ...outcome, id: step.id, name: step.name, ms: Date.now() - startedAt });
|
|
22948
|
+
say?.(`${ui.clear()}${outcome.ok ? ui.ok(step.name) : ui.bad(step.name, outcome.detail)}`);
|
|
22963
22949
|
}
|
|
22964
|
-
|
|
22965
|
-
|
|
22950
|
+
if (results.length > 0) {
|
|
22951
|
+
say?.(ui.tally({ done: results.filter((result) => result.ok).length, total: results.length, noun: "ready" }));
|
|
22952
|
+
}
|
|
22953
|
+
return results;
|
|
22966
22954
|
}
|
|
22967
22955
|
};
|
|
22968
|
-
function
|
|
22969
|
-
|
|
22970
|
-
|
|
22971
|
-
|
|
22972
|
-
|
|
22973
|
-
|
|
22974
|
-
|
|
22975
|
-
|
|
22956
|
+
function runScript(script) {
|
|
22957
|
+
return new Promise((resolve) => {
|
|
22958
|
+
execFile("/bin/sh", ["-e", "-c", script], { timeout: STEP_TIMEOUT_MS, maxBuffer: SCRIPT_BUFFER_BYTES }, (error51, stdout, stderr) => {
|
|
22959
|
+
if (error51 === null)
|
|
22960
|
+
return resolve({ ok: true, detail: lastLines(stdout) });
|
|
22961
|
+
resolve({ ok: false, detail: lastLines(`${stderr}
|
|
22962
|
+
${stdout}`) || error51.message.split("\n")[0] || "it failed" });
|
|
22963
|
+
});
|
|
22976
22964
|
});
|
|
22977
22965
|
}
|
|
22966
|
+
function lastLines(output) {
|
|
22967
|
+
return output.split("\n").map((line) => line.trim()).filter((line) => line !== "").slice(-KEPT_LINES).join(" \xB7 ").slice(0, WORKSTATION_STEP_DETAIL_MAX_CHARS);
|
|
22968
|
+
}
|
|
22978
22969
|
function toolDirs() {
|
|
22979
22970
|
const prefix = process.env.npm_config_prefix;
|
|
22980
22971
|
return [
|
|
@@ -22986,56 +22977,14 @@ function toolDirs() {
|
|
|
22986
22977
|
"/usr/local/bin"
|
|
22987
22978
|
];
|
|
22988
22979
|
}
|
|
22989
|
-
var
|
|
22990
|
-
|
|
22991
|
-
|
|
22992
|
-
git: {
|
|
22993
|
-
name: "the GitHub CLI",
|
|
22994
|
-
fix: async () => {
|
|
22995
|
-
if (await firstAvailable(["gh"]) !== null)
|
|
22996
|
-
return;
|
|
22997
|
-
await installPackage({ brew: ["gh"], apt: ["gh"], dnf: ["gh"] });
|
|
22998
|
-
}
|
|
22999
|
-
},
|
|
23000
|
-
chrome: {
|
|
23001
|
-
name: "Google Chrome",
|
|
23002
|
-
fix: () => installPackage({ brew: ["--cask", "google-chrome"], apt: ["chromium"], dnf: ["chromium"] })
|
|
23003
|
-
}
|
|
23004
|
-
};
|
|
23005
|
-
async function npmGlobal(name) {
|
|
23006
|
-
await run2("npm", ["install", "-g", name], { timeout: INSTALL_TIMEOUT_MS });
|
|
23007
|
-
}
|
|
23008
|
-
async function installPackage({ brew, apt, dnf }) {
|
|
23009
|
-
if (process.platform === "darwin") {
|
|
23010
|
-
await run2("brew", ["install", ...brew], { timeout: INSTALL_TIMEOUT_MS });
|
|
23011
|
-
return;
|
|
23012
|
-
}
|
|
23013
|
-
const manager = await firstAvailable(["apt-get", "dnf"]);
|
|
23014
|
-
if (manager === null)
|
|
23015
|
-
throw new Error("no package manager this CLI knows how to drive");
|
|
23016
|
-
const packages = manager === "apt-get" ? apt : dnf;
|
|
23017
|
-
await run2("sudo", ["-n", manager, "install", "-y", ...packages], { timeout: INSTALL_TIMEOUT_MS });
|
|
23018
|
-
}
|
|
23019
|
-
async function firstAvailable(commands) {
|
|
23020
|
-
for (const command of commands) {
|
|
23021
|
-
const there = await run2("/bin/sh", ["-c", `command -v ${command}`]).then(() => true, () => false);
|
|
23022
|
-
if (there)
|
|
23023
|
-
return command;
|
|
23024
|
-
}
|
|
23025
|
-
return null;
|
|
23026
|
-
}
|
|
23027
|
-
function firstLine2(message) {
|
|
23028
|
-
return message.split("\n")[0] ?? "it failed";
|
|
23029
|
-
}
|
|
23030
|
-
var tried = /* @__PURE__ */ new Map();
|
|
23031
|
-
var reasons = /* @__PURE__ */ new Map();
|
|
23032
|
-
var INSTALL_TIMEOUT_MS = 18e4;
|
|
23033
|
-
var RETRY_AFTER_MS = 216e5;
|
|
22980
|
+
var STEP_TIMEOUT_MS = 6e5;
|
|
22981
|
+
var SCRIPT_BUFFER_BYTES = 4 * 1024 * 1024;
|
|
22982
|
+
var KEPT_LINES = 3;
|
|
23034
22983
|
|
|
23035
22984
|
// dist/update.js
|
|
23036
|
-
import { execFile as
|
|
23037
|
-
import { promisify
|
|
23038
|
-
var
|
|
22985
|
+
import { execFile as execFile2 } from "node:child_process";
|
|
22986
|
+
import { promisify } from "node:util";
|
|
22987
|
+
var run = promisify(execFile2);
|
|
23039
22988
|
var update = {
|
|
23040
22989
|
async latest() {
|
|
23041
22990
|
const answer = await fetch(`${REGISTRY}/${CLI_PACKAGE}/latest`, {
|
|
@@ -23045,17 +22994,17 @@ var update = {
|
|
|
23045
22994
|
if (answer === null || !answer.ok)
|
|
23046
22995
|
return null;
|
|
23047
22996
|
const body = await answer.json().catch(() => null);
|
|
23048
|
-
const
|
|
23049
|
-
return typeof
|
|
22997
|
+
const version2 = isRecord(body) ? body.version : void 0;
|
|
22998
|
+
return typeof version2 === "string" && isNewer(version2) ? version2 : null;
|
|
23050
22999
|
},
|
|
23051
23000
|
async toLatest() {
|
|
23052
|
-
const
|
|
23053
|
-
if (
|
|
23001
|
+
const version2 = await update.latest();
|
|
23002
|
+
if (version2 === null)
|
|
23054
23003
|
return null;
|
|
23055
|
-
const installed = await
|
|
23056
|
-
timeout:
|
|
23004
|
+
const installed = await run("npm", ["install", "--global", "--no-fund", `${CLI_PACKAGE}@${version2}`], {
|
|
23005
|
+
timeout: INSTALL_TIMEOUT_MS
|
|
23057
23006
|
}).then(() => true, () => false);
|
|
23058
|
-
return installed ?
|
|
23007
|
+
return installed ? version2 : null;
|
|
23059
23008
|
}
|
|
23060
23009
|
};
|
|
23061
23010
|
function isNewer(candidate, current = CLI_VERSION) {
|
|
@@ -23069,18 +23018,18 @@ function isNewer(candidate, current = CLI_VERSION) {
|
|
|
23069
23018
|
}
|
|
23070
23019
|
return false;
|
|
23071
23020
|
}
|
|
23072
|
-
function parts(
|
|
23073
|
-
return (/^\d+\.\d+\.\d+/.exec(
|
|
23021
|
+
function parts(version2) {
|
|
23022
|
+
return (/^\d+\.\d+\.\d+/.exec(version2.trim())?.[0] ?? "").split(".").map(Number);
|
|
23074
23023
|
}
|
|
23075
23024
|
function isRecord(value) {
|
|
23076
23025
|
return typeof value === "object" && value !== null;
|
|
23077
23026
|
}
|
|
23078
23027
|
var REGISTRY = "https://registry.npmjs.org";
|
|
23079
23028
|
var REQUEST_TIMEOUT_MS = 1e4;
|
|
23080
|
-
var
|
|
23029
|
+
var INSTALL_TIMEOUT_MS = 18e4;
|
|
23081
23030
|
|
|
23082
23031
|
// dist/machine.js
|
|
23083
|
-
var
|
|
23032
|
+
var run2 = promisify2(execFile3);
|
|
23084
23033
|
var machine = {
|
|
23085
23034
|
home() {
|
|
23086
23035
|
return process.env.CRAFTSPACE_CLI_HOME ?? path4.join(os5.homedir(), ".craftspace");
|
|
@@ -23107,10 +23056,8 @@ var machine = {
|
|
|
23107
23056
|
await writeFile(tokenPath(), token, { mode: 384 });
|
|
23108
23057
|
await writeAgentConfigs({ url: url2, token, writes: answer.write });
|
|
23109
23058
|
await installService();
|
|
23110
|
-
|
|
23111
|
-
|
|
23112
|
-
tools: await setup.run({ install, rewire, say: ui.say })
|
|
23113
|
-
};
|
|
23059
|
+
if (install)
|
|
23060
|
+
await machine.beatOnce(ui.say);
|
|
23114
23061
|
return answer.machine;
|
|
23115
23062
|
},
|
|
23116
23063
|
async controlPlane(override) {
|
|
@@ -23147,8 +23094,9 @@ ${ui.ok(`Signed in as ${signed.ownerName}. This machine is ${ui.name(signed.name
|
|
|
23147
23094
|
const found = await withAuth(await signedInOrAsk(), (auth) => call({ ...auth, method: "GET", path: "/api/machines/me", schema: MachineSchema }));
|
|
23148
23095
|
return { machine: found.value, url: found.auth.url };
|
|
23149
23096
|
},
|
|
23150
|
-
async beatOnce() {
|
|
23097
|
+
async beatOnce(say) {
|
|
23151
23098
|
const { url: url2, token } = await requireSignedIn();
|
|
23099
|
+
const built = await readEnvironment();
|
|
23152
23100
|
const answer = await call({
|
|
23153
23101
|
url: url2,
|
|
23154
23102
|
token,
|
|
@@ -23159,12 +23107,19 @@ ${ui.ok(`Signed in as ${signed.ownerName}. This machine is ${ui.name(signed.name
|
|
|
23159
23107
|
...load2(),
|
|
23160
23108
|
sessions: await readSessions(),
|
|
23161
23109
|
runs: drainReports(),
|
|
23162
|
-
tools: await
|
|
23110
|
+
tools: await checks(),
|
|
23111
|
+
environment: built?.results ?? [],
|
|
23112
|
+
templateId: built?.templateId ?? null,
|
|
23163
23113
|
sshUser: os5.userInfo().username
|
|
23164
23114
|
},
|
|
23165
23115
|
schema: MachineBeatResponseSchema
|
|
23166
23116
|
});
|
|
23167
23117
|
await writeAuthorizedKeys(answer.authorizedKeys);
|
|
23118
|
+
const building2 = buildEnvironment(answer.environment, say);
|
|
23119
|
+
if (say === void 0)
|
|
23120
|
+
void building2.catch(() => void 0);
|
|
23121
|
+
else
|
|
23122
|
+
await building2;
|
|
23168
23123
|
for (const work of answer.work) {
|
|
23169
23124
|
if (running.has(work.id))
|
|
23170
23125
|
continue;
|
|
@@ -23240,7 +23195,7 @@ async function pick2(machines) {
|
|
|
23240
23195
|
choices: machines.map((candidate) => ({
|
|
23241
23196
|
name: `${candidate.name.padEnd(24)} ${candidate.state.padEnd(12)} ${specs(candidate)} ${beat(candidate)}`,
|
|
23242
23197
|
value: candidate,
|
|
23243
|
-
|
|
23198
|
+
disabled: candidate.sshAddress === null ? "(no address yet, so nothing to open)" : false
|
|
23244
23199
|
})),
|
|
23245
23200
|
pageSize: 12
|
|
23246
23201
|
});
|
|
@@ -23268,7 +23223,10 @@ ${ui.dim("\u2192")} ${ui.name(target.name)} ${ui.dim(`\xB7 ${where}`)}
|
|
|
23268
23223
|
|
|
23269
23224
|
`);
|
|
23270
23225
|
return new Promise((resolve) => {
|
|
23271
|
-
const session = spawn2("ssh", ["-t", where], {
|
|
23226
|
+
const session = spawn2("ssh", ["-t", where], {
|
|
23227
|
+
stdio: "inherit",
|
|
23228
|
+
env: { ...process.env, TERM: portableTerm(process.env.TERM) }
|
|
23229
|
+
});
|
|
23272
23230
|
session.on("error", (error51) => {
|
|
23273
23231
|
ui.say(ui.bad(`could not start ssh`, error51.message));
|
|
23274
23232
|
resolve(1);
|
|
@@ -23276,6 +23234,9 @@ ${ui.dim("\u2192")} ${ui.name(target.name)} ${ui.dim(`\xB7 ${where}`)}
|
|
|
23276
23234
|
session.on("exit", (code) => resolve(code ?? 0));
|
|
23277
23235
|
});
|
|
23278
23236
|
}
|
|
23237
|
+
function portableTerm(local) {
|
|
23238
|
+
return local !== void 0 && PORTABLE_TERMS.has(local) ? local : "xterm-256color";
|
|
23239
|
+
}
|
|
23279
23240
|
function nowhereToGo({ url: url2 }) {
|
|
23280
23241
|
ui.say(`
|
|
23281
23242
|
${ui.attention("No workstations here yet.")}
|
|
@@ -23286,13 +23247,51 @@ ${ui.attention("No workstations here yet.")}
|
|
|
23286
23247
|
ui.say("\n");
|
|
23287
23248
|
return 1;
|
|
23288
23249
|
}
|
|
23289
|
-
async function
|
|
23250
|
+
async function checks() {
|
|
23290
23251
|
if (probed !== null && Date.now() - probed.at < PROBE_EVERY_MS)
|
|
23291
23252
|
return probed.tools;
|
|
23292
|
-
const
|
|
23253
|
+
const first = await probe.tools();
|
|
23254
|
+
const unwired = first.some((tool) => tool.id === "brain" && !tool.ok);
|
|
23255
|
+
const found = unwired && installs() ? await rewire().then(() => probe.tools(), () => first) : first;
|
|
23293
23256
|
probed = { at: Date.now(), tools: found };
|
|
23294
23257
|
return found;
|
|
23295
23258
|
}
|
|
23259
|
+
async function buildEnvironment(next, say) {
|
|
23260
|
+
if (building || !installs() || next.templateId === null)
|
|
23261
|
+
return;
|
|
23262
|
+
const built = await readEnvironment();
|
|
23263
|
+
if (!buildIsDue(built, next.templateId))
|
|
23264
|
+
return;
|
|
23265
|
+
building = true;
|
|
23266
|
+
try {
|
|
23267
|
+
say?.(ui.heading(`Building the ${next.steps.length} setup scripts your team runs on every box`));
|
|
23268
|
+
const results = await setup.runSteps({ steps: next.steps, say });
|
|
23269
|
+
await writeEnvironment({ templateId: next.templateId, results, at: Date.now() });
|
|
23270
|
+
} finally {
|
|
23271
|
+
building = false;
|
|
23272
|
+
}
|
|
23273
|
+
}
|
|
23274
|
+
function buildIsDue(built, templateId) {
|
|
23275
|
+
if (built === null || built.templateId !== templateId)
|
|
23276
|
+
return true;
|
|
23277
|
+
if (built.results.every((result) => result.ok))
|
|
23278
|
+
return false;
|
|
23279
|
+
return Date.now() - built.at > REBUILD_AFTER_MS;
|
|
23280
|
+
}
|
|
23281
|
+
async function readEnvironment() {
|
|
23282
|
+
const raw = await readFile2(environmentPath(), "utf8").catch(() => null);
|
|
23283
|
+
if (raw === null)
|
|
23284
|
+
return null;
|
|
23285
|
+
const parsed = BuiltSchema.safeParse(JSON.parse(raw));
|
|
23286
|
+
return parsed.success ? parsed.data : null;
|
|
23287
|
+
}
|
|
23288
|
+
async function writeEnvironment(built) {
|
|
23289
|
+
await mkdir(machine.home(), { recursive: true, mode: 448 });
|
|
23290
|
+
await writeFile(environmentPath(), JSON.stringify(built, null, 2), { mode: 384 });
|
|
23291
|
+
}
|
|
23292
|
+
function installs() {
|
|
23293
|
+
return process.env.CRAFTSPACE_NO_INSTALL !== "1";
|
|
23294
|
+
}
|
|
23296
23295
|
async function rewire() {
|
|
23297
23296
|
const { url: url2, token } = await requireSignedIn();
|
|
23298
23297
|
await writeAgentConfigs({ url: url2, token, writes: [] });
|
|
@@ -23353,7 +23352,7 @@ ${ui.note("Picking up where you left off.")}
|
|
|
23353
23352
|
}
|
|
23354
23353
|
async function openInBrowser(url2) {
|
|
23355
23354
|
const opener = process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
|
|
23356
|
-
await
|
|
23355
|
+
await run2(opener, [url2]).catch(() => void 0);
|
|
23357
23356
|
}
|
|
23358
23357
|
function tokenIn(line) {
|
|
23359
23358
|
return /cst_[A-Za-z0-9_-]+/.exec(line)?.[0];
|
|
@@ -23365,7 +23364,7 @@ async function ensureKey() {
|
|
|
23365
23364
|
if (existing !== null)
|
|
23366
23365
|
return existing.trim();
|
|
23367
23366
|
await mkdir(machine.home(), { recursive: true, mode: 448 });
|
|
23368
|
-
await
|
|
23367
|
+
await run2("ssh-keygen", ["-t", "ed25519", "-N", "", "-q", "-f", priv, "-C", `craftspace-${os5.hostname()}`]);
|
|
23369
23368
|
return (await readFile2(pub, "utf8")).trim();
|
|
23370
23369
|
}
|
|
23371
23370
|
async function readConfig() {
|
|
@@ -23498,28 +23497,28 @@ async function installService() {
|
|
|
23498
23497
|
const dir = path4.join(os5.homedir(), ".config", "systemd", "user");
|
|
23499
23498
|
await mkdir(dir, { recursive: true });
|
|
23500
23499
|
await writeFile(path4.join(dir, `${SERVICE_NAME}.service`), systemdUnit());
|
|
23501
|
-
await
|
|
23502
|
-
await
|
|
23503
|
-
await
|
|
23500
|
+
await run2("loginctl", ["enable-linger", os5.userInfo().username]).catch(() => void 0);
|
|
23501
|
+
await run2("systemctl", ["--user", "daemon-reload"]).catch(() => void 0);
|
|
23502
|
+
await run2("systemctl", ["--user", "enable", "--now", SERVICE_NAME]).catch(() => void 0);
|
|
23504
23503
|
return;
|
|
23505
23504
|
}
|
|
23506
23505
|
if (process.platform === "darwin") {
|
|
23507
23506
|
const target = path4.join(os5.homedir(), "Library", "LaunchAgents", `${LAUNCH_LABEL}.plist`);
|
|
23508
23507
|
await mkdir(path4.dirname(target), { recursive: true });
|
|
23509
23508
|
await writeFile(target, launchdPlist());
|
|
23510
|
-
await
|
|
23511
|
-
await
|
|
23509
|
+
await run2("launchctl", ["unload", target]).catch(() => void 0);
|
|
23510
|
+
await run2("launchctl", ["load", target]).catch(() => void 0);
|
|
23512
23511
|
}
|
|
23513
23512
|
}
|
|
23514
23513
|
async function uninstallService() {
|
|
23515
23514
|
if (process.platform === "linux") {
|
|
23516
|
-
await
|
|
23515
|
+
await run2("systemctl", ["--user", "disable", "--now", SERVICE_NAME]).catch(() => void 0);
|
|
23517
23516
|
await rm(path4.join(os5.homedir(), ".config", "systemd", "user", `${SERVICE_NAME}.service`), { force: true });
|
|
23518
23517
|
return;
|
|
23519
23518
|
}
|
|
23520
23519
|
if (process.platform === "darwin") {
|
|
23521
23520
|
const target = path4.join(os5.homedir(), "Library", "LaunchAgents", `${LAUNCH_LABEL}.plist`);
|
|
23522
|
-
await
|
|
23521
|
+
await run2("launchctl", ["unload", target]).catch(() => void 0);
|
|
23523
23522
|
await rm(target, { force: true });
|
|
23524
23523
|
}
|
|
23525
23524
|
}
|
|
@@ -23556,10 +23555,10 @@ function here() {
|
|
|
23556
23555
|
return `${process.execPath} ${entryPath()}`;
|
|
23557
23556
|
}
|
|
23558
23557
|
async function serviceRunning() {
|
|
23559
|
-
return await
|
|
23558
|
+
return await run2("systemctl", ["--user", "is-active", SERVICE_NAME]).catch(() => null) !== null;
|
|
23560
23559
|
}
|
|
23561
23560
|
async function userLingers() {
|
|
23562
|
-
const shown = await
|
|
23561
|
+
const shown = await run2("loginctl", ["show-user", os5.userInfo().username, "-p", "Linger"]).catch(() => null);
|
|
23563
23562
|
return shown?.stdout.includes("Linger=yes") === true;
|
|
23564
23563
|
}
|
|
23565
23564
|
function entryPath() {
|
|
@@ -23577,6 +23576,9 @@ function tokenPath() {
|
|
|
23577
23576
|
function ownedPath() {
|
|
23578
23577
|
return path4.join(machine.home(), "owned.json");
|
|
23579
23578
|
}
|
|
23579
|
+
function environmentPath() {
|
|
23580
|
+
return path4.join(machine.home(), "environment.json");
|
|
23581
|
+
}
|
|
23580
23582
|
function load2() {
|
|
23581
23583
|
const cores = Math.max(1, os5.cpus().length);
|
|
23582
23584
|
const busy = Math.min(100, (os5.loadavg()[0] ?? 0) / cores * 100);
|
|
@@ -23595,6 +23597,11 @@ function messageOf(error51) {
|
|
|
23595
23597
|
return error51 instanceof Error ? error51.message : String(error51);
|
|
23596
23598
|
}
|
|
23597
23599
|
var ConfigSchema = external_exports.object({ url: external_exports.string(), machineId: external_exports.string() });
|
|
23600
|
+
var BuiltSchema = external_exports.object({
|
|
23601
|
+
templateId: external_exports.string(),
|
|
23602
|
+
results: external_exports.array(WorkstationStepResultSchema),
|
|
23603
|
+
at: external_exports.number()
|
|
23604
|
+
});
|
|
23598
23605
|
var OwnedSchema = external_exports.object({ paths: external_exports.array(external_exports.string()) });
|
|
23599
23606
|
var SERVICE_NAME = "craftspace";
|
|
23600
23607
|
var LAUNCH_LABEL = "app.craftspace.machine";
|
|
@@ -23605,10 +23612,27 @@ var KEYS_BEGIN = "# craftspace begin";
|
|
|
23605
23612
|
var KEYS_END = "# craftspace end";
|
|
23606
23613
|
var UPDATE_EVERY_MS = 6 * 60 * 60 * 1e3;
|
|
23607
23614
|
var BEATING = "beating every 15s, outbound only, and keeps this set up";
|
|
23615
|
+
var PORTABLE_TERMS = /* @__PURE__ */ new Set([
|
|
23616
|
+
"ansi",
|
|
23617
|
+
"dumb",
|
|
23618
|
+
"linux",
|
|
23619
|
+
"rxvt",
|
|
23620
|
+
"rxvt-unicode",
|
|
23621
|
+
"rxvt-unicode-256color",
|
|
23622
|
+
"screen",
|
|
23623
|
+
"screen-256color",
|
|
23624
|
+
"vt100",
|
|
23625
|
+
"vt220",
|
|
23626
|
+
"xterm",
|
|
23627
|
+
"xterm-color",
|
|
23628
|
+
"xterm-256color"
|
|
23629
|
+
]);
|
|
23608
23630
|
var LINGER_LINE = `sudo loginctl enable-linger ${os5.userInfo().username}`;
|
|
23609
23631
|
var DEFAULT_URL = process.env.CRAFTSPACE_URL ?? "https://craftspace.app";
|
|
23610
23632
|
var PROBE_EVERY_MS = 3e5;
|
|
23633
|
+
var REBUILD_AFTER_MS = 216e5;
|
|
23611
23634
|
var probed = null;
|
|
23635
|
+
var building = false;
|
|
23612
23636
|
var reports = /* @__PURE__ */ new Map();
|
|
23613
23637
|
var running = /* @__PURE__ */ new Set();
|
|
23614
23638
|
|