@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 +9 -0
- package/dist/cli.js +34 -11
- package/dist/main.js +35 -12
- package/package.json +1 -1
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
|
|
11634
|
+
const delimiter3 = lowercaseName === "cookie" ? "; " : ", ";
|
|
11635
11635
|
this[kHeadersMap].set(lowercaseName, {
|
|
11636
11636
|
name: exists.name,
|
|
11637
|
-
value: `${exists.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 [
|
|
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, {
|
|
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 {
|
|
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,
|
|
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
|
|
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(
|
|
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
|
|
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 [
|
|
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, {
|
|
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(
|
|
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(
|
|
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 {
|
|
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,
|
|
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 =
|
|
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();
|