youmd 0.7.1 → 0.8.2

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.
Files changed (125) hide show
  1. package/dist/commands/chat.d.ts.map +1 -1
  2. package/dist/commands/chat.js +3 -2
  3. package/dist/commands/chat.js.map +1 -1
  4. package/dist/commands/env.d.ts +2 -0
  5. package/dist/commands/env.d.ts.map +1 -1
  6. package/dist/commands/env.js +7 -3
  7. package/dist/commands/env.js.map +1 -1
  8. package/dist/commands/login.d.ts +1 -0
  9. package/dist/commands/login.d.ts.map +1 -1
  10. package/dist/commands/login.js +20 -4
  11. package/dist/commands/login.js.map +1 -1
  12. package/dist/commands/machine.d.ts +31 -0
  13. package/dist/commands/machine.d.ts.map +1 -1
  14. package/dist/commands/machine.js +610 -14
  15. package/dist/commands/machine.js.map +1 -1
  16. package/dist/commands/project-log.d.ts +13 -0
  17. package/dist/commands/project-log.d.ts.map +1 -0
  18. package/dist/commands/project-log.js +241 -0
  19. package/dist/commands/project-log.js.map +1 -0
  20. package/dist/commands/project.d.ts.map +1 -1
  21. package/dist/commands/project.js +872 -15
  22. package/dist/commands/project.js.map +1 -1
  23. package/dist/commands/prompts.d.ts +19 -0
  24. package/dist/commands/prompts.d.ts.map +1 -1
  25. package/dist/commands/prompts.js +304 -1
  26. package/dist/commands/prompts.js.map +1 -1
  27. package/dist/commands/pull.d.ts.map +1 -1
  28. package/dist/commands/pull.js +28 -8
  29. package/dist/commands/pull.js.map +1 -1
  30. package/dist/commands/push.d.ts +3 -1
  31. package/dist/commands/push.d.ts.map +1 -1
  32. package/dist/commands/push.js +26 -12
  33. package/dist/commands/push.js.map +1 -1
  34. package/dist/commands/skill.d.ts.map +1 -1
  35. package/dist/commands/skill.js +19 -15
  36. package/dist/commands/skill.js.map +1 -1
  37. package/dist/commands/stack.d.ts.map +1 -1
  38. package/dist/commands/stack.js +37 -17
  39. package/dist/commands/stack.js.map +1 -1
  40. package/dist/commands/status.d.ts.map +1 -1
  41. package/dist/commands/status.js +31 -0
  42. package/dist/commands/status.js.map +1 -1
  43. package/dist/commands/sync.d.ts +1 -0
  44. package/dist/commands/sync.d.ts.map +1 -1
  45. package/dist/commands/sync.js +51 -2
  46. package/dist/commands/sync.js.map +1 -1
  47. package/dist/index.js +125 -36
  48. package/dist/index.js.map +1 -1
  49. package/dist/lib/api.d.ts +324 -0
  50. package/dist/lib/api.d.ts.map +1 -1
  51. package/dist/lib/api.js +68 -0
  52. package/dist/lib/api.js.map +1 -1
  53. package/dist/lib/compiler.d.ts.map +1 -1
  54. package/dist/lib/compiler.js +10 -0
  55. package/dist/lib/compiler.js.map +1 -1
  56. package/dist/lib/daemon.d.ts +23 -0
  57. package/dist/lib/daemon.d.ts.map +1 -0
  58. package/dist/lib/daemon.js +166 -0
  59. package/dist/lib/daemon.js.map +1 -0
  60. package/dist/lib/first-run.d.ts +1 -1
  61. package/dist/lib/first-run.d.ts.map +1 -1
  62. package/dist/lib/first-run.js +8 -0
  63. package/dist/lib/first-run.js.map +1 -1
  64. package/dist/lib/machine-bootstrap-prompt.d.ts +17 -0
  65. package/dist/lib/machine-bootstrap-prompt.d.ts.map +1 -0
  66. package/dist/lib/machine-bootstrap-prompt.js +305 -0
  67. package/dist/lib/machine-bootstrap-prompt.js.map +1 -0
  68. package/dist/lib/machine-projects.d.ts +71 -0
  69. package/dist/lib/machine-projects.d.ts.map +1 -0
  70. package/dist/lib/machine-projects.js +510 -0
  71. package/dist/lib/machine-projects.js.map +1 -0
  72. package/dist/lib/machine-verify.d.ts +175 -0
  73. package/dist/lib/machine-verify.d.ts.map +1 -0
  74. package/dist/lib/machine-verify.js +684 -0
  75. package/dist/lib/machine-verify.js.map +1 -0
  76. package/dist/lib/portfolio-audit.d.ts +34 -0
  77. package/dist/lib/portfolio-audit.d.ts.map +1 -0
  78. package/dist/lib/portfolio-audit.js +254 -0
  79. package/dist/lib/portfolio-audit.js.map +1 -0
  80. package/dist/lib/portfolio-graph.d.ts +104 -0
  81. package/dist/lib/portfolio-graph.d.ts.map +1 -0
  82. package/dist/lib/portfolio-graph.js +281 -0
  83. package/dist/lib/portfolio-graph.js.map +1 -0
  84. package/dist/lib/project-strategy.d.ts +45 -0
  85. package/dist/lib/project-strategy.d.ts.map +1 -0
  86. package/dist/lib/project-strategy.js +234 -0
  87. package/dist/lib/project-strategy.js.map +1 -0
  88. package/dist/lib/reusable-patterns.d.ts +30 -0
  89. package/dist/lib/reusable-patterns.d.ts.map +1 -0
  90. package/dist/lib/reusable-patterns.js +375 -0
  91. package/dist/lib/reusable-patterns.js.map +1 -0
  92. package/dist/lib/skill-catalog.d.ts.map +1 -1
  93. package/dist/lib/skill-catalog.js +20 -0
  94. package/dist/lib/skill-catalog.js.map +1 -1
  95. package/dist/lib/skills.d.ts +1 -0
  96. package/dist/lib/skills.d.ts.map +1 -1
  97. package/dist/lib/skills.js +43 -13
  98. package/dist/lib/skills.js.map +1 -1
  99. package/dist/lib/version.d.ts +2 -0
  100. package/dist/lib/version.d.ts.map +1 -0
  101. package/dist/lib/version.js +63 -0
  102. package/dist/lib/version.js.map +1 -0
  103. package/dist/mcp/registry.d.ts +5 -1
  104. package/dist/mcp/registry.d.ts.map +1 -1
  105. package/dist/mcp/registry.js +426 -2
  106. package/dist/mcp/registry.js.map +1 -1
  107. package/dist/mcp/server.d.ts +2 -0
  108. package/dist/mcp/server.d.ts.map +1 -1
  109. package/dist/mcp/server.js +50 -5
  110. package/dist/mcp/server.js.map +1 -1
  111. package/package.json +1 -1
  112. package/scripts/env-vault/README.md +37 -10
  113. package/scripts/env-vault/backup.sh +70 -4
  114. package/scripts/env-vault/restore.sh +117 -9
  115. package/scripts/skillstack-sync/README.md +13 -6
  116. package/scripts/skillstack-sync/bootstrap-new-mac.sh +19 -5
  117. package/scripts/skillstack-sync/capture-agent-config.sh +110 -0
  118. package/scripts/skillstack-sync/com.youmd.context-sync.plist +38 -0
  119. package/scripts/skillstack-sync/com.youmd.identity-sync.plist +3 -1
  120. package/scripts/skillstack-sync/com.youmd.skillstack-sync.plist +1 -1
  121. package/scripts/skillstack-sync/context-sync.sh +412 -0
  122. package/scripts/skillstack-sync/install-daemons.sh +7 -3
  123. package/scripts/skillstack-sync/restore-agent-config.sh +152 -0
  124. package/scripts/skillstack-sync/sync.sh +20 -6
  125. package/skills/machine-bootstrap.md +243 -0
@@ -0,0 +1,684 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.DEFAULT_MACHINE_SERVER_START_PORT = exports.DEFAULT_MACHINE_CHECK_SCRIPTS = void 0;
37
+ exports.inspectMachineProject = inspectMachineProject;
38
+ exports.buildMachineReadinessReport = buildMachineReadinessReport;
39
+ exports.runMachineProjectChecks = runMachineProjectChecks;
40
+ exports.runMachineDependencyInstalls = runMachineDependencyInstalls;
41
+ exports.runMachineServerProbes = runMachineServerProbes;
42
+ exports.buildMachineRunChecksReport = buildMachineRunChecksReport;
43
+ exports.buildMachineInstallReport = buildMachineInstallReport;
44
+ exports.buildMachineServerProbeReport = buildMachineServerProbeReport;
45
+ exports.buildMachineVerificationProof = buildMachineVerificationProof;
46
+ exports.defaultMachineReportPath = defaultMachineReportPath;
47
+ exports.writeMachineVerificationProof = writeMachineVerificationProof;
48
+ const fs = __importStar(require("fs"));
49
+ const path = __importStar(require("path"));
50
+ const childProcess = __importStar(require("child_process"));
51
+ const http = __importStar(require("http"));
52
+ const os = __importStar(require("os"));
53
+ exports.DEFAULT_MACHINE_CHECK_SCRIPTS = ["typecheck", "lint", "test", "build"];
54
+ exports.DEFAULT_MACHINE_SERVER_START_PORT = 4310;
55
+ function readText(filePath) {
56
+ try {
57
+ return fs.readFileSync(filePath, "utf-8");
58
+ }
59
+ catch {
60
+ return "";
61
+ }
62
+ }
63
+ function readJson(filePath) {
64
+ try {
65
+ const raw = fs.readFileSync(filePath, "utf-8");
66
+ const parsed = JSON.parse(raw);
67
+ return typeof parsed === "object" && parsed !== null && !Array.isArray(parsed)
68
+ ? parsed
69
+ : null;
70
+ }
71
+ catch {
72
+ return null;
73
+ }
74
+ }
75
+ function detectRemoteUrl(projectDir) {
76
+ const config = readText(path.join(projectDir, ".git", "config"));
77
+ const match = config.match(/\[remote "origin"\][\s\S]*?\n\s*url\s*=\s*(.+)/);
78
+ return match?.[1]?.trim() || undefined;
79
+ }
80
+ function detectPackageManager(projectDir) {
81
+ if (fs.existsSync(path.join(projectDir, "pnpm-lock.yaml")))
82
+ return "pnpm";
83
+ if (fs.existsSync(path.join(projectDir, "yarn.lock")))
84
+ return "yarn";
85
+ if (fs.existsSync(path.join(projectDir, "bun.lockb")) || fs.existsSync(path.join(projectDir, "bun.lock")))
86
+ return "bun";
87
+ if (fs.existsSync(path.join(projectDir, "package-lock.json")))
88
+ return "npm";
89
+ if (fs.existsSync(path.join(projectDir, "package.json")))
90
+ return "npm";
91
+ return undefined;
92
+ }
93
+ function checkCommand(packageManager, script) {
94
+ if (packageManager === "yarn")
95
+ return `yarn ${script}`;
96
+ if (packageManager === "bun")
97
+ return `bun run ${script}`;
98
+ return `${packageManager} run ${script}`;
99
+ }
100
+ function checkCommandParts(packageManager, script) {
101
+ if (packageManager === "yarn")
102
+ return { command: "yarn", args: [script], display: `yarn ${script}` };
103
+ if (packageManager === "bun")
104
+ return { command: "bun", args: ["run", script], display: `bun run ${script}` };
105
+ return { command: packageManager, args: ["run", script], display: `${packageManager} run ${script}` };
106
+ }
107
+ function installCommandParts(project) {
108
+ if (!project.packageManager)
109
+ return null;
110
+ if (project.packageManager === "npm") {
111
+ const hasPackageLock = fs.existsSync(path.join(project.projectDir, "package-lock.json"));
112
+ return hasPackageLock
113
+ ? { command: "npm", args: ["ci"], display: "npm ci" }
114
+ : { command: "npm", args: ["install"], display: "npm install" };
115
+ }
116
+ if (project.packageManager === "pnpm") {
117
+ const hasLock = fs.existsSync(path.join(project.projectDir, "pnpm-lock.yaml"));
118
+ return {
119
+ command: "pnpm",
120
+ args: hasLock ? ["install", "--frozen-lockfile"] : ["install"],
121
+ display: hasLock ? "pnpm install --frozen-lockfile" : "pnpm install",
122
+ };
123
+ }
124
+ if (project.packageManager === "yarn") {
125
+ const hasLock = fs.existsSync(path.join(project.projectDir, "yarn.lock"));
126
+ return {
127
+ command: "yarn",
128
+ args: hasLock ? ["install", "--frozen-lockfile"] : ["install"],
129
+ display: hasLock ? "yarn install --frozen-lockfile" : "yarn install",
130
+ };
131
+ }
132
+ const hasLock = fs.existsSync(path.join(project.projectDir, "bun.lockb")) || fs.existsSync(path.join(project.projectDir, "bun.lock"));
133
+ return {
134
+ command: "bun",
135
+ args: hasLock ? ["install", "--frozen-lockfile"] : ["install"],
136
+ display: hasLock ? "bun install --frozen-lockfile" : "bun install",
137
+ };
138
+ }
139
+ function packageText(projectDir) {
140
+ return readText(path.join(projectDir, "package.json")).toLowerCase();
141
+ }
142
+ function devServerCommandParts(project, port) {
143
+ if (!project.packageManager || !project.scripts.includes("dev"))
144
+ return null;
145
+ const text = packageText(project.projectDir);
146
+ let extraArgs = [];
147
+ if (text.includes("\"next\"") || text.includes("next dev")) {
148
+ extraArgs = ["--hostname", "127.0.0.1", "--port", String(port)];
149
+ }
150
+ else if (text.includes("\"vite\"") || text.includes("vite ")) {
151
+ extraArgs = ["--host", "127.0.0.1", "--port", String(port), "--strictPort"];
152
+ }
153
+ else if (text.includes("\"astro\"") || text.includes("astro dev")) {
154
+ extraArgs = ["--host", "127.0.0.1", "--port", String(port)];
155
+ }
156
+ const withArgs = extraArgs.length > 0 ? ["--", ...extraArgs] : [];
157
+ if (project.packageManager === "yarn") {
158
+ return {
159
+ command: "yarn",
160
+ args: ["dev", ...extraArgs],
161
+ display: ["yarn dev", ...extraArgs].join(" "),
162
+ };
163
+ }
164
+ if (project.packageManager === "bun") {
165
+ return {
166
+ command: "bun",
167
+ args: ["run", "dev", ...withArgs],
168
+ display: ["bun run dev", ...withArgs].join(" "),
169
+ };
170
+ }
171
+ return {
172
+ command: project.packageManager,
173
+ args: ["run", "dev", ...withArgs],
174
+ display: [`${project.packageManager} run dev`, ...withArgs].join(" "),
175
+ };
176
+ }
177
+ function redactSensitive(value) {
178
+ return value
179
+ .replace(/((?:API|AUTH|ACCESS|REFRESH|SECRET|TOKEN|PASSWORD|PASS|KEY)[A-Z0-9_]*=)[^\s'"`]+/gi, "$1[redacted]")
180
+ .replace(/\b(?:sk|pk|ghp|gho|ghs|ghu|ghr|xox[baprs]|or)-[A-Za-z0-9_-]{12,}\b/g, "[redacted-token]")
181
+ .replace(/\b[A-Za-z0-9_./+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}\b/g, "[redacted-email]");
182
+ }
183
+ function outputTail(value, maxLength = 1200) {
184
+ const trimmed = value.trim();
185
+ const tail = trimmed.length <= maxLength ? trimmed : trimmed.slice(trimmed.length - maxLength);
186
+ return redactSensitive(tail);
187
+ }
188
+ function classifyMachineFailure(output, fallback) {
189
+ const normalized = output.toLowerCase();
190
+ if (normalized.includes("cannot prompt for input in non-interactive terminals") && normalized.includes("convex")) {
191
+ return "non-interactive Convex setup required before dev server start; restore Convex/env config or run convex dev interactively once";
192
+ }
193
+ if (normalized.includes("cannot prompt for input in non-interactive terminals")) {
194
+ return "non-interactive setup prompt blocked fresh-host run";
195
+ }
196
+ return fallback;
197
+ }
198
+ function sanitizeForProof(value) {
199
+ return JSON.parse(redactSensitive(JSON.stringify(value)));
200
+ }
201
+ function appendBounded(buffer, chunk, maxLength = 12000) {
202
+ const next = buffer + String(chunk);
203
+ if (next.length <= maxLength)
204
+ return next;
205
+ return next.slice(next.length - maxLength);
206
+ }
207
+ function statusForProject(project) {
208
+ if (!project.isDirectory)
209
+ return "empty";
210
+ if (!project.isGitRepo && !project.packageManager && !project.hasProjectContext && !project.hasAgentDocs)
211
+ return "empty";
212
+ if (!project.packageManager && (project.hasAgentDocs || project.hasProjectContext))
213
+ return "docs-only";
214
+ if (project.hasEnvExample && !project.hasEnvLocal)
215
+ return "needs-env";
216
+ if (project.isGitRepo && project.packageManager)
217
+ return "ready";
218
+ return "partial";
219
+ }
220
+ function inspectMachineProject(projectDir) {
221
+ const dirName = path.basename(projectDir);
222
+ const isDirectory = fs.existsSync(projectDir) && fs.statSync(projectDir).isDirectory();
223
+ const isGitRepo = isDirectory && fs.existsSync(path.join(projectDir, ".git"));
224
+ const hasAgentDocs = isDirectory && (fs.existsSync(path.join(projectDir, "AGENTS.md")) ||
225
+ fs.existsSync(path.join(projectDir, "CLAUDE.md")) ||
226
+ fs.existsSync(path.join(projectDir, ".codex", "AGENTS.md")) ||
227
+ fs.existsSync(path.join(projectDir, ".claude", "CLAUDE.md")));
228
+ const hasProjectContext = isDirectory && fs.existsSync(path.join(projectDir, "project-context"));
229
+ const hasEnvLocal = isDirectory && fs.existsSync(path.join(projectDir, ".env.local"));
230
+ const hasEnvExample = isDirectory && (fs.existsSync(path.join(projectDir, ".env.example")) ||
231
+ fs.existsSync(path.join(projectDir, ".env.local.example")));
232
+ const packageJson = isDirectory ? readJson(path.join(projectDir, "package.json")) : null;
233
+ const scriptsRecord = packageJson && typeof packageJson.scripts === "object" && packageJson.scripts !== null && !Array.isArray(packageJson.scripts)
234
+ ? packageJson.scripts
235
+ : {};
236
+ const scripts = Object.entries(scriptsRecord)
237
+ .filter(([, value]) => typeof value === "string")
238
+ .map(([key]) => key)
239
+ .sort();
240
+ const packageManager = isDirectory ? detectPackageManager(projectDir) : undefined;
241
+ const preferredChecks = ["typecheck", "lint", "test", "build", "dev"].filter((script) => scripts.includes(script));
242
+ const suggestedChecks = packageManager
243
+ ? preferredChecks.map((script) => checkCommand(packageManager, script))
244
+ : [];
245
+ const base = {
246
+ dirName,
247
+ projectDir,
248
+ isDirectory,
249
+ isGitRepo,
250
+ remoteUrl: isGitRepo ? detectRemoteUrl(projectDir) : undefined,
251
+ hasAgentDocs,
252
+ hasProjectContext,
253
+ hasEnvLocal,
254
+ hasEnvExample,
255
+ packageManager,
256
+ scripts,
257
+ suggestedChecks,
258
+ notes: [
259
+ hasEnvExample && !hasEnvLocal ? "env restore needed before full local run" : "",
260
+ !hasAgentDocs ? "agent docs missing or not at root" : "",
261
+ packageManager && suggestedChecks.length === 0 ? "package scripts found but no standard check scripts" : "",
262
+ ].filter(Boolean),
263
+ };
264
+ return {
265
+ ...base,
266
+ status: statusForProject(base),
267
+ };
268
+ }
269
+ function buildMachineReadinessReport(rootDir, maxProjects = 80) {
270
+ const entries = fs.existsSync(rootDir)
271
+ ? fs.readdirSync(rootDir)
272
+ .filter((entry) => !entry.startsWith("."))
273
+ .map((entry) => path.join(rootDir, entry))
274
+ .filter((entryPath) => {
275
+ try {
276
+ return fs.statSync(entryPath).isDirectory();
277
+ }
278
+ catch {
279
+ return false;
280
+ }
281
+ })
282
+ .sort((a, b) => path.basename(a).localeCompare(path.basename(b)))
283
+ .slice(0, Math.max(1, maxProjects))
284
+ : [];
285
+ const projects = entries.map(inspectMachineProject);
286
+ return {
287
+ rootDir,
288
+ scanned: projects.length,
289
+ projects,
290
+ totals: {
291
+ gitRepos: projects.filter((project) => project.isGitRepo).length,
292
+ packageProjects: projects.filter((project) => Boolean(project.packageManager)).length,
293
+ envLocal: projects.filter((project) => project.hasEnvLocal).length,
294
+ envExample: projects.filter((project) => project.hasEnvExample).length,
295
+ agentDocs: projects.filter((project) => project.hasAgentDocs).length,
296
+ projectContext: projects.filter((project) => project.hasProjectContext).length,
297
+ ready: projects.filter((project) => project.status === "ready").length,
298
+ needsEnv: projects.filter((project) => project.status === "needs-env").length,
299
+ partial: projects.filter((project) => project.status === "partial").length,
300
+ },
301
+ };
302
+ }
303
+ function runMachineProjectChecks(projects, options = {}) {
304
+ const requestedScripts = (options.scripts?.length ? options.scripts : exports.DEFAULT_MACHINE_CHECK_SCRIPTS)
305
+ .map((script) => script.trim())
306
+ .filter(Boolean);
307
+ const timeoutMs = Number.isFinite(options.timeoutMs) && Number(options.timeoutMs) > 0
308
+ ? Number(options.timeoutMs)
309
+ : 120000;
310
+ const maxProjects = Number.isFinite(options.maxProjects) && Number(options.maxProjects) > 0
311
+ ? Number(options.maxProjects)
312
+ : 8;
313
+ const runnableProjects = projects
314
+ .filter((project) => Boolean(project.packageManager))
315
+ .slice(0, maxProjects);
316
+ const results = [];
317
+ for (const project of runnableProjects) {
318
+ if (!project.packageManager)
319
+ continue;
320
+ const scriptsToRun = requestedScripts.filter((script) => project.scripts.includes(script));
321
+ if (scriptsToRun.length === 0) {
322
+ results.push({
323
+ dirName: project.dirName,
324
+ projectDir: project.projectDir,
325
+ script: requestedScripts.join(","),
326
+ command: requestedScripts.map((script) => checkCommand(project.packageManager, script)).join(" | "),
327
+ status: "skipped",
328
+ durationMs: 0,
329
+ reason: "no requested check scripts found",
330
+ });
331
+ continue;
332
+ }
333
+ for (const script of scriptsToRun) {
334
+ const { command, args, display } = checkCommandParts(project.packageManager, script);
335
+ const startedAt = Date.now();
336
+ const result = childProcess.spawnSync(command, args, {
337
+ cwd: project.projectDir,
338
+ encoding: "utf-8",
339
+ timeout: timeoutMs,
340
+ maxBuffer: 1024 * 1024,
341
+ env: {
342
+ ...process.env,
343
+ CI: process.env.CI || "1",
344
+ NO_COLOR: process.env.NO_COLOR || "1",
345
+ },
346
+ });
347
+ const durationMs = Date.now() - startedAt;
348
+ const combinedOutput = [result.stdout, result.stderr].filter(Boolean).join("\n");
349
+ const timedOut = result.error && result.error.message.includes("ETIMEDOUT");
350
+ results.push({
351
+ dirName: project.dirName,
352
+ projectDir: project.projectDir,
353
+ script,
354
+ command: display,
355
+ status: timedOut ? "timeout" : result.status === 0 ? "passed" : "failed",
356
+ exitCode: result.status,
357
+ durationMs,
358
+ outputTail: outputTail(combinedOutput),
359
+ reason: result.error && !timedOut ? result.error.message : undefined,
360
+ });
361
+ }
362
+ }
363
+ return results;
364
+ }
365
+ function runMachineDependencyInstalls(projects, options = {}) {
366
+ const timeoutMs = Number.isFinite(options.timeoutMs) && Number(options.timeoutMs) > 0
367
+ ? Number(options.timeoutMs)
368
+ : 180000;
369
+ const maxProjects = Number.isFinite(options.maxProjects) && Number(options.maxProjects) > 0
370
+ ? Number(options.maxProjects)
371
+ : 4;
372
+ const runnableProjects = projects
373
+ .filter((project) => Boolean(project.packageManager))
374
+ .slice(0, maxProjects);
375
+ const results = [];
376
+ for (const project of runnableProjects) {
377
+ const commandParts = installCommandParts(project);
378
+ if (!commandParts) {
379
+ results.push({
380
+ dirName: project.dirName,
381
+ projectDir: project.projectDir,
382
+ command: "install",
383
+ status: "skipped",
384
+ durationMs: 0,
385
+ reason: "no package manager detected",
386
+ });
387
+ continue;
388
+ }
389
+ const startedAt = Date.now();
390
+ const result = childProcess.spawnSync(commandParts.command, commandParts.args, {
391
+ cwd: project.projectDir,
392
+ encoding: "utf-8",
393
+ timeout: timeoutMs,
394
+ maxBuffer: 1024 * 1024,
395
+ env: {
396
+ ...process.env,
397
+ CI: process.env.CI || "1",
398
+ NO_COLOR: process.env.NO_COLOR || "1",
399
+ },
400
+ });
401
+ const durationMs = Date.now() - startedAt;
402
+ const combinedOutput = [result.stdout, result.stderr].filter(Boolean).join("\n");
403
+ const timedOut = result.error && result.error.message.includes("ETIMEDOUT");
404
+ results.push({
405
+ dirName: project.dirName,
406
+ projectDir: project.projectDir,
407
+ command: commandParts.display,
408
+ status: timedOut ? "timeout" : result.status === 0 ? "passed" : "failed",
409
+ exitCode: result.status,
410
+ durationMs,
411
+ outputTail: outputTail(combinedOutput),
412
+ reason: result.error && !timedOut ? result.error.message : undefined,
413
+ });
414
+ }
415
+ return results;
416
+ }
417
+ function waitForHttp(url, timeoutMs) {
418
+ const startedAt = Date.now();
419
+ return new Promise((resolve) => {
420
+ let lastError = "";
421
+ const attempt = () => {
422
+ const req = http.get(url, { timeout: 1500 }, (res) => {
423
+ res.resume();
424
+ resolve({ status: "passed", statusCode: res.statusCode });
425
+ });
426
+ req.on("timeout", () => {
427
+ req.destroy(new Error("probe request timed out"));
428
+ });
429
+ req.on("error", (err) => {
430
+ lastError = err.message;
431
+ if (Date.now() - startedAt >= timeoutMs) {
432
+ resolve({ status: "timeout", reason: lastError || "server did not respond before timeout" });
433
+ }
434
+ else {
435
+ setTimeout(attempt, 500);
436
+ }
437
+ });
438
+ };
439
+ attempt();
440
+ });
441
+ }
442
+ function stopChild(child) {
443
+ if (child.exitCode !== null || child.killed)
444
+ return;
445
+ child.kill("SIGTERM");
446
+ setTimeout(() => {
447
+ if (child.exitCode === null && !child.killed) {
448
+ child.kill("SIGKILL");
449
+ }
450
+ }, 1000).unref();
451
+ }
452
+ async function runMachineServerProbes(projects, options = {}) {
453
+ const timeoutMs = Number.isFinite(options.timeoutMs) && Number(options.timeoutMs) > 0
454
+ ? Number(options.timeoutMs)
455
+ : 45000;
456
+ const maxProjects = Number.isFinite(options.maxProjects) && Number(options.maxProjects) > 0
457
+ ? Number(options.maxProjects)
458
+ : 3;
459
+ const startPort = Number.isFinite(options.startPort) && Number(options.startPort) > 0
460
+ ? Number(options.startPort)
461
+ : exports.DEFAULT_MACHINE_SERVER_START_PORT;
462
+ const runnableProjects = projects
463
+ .filter((project) => Boolean(project.packageManager) && project.scripts.includes("dev"))
464
+ .slice(0, maxProjects);
465
+ const results = [];
466
+ for (const [index, project] of runnableProjects.entries()) {
467
+ const port = startPort + index;
468
+ const commandParts = devServerCommandParts(project, port);
469
+ const url = `http://127.0.0.1:${port}`;
470
+ if (!commandParts) {
471
+ results.push({
472
+ dirName: project.dirName,
473
+ projectDir: project.projectDir,
474
+ command: "dev",
475
+ url,
476
+ status: "skipped",
477
+ durationMs: 0,
478
+ reason: "no dev server command could be inferred",
479
+ });
480
+ continue;
481
+ }
482
+ const startedAt = Date.now();
483
+ let output = "";
484
+ const child = childProcess.spawn(commandParts.command, commandParts.args, {
485
+ cwd: project.projectDir,
486
+ stdio: ["ignore", "pipe", "pipe"],
487
+ env: {
488
+ ...process.env,
489
+ PORT: String(port),
490
+ HOST: "127.0.0.1",
491
+ HOSTNAME: "127.0.0.1",
492
+ BROWSER: "none",
493
+ CI: "1",
494
+ NEXT_TELEMETRY_DISABLED: "1",
495
+ NO_COLOR: process.env.NO_COLOR || "1",
496
+ },
497
+ });
498
+ child.stdout?.on("data", (chunk) => {
499
+ output = appendBounded(output, chunk);
500
+ });
501
+ child.stderr?.on("data", (chunk) => {
502
+ output = appendBounded(output, chunk);
503
+ });
504
+ const earlyExit = new Promise((resolve) => {
505
+ child.once("error", (err) => resolve({ status: "failed", reason: err.message }));
506
+ child.once("exit", (code, signal) => {
507
+ const exitReason = signal || (code ?? "unknown");
508
+ resolve({ status: "failed", reason: `server exited before probe responded (${exitReason})` });
509
+ });
510
+ });
511
+ const probe = await Promise.race([
512
+ waitForHttp(url, timeoutMs),
513
+ earlyExit,
514
+ ]);
515
+ const durationMs = Date.now() - startedAt;
516
+ const tail = outputTail(output);
517
+ stopChild(child);
518
+ results.push({
519
+ dirName: project.dirName,
520
+ projectDir: project.projectDir,
521
+ command: commandParts.display,
522
+ url,
523
+ status: probe.status,
524
+ statusCode: "statusCode" in probe ? probe.statusCode : undefined,
525
+ durationMs,
526
+ outputTail: tail,
527
+ reason: classifyMachineFailure(tail, probe.reason),
528
+ });
529
+ }
530
+ return results;
531
+ }
532
+ function buildMachineRunChecksReport(rootDir, options = {}) {
533
+ const scanLimit = Number.isFinite(options.scanLimit) && Number(options.scanLimit) > 0
534
+ ? Number(options.scanLimit)
535
+ : 80;
536
+ const requestedScripts = (options.scripts?.length ? options.scripts : exports.DEFAULT_MACHINE_CHECK_SCRIPTS)
537
+ .map((script) => script.trim())
538
+ .filter(Boolean);
539
+ const timeoutMs = Number.isFinite(options.timeoutMs) && Number(options.timeoutMs) > 0
540
+ ? Number(options.timeoutMs)
541
+ : 120000;
542
+ const maxProjects = Number.isFinite(options.maxProjects) && Number(options.maxProjects) > 0
543
+ ? Number(options.maxProjects)
544
+ : 8;
545
+ const readiness = buildMachineReadinessReport(rootDir, scanLimit);
546
+ const results = runMachineProjectChecks(readiness.projects, {
547
+ scripts: requestedScripts,
548
+ timeoutMs,
549
+ maxProjects,
550
+ });
551
+ return {
552
+ rootDir,
553
+ requestedScripts,
554
+ timeoutMs,
555
+ maxProjects,
556
+ results,
557
+ totals: {
558
+ passed: results.filter((result) => result.status === "passed").length,
559
+ failed: results.filter((result) => result.status === "failed").length,
560
+ timeout: results.filter((result) => result.status === "timeout").length,
561
+ skipped: results.filter((result) => result.status === "skipped").length,
562
+ },
563
+ };
564
+ }
565
+ function buildMachineInstallReport(rootDir, options = {}) {
566
+ const scanLimit = Number.isFinite(options.scanLimit) && Number(options.scanLimit) > 0
567
+ ? Number(options.scanLimit)
568
+ : 80;
569
+ const timeoutMs = Number.isFinite(options.timeoutMs) && Number(options.timeoutMs) > 0
570
+ ? Number(options.timeoutMs)
571
+ : 180000;
572
+ const maxProjects = Number.isFinite(options.maxProjects) && Number(options.maxProjects) > 0
573
+ ? Number(options.maxProjects)
574
+ : 4;
575
+ const readiness = buildMachineReadinessReport(rootDir, scanLimit);
576
+ const results = runMachineDependencyInstalls(readiness.projects, {
577
+ timeoutMs,
578
+ maxProjects,
579
+ });
580
+ return {
581
+ rootDir,
582
+ timeoutMs,
583
+ maxProjects,
584
+ results,
585
+ totals: {
586
+ passed: results.filter((result) => result.status === "passed").length,
587
+ failed: results.filter((result) => result.status === "failed").length,
588
+ timeout: results.filter((result) => result.status === "timeout").length,
589
+ skipped: results.filter((result) => result.status === "skipped").length,
590
+ },
591
+ };
592
+ }
593
+ async function buildMachineServerProbeReport(rootDir, options = {}) {
594
+ const scanLimit = Number.isFinite(options.scanLimit) && Number(options.scanLimit) > 0
595
+ ? Number(options.scanLimit)
596
+ : 80;
597
+ const timeoutMs = Number.isFinite(options.timeoutMs) && Number(options.timeoutMs) > 0
598
+ ? Number(options.timeoutMs)
599
+ : 45000;
600
+ const maxProjects = Number.isFinite(options.maxProjects) && Number(options.maxProjects) > 0
601
+ ? Number(options.maxProjects)
602
+ : 3;
603
+ const startPort = Number.isFinite(options.startPort) && Number(options.startPort) > 0
604
+ ? Number(options.startPort)
605
+ : exports.DEFAULT_MACHINE_SERVER_START_PORT;
606
+ const readiness = buildMachineReadinessReport(rootDir, scanLimit);
607
+ const results = await runMachineServerProbes(readiness.projects, {
608
+ timeoutMs,
609
+ maxProjects,
610
+ startPort,
611
+ });
612
+ return {
613
+ rootDir,
614
+ timeoutMs,
615
+ maxProjects,
616
+ startPort,
617
+ results,
618
+ totals: {
619
+ passed: results.filter((result) => result.status === "passed").length,
620
+ failed: results.filter((result) => result.status === "failed").length,
621
+ timeout: results.filter((result) => result.status === "timeout").length,
622
+ skipped: results.filter((result) => result.status === "skipped").length,
623
+ },
624
+ };
625
+ }
626
+ function buildMachineVerificationProof(options) {
627
+ const generatedAt = options.generatedAt ?? new Date().toISOString();
628
+ const installFailures = (options.installs?.totals.failed ?? 0) + (options.installs?.totals.timeout ?? 0);
629
+ const checkFailures = (options.checks?.totals.failed ?? 0) + (options.checks?.totals.timeout ?? 0);
630
+ const serverFailures = (options.servers?.totals.failed ?? 0) + (options.servers?.totals.timeout ?? 0);
631
+ const failures = installFailures + checkFailures + serverFailures;
632
+ const warnings = [
633
+ options.readiness.totals.needsEnv > 0 ? `${options.readiness.totals.needsEnv} projects need env restore` : "",
634
+ options.readiness.totals.partial > 0 ? `${options.readiness.totals.partial} projects are partial` : "",
635
+ options.installs && options.installs.results.length === 0 ? "no package projects were available for dependency install" : "",
636
+ options.checks && options.checks.results.length === 0 ? "no package projects had requested check scripts" : "",
637
+ options.servers && options.servers.results.length === 0 ? "no package projects had dev servers to probe" : "",
638
+ ...(options.servers?.results ?? [])
639
+ .filter((result) => result.status === "failed" || result.status === "timeout")
640
+ .map((result) => result.reason ? `${result.dirName}: ${result.reason}` : "")
641
+ .filter(Boolean),
642
+ ].filter(Boolean);
643
+ return {
644
+ schemaVersion: 1,
645
+ generatedAt,
646
+ hostName: os.hostname(),
647
+ platform: `${process.platform} ${os.release()}`,
648
+ rootDir: options.readiness.rootDir,
649
+ secretValuesExposed: false,
650
+ readiness: sanitizeForProof(options.readiness),
651
+ installs: options.installs ? sanitizeForProof(options.installs) : undefined,
652
+ checks: options.checks ? sanitizeForProof(options.checks) : undefined,
653
+ servers: options.servers ? sanitizeForProof(options.servers) : undefined,
654
+ summary: {
655
+ status: failures > 0 ? "failed" : warnings.length > 0 ? "warn" : "ready",
656
+ scanned: options.readiness.scanned,
657
+ ready: options.readiness.totals.ready,
658
+ needsEnv: options.readiness.totals.needsEnv,
659
+ partial: options.readiness.totals.partial,
660
+ installPassed: options.installs?.totals.passed ?? 0,
661
+ checksPassed: options.checks?.totals.passed ?? 0,
662
+ serversPassed: options.servers?.totals.passed ?? 0,
663
+ failures,
664
+ warnings: warnings.slice(0, 8),
665
+ },
666
+ };
667
+ }
668
+ function defaultMachineReportPath() {
669
+ return path.join(os.homedir(), ".youmd", "machine-reports", "latest.json");
670
+ }
671
+ function timestampForPath(value) {
672
+ return value.replace(/[:.]/g, "-");
673
+ }
674
+ function writeMachineVerificationProof(proof, reportPath = defaultMachineReportPath()) {
675
+ const latestPath = path.resolve(reportPath);
676
+ const reportDir = path.dirname(latestPath);
677
+ fs.mkdirSync(reportDir, { recursive: true });
678
+ const archivedPath = path.join(reportDir, `machine-proof-${timestampForPath(proof.generatedAt)}.json`);
679
+ const body = `${JSON.stringify(proof, null, 2)}\n`;
680
+ fs.writeFileSync(latestPath, body, { mode: 0o600 });
681
+ fs.writeFileSync(archivedPath, body, { mode: 0o600 });
682
+ return { latestPath, archivedPath };
683
+ }
684
+ //# sourceMappingURL=machine-verify.js.map