terminalhire 0.2.4 → 0.2.5
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/bin/jpi-dispatch.js +123 -19
- package/dist/bin/jpi-sync.js +121 -17
- package/package.json +1 -1
package/dist/bin/jpi-dispatch.js
CHANGED
|
@@ -2959,8 +2959,9 @@ __export(jpi_sync_exports, {
|
|
|
2959
2959
|
});
|
|
2960
2960
|
import { readFileSync as readFileSync9, writeFileSync as writeFileSync7, mkdirSync as mkdirSync7, existsSync as existsSync7, rmSync as rmSync2 } from "fs";
|
|
2961
2961
|
import { join as join9 } from "path";
|
|
2962
|
-
import { homedir as homedir7 } from "os";
|
|
2962
|
+
import { homedir as homedir7, hostname as osHostname } from "os";
|
|
2963
2963
|
import { createInterface as createInterface4 } from "readline";
|
|
2964
|
+
import { spawn } from "child_process";
|
|
2964
2965
|
function ask2(question) {
|
|
2965
2966
|
const rl = createInterface4({ input: process.stdin, output: process.stdout });
|
|
2966
2967
|
return new Promise((res) => {
|
|
@@ -3003,14 +3004,14 @@ function buildConsentFields(profile) {
|
|
|
3003
3004
|
}
|
|
3004
3005
|
return fields;
|
|
3005
3006
|
}
|
|
3006
|
-
function
|
|
3007
|
+
function renderPreview(fields) {
|
|
3007
3008
|
console.log("");
|
|
3008
3009
|
console.log("\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510");
|
|
3009
3010
|
console.log("\u2502 terminalhire \u2014 sync your profile (Tier-1, opt-in) \u2502");
|
|
3010
3011
|
console.log("\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518");
|
|
3011
3012
|
console.log("");
|
|
3012
|
-
console.log("
|
|
3013
|
-
console.log("
|
|
3013
|
+
console.log(" The following data will be shared with staqs (terminalhire.com)");
|
|
3014
|
+
console.log(" AFTER you authorize + consent in the browser:");
|
|
3014
3015
|
console.log("");
|
|
3015
3016
|
for (const f of fields) {
|
|
3016
3017
|
const shown = Array.isArray(f.value) ? JSON.stringify(f.value) : String(f.value ?? "(not set)");
|
|
@@ -3029,6 +3030,30 @@ function renderConsentCard(fields) {
|
|
|
3029
3030
|
console.log(" This is NOT required to use terminalhire.");
|
|
3030
3031
|
console.log("");
|
|
3031
3032
|
}
|
|
3033
|
+
function openInBrowser(url) {
|
|
3034
|
+
let cmd;
|
|
3035
|
+
let args2;
|
|
3036
|
+
if (process.platform === "darwin") {
|
|
3037
|
+
cmd = "open";
|
|
3038
|
+
args2 = [url];
|
|
3039
|
+
} else if (process.platform === "win32") {
|
|
3040
|
+
cmd = "cmd";
|
|
3041
|
+
args2 = ["/c", "start", "", url];
|
|
3042
|
+
} else {
|
|
3043
|
+
cmd = "xdg-open";
|
|
3044
|
+
args2 = [url];
|
|
3045
|
+
}
|
|
3046
|
+
try {
|
|
3047
|
+
const child = spawn(cmd, args2, { stdio: "ignore", detached: true });
|
|
3048
|
+
child.on("error", () => {
|
|
3049
|
+
});
|
|
3050
|
+
child.unref();
|
|
3051
|
+
} catch {
|
|
3052
|
+
}
|
|
3053
|
+
}
|
|
3054
|
+
function sleep2(ms) {
|
|
3055
|
+
return new Promise((res) => setTimeout(res, ms));
|
|
3056
|
+
}
|
|
3032
3057
|
async function runPush() {
|
|
3033
3058
|
const { readProfile: readProfile2 } = await Promise.resolve().then(() => (init_profile(), profile_exports));
|
|
3034
3059
|
const profile = await readProfile2();
|
|
@@ -3040,15 +3065,91 @@ async function runPush() {
|
|
|
3040
3065
|
process.exit(1);
|
|
3041
3066
|
}
|
|
3042
3067
|
const fields = buildConsentFields(profile);
|
|
3043
|
-
|
|
3044
|
-
|
|
3045
|
-
|
|
3046
|
-
|
|
3047
|
-
|
|
3048
|
-
|
|
3049
|
-
|
|
3050
|
-
|
|
3051
|
-
|
|
3068
|
+
renderPreview(fields);
|
|
3069
|
+
await new Promise((resolve2) => {
|
|
3070
|
+
const rl = createInterface4({ input: process.stdin, output: process.stdout });
|
|
3071
|
+
rl.question(
|
|
3072
|
+
" Press Enter to open your browser to authorize + consent (or Ctrl-C to cancel)... ",
|
|
3073
|
+
() => {
|
|
3074
|
+
rl.close();
|
|
3075
|
+
resolve2();
|
|
3076
|
+
}
|
|
3077
|
+
);
|
|
3078
|
+
});
|
|
3079
|
+
console.log("");
|
|
3080
|
+
console.log(" Starting browser verification...");
|
|
3081
|
+
let begin;
|
|
3082
|
+
try {
|
|
3083
|
+
const r = await fetch(`${SYNC_BASE}/api/profile-sync/begin`, {
|
|
3084
|
+
method: "POST",
|
|
3085
|
+
headers: { "Content-Type": "application/json" },
|
|
3086
|
+
body: JSON.stringify({ hostname: osHostname() }),
|
|
3087
|
+
signal: AbortSignal.timeout(1e4)
|
|
3088
|
+
});
|
|
3089
|
+
if (!r.ok) {
|
|
3090
|
+
let detail = "";
|
|
3091
|
+
try {
|
|
3092
|
+
detail = (await r.json())?.message || "";
|
|
3093
|
+
} catch {
|
|
3094
|
+
}
|
|
3095
|
+
console.error(`
|
|
3096
|
+
Could not start sync: /api/profile-sync/begin returned ${r.status}. ${detail}`);
|
|
3097
|
+
if (r.status === 503) console.error(" (Tier-1 sync is not enabled on the server yet.)");
|
|
3098
|
+
process.exit(1);
|
|
3099
|
+
}
|
|
3100
|
+
begin = await r.json();
|
|
3101
|
+
} catch (err) {
|
|
3102
|
+
console.error(`
|
|
3103
|
+
Could not start sync: ${err instanceof Error ? err.message : String(err)}`);
|
|
3104
|
+
process.exit(1);
|
|
3105
|
+
}
|
|
3106
|
+
const { challenge, verifyUrl } = begin || {};
|
|
3107
|
+
if (!challenge || !verifyUrl) {
|
|
3108
|
+
console.error("\n Could not start sync: malformed begin response.");
|
|
3109
|
+
process.exit(1);
|
|
3110
|
+
}
|
|
3111
|
+
console.log("");
|
|
3112
|
+
console.log(" Open this URL in your browser to authorize + consent:");
|
|
3113
|
+
console.log(` ${verifyUrl}`);
|
|
3114
|
+
console.log("");
|
|
3115
|
+
console.log(" (Attempting to open it automatically...)");
|
|
3116
|
+
openInBrowser(verifyUrl);
|
|
3117
|
+
console.log(" Waiting for browser verification...");
|
|
3118
|
+
const deadline = Date.now() + POLL_TIMEOUT_MS;
|
|
3119
|
+
let proofToken = null;
|
|
3120
|
+
while (Date.now() < deadline) {
|
|
3121
|
+
await sleep2(POLL_INTERVAL_MS);
|
|
3122
|
+
let statusRes;
|
|
3123
|
+
try {
|
|
3124
|
+
statusRes = await fetch(
|
|
3125
|
+
`${SYNC_BASE}/api/profile-sync/status?challenge=${encodeURIComponent(challenge)}`,
|
|
3126
|
+
{ signal: AbortSignal.timeout(1e4) }
|
|
3127
|
+
);
|
|
3128
|
+
} catch {
|
|
3129
|
+
continue;
|
|
3130
|
+
}
|
|
3131
|
+
if (!statusRes.ok) {
|
|
3132
|
+
if (statusRes.status === 503) {
|
|
3133
|
+
console.error("\n Tier-1 sync is not enabled on the server yet.\n");
|
|
3134
|
+
process.exit(1);
|
|
3135
|
+
}
|
|
3136
|
+
continue;
|
|
3137
|
+
}
|
|
3138
|
+
let body;
|
|
3139
|
+
try {
|
|
3140
|
+
body = await statusRes.json();
|
|
3141
|
+
} catch {
|
|
3142
|
+
continue;
|
|
3143
|
+
}
|
|
3144
|
+
if (body && body.status === "verified" && body.proofToken) {
|
|
3145
|
+
proofToken = body.proofToken;
|
|
3146
|
+
break;
|
|
3147
|
+
}
|
|
3148
|
+
}
|
|
3149
|
+
if (!proofToken) {
|
|
3150
|
+
console.error("\n Timed out waiting for browser verification (10 min).");
|
|
3151
|
+
console.error(" Re-run `terminalhire sync --push` to try again.\n");
|
|
3152
|
+
process.exit(1);
|
|
3052
3153
|
}
|
|
3053
3154
|
const consentedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
3054
3155
|
const consentToken = {
|
|
@@ -3067,14 +3168,14 @@ async function runPush() {
|
|
|
3067
3168
|
};
|
|
3068
3169
|
const priorMarker = readMarker();
|
|
3069
3170
|
const rowToken = priorMarker && priorMarker.deleteToken ? priorMarker.deleteToken : null;
|
|
3070
|
-
const requestBody = { consentToken, profile: payloadProfile };
|
|
3171
|
+
const requestBody = { consentToken, profile: payloadProfile, proofToken };
|
|
3071
3172
|
if (rowToken) {
|
|
3072
3173
|
requestBody.rowToken = rowToken;
|
|
3073
3174
|
}
|
|
3074
|
-
console.log("\n Sending one-time snapshot...");
|
|
3175
|
+
console.log("\n Verified. Sending one-time snapshot...");
|
|
3075
3176
|
let res;
|
|
3076
3177
|
try {
|
|
3077
|
-
res = await fetch(`${
|
|
3178
|
+
res = await fetch(`${SYNC_BASE}/api/profile-sync`, {
|
|
3078
3179
|
method: "POST",
|
|
3079
3180
|
headers: { "Content-Type": "application/json" },
|
|
3080
3181
|
body: JSON.stringify(requestBody),
|
|
@@ -3097,7 +3198,7 @@ async function runPush() {
|
|
|
3097
3198
|
console.error(" (Tier-1 sync is not enabled on the server yet.)");
|
|
3098
3199
|
}
|
|
3099
3200
|
if (res.status === 403) {
|
|
3100
|
-
console.error(" (
|
|
3201
|
+
console.error(" (Ownership proof rejected, expired, or already used \u2014 re-run sync --push.)");
|
|
3101
3202
|
}
|
|
3102
3203
|
process.exit(1);
|
|
3103
3204
|
}
|
|
@@ -3214,13 +3315,16 @@ async function run7() {
|
|
|
3214
3315
|
console.log(" This is NOT required to use terminalhire.");
|
|
3215
3316
|
console.log("");
|
|
3216
3317
|
}
|
|
3217
|
-
var TH_DIR3, TIER1_MARKER, API_URL2, CONSENT_VERSION;
|
|
3318
|
+
var TH_DIR3, TIER1_MARKER, API_URL2, SYNC_BASE, POLL_INTERVAL_MS, POLL_TIMEOUT_MS, CONSENT_VERSION;
|
|
3218
3319
|
var init_jpi_sync = __esm({
|
|
3219
3320
|
"bin/jpi-sync.js"() {
|
|
3220
3321
|
"use strict";
|
|
3221
3322
|
TH_DIR3 = process.env["TERMINALHIRE_DIR"] || join9(homedir7(), ".terminalhire");
|
|
3222
3323
|
TIER1_MARKER = join9(TH_DIR3, "tier1.json");
|
|
3223
3324
|
API_URL2 = process.env["TERMINALHIRE_API_URL"] || process.env["JPI_API_URL"] || "https://terminalhire.com";
|
|
3325
|
+
SYNC_BASE = "https://www.terminalhire.com";
|
|
3326
|
+
POLL_INTERVAL_MS = 2e3;
|
|
3327
|
+
POLL_TIMEOUT_MS = 10 * 60 * 1e3;
|
|
3224
3328
|
CONSENT_VERSION = 1;
|
|
3225
3329
|
}
|
|
3226
3330
|
});
|
|
@@ -3234,7 +3338,7 @@ import { existsSync as existsSync8 } from "fs";
|
|
|
3234
3338
|
import { join as join10, resolve } from "path";
|
|
3235
3339
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
3236
3340
|
import { createInterface as createInterface5 } from "readline";
|
|
3237
|
-
import { spawnSync, spawn } from "child_process";
|
|
3341
|
+
import { spawnSync, spawn as spawn2 } from "child_process";
|
|
3238
3342
|
import { homedir as homedir8 } from "os";
|
|
3239
3343
|
function ask3(question) {
|
|
3240
3344
|
const rl = createInterface5({ input: process.stdin, output: process.stdout });
|
package/dist/bin/jpi-sync.js
CHANGED
|
@@ -691,11 +691,15 @@ var init_profile = __esm({
|
|
|
691
691
|
// bin/jpi-sync.js
|
|
692
692
|
import { readFileSync as readFileSync3, writeFileSync as writeFileSync2, mkdirSync as mkdirSync2, existsSync as existsSync2, rmSync } from "fs";
|
|
693
693
|
import { join as join3 } from "path";
|
|
694
|
-
import { homedir as homedir2 } from "os";
|
|
694
|
+
import { homedir as homedir2, hostname as osHostname } from "os";
|
|
695
695
|
import { createInterface } from "readline";
|
|
696
|
+
import { spawn } from "child_process";
|
|
696
697
|
var TH_DIR = process.env["TERMINALHIRE_DIR"] || join3(homedir2(), ".terminalhire");
|
|
697
698
|
var TIER1_MARKER = join3(TH_DIR, "tier1.json");
|
|
698
699
|
var API_URL = process.env["TERMINALHIRE_API_URL"] || process.env["JPI_API_URL"] || "https://terminalhire.com";
|
|
700
|
+
var SYNC_BASE = "https://www.terminalhire.com";
|
|
701
|
+
var POLL_INTERVAL_MS = 2e3;
|
|
702
|
+
var POLL_TIMEOUT_MS = 10 * 60 * 1e3;
|
|
699
703
|
var CONSENT_VERSION = 1;
|
|
700
704
|
function ask(question) {
|
|
701
705
|
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
@@ -739,14 +743,14 @@ function buildConsentFields(profile) {
|
|
|
739
743
|
}
|
|
740
744
|
return fields;
|
|
741
745
|
}
|
|
742
|
-
function
|
|
746
|
+
function renderPreview(fields) {
|
|
743
747
|
console.log("");
|
|
744
748
|
console.log("\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510");
|
|
745
749
|
console.log("\u2502 terminalhire \u2014 sync your profile (Tier-1, opt-in) \u2502");
|
|
746
750
|
console.log("\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518");
|
|
747
751
|
console.log("");
|
|
748
|
-
console.log("
|
|
749
|
-
console.log("
|
|
752
|
+
console.log(" The following data will be shared with staqs (terminalhire.com)");
|
|
753
|
+
console.log(" AFTER you authorize + consent in the browser:");
|
|
750
754
|
console.log("");
|
|
751
755
|
for (const f of fields) {
|
|
752
756
|
const shown = Array.isArray(f.value) ? JSON.stringify(f.value) : String(f.value ?? "(not set)");
|
|
@@ -765,6 +769,30 @@ function renderConsentCard(fields) {
|
|
|
765
769
|
console.log(" This is NOT required to use terminalhire.");
|
|
766
770
|
console.log("");
|
|
767
771
|
}
|
|
772
|
+
function openInBrowser(url) {
|
|
773
|
+
let cmd;
|
|
774
|
+
let args;
|
|
775
|
+
if (process.platform === "darwin") {
|
|
776
|
+
cmd = "open";
|
|
777
|
+
args = [url];
|
|
778
|
+
} else if (process.platform === "win32") {
|
|
779
|
+
cmd = "cmd";
|
|
780
|
+
args = ["/c", "start", "", url];
|
|
781
|
+
} else {
|
|
782
|
+
cmd = "xdg-open";
|
|
783
|
+
args = [url];
|
|
784
|
+
}
|
|
785
|
+
try {
|
|
786
|
+
const child = spawn(cmd, args, { stdio: "ignore", detached: true });
|
|
787
|
+
child.on("error", () => {
|
|
788
|
+
});
|
|
789
|
+
child.unref();
|
|
790
|
+
} catch {
|
|
791
|
+
}
|
|
792
|
+
}
|
|
793
|
+
function sleep(ms) {
|
|
794
|
+
return new Promise((res) => setTimeout(res, ms));
|
|
795
|
+
}
|
|
768
796
|
async function runPush() {
|
|
769
797
|
const { readProfile: readProfile2 } = await Promise.resolve().then(() => (init_profile(), profile_exports));
|
|
770
798
|
const profile = await readProfile2();
|
|
@@ -776,15 +804,91 @@ async function runPush() {
|
|
|
776
804
|
process.exit(1);
|
|
777
805
|
}
|
|
778
806
|
const fields = buildConsentFields(profile);
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
807
|
+
renderPreview(fields);
|
|
808
|
+
await new Promise((resolve) => {
|
|
809
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
810
|
+
rl.question(
|
|
811
|
+
" Press Enter to open your browser to authorize + consent (or Ctrl-C to cancel)... ",
|
|
812
|
+
() => {
|
|
813
|
+
rl.close();
|
|
814
|
+
resolve();
|
|
815
|
+
}
|
|
816
|
+
);
|
|
817
|
+
});
|
|
818
|
+
console.log("");
|
|
819
|
+
console.log(" Starting browser verification...");
|
|
820
|
+
let begin;
|
|
821
|
+
try {
|
|
822
|
+
const r = await fetch(`${SYNC_BASE}/api/profile-sync/begin`, {
|
|
823
|
+
method: "POST",
|
|
824
|
+
headers: { "Content-Type": "application/json" },
|
|
825
|
+
body: JSON.stringify({ hostname: osHostname() }),
|
|
826
|
+
signal: AbortSignal.timeout(1e4)
|
|
827
|
+
});
|
|
828
|
+
if (!r.ok) {
|
|
829
|
+
let detail = "";
|
|
830
|
+
try {
|
|
831
|
+
detail = (await r.json())?.message || "";
|
|
832
|
+
} catch {
|
|
833
|
+
}
|
|
834
|
+
console.error(`
|
|
835
|
+
Could not start sync: /api/profile-sync/begin returned ${r.status}. ${detail}`);
|
|
836
|
+
if (r.status === 503) console.error(" (Tier-1 sync is not enabled on the server yet.)");
|
|
837
|
+
process.exit(1);
|
|
838
|
+
}
|
|
839
|
+
begin = await r.json();
|
|
840
|
+
} catch (err) {
|
|
841
|
+
console.error(`
|
|
842
|
+
Could not start sync: ${err instanceof Error ? err.message : String(err)}`);
|
|
843
|
+
process.exit(1);
|
|
844
|
+
}
|
|
845
|
+
const { challenge, verifyUrl } = begin || {};
|
|
846
|
+
if (!challenge || !verifyUrl) {
|
|
847
|
+
console.error("\n Could not start sync: malformed begin response.");
|
|
848
|
+
process.exit(1);
|
|
849
|
+
}
|
|
850
|
+
console.log("");
|
|
851
|
+
console.log(" Open this URL in your browser to authorize + consent:");
|
|
852
|
+
console.log(` ${verifyUrl}`);
|
|
853
|
+
console.log("");
|
|
854
|
+
console.log(" (Attempting to open it automatically...)");
|
|
855
|
+
openInBrowser(verifyUrl);
|
|
856
|
+
console.log(" Waiting for browser verification...");
|
|
857
|
+
const deadline = Date.now() + POLL_TIMEOUT_MS;
|
|
858
|
+
let proofToken = null;
|
|
859
|
+
while (Date.now() < deadline) {
|
|
860
|
+
await sleep(POLL_INTERVAL_MS);
|
|
861
|
+
let statusRes;
|
|
862
|
+
try {
|
|
863
|
+
statusRes = await fetch(
|
|
864
|
+
`${SYNC_BASE}/api/profile-sync/status?challenge=${encodeURIComponent(challenge)}`,
|
|
865
|
+
{ signal: AbortSignal.timeout(1e4) }
|
|
866
|
+
);
|
|
867
|
+
} catch {
|
|
868
|
+
continue;
|
|
869
|
+
}
|
|
870
|
+
if (!statusRes.ok) {
|
|
871
|
+
if (statusRes.status === 503) {
|
|
872
|
+
console.error("\n Tier-1 sync is not enabled on the server yet.\n");
|
|
873
|
+
process.exit(1);
|
|
874
|
+
}
|
|
875
|
+
continue;
|
|
876
|
+
}
|
|
877
|
+
let body;
|
|
878
|
+
try {
|
|
879
|
+
body = await statusRes.json();
|
|
880
|
+
} catch {
|
|
881
|
+
continue;
|
|
882
|
+
}
|
|
883
|
+
if (body && body.status === "verified" && body.proofToken) {
|
|
884
|
+
proofToken = body.proofToken;
|
|
885
|
+
break;
|
|
886
|
+
}
|
|
887
|
+
}
|
|
888
|
+
if (!proofToken) {
|
|
889
|
+
console.error("\n Timed out waiting for browser verification (10 min).");
|
|
890
|
+
console.error(" Re-run `terminalhire sync --push` to try again.\n");
|
|
891
|
+
process.exit(1);
|
|
788
892
|
}
|
|
789
893
|
const consentedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
790
894
|
const consentToken = {
|
|
@@ -803,14 +907,14 @@ async function runPush() {
|
|
|
803
907
|
};
|
|
804
908
|
const priorMarker = readMarker();
|
|
805
909
|
const rowToken = priorMarker && priorMarker.deleteToken ? priorMarker.deleteToken : null;
|
|
806
|
-
const requestBody = { consentToken, profile: payloadProfile };
|
|
910
|
+
const requestBody = { consentToken, profile: payloadProfile, proofToken };
|
|
807
911
|
if (rowToken) {
|
|
808
912
|
requestBody.rowToken = rowToken;
|
|
809
913
|
}
|
|
810
|
-
console.log("\n Sending one-time snapshot...");
|
|
914
|
+
console.log("\n Verified. Sending one-time snapshot...");
|
|
811
915
|
let res;
|
|
812
916
|
try {
|
|
813
|
-
res = await fetch(`${
|
|
917
|
+
res = await fetch(`${SYNC_BASE}/api/profile-sync`, {
|
|
814
918
|
method: "POST",
|
|
815
919
|
headers: { "Content-Type": "application/json" },
|
|
816
920
|
body: JSON.stringify(requestBody),
|
|
@@ -833,7 +937,7 @@ async function runPush() {
|
|
|
833
937
|
console.error(" (Tier-1 sync is not enabled on the server yet.)");
|
|
834
938
|
}
|
|
835
939
|
if (res.status === 403) {
|
|
836
|
-
console.error(" (
|
|
940
|
+
console.error(" (Ownership proof rejected, expired, or already used \u2014 re-run sync --push.)");
|
|
837
941
|
}
|
|
838
942
|
process.exit(1);
|
|
839
943
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "terminalhire",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.5",
|
|
4
4
|
"description": "Local-first job matching for developers — ambient job matches in the Claude Code spinner. Matching runs on your machine; your profile never leaves it.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|