@floh-solutions/pharos-cli 0.29.0 → 0.31.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.
Files changed (45) hide show
  1. package/README.md +33 -0
  2. package/dist/capabilities.d.ts +7 -0
  3. package/dist/capabilities.d.ts.map +1 -1
  4. package/dist/capabilities.js +25 -0
  5. package/dist/capabilities.js.map +1 -1
  6. package/dist/cli.d.ts +18 -1
  7. package/dist/cli.d.ts.map +1 -1
  8. package/dist/cli.js +193 -86
  9. package/dist/cli.js.map +1 -1
  10. package/dist/commands/delegate.d.ts +248 -0
  11. package/dist/commands/delegate.d.ts.map +1 -0
  12. package/dist/commands/delegate.js +582 -0
  13. package/dist/commands/delegate.js.map +1 -0
  14. package/dist/commands/doctor.d.ts +8 -0
  15. package/dist/commands/doctor.d.ts.map +1 -1
  16. package/dist/commands/doctor.js +179 -4
  17. package/dist/commands/doctor.js.map +1 -1
  18. package/dist/commands/setup.d.ts.map +1 -1
  19. package/dist/commands/setup.js +7 -3
  20. package/dist/commands/setup.js.map +1 -1
  21. package/dist/delegate/hosts.d.ts +83 -0
  22. package/dist/delegate/hosts.d.ts.map +1 -0
  23. package/dist/delegate/hosts.js +154 -0
  24. package/dist/delegate/hosts.js.map +1 -0
  25. package/dist/delegate/quote.d.ts +78 -0
  26. package/dist/delegate/quote.d.ts.map +1 -0
  27. package/dist/delegate/quote.js +134 -0
  28. package/dist/delegate/quote.js.map +1 -0
  29. package/dist/delegate/sessions.d.ts +121 -0
  30. package/dist/delegate/sessions.d.ts.map +1 -0
  31. package/dist/delegate/sessions.js +229 -0
  32. package/dist/delegate/sessions.js.map +1 -0
  33. package/dist/delegate/vsix.d.ts +122 -0
  34. package/dist/delegate/vsix.d.ts.map +1 -0
  35. package/dist/delegate/vsix.js +329 -0
  36. package/dist/delegate/vsix.js.map +1 -0
  37. package/package.json +5 -4
  38. package/skill/SKILL.md +47 -0
  39. package/vscode/README.md +30 -0
  40. package/vscode/pharos-bridge.json +10 -0
  41. package/vscode/pharos-bridge.vsix +0 -0
  42. package/dist/commands/pr.d.ts +0 -56
  43. package/dist/commands/pr.d.ts.map +0 -1
  44. package/dist/commands/pr.js +0 -202
  45. package/dist/commands/pr.js.map +0 -1
@@ -0,0 +1,329 @@
1
+ import { execFile } from "node:child_process";
2
+ import { createHash } from "node:crypto";
3
+ import { readdir, readFile, stat } from "node:fs/promises";
4
+ import { homedir } from "node:os";
5
+ import { dirname, join } from "node:path";
6
+ import { fileURLToPath } from "node:url";
7
+ import { promisify } from "node:util";
8
+ import { inflateRawSync } from "node:zlib";
9
+ import { bundleCli, findApp, HOSTS } from "./hosts.js";
10
+ const run = promisify(execFile);
11
+ /**
12
+ * The Pharos bridge for VS Code — what this CLI ships, and what a machine has.
13
+ *
14
+ * ## Why the CLI carries a `.vsix` at all
15
+ *
16
+ * Nothing outside VS Code can put a prompt into a session (measured against
17
+ * the Claude Code and Codex extensions: no URI handler takes text, and the
18
+ * `code` CLI runs no terminal command). The bridge — `packages/pharos-vscode`,
19
+ * publisher `floh-solutions`, name `pharos` — is the thing that can, and it
20
+ * ships INSIDE the npm package the way `skill/` does, so `pharos setup
21
+ * --install vscode-bridge` needs no network and no Marketplace listing. A
22
+ * listing is a later, separate decision and a fourth release route.
23
+ *
24
+ * ## Two files, one source of truth
25
+ *
26
+ * The bridge's build writes `vscode/pharos-bridge.vsix` and, beside it,
27
+ * `vscode/pharos-bridge.json` — `{ id, version, vsix, sha256, bytes }`,
28
+ * derived from the extension's own `package.json`. The JSON is what `doctor`
29
+ * reads to say which bridge this CLI ships, and the sha256 in it is what the
30
+ * installer checks the `.vsix` against before handing it to VS Code: the
31
+ * `convert.ts` rule, that bytes are verified against something already in the
32
+ * package rather than trusted because they are there. When the JSON is absent
33
+ * the `.vsix` is unzipped for its `extension/package.json` instead, so an
34
+ * older build still reports a version.
35
+ */
36
+ export const BRIDGE_EXTENSION_ID = "floh-solutions.pharos";
37
+ /** `anthropic.claude-code` and `openai.chatgpt` — the ids the extension folders and manifest carry. */
38
+ export const CLAUDE_EXTENSION_ID = "anthropic.claude-code";
39
+ export const CODEX_EXTENSION_ID = "openai.chatgpt";
40
+ /**
41
+ * Where the bundled `.vsix` is.
42
+ *
43
+ * `PHAROS_BRIDGE_VSIX` overrides it — for a developer installing a local
44
+ * build, and for the tests, which must never install a real extension into
45
+ * somebody's editor to prove a refusal.
46
+ */
47
+ export function bundledVsixPath(env = process.env) {
48
+ const override = env["PHAROS_BRIDGE_VSIX"];
49
+ if (override !== undefined && override !== "")
50
+ return override;
51
+ // Relative to the compiled file, so it resolves from dist/ in a global npm
52
+ // install as well as from src/ in this checkout — the `skill/` rule.
53
+ return fileURLToPath(new URL("../../vscode/pharos-bridge.vsix", import.meta.url));
54
+ }
55
+ /** The manifest the bridge's build writes beside the `.vsix`. */
56
+ export function bundledManifestPath(env = process.env) {
57
+ return join(dirname(bundledVsixPath(env)), "pharos-bridge.json");
58
+ }
59
+ /** The bridge this CLI ships, or null when the `.vsix` is not there. Never throws. */
60
+ export async function bundledBridge(env = process.env) {
61
+ const path = bundledVsixPath(env);
62
+ let bytes;
63
+ try {
64
+ const info = await stat(path);
65
+ if (!info.isFile())
66
+ return null;
67
+ bytes = await readFile(path);
68
+ }
69
+ catch {
70
+ return null;
71
+ }
72
+ try {
73
+ const raw = await readFile(bundledManifestPath(env), "utf8");
74
+ const parsed = JSON.parse(raw);
75
+ const id = typeof parsed["id"] === "string" ? parsed["id"] : null;
76
+ const dot = id?.indexOf(".") ?? -1;
77
+ return {
78
+ path,
79
+ bytes: bytes.length,
80
+ manifest: {
81
+ publisher: id !== null && dot > 0 ? id.slice(0, dot) : null,
82
+ name: id !== null && dot > 0 ? id.slice(dot + 1) : null,
83
+ version: typeof parsed["version"] === "string" ? parsed["version"] : null,
84
+ },
85
+ sha256: typeof parsed["sha256"] === "string" ? parsed["sha256"].toLowerCase() : null,
86
+ via: "manifest",
87
+ };
88
+ }
89
+ catch {
90
+ return { path, bytes: bytes.length, manifest: vsixManifest(bytes), sha256: null, via: "vsix" };
91
+ }
92
+ }
93
+ /**
94
+ * `extension/package.json` out of a `.vsix`, which is a zip.
95
+ *
96
+ * A zip reader in forty lines rather than a dependency: the package has none
97
+ * today, and one to read three fields out of a file we produce ourselves
98
+ * would be a poor trade. Handles the two methods `vsce` writes (stored and
99
+ * deflate) and nothing else; zip64 is not needed for a bridge this size.
100
+ */
101
+ export function vsixManifest(bytes) {
102
+ const empty = { publisher: null, name: null, version: null };
103
+ const entry = zipEntry(bytes, "extension/package.json");
104
+ if (entry === null)
105
+ return empty;
106
+ try {
107
+ const parsed = JSON.parse(entry.toString("utf8"));
108
+ return {
109
+ publisher: typeof parsed["publisher"] === "string" ? parsed["publisher"] : null,
110
+ name: typeof parsed["name"] === "string" ? parsed["name"] : null,
111
+ version: typeof parsed["version"] === "string" ? parsed["version"] : null,
112
+ };
113
+ }
114
+ catch {
115
+ return empty;
116
+ }
117
+ }
118
+ const EOCD = 0x06054b50;
119
+ const CENTRAL = 0x02014b50;
120
+ const LOCAL = 0x04034b50;
121
+ /** One file's contents out of a zip, by exact name, or null. */
122
+ export function zipEntry(bytes, name) {
123
+ // The end-of-central-directory record is at the very end, before an optional
124
+ // comment of at most 65535 bytes. Scan back for its signature.
125
+ let eocd = -1;
126
+ for (let at = bytes.length - 22; at >= Math.max(0, bytes.length - 22 - 65_535); at -= 1) {
127
+ if (bytes.readUInt32LE(at) === EOCD) {
128
+ eocd = at;
129
+ break;
130
+ }
131
+ }
132
+ if (eocd === -1)
133
+ return null;
134
+ const entries = bytes.readUInt16LE(eocd + 10);
135
+ let at = bytes.readUInt32LE(eocd + 16);
136
+ for (let index = 0; index < entries; index += 1) {
137
+ if (at + 46 > bytes.length || bytes.readUInt32LE(at) !== CENTRAL)
138
+ return null;
139
+ const method = bytes.readUInt16LE(at + 10);
140
+ const compressedSize = bytes.readUInt32LE(at + 20);
141
+ const nameLength = bytes.readUInt16LE(at + 28);
142
+ const extraLength = bytes.readUInt16LE(at + 30);
143
+ const commentLength = bytes.readUInt16LE(at + 32);
144
+ const localOffset = bytes.readUInt32LE(at + 42);
145
+ const entryName = bytes.subarray(at + 46, at + 46 + nameLength).toString("utf8");
146
+ if (entryName === name) {
147
+ if (localOffset + 30 > bytes.length || bytes.readUInt32LE(localOffset) !== LOCAL)
148
+ return null;
149
+ const localNameLength = bytes.readUInt16LE(localOffset + 26);
150
+ const localExtraLength = bytes.readUInt16LE(localOffset + 28);
151
+ const start = localOffset + 30 + localNameLength + localExtraLength;
152
+ const data = bytes.subarray(start, start + compressedSize);
153
+ if (method === 0)
154
+ return Buffer.from(data);
155
+ if (method === 8) {
156
+ try {
157
+ return inflateRawSync(data);
158
+ }
159
+ catch {
160
+ return null;
161
+ }
162
+ }
163
+ return null;
164
+ }
165
+ at += 46 + nameLength + extraLength + commentLength;
166
+ }
167
+ return null;
168
+ }
169
+ /** `~/.vscode[-insiders]/extensions` for a VS Code flavour; null for any other host. */
170
+ export function extensionsDirectory(host, env = process.env) {
171
+ const spec = HOSTS[host].vscode;
172
+ if (spec === undefined)
173
+ return null;
174
+ return join(env["HOME"] ?? homedir(), spec.extensionsDir);
175
+ }
176
+ /**
177
+ * What a flavour has installed. `null` when the directory does not exist —
178
+ * which is "this VS Code has never run", a different fact from "no extensions".
179
+ *
180
+ * `extensions.json` is read first because it is what VS Code itself reads:
181
+ * the reference machine held two `anthropic.claude-code-*` folders side by
182
+ * side (an update leaves the old one behind), and only the manifest says which
183
+ * is live. A missing or unreadable manifest falls back to the folder names,
184
+ * `<publisher>.<name>-<version>[-<platform>]`.
185
+ */
186
+ export async function installedExtensions(host, env = process.env) {
187
+ const directory = extensionsDirectory(host, env);
188
+ if (directory === null)
189
+ return null;
190
+ let names;
191
+ try {
192
+ names = await readdir(directory);
193
+ }
194
+ catch {
195
+ return null;
196
+ }
197
+ try {
198
+ const raw = await readFile(join(directory, "extensions.json"), "utf8");
199
+ const parsed = JSON.parse(raw);
200
+ if (Array.isArray(parsed)) {
201
+ const listed = [];
202
+ for (const entry of parsed) {
203
+ const record = entry;
204
+ const id = record.identifier?.id;
205
+ if (typeof id !== "string" || typeof record.version !== "string")
206
+ continue;
207
+ const folder = typeof record.relativeLocation === "string" ? record.relativeLocation : `${id}-${record.version}`;
208
+ listed.push({ id: id.toLowerCase(), version: record.version, path: join(directory, folder) });
209
+ }
210
+ return listed;
211
+ }
212
+ }
213
+ catch {
214
+ // No manifest, or not the shape expected. The folders still say.
215
+ }
216
+ const scanned = [];
217
+ for (const name of names) {
218
+ const parsed = parseExtensionFolder(name);
219
+ if (parsed !== null)
220
+ scanned.push({ ...parsed, path: join(directory, name) });
221
+ }
222
+ return scanned;
223
+ }
224
+ /** `anthropic.claude-code-2.1.228-darwin-arm64` → id and version. Null for anything else. */
225
+ export function parseExtensionFolder(name) {
226
+ const match = /^([a-z0-9][a-z0-9-]*\.[a-z0-9][a-z0-9-]*)-(\d+\.\d+\.\d+(?:[-.][0-9A-Za-z.-]+)?)$/i.exec(name);
227
+ if (match === null)
228
+ return null;
229
+ let version = match[2];
230
+ // A platform suffix is not part of the version: strip `-darwin-arm64` and its kin.
231
+ version = version.replace(/-(darwin|linux|win32|alpine|web|universal)[-0-9A-Za-z]*$/i, "");
232
+ return { id: match[1].toLowerCase(), version };
233
+ }
234
+ /**
235
+ * Install the bundled bridge into every VS Code flavour on this machine.
236
+ *
237
+ * Through the bundle's OWN `bin/code`, because the `code` command is usually
238
+ * not on PATH (see {@link bundleCli}). `--force` replaces an older bridge
239
+ * without a prompt; a headless install that stops to ask is a wizard that
240
+ * hangs.
241
+ *
242
+ * A missing `.vsix` is a refusal with the path, never a stack trace: the
243
+ * package can legitimately ship without one until the bridge's build has
244
+ * written it, and `doctor` names that state too. A `.vsix` that does not
245
+ * match its manifest's checksum is refused the same way — nothing is handed
246
+ * to VS Code that the package did not vouch for.
247
+ */
248
+ export async function installBridge(options = {}) {
249
+ const env = options.env ?? process.env;
250
+ const bundled = await bundledBridge(env);
251
+ if (bundled === null) {
252
+ return {
253
+ ok: false,
254
+ command: null,
255
+ detail: `This pharos ships no bridge — ${bundledVsixPath(env)} is absent. It is produced by the `
256
+ + "bridge's build (packages/pharos-vscode) and packed into the npm package; a checkout "
257
+ + "gets it from `pnpm --filter ./packages/pharos-vscode build`, or point "
258
+ + "PHAROS_BRIDGE_VSIX at one.",
259
+ flavours: [],
260
+ };
261
+ }
262
+ if (bundled.sha256 !== null) {
263
+ const digest = createHash("sha256").update(await readFile(bundled.path)).digest("hex");
264
+ if (digest !== bundled.sha256) {
265
+ return {
266
+ ok: false,
267
+ command: null,
268
+ detail: `${bundled.path} does not match the checksum in ${bundledManifestPath(env)} — got ${digest}, `
269
+ + `expected ${bundled.sha256}. Nothing was installed: the two files were written by `
270
+ + "different builds, or one was replaced by hand. Rebuild the bridge so both come from "
271
+ + "one build.",
272
+ flavours: [],
273
+ };
274
+ }
275
+ }
276
+ const flavours = [];
277
+ let lastCommand = null;
278
+ for (const host of ["vscode", "vscode-insiders"]) {
279
+ const app = await findApp(host, env);
280
+ if (app === null)
281
+ continue;
282
+ const cli = bundleCli(app.path);
283
+ const args = ["--install-extension", bundled.path, "--force"];
284
+ const command = `${quoteForDisplay(cli)} ${args.map(quoteForDisplay).join(" ")}`;
285
+ lastCommand = command;
286
+ options.onCommand?.(command);
287
+ try {
288
+ await run(cli, args, { timeout: 5 * 60_000, maxBuffer: 4 * 1024 * 1024, env });
289
+ flavours.push({
290
+ host,
291
+ ok: true,
292
+ detail: `Installed ${bundled.manifest.version ?? "the bundled bridge"} into ${HOSTS[host].name}.`,
293
+ });
294
+ }
295
+ catch (error) {
296
+ flavours.push({
297
+ host,
298
+ ok: false,
299
+ detail: `That command failed: ${error instanceof Error ? error.message : String(error)}`,
300
+ });
301
+ }
302
+ }
303
+ if (flavours.length === 0) {
304
+ return {
305
+ ok: false,
306
+ command: null,
307
+ detail: "Neither Visual Studio Code nor Visual Studio Code - Insiders is installed — looked up by "
308
+ + `bundle id (${HOSTS.vscode.bundleId}, ${HOSTS["vscode-insiders"].bundleId}) through `
309
+ + "Spotlight and at the usual paths under /Applications and ~/Applications. "
310
+ + "Install one and run this again.",
311
+ flavours,
312
+ };
313
+ }
314
+ const ok = flavours.every((flavour) => flavour.ok);
315
+ return {
316
+ ok,
317
+ command: lastCommand,
318
+ detail: flavours.map((flavour) => `${HOSTS[flavour.host].name}: ${flavour.detail}`).join(" ")
319
+ + (ok
320
+ ? " VS Code asks once whether the extension may handle a pharos URI — that is the "
321
+ + "trust prompt, not a fault."
322
+ : ""),
323
+ flavours,
324
+ };
325
+ }
326
+ function quoteForDisplay(value) {
327
+ return /[\s'"$`\\]/.test(value) ? `'${value.replace(/'/g, `'\\''`)}'` : value;
328
+ }
329
+ //# sourceMappingURL=vsix.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vsix.js","sourceRoot":"","sources":["../../src/delegate/vsix.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAC3D,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAE3C,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,KAAK,EAAe,MAAM,YAAY,CAAC;AAEpE,MAAM,GAAG,GAAG,SAAS,CAAC,QAAQ,CAAC,CAAC;AAEhC;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,MAAM,CAAC,MAAM,mBAAmB,GAAG,uBAAuB,CAAC;AAE3D,uGAAuG;AACvG,MAAM,CAAC,MAAM,mBAAmB,GAAG,uBAAuB,CAAC;AAC3D,MAAM,CAAC,MAAM,kBAAkB,GAAG,gBAAgB,CAAC;AAEnD;;;;;;GAMG;AACH,MAAM,UAAU,eAAe,CAAC,MAAyB,OAAO,CAAC,GAAG;IAClE,MAAM,QAAQ,GAAG,GAAG,CAAC,oBAAoB,CAAC,CAAC;IAC3C,IAAI,QAAQ,KAAK,SAAS,IAAI,QAAQ,KAAK,EAAE;QAAE,OAAO,QAAQ,CAAC;IAC/D,2EAA2E;IAC3E,qEAAqE;IACrE,OAAO,aAAa,CAAC,IAAI,GAAG,CAAC,iCAAiC,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AACpF,CAAC;AAED,iEAAiE;AACjE,MAAM,UAAU,mBAAmB,CAAC,MAAyB,OAAO,CAAC,GAAG;IACtE,OAAO,IAAI,CAAC,OAAO,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC,EAAE,oBAAoB,CAAC,CAAC;AACnE,CAAC;AAmBD,sFAAsF;AACtF,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,MAAyB,OAAO,CAAC,GAAG;IACtE,MAAM,IAAI,GAAG,eAAe,CAAC,GAAG,CAAC,CAAC;IAClC,IAAI,KAAa,CAAC;IAClB,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,CAAC;QAC9B,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE;YAAE,OAAO,IAAI,CAAC;QAChC,KAAK,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC,CAAC;IAC/B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;IAED,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,mBAAmB,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,CAAC;QAC7D,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAA4B,CAAC;QAC1D,MAAM,EAAE,GAAG,OAAO,MAAM,CAAC,IAAI,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;QAClE,MAAM,GAAG,GAAG,EAAE,EAAE,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC;QACnC,OAAO;YACL,IAAI;YACJ,KAAK,EAAE,KAAK,CAAC,MAAM;YACnB,QAAQ,EAAE;gBACR,SAAS,EAAE,EAAE,KAAK,IAAI,IAAI,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI;gBAC3D,IAAI,EAAE,EAAE,KAAK,IAAI,IAAI,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI;gBACvD,OAAO,EAAE,OAAO,MAAM,CAAC,SAAS,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,IAAI;aAC1E;YACD,MAAM,EAAE,OAAO,MAAM,CAAC,QAAQ,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,IAAI;YACpF,GAAG,EAAE,UAAU;SAChB,CAAC;IACJ,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,CAAC,MAAM,EAAE,QAAQ,EAAE,YAAY,CAAC,KAAK,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,EAAE,MAAM,EAAE,CAAC;IACjG,CAAC;AACH,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,YAAY,CAAC,KAAa;IACxC,MAAM,KAAK,GAAiB,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;IAC3E,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,EAAE,wBAAwB,CAAC,CAAC;IACxD,IAAI,KAAK,KAAK,IAAI;QAAE,OAAO,KAAK,CAAC;IACjC,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,CAA4B,CAAC;QAC7E,OAAO;YACL,SAAS,EAAE,OAAO,MAAM,CAAC,WAAW,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,IAAI;YAC/E,IAAI,EAAE,OAAO,MAAM,CAAC,MAAM,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI;YAChE,OAAO,EAAE,OAAO,MAAM,CAAC,SAAS,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,IAAI;SAC1E,CAAC;IACJ,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,MAAM,IAAI,GAAG,UAAU,CAAC;AACxB,MAAM,OAAO,GAAG,UAAU,CAAC;AAC3B,MAAM,KAAK,GAAG,UAAU,CAAC;AAEzB,gEAAgE;AAChE,MAAM,UAAU,QAAQ,CAAC,KAAa,EAAE,IAAY;IAClD,6EAA6E;IAC7E,+DAA+D;IAC/D,IAAI,IAAI,GAAG,CAAC,CAAC,CAAC;IACd,KAAK,IAAI,EAAE,GAAG,KAAK,CAAC,MAAM,GAAG,EAAE,EAAE,EAAE,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,MAAM,GAAG,EAAE,GAAG,MAAM,CAAC,EAAE,EAAE,IAAI,CAAC,EAAE,CAAC;QACxF,IAAI,KAAK,CAAC,YAAY,CAAC,EAAE,CAAC,KAAK,IAAI,EAAE,CAAC;YACpC,IAAI,GAAG,EAAE,CAAC;YACV,MAAM;QACR,CAAC;IACH,CAAC;IACD,IAAI,IAAI,KAAK,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC;IAE7B,MAAM,OAAO,GAAG,KAAK,CAAC,YAAY,CAAC,IAAI,GAAG,EAAE,CAAC,CAAC;IAC9C,IAAI,EAAE,GAAG,KAAK,CAAC,YAAY,CAAC,IAAI,GAAG,EAAE,CAAC,CAAC;IAEvC,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,OAAO,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC;QAChD,IAAI,EAAE,GAAG,EAAE,GAAG,KAAK,CAAC,MAAM,IAAI,KAAK,CAAC,YAAY,CAAC,EAAE,CAAC,KAAK,OAAO;YAAE,OAAO,IAAI,CAAC;QAC9E,MAAM,MAAM,GAAG,KAAK,CAAC,YAAY,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC;QAC3C,MAAM,cAAc,GAAG,KAAK,CAAC,YAAY,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC;QACnD,MAAM,UAAU,GAAG,KAAK,CAAC,YAAY,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC;QAC/C,MAAM,WAAW,GAAG,KAAK,CAAC,YAAY,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC;QAChD,MAAM,aAAa,GAAG,KAAK,CAAC,YAAY,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC;QAClD,MAAM,WAAW,GAAG,KAAK,CAAC,YAAY,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC;QAChD,MAAM,SAAS,GAAG,KAAK,CAAC,QAAQ,CAAC,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,EAAE,GAAG,UAAU,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;QAEjF,IAAI,SAAS,KAAK,IAAI,EAAE,CAAC;YACvB,IAAI,WAAW,GAAG,EAAE,GAAG,KAAK,CAAC,MAAM,IAAI,KAAK,CAAC,YAAY,CAAC,WAAW,CAAC,KAAK,KAAK;gBAAE,OAAO,IAAI,CAAC;YAC9F,MAAM,eAAe,GAAG,KAAK,CAAC,YAAY,CAAC,WAAW,GAAG,EAAE,CAAC,CAAC;YAC7D,MAAM,gBAAgB,GAAG,KAAK,CAAC,YAAY,CAAC,WAAW,GAAG,EAAE,CAAC,CAAC;YAC9D,MAAM,KAAK,GAAG,WAAW,GAAG,EAAE,GAAG,eAAe,GAAG,gBAAgB,CAAC;YACpE,MAAM,IAAI,GAAG,KAAK,CAAC,QAAQ,CAAC,KAAK,EAAE,KAAK,GAAG,cAAc,CAAC,CAAC;YAC3D,IAAI,MAAM,KAAK,CAAC;gBAAE,OAAO,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAC3C,IAAI,MAAM,KAAK,CAAC,EAAE,CAAC;gBACjB,IAAI,CAAC;oBACH,OAAO,cAAc,CAAC,IAAI,CAAC,CAAC;gBAC9B,CAAC;gBAAC,MAAM,CAAC;oBACP,OAAO,IAAI,CAAC;gBACd,CAAC;YACH,CAAC;YACD,OAAO,IAAI,CAAC;QACd,CAAC;QAED,EAAE,IAAI,EAAE,GAAG,UAAU,GAAG,WAAW,GAAG,aAAa,CAAC;IACtD,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAQD,wFAAwF;AACxF,MAAM,UAAU,mBAAmB,CAAC,IAAY,EAAE,MAAyB,OAAO,CAAC,GAAG;IACpF,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC;IAChC,IAAI,IAAI,KAAK,SAAS;QAAE,OAAO,IAAI,CAAC;IACpC,OAAO,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,OAAO,EAAE,EAAE,IAAI,CAAC,aAAa,CAAC,CAAC;AAC5D,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,IAAY,EACZ,MAAyB,OAAO,CAAC,GAAG;IAEpC,MAAM,SAAS,GAAG,mBAAmB,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;IACjD,IAAI,SAAS,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IAEpC,IAAI,KAAe,CAAC;IACpB,IAAI,CAAC;QACH,KAAK,GAAG,MAAM,OAAO,CAAC,SAAS,CAAC,CAAC;IACnC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;IAED,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC,SAAS,EAAE,iBAAiB,CAAC,EAAE,MAAM,CAAC,CAAC;QACvE,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAY,CAAC;QAC1C,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;YAC1B,MAAM,MAAM,GAAyB,EAAE,CAAC;YACxC,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;gBAC3B,MAAM,MAAM,GAAG,KAAyF,CAAC;gBACzG,MAAM,EAAE,GAAG,MAAM,CAAC,UAAU,EAAE,EAAE,CAAC;gBACjC,IAAI,OAAO,EAAE,KAAK,QAAQ,IAAI,OAAO,MAAM,CAAC,OAAO,KAAK,QAAQ;oBAAE,SAAS;gBAC3E,MAAM,MAAM,GAAG,OAAO,MAAM,CAAC,gBAAgB,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC,CAAC,GAAG,EAAE,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;gBACjH,MAAM,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,EAAE,CAAC,WAAW,EAAE,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC;YAChG,CAAC;YACD,OAAO,MAAM,CAAC;QAChB,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,iEAAiE;IACnE,CAAC;IAED,MAAM,OAAO,GAAyB,EAAE,CAAC;IACzC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,MAAM,GAAG,oBAAoB,CAAC,IAAI,CAAC,CAAC;QAC1C,IAAI,MAAM,KAAK,IAAI;YAAE,OAAO,CAAC,IAAI,CAAC,EAAE,GAAG,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC;IAChF,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,6FAA6F;AAC7F,MAAM,UAAU,oBAAoB,CAAC,IAAY;IAC/C,MAAM,KAAK,GAAG,oFAAoF,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC9G,IAAI,KAAK,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IAChC,IAAI,OAAO,GAAG,KAAK,CAAC,CAAC,CAAE,CAAC;IACxB,mFAAmF;IACnF,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,2DAA2D,EAAE,EAAE,CAAC,CAAC;IAC3F,OAAO,EAAE,EAAE,EAAE,KAAK,CAAC,CAAC,CAAE,CAAC,WAAW,EAAE,EAAE,OAAO,EAAE,CAAC;AAClD,CAAC;AAWD;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,UAGI,EAAE;IAEN,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,CAAC;IACvC,MAAM,OAAO,GAAG,MAAM,aAAa,CAAC,GAAG,CAAC,CAAC;IACzC,IAAI,OAAO,KAAK,IAAI,EAAE,CAAC;QACrB,OAAO;YACL,EAAE,EAAE,KAAK;YACT,OAAO,EAAE,IAAI;YACb,MAAM,EACJ,iCAAiC,eAAe,CAAC,GAAG,CAAC,oCAAoC;kBACvF,sFAAsF;kBACtF,wEAAwE;kBACxE,4BAA4B;YAChC,QAAQ,EAAE,EAAE;SACb,CAAC;IACJ,CAAC;IAED,IAAI,OAAO,CAAC,MAAM,KAAK,IAAI,EAAE,CAAC;QAC5B,MAAM,MAAM,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,MAAM,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QACvF,IAAI,MAAM,KAAK,OAAO,CAAC,MAAM,EAAE,CAAC;YAC9B,OAAO;gBACL,EAAE,EAAE,KAAK;gBACT,OAAO,EAAE,IAAI;gBACb,MAAM,EACJ,GAAG,OAAO,CAAC,IAAI,mCAAmC,mBAAmB,CAAC,GAAG,CAAC,UAAU,MAAM,IAAI;sBAC5F,YAAY,OAAO,CAAC,MAAM,yDAAyD;sBACnF,sFAAsF;sBACtF,YAAY;gBAChB,QAAQ,EAAE,EAAE;aACb,CAAC;QACJ,CAAC;IACH,CAAC;IAED,MAAM,QAAQ,GAAqC,EAAE,CAAC;IACtD,IAAI,WAAW,GAAkB,IAAI,CAAC;IAEtC,KAAK,MAAM,IAAI,IAAI,CAAC,QAAQ,EAAE,iBAAiB,CAAU,EAAE,CAAC;QAC1D,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;QACrC,IAAI,GAAG,KAAK,IAAI;YAAE,SAAS;QAC3B,MAAM,GAAG,GAAG,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAChC,MAAM,IAAI,GAAG,CAAC,qBAAqB,EAAE,OAAO,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;QAC9D,MAAM,OAAO,GAAG,GAAG,eAAe,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;QACjF,WAAW,GAAG,OAAO,CAAC;QACtB,OAAO,CAAC,SAAS,EAAE,CAAC,OAAO,CAAC,CAAC;QAC7B,IAAI,CAAC;YACH,MAAM,GAAG,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE,OAAO,EAAE,CAAC,GAAG,MAAM,EAAE,SAAS,EAAE,CAAC,GAAG,IAAI,GAAG,IAAI,EAAE,GAAG,EAAE,CAAC,CAAC;YAC/E,QAAQ,CAAC,IAAI,CAAC;gBACZ,IAAI;gBACJ,EAAE,EAAE,IAAI;gBACR,MAAM,EAAE,aAAa,OAAO,CAAC,QAAQ,CAAC,OAAO,IAAI,oBAAoB,SAAS,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,GAAG;aAClG,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,QAAQ,CAAC,IAAI,CAAC;gBACZ,IAAI;gBACJ,EAAE,EAAE,KAAK;gBACT,MAAM,EAAE,wBAAwB,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE;aACzF,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC1B,OAAO;YACL,EAAE,EAAE,KAAK;YACT,OAAO,EAAE,IAAI;YACb,MAAM,EACJ,2FAA2F;kBACzF,cAAc,KAAK,CAAC,MAAM,CAAC,QAAQ,KAAK,KAAK,CAAC,iBAAiB,CAAC,CAAC,QAAQ,YAAY;kBACrF,2EAA2E;kBAC3E,iCAAiC;YACrC,QAAQ;SACT,CAAC;IACJ,CAAC;IAED,MAAM,EAAE,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IACnD,OAAO;QACL,EAAE;QACF,OAAO,EAAE,WAAW;QACpB,MAAM,EACJ,QAAQ,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,IAAI,KAAK,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC;cACnF,CAAC,EAAE;gBACH,CAAC,CAAC,iFAAiF;sBAC/E,4BAA4B;gBAChC,CAAC,CAAC,EAAE,CAAC;QACT,QAAQ;KACT,CAAC;AACJ,CAAC;AAED,SAAS,eAAe,CAAC,KAAa;IACpC,OAAO,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC;AAChF,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@floh-solutions/pharos-cli",
3
- "version": "0.29.0",
3
+ "version": "0.31.0",
4
4
  "description": "Azure DevOps from a headless shell, for an agent: the whole context of a task in one call, and the wiki/comment verbs Microsoft's MCP server does not ship.",
5
5
  "license": "UNLICENSED",
6
6
  "author": "FLOH Solutions",
@@ -18,15 +18,16 @@
18
18
  },
19
19
  "files": [
20
20
  "dist",
21
- "skill"
21
+ "skill",
22
+ "vscode"
22
23
  ],
23
24
  "engines": {
24
25
  "node": ">=22"
25
26
  },
26
27
  "dependencies": {
27
28
  "@floh-solutions/ado-core": "0.11.0",
28
- "@floh-solutions/plan-to-board": "0.2.0",
29
- "@floh-solutions/gh-core": "0.4.0"
29
+ "@floh-solutions/gh-core": "0.4.0",
30
+ "@floh-solutions/plan-to-board": "0.2.0"
30
31
  },
31
32
  "devDependencies": {
32
33
  "@types/node": "^22.10.2",
package/skill/SKILL.md CHANGED
@@ -119,6 +119,16 @@ bridge map|unmap|digest edit that mapping (--label is an ID, not a name
119
119
  written back to the work item
120
120
  doctor what is installed on THIS machine, what is
121
121
  missing, and what each missing thing costs
122
+ delegate hand a prompt to a coding agent in Terminal or
123
+ VS Code — Pharos.app's verb, not usually yours.
124
+ You are on the RECEIVING end: see "When a
125
+ prompt begins Fetch Azure DevOps work item".
126
+ `--list` names the sessions already on a folder
127
+ (id, name, status, host; `recommended` on the
128
+ one a plain delegate takes) and `--session <id>`
129
+ picks one of them — or `--session new` for a
130
+ fresh one. A pick that has gone answers
131
+ `session-gone` and starts nothing
122
132
  ```
123
133
 
124
134
  Text input: `--text` / `--file` / `--stdin`. Global: `--pretty` for a human,
@@ -1303,6 +1313,43 @@ no Azure DevOps account, which is every reporter.
1303
1313
  anything you do is recorded against whoever owns `ADO_PAT`. Never suggest
1304
1314
  sharing one.
1305
1315
 
1316
+ ## When a prompt begins "Fetch Azure DevOps work item #N with the pharos skill"
1317
+
1318
+ That is a **delegation from Pharos**, the macOS board app. Somebody right-
1319
+ clicked a work item and chose *Ask Agent*; the app found or started this
1320
+ session in the folder linked to that project and typed the prompt in. Only the
1321
+ **id** was sent — no title, no URL, no description — on purpose: you fetch the
1322
+ item yourself, with the CLI already configured for the right organisation, so
1323
+ what you read is what is on the board now rather than a copy the app might
1324
+ have got wrong.
1325
+
1326
+ So the first move is the usual one, and it is the whole context in one call:
1327
+
1328
+ ```bash
1329
+ pharos task <id> # description, discussion, attachments, relations, linked pages
1330
+ pharos download <id> --all --out ./attachments # then READ them — images too
1331
+ ```
1332
+
1333
+ Read everything it returns, including the discussion and every attachment and
1334
+ image (the section on reading attachments above says how, and `pharos doctor`
1335
+ says what this machine can open). Then, **which of the two prompts you got
1336
+ decides what happens next**:
1337
+
1338
+ - It ends with *"so we can then discuss the task"* — the person wants to talk
1339
+ first. Summarise what the item asks for, what is specified and what is not,
1340
+ and what you would do; then **wait**.
1341
+ - It carries instructions after the fetch sentence — the person has already
1342
+ decided. Take the item on as instructed, without asking whether to start.
1343
+
1344
+ Either way the reply loop is the board's, not the chat's, because the person
1345
+ who delegated is watching the work item in Pharos rather than this pane:
1346
+
1347
+ ```bash
1348
+ pharos update <id> --state Doing # the moment work starts (`pharos types` for the names)
1349
+ pharos comment add <id> --file notes.md # questions, findings, decisions — on the item
1350
+ pharos task <id> # re-read before acting on an answer
1351
+ ```
1352
+
1306
1353
  ## When it is not set up
1307
1354
 
1308
1355
  `"kind": "config"` on exit 2 means the environment is missing. Run `pharos
@@ -0,0 +1,30 @@
1
+ # The Pharos bridge for VS Code, as shipped by the CLI
2
+
3
+ Two files land here, and neither is committed:
4
+
5
+ | file | what |
6
+ |---|---|
7
+ | `pharos-bridge.vsix` | the extension `floh-solutions.pharos`, built from `packages/pharos-vscode` |
8
+ | `pharos-bridge.json` | `{ id, version, vsix, sha256, bytes, engines }`, derived from that package's `package.json` by the same build |
9
+
10
+ ```bash
11
+ pnpm --filter ./packages/pharos-vscode build # from the repo root; writes both files here
12
+ ```
13
+
14
+ They ship inside the npm package because `files` in `package.json` names
15
+ `vscode/` — npm packs a gitignored path when `files` names it — and
16
+ `scripts/prepack.mjs` refuses to pack when either is missing, so the CLI can
17
+ never go out bridge-less by accident.
18
+
19
+ The CLI reads them in two places:
20
+
21
+ - `pharos doctor` compares the bridge installed in each VS Code flavour with
22
+ the `version` in the JSON (`vscode-bridge`, `vscode-insiders-bridge`).
23
+ - `pharos setup --install vscode-bridge` checks the `.vsix` against the
24
+ JSON's `sha256` and hands it to each installed flavour's own
25
+ `Contents/Resources/app/bin/code --install-extension`, because the `code`
26
+ command is usually not on PATH.
27
+
28
+ `PHAROS_BRIDGE_VSIX=/path/to/other.vsix` overrides the location — for
29
+ installing a local build, and for the tests, which must never install a real
30
+ extension into somebody's editor.
@@ -0,0 +1,10 @@
1
+ {
2
+ "id": "floh-solutions.pharos",
3
+ "version": "0.2.0",
4
+ "vsix": "pharos-bridge.vsix",
5
+ "sha256": "1dfde61c1bf0e3bba1ec98e798ae26b05a04415a9e903c8440dca1748c4dccae",
6
+ "bytes": 23158,
7
+ "engines": {
8
+ "vscode": "^1.94.0"
9
+ }
10
+ }
Binary file
@@ -1,56 +0,0 @@
1
- import { type ExitCode, type Io } from "../output.js";
2
- import type { Session } from "../session.js";
3
- /**
4
- * `pharos pr` — where the trail goes after adoption.
5
- *
6
- * ## The gap this closes
7
- *
8
- * `pharos issue` joins a GitHub issue to a work item, and `issue trail` follows
9
- * that join from either end. Both stop at the moment the work becomes code. A
10
- * session asking *"is this actually done?"* got filing, adoption and a state
11
- * field, and nothing at all about the branch that answers the question.
12
- *
13
- * ## What it composes
14
- *
15
- * One call, two platforms, four questions that are otherwise four commands and
16
- * two credentials:
17
- *
18
- * | | otherwise |
19
- * |---|---|
20
- * | the pull request and its review verdict | `gh pr view` |
21
- * | which checks are RED (not the first few) | `gh pr checks` |
22
- * | which work items it belongs to | a WIQL query, or reading a marker by hand |
23
- * | whether the two platforms AGREE | nothing — this is the part nobody has |
24
- *
25
- * ## The join is two paths, and the implicit one is the one that fires
26
- *
27
- * A pull request reaches a work item two ways, and both are read:
28
- *
29
- * 1. **Directly** — `AB#4821` in the body. This is what Azure Boards' own GitHub
30
- * app reads, and Pharos writes it so that integration lights up free where it
31
- * happens to be installed.
32
- * 2. **Transitively** — `Fixes #45`, where issue #45 has been adopted. GitHub
33
- * reports this as `closingIssuesReferences`, and it is the path that actually
34
- * occurs: developers write `Fixes #45` constantly and `AB#4821` almost never.
35
- *
36
- * Path 2 costs one extra read per closed issue — the issue's comments, which is
37
- * where the `pharos:v1` trailer lives. `linksFromComments` is `gh-core`'s, the
38
- * same function `issue trail` and the macOS app use, because "what counts as a
39
- * link" must have exactly one answer.
40
- *
41
- * ## The disagreements are the point
42
- *
43
- * Everything above is a read that something else could eventually do. The
44
- * `disagreements` array is the part **neither platform will ever tell you**:
45
- * an open pull request against a work item somebody already closed, a merged one
46
- * against a work item still sitting in To Do. Azure DevOps cannot see the pull
47
- * request and GitHub does not know the work item exists, so nothing anywhere is
48
- * in a position to notice. Same shape as `pharos issue drift`, one step further
49
- * down the pipeline.
50
- */
51
- export interface PrCommandOptions {
52
- /** Skip resolving `Fixes #N` through to work items. One read per closed issue. */
53
- noWorkItems: boolean;
54
- }
55
- export declare function runPr(io: Io, session: Session, rest: readonly string[], options: PrCommandOptions): Promise<ExitCode>;
56
- //# sourceMappingURL=pr.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"pr.d.ts","sourceRoot":"","sources":["../../src/commands/pr.ts"],"names":[],"mappings":"AAOA,OAAO,EAAyC,KAAK,QAAQ,EAAE,KAAK,EAAE,EAAE,MAAM,cAAc,CAAC;AAC7F,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAE7C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+CG;AAEH,MAAM,WAAW,gBAAgB;IAC/B,kFAAkF;IAClF,WAAW,EAAE,OAAO,CAAC;CACtB;AAED,wBAAsB,KAAK,CACzB,EAAE,EAAE,EAAE,EACN,OAAO,EAAE,OAAO,EAChB,IAAI,EAAE,SAAS,MAAM,EAAE,EACvB,OAAO,EAAE,gBAAgB,GACxB,OAAO,CAAC,QAAQ,CAAC,CA6EnB"}