@cospacehq/cli 0.1.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/config.d.ts +23 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +72 -0
- package/dist/config.js.map +1 -0
- package/dist/doctor.d.ts +5 -0
- package/dist/doctor.d.ts.map +1 -0
- package/dist/doctor.js +99 -0
- package/dist/doctor.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +248 -0
- package/dist/index.js.map +1 -0
- package/dist/postinstall.d.ts +3 -0
- package/dist/postinstall.d.ts.map +1 -0
- package/dist/postinstall.js +26 -0
- package/dist/postinstall.js.map +1 -0
- package/dist/tunnel.d.ts +18 -0
- package/dist/tunnel.d.ts.map +1 -0
- package/dist/tunnel.js +103 -0
- package/dist/tunnel.js.map +1 -0
- package/package.json +33 -0
- package/web-dist/assets/index-C1jgYY2x.css +1 -0
- package/web-dist/assets/index-tgwWzseM.js +65 -0
- package/web-dist/index.html +13 -0
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { type CoSpaceConfig, type TunnelProvider } from "@cospacehq/shared";
|
|
2
|
+
export type InitConfigInput = {
|
|
3
|
+
projectRoot: string;
|
|
4
|
+
projectName?: string;
|
|
5
|
+
port: number;
|
|
6
|
+
tunnelProvider: TunnelProvider;
|
|
7
|
+
tunnelApiKey?: string;
|
|
8
|
+
sessionPasscode?: string;
|
|
9
|
+
};
|
|
10
|
+
export declare function passcodeHashFromRaw(rawPasscode: string): string;
|
|
11
|
+
export declare function projectRootFromConfigPath(configFilePath: string): string;
|
|
12
|
+
export declare function cospaceDir(projectRoot: string): string;
|
|
13
|
+
export declare function configPath(projectRoot: string): string;
|
|
14
|
+
export declare function createRuntimeDirectories(projectRoot: string): Promise<void>;
|
|
15
|
+
export declare function createConfig(input: InitConfigInput): CoSpaceConfig;
|
|
16
|
+
export declare function writeConfig(projectRoot: string, config: CoSpaceConfig): Promise<string>;
|
|
17
|
+
export declare function loadConfig(projectRoot: string, explicitPath?: string): Promise<{
|
|
18
|
+
config: CoSpaceConfig;
|
|
19
|
+
path: string;
|
|
20
|
+
projectRoot: string;
|
|
21
|
+
}>;
|
|
22
|
+
export declare function configExists(projectRoot: string): Promise<boolean>;
|
|
23
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAGA,OAAO,EAAuB,KAAK,aAAa,EAAE,KAAK,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAEjG,MAAM,MAAM,eAAe,GAAG;IAC5B,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,cAAc,EAAE,cAAc,CAAC;IAC/B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B,CAAC;AAEF,wBAAgB,mBAAmB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAE/D;AAED,wBAAgB,yBAAyB,CAAC,cAAc,EAAE,MAAM,GAAG,MAAM,CAIxE;AAED,wBAAgB,UAAU,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAEtD;AAED,wBAAgB,UAAU,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAEtD;AAED,wBAAsB,wBAAwB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAKjF;AAOD,wBAAgB,YAAY,CAAC,KAAK,EAAE,eAAe,GAAG,aAAa,CAkBlE;AAED,wBAAsB,WAAW,CAAC,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,aAAa,GAAG,OAAO,CAAC,MAAM,CAAC,CAK7F;AAED,wBAAsB,UAAU,CAC9B,WAAW,EAAE,MAAM,EACnB,YAAY,CAAC,EAAE,MAAM,GACpB,OAAO,CAAC;IAAE,MAAM,EAAE,aAAa,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,CAAC,CAQvE;AAED,wBAAsB,YAAY,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAOxE"}
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import crypto from "node:crypto";
|
|
2
|
+
import fs from "node:fs/promises";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { CoSpaceConfigSchema } from "@cospacehq/shared";
|
|
5
|
+
export function passcodeHashFromRaw(rawPasscode) {
|
|
6
|
+
return crypto.createHash("sha256").update(rawPasscode, "utf8").digest("hex");
|
|
7
|
+
}
|
|
8
|
+
export function projectRootFromConfigPath(configFilePath) {
|
|
9
|
+
const absoluteConfigPath = path.resolve(configFilePath);
|
|
10
|
+
const configDir = path.dirname(absoluteConfigPath);
|
|
11
|
+
return path.basename(configDir) === ".cospace" ? path.dirname(configDir) : configDir;
|
|
12
|
+
}
|
|
13
|
+
export function cospaceDir(projectRoot) {
|
|
14
|
+
return path.join(projectRoot, ".cospace");
|
|
15
|
+
}
|
|
16
|
+
export function configPath(projectRoot) {
|
|
17
|
+
return path.join(cospaceDir(projectRoot), "config.json");
|
|
18
|
+
}
|
|
19
|
+
export async function createRuntimeDirectories(projectRoot) {
|
|
20
|
+
const base = cospaceDir(projectRoot);
|
|
21
|
+
await fs.mkdir(path.join(base, "workspace"), { recursive: true });
|
|
22
|
+
await fs.mkdir(path.join(base, "data"), { recursive: true });
|
|
23
|
+
await fs.mkdir(path.join(base, "logs"), { recursive: true });
|
|
24
|
+
}
|
|
25
|
+
function normalizeProjectName(value) {
|
|
26
|
+
const trimmed = (value ?? "").trim();
|
|
27
|
+
return trimmed.length > 0 ? trimmed : "CoSpace";
|
|
28
|
+
}
|
|
29
|
+
export function createConfig(input) {
|
|
30
|
+
const sessionPasscode = input.sessionPasscode?.trim();
|
|
31
|
+
return {
|
|
32
|
+
version: 1,
|
|
33
|
+
projectName: normalizeProjectName(input.projectName),
|
|
34
|
+
port: input.port,
|
|
35
|
+
workspaceRoot: ".cospace/workspace",
|
|
36
|
+
dataDir: ".cospace/data",
|
|
37
|
+
auth: {
|
|
38
|
+
token: crypto.randomBytes(18).toString("hex"),
|
|
39
|
+
encryptionSecret: crypto.randomBytes(18).toString("hex"),
|
|
40
|
+
passcodeHash: sessionPasscode ? passcodeHashFromRaw(sessionPasscode) : undefined
|
|
41
|
+
},
|
|
42
|
+
tunnel: {
|
|
43
|
+
provider: input.tunnelProvider,
|
|
44
|
+
apiKey: input.tunnelApiKey
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
export async function writeConfig(projectRoot, config) {
|
|
49
|
+
const filePath = configPath(projectRoot);
|
|
50
|
+
await fs.mkdir(path.dirname(filePath), { recursive: true });
|
|
51
|
+
await fs.writeFile(filePath, `${JSON.stringify(config, null, 2)}\n`, "utf8");
|
|
52
|
+
return filePath;
|
|
53
|
+
}
|
|
54
|
+
export async function loadConfig(projectRoot, explicitPath) {
|
|
55
|
+
const filePath = explicitPath ? path.resolve(explicitPath) : configPath(projectRoot);
|
|
56
|
+
const raw = await fs.readFile(filePath, "utf8");
|
|
57
|
+
return {
|
|
58
|
+
config: CoSpaceConfigSchema.parse(JSON.parse(raw)),
|
|
59
|
+
path: filePath,
|
|
60
|
+
projectRoot: projectRootFromConfigPath(filePath)
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
export async function configExists(projectRoot) {
|
|
64
|
+
try {
|
|
65
|
+
await fs.stat(configPath(projectRoot));
|
|
66
|
+
return true;
|
|
67
|
+
}
|
|
68
|
+
catch {
|
|
69
|
+
return false;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
|
package/dist/doctor.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../src/doctor.ts"],"names":[],"mappings":"AA0BA,wBAAsB,SAAS,CAAC,WAAW,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IAAE,EAAE,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC,CAsFnH"}
|
package/dist/doctor.js
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import fs from "node:fs/promises";
|
|
2
|
+
import { constants as fsConstants } from "node:fs";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
import { CoSpaceConfigSchema } from "@cospacehq/shared";
|
|
6
|
+
import { projectRootFromConfigPath } from "./config.js";
|
|
7
|
+
import { tunnelDoctor } from "./tunnel.js";
|
|
8
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
9
|
+
const __dirname = path.dirname(__filename);
|
|
10
|
+
function isWithin(root, candidate) {
|
|
11
|
+
const relative = path.relative(path.resolve(root), path.resolve(candidate));
|
|
12
|
+
return relative === "" || (!relative.startsWith("..") && !path.isAbsolute(relative));
|
|
13
|
+
}
|
|
14
|
+
function webBundleCandidates(configProjectRoot) {
|
|
15
|
+
const fromEnv = process.env.COSPACE_WEB_DIST ? [path.resolve(process.env.COSPACE_WEB_DIST, "index.html")] : [];
|
|
16
|
+
return [
|
|
17
|
+
...fromEnv,
|
|
18
|
+
path.resolve(__dirname, "../web-dist/index.html"),
|
|
19
|
+
path.resolve(configProjectRoot, "apps/web/dist/index.html")
|
|
20
|
+
];
|
|
21
|
+
}
|
|
22
|
+
export async function runDoctor(projectRoot, configPath) {
|
|
23
|
+
const lines = [];
|
|
24
|
+
const resolvedConfigPath = configPath
|
|
25
|
+
? path.resolve(configPath)
|
|
26
|
+
: path.resolve(projectRoot, ".cospace/config.json");
|
|
27
|
+
const configProjectRoot = projectRootFromConfigPath(resolvedConfigPath);
|
|
28
|
+
let rawConfig;
|
|
29
|
+
try {
|
|
30
|
+
rawConfig = await fs.readFile(resolvedConfigPath, "utf8");
|
|
31
|
+
lines.push(`ok config exists: ${resolvedConfigPath}`);
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
return { ok: false, lines: [`err config missing: ${resolvedConfigPath}`] };
|
|
35
|
+
}
|
|
36
|
+
const config = CoSpaceConfigSchema.parse(JSON.parse(rawConfig));
|
|
37
|
+
lines.push("ok config parse: valid schema");
|
|
38
|
+
const cospaceBase = path.resolve(configProjectRoot, ".cospace");
|
|
39
|
+
const requiredDirs = [
|
|
40
|
+
path.resolve(configProjectRoot, config.workspaceRoot),
|
|
41
|
+
path.resolve(configProjectRoot, config.dataDir),
|
|
42
|
+
path.resolve(configProjectRoot, ".cospace/logs")
|
|
43
|
+
];
|
|
44
|
+
for (const dir of requiredDirs) {
|
|
45
|
+
try {
|
|
46
|
+
await fs.access(dir);
|
|
47
|
+
lines.push(`ok dir exists: ${dir}`);
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
lines.push(`err dir missing: ${dir}`);
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
try {
|
|
54
|
+
await fs.access(dir, fsConstants.W_OK);
|
|
55
|
+
lines.push(`ok dir writable: ${dir}`);
|
|
56
|
+
}
|
|
57
|
+
catch {
|
|
58
|
+
lines.push(`err dir not writable: ${dir}`);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
const workspacePath = path.resolve(configProjectRoot, config.workspaceRoot);
|
|
62
|
+
lines.push(isWithin(cospaceBase, workspacePath)
|
|
63
|
+
? `ok workspaceRoot scoped to .cospace: ${workspacePath}`
|
|
64
|
+
: `err workspaceRoot escapes .cospace: ${workspacePath}`);
|
|
65
|
+
const dataPath = path.resolve(configProjectRoot, config.dataDir);
|
|
66
|
+
lines.push(isWithin(cospaceBase, dataPath)
|
|
67
|
+
? `ok dataDir scoped to .cospace: ${dataPath}`
|
|
68
|
+
: `err dataDir escapes .cospace: ${dataPath}`);
|
|
69
|
+
let webBundlePath = null;
|
|
70
|
+
for (const candidate of webBundleCandidates(configProjectRoot)) {
|
|
71
|
+
try {
|
|
72
|
+
await fs.access(candidate);
|
|
73
|
+
webBundlePath = candidate;
|
|
74
|
+
break;
|
|
75
|
+
}
|
|
76
|
+
catch {
|
|
77
|
+
continue;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
if (webBundlePath) {
|
|
81
|
+
lines.push(`ok web bundle: ${webBundlePath}`);
|
|
82
|
+
}
|
|
83
|
+
else {
|
|
84
|
+
lines.push("warn web bundle missing: run `pnpm --filter @cospacehq/web build` before packaging");
|
|
85
|
+
}
|
|
86
|
+
const tunnel = await tunnelDoctor(config.tunnel.provider);
|
|
87
|
+
lines.push(`${tunnel.ok ? "ok " : "err"} tunnel: ${tunnel.detail}`);
|
|
88
|
+
if (config.tunnel.provider !== "none") {
|
|
89
|
+
if (config.auth.passcodeHash) {
|
|
90
|
+
lines.push("ok tunnel passcode guard: enabled");
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
lines.push("warn tunnel passcode guard: disabled (recommended for public tunnel use)");
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
const ok = !lines.some((line) => line.startsWith("err"));
|
|
97
|
+
return { ok, lines };
|
|
98
|
+
}
|
|
99
|
+
//# sourceMappingURL=doctor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"doctor.js","sourceRoot":"","sources":["../src/doctor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAClC,OAAO,EAAE,SAAS,IAAI,WAAW,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAAE,yBAAyB,EAAE,MAAM,aAAa,CAAC;AACxD,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,MAAM,UAAU,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAClD,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;AAE3C,SAAS,QAAQ,CAAC,IAAY,EAAE,SAAiB;IAC/C,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC;IAC5E,OAAO,QAAQ,KAAK,EAAE,IAAI,CAAC,CAAC,QAAQ,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAC;AACvF,CAAC;AAED,SAAS,mBAAmB,CAAC,iBAAyB;IACpD,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,gBAAgB,EAAE,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAE/G,OAAO;QACL,GAAG,OAAO;QACV,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,wBAAwB,CAAC;QACjD,IAAI,CAAC,OAAO,CAAC,iBAAiB,EAAE,0BAA0B,CAAC;KAC5D,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,WAAmB,EAAE,UAAmB;IACtE,MAAM,KAAK,GAAa,EAAE,CAAC;IAE3B,MAAM,kBAAkB,GAAG,UAAU;QACnC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC;QAC1B,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,sBAAsB,CAAC,CAAC;IACtD,MAAM,iBAAiB,GAAG,yBAAyB,CAAC,kBAAkB,CAAC,CAAC;IAExE,IAAI,SAAiB,CAAC;IACtB,IAAI,CAAC;QACH,SAAS,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,kBAAkB,EAAE,MAAM,CAAC,CAAC;QAC1D,KAAK,CAAC,IAAI,CAAC,sBAAsB,kBAAkB,EAAE,CAAC,CAAC;IACzD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,uBAAuB,kBAAkB,EAAE,CAAC,EAAE,CAAC;IAC7E,CAAC;IAED,MAAM,MAAM,GAAG,mBAAmB,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC;IAChE,KAAK,CAAC,IAAI,CAAC,gCAAgC,CAAC,CAAC;IAE7C,MAAM,WAAW,GAAG,IAAI,CAAC,OAAO,CAAC,iBAAiB,EAAE,UAAU,CAAC,CAAC;IAChE,MAAM,YAAY,GAAG;QACnB,IAAI,CAAC,OAAO,CAAC,iBAAiB,EAAE,MAAM,CAAC,aAAa,CAAC;QACrD,IAAI,CAAC,OAAO,CAAC,iBAAiB,EAAE,MAAM,CAAC,OAAO,CAAC;QAC/C,IAAI,CAAC,OAAO,CAAC,iBAAiB,EAAE,eAAe,CAAC;KACjD,CAAC;IAEF,KAAK,MAAM,GAAG,IAAI,YAAY,EAAE,CAAC;QAC/B,IAAI,CAAC;YACH,MAAM,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACrB,KAAK,CAAC,IAAI,CAAC,mBAAmB,GAAG,EAAE,CAAC,CAAC;QACvC,CAAC;QAAC,MAAM,CAAC;YACP,KAAK,CAAC,IAAI,CAAC,oBAAoB,GAAG,EAAE,CAAC,CAAC;YACtC,SAAS;QACX,CAAC;QAED,IAAI,CAAC;YACH,MAAM,EAAE,CAAC,MAAM,CAAC,GAAG,EAAE,WAAW,CAAC,IAAI,CAAC,CAAC;YACvC,KAAK,CAAC,IAAI,CAAC,qBAAqB,GAAG,EAAE,CAAC,CAAC;QACzC,CAAC;QAAC,MAAM,CAAC;YACP,KAAK,CAAC,IAAI,CAAC,yBAAyB,GAAG,EAAE,CAAC,CAAC;QAC7C,CAAC;IACH,CAAC;IAED,MAAM,aAAa,GAAG,IAAI,CAAC,OAAO,CAAC,iBAAiB,EAAE,MAAM,CAAC,aAAa,CAAC,CAAC;IAC5E,KAAK,CAAC,IAAI,CACR,QAAQ,CAAC,WAAW,EAAE,aAAa,CAAC;QAClC,CAAC,CAAC,yCAAyC,aAAa,EAAE;QAC1D,CAAC,CAAC,uCAAuC,aAAa,EAAE,CAC3D,CAAC;IAEF,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,iBAAiB,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC;IACjE,KAAK,CAAC,IAAI,CACR,QAAQ,CAAC,WAAW,EAAE,QAAQ,CAAC;QAC7B,CAAC,CAAC,mCAAmC,QAAQ,EAAE;QAC/C,CAAC,CAAC,iCAAiC,QAAQ,EAAE,CAChD,CAAC;IAEF,IAAI,aAAa,GAAkB,IAAI,CAAC;IACxC,KAAK,MAAM,SAAS,IAAI,mBAAmB,CAAC,iBAAiB,CAAC,EAAE,CAAC;QAC/D,IAAI,CAAC;YACH,MAAM,EAAE,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;YAC3B,aAAa,GAAG,SAAS,CAAC;YAC1B,MAAM;QACR,CAAC;QAAC,MAAM,CAAC;YACP,SAAS;QACX,CAAC;IACH,CAAC;IACD,IAAI,aAAa,EAAE,CAAC;QAClB,KAAK,CAAC,IAAI,CAAC,mBAAmB,aAAa,EAAE,CAAC,CAAC;IACjD,CAAC;SAAM,CAAC;QACN,KAAK,CAAC,IAAI,CAAC,oFAAoF,CAAC,CAAC;IACnG,CAAC;IAED,MAAM,MAAM,GAAG,MAAM,YAAY,CAAC,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IAC1D,KAAK,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,YAAY,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;IAEpE,IAAI,MAAM,CAAC,MAAM,CAAC,QAAQ,KAAK,MAAM,EAAE,CAAC;QACtC,IAAI,MAAM,CAAC,IAAI,CAAC,YAAY,EAAE,CAAC;YAC7B,KAAK,CAAC,IAAI,CAAC,oCAAoC,CAAC,CAAC;QACnD,CAAC;aAAM,CAAC;YACN,KAAK,CAAC,IAAI,CAAC,0EAA0E,CAAC,CAAC;QACzF,CAAC;IACH,CAAC;IAED,MAAM,EAAE,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC;IACzD,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC;AACvB,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { existsSync } from "node:fs";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import process from "node:process";
|
|
5
|
+
import { fileURLToPath } from "node:url";
|
|
6
|
+
import { Command } from "commander";
|
|
7
|
+
import Enquirer from "enquirer";
|
|
8
|
+
import { configExists, configPath, createConfig, createRuntimeDirectories, loadConfig, writeConfig } from "./config.js";
|
|
9
|
+
import { runDoctor } from "./doctor.js";
|
|
10
|
+
import { maybeStartTunnel } from "./tunnel.js";
|
|
11
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
12
|
+
const __dirname = path.dirname(__filename);
|
|
13
|
+
const { prompt } = Enquirer;
|
|
14
|
+
function findWebDist(projectRoot) {
|
|
15
|
+
const candidates = [
|
|
16
|
+
process.env.COSPACE_WEB_DIST,
|
|
17
|
+
path.resolve(__dirname, "../web-dist"),
|
|
18
|
+
path.resolve(__dirname, "../../web/dist"),
|
|
19
|
+
path.resolve(projectRoot, "apps/web/dist")
|
|
20
|
+
].filter((value) => Boolean(value));
|
|
21
|
+
for (const candidate of candidates) {
|
|
22
|
+
const absolute = path.resolve(candidate);
|
|
23
|
+
const indexPath = path.join(absolute, "index.html");
|
|
24
|
+
if (existsSync(indexPath)) {
|
|
25
|
+
return absolute;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
return undefined;
|
|
29
|
+
}
|
|
30
|
+
function withToken(url, token) {
|
|
31
|
+
const separator = url.includes("?") ? "&" : "?";
|
|
32
|
+
return `${url}${separator}token=${token}`;
|
|
33
|
+
}
|
|
34
|
+
function suggestedProjectName(projectRoot) {
|
|
35
|
+
const base = path.basename(path.resolve(projectRoot)).trim();
|
|
36
|
+
return base.length > 0 ? base : "CoSpace";
|
|
37
|
+
}
|
|
38
|
+
async function promptTunnelProvider() {
|
|
39
|
+
const answer = await prompt({
|
|
40
|
+
type: "select",
|
|
41
|
+
name: "tunnelProvider",
|
|
42
|
+
message: "Tunnel provider",
|
|
43
|
+
choices: ["none", "cloudflare", "ngrok"],
|
|
44
|
+
initial: 0
|
|
45
|
+
});
|
|
46
|
+
return answer.tunnelProvider;
|
|
47
|
+
}
|
|
48
|
+
async function promptTunnelApiKey(provider) {
|
|
49
|
+
if (provider === "none") {
|
|
50
|
+
return undefined;
|
|
51
|
+
}
|
|
52
|
+
const keyLabel = provider === "ngrok" ? "ngrok authtoken (required)" : "Cloudflare tunnel token (optional)";
|
|
53
|
+
const answer = await prompt({
|
|
54
|
+
type: "password",
|
|
55
|
+
name: "tunnelApiKey",
|
|
56
|
+
message: keyLabel
|
|
57
|
+
});
|
|
58
|
+
const trimmed = answer.tunnelApiKey.trim();
|
|
59
|
+
if (provider === "ngrok" && trimmed.length === 0) {
|
|
60
|
+
throw new Error("ngrok tunnel selected but no authtoken was provided");
|
|
61
|
+
}
|
|
62
|
+
return trimmed.length > 0 ? trimmed : undefined;
|
|
63
|
+
}
|
|
64
|
+
async function promptSessionPasscode() {
|
|
65
|
+
const answer = await prompt({
|
|
66
|
+
type: "confirm",
|
|
67
|
+
name: "enablePasscode",
|
|
68
|
+
message: "Require a session passcode for web access (recommended for tunnel use)?",
|
|
69
|
+
initial: true
|
|
70
|
+
});
|
|
71
|
+
if (!answer.enablePasscode) {
|
|
72
|
+
return undefined;
|
|
73
|
+
}
|
|
74
|
+
const passcode = await prompt({
|
|
75
|
+
type: "password",
|
|
76
|
+
name: "passcode",
|
|
77
|
+
message: "Session passcode (min 6 chars)"
|
|
78
|
+
});
|
|
79
|
+
const confirm = await prompt({
|
|
80
|
+
type: "password",
|
|
81
|
+
name: "passcode",
|
|
82
|
+
message: "Confirm session passcode"
|
|
83
|
+
});
|
|
84
|
+
const value = passcode.passcode.trim();
|
|
85
|
+
if (value.length < 6) {
|
|
86
|
+
throw new Error("Session passcode must be at least 6 characters");
|
|
87
|
+
}
|
|
88
|
+
if (value !== confirm.passcode.trim()) {
|
|
89
|
+
throw new Error("Session passcode confirmation does not match");
|
|
90
|
+
}
|
|
91
|
+
return value;
|
|
92
|
+
}
|
|
93
|
+
async function holdUntilExit(shutdown, tunnel) {
|
|
94
|
+
const close = async () => {
|
|
95
|
+
if (tunnel) {
|
|
96
|
+
await tunnel.stop();
|
|
97
|
+
}
|
|
98
|
+
await shutdown();
|
|
99
|
+
process.exit(0);
|
|
100
|
+
};
|
|
101
|
+
process.on("SIGINT", close);
|
|
102
|
+
process.on("SIGTERM", close);
|
|
103
|
+
return new Promise(() => {
|
|
104
|
+
// Keep process alive until signal.
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
async function runStart(projectRoot, explicitConfigPath, noTunnel) {
|
|
108
|
+
const { startCoSpaceServer } = await import("@cospacehq/server");
|
|
109
|
+
const { config, path: resolvedConfigPath, projectRoot: configProjectRoot } = await loadConfig(projectRoot, explicitConfigPath);
|
|
110
|
+
const server = await startCoSpaceServer({
|
|
111
|
+
config,
|
|
112
|
+
configPath: resolvedConfigPath,
|
|
113
|
+
webDistPath: findWebDist(configProjectRoot)
|
|
114
|
+
});
|
|
115
|
+
const localBrowserUrl = withToken(server.localUrl, config.auth.token);
|
|
116
|
+
let accessUrl = localBrowserUrl;
|
|
117
|
+
let tunnel = null;
|
|
118
|
+
try {
|
|
119
|
+
tunnel = await maybeStartTunnel({
|
|
120
|
+
provider: config.tunnel.provider,
|
|
121
|
+
apiKey: config.tunnel.apiKey,
|
|
122
|
+
localUrl: server.localUrl,
|
|
123
|
+
port: config.port,
|
|
124
|
+
noTunnel
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
catch (error) {
|
|
128
|
+
process.stderr.write(`Tunnel failed: ${error instanceof Error ? error.message : String(error)}. Continuing local-only.\n`);
|
|
129
|
+
}
|
|
130
|
+
if (tunnel) {
|
|
131
|
+
accessUrl = withToken(tunnel.publicUrl, config.auth.token);
|
|
132
|
+
}
|
|
133
|
+
process.stdout.write(`CoSpace running.\n`);
|
|
134
|
+
process.stdout.write(`Open: ${accessUrl}\n`);
|
|
135
|
+
process.stdout.write(`Local: ${localBrowserUrl}\n`);
|
|
136
|
+
if (tunnel) {
|
|
137
|
+
process.stdout.write(`Public: ${withToken(tunnel.publicUrl, config.auth.token)}\n`);
|
|
138
|
+
if (!config.auth.passcodeHash) {
|
|
139
|
+
process.stdout.write("Security warning: tunnel is public and session passcode is disabled. Configure passcode in Settings.\n");
|
|
140
|
+
}
|
|
141
|
+
else {
|
|
142
|
+
process.stdout.write("Security: session passcode is enabled for API/WebSocket access.\n");
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
process.stdout.write("Next: open Settings -> Integrations in the web app to add model API keys.\n");
|
|
146
|
+
return holdUntilExit(server.stop, tunnel);
|
|
147
|
+
}
|
|
148
|
+
async function runInit(projectRoot) {
|
|
149
|
+
const hasConfig = await configExists(projectRoot);
|
|
150
|
+
if (hasConfig) {
|
|
151
|
+
const overwriteAnswer = await prompt({
|
|
152
|
+
type: "confirm",
|
|
153
|
+
name: "overwrite",
|
|
154
|
+
message: `Found existing ${configPath(projectRoot)}. Overwrite?`,
|
|
155
|
+
initial: false
|
|
156
|
+
});
|
|
157
|
+
if (!overwriteAnswer.overwrite) {
|
|
158
|
+
throw new Error("Init aborted by user");
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
const projectNameAnswer = await prompt({
|
|
162
|
+
type: "input",
|
|
163
|
+
name: "projectName",
|
|
164
|
+
message: "Project name",
|
|
165
|
+
initial: suggestedProjectName(projectRoot)
|
|
166
|
+
});
|
|
167
|
+
const portAnswer = await prompt({
|
|
168
|
+
type: "input",
|
|
169
|
+
name: "port",
|
|
170
|
+
message: "Local port for CoSpace server",
|
|
171
|
+
initial: "4237"
|
|
172
|
+
});
|
|
173
|
+
const tunnelProvider = await promptTunnelProvider();
|
|
174
|
+
const tunnelApiKey = await promptTunnelApiKey(tunnelProvider);
|
|
175
|
+
const sessionPasscode = await promptSessionPasscode();
|
|
176
|
+
const port = Number.parseInt(portAnswer.port, 10);
|
|
177
|
+
if (!Number.isInteger(port) || port <= 0 || port > 65535) {
|
|
178
|
+
throw new Error("Port must be an integer between 1 and 65535");
|
|
179
|
+
}
|
|
180
|
+
await createRuntimeDirectories(projectRoot);
|
|
181
|
+
const config = createConfig({
|
|
182
|
+
projectRoot,
|
|
183
|
+
projectName: projectNameAnswer.projectName,
|
|
184
|
+
port,
|
|
185
|
+
tunnelProvider,
|
|
186
|
+
tunnelApiKey,
|
|
187
|
+
sessionPasscode
|
|
188
|
+
});
|
|
189
|
+
await writeConfig(projectRoot, config);
|
|
190
|
+
process.stdout.write(`Created ${configPath(projectRoot)}\n`);
|
|
191
|
+
return runStart(projectRoot, undefined, false);
|
|
192
|
+
}
|
|
193
|
+
async function main() {
|
|
194
|
+
const program = new Command();
|
|
195
|
+
program.name("cospace").description("Local-first multi-agent AI workspace").version("0.1.0");
|
|
196
|
+
program
|
|
197
|
+
.command("init")
|
|
198
|
+
.description("Create CoSpace config and launch the app")
|
|
199
|
+
.action(async () => {
|
|
200
|
+
await runInit(process.cwd());
|
|
201
|
+
});
|
|
202
|
+
program
|
|
203
|
+
.command("quickstart")
|
|
204
|
+
.description("Run environment checks, then guided init")
|
|
205
|
+
.action(async () => {
|
|
206
|
+
const result = await runDoctor(process.cwd());
|
|
207
|
+
for (const line of result.lines) {
|
|
208
|
+
process.stdout.write(`${line}\n`);
|
|
209
|
+
}
|
|
210
|
+
if (!result.ok) {
|
|
211
|
+
const proceed = await prompt({
|
|
212
|
+
type: "confirm",
|
|
213
|
+
name: "continueSetup",
|
|
214
|
+
message: "Doctor found issues. Continue with init anyway?",
|
|
215
|
+
initial: false
|
|
216
|
+
});
|
|
217
|
+
if (!proceed.continueSetup) {
|
|
218
|
+
throw new Error("Quickstart aborted due to doctor errors");
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
await runInit(process.cwd());
|
|
222
|
+
});
|
|
223
|
+
program
|
|
224
|
+
.command("start")
|
|
225
|
+
.description("Start CoSpace from existing config")
|
|
226
|
+
.option("--config <path>", "Path to config file")
|
|
227
|
+
.option("--no-tunnel", "Disable tunnel for this run")
|
|
228
|
+
.action(async (options) => {
|
|
229
|
+
await runStart(process.cwd(), options.config, !options.tunnel);
|
|
230
|
+
});
|
|
231
|
+
program
|
|
232
|
+
.command("doctor")
|
|
233
|
+
.description("Validate local CoSpace setup")
|
|
234
|
+
.option("--config <path>", "Path to config file")
|
|
235
|
+
.action(async (options) => {
|
|
236
|
+
const result = await runDoctor(process.cwd(), options.config);
|
|
237
|
+
for (const line of result.lines) {
|
|
238
|
+
process.stdout.write(`${line}\n`);
|
|
239
|
+
}
|
|
240
|
+
process.exit(result.ok ? 0 : 1);
|
|
241
|
+
});
|
|
242
|
+
await program.parseAsync(process.argv);
|
|
243
|
+
}
|
|
244
|
+
main().catch((error) => {
|
|
245
|
+
process.stderr.write(`CoSpace CLI error: ${error instanceof Error ? error.message : String(error)}\n`);
|
|
246
|
+
process.exit(1);
|
|
247
|
+
});
|
|
248
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"postinstall.d.ts","sourceRoot":"","sources":["../src/postinstall.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { spawnSync } from "node:child_process";
|
|
3
|
+
function checkBinary(binary) {
|
|
4
|
+
const result = spawnSync(binary, ["--version"], {
|
|
5
|
+
encoding: "utf8",
|
|
6
|
+
stdio: "ignore"
|
|
7
|
+
});
|
|
8
|
+
return result.status === 0;
|
|
9
|
+
}
|
|
10
|
+
function nodeMajorVersion() {
|
|
11
|
+
const match = process.versions.node.match(/^(\d+)\./);
|
|
12
|
+
if (!match) {
|
|
13
|
+
return 0;
|
|
14
|
+
}
|
|
15
|
+
return Number.parseInt(match[1], 10);
|
|
16
|
+
}
|
|
17
|
+
const nodeMajor = nodeMajorVersion();
|
|
18
|
+
const hasCloudflared = checkBinary("cloudflared");
|
|
19
|
+
const hasNgrok = checkBinary("ngrok");
|
|
20
|
+
process.stdout.write("CoSpace CLI installed.\n");
|
|
21
|
+
if (nodeMajor < 20) {
|
|
22
|
+
process.stdout.write(`Warning: Node.js ${process.versions.node} detected. Node.js 20+ is recommended.\n`);
|
|
23
|
+
}
|
|
24
|
+
process.stdout.write(`Tunnel helpers: cloudflared=${hasCloudflared ? "found" : "missing"}, ngrok=${hasNgrok ? "found" : "missing"}\n`);
|
|
25
|
+
process.stdout.write("Next: run `cospace quickstart` (or `cospace init`) to configure your first workspace.\n");
|
|
26
|
+
//# sourceMappingURL=postinstall.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"postinstall.js","sourceRoot":"","sources":["../src/postinstall.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAE/C,SAAS,WAAW,CAAC,MAAc;IACjC,MAAM,MAAM,GAAG,SAAS,CAAC,MAAM,EAAE,CAAC,WAAW,CAAC,EAAE;QAC9C,QAAQ,EAAE,MAAM;QAChB,KAAK,EAAE,QAAQ;KAChB,CAAC,CAAC;IACH,OAAO,MAAM,CAAC,MAAM,KAAK,CAAC,CAAC;AAC7B,CAAC;AAED,SAAS,gBAAgB;IACvB,MAAM,KAAK,GAAG,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;IACtD,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO,CAAC,CAAC;IACX,CAAC;IACD,OAAO,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AACvC,CAAC;AAED,MAAM,SAAS,GAAG,gBAAgB,EAAE,CAAC;AACrC,MAAM,cAAc,GAAG,WAAW,CAAC,aAAa,CAAC,CAAC;AAClD,MAAM,QAAQ,GAAG,WAAW,CAAC,OAAO,CAAC,CAAC;AAEtC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,0BAA0B,CAAC,CAAC;AACjD,IAAI,SAAS,GAAG,EAAE,EAAE,CAAC;IACnB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,oBAAoB,OAAO,CAAC,QAAQ,CAAC,IAAI,0CAA0C,CAAC,CAAC;AAC5G,CAAC;AACD,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,+BAA+B,cAAc,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,WAAW,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,IAAI,CACjH,CAAC;AACF,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,yFAAyF,CAAC,CAAC"}
|
package/dist/tunnel.d.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { TunnelProvider } from "@cospacehq/shared";
|
|
2
|
+
export type TunnelSession = {
|
|
3
|
+
publicUrl: string;
|
|
4
|
+
provider: TunnelProvider;
|
|
5
|
+
stop: () => Promise<void>;
|
|
6
|
+
};
|
|
7
|
+
export declare function maybeStartTunnel(input: {
|
|
8
|
+
provider: TunnelProvider;
|
|
9
|
+
apiKey?: string;
|
|
10
|
+
localUrl: string;
|
|
11
|
+
port: number;
|
|
12
|
+
noTunnel: boolean;
|
|
13
|
+
}): Promise<TunnelSession | null>;
|
|
14
|
+
export declare function tunnelDoctor(provider: TunnelProvider): Promise<{
|
|
15
|
+
ok: boolean;
|
|
16
|
+
detail: string;
|
|
17
|
+
}>;
|
|
18
|
+
//# sourceMappingURL=tunnel.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tunnel.d.ts","sourceRoot":"","sources":["../src/tunnel.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAExD,MAAM,MAAM,aAAa,GAAG;IAC1B,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,cAAc,CAAC;IACzB,IAAI,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC3B,CAAC;AAwGF,wBAAsB,gBAAgB,CAAC,KAAK,EAAE;IAC5C,QAAQ,EAAE,cAAc,CAAC;IACzB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,OAAO,CAAC;CACnB,GAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC,CAUhC;AAED,wBAAsB,YAAY,CAAC,QAAQ,EAAE,cAAc,GAAG,OAAO,CAAC;IAAE,EAAE,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CAWrG"}
|