humanish 0.95.0 → 0.96.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 (87) hide show
  1. package/README.md +4 -2
  2. package/dist/comms-agentmail.d.ts +25 -0
  3. package/dist/comms-agentmail.js +418 -0
  4. package/dist/comms-agentmail.js.map +1 -0
  5. package/dist/comms-connections.d.ts +4 -2
  6. package/dist/comms-connections.js +3 -3
  7. package/dist/comms-connections.js.map +1 -1
  8. package/dist/comms-lease-store.d.ts +90 -0
  9. package/dist/comms-lease-store.js +489 -0
  10. package/dist/comms-lease-store.js.map +1 -0
  11. package/dist/comms-receiving-evidence.d.ts +46 -0
  12. package/dist/comms-receiving-evidence.js +35 -0
  13. package/dist/comms-receiving-evidence.js.map +1 -0
  14. package/dist/comms-receiving-inbox.d.ts +16 -0
  15. package/dist/comms-receiving-inbox.js +410 -0
  16. package/dist/comms-receiving-inbox.js.map +1 -0
  17. package/dist/comms-receiving-runtime.d.ts +25 -0
  18. package/dist/comms-receiving-runtime.js +45 -0
  19. package/dist/comms-receiving-runtime.js.map +1 -0
  20. package/dist/comms-receiving-types.d.ts +98 -0
  21. package/dist/comms-receiving-types.js +2 -0
  22. package/dist/comms-receiving-types.js.map +1 -0
  23. package/dist/comms-receiving.d.ts +58 -0
  24. package/dist/comms-receiving.js +554 -0
  25. package/dist/comms-receiving.js.map +1 -0
  26. package/dist/comms-setup.d.ts +40 -0
  27. package/dist/comms-setup.js +121 -0
  28. package/dist/comms-setup.js.map +1 -0
  29. package/dist/concurrent-shared-world-lab.js +662 -624
  30. package/dist/concurrent-shared-world-lab.js.map +1 -1
  31. package/dist/cua-actor-lab.d.ts +4 -1
  32. package/dist/cua-actor-lab.js +98 -17
  33. package/dist/cua-actor-lab.js.map +1 -1
  34. package/dist/doctor-lab.js +11 -0
  35. package/dist/doctor-lab.js.map +1 -1
  36. package/dist/e2b-terminal-lab.js +3 -0
  37. package/dist/e2b-terminal-lab.js.map +1 -1
  38. package/dist/index.d.ts +2 -0
  39. package/dist/index.js +1 -0
  40. package/dist/index.js.map +1 -1
  41. package/dist/lab-config.d.ts +20 -3
  42. package/dist/lab-config.js +59 -6
  43. package/dist/lab-config.js.map +1 -1
  44. package/dist/lab-engine.js +8 -3
  45. package/dist/lab-engine.js.map +1 -1
  46. package/dist/lab-summary.d.ts +1 -0
  47. package/dist/lab-summary.js +8 -2
  48. package/dist/lab-summary.js.map +1 -1
  49. package/dist/observer-app.html +1 -1
  50. package/dist/observer-data.js +14 -1
  51. package/dist/observer-data.js.map +1 -1
  52. package/dist/oss-lab.d.ts +1 -1
  53. package/dist/oss-lab.js.map +1 -1
  54. package/dist/oss-meta-lab.d.ts +1 -1
  55. package/dist/oss-meta-lab.js.map +1 -1
  56. package/dist/program.d.ts +2 -0
  57. package/dist/program.js +100 -4
  58. package/dist/program.js.map +1 -1
  59. package/dist/run-narration-secrets.d.ts +5 -0
  60. package/dist/run-narration-secrets.js +68 -0
  61. package/dist/run-narration-secrets.js.map +1 -0
  62. package/dist/run.d.ts +7 -2
  63. package/dist/run.js +25 -3
  64. package/dist/run.js.map +1 -1
  65. package/dist/scripted-browser-lab.js +7 -0
  66. package/dist/scripted-browser-lab.js.map +1 -1
  67. package/dist/shared-world-lab.js +4 -0
  68. package/dist/shared-world-lab.js.map +1 -1
  69. package/dist/study-analysis-engine.js +30 -1
  70. package/dist/study-analysis-engine.js.map +1 -1
  71. package/dist/study-analysis-evidence.js +9 -1
  72. package/dist/study-analysis-evidence.js.map +1 -1
  73. package/dist/tui-app.js +134 -134
  74. package/dist/tui-contract.d.ts +13 -0
  75. package/dist/tui-contract.js.map +1 -1
  76. package/dist/tui-launch.d.ts +2 -0
  77. package/dist/tui-launch.js +9 -1
  78. package/dist/tui-launch.js.map +1 -1
  79. package/docs/architecture/comms-inbox.md +4 -0
  80. package/docs/architecture/real-email-receiving.md +135 -0
  81. package/docs/contracts/run-bundle.md +9 -1
  82. package/docs/contracts/schemas.md +20 -3
  83. package/docs/goals/current.md +5 -5
  84. package/docs/ramp/README.md +9 -5
  85. package/docs/release/0.96.0-real-email-receiving.md +47 -0
  86. package/package.json +2 -1
  87. package/skills/humanish/SKILL.md +33 -13
package/dist/program.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import { type AutomaticAnalysisHooks } from "./automatic-analysis-completion.js";
2
2
  import { Command } from "commander";
3
3
  import { discoverProviderKeys } from "./key-resolution.js";
4
+ import { checkCommsConnection } from "./comms-setup.js";
4
5
  import { promptSecret } from "./secret-prompt.js";
5
6
  import { type TelemetryProperties } from "./telemetry.js";
6
7
  import type { CuaActorLabResult } from "./cua-actor-lab.js";
@@ -40,6 +41,7 @@ export declare function createProgram(io?: Partial<CliIo> & {
40
41
  * TTY, an old Node, or a missing bundle appear.
41
42
  */
42
43
  export interface TuiRuntime {
44
+ checkComms: typeof checkCommsConnection;
43
45
  promptSecret: typeof promptSecret;
44
46
  stdin: NodeJS.ReadStream;
45
47
  stdout: NodeJS.WriteStream;
package/dist/program.js CHANGED
@@ -11,6 +11,9 @@ import { startCodexAppServerUi } from "./codex-app-server-ui.js";
11
11
  import { loadEnvFile } from "./env-file.js";
12
12
  import { discoverProviderKeys, listUserKeys, resolveKeyName, setUserKey, unsetUserKey, userKeyStorePath } from "./key-resolution.js";
13
13
  import { COMMS_PROVIDERS, readCommsSetup, saveCommsConnection } from "./comms-connections.js";
14
+ import { checkCommsConnection, configureCommsLab } from "./comms-setup.js";
15
+ import { inspectCommsRecovery, recoverCommsReceiving } from "./comms-receiving.js";
16
+ import { resolveReceivingConnection } from "./comms-receiving-runtime.js";
14
17
  import { promptSecret } from "./secret-prompt.js";
15
18
  import { redactText } from "./redaction.js";
16
19
  import { draftFeedback, listFeedback, renderIssueMarkdown, renderIssueUrl, verifyFeedback } from "./feedback.js";
@@ -463,6 +466,7 @@ function registerDoctorCommand(parent, io) {
463
466
  });
464
467
  }
465
468
  const defaultTuiRuntime = {
469
+ checkComms: checkCommsConnection,
466
470
  promptSecret,
467
471
  stdin: process.stdin,
468
472
  stdout: process.stdout,
@@ -645,6 +649,7 @@ function registerTuiCommand(parent, io) {
645
649
  const observerSession = createTuiObserverSession(resolve(options.cwd));
646
650
  let exitCode = 0;
647
651
  let connectionNotice;
652
+ let connectionCheck;
648
653
  try {
649
654
  for (;;) {
650
655
  const outcome = await loaded.startTui({
@@ -653,8 +658,21 @@ function registerTuiCommand(parent, io) {
653
658
  version: { cli: CLI_VERSION },
654
659
  capabilities: {
655
660
  comms: {
656
- read: () => readCommsSetup(resolve(options.cwd), connectionEnv()),
657
- save: () => saveCommsConnection(resolve(options.cwd))
661
+ read: async () => ({ ...await readCommsSetup(resolve(options.cwd), connectionEnv()), ...(connectionCheck ? { authentication: connectionCheck } : {}) }),
662
+ save: () => saveCommsConnection(resolve(options.cwd)),
663
+ check: async () => { connectionCheck = await tuiRuntime.checkComms({ cwd: resolve(options.cwd), env: connectionEnv(), online: true }); return connectionCheck; },
664
+ labs: async () => (await listLabManifests(resolve(options.cwd))).labs.map(lab => ({ title: lab.title ?? lab.id, path: lab.path })),
665
+ configure: (lab, apply, planToken) => configureCommsLab({ cwd: resolve(options.cwd), lab, connection: "agentmail", apply, ...(planToken ? { planToken } : {}) }),
666
+ recovery: () => inspectCommsRecovery({ cwd: resolve(options.cwd) }),
667
+ recover: async (runId, connectionName) => {
668
+ try {
669
+ const { connection, adapter } = await resolveReceivingConnection(resolve(options.cwd), connectionName, connectionEnv());
670
+ return await recoverCommsReceiving({ cwd: resolve(options.cwd), runId, connectionName, apiKeyEnv: connection.apiKeyEnv, adapter });
671
+ }
672
+ catch {
673
+ return { ok: false, message: "Could not recover email resources. Check the connection and retry." };
674
+ }
675
+ }
658
676
  },
659
677
  // One cache for the life of the surface: it refreshes on a cadence, and re-walking every
660
678
  // run tree each tick is the cost this index exists to avoid.
@@ -708,6 +726,13 @@ function registerTuiCommand(parent, io) {
708
726
  const saved = await saveCommsConnection(resolve(options.cwd));
709
727
  connectionNotice = saved.ok ? "Key stored. Project connection saved."
710
728
  : `Key stored for your user. ${saved.message}`;
729
+ stdout.write("Checking AgentMail authentication…\n");
730
+ connectionCheck = await tuiRuntime.checkComms({ cwd: resolve(options.cwd), env: connectionEnv(), online: true });
731
+ connectionNotice = saved.ok
732
+ ? connectionCheck.authenticated === true ? "Key stored. Authentication passed."
733
+ : connectionCheck.authenticated === false ? "Key stored. Authentication rejected; test it for details."
734
+ : "Key stored. Authentication unknown; test it to retry."
735
+ : `${connectionNotice} ${connectionCheck.message}`;
711
736
  }
712
737
  catch {
713
738
  connectionNotice = "Could not store the key. Use a single non-empty line and check key-store permissions.";
@@ -1162,7 +1187,7 @@ function registerRunsCommand(parent, io) {
1162
1187
  function registerCommsCommands(parent, io) {
1163
1188
  const comms = parent
1164
1189
  .command("comms")
1165
- .description("Email capture and communication connection setup.")
1190
+ .description("Local email capture, real receiving connections, checks and cleanup recovery.")
1166
1191
  .summary("Off-app comms surfaces.");
1167
1192
  comms.command("providers")
1168
1193
  .description("List installed communication provider capabilities. No network requests.")
@@ -1171,7 +1196,7 @@ function registerCommsCommands(parent, io) {
1171
1196
  const result = { schema: "humanish.comms-providers.v1", ok: true, providers: COMMS_PROVIDERS };
1172
1197
  writeResult(command, io, result, () => COMMS_PROVIDERS.map(provider => `${provider.label}: ${provider.limitation}\nKey: ${provider.keyEnv}\nSetup: ${provider.setupUrl}\n`).join("\n"));
1173
1198
  });
1174
- const connections = comms.command("connections").description("Manage project-local non-secret connection profiles. Setup does not enable email receiving.");
1199
+ const connections = comms.command("connections").description("Manage project-local non-secret connection profiles. A lab explicitly selects its receiving connection.");
1175
1200
  connections.command("list")
1176
1201
  .description("Show saved connections and local credential status; does not authenticate with a provider.")
1177
1202
  .option("--cwd <path>", "Target project directory.", ".")
@@ -1198,6 +1223,77 @@ function registerCommsCommands(parent, io) {
1198
1223
  writeResult(command, io, result, value => `${value.message}\n`);
1199
1224
  io.setExitCode(result.ok ? 0 : 2);
1200
1225
  });
1226
+ comms.command("check")
1227
+ .description("Check connection and credential presence; --online authenticates without creating inboxes.")
1228
+ .option("--cwd <path>", "Target project directory.", ".")
1229
+ .option("--connection <name>", "Saved connection name.", "agentmail")
1230
+ .option("--lab <path>", "Check the connection selected by this exact lab.")
1231
+ .option("--online", "Make a read-only provider authentication request.")
1232
+ .option("--env-file <path>", "Load credentials without printing values.")
1233
+ .option("--json", JSON_OPTION_DESCRIPTION)
1234
+ .action(async (options, command) => {
1235
+ if (!await applyEnvFileOption({ command, cwd: options.cwd, envFile: options.envFile, io }))
1236
+ return;
1237
+ let connection = options.connection;
1238
+ if (options.lab) {
1239
+ const lab = await resolveLabManifest(options.cwd, options.lab);
1240
+ if (!lab.ok || lab.config.comms?.email?.kind !== "real") {
1241
+ const result = { ok: false, message: "This lab does not select a real email connection." };
1242
+ writeResult(command, io, result, value => `${value.message}\n`);
1243
+ io.setExitCode(2);
1244
+ return;
1245
+ }
1246
+ connection = lab.config.comms.email.connection;
1247
+ }
1248
+ const result = await checkCommsConnection({ cwd: resolve(options.cwd), connection, env: process.env, online: options.online === true });
1249
+ writeResult(command, io, result, value => `${value.message}\n`);
1250
+ io.setExitCode(result.ok ? 0 : 2);
1251
+ });
1252
+ comms.command("configure")
1253
+ .description("Preview or save a local receiving-enabled copy of a supported lab. No provider requests.")
1254
+ .requiredOption("--lab <path>", "Exact source lab path or handle.")
1255
+ .option("--cwd <path>", "Target project directory.", ".")
1256
+ .option("--connection <name>", "Saved connection name.", "agentmail")
1257
+ .option("--apply", "Save the local copy; original lab remains unchanged.")
1258
+ .option("--plan-token <digest>", "Require the source and destination to match a previous preview.")
1259
+ .option("--json", JSON_OPTION_DESCRIPTION)
1260
+ .action(async (options, command) => {
1261
+ const result = await configureCommsLab({ ...options, cwd: resolve(options.cwd) });
1262
+ writeResult(command, io, result, value => `${value.message}\n`);
1263
+ io.setExitCode(result.ok ? 0 : 2);
1264
+ });
1265
+ comms.command("recover")
1266
+ .description("Inspect interrupted email leases; --apply deletes only privately recorded resources owned by this project and account.")
1267
+ .option("--cwd <path>", "Target project directory.", ".")
1268
+ .option("--run <id>", "One run to inspect or recover.")
1269
+ .option("--apply", "Recover the selected inactive run and verify mailbox deletion.")
1270
+ .option("--env-file <path>", "Load credentials without printing values.")
1271
+ .option("--json", JSON_OPTION_DESCRIPTION)
1272
+ .action(async (options, command) => {
1273
+ if (!await applyEnvFileOption({ command, cwd: options.cwd, envFile: options.envFile, io }))
1274
+ return;
1275
+ const cwd = resolve(options.cwd);
1276
+ try {
1277
+ const entries = (await inspectCommsRecovery({ cwd })).filter(entry => !options.run || entry.runId === options.run);
1278
+ if (!options.apply) {
1279
+ const result = { schema: "humanish.comms-recovery.v1", ok: true, entries };
1280
+ writeResult(command, io, result, value => value.entries.length ? value.entries.map(entry => `${entry.runId}: ${entry.unresolvedCount} unresolved; ${entry.activeOwner === null ? "unknown owner" : entry.activeOwner ? "active owner" : "inactive"}\n`).join("") : "No recoverable email leases in this project.\n");
1281
+ return;
1282
+ }
1283
+ if (!options.run || entries.length !== 1)
1284
+ throw new Error("selection");
1285
+ const entry = entries[0];
1286
+ const { connection, adapter } = await resolveReceivingConnection(cwd, entry.connectionName, process.env);
1287
+ const result = { schema: "humanish.comms-recovery-result.v1", ...await recoverCommsReceiving({ cwd, runId: options.run, connectionName: entry.connectionName, apiKeyEnv: connection.apiKeyEnv, adapter }) };
1288
+ writeResult(command, io, result, value => `${value.message}\n`);
1289
+ io.setExitCode(result.ok ? 0 : 2);
1290
+ }
1291
+ catch {
1292
+ const result = { schema: "humanish.comms-recovery-result.v1", ok: false, message: "Recovery could not complete. Select one recorded run with --run, check its connection, and retry. No unrecorded resources are eligible." };
1293
+ writeResult(command, io, result, value => `${value.message}\n`);
1294
+ io.setExitCode(2);
1295
+ }
1296
+ });
1201
1297
  comms
1202
1298
  .command("catch")
1203
1299
  .description("Run the email catch on THIS host so humanish can study an app it does not provision (#328). Your app posts its email sends here; the persona opens /inbox; humanish drains GET /deliveries and writes digest-only evidence. Point your lab's comms.email.external.catchBaseUrl at this server.")