@junghanacs/entwurf 0.14.2 → 0.15.1

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 (87) hide show
  1. package/AGENTS.md +9 -5
  2. package/CHANGELOG.md +149 -0
  3. package/DELIVERY.md +72 -59
  4. package/README.md +120 -20
  5. package/VERIFY.md +10 -7
  6. package/demo/README.md +1 -1
  7. package/docs/acp-backend-rail.md +2 -2
  8. package/docs/external-mcp-host.md +26 -4
  9. package/docs/setup-clean-host.md +118 -18
  10. package/mcp/entwurf-bridge/dist/mcp/entwurf-bridge/src/index.js +8 -6
  11. package/mcp/entwurf-bridge/dist/pi-extensions/entwurf-capabilities.json +1 -0
  12. package/mcp/entwurf-bridge/dist/pi-extensions/lib/copilot-fresh-preflight.js +253 -0
  13. package/mcp/entwurf-bridge/dist/pi-extensions/lib/meta-sender-identity.js +10 -2
  14. package/mcp/entwurf-bridge/dist/pi-extensions/lib/meta-session.js +102 -28
  15. package/mcp/entwurf-bridge/dist/pi-extensions/lib/mux-fresh-call.js +77 -11
  16. package/mcp/entwurf-bridge/dist/pi-extensions/meta-bridge-hook-copilot.js +288 -0
  17. package/mcp/entwurf-bridge/src/index.ts +10 -6
  18. package/mcp/entwurf-bridge/tsconfig.build.json +2 -1
  19. package/package.json +22 -11
  20. package/pi/copilot-receive/entwurf-receive/extension.mjs +323 -0
  21. package/pi/entwurf-capabilities.json +1 -0
  22. package/pi/meta-bridge-copilot/.claude-plugin/marketplace.json +11 -0
  23. package/pi/meta-bridge-copilot/entwurf-meta-receive-copilot/.claude-plugin/plugin.json +5 -0
  24. package/pi/meta-bridge-copilot/entwurf-meta-receive-copilot/hooks/hooks.json +7 -0
  25. package/pi/meta-bridge-copilot/entwurf-meta-receive-copilot/scripts/copilot-hook-launch.sh +85 -0
  26. package/pi-extensions/entwurf-control.ts +17 -8
  27. package/pi-extensions/lib/copilot-fresh-preflight.ts +251 -0
  28. package/pi-extensions/lib/meta-sender-identity.ts +10 -2
  29. package/pi-extensions/lib/meta-session.ts +102 -29
  30. package/pi-extensions/lib/mux-fresh-call.ts +82 -11
  31. package/pi-extensions/meta-bridge-hook-copilot.ts +323 -0
  32. package/run.sh +1079 -186
  33. package/scripts/agy-bridge.sh +4 -2
  34. package/scripts/check-copilot-birth-hook.ts +1174 -0
  35. package/scripts/check-copilot-launch.ts +395 -0
  36. package/scripts/check-copilot-receive-arm.ts +734 -0
  37. package/scripts/check-copilot-statusline.ts +122 -0
  38. package/scripts/check-entwurf-capabilities.ts +25 -6
  39. package/scripts/check-fresh-cut-gate.sh +104 -27
  40. package/scripts/check-gate-qualification.ts +10 -1
  41. package/scripts/check-install-container.sh +2 -2
  42. package/scripts/check-install-surface.ts +1 -1
  43. package/scripts/check-meta-capability-source.ts +89 -5
  44. package/scripts/check-meta-doctor-oracle.sh +26 -0
  45. package/scripts/check-meta-manifest-schema.py +38 -0
  46. package/scripts/check-meta-receiver-marker.ts +25 -2
  47. package/scripts/check-meta-session.ts +32 -0
  48. package/scripts/check-setup-qualification.sh +126 -0
  49. package/scripts/copilot-bridge-doctor.sh +242 -0
  50. package/scripts/copilot-bridge-install.sh +384 -0
  51. package/scripts/copilot-bridge-oracle.sh +223 -0
  52. package/scripts/copilot-bridge-uninstall.sh +137 -0
  53. package/scripts/copilot-launch.sh +236 -0
  54. package/scripts/copilot-mcp-bridge.sh +177 -0
  55. package/scripts/copilot-mcp-config.py +221 -0
  56. package/scripts/copilot-receive-bridge.sh +483 -0
  57. package/scripts/copilot-statusline-bridge.sh +149 -0
  58. package/scripts/copilot-statusline-config.py +201 -0
  59. package/scripts/copilot-statusline.sh +68 -0
  60. package/scripts/dev-bin.sh +53 -9
  61. package/scripts/fake-copilot-vendor.sh +67 -0
  62. package/scripts/meta-bridge-hook-log.sh +17 -5
  63. package/scripts/mutants/capability-cache.json +64 -0
  64. package/scripts/mutants/copilot-birth.json +244 -0
  65. package/scripts/mutants/copilot-launch.json +187 -0
  66. package/scripts/mutants/copilot-receive.json +263 -0
  67. package/scripts/mutants/fresh-cut.json +17 -0
  68. package/scripts/mutants/mux-fresh-call.json +216 -2
  69. package/scripts/mutants/pack-install.json +17 -0
  70. package/scripts/mutants/pi-package-ownership.json +92 -0
  71. package/scripts/mutants/setup-verdict.json +148 -0
  72. package/scripts/mutants/source-install.json +32 -0
  73. package/scripts/pi_settings_io.py +22 -0
  74. package/scripts/raw-async-delivery/README.md +170 -125
  75. package/scripts/raw-async-delivery/copilot-enqueue-addressed.sh +35 -0
  76. package/scripts/raw-async-delivery/copilot-extension-receive/extension.mjs +123 -0
  77. package/scripts/register-pi-package.py +525 -7
  78. package/scripts/register-pi-provider.py +162 -12
  79. package/scripts/smoke-agy-install-state.sh +86 -30
  80. package/scripts/smoke-agy-statusline-state.sh +9 -6
  81. package/scripts/smoke-copilot-mcp-state.sh +153 -0
  82. package/scripts/smoke-copilot-statusline-state.sh +131 -0
  83. package/scripts/smoke-mux-fresh-call-live.ts +2 -0
  84. package/scripts/smoke-mux-lifecycle-live.ts +3 -1
  85. package/scripts/smoke-setup-verdict.sh +291 -0
  86. package/scripts/smoke-user-scope-citizen.sh +388 -1
  87. package/scripts/tsconfig.json +1 -0
@@ -0,0 +1,123 @@
1
+ /**
2
+ * entwurf mailbox receiver — GitHub Copilot CLI extension.
3
+ *
4
+ * WHAT THIS REPLACES. The earlier Copilot probe reached the TUI through the
5
+ * hidden `--ui-server` loopback port, and that rail was refused admission for a
6
+ * reason no amount of care could fix from outside: its authentication was not
7
+ * established (an unauthenticated SDK client connected; a token-bearing one got
8
+ * AUTHENTICATION_NOT_CONFIGURED). This rail does not answer that objection — it
9
+ * removes it. An extension is forked by the CLI itself and speaks JSON-RPC over
10
+ * its own stdio, so there is no port, no token, and no listener to authenticate.
11
+ * The trust boundary is the process fork.
12
+ *
13
+ * WHAT IT DOES. `joinSession()` attaches to the CLI's foreground session; the
14
+ * extension then watches ONE per-session signal file and calls `session.send()`
15
+ * when it changes. `fs.watch` -> `session.send()` is the pattern the bundled SDK
16
+ * documents itself (copilot-sdk/docs/examples.md, "Detecting when the plan file
17
+ * is created or edited"), not a mechanism discovered by inspection.
18
+ *
19
+ * ADDRESSED, NEVER BROADCAST. Each receiver owns `<root>/<sessionId>/` and
20
+ * watches only its own signal, so a sender pokes exactly one session rather than
21
+ * broadcasting. A two-process isolation run was observed, but its decisive B log
22
+ * was not preserved; managed admission must rerun that D3 control.
23
+ *
24
+ * LAUNCH CONTRACT. Extensions sit behind an experimental feature flag; without
25
+ * it the CLI never scans for them and this file is inert with no error:
26
+ *
27
+ * COPILOT_CLI_ENABLED_FEATURE_FLAGS=EXTENSIONS copilot --model auto
28
+ *
29
+ * `--experimental` is NOT required (measured separately). Discovery scopes are
30
+ * user (`~/.copilot/extensions/`), plugin, session, and — interactive mode only
31
+ * — project (`.github/extensions/`).
32
+ */
33
+
34
+ import {
35
+ appendFileSync,
36
+ existsSync,
37
+ mkdirSync,
38
+ readdirSync,
39
+ readFileSync,
40
+ renameSync,
41
+ watch,
42
+ writeFileSync,
43
+ } from "node:fs";
44
+ import { homedir } from "node:os";
45
+ import { join } from "node:path";
46
+ import { joinSession } from "@github/copilot-sdk/extension";
47
+
48
+ const root = process.env.COPILOT_MAILBOX_ROOT ?? join(homedir(), ".copilot", "mailbox");
49
+
50
+ const session = await joinSession();
51
+ const box = join(root, session.sessionId);
52
+ mkdirSync(box, { recursive: true });
53
+ const logPath = join(box, "ext.log");
54
+ const log = (line) => appendFileSync(logPath, `${new Date().toISOString()} ${line}\n`);
55
+
56
+ // The sender needs an address, and scraping ~/.copilot storage for one is what
57
+ // the old command-hook probe failed at (its sessionStart input carries no
58
+ // sessionId). The receiver publishes its own identity instead, so discovery is
59
+ // a file this process wrote about itself rather than an inference about it.
60
+ writeFileSync(
61
+ join(box, "ready.json"),
62
+ JSON.stringify(
63
+ {
64
+ sessionId: session.sessionId,
65
+ pid: process.pid,
66
+ cwd: process.cwd(),
67
+ armedAt: new Date().toISOString(),
68
+ },
69
+ null,
70
+ 2,
71
+ ),
72
+ );
73
+
74
+ const signal = join(box, "inbox.signal");
75
+ if (!existsSync(signal)) writeFileSync(signal, "");
76
+ log(`ARMED sessionId=${session.sessionId} signal=${signal}`);
77
+
78
+ for (const type of ["user.message", "assistant.turn_start", "assistant.message", "session.idle"]) {
79
+ session.on(type, (event) => {
80
+ const d = event?.data ?? {};
81
+ log(
82
+ `EVENT ${type} ${JSON.stringify({
83
+ turnId: d.turnId,
84
+ content: typeof d.content === "string" ? d.content.slice(0, 200) : undefined,
85
+ source: d.source,
86
+ })}`,
87
+ );
88
+ });
89
+ }
90
+
91
+ // Serialized because a burst of writes to one signal file is normal and two
92
+ // overlapping drains would rename the same `.msg` twice.
93
+ let busy = false;
94
+ async function drain(why) {
95
+ if (busy) return;
96
+ busy = true;
97
+ try {
98
+ const pending = readdirSync(box)
99
+ .filter((f) => f.endsWith(".msg"))
100
+ .sort();
101
+ for (const name of pending) {
102
+ const from = join(box, name);
103
+ const to = `${from}.delivered`;
104
+ // Rename BEFORE sending: a crash between the two loses one delivery,
105
+ // but sending before renaming would replay it on every later poke.
106
+ renameSync(from, to);
107
+ const body = readFileSync(to, "utf-8");
108
+ log(`DELIVER (${why}) ${name} bytes=${body.length}`);
109
+ await session.send({ prompt: body, mode: "enqueue" });
110
+ log(`SENT ${name}`);
111
+ }
112
+ } catch (err) {
113
+ log(`ERROR ${String(err)}`);
114
+ } finally {
115
+ busy = false;
116
+ }
117
+ }
118
+
119
+ watch(signal, () => {
120
+ void drain("signal");
121
+ });
122
+ // Messages that arrived while nothing was armed are still owed a delivery.
123
+ void drain("startup");