@rubytech/create-maxy-code 0.1.108 → 0.1.110
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 +11 -125
- package/dist/snap-chromium.js +1 -2
- package/dist/uninstall.js +10 -9
- package/package.json +1 -1
- package/payload/platform/plugins/admin/PLUGIN.md +1 -0
- package/payload/platform/plugins/admin/mcp/dist/index.js +1 -1
- package/payload/platform/plugins/admin/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/admin/skills/upgrade/SKILL.md +34 -0
- package/payload/platform/plugins/cloudflare/.claude-plugin/plugin.json +1 -1
- package/payload/platform/plugins/cloudflare/PLUGIN.md +9 -16
- package/payload/platform/plugins/cloudflare/mcp/dist/index.js +7 -12
- package/payload/platform/plugins/cloudflare/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/cloudflare/references/dashboard-guide.md +3 -3
- package/payload/platform/plugins/cloudflare/references/manual-setup.md +16 -51
- package/payload/platform/plugins/cloudflare/references/reset-guide.md +24 -25
- package/payload/platform/plugins/cloudflare/skills/setup-tunnel/SKILL.md +29 -144
- package/payload/platform/plugins/docs/references/admin-session.md +1 -1
- package/payload/platform/plugins/docs/references/admin-ui.md +1 -1
- package/payload/platform/plugins/docs/references/cloudflare.md +20 -29
- package/payload/platform/plugins/docs/references/platform.md +4 -22
- package/payload/platform/plugins/docs/references/plugins-guide.md +1 -1
- package/payload/platform/plugins/docs/references/troubleshooting.md +4 -316
- package/payload/platform/plugins/venture-studio/PLUGIN.md +35 -4
- package/payload/platform/plugins/venture-studio/bin/scaffold.sh +104 -0
- package/payload/platform/plugins/venture-studio/skills/investor-data-room/SKILL.md +3 -1
- package/payload/platform/plugins/work/mcp/dist/cli/project-create-cli.d.ts +2 -0
- package/payload/platform/plugins/work/mcp/dist/cli/project-create-cli.d.ts.map +1 -0
- package/payload/platform/plugins/work/mcp/dist/cli/project-create-cli.js +78 -0
- package/payload/platform/plugins/work/mcp/dist/cli/project-create-cli.js.map +1 -0
- package/payload/platform/scripts/check-no-task-id-leaks.mjs +1 -1
- package/payload/platform/scripts/vnc.sh +4 -3
- package/payload/platform/templates/agents/admin/IDENTITY.md +1 -1
- package/payload/premium-plugins/venture-studio/PLUGIN.md +35 -4
- package/payload/premium-plugins/venture-studio/bin/scaffold.sh +104 -0
- package/payload/premium-plugins/venture-studio/skills/investor-data-room/SKILL.md +3 -1
- package/payload/server/{chunk-AGFS3TVN.js → chunk-FSPPVVWM.js} +1303 -496
- package/payload/server/maxy-edge.js +21 -259
- package/payload/server/public/assets/{ChatInput-DJsqm_Gf.js → ChatInput-CsnIedhS.js} +1 -5
- package/payload/server/public/assets/{Checkbox-DGZG9BKc.js → Checkbox-CWugFyFT.js} +1 -1
- package/payload/server/public/assets/admin-D3gZuyUn.js +217 -0
- package/payload/server/public/assets/{architectureDiagram-Q4EWVU46-Dw16BhiX.js → architectureDiagram-Q4EWVU46-CeTRKWDb.js} +1 -1
- package/payload/server/public/assets/{blockDiagram-DXYQGD6D-DIOpmf5Y.js → blockDiagram-DXYQGD6D-DeeIX5U3.js} +1 -1
- package/payload/server/public/assets/{c4Diagram-AHTNJAMY-Tdb_HZeX.js → c4Diagram-AHTNJAMY-CFsqZuil.js} +1 -1
- package/payload/server/public/assets/channel-CrSx5mnG.js +1 -0
- package/payload/server/public/assets/{chunk-336JU56O-CebpwDDe.js → chunk-336JU56O-DpIXuFM0.js} +2 -2
- package/payload/server/public/assets/{chunk-426QAEUC-BtRCmfDU.js → chunk-426QAEUC-Qk8qqrvA.js} +1 -1
- package/payload/server/public/assets/{chunk-4TB4RGXK-BZ3GEWs3.js → chunk-4TB4RGXK-DtM8-CUn.js} +1 -1
- package/payload/server/public/assets/{chunk-5FUZZQ4R-iDI6Xu0U.js → chunk-5FUZZQ4R-CrSQ4ySU.js} +1 -1
- package/payload/server/public/assets/{chunk-5PVQY5BW-SQD_EpYa.js → chunk-5PVQY5BW-Bn2nQwdj.js} +1 -1
- package/payload/server/public/assets/{chunk-EDXVE4YY-CtCcA7_e.js → chunk-EDXVE4YY-CzCPnR0P.js} +1 -1
- package/payload/server/public/assets/{chunk-ENJZ2VHE-pXVGVCbb.js → chunk-ENJZ2VHE-CgZj9RoG.js} +1 -1
- package/payload/server/public/assets/{chunk-ICPOFSXX-Dkzg9o2N.js → chunk-ICPOFSXX-wy-eNjwW.js} +1 -1
- package/payload/server/public/assets/{chunk-OYMX7WX6-1ZZWzf9F.js → chunk-OYMX7WX6-CMmJtL8S.js} +1 -1
- package/payload/server/public/assets/{chunk-U2HBQHQK-CpQ3kzO0.js → chunk-U2HBQHQK-CFCW7OaT.js} +1 -1
- package/payload/server/public/assets/{chunk-X2U36JSP-C2LkxroC.js → chunk-X2U36JSP-Bgh-CJSN.js} +1 -1
- package/payload/server/public/assets/{chunk-YZCP3GAM-Bl5jBOt5.js → chunk-YZCP3GAM-BXKwZ4vN.js} +1 -1
- package/payload/server/public/assets/{chunk-ZZ45TVLE-CHtnptPS.js → chunk-ZZ45TVLE-BiOuK5NP.js} +1 -1
- package/payload/server/public/assets/classDiagram-6PBFFD2Q-C3IDJsqN.js +1 -0
- package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-BOIrJ5Zb.js +1 -0
- package/payload/server/public/assets/clone-P8Fkz7JD.js +1 -0
- package/payload/server/public/assets/{dagre-BziN0Nkh.js → dagre-DyCxa9Q2.js} +1 -1
- package/payload/server/public/assets/{dagre-KV5264BT-B7OG1g1Y.js → dagre-KV5264BT-Cffo_hmf.js} +1 -1
- package/payload/server/public/assets/data-DRfwJPja.js +1 -0
- package/payload/server/public/assets/{diagram-5BDNPKRD-Bf31nIDs.js → diagram-5BDNPKRD-Bt93Du3V.js} +1 -1
- package/payload/server/public/assets/{diagram-G4DWMVQ6-DQu85hhH.js → diagram-G4DWMVQ6-v4r-tBsC.js} +1 -1
- package/payload/server/public/assets/{diagram-MMDJMWI5-5tstbs4y.js → diagram-MMDJMWI5-DKrVPOP-.js} +1 -1
- package/payload/server/public/assets/{diagram-TYMM5635--MOV1U4o.js → diagram-TYMM5635-B1PzWQb9.js} +1 -1
- package/payload/server/public/assets/{erDiagram-SMLLAGMA-BtAnOJmd.js → erDiagram-SMLLAGMA-ClQzsQAs.js} +1 -1
- package/payload/server/public/assets/{flowDiagram-DWJPFMVM-CybiCIih.js → flowDiagram-DWJPFMVM-h3IbpN_7.js} +1 -1
- package/payload/server/public/assets/{ganttDiagram-T4ZO3ILL-B44jN7Cy.js → ganttDiagram-T4ZO3ILL-ClaxOJi8.js} +1 -1
- package/payload/server/public/assets/{gitGraphDiagram-UUTBAWPF-CT7iYcwg.js → gitGraphDiagram-UUTBAWPF-pM-U4ClD.js} +1 -1
- package/payload/server/public/assets/graph-B4FFYwus.js +1 -0
- package/payload/server/public/assets/graph-labels-Cpk9Ktt0.js +1 -0
- package/payload/server/public/assets/{graphlib-DP4o0pYL.js → graphlib-CwimOv_M.js} +1 -1
- package/payload/server/public/assets/{infoDiagram-42DDH7IO-CvxFpFHN.js → infoDiagram-42DDH7IO-DcO3Giwe.js} +1 -1
- package/payload/server/public/assets/{ishikawaDiagram-UXIWVN3A-CUwWLPeR.js → ishikawaDiagram-UXIWVN3A-BcdSL5VS.js} +1 -1
- package/payload/server/public/assets/{journeyDiagram-VCZTEJTY-y-OnGgLi.js → journeyDiagram-VCZTEJTY-CYahHYzf.js} +1 -1
- package/payload/server/public/assets/{kanban-definition-6JOO6SKY-BhrSe8R4.js → kanban-definition-6JOO6SKY-Cl5KhoS4.js} +1 -1
- package/payload/server/public/assets/lib--yuBd0Xi.js +33 -0
- package/payload/server/public/assets/{line-C9uS7z4J.js → line-d_2oTxLp.js} +1 -1
- package/payload/server/public/assets/{mermaid-parser.core-Cg4ZdKp-.js → mermaid-parser.core-CMMDGv3x.js} +1 -1
- package/payload/server/public/assets/{mermaid.core-BHdKOsex.js → mermaid.core-DK9ENGbr.js} +3 -3
- package/payload/server/public/assets/{mindmap-definition-QFDTVHPH-NBYiXHo7.js → mindmap-definition-QFDTVHPH-mA3x3MFG.js} +1 -1
- package/payload/server/public/assets/page-CgDmg_fX.js +1 -0
- package/payload/server/public/assets/{page-D9YpwhIu.js → page-D9lluVl7.js} +2 -2
- package/payload/server/public/assets/{pieDiagram-DEJITSTG-CbojC64C.js → pieDiagram-DEJITSTG-CW1nGFlY.js} +1 -1
- package/payload/server/public/assets/public-DdLMkNdS.js +7 -0
- package/payload/server/public/assets/{quadrantDiagram-34T5L4WZ-CnnoZXcL.js → quadrantDiagram-34T5L4WZ-DI5igJhR.js} +1 -1
- package/payload/server/public/assets/{requirementDiagram-MS252O5E-DFRFRtyJ.js → requirementDiagram-MS252O5E-DyVeI4e_.js} +1 -1
- package/payload/server/public/assets/{sankeyDiagram-XADWPNL6-DU5gcpzO.js → sankeyDiagram-XADWPNL6-CCTTBYKY.js} +1 -1
- package/payload/server/public/assets/{sequenceDiagram-FGHM5R23-BN7HZ6Hq.js → sequenceDiagram-FGHM5R23-hVVf35ly.js} +1 -1
- package/payload/server/public/assets/{stateDiagram-FHFEXIEX-DG6cCjvg.js → stateDiagram-FHFEXIEX-CSLuQDUX.js} +1 -1
- package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-C5JejhQU.js +1 -0
- package/payload/server/public/assets/{timeline-definition-GMOUNBTQ-qmV-8SEV.js → timeline-definition-GMOUNBTQ-sxC3W8Q4.js} +1 -1
- package/payload/server/public/assets/{vennDiagram-DHZGUBPP-BMXQ1s3n.js → vennDiagram-DHZGUBPP-Ro-ton6Z.js} +1 -1
- package/payload/server/public/assets/{wardleyDiagram-NUSXRM2D-CoAdP1Gw.js → wardleyDiagram-NUSXRM2D-T-dKD0Zx.js} +1 -1
- package/payload/server/public/assets/{xychartDiagram-5P7HB3ND-CZlfGTEn.js → xychartDiagram-5P7HB3ND-CfProPts.js} +1 -1
- package/payload/server/public/data.html +4 -4
- package/payload/server/public/graph.html +5 -5
- package/payload/server/public/index.html +7 -7
- package/payload/server/public/public.html +4 -4
- package/payload/server/server.js +299 -1392
- package/payload/platform/plugins/cloudflare/scripts/__tests__/tunnel-ingress.test.ts +0 -241
- package/payload/platform/plugins/cloudflare/scripts/_stream-log.sh +0 -154
- package/payload/platform/plugins/cloudflare/scripts/list-cf-domains.sh +0 -98
- package/payload/platform/plugins/cloudflare/scripts/list-cf-domains.ts +0 -749
- package/payload/platform/plugins/cloudflare/scripts/reset-tunnel.sh +0 -107
- package/payload/platform/plugins/cloudflare/scripts/setup-tunnel.sh +0 -854
- package/payload/platform/plugins/cloudflare/scripts/tunnel-ingress.ts +0 -291
- package/payload/server/chunk-BDFOTLPW.js +0 -759
- package/payload/server/chunk-JRBCOVA4.js +0 -1305
- package/payload/server/cloudflare-task-tracker-M5ONAGUT.js +0 -22
- package/payload/server/public/assets/admin-BvzMvMGo.js +0 -217
- package/payload/server/public/assets/channel-DThrH4QF.js +0 -1
- package/payload/server/public/assets/classDiagram-6PBFFD2Q-BC6oGTNX.js +0 -1
- package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-COwC5Umh.js +0 -1
- package/payload/server/public/assets/clone-Chp7hvnA.js +0 -1
- package/payload/server/public/assets/data-BAgaPs4j.js +0 -1
- package/payload/server/public/assets/graph-Cma7EArf.js +0 -1
- package/payload/server/public/assets/graph-labels-DyKk6Sxf.js +0 -1
- package/payload/server/public/assets/lib-CpkYtEDz.js +0 -29
- package/payload/server/public/assets/page-B4IWl3aZ.js +0 -1
- package/payload/server/public/assets/public-BtOXjy3A.js +0 -8
- package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-CvVd1Q_q.js +0 -1
|
@@ -1,241 +0,0 @@
|
|
|
1
|
-
// acceptance grid for tunnel-ingress.ts pure layer.
|
|
2
|
-
//
|
|
3
|
-
// Runs under `node --test --experimental-strip-types` (no compile step). No
|
|
4
|
-
// filesystem reads except via temp files written by the test itself; no
|
|
5
|
-
// network; no shell-outs. Mirrors apt-resolve / samba-provision style.
|
|
6
|
-
|
|
7
|
-
import test from "node:test";
|
|
8
|
-
import assert from "node:assert/strict";
|
|
9
|
-
import { mkdtempSync, writeFileSync, rmSync } from "node:fs";
|
|
10
|
-
import { join } from "node:path";
|
|
11
|
-
import { tmpdir } from "node:os";
|
|
12
|
-
import {
|
|
13
|
-
renderConfigYml,
|
|
14
|
-
renderTunnelState,
|
|
15
|
-
readPersistedHostnames,
|
|
16
|
-
probeSambaStanza,
|
|
17
|
-
renderAccessPolicyActionRequired,
|
|
18
|
-
type IngressSpec,
|
|
19
|
-
type TunnelState,
|
|
20
|
-
} from "../tunnel-ingress.ts";
|
|
21
|
-
|
|
22
|
-
// ---------------------------------------------------------------------------
|
|
23
|
-
// renderConfigYml
|
|
24
|
-
// ---------------------------------------------------------------------------
|
|
25
|
-
|
|
26
|
-
test("renderConfigYml: HTTPS-only matches expected shape byte-for-byte", () => {
|
|
27
|
-
const spec: IngressSpec = {
|
|
28
|
-
tunnelId: "abc-123",
|
|
29
|
-
credentialsPath: "/home/admin/.maxy/cloudflared/abc-123.json",
|
|
30
|
-
httpPort: 19200,
|
|
31
|
-
httpHostnames: ["admin.maxy.bot", "public.maxy.bot"],
|
|
32
|
-
};
|
|
33
|
-
assert.equal(
|
|
34
|
-
renderConfigYml(spec),
|
|
35
|
-
[
|
|
36
|
-
"tunnel: abc-123",
|
|
37
|
-
"credentials-file: /home/admin/.maxy/cloudflared/abc-123.json",
|
|
38
|
-
"ingress:",
|
|
39
|
-
" - hostname: admin.maxy.bot",
|
|
40
|
-
" service: http://localhost:19200",
|
|
41
|
-
" - hostname: public.maxy.bot",
|
|
42
|
-
" service: http://localhost:19200",
|
|
43
|
-
" - service: http_status:404",
|
|
44
|
-
"",
|
|
45
|
-
].join("\n"),
|
|
46
|
-
);
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
test("renderConfigYml: SSH+SMB appear AFTER http hostnames and BEFORE catch-all", () => {
|
|
50
|
-
const spec: IngressSpec = {
|
|
51
|
-
tunnelId: "t-id",
|
|
52
|
-
credentialsPath: "/creds.json",
|
|
53
|
-
httpPort: 19200,
|
|
54
|
-
httpHostnames: ["admin.maxy.bot"],
|
|
55
|
-
sshHostname: "ssh.maxy.bot",
|
|
56
|
-
smbHostname: "smb.maxy.bot",
|
|
57
|
-
};
|
|
58
|
-
const out = renderConfigYml(spec);
|
|
59
|
-
const idxHttp = out.indexOf("admin.maxy.bot");
|
|
60
|
-
const idxSsh = out.indexOf("ssh.maxy.bot");
|
|
61
|
-
const idxSmb = out.indexOf("smb.maxy.bot");
|
|
62
|
-
const idx404 = out.indexOf("http_status:404");
|
|
63
|
-
assert.ok(idxHttp < idxSsh, "HTTP before SSH");
|
|
64
|
-
assert.ok(idxSsh < idxSmb, "SSH before SMB");
|
|
65
|
-
assert.ok(idxSmb < idx404, "SMB before catch-all 404");
|
|
66
|
-
assert.match(out, /\s+service: ssh:\/\/localhost:22$/m);
|
|
67
|
-
assert.match(out, /\s+service: tcp:\/\/localhost:445$/m);
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
test("renderConfigYml: SSH only — no SMB block when smbHostname is null", () => {
|
|
71
|
-
const spec: IngressSpec = {
|
|
72
|
-
tunnelId: "t-id",
|
|
73
|
-
credentialsPath: "/creds.json",
|
|
74
|
-
httpPort: 19200,
|
|
75
|
-
httpHostnames: ["admin.maxy.bot"],
|
|
76
|
-
sshHostname: "ssh.maxy.bot",
|
|
77
|
-
smbHostname: null,
|
|
78
|
-
};
|
|
79
|
-
const out = renderConfigYml(spec);
|
|
80
|
-
assert.ok(out.includes("ssh.maxy.bot"));
|
|
81
|
-
assert.ok(!out.includes("tcp://localhost:445"));
|
|
82
|
-
});
|
|
83
|
-
|
|
84
|
-
test("renderConfigYml: empty string hostnames are treated as absent", () => {
|
|
85
|
-
const spec: IngressSpec = {
|
|
86
|
-
tunnelId: "t-id",
|
|
87
|
-
credentialsPath: "/creds.json",
|
|
88
|
-
httpPort: 19200,
|
|
89
|
-
httpHostnames: ["admin.maxy.bot"],
|
|
90
|
-
sshHostname: "",
|
|
91
|
-
smbHostname: "",
|
|
92
|
-
};
|
|
93
|
-
const out = renderConfigYml(spec);
|
|
94
|
-
assert.ok(!out.includes("ssh://localhost:22"));
|
|
95
|
-
assert.ok(!out.includes("tcp://localhost:445"));
|
|
96
|
-
});
|
|
97
|
-
|
|
98
|
-
// ---------------------------------------------------------------------------
|
|
99
|
-
// renderTunnelState
|
|
100
|
-
// ---------------------------------------------------------------------------
|
|
101
|
-
|
|
102
|
-
test("renderTunnelState: base fields preserved when ssh/smb absent", () => {
|
|
103
|
-
const state: TunnelState = {
|
|
104
|
-
tunnelId: "abc",
|
|
105
|
-
tunnelName: "maxy",
|
|
106
|
-
domain: "admin.maxy.bot",
|
|
107
|
-
configPath: "/home/admin/.maxy/cloudflared/config.yml",
|
|
108
|
-
credentialsPath: "/home/admin/.maxy/cloudflared/abc.json",
|
|
109
|
-
};
|
|
110
|
-
const parsed = JSON.parse(renderTunnelState(state));
|
|
111
|
-
assert.deepEqual(parsed, {
|
|
112
|
-
tunnelId: "abc",
|
|
113
|
-
tunnelName: "maxy",
|
|
114
|
-
domain: "admin.maxy.bot",
|
|
115
|
-
configPath: "/home/admin/.maxy/cloudflared/config.yml",
|
|
116
|
-
credentialsPath: "/home/admin/.maxy/cloudflared/abc.json",
|
|
117
|
-
});
|
|
118
|
-
});
|
|
119
|
-
|
|
120
|
-
test("renderTunnelState: ssh/smb hostnames persist when present", () => {
|
|
121
|
-
const state: TunnelState = {
|
|
122
|
-
tunnelId: "abc",
|
|
123
|
-
tunnelName: "maxy",
|
|
124
|
-
domain: "admin.maxy.bot",
|
|
125
|
-
configPath: "/cfg.yml",
|
|
126
|
-
credentialsPath: "/creds.json",
|
|
127
|
-
sshHostname: "ssh.maxy.bot",
|
|
128
|
-
smbHostname: "smb.maxy.bot",
|
|
129
|
-
};
|
|
130
|
-
const parsed = JSON.parse(renderTunnelState(state));
|
|
131
|
-
assert.equal(parsed.sshHostname, "ssh.maxy.bot");
|
|
132
|
-
assert.equal(parsed.smbHostname, "smb.maxy.bot");
|
|
133
|
-
});
|
|
134
|
-
|
|
135
|
-
// ---------------------------------------------------------------------------
|
|
136
|
-
// readPersistedHostnames
|
|
137
|
-
// ---------------------------------------------------------------------------
|
|
138
|
-
|
|
139
|
-
test("readPersistedHostnames: returns nulls when file missing", () => {
|
|
140
|
-
const got = readPersistedHostnames("/nope/does/not/exist.json");
|
|
141
|
-
assert.deepEqual(got, { sshHostname: null, smbHostname: null });
|
|
142
|
-
});
|
|
143
|
-
|
|
144
|
-
test("readPersistedHostnames: round-trips ssh/smb hostnames from disk", () => {
|
|
145
|
-
const dir = mkdtempSync(join(tmpdir(), "tunnel-state-"));
|
|
146
|
-
const path = join(dir, "tunnel.state");
|
|
147
|
-
try {
|
|
148
|
-
writeFileSync(
|
|
149
|
-
path,
|
|
150
|
-
JSON.stringify({
|
|
151
|
-
tunnelId: "abc",
|
|
152
|
-
tunnelName: "maxy",
|
|
153
|
-
domain: "admin.maxy.bot",
|
|
154
|
-
configPath: "/cfg.yml",
|
|
155
|
-
credentialsPath: "/creds.json",
|
|
156
|
-
sshHostname: "ssh.maxy.bot",
|
|
157
|
-
smbHostname: "smb.maxy.bot",
|
|
158
|
-
}),
|
|
159
|
-
);
|
|
160
|
-
const got = readPersistedHostnames(path);
|
|
161
|
-
assert.deepEqual(got, { sshHostname: "ssh.maxy.bot", smbHostname: "smb.maxy.bot" });
|
|
162
|
-
} finally {
|
|
163
|
-
rmSync(dir, { recursive: true, force: true });
|
|
164
|
-
}
|
|
165
|
-
});
|
|
166
|
-
|
|
167
|
-
test("readPersistedHostnames: malformed JSON returns nulls (no throw)", () => {
|
|
168
|
-
const dir = mkdtempSync(join(tmpdir(), "tunnel-state-bad-"));
|
|
169
|
-
const path = join(dir, "tunnel.state");
|
|
170
|
-
try {
|
|
171
|
-
writeFileSync(path, "not json");
|
|
172
|
-
assert.deepEqual(readPersistedHostnames(path), { sshHostname: null, smbHostname: null });
|
|
173
|
-
} finally {
|
|
174
|
-
rmSync(dir, { recursive: true, force: true });
|
|
175
|
-
}
|
|
176
|
-
});
|
|
177
|
-
|
|
178
|
-
// ---------------------------------------------------------------------------
|
|
179
|
-
// probeSambaStanza
|
|
180
|
-
// ---------------------------------------------------------------------------
|
|
181
|
-
|
|
182
|
-
test("probeSambaStanza: true when [<brand>] header present", () => {
|
|
183
|
-
const dir = mkdtempSync(join(tmpdir(), "smb-probe-"));
|
|
184
|
-
const path = join(dir, "smb.conf");
|
|
185
|
-
try {
|
|
186
|
-
writeFileSync(path, "[global]\nworkgroup = WORKGROUP\n\n[maxy]\n path = /home/admin\n");
|
|
187
|
-
assert.equal(probeSambaStanza("maxy", path), true);
|
|
188
|
-
} finally {
|
|
189
|
-
rmSync(dir, { recursive: true, force: true });
|
|
190
|
-
}
|
|
191
|
-
});
|
|
192
|
-
|
|
193
|
-
test("probeSambaStanza: false when only peer brand present (isolation)", () => {
|
|
194
|
-
const dir = mkdtempSync(join(tmpdir(), "smb-probe-peer-"));
|
|
195
|
-
const path = join(dir, "smb.conf");
|
|
196
|
-
try {
|
|
197
|
-
writeFileSync(path, "[global]\n\n[realagent]\n path = /home/admin\n");
|
|
198
|
-
assert.equal(probeSambaStanza("maxy", path), false);
|
|
199
|
-
} finally {
|
|
200
|
-
rmSync(dir, { recursive: true, force: true });
|
|
201
|
-
}
|
|
202
|
-
});
|
|
203
|
-
|
|
204
|
-
test("probeSambaStanza: false when smb.conf missing", () => {
|
|
205
|
-
assert.equal(probeSambaStanza("maxy", "/nope/smb.conf"), false);
|
|
206
|
-
});
|
|
207
|
-
|
|
208
|
-
test("probeSambaStanza: brand names with regex meta characters are escaped", () => {
|
|
209
|
-
const dir = mkdtempSync(join(tmpdir(), "smb-probe-regex-"));
|
|
210
|
-
const path = join(dir, "smb.conf");
|
|
211
|
-
try {
|
|
212
|
-
writeFileSync(path, "[some.brand]\n path = /x\n");
|
|
213
|
-
assert.equal(probeSambaStanza("some.brand", path), true);
|
|
214
|
-
assert.equal(probeSambaStanza("someXbrand", path), false);
|
|
215
|
-
} finally {
|
|
216
|
-
rmSync(dir, { recursive: true, force: true });
|
|
217
|
-
}
|
|
218
|
-
});
|
|
219
|
-
|
|
220
|
-
// ---------------------------------------------------------------------------
|
|
221
|
-
// renderAccessPolicyActionRequired
|
|
222
|
-
// ---------------------------------------------------------------------------
|
|
223
|
-
|
|
224
|
-
test("renderAccessPolicyActionRequired: empty string when neither hostname set", () => {
|
|
225
|
-
assert.equal(
|
|
226
|
-
renderAccessPolicyActionRequired({ operatorEmail: "x@y.com" }),
|
|
227
|
-
"",
|
|
228
|
-
);
|
|
229
|
-
});
|
|
230
|
-
|
|
231
|
-
test("renderAccessPolicyActionRequired: lists each hostname with operator email", () => {
|
|
232
|
-
const out = renderAccessPolicyActionRequired({
|
|
233
|
-
sshHostname: "ssh.maxy.bot",
|
|
234
|
-
smbHostname: "smb.maxy.bot",
|
|
235
|
-
operatorEmail: "joel@example.com",
|
|
236
|
-
});
|
|
237
|
-
assert.match(out, /SSH: ssh\.maxy\.bot/);
|
|
238
|
-
assert.match(out, /SMB: smb\.maxy\.bot/);
|
|
239
|
-
assert.match(out, /Emails: joel@example\.com/);
|
|
240
|
-
assert.match(out, /Zero Trust → Access → Applications/);
|
|
241
|
-
});
|
|
@@ -1,154 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bash
|
|
2
|
-
# Shared stream-log helpers sourced by setup-tunnel.sh and reset-tunnel.sh.
|
|
3
|
-
#
|
|
4
|
-
# The platform exposes STREAM_LOG_PATH in the `claude` spawn env;
|
|
5
|
-
# the Bash-tool subprocess inherits it, and opt-in scripts call these
|
|
6
|
-
# helpers to emit phase lines and tee subprocess output into the same
|
|
7
|
-
# per-conversation file the chat UI's server-side tailer reads.
|
|
8
|
-
#
|
|
9
|
-
# Contract (read by platform/ui/app/lib/script-stream-tailer.ts tailer and
|
|
10
|
-
# .docs/web-chat.md):
|
|
11
|
-
# [<ISO-ts>] [script:<scope>] <kv …>
|
|
12
|
-
# [<ISO-ts>] [script:<scope>:<subprocess-tag>] <raw line>
|
|
13
|
-
# Canonical regex — SCRIPT_STREAM_RE at platform/ui/app/lib/script-stream-tailer.ts:
|
|
14
|
-
# ^\[([^\]]+)\] \[script:([a-z][a-z0-9-]*)((?::[a-z0-9:_-]+)?)\] (.*)$
|
|
15
|
-
# The literal `script:` prefix is the chat-surface namespace. It
|
|
16
|
-
# separates chat-surface emitters from log-file-only scopes (`[mcp:<server>]`
|
|
17
|
-
# from mcp-stderr-tee, `[init]` / `[api-wait-*]` / `[mcp-init-error]` /
|
|
18
|
-
# `[subproc-stderr]` / `[compaction-*]` from claude-agent.ts) which share
|
|
19
|
-
# the same per-conversation stream log but must NOT reach the chat UI.
|
|
20
|
-
# Callers of phase_line / tee_subprocess / tee_subprocess_capture pass the
|
|
21
|
-
# bare scope (e.g. `setup-tunnel`, `list-cf-domains`, `reset-tunnel:cloudflared`);
|
|
22
|
-
# these helpers prepend `script:` to the stream-log write. Stderr mirrors
|
|
23
|
-
# stay unprefixed — stderr is for direct-SSH operators and route-handler
|
|
24
|
-
# `reason=<enum>` regex, not the chat-surface contract.
|
|
25
|
-
# <scope> is any `[a-z][a-z0-9-]*` token
|
|
26
|
-
# pre-592 enum `setup-tunnel|reset-tunnel`, which silently filtered out the
|
|
27
|
-
# `[list-cf-domains]` lines). <subprocess-tag> may contain
|
|
28
|
-
# lowercase, digits, `-`, `_`, `:`. Adding a new chat-surface scope requires
|
|
29
|
-
# no edit to the regex — the shape is the only contract. Any prefix-shape
|
|
30
|
-
# change must be made on both sides (this helper + script-stream-tailer.ts)
|
|
31
|
-
# atomically.
|
|
32
|
-
#
|
|
33
|
-
# Inner layers (e.g. a node/python helper a.sh wrapper spawns — the
|
|
34
|
-
# `list-cf-domains.sh` → `list-cf-domains.ts` pattern) must write phase lines
|
|
35
|
-
# directly to STREAM_LOG_PATH with the same prefix shape (including the
|
|
36
|
-
# `script:` namespace): stderr alone is silently discarded by runFormSpawn on
|
|
37
|
-
# exit 0. The build-gate `platform/ui/scripts/check-stream-log-contract.mjs`
|
|
38
|
-
# enforces this by rejecting any.sh under `platform/plugins/*/scripts/`
|
|
39
|
-
# that sources this helper and invokes an interpreter subprocess whose target
|
|
40
|
-
# does not pair a STREAM_LOG_PATH env read with an append/write call. Opt out
|
|
41
|
-
# per invocation with `# stream-log-contract: stderr-only (reason: <prose>)`.
|
|
42
|
-
|
|
43
|
-
# Exit 1 loudly with the variable name and the invoking scope so direct-SSH
|
|
44
|
-
# invocations fail fast and the operator reads exactly what to set. No
|
|
45
|
-
# silent fallback — criterion 4 of.
|
|
46
|
-
require_stream_log_path() {
|
|
47
|
-
local scope="$1"
|
|
48
|
-
if [ -z "${STREAM_LOG_PATH:-}" ]; then
|
|
49
|
-
echo "ERROR [${scope}]: STREAM_LOG_PATH environment variable is unset." >&2
|
|
50
|
-
echo " This script tees subprocess output into a per-conversation" >&2
|
|
51
|
-
echo " stream log; it is meaningless without a target path." >&2
|
|
52
|
-
echo " The platform sets STREAM_LOG_PATH automatically for every" >&2
|
|
53
|
-
echo " \`claude\` spawn. If you are invoking this" >&2
|
|
54
|
-
echo " script by hand, export it yourself, for example:" >&2
|
|
55
|
-
echo " export STREAM_LOG_PATH=\"\${HOME}/.maxy/logs/manual-invocation.log\"" >&2
|
|
56
|
-
exit 1
|
|
57
|
-
fi
|
|
58
|
-
mkdir -p "$(dirname "${STREAM_LOG_PATH}")"
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
# ISO-8601 UTC timestamp with millisecond precision.
|
|
62
|
-
stream_log_ts() {
|
|
63
|
-
date -u +"%Y-%m-%dT%H:%M:%S.%3NZ"
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
# Append one phase line to STREAM_LOG_PATH AND echo to stderr so the Bash
|
|
67
|
-
# tool's stderr capture carries it. Both paths matter: the stream log is
|
|
68
|
-
# the live tailer surface; stderr is the exit-time Bash-tool surface.
|
|
69
|
-
#
|
|
70
|
-
# The stream-log write carries the `script:` chat-surface namespace;
|
|
71
|
-
# the stderr mirror stays unprefixed because stderr is read by direct-SSH
|
|
72
|
-
# operators and the route-handler `reason=<enum>` regex, not the chat UI.
|
|
73
|
-
#
|
|
74
|
-
# Usage: phase_line <scope> <key=value …>
|
|
75
|
-
phase_line() {
|
|
76
|
-
local scope="$1"; shift
|
|
77
|
-
local ts
|
|
78
|
-
ts="$(stream_log_ts)"
|
|
79
|
-
printf '[%s] [script:%s] %s\n' "${ts}" "${scope}" "$*" >> "${STREAM_LOG_PATH}"
|
|
80
|
-
printf '[%s] %s\n' "${scope}" "$*" >&2
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
# Tee a subprocess's combined stdout+stderr into STREAM_LOG_PATH line-by-line
|
|
84
|
-
# with the given tag, mirroring each line to stderr for the Bash tool.
|
|
85
|
-
# Returns the subprocess's exit code.
|
|
86
|
-
#
|
|
87
|
-
# Use for fire-and-forget subprocesses whose stdout does NOT need to be
|
|
88
|
-
# captured by the caller (the caller only cares about the exit code).
|
|
89
|
-
# For subprocesses whose stdout the caller must parse (e.g. JSON output
|
|
90
|
-
# feeding `jq`), use `tee_subprocess_capture` instead.
|
|
91
|
-
#
|
|
92
|
-
# Usage: tee_subprocess <tag> -- <cmd> <args …>
|
|
93
|
-
# Example: tee_subprocess reset-tunnel:cloudflared -- cloudflared --origincert … tunnel delete my-tunnel
|
|
94
|
-
#
|
|
95
|
-
# stdbuf forces line buffering; without it cloudflared holds its stdout in
|
|
96
|
-
# libc's 8 KB buffer until exit and the ≤ 1 s latency criterion fails.
|
|
97
|
-
tee_subprocess() {
|
|
98
|
-
local tag="$1"; shift
|
|
99
|
-
if [ "${1:-}" != "--" ]; then
|
|
100
|
-
echo "tee_subprocess: expected -- before command" >&2
|
|
101
|
-
return 2
|
|
102
|
-
fi
|
|
103
|
-
shift
|
|
104
|
-
# Prefer `stdbuf -oL -eL` to force line buffering on the subprocess; fall
|
|
105
|
-
# back to the bare command when stdbuf is unavailable (macOS dev). On the
|
|
106
|
-
# Pi (Linux), stdbuf is present via coreutils and cloudflared's output
|
|
107
|
-
# reaches the tee as soon as each line is written.
|
|
108
|
-
local -a buf_prefix=()
|
|
109
|
-
if command -v stdbuf >/dev/null 2>&1; then
|
|
110
|
-
buf_prefix=(stdbuf -oL -eL)
|
|
111
|
-
fi
|
|
112
|
-
"${buf_prefix[@]}" "$@" 2>&1 | while IFS= read -r line; do
|
|
113
|
-
local ts
|
|
114
|
-
ts="$(stream_log_ts)"
|
|
115
|
-
printf '[%s] [script:%s] %s\n' "${ts}" "${tag}" "${line}" >> "${STREAM_LOG_PATH}"
|
|
116
|
-
printf '%s\n' "${line}" >&2
|
|
117
|
-
done
|
|
118
|
-
return "${PIPESTATUS[0]}"
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
# Tee a subprocess's combined stdout+stderr into STREAM_LOG_PATH line-by-line
|
|
122
|
-
# with the given tag, passing each line through on stdout so the caller can
|
|
123
|
-
# capture it with `> file` or `$( … )`. Stderr mirroring is dropped so the
|
|
124
|
-
# caller's stdout is exactly the subprocess's output — `jq` and friends
|
|
125
|
-
# remain parseable.
|
|
126
|
-
#
|
|
127
|
-
# Usage: tee_subprocess_capture <tag> -- <cmd> <args …> > captured.file
|
|
128
|
-
# Example:
|
|
129
|
-
# tee_subprocess_capture reset-tunnel:cloudflared -- \
|
|
130
|
-
# cloudflared --origincert "${CERT}" tunnel list --output json \
|
|
131
|
-
# > "${NAMES_TMP}"
|
|
132
|
-
tee_subprocess_capture() {
|
|
133
|
-
local tag="$1"; shift
|
|
134
|
-
if [ "${1:-}" != "--" ]; then
|
|
135
|
-
echo "tee_subprocess_capture: expected -- before command" >&2
|
|
136
|
-
return 2
|
|
137
|
-
fi
|
|
138
|
-
shift
|
|
139
|
-
# Prefer `stdbuf -oL -eL` to force line buffering on the subprocess; fall
|
|
140
|
-
# back to the bare command when stdbuf is unavailable (macOS dev). On the
|
|
141
|
-
# Pi (Linux), stdbuf is present via coreutils and cloudflared's output
|
|
142
|
-
# reaches the tee as soon as each line is written.
|
|
143
|
-
local -a buf_prefix=()
|
|
144
|
-
if command -v stdbuf >/dev/null 2>&1; then
|
|
145
|
-
buf_prefix=(stdbuf -oL -eL)
|
|
146
|
-
fi
|
|
147
|
-
"${buf_prefix[@]}" "$@" 2>&1 | while IFS= read -r line; do
|
|
148
|
-
local ts
|
|
149
|
-
ts="$(stream_log_ts)"
|
|
150
|
-
printf '[%s] [script:%s] %s\n' "${ts}" "${tag}" "${line}" >> "${STREAM_LOG_PATH}"
|
|
151
|
-
printf '%s\n' "${line}"
|
|
152
|
-
done
|
|
153
|
-
return "${PIPESTATUS[0]}"
|
|
154
|
-
}
|
|
@@ -1,98 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bash
|
|
2
|
-
# Deterministic scrape of the operator's Cloudflare dashboard to discover
|
|
3
|
-
# the domains on the logged-in account. Output on stdout is a JSON `string[]`,
|
|
4
|
-
# sorted and deduped. Every failure exits non-zero with a `reason=<enum>`
|
|
5
|
-
# token on stderr tagged `[list-cf-domains]`.
|
|
6
|
-
#
|
|
7
|
-
# Usage:
|
|
8
|
-
# list-cf-domains.sh <brand>
|
|
9
|
-
#
|
|
10
|
-
# brand arg is REQUIRED — the prior silent default (string
|
|
11
|
-
# fallback to "maxy" when $1 was empty) made every non-Maxy brand's CF
|
|
12
|
-
# setup form fail on first use because the wrapper's child node helper
|
|
13
|
-
# read the Maxy CDP port from a hardcoded fallback. Missing arg now exits
|
|
14
|
-
# 1 with `phase=error reason=brand-arg-missing`.
|
|
15
|
-
#
|
|
16
|
-
# The wrapper also resolves and exports MAXY_PLATFORM_ROOT from its own
|
|
17
|
-
# script location so the .ts helper can read `<root>/config/brand.json` for
|
|
18
|
-
# the brand's `cdpPort` (the source of truth). Direct-SSH invocation
|
|
19
|
-
# works because the script lives at `<install>/platform/plugins/cloudflare/
|
|
20
|
-
# scripts/`, making platform root three dirs up from the resolved script.
|
|
21
|
-
#
|
|
22
|
-
# Runtime: Node 22's `--experimental-strip-types` runs the .ts helper
|
|
23
|
-
# directly, so no tsx / playwright / ws dependency exists.
|
|
24
|
-
|
|
25
|
-
set -euo pipefail
|
|
26
|
-
|
|
27
|
-
# --------------------------------------------------------------------------
|
|
28
|
-
# Shared stream-log helpers (require STREAM_LOG_PATH, phase_line, …).
|
|
29
|
-
# --------------------------------------------------------------------------
|
|
30
|
-
|
|
31
|
-
# shellcheck source=_stream-log.sh
|
|
32
|
-
# Resolve symlinks before dirname — ~/list-cf-domains.sh is installed as a
|
|
33
|
-
# symlink into $HOME, so the raw BASH_SOURCE[0] points at $HOME, not the
|
|
34
|
-
# scripts directory where _stream-log.sh lives.
|
|
35
|
-
SCRIPT_DIR="$(dirname "$(readlink -f "${BASH_SOURCE[0]}")")"
|
|
36
|
-
source "${SCRIPT_DIR}/_stream-log.sh"
|
|
37
|
-
require_stream_log_path list-cf-domains
|
|
38
|
-
|
|
39
|
-
if [ "$#" -lt 1 ] || [ -z "${1:-}" ]; then
|
|
40
|
-
phase_line list-cf-domains phase=error reason=brand-arg-missing
|
|
41
|
-
exit 1
|
|
42
|
-
fi
|
|
43
|
-
|
|
44
|
-
BRAND="${1}"
|
|
45
|
-
CONFIG_DIR=".${BRAND}"
|
|
46
|
-
mkdir -p "${HOME}/${CONFIG_DIR}/logs"
|
|
47
|
-
|
|
48
|
-
# MAXY_PLATFORM_ROOT is set by the systemd service when the admin server
|
|
49
|
-
# spawns this script via runFormSpawn. Direct-SSH invocation has no such env
|
|
50
|
-
# so derive it from the resolved script location: scripts/ → cloudflare/ →
|
|
51
|
-
# plugins/ → platform → install root (three dirs up).
|
|
52
|
-
if [ -z "${MAXY_PLATFORM_ROOT:-}" ]; then
|
|
53
|
-
MAXY_PLATFORM_ROOT="$(cd "${SCRIPT_DIR}/../../.." && pwd)"
|
|
54
|
-
fi
|
|
55
|
-
|
|
56
|
-
phase_line list-cf-domains phase=script-start brand="${BRAND}" config_dir="${CONFIG_DIR}"
|
|
57
|
-
|
|
58
|
-
TS_ENTRY="${SCRIPT_DIR}/list-cf-domains.ts"
|
|
59
|
-
|
|
60
|
-
if [ ! -f "${TS_ENTRY}" ]; then
|
|
61
|
-
phase_line list-cf-domains phase=error reason=entry-missing path="${TS_ENTRY}"
|
|
62
|
-
exit 1
|
|
63
|
-
fi
|
|
64
|
-
|
|
65
|
-
# 30s hard ceiling. The node helper has its own per-phase budgets totalling
|
|
66
|
-
# ~27s; the wrapper's extra 3s absorbs process startup and CF network jitter.
|
|
67
|
-
# Use `timeout --preserve-status` so the exit code of a timeout is distinct
|
|
68
|
-
# (124) from a helper-reported failure (1).
|
|
69
|
-
HARD_TIMEOUT_SECS=30
|
|
70
|
-
|
|
71
|
-
# Env passed through:
|
|
72
|
-
# - CONFIG_DIR — consumed by the node helper when writing selector-drift
|
|
73
|
-
# dumps to ~/.${BRAND}/logs/list-cf-domains-<ts>.html.
|
|
74
|
-
# - BRAND — names the brand for log lines naming the brand on
|
|
75
|
-
# config-class failures (helper does not derive it from
|
|
76
|
-
# CONFIG_DIR to keep the two concerns independent).
|
|
77
|
-
# - MAXY_PLATFORM_ROOT — install root the helper reads `config/brand.json`
|
|
78
|
-
# from for `cdpPort`. Resolved above so direct-SSH
|
|
79
|
-
# invocation matches the systemd-spawned path.
|
|
80
|
-
#
|
|
81
|
-
# `node --experimental-strip-types` (stable in Node 22.22) runs the .ts file
|
|
82
|
-
# natively: type annotations are stripped, no enums / decorators are used, so
|
|
83
|
-
# no TS type-transform is needed. `--no-warnings` suppresses the experimental
|
|
84
|
-
# banner which would otherwise leak into stderr and confuse the route parser.
|
|
85
|
-
set +e
|
|
86
|
-
CONFIG_DIR="${CONFIG_DIR}" BRAND="${BRAND}" MAXY_PLATFORM_ROOT="${MAXY_PLATFORM_ROOT}" \
|
|
87
|
-
timeout --preserve-status --signal=TERM "${HARD_TIMEOUT_SECS}" \
|
|
88
|
-
node --experimental-strip-types --no-warnings "${TS_ENTRY}"
|
|
89
|
-
EXIT_CODE=$?
|
|
90
|
-
set -e
|
|
91
|
-
|
|
92
|
-
if [ "${EXIT_CODE}" -eq 124 ]; then
|
|
93
|
-
phase_line list-cf-domains phase=script-exit code=124 reason=wrapper-timeout budget_secs="${HARD_TIMEOUT_SECS}"
|
|
94
|
-
exit 1
|
|
95
|
-
fi
|
|
96
|
-
|
|
97
|
-
phase_line list-cf-domains phase=script-exit code="${EXIT_CODE}"
|
|
98
|
-
exit "${EXIT_CODE}"
|