litmus-cli 0.2.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/commands/init.d.ts +2 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +153 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/submit.d.ts +4 -0
- package/dist/commands/submit.d.ts.map +1 -0
- package/dist/commands/submit.js +124 -0
- package/dist/commands/submit.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +36 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/api.d.ts +30 -0
- package/dist/lib/api.d.ts.map +1 -0
- package/dist/lib/api.js +54 -0
- package/dist/lib/api.js.map +1 -0
- package/dist/lib/config.d.ts +19 -0
- package/dist/lib/config.d.ts.map +1 -0
- package/dist/lib/config.js +40 -0
- package/dist/lib/config.js.map +1 -0
- package/dist/lib/extract.d.ts +6 -0
- package/dist/lib/extract.d.ts.map +1 -0
- package/dist/lib/extract.js +12 -0
- package/dist/lib/extract.js.map +1 -0
- package/dist/lib/tracker.d.ts +7 -0
- package/dist/lib/tracker.d.ts.map +1 -0
- package/dist/lib/tracker.js +36 -0
- package/dist/lib/tracker.js.map +1 -0
- package/dist/lib/zip.d.ts +10 -0
- package/dist/lib/zip.d.ts.map +1 -0
- package/dist/lib/zip.js +96 -0
- package/dist/lib/zip.js.map +1 -0
- package/dist/utils/detect-project.d.ts +11 -0
- package/dist/utils/detect-project.d.ts.map +1 -0
- package/dist/utils/detect-project.js +55 -0
- package/dist/utils/detect-project.js.map +1 -0
- package/dist/utils/errors.d.ts +19 -0
- package/dist/utils/errors.d.ts.map +1 -0
- package/dist/utils/errors.js +35 -0
- package/dist/utils/errors.js.map +1 -0
- package/dist/watcher.cjs +58 -0
- package/package.json +37 -0
- package/src/commands/init.ts +171 -0
- package/src/commands/submit.ts +141 -0
- package/src/index.ts +38 -0
- package/src/lib/api.ts +93 -0
- package/src/lib/config.ts +59 -0
- package/src/lib/extract.ts +15 -0
- package/src/lib/tracker.ts +38 -0
- package/src/lib/watcher.cjs +58 -0
- package/src/lib/zip.ts +104 -0
- package/src/utils/detect-project.ts +83 -0
- package/src/utils/errors.ts +41 -0
- package/tsconfig.json +19 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AAiBA,wBAAsB,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAyJ1D"}
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import { createWriteStream, unlinkSync } from "fs";
|
|
2
|
+
import { pipeline } from "stream/promises";
|
|
3
|
+
import { Readable } from "stream";
|
|
4
|
+
import path from "path";
|
|
5
|
+
import os from "os";
|
|
6
|
+
import chalk from "chalk";
|
|
7
|
+
import ora from "ora";
|
|
8
|
+
import { fetchInitMetadata, downloadZip } from "../lib/api.js";
|
|
9
|
+
import { writeConfig } from "../lib/config.js";
|
|
10
|
+
import { extractZip } from "../lib/extract.js";
|
|
11
|
+
import { startTracker } from "../lib/tracker.js";
|
|
12
|
+
import { detectProject } from "../utils/detect-project.js";
|
|
13
|
+
import { fatal, success, info, warn, FALLBACK_URL } from "../utils/errors.js";
|
|
14
|
+
import { execSync } from "child_process";
|
|
15
|
+
const DEFAULT_API_BASE = process.env.LITMUS_API_URL || "https://app.litmus.sh";
|
|
16
|
+
export async function runInit(token) {
|
|
17
|
+
const apiBase = DEFAULT_API_BASE;
|
|
18
|
+
// Step 1: Fetch metadata
|
|
19
|
+
const spinner = ora("Connecting to Litmus...").start();
|
|
20
|
+
let metadata;
|
|
21
|
+
try {
|
|
22
|
+
metadata = await fetchInitMetadata(apiBase, token);
|
|
23
|
+
spinner.succeed("Connected");
|
|
24
|
+
}
|
|
25
|
+
catch (err) {
|
|
26
|
+
spinner.fail("Connection failed");
|
|
27
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
28
|
+
fatal(msg, `Check your token or visit ${FALLBACK_URL} to download manually.`);
|
|
29
|
+
}
|
|
30
|
+
// Check for naming collision
|
|
31
|
+
const targetDir = path.resolve(process.cwd(), metadata.folderName);
|
|
32
|
+
const { existsSync } = await import("fs");
|
|
33
|
+
if (existsSync(targetDir)) {
|
|
34
|
+
fatal(`Folder "${metadata.folderName}" already exists in this directory.`, `Delete or rename it, then run: litmus init ${token}`);
|
|
35
|
+
}
|
|
36
|
+
// Print what we're setting up
|
|
37
|
+
console.log();
|
|
38
|
+
console.log(chalk.bold(` ${metadata.assessmentName}`));
|
|
39
|
+
if (metadata.deadline) {
|
|
40
|
+
const deadline = new Date(metadata.deadline);
|
|
41
|
+
const hoursLeft = Math.max(0, Math.floor((deadline.getTime() - Date.now()) / (1000 * 60 * 60)));
|
|
42
|
+
const deadlineStr = deadline.toLocaleString();
|
|
43
|
+
if (hoursLeft < 24) {
|
|
44
|
+
warn(`Deadline in ${hoursLeft} hours (${deadlineStr})`);
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
info(`Deadline: ${deadlineStr}`);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
if (metadata.timeLimit) {
|
|
51
|
+
info(`Time limit: ${metadata.timeLimit} minutes`);
|
|
52
|
+
}
|
|
53
|
+
console.log();
|
|
54
|
+
// Step 2: Download ZIP to a temp file
|
|
55
|
+
const downloadSpinner = ora("Downloading assessment...").start();
|
|
56
|
+
const tmpZip = path.join(os.tmpdir(), `litmus-${Date.now()}.zip`);
|
|
57
|
+
try {
|
|
58
|
+
const zipResponse = await downloadZip(apiBase, token);
|
|
59
|
+
if (!zipResponse.body) {
|
|
60
|
+
throw new Error("Empty response from server");
|
|
61
|
+
}
|
|
62
|
+
const nodeStream = Readable.fromWeb(zipResponse.body);
|
|
63
|
+
await pipeline(nodeStream, createWriteStream(tmpZip));
|
|
64
|
+
downloadSpinner.succeed("Downloaded");
|
|
65
|
+
}
|
|
66
|
+
catch (err) {
|
|
67
|
+
downloadSpinner.fail("Download failed");
|
|
68
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
69
|
+
fatal(msg, `Visit ${FALLBACK_URL} to download manually.`);
|
|
70
|
+
}
|
|
71
|
+
// Step 3: Extract from temp file to target directory
|
|
72
|
+
const extractSpinner = ora(`Setting up ${metadata.folderName}/...`).start();
|
|
73
|
+
try {
|
|
74
|
+
await extractZip(tmpZip, targetDir);
|
|
75
|
+
extractSpinner.succeed(`Created ${chalk.bold(metadata.folderName)}/`);
|
|
76
|
+
}
|
|
77
|
+
catch (err) {
|
|
78
|
+
extractSpinner.fail("Extraction failed");
|
|
79
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
80
|
+
fatal(msg, `Visit ${FALLBACK_URL} to download manually.`);
|
|
81
|
+
}
|
|
82
|
+
finally {
|
|
83
|
+
try {
|
|
84
|
+
unlinkSync(tmpZip);
|
|
85
|
+
}
|
|
86
|
+
catch { /* cleanup */ }
|
|
87
|
+
}
|
|
88
|
+
// Step 4: Initialize git repo with initial commit
|
|
89
|
+
try {
|
|
90
|
+
execSync("git init", { cwd: targetDir, stdio: "pipe" });
|
|
91
|
+
execSync("git add -A", { cwd: targetDir, stdio: "pipe" });
|
|
92
|
+
execSync("git commit -m \"Assessment: initial state\"", { cwd: targetDir, stdio: "pipe" });
|
|
93
|
+
}
|
|
94
|
+
catch {
|
|
95
|
+
// Non-critical — git may not be installed; analysis degrades gracefully
|
|
96
|
+
}
|
|
97
|
+
// Step 5: Write .litmus/config.json
|
|
98
|
+
await writeConfig(targetDir, {
|
|
99
|
+
assessmentId: metadata.assessmentId,
|
|
100
|
+
assessmentName: metadata.assessmentName,
|
|
101
|
+
candidateEmail: metadata.candidateEmail,
|
|
102
|
+
candidateName: metadata.candidateName,
|
|
103
|
+
token,
|
|
104
|
+
startedAt: metadata.startedAt,
|
|
105
|
+
deadline: metadata.deadline,
|
|
106
|
+
timeLimit: metadata.timeLimit,
|
|
107
|
+
apiBase,
|
|
108
|
+
});
|
|
109
|
+
// Step 5: Detect project type and optionally install
|
|
110
|
+
const project = detectProject(targetDir);
|
|
111
|
+
if (project.installCommand) {
|
|
112
|
+
console.log();
|
|
113
|
+
const installSpinner = ora(`Running ${chalk.cyan(project.installCommand)}... (this may take a minute)`).start();
|
|
114
|
+
try {
|
|
115
|
+
execSync(project.installCommand, {
|
|
116
|
+
cwd: targetDir,
|
|
117
|
+
stdio: "pipe",
|
|
118
|
+
});
|
|
119
|
+
installSpinner.succeed("Dependencies installed");
|
|
120
|
+
}
|
|
121
|
+
catch {
|
|
122
|
+
installSpinner.warn(`Couldn't run "${project.installCommand}" automatically. Run it manually inside ${metadata.folderName}/.`);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
// Step 6: Start tracker in background
|
|
126
|
+
try {
|
|
127
|
+
startTracker(targetDir);
|
|
128
|
+
}
|
|
129
|
+
catch {
|
|
130
|
+
// Non-critical
|
|
131
|
+
}
|
|
132
|
+
// Done — print next steps
|
|
133
|
+
console.log();
|
|
134
|
+
success("Assessment ready");
|
|
135
|
+
console.log();
|
|
136
|
+
console.log(chalk.bold(" Next steps:"));
|
|
137
|
+
console.log();
|
|
138
|
+
console.log(` ${chalk.cyan(`cd ${metadata.folderName}`)}`);
|
|
139
|
+
if (project.runHint) {
|
|
140
|
+
console.log(` ${chalk.dim(`# ${project.runHint}`)}`);
|
|
141
|
+
}
|
|
142
|
+
console.log();
|
|
143
|
+
console.log(chalk.dim(" Your work is being tracked. When you're done:"));
|
|
144
|
+
console.log();
|
|
145
|
+
console.log(` ${chalk.cyan("litmus submit")}`);
|
|
146
|
+
console.log();
|
|
147
|
+
if (metadata.deadline) {
|
|
148
|
+
const deadline = new Date(metadata.deadline);
|
|
149
|
+
console.log(chalk.dim(` Deadline: ${deadline.toLocaleString()}`));
|
|
150
|
+
console.log();
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
//# sourceMappingURL=init.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"submit.d.ts","sourceRoot":"","sources":["../../src/commands/submit.ts"],"names":[],"mappings":"AAWA,wBAAsB,SAAS,CAAC,IAAI,EAAE;IAAE,GAAG,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAiItE"}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { statSync, unlinkSync } from "fs";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import chalk from "chalk";
|
|
4
|
+
import ora from "ora";
|
|
5
|
+
import * as readline from "readline/promises";
|
|
6
|
+
import { stdin as input, stdout as output } from "process";
|
|
7
|
+
import { readConfig } from "../lib/config.js";
|
|
8
|
+
import { submitZip } from "../lib/api.js";
|
|
9
|
+
import { createSubmissionZip } from "../lib/zip.js";
|
|
10
|
+
import { fatal, success, warn, info, FALLBACK_URL } from "../utils/errors.js";
|
|
11
|
+
export async function runSubmit(opts) {
|
|
12
|
+
// Step 1: Read config
|
|
13
|
+
const config = await readConfig();
|
|
14
|
+
if (!config) {
|
|
15
|
+
fatal("No Litmus assessment found in this directory.", "Run this command from inside your assessment folder, or run 'litmus init <token>' first.");
|
|
16
|
+
}
|
|
17
|
+
// Step 2: Check deadline
|
|
18
|
+
if (config.deadline) {
|
|
19
|
+
const deadline = new Date(config.deadline);
|
|
20
|
+
const now = new Date();
|
|
21
|
+
if (now > deadline) {
|
|
22
|
+
fatal(`The submission deadline passed at ${deadline.toLocaleString()}.`, `Contact the company if you need an extension. Visit ${FALLBACK_URL} for help.`);
|
|
23
|
+
}
|
|
24
|
+
const minsLeft = Math.floor((deadline.getTime() - now.getTime()) / (1000 * 60));
|
|
25
|
+
if (minsLeft < 30) {
|
|
26
|
+
warn(`Only ${minsLeft} minutes left before the deadline!`);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
// Step 3: Find the project root (where .litmus/config.json lives)
|
|
30
|
+
let projectRoot = process.cwd();
|
|
31
|
+
// readConfig walks up the tree, so we use the config's assessed location
|
|
32
|
+
// The config file is at .litmus/config.json relative to the project root
|
|
33
|
+
// We find it by searching from cwd up, same as readConfig does
|
|
34
|
+
{
|
|
35
|
+
let dir = process.cwd();
|
|
36
|
+
while (true) {
|
|
37
|
+
const configPath = path.join(dir, ".litmus", "config.json");
|
|
38
|
+
const { existsSync } = await import("fs");
|
|
39
|
+
if (existsSync(configPath)) {
|
|
40
|
+
projectRoot = dir;
|
|
41
|
+
break;
|
|
42
|
+
}
|
|
43
|
+
const parent = path.dirname(dir);
|
|
44
|
+
if (parent === dir)
|
|
45
|
+
break;
|
|
46
|
+
dir = parent;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
// Step 4: Create the submission ZIP
|
|
50
|
+
const zipSpinner = ora("Preparing submission...").start();
|
|
51
|
+
let zipPath;
|
|
52
|
+
try {
|
|
53
|
+
zipPath = await createSubmissionZip(projectRoot);
|
|
54
|
+
zipSpinner.succeed("Submission prepared");
|
|
55
|
+
}
|
|
56
|
+
catch (err) {
|
|
57
|
+
zipSpinner.fail("Failed to create submission archive");
|
|
58
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
59
|
+
fatal(msg, `Visit ${FALLBACK_URL} to submit manually.`);
|
|
60
|
+
}
|
|
61
|
+
// Step 5: Show what's being submitted
|
|
62
|
+
const zipSizeMb = (statSync(zipPath).size / (1024 * 1024)).toFixed(1);
|
|
63
|
+
const folderName = path.basename(projectRoot);
|
|
64
|
+
console.log();
|
|
65
|
+
console.log(chalk.bold(` Submitting: ${config.assessmentName}`));
|
|
66
|
+
info(` Archive size: ${zipSizeMb} MB`);
|
|
67
|
+
info(` Tracking log included`);
|
|
68
|
+
if (config.deadline) {
|
|
69
|
+
info(` Deadline: ${new Date(config.deadline).toLocaleString()}`);
|
|
70
|
+
}
|
|
71
|
+
console.log();
|
|
72
|
+
// Step 6: Confirm (unless --yes flag)
|
|
73
|
+
if (!opts.yes) {
|
|
74
|
+
const rl = readline.createInterface({ input, output });
|
|
75
|
+
let answer;
|
|
76
|
+
try {
|
|
77
|
+
answer = await rl.question(chalk.bold(" Confirm submission? ") + chalk.dim("[Y/n] "));
|
|
78
|
+
}
|
|
79
|
+
finally {
|
|
80
|
+
rl.close();
|
|
81
|
+
}
|
|
82
|
+
const confirmed = answer.trim().toLowerCase();
|
|
83
|
+
if (confirmed !== "" && confirmed !== "y" && confirmed !== "yes") {
|
|
84
|
+
console.log();
|
|
85
|
+
console.log(chalk.dim(" Submission cancelled. Your work is saved."));
|
|
86
|
+
console.log();
|
|
87
|
+
try {
|
|
88
|
+
unlinkSync(zipPath);
|
|
89
|
+
}
|
|
90
|
+
catch { /* cleanup */ }
|
|
91
|
+
process.exit(0);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
console.log();
|
|
95
|
+
// Step 7: Upload
|
|
96
|
+
const uploadSpinner = ora("Uploading submission...").start();
|
|
97
|
+
try {
|
|
98
|
+
const fileName = `${folderName}_submission.zip`;
|
|
99
|
+
const result = await submitZip(config.apiBase, config.token, zipPath, fileName);
|
|
100
|
+
uploadSpinner.succeed("Submission received");
|
|
101
|
+
console.log();
|
|
102
|
+
success("You're done!");
|
|
103
|
+
console.log();
|
|
104
|
+
console.log(chalk.dim(" The company will review your work and be in touch."));
|
|
105
|
+
if (result.submissionId) {
|
|
106
|
+
console.log(chalk.dim(` Submission ID: ${result.submissionId}`));
|
|
107
|
+
}
|
|
108
|
+
console.log();
|
|
109
|
+
}
|
|
110
|
+
catch (err) {
|
|
111
|
+
uploadSpinner.fail("Upload failed");
|
|
112
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
113
|
+
console.log();
|
|
114
|
+
fatal(msg, `To submit manually, visit ${FALLBACK_URL} and upload your ZIP from there.`);
|
|
115
|
+
}
|
|
116
|
+
finally {
|
|
117
|
+
// Clean up temp ZIP
|
|
118
|
+
try {
|
|
119
|
+
unlinkSync(zipPath);
|
|
120
|
+
}
|
|
121
|
+
catch { /* cleanup */ }
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
//# sourceMappingURL=submit.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"submit.js","sourceRoot":"","sources":["../../src/commands/submit.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,IAAI,CAAA;AACzC,OAAO,IAAI,MAAM,MAAM,CAAA;AACvB,OAAO,KAAK,MAAM,OAAO,CAAA;AACzB,OAAO,GAAG,MAAM,KAAK,CAAA;AACrB,OAAO,KAAK,QAAQ,MAAM,mBAAmB,CAAA;AAC7C,OAAO,EAAE,KAAK,IAAI,KAAK,EAAE,MAAM,IAAI,MAAM,EAAE,MAAM,SAAS,CAAA;AAC1D,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAC7C,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAA;AACzC,OAAO,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAA;AACnD,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AAE7E,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,IAAuB;IACrD,sBAAsB;IACtB,MAAM,MAAM,GAAG,MAAM,UAAU,EAAE,CAAA;IAEjC,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,KAAK,CACH,+CAA+C,EAC/C,0FAA0F,CAC3F,CAAA;IACH,CAAC;IAED,yBAAyB;IACzB,IAAI,MAAM,CAAC,QAAQ,EAAE,CAAC;QACpB,MAAM,QAAQ,GAAG,IAAI,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAA;QAC1C,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAA;QAEtB,IAAI,GAAG,GAAG,QAAQ,EAAE,CAAC;YACnB,KAAK,CACH,qCAAqC,QAAQ,CAAC,cAAc,EAAE,GAAG,EACjE,uDAAuD,YAAY,YAAY,CAChF,CAAA;QACH,CAAC;QAED,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,OAAO,EAAE,GAAG,GAAG,CAAC,OAAO,EAAE,CAAC,GAAG,CAAC,IAAI,GAAG,EAAE,CAAC,CAAC,CAAA;QAC/E,IAAI,QAAQ,GAAG,EAAE,EAAE,CAAC;YAClB,IAAI,CAAC,QAAQ,QAAQ,oCAAoC,CAAC,CAAA;QAC5D,CAAC;IACH,CAAC;IAED,kEAAkE;IAClE,IAAI,WAAW,GAAG,OAAO,CAAC,GAAG,EAAE,CAAA;IAC/B,yEAAyE;IACzE,yEAAyE;IACzE,+DAA+D;IAC/D,CAAC;QACC,IAAI,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE,CAAA;QACvB,OAAO,IAAI,EAAE,CAAC;YACZ,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,SAAS,EAAE,aAAa,CAAC,CAAA;YAC3D,MAAM,EAAE,UAAU,EAAE,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,CAAA;YACzC,IAAI,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;gBAC3B,WAAW,GAAG,GAAG,CAAA;gBACjB,MAAK;YACP,CAAC;YACD,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAA;YAChC,IAAI,MAAM,KAAK,GAAG;gBAAE,MAAK;YACzB,GAAG,GAAG,MAAM,CAAA;QACd,CAAC;IACH,CAAC;IAED,oCAAoC;IACpC,MAAM,UAAU,GAAG,GAAG,CAAC,yBAAyB,CAAC,CAAC,KAAK,EAAE,CAAA;IACzD,IAAI,OAAe,CAAA;IAEnB,IAAI,CAAC;QACH,OAAO,GAAG,MAAM,mBAAmB,CAAC,WAAW,CAAC,CAAA;QAChD,UAAU,CAAC,OAAO,CAAC,qBAAqB,CAAC,CAAA;IAC3C,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,UAAU,CAAC,IAAI,CAAC,qCAAqC,CAAC,CAAA;QACtD,MAAM,GAAG,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;QAC5D,KAAK,CAAC,GAAG,EAAE,SAAS,YAAY,sBAAsB,CAAC,CAAA;IACzD,CAAC;IAED,sCAAsC;IACtC,MAAM,SAAS,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,IAAI,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAA;IACrE,MAAM,UAAU,GAAG,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAA;IAE7C,OAAO,CAAC,GAAG,EAAE,CAAA;IACb,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,iBAAiB,MAAM,CAAC,cAAc,EAAE,CAAC,CAAC,CAAA;IACjE,IAAI,CAAC,mBAAmB,SAAS,KAAK,CAAC,CAAA;IACvC,IAAI,CAAC,yBAAyB,CAAC,CAAA;IAC/B,IAAI,MAAM,CAAC,QAAQ,EAAE,CAAC;QACpB,IAAI,CAAC,eAAe,IAAI,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,cAAc,EAAE,EAAE,CAAC,CAAA;IACnE,CAAC;IACD,OAAO,CAAC,GAAG,EAAE,CAAA;IAEb,sCAAsC;IACtC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC;QACd,MAAM,EAAE,GAAG,QAAQ,CAAC,eAAe,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAA;QACtD,IAAI,MAAc,CAAA;QAClB,IAAI,CAAC;YACH,MAAM,GAAG,MAAM,EAAE,CAAC,QAAQ,CACxB,KAAK,CAAC,IAAI,CAAC,wBAAwB,CAAC,GAAG,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,CAC3D,CAAA;QACH,CAAC;gBAAS,CAAC;YACT,EAAE,CAAC,KAAK,EAAE,CAAA;QACZ,CAAC;QAED,MAAM,SAAS,GAAG,MAAM,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAA;QAC7C,IAAI,SAAS,KAAK,EAAE,IAAI,SAAS,KAAK,GAAG,IAAI,SAAS,KAAK,KAAK,EAAE,CAAC;YACjE,OAAO,CAAC,GAAG,EAAE,CAAA;YACb,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,6CAA6C,CAAC,CAAC,CAAA;YACrE,OAAO,CAAC,GAAG,EAAE,CAAA;YACb,IAAI,CAAC;gBAAC,UAAU,CAAC,OAAO,CAAC,CAAA;YAAC,CAAC;YAAC,MAAM,CAAC,CAAC,aAAa,CAAC,CAAC;YACnD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;QACjB,CAAC;IACH,CAAC;IAED,OAAO,CAAC,GAAG,EAAE,CAAA;IAEb,iBAAiB;IACjB,MAAM,aAAa,GAAG,GAAG,CAAC,yBAAyB,CAAC,CAAC,KAAK,EAAE,CAAA;IAE5D,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,GAAG,UAAU,iBAAiB,CAAA;QAC/C,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAA;QAC/E,aAAa,CAAC,OAAO,CAAC,qBAAqB,CAAC,CAAA;QAE5C,OAAO,CAAC,GAAG,EAAE,CAAA;QACb,OAAO,CAAC,cAAc,CAAC,CAAA;QACvB,OAAO,CAAC,GAAG,EAAE,CAAA;QACb,OAAO,CAAC,GAAG,CACT,KAAK,CAAC,GAAG,CAAC,sDAAsD,CAAC,CAClE,CAAA;QACD,IAAI,MAAM,CAAC,YAAY,EAAE,CAAC;YACxB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,oBAAoB,MAAM,CAAC,YAAY,EAAE,CAAC,CAAC,CAAA;QACnE,CAAC;QACD,OAAO,CAAC,GAAG,EAAE,CAAA;IACf,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,aAAa,CAAC,IAAI,CAAC,eAAe,CAAC,CAAA;QACnC,MAAM,GAAG,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;QAC5D,OAAO,CAAC,GAAG,EAAE,CAAA;QACb,KAAK,CACH,GAAG,EACH,6BAA6B,YAAY,kCAAkC,CAC5E,CAAA;IACH,CAAC;YAAS,CAAC;QACT,oBAAoB;QACpB,IAAI,CAAC;YAAC,UAAU,CAAC,OAAO,CAAC,CAAA;QAAC,CAAC;QAAC,MAAM,CAAC,CAAC,aAAa,CAAC,CAAC;IACrD,CAAC;AACH,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,36 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { program } from "commander";
|
|
3
|
+
import { runInit } from "./commands/init.js";
|
|
4
|
+
import { runSubmit } from "./commands/submit.js";
|
|
5
|
+
const VERSION = "0.1.0";
|
|
6
|
+
program
|
|
7
|
+
.name("litmus")
|
|
8
|
+
.description("Litmus engineering assessment CLI")
|
|
9
|
+
.version(VERSION);
|
|
10
|
+
program
|
|
11
|
+
.command("init <token>")
|
|
12
|
+
.description("Download and set up a Litmus assessment")
|
|
13
|
+
.action(async (token) => {
|
|
14
|
+
try {
|
|
15
|
+
await runInit(token);
|
|
16
|
+
}
|
|
17
|
+
catch (err) {
|
|
18
|
+
console.error(err instanceof Error ? err.message : String(err));
|
|
19
|
+
process.exit(1);
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
program
|
|
23
|
+
.command("submit")
|
|
24
|
+
.description("Submit your completed assessment")
|
|
25
|
+
.option("-y, --yes", "Skip confirmation prompt")
|
|
26
|
+
.action(async (opts) => {
|
|
27
|
+
try {
|
|
28
|
+
await runSubmit(opts);
|
|
29
|
+
}
|
|
30
|
+
catch (err) {
|
|
31
|
+
console.error(err instanceof Error ? err.message : String(err));
|
|
32
|
+
process.exit(1);
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
program.parse();
|
|
36
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AACnC,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAA;AAC5C,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAA;AAEhD,MAAM,OAAO,GAAG,OAAO,CAAA;AAEvB,OAAO;KACJ,IAAI,CAAC,QAAQ,CAAC;KACd,WAAW,CAAC,mCAAmC,CAAC;KAChD,OAAO,CAAC,OAAO,CAAC,CAAA;AAEnB,OAAO;KACJ,OAAO,CAAC,cAAc,CAAC;KACvB,WAAW,CAAC,yCAAyC,CAAC;KACtD,MAAM,CAAC,KAAK,EAAE,KAAa,EAAE,EAAE;IAC9B,IAAI,CAAC;QACH,MAAM,OAAO,CAAC,KAAK,CAAC,CAAA;IACtB,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,CAAC,KAAK,CAAC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAA;QAC/D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IACjB,CAAC;AACH,CAAC,CAAC,CAAA;AAEJ,OAAO;KACJ,OAAO,CAAC,QAAQ,CAAC;KACjB,WAAW,CAAC,kCAAkC,CAAC;KAC/C,MAAM,CAAC,WAAW,EAAE,0BAA0B,CAAC;KAC/C,MAAM,CAAC,KAAK,EAAE,IAAuB,EAAE,EAAE;IACxC,IAAI,CAAC;QACH,MAAM,SAAS,CAAC,IAAI,CAAC,CAAA;IACvB,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,CAAC,KAAK,CAAC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAA;QAC/D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IACjB,CAAC;AACH,CAAC,CAAC,CAAA;AAEJ,OAAO,CAAC,KAAK,EAAE,CAAA"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export interface InitMetadata {
|
|
2
|
+
assessmentId: string;
|
|
3
|
+
assessmentName: string;
|
|
4
|
+
folderName: string;
|
|
5
|
+
candidateEmail: string;
|
|
6
|
+
candidateName: string;
|
|
7
|
+
deadline: string | null;
|
|
8
|
+
timeLimit: number | null;
|
|
9
|
+
startedAt: string;
|
|
10
|
+
}
|
|
11
|
+
export interface SubmitResult {
|
|
12
|
+
success: boolean;
|
|
13
|
+
submissionId: string;
|
|
14
|
+
message: string;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Fetch assessment metadata by token.
|
|
18
|
+
* Marks the candidate as in_progress if they were pending.
|
|
19
|
+
*/
|
|
20
|
+
export declare function fetchInitMetadata(apiBase: string, token: string): Promise<InitMetadata>;
|
|
21
|
+
/**
|
|
22
|
+
* Download the candidate ZIP by token.
|
|
23
|
+
* Returns a ReadableStream of the ZIP bytes.
|
|
24
|
+
*/
|
|
25
|
+
export declare function downloadZip(apiBase: string, token: string): Promise<Response>;
|
|
26
|
+
/**
|
|
27
|
+
* Upload a ZIP file for submission.
|
|
28
|
+
*/
|
|
29
|
+
export declare function submitZip(apiBase: string, token: string, zipPath: string, fileName: string): Promise<SubmitResult>;
|
|
30
|
+
//# sourceMappingURL=api.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../../src/lib/api.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,YAAY;IAC3B,YAAY,EAAE,MAAM,CAAA;IACpB,cAAc,EAAE,MAAM,CAAA;IACtB,UAAU,EAAE,MAAM,CAAA;IAClB,cAAc,EAAE,MAAM,CAAA;IACtB,aAAa,EAAE,MAAM,CAAA;IACrB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;IACvB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,SAAS,EAAE,MAAM,CAAA;CAClB;AAED,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,OAAO,CAAA;IAChB,YAAY,EAAE,MAAM,CAAA;IACpB,OAAO,EAAE,MAAM,CAAA;CAChB;AAED;;;GAGG;AACH,wBAAsB,iBAAiB,CACrC,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,YAAY,CAAC,CAWvB;AAED;;;GAGG;AACH,wBAAsB,WAAW,CAC/B,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,QAAQ,CAAC,CAWnB;AAED;;GAEG;AACH,wBAAsB,SAAS,CAC7B,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,YAAY,CAAC,CAwBvB"}
|
package/dist/lib/api.js
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import FormData from "form-data";
|
|
2
|
+
import { createReadStream } from "fs";
|
|
3
|
+
/**
|
|
4
|
+
* Fetch assessment metadata by token.
|
|
5
|
+
* Marks the candidate as in_progress if they were pending.
|
|
6
|
+
*/
|
|
7
|
+
export async function fetchInitMetadata(apiBase, token) {
|
|
8
|
+
const url = `${apiBase}/api/cli/init?token=${encodeURIComponent(token)}`;
|
|
9
|
+
const res = await fetch(url);
|
|
10
|
+
const body = await res.json().catch(() => ({}));
|
|
11
|
+
if (!res.ok) {
|
|
12
|
+
const message = body.message || body.error || `Server returned ${res.status}`;
|
|
13
|
+
throw new Error(message);
|
|
14
|
+
}
|
|
15
|
+
return body;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Download the candidate ZIP by token.
|
|
19
|
+
* Returns a ReadableStream of the ZIP bytes.
|
|
20
|
+
*/
|
|
21
|
+
export async function downloadZip(apiBase, token) {
|
|
22
|
+
const url = `${apiBase}/api/cli/download?token=${encodeURIComponent(token)}`;
|
|
23
|
+
const res = await fetch(url);
|
|
24
|
+
if (!res.ok) {
|
|
25
|
+
const body = await res.json().catch(() => ({}));
|
|
26
|
+
const message = body.message || body.error || `Server returned ${res.status}`;
|
|
27
|
+
throw new Error(message);
|
|
28
|
+
}
|
|
29
|
+
return res;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Upload a ZIP file for submission.
|
|
33
|
+
*/
|
|
34
|
+
export async function submitZip(apiBase, token, zipPath, fileName) {
|
|
35
|
+
const url = `${apiBase}/api/cli/submit?token=${encodeURIComponent(token)}`;
|
|
36
|
+
const form = new FormData();
|
|
37
|
+
form.append("file", createReadStream(zipPath), {
|
|
38
|
+
filename: fileName,
|
|
39
|
+
contentType: "application/zip",
|
|
40
|
+
});
|
|
41
|
+
const res = await fetch(url, {
|
|
42
|
+
method: "POST",
|
|
43
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
44
|
+
body: form,
|
|
45
|
+
headers: form.getHeaders(),
|
|
46
|
+
});
|
|
47
|
+
const body = await res.json().catch(() => ({}));
|
|
48
|
+
if (!res.ok) {
|
|
49
|
+
const message = body.message || body.error || `Server returned ${res.status}`;
|
|
50
|
+
throw new Error(message);
|
|
51
|
+
}
|
|
52
|
+
return body;
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=api.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api.js","sourceRoot":"","sources":["../../src/lib/api.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,MAAM,WAAW,CAAA;AAChC,OAAO,EAAE,gBAAgB,EAAE,MAAM,IAAI,CAAA;AAmBrC;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,OAAe,EACf,KAAa;IAEb,MAAM,GAAG,GAAG,GAAG,OAAO,uBAAuB,kBAAkB,CAAC,KAAK,CAAC,EAAE,CAAA;IACxE,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,CAAC,CAAA;IAC5B,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC,CAA4B,CAAA;IAE1E,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;QACZ,MAAM,OAAO,GAAI,IAAI,CAAC,OAAkB,IAAK,IAAI,CAAC,KAAgB,IAAI,mBAAmB,GAAG,CAAC,MAAM,EAAE,CAAA;QACrG,MAAM,IAAI,KAAK,CAAC,OAAO,CAAC,CAAA;IAC1B,CAAC;IAED,OAAO,IAA+B,CAAA;AACxC,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,OAAe,EACf,KAAa;IAEb,MAAM,GAAG,GAAG,GAAG,OAAO,2BAA2B,kBAAkB,CAAC,KAAK,CAAC,EAAE,CAAA;IAC5E,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,CAAC,CAAA;IAE5B,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;QACZ,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC,CAA4B,CAAA;QAC1E,MAAM,OAAO,GAAI,IAAI,CAAC,OAAkB,IAAK,IAAI,CAAC,KAAgB,IAAI,mBAAmB,GAAG,CAAC,MAAM,EAAE,CAAA;QACrG,MAAM,IAAI,KAAK,CAAC,OAAO,CAAC,CAAA;IAC1B,CAAC;IAED,OAAO,GAAG,CAAA;AACZ,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,SAAS,CAC7B,OAAe,EACf,KAAa,EACb,OAAe,EACf,QAAgB;IAEhB,MAAM,GAAG,GAAG,GAAG,OAAO,yBAAyB,kBAAkB,CAAC,KAAK,CAAC,EAAE,CAAA;IAE1E,MAAM,IAAI,GAAG,IAAI,QAAQ,EAAE,CAAA;IAC3B,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,OAAO,CAAC,EAAE;QAC7C,QAAQ,EAAE,QAAQ;QAClB,WAAW,EAAE,iBAAiB;KAC/B,CAAC,CAAA;IAEF,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;QAC3B,MAAM,EAAE,MAAM;QACd,8DAA8D;QAC9D,IAAI,EAAE,IAAW;QACjB,OAAO,EAAE,IAAI,CAAC,UAAU,EAAE;KAC3B,CAAC,CAAA;IAEF,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC,CAA4B,CAAA;IAE1E,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;QACZ,MAAM,OAAO,GAAI,IAAI,CAAC,OAAkB,IAAK,IAAI,CAAC,KAAgB,IAAI,mBAAmB,GAAG,CAAC,MAAM,EAAE,CAAA;QACrG,MAAM,IAAI,KAAK,CAAC,OAAO,CAAC,CAAA;IAC1B,CAAC;IAED,OAAO,IAA+B,CAAA;AACxC,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export interface LitmusConfig {
|
|
2
|
+
assessmentId: string;
|
|
3
|
+
assessmentName: string;
|
|
4
|
+
candidateEmail: string;
|
|
5
|
+
candidateName: string;
|
|
6
|
+
token: string;
|
|
7
|
+
startedAt: string;
|
|
8
|
+
deadline: string | null;
|
|
9
|
+
timeLimit: number | null;
|
|
10
|
+
apiBase: string;
|
|
11
|
+
}
|
|
12
|
+
export declare function getConfigPath(projectRoot: string): string;
|
|
13
|
+
export declare function writeConfig(projectRoot: string, config: LitmusConfig): Promise<void>;
|
|
14
|
+
/**
|
|
15
|
+
* Read .litmus/config.json from the current directory or a parent directory.
|
|
16
|
+
* Returns null if no config is found.
|
|
17
|
+
*/
|
|
18
|
+
export declare function readConfig(): Promise<LitmusConfig | null>;
|
|
19
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,YAAY;IAC3B,YAAY,EAAE,MAAM,CAAA;IACpB,cAAc,EAAE,MAAM,CAAA;IACtB,cAAc,EAAE,MAAM,CAAA;IACtB,aAAa,EAAE,MAAM,CAAA;IACrB,KAAK,EAAE,MAAM,CAAA;IACb,SAAS,EAAE,MAAM,CAAA;IACjB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;IACvB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,OAAO,EAAE,MAAM,CAAA;CAChB;AAKD,wBAAgB,aAAa,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAEzD;AAED,wBAAsB,WAAW,CAC/B,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,YAAY,GACnB,OAAO,CAAC,IAAI,CAAC,CAKf;AAED;;;GAGG;AACH,wBAAsB,UAAU,IAAI,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAqB/D"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { readFile, writeFile, mkdir } from "fs/promises";
|
|
2
|
+
import { existsSync } from "fs";
|
|
3
|
+
import path from "path";
|
|
4
|
+
const CONFIG_DIR = ".litmus";
|
|
5
|
+
const CONFIG_FILE = "config.json";
|
|
6
|
+
export function getConfigPath(projectRoot) {
|
|
7
|
+
return path.join(projectRoot, CONFIG_DIR, CONFIG_FILE);
|
|
8
|
+
}
|
|
9
|
+
export async function writeConfig(projectRoot, config) {
|
|
10
|
+
const configDir = path.join(projectRoot, CONFIG_DIR);
|
|
11
|
+
await mkdir(configDir, { recursive: true });
|
|
12
|
+
const configPath = path.join(configDir, CONFIG_FILE);
|
|
13
|
+
await writeFile(configPath, JSON.stringify(config, null, 2), "utf8");
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Read .litmus/config.json from the current directory or a parent directory.
|
|
17
|
+
* Returns null if no config is found.
|
|
18
|
+
*/
|
|
19
|
+
export async function readConfig() {
|
|
20
|
+
let dir = process.cwd();
|
|
21
|
+
// Walk up the directory tree looking for .litmus/config.json
|
|
22
|
+
while (true) {
|
|
23
|
+
const configPath = path.join(dir, CONFIG_DIR, CONFIG_FILE);
|
|
24
|
+
if (existsSync(configPath)) {
|
|
25
|
+
try {
|
|
26
|
+
const raw = await readFile(configPath, "utf8");
|
|
27
|
+
return JSON.parse(raw);
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
const parent = path.dirname(dir);
|
|
34
|
+
if (parent === dir)
|
|
35
|
+
break; // Reached filesystem root
|
|
36
|
+
dir = parent;
|
|
37
|
+
}
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,aAAa,CAAA;AACxD,OAAO,EAAE,UAAU,EAAE,MAAM,IAAI,CAAA;AAC/B,OAAO,IAAI,MAAM,MAAM,CAAA;AAcvB,MAAM,UAAU,GAAG,SAAS,CAAA;AAC5B,MAAM,WAAW,GAAG,aAAa,CAAA;AAEjC,MAAM,UAAU,aAAa,CAAC,WAAmB;IAC/C,OAAO,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,UAAU,EAAE,WAAW,CAAC,CAAA;AACxD,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,WAAmB,EACnB,MAAoB;IAEpB,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,UAAU,CAAC,CAAA;IACpD,MAAM,KAAK,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;IAC3C,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,WAAW,CAAC,CAAA;IACpD,MAAM,SAAS,CAAC,UAAU,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,MAAM,CAAC,CAAA;AACtE,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU;IAC9B,IAAI,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE,CAAA;IAEvB,6DAA6D;IAC7D,OAAO,IAAI,EAAE,CAAC;QACZ,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,UAAU,EAAE,WAAW,CAAC,CAAA;QAC1D,IAAI,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;YAC3B,IAAI,CAAC;gBACH,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC,CAAA;gBAC9C,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAiB,CAAA;YACxC,CAAC;YAAC,MAAM,CAAC;gBACP,OAAO,IAAI,CAAA;YACb,CAAC;QACH,CAAC;QAED,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAA;QAChC,IAAI,MAAM,KAAK,GAAG;YAAE,MAAK,CAAC,0BAA0B;QACpD,GAAG,GAAG,MAAM,CAAA;IACd,CAAC;IAED,OAAO,IAAI,CAAA;AACb,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extract.d.ts","sourceRoot":"","sources":["../../src/lib/extract.ts"],"names":[],"mappings":"AAGA;;;GAGG;AACH,wBAAsB,UAAU,CAC9B,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,IAAI,CAAC,CAIf"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { mkdir } from "fs/promises";
|
|
2
|
+
import unzipper from "unzipper";
|
|
3
|
+
/**
|
|
4
|
+
* Extract a ZIP file from disk to a target directory.
|
|
5
|
+
* Using Open.file + extract() is the most reliable unzipper API.
|
|
6
|
+
*/
|
|
7
|
+
export async function extractZip(zipPath, targetDir) {
|
|
8
|
+
await mkdir(targetDir, { recursive: true });
|
|
9
|
+
const directory = await unzipper.Open.file(zipPath);
|
|
10
|
+
await directory.extract({ path: targetDir });
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=extract.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extract.js","sourceRoot":"","sources":["../../src/lib/extract.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAA;AACnC,OAAO,QAAQ,MAAM,UAAU,CAAA;AAE/B;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAC9B,OAAe,EACf,SAAiB;IAEjB,MAAM,KAAK,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;IAC3C,MAAM,SAAS,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;IACnD,MAAM,SAAS,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,CAAA;AAC9C,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Start the chokidar file watcher in the background.
|
|
3
|
+
* Spawns dist/watcher.cjs as a detached process; logs file events to
|
|
4
|
+
* <projectDir>/.litmus/activity.jsonl for later inclusion in the submission ZIP.
|
|
5
|
+
*/
|
|
6
|
+
export declare function startTracker(projectDir: string): void;
|
|
7
|
+
//# sourceMappingURL=tracker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tracker.d.ts","sourceRoot":"","sources":["../../src/lib/tracker.ts"],"names":[],"mappings":"AAOA;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAyBrD"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { spawn } from "child_process";
|
|
2
|
+
import { mkdirSync, writeFileSync } from "fs";
|
|
3
|
+
import path from "path";
|
|
4
|
+
import { fileURLToPath } from "url";
|
|
5
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
6
|
+
/**
|
|
7
|
+
* Start the chokidar file watcher in the background.
|
|
8
|
+
* Spawns dist/watcher.cjs as a detached process; logs file events to
|
|
9
|
+
* <projectDir>/.litmus/activity.jsonl for later inclusion in the submission ZIP.
|
|
10
|
+
*/
|
|
11
|
+
export function startTracker(projectDir) {
|
|
12
|
+
const litmusDir = path.join(projectDir, ".litmus");
|
|
13
|
+
const activityLog = path.join(litmusDir, "activity.jsonl");
|
|
14
|
+
const pidFile = path.join(litmusDir, "tracker.pid");
|
|
15
|
+
const watcherScript = path.join(__dirname, "watcher.cjs");
|
|
16
|
+
try {
|
|
17
|
+
mkdirSync(litmusDir, { recursive: true });
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
// Non-critical
|
|
21
|
+
}
|
|
22
|
+
const child = spawn("node", [watcherScript, projectDir, activityLog], {
|
|
23
|
+
detached: true,
|
|
24
|
+
stdio: "ignore",
|
|
25
|
+
});
|
|
26
|
+
if (child.pid) {
|
|
27
|
+
child.unref();
|
|
28
|
+
try {
|
|
29
|
+
writeFileSync(pidFile, String(child.pid), "utf8");
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
// Non-critical
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=tracker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tracker.js","sourceRoot":"","sources":["../../src/lib/tracker.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,eAAe,CAAA;AACrC,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,IAAI,CAAA;AAC7C,OAAO,IAAI,MAAM,MAAM,CAAA;AACvB,OAAO,EAAE,aAAa,EAAE,MAAM,KAAK,CAAA;AAEnC,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAA;AAE9D;;;;GAIG;AACH,MAAM,UAAU,YAAY,CAAC,UAAkB;IAC7C,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,SAAS,CAAC,CAAA;IAClD,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,gBAAgB,CAAC,CAAA;IAC1D,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,aAAa,CAAC,CAAA;IACnD,MAAM,aAAa,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,aAAa,CAAC,CAAA;IAEzD,IAAI,CAAC;QACH,SAAS,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;IAC3C,CAAC;IAAC,MAAM,CAAC;QACP,eAAe;IACjB,CAAC;IAED,MAAM,KAAK,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,aAAa,EAAE,UAAU,EAAE,WAAW,CAAC,EAAE;QACpE,QAAQ,EAAE,IAAI;QACd,KAAK,EAAE,QAAQ;KAChB,CAAC,CAAA;IAEF,IAAI,KAAK,CAAC,GAAG,EAAE,CAAC;QACd,KAAK,CAAC,KAAK,EAAE,CAAA;QACb,IAAI,CAAC;YACH,aAAa,CAAC,OAAO,EAAE,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,CAAA;QACnD,CAAC;QAAC,MAAM,CAAC;YACP,eAAe;QACjB,CAAC;IACH,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Create a ZIP of the project directory for submission.
|
|
3
|
+
* Respects .gitignore patterns (basic support) and excludes common large dirs.
|
|
4
|
+
* Always includes .litmus/activity.jsonl (the tracking log).
|
|
5
|
+
*
|
|
6
|
+
* @param projectDir - Root of the project to zip
|
|
7
|
+
* @returns Path to the temporary ZIP file
|
|
8
|
+
*/
|
|
9
|
+
export declare function createSubmissionZip(projectDir: string): Promise<string>;
|
|
10
|
+
//# sourceMappingURL=zip.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"zip.d.ts","sourceRoot":"","sources":["../../src/lib/zip.ts"],"names":[],"mappings":"AA+BA;;;;;;;GAOG;AACH,wBAAsB,mBAAmB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAuB7E"}
|