@gafj/gafj 0.1.1 → 0.1.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.
- package/README.md +1 -1
- package/bin/cli.js +27 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -28,7 +28,7 @@ Status: phases 1 through 6 built and tested (82 public tests on the synthetic ca
|
|
|
28
28
|
- Bullet register (screen 6): `house_rules.bullet_register` is `result_first` (default, RAS), `action_first`, or `posting`; it travels in the resume packet's HOUSE RULES and `core/rules/resume.md` says what each means. Same facts, same claims, same gate; only word order.
|
|
29
29
|
- Backup folder (screen 6): `config.backup_dir`, meant for a synced folder (Drive, OneDrive, Dropbox); `store/backup_dir.js` writes dated consistent copies there (`gafj backup`, the Back up now button, and one a day at `serve` start), keeps the newest 14, never prunes a pre-restore copy, and refuses the data folder itself. The live store never goes to a synced folder.
|
|
30
30
|
- Hosted tier (plan W, gates 2 and 4 as code): `http/hosted.js` runs the same routes, screens, and doors behind a Google sign-in with one store per user under `<root>/tenants/<uid>/`; the session names the uid, the uid names the folder, and no query spans tenants (`test/hosted.test.js` drives every parameterized route as user B with user A's ids and expects 404 and no leaked text). Provider keys, MCP config, and the restore test are 404 for hosted users; the model is reached through the relay with a service key and the uid (`x-gafj-service`, `x-gafj-uid`; the relay's second auth path), never a stored user token. `/account/export` streams a restorable backup, `/account/delete` removes the folder and every session. `http/identity.js` verifies Firebase ID tokens with node:crypto against Google's JWK set, no SDK. `ui/hosted/signin.html` is the one page with a loosened CSP (Firebase Auth from gstatic). `gafj serve-hosted` is configured by environment only; `deploy/hosted/` holds the Dockerfile and fly.toml; `functions/relay/deploy.js` builds the relay with Firebase Admin, Stripe, and the Anthropic SDK and `functions/index.js` exports it as `relay`. Nothing is deployed; `docs/operator-setup.md` is the list of what only the operator can do.
|
|
31
|
-
- `bin/cli.js`: `migrate`, `import`, `snapshot`, `review`, `lint`, `list`, `score-freeze`, `packet`, `ingest`, `render`, `export`, `backup`, `restore`, `mcp`, `print-mcp-config`, `serve`, `url`, `rotate-token`, `install-startup`, `allow-host`, `init`, `onboard`; every other command names its phase and exits
|
|
31
|
+
- `bin/cli.js`: `start` (the one command: candidate if none, then url or serve), `migrate`, `import`, `snapshot`, `review`, `lint`, `list`, `score-freeze`, `packet`, `ingest`, `render`, `export`, `backup`, `restore`, `mcp`, `print-mcp-config`, `serve`, `url`, `rotate-token`, `install-startup`, `allow-host`, `init`, `onboard`; every other command names its phase and exits
|
|
32
32
|
|
|
33
33
|
Onboarding another candidate, phase 5b:
|
|
34
34
|
|
package/bin/cli.js
CHANGED
|
@@ -39,6 +39,7 @@ const COMMANDS = {
|
|
|
39
39
|
render: "write a passed document as Markdown: render --document <id> [--out <dir>]",
|
|
40
40
|
list: "list ids: list postings|applications|interviews|documents|runs",
|
|
41
41
|
mcp: "run the stdio MCP server for Claude Desktop or Claude Code (stdout is the wire)",
|
|
42
|
+
start: "the one command: creates your candidate the first time (asks your name), then opens the app: start [--name <name>]",
|
|
42
43
|
serve: "run the local UI server on 127.0.0.1: serve [--port <n>] [--force] [--no-open]",
|
|
43
44
|
url: "print a fresh launch URL for the running server (and open the browser): url [--no-open] [--host <allowed host>] [--qr]",
|
|
44
45
|
"allow-host": "let a local HTTPS proxy front the server for your phone: allow-host <name.tail1234.ts.net> | allow-host --remove <name>",
|
|
@@ -487,10 +488,35 @@ async function main(argv) {
|
|
|
487
488
|
} finally { db.close(); }
|
|
488
489
|
}
|
|
489
490
|
|
|
491
|
+
if (cmd === "start") {
|
|
492
|
+
// One command for a new user and for every day after: make the candidate if there is none (asking the
|
|
493
|
+
// name once), then open the app: a fresh launch link if the server is up, otherwise serve.
|
|
494
|
+
const { readLock, pidAlive } = require("../http/server");
|
|
495
|
+
if (!cfg.candidate_id) {
|
|
496
|
+
let name = opts.name ? String(opts.name) : "";
|
|
497
|
+
if (!name && process.stdin.isTTY) {
|
|
498
|
+
const rl = require("readline").createInterface({ input: process.stdin, output: process.stdout });
|
|
499
|
+
name = await new Promise((resolve) => rl.question("Your name, as it should appear on a resume: ", (a) => { rl.close(); resolve(String(a || "").trim()); }));
|
|
500
|
+
}
|
|
501
|
+
name = name || "Candidate";
|
|
502
|
+
const db = openStore(home);
|
|
503
|
+
try {
|
|
504
|
+
const id = ulid(Date.now());
|
|
505
|
+
db.prepare("INSERT INTO candidate (id, name, created_at) VALUES (?, ?, ?)").run(id, name, nowIso());
|
|
506
|
+
cfg.candidate_id = id;
|
|
507
|
+
writeConfig(home.dir, cfg);
|
|
508
|
+
require("../store/onboarding").openBatch(db, { candidate_id: id, now: nowIso(), actor: ACTOR("start") });
|
|
509
|
+
} finally { db.close(); }
|
|
510
|
+
out(`welcome, ${name}. Your data lives in ${home.dir}`);
|
|
511
|
+
}
|
|
512
|
+
const lock = readLock(home.dir);
|
|
513
|
+
return main(lock && pidAlive(lock.pid) ? ["url"] : ["serve"]);
|
|
514
|
+
}
|
|
515
|
+
|
|
490
516
|
if (cmd === "serve") {
|
|
491
517
|
const { createServer, ensureSessionToken, readLock, writeLock, removeLock, pidAlive } = require("../http/server");
|
|
492
518
|
const pkg = require("../package.json");
|
|
493
|
-
if (!cfg.candidate_id) { process.stderr.write("no candidate yet; run gafj
|
|
519
|
+
if (!cfg.candidate_id) { process.stderr.write("no candidate yet; run gafj start\n"); process.exit(2); }
|
|
494
520
|
const lock = readLock(home.dir);
|
|
495
521
|
if (lock && pidAlive(lock.pid) && !opts.force) {
|
|
496
522
|
out(`gafj serve is already running (pid ${lock.pid}) at http://127.0.0.1:${lock.port}; run "gafj url" for a launch link, or serve --force`);
|
package/package.json
CHANGED