@paigy/harness 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/README.md CHANGED
@@ -168,6 +168,15 @@ macOS launchd agent so hosting survives reboots — the host loop IS the service
168
168
  launchd just keeps it alive (the old "no daemon" note was about the WAKE channel,
169
169
  which still belongs to paigy-listen).
170
170
 
171
+ ## The window is not distributable (yet)
172
+
173
+ npm is the ONLY shipping channel: `@paigy/harness` installs the CLI and the whole
174
+ bridge, and updates with `npm i -g @paigy/harness@latest`. The Electron window runs
175
+ from source (`electron .`) — there is no packaging, no Developer ID signing or
176
+ notarization, and therefore no auto-update (macOS auto-update requires the signing).
177
+ A downloaded unsigned app would hit Gatekeeper's "damaged" dialog, which is worse
178
+ than no download button. Steps for when it's time: #854.
179
+
171
180
  ## Run it
172
181
 
173
182
  ```sh
package/dist/cli.js CHANGED
@@ -11631,10 +11631,10 @@ var require_headers = __commonJS({
11631
11631
  const lowercaseName = isLowerCase ? name : name.toLowerCase();
11632
11632
  const exists = this[kHeadersMap].get(lowercaseName);
11633
11633
  if (exists) {
11634
- const delimiter2 = lowercaseName === "cookie" ? "; " : ", ";
11634
+ const delimiter3 = lowercaseName === "cookie" ? "; " : ", ";
11635
11635
  this[kHeadersMap].set(lowercaseName, {
11636
11636
  name: exists.name,
11637
- value: `${exists.value}${delimiter2}${value}`
11637
+ value: `${exists.value}${delimiter3}${value}`
11638
11638
  });
11639
11639
  } else {
11640
11640
  this[kHeadersMap].set(lowercaseName, { name, value });
@@ -23091,7 +23091,7 @@ var require_lib = __commonJS({
23091
23091
  import { spawnSync } from "child_process";
23092
23092
  import { existsSync } from "fs";
23093
23093
  import { homedir } from "os";
23094
- import { join } from "path";
23094
+ import { delimiter, dirname, join } from "path";
23095
23095
  var CATALOG = [
23096
23096
  {
23097
23097
  name: "claude",
@@ -23115,7 +23115,13 @@ var CATALOG = [
23115
23115
  }
23116
23116
  ];
23117
23117
  function probeDirs(home = homedir()) {
23118
- return [join(home, ".local", "bin"), "/usr/local/bin", "/opt/homebrew/bin", join(home, ".npm-global", "bin")];
23118
+ return [
23119
+ dirname(process.execPath),
23120
+ join(home, ".local", "bin"),
23121
+ "/usr/local/bin",
23122
+ "/opt/homebrew/bin",
23123
+ join(home, ".npm-global", "bin")
23124
+ ];
23119
23125
  }
23120
23126
  function which(bin) {
23121
23127
  const hit = spawnSync("which", [bin], { encoding: "utf8" });
@@ -23132,7 +23138,11 @@ function runProbe(argv) {
23132
23138
  if (!cmd) return false;
23133
23139
  const resolved = which(cmd);
23134
23140
  if (!resolved) return false;
23135
- return spawnSync(resolved, args, { timeout: 1e4, stdio: "ignore" }).status === 0;
23141
+ return spawnSync(resolved, args, {
23142
+ timeout: 1e4,
23143
+ stdio: "ignore",
23144
+ env: { ...process.env, PATH: [process.env.PATH, ...probeDirs()].filter(Boolean).join(delimiter) }
23145
+ }).status === 0;
23136
23146
  }
23137
23147
  function detect(entry, deps = {}) {
23138
23148
  const find = deps.which ?? which;
@@ -29735,7 +29745,12 @@ var UserAnswerSchema = external_exports.discriminatedUnion("kind", [
29735
29745
  external_exports.object({ kind: external_exports.literal("ranked"), optionIds: external_exports.array(external_exports.string()), labels: external_exports.array(external_exports.string()).optional() }),
29736
29746
  external_exports.object({ kind: external_exports.literal("clarify"), chunks: external_exports.array(external_exports.string()).min(1) }),
29737
29747
  external_exports.object({ kind: external_exports.literal("confirm"), approved: external_exports.boolean() }),
29738
- external_exports.object({ kind: external_exports.literal("turns"), turns: external_exports.array(TurnSchema).min(1) })
29748
+ external_exports.object({ kind: external_exports.literal("turns"), turns: external_exports.array(TurnSchema).min(1) }),
29749
+ /** An auto-answer derived from the user's PAST decisions (broker/precedent-design.md §2):
29750
+ * delivered through the same settle/await path as a human answer, carrying the judge's
29751
+ * derivation and the precedent ids it grew from. Always paired with a visible trail
29752
+ * card the user can reply to — the broker never overrides the user. */
29753
+ external_exports.object({ kind: external_exports.literal("precedent"), answer: external_exports.string(), derivation: external_exports.string(), sources: external_exports.array(external_exports.string()).min(1) })
29739
29754
  ]);
29740
29755
  var IntentSchema = external_exports.object({
29741
29756
  // The full vocabulary the bot's mapper emits (mapper.INTENT_KINDS) — the schema lagged
@@ -31084,7 +31099,12 @@ var UserAnswerSchema2 = external_exports.discriminatedUnion("kind", [
31084
31099
  external_exports.object({ kind: external_exports.literal("ranked"), optionIds: external_exports.array(external_exports.string()), labels: external_exports.array(external_exports.string()).optional() }),
31085
31100
  external_exports.object({ kind: external_exports.literal("clarify"), chunks: external_exports.array(external_exports.string()).min(1) }),
31086
31101
  external_exports.object({ kind: external_exports.literal("confirm"), approved: external_exports.boolean() }),
31087
- external_exports.object({ kind: external_exports.literal("turns"), turns: external_exports.array(TurnSchema2).min(1) })
31102
+ external_exports.object({ kind: external_exports.literal("turns"), turns: external_exports.array(TurnSchema2).min(1) }),
31103
+ /** An auto-answer derived from the user's PAST decisions (broker/precedent-design.md §2):
31104
+ * delivered through the same settle/await path as a human answer, carrying the judge's
31105
+ * derivation and the precedent ids it grew from. Always paired with a visible trail
31106
+ * card the user can reply to — the broker never overrides the user. */
31107
+ external_exports.object({ kind: external_exports.literal("precedent"), answer: external_exports.string(), derivation: external_exports.string(), sources: external_exports.array(external_exports.string()).min(1) })
31088
31108
  ]);
31089
31109
  var IntentSchema2 = external_exports.object({
31090
31110
  // The full vocabulary the bot's mapper emits (mapper.INTENT_KINDS) — the schema lagged
@@ -31956,6 +31976,9 @@ function spokenText(answer) {
31956
31976
  // A call log: the user's replies are the instruction, the bot's prompts are not.
31957
31977
  case "turns":
31958
31978
  return answer.turns.map((t) => t.reply).join(" ").trim() || null;
31979
+ // An auto-answer derived from the user's past decisions — reads like a fast human.
31980
+ case "precedent":
31981
+ return answer.answer;
31959
31982
  case "ignored":
31960
31983
  return null;
31961
31984
  }
@@ -31967,7 +31990,7 @@ var clip = (s) => (s.length > 120 ? `${s.slice(0, 117)}\u2026` : s) || "(no text
31967
31990
  import { spawn } from "child_process";
31968
31991
  import { existsSync as existsSync3 } from "fs";
31969
31992
  import { homedir as homedir3 } from "os";
31970
- import { dirname, resolve, delimiter } from "path";
31993
+ import { resolve, delimiter as delimiter2 } from "path";
31971
31994
 
31972
31995
  // src/harness/acp.ts
31973
31996
  var none = { events: [], writes: [] };
@@ -32200,7 +32223,7 @@ function startSession(opts) {
32200
32223
  // PATH knows neither — live catch 2026-08-04: the first slot-wake ENOENT'd).
32201
32224
  env: {
32202
32225
  ...process.env,
32203
- PATH: [process.env.PATH, dirname(process.execPath), ...probeDirs()].filter(Boolean).join(delimiter),
32226
+ PATH: [process.env.PATH, ...probeDirs()].filter(Boolean).join(delimiter2),
32204
32227
  ...opts.token ? { PAIGY_TOKEN: opts.token } : {}
32205
32228
  },
32206
32229
  stdio: ["pipe", "pipe", "pipe"]
@@ -32329,7 +32352,7 @@ function runHarness(opts) {
32329
32352
 
32330
32353
  // src/workspaces.ts
32331
32354
  import { existsSync as existsSync4, mkdirSync as mkdirSync2, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "fs";
32332
- import { dirname as dirname2, join as join3, resolve as resolve2 } from "path";
32355
+ import { dirname as dirname3, join as join3, resolve as resolve2 } from "path";
32333
32356
  import { homedir as homedir4 } from "os";
32334
32357
  function workspacesFile() {
32335
32358
  return join3(homedir4(), ".paigy", "workspaces.json");
@@ -32347,7 +32370,7 @@ function addWorkspace(dir, deps) {
32347
32370
  const all = listWorkspaces(deps);
32348
32371
  if (!all.includes(next)) {
32349
32372
  all.push(next);
32350
- mkdirSync2(dirname2(deps.file), { recursive: true });
32373
+ mkdirSync2(dirname3(deps.file), { recursive: true });
32351
32374
  writeFileSync2(deps.file, JSON.stringify(all, null, 2));
32352
32375
  }
32353
32376
  return all;
package/dist/main.js CHANGED
@@ -4577,7 +4577,7 @@ var require_lib = __commonJS({
4577
4577
  import { app, BrowserWindow, dialog, ipcMain } from "electron";
4578
4578
  import { spawn as spawn2 } from "child_process";
4579
4579
  import { fileURLToPath } from "url";
4580
- import { dirname as dirname3, join as join4 } from "path";
4580
+ import { dirname as dirname4, join as join4 } from "path";
4581
4581
 
4582
4582
  // ../../packages/sdk/dist/index.js
4583
4583
  import { createRequire as __sdkCreateRequire } from "module";
@@ -11157,7 +11157,12 @@ var UserAnswerSchema = external_exports.discriminatedUnion("kind", [
11157
11157
  external_exports.object({ kind: external_exports.literal("ranked"), optionIds: external_exports.array(external_exports.string()), labels: external_exports.array(external_exports.string()).optional() }),
11158
11158
  external_exports.object({ kind: external_exports.literal("clarify"), chunks: external_exports.array(external_exports.string()).min(1) }),
11159
11159
  external_exports.object({ kind: external_exports.literal("confirm"), approved: external_exports.boolean() }),
11160
- external_exports.object({ kind: external_exports.literal("turns"), turns: external_exports.array(TurnSchema).min(1) })
11160
+ external_exports.object({ kind: external_exports.literal("turns"), turns: external_exports.array(TurnSchema).min(1) }),
11161
+ /** An auto-answer derived from the user's PAST decisions (broker/precedent-design.md §2):
11162
+ * delivered through the same settle/await path as a human answer, carrying the judge's
11163
+ * derivation and the precedent ids it grew from. Always paired with a visible trail
11164
+ * card the user can reply to — the broker never overrides the user. */
11165
+ external_exports.object({ kind: external_exports.literal("precedent"), answer: external_exports.string(), derivation: external_exports.string(), sources: external_exports.array(external_exports.string()).min(1) })
11161
11166
  ]);
11162
11167
  var IntentSchema = external_exports.object({
11163
11168
  // The full vocabulary the bot's mapper emits (mapper.INTENT_KINDS) — the schema lagged
@@ -12278,7 +12283,7 @@ import { hostname } from "os";
12278
12283
  import { spawnSync } from "child_process";
12279
12284
  import { existsSync as existsSync2 } from "fs";
12280
12285
  import { homedir as homedir2 } from "os";
12281
- import { join as join2 } from "path";
12286
+ import { delimiter, dirname, join as join2 } from "path";
12282
12287
  var CATALOG = [
12283
12288
  {
12284
12289
  name: "claude",
@@ -12302,7 +12307,13 @@ var CATALOG = [
12302
12307
  }
12303
12308
  ];
12304
12309
  function probeDirs(home = homedir2()) {
12305
- return [join2(home, ".local", "bin"), "/usr/local/bin", "/opt/homebrew/bin", join2(home, ".npm-global", "bin")];
12310
+ return [
12311
+ dirname(process.execPath),
12312
+ join2(home, ".local", "bin"),
12313
+ "/usr/local/bin",
12314
+ "/opt/homebrew/bin",
12315
+ join2(home, ".npm-global", "bin")
12316
+ ];
12306
12317
  }
12307
12318
  function which(bin) {
12308
12319
  const hit = spawnSync("which", [bin], { encoding: "utf8" });
@@ -12319,7 +12330,11 @@ function runProbe(argv) {
12319
12330
  if (!cmd) return false;
12320
12331
  const resolved = which(cmd);
12321
12332
  if (!resolved) return false;
12322
- return spawnSync(resolved, args, { timeout: 1e4, stdio: "ignore" }).status === 0;
12333
+ return spawnSync(resolved, args, {
12334
+ timeout: 1e4,
12335
+ stdio: "ignore",
12336
+ env: { ...process.env, PATH: [process.env.PATH, ...probeDirs()].filter(Boolean).join(delimiter) }
12337
+ }).status === 0;
12323
12338
  }
12324
12339
  function detect(entry, deps = {}) {
12325
12340
  const find = deps.which ?? which;
@@ -12346,7 +12361,7 @@ function detectAll(deps = {}) {
12346
12361
 
12347
12362
  // src/workspaces.ts
12348
12363
  import { existsSync as existsSync3, mkdirSync as mkdirSync2, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "fs";
12349
- import { dirname, join as join3, resolve } from "path";
12364
+ import { dirname as dirname2, join as join3, resolve } from "path";
12350
12365
  import { homedir as homedir3 } from "os";
12351
12366
  function workspacesFile() {
12352
12367
  return join3(homedir3(), ".paigy", "workspaces.json");
@@ -12364,14 +12379,14 @@ function addWorkspace(dir, deps) {
12364
12379
  const all = listWorkspaces(deps);
12365
12380
  if (!all.includes(next)) {
12366
12381
  all.push(next);
12367
- mkdirSync2(dirname(deps.file), { recursive: true });
12382
+ mkdirSync2(dirname2(deps.file), { recursive: true });
12368
12383
  writeFileSync2(deps.file, JSON.stringify(all, null, 2));
12369
12384
  }
12370
12385
  return all;
12371
12386
  }
12372
12387
  function removeWorkspace(dir, deps) {
12373
12388
  const all = listWorkspaces(deps).filter((w) => w !== dir);
12374
- mkdirSync2(dirname(deps.file), { recursive: true });
12389
+ mkdirSync2(dirname2(deps.file), { recursive: true });
12375
12390
  writeFileSync2(deps.file, JSON.stringify(all, null, 2));
12376
12391
  return all;
12377
12392
  }
@@ -12380,7 +12395,7 @@ function removeWorkspace(dir, deps) {
12380
12395
  import { spawn } from "child_process";
12381
12396
  import { existsSync as existsSync4 } from "fs";
12382
12397
  import { homedir as homedir4 } from "os";
12383
- import { dirname as dirname2, resolve as resolve2, delimiter } from "path";
12398
+ import { resolve as resolve2, delimiter as delimiter2 } from "path";
12384
12399
 
12385
12400
  // src/harness/acp.ts
12386
12401
  var none = { events: [], writes: [] };
@@ -12613,7 +12628,7 @@ function startSession(opts) {
12613
12628
  // PATH knows neither — live catch 2026-08-04: the first slot-wake ENOENT'd).
12614
12629
  env: {
12615
12630
  ...process.env,
12616
- PATH: [process.env.PATH, dirname2(process.execPath), ...probeDirs()].filter(Boolean).join(delimiter),
12631
+ PATH: [process.env.PATH, ...probeDirs()].filter(Boolean).join(delimiter2),
12617
12632
  ...opts.token ? { PAIGY_TOKEN: opts.token } : {}
12618
12633
  },
12619
12634
  stdio: ["pipe", "pipe", "pipe"]
@@ -12876,7 +12891,12 @@ var UserAnswerSchema2 = external_exports.discriminatedUnion("kind", [
12876
12891
  external_exports.object({ kind: external_exports.literal("ranked"), optionIds: external_exports.array(external_exports.string()), labels: external_exports.array(external_exports.string()).optional() }),
12877
12892
  external_exports.object({ kind: external_exports.literal("clarify"), chunks: external_exports.array(external_exports.string()).min(1) }),
12878
12893
  external_exports.object({ kind: external_exports.literal("confirm"), approved: external_exports.boolean() }),
12879
- external_exports.object({ kind: external_exports.literal("turns"), turns: external_exports.array(TurnSchema2).min(1) })
12894
+ external_exports.object({ kind: external_exports.literal("turns"), turns: external_exports.array(TurnSchema2).min(1) }),
12895
+ /** An auto-answer derived from the user's PAST decisions (broker/precedent-design.md §2):
12896
+ * delivered through the same settle/await path as a human answer, carrying the judge's
12897
+ * derivation and the precedent ids it grew from. Always paired with a visible trail
12898
+ * card the user can reply to — the broker never overrides the user. */
12899
+ external_exports.object({ kind: external_exports.literal("precedent"), answer: external_exports.string(), derivation: external_exports.string(), sources: external_exports.array(external_exports.string()).min(1) })
12880
12900
  ]);
12881
12901
  var IntentSchema2 = external_exports.object({
12882
12902
  // The full vocabulary the bot's mapper emits (mapper.INTENT_KINDS) — the schema lagged
@@ -13737,6 +13757,9 @@ function spokenText(answer) {
13737
13757
  // A call log: the user's replies are the instruction, the bot's prompts are not.
13738
13758
  case "turns":
13739
13759
  return answer.turns.map((t) => t.reply).join(" ").trim() || null;
13760
+ // An auto-answer derived from the user's past decisions — reads like a fast human.
13761
+ case "precedent":
13762
+ return answer.answer;
13740
13763
  case "ignored":
13741
13764
  return null;
13742
13765
  }
@@ -13914,7 +13937,7 @@ function startHost(opts) {
13914
13937
  }
13915
13938
 
13916
13939
  // src/main.ts
13917
- var here = dirname3(fileURLToPath(import.meta.url));
13940
+ var here = dirname4(fileURLToPath(import.meta.url));
13918
13941
  var wsDeps = { file: workspacesFile() };
13919
13942
  var DEVICE_SLOT = "Desktop";
13920
13943
  var deviceToken = () => readToken(DEVICE_SLOT) || readToken();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@paigy/harness",
3
- "version": "0.2.4",
3
+ "version": "0.2.5",
4
4
  "description": "Run Claude Code / Codex on this machine, bridged to Paigy — launchable from your phone.",
5
5
  "license": "MIT",
6
6
  "type": "module",