@tinycloud/courier 0.2.0-beta.37 → 0.2.0-beta.38

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 +331 -12
  2. package/dist/a2a.d.ts +6 -0
  3. package/dist/a2a.js +10 -0
  4. package/dist/a2a.js.map +1 -1
  5. package/dist/approval.d.ts +6 -5
  6. package/dist/approval.js +7 -16
  7. package/dist/approval.js.map +1 -1
  8. package/dist/args.js +1 -1
  9. package/dist/args.js.map +1 -1
  10. package/dist/broker-config.d.ts +24 -0
  11. package/dist/broker-config.js +99 -0
  12. package/dist/broker-config.js.map +1 -0
  13. package/dist/broker.d.ts +77 -0
  14. package/dist/broker.js +253 -0
  15. package/dist/broker.js.map +1 -0
  16. package/dist/commands.js +5 -2
  17. package/dist/commands.js.map +1 -1
  18. package/dist/consumed.d.ts +10 -0
  19. package/dist/consumed.js +54 -0
  20. package/dist/consumed.js.map +1 -0
  21. package/dist/guard/binaries.d.ts +17 -0
  22. package/dist/guard/binaries.js +89 -0
  23. package/dist/guard/binaries.js.map +1 -0
  24. package/dist/guard/cleanhome.d.ts +27 -0
  25. package/dist/guard/cleanhome.js +111 -0
  26. package/dist/guard/cleanhome.js.map +1 -0
  27. package/dist/guard/command.d.ts +13 -0
  28. package/dist/guard/command.js +158 -0
  29. package/dist/guard/command.js.map +1 -0
  30. package/dist/guard/expansion.d.ts +10 -0
  31. package/dist/guard/expansion.js +74 -0
  32. package/dist/guard/expansion.js.map +1 -0
  33. package/dist/guard/hook.d.ts +38 -0
  34. package/dist/guard/hook.js +124 -0
  35. package/dist/guard/hook.js.map +1 -0
  36. package/dist/guard/install.d.ts +67 -0
  37. package/dist/guard/install.js +193 -0
  38. package/dist/guard/install.js.map +1 -0
  39. package/dist/guard/network.d.ts +7 -0
  40. package/dist/guard/network.js +78 -0
  41. package/dist/guard/network.js.map +1 -0
  42. package/dist/guard/normalize.d.ts +28 -0
  43. package/dist/guard/normalize.js +257 -0
  44. package/dist/guard/normalize.js.map +1 -0
  45. package/dist/guard/paseo.d.ts +30 -0
  46. package/dist/guard/paseo.js +148 -0
  47. package/dist/guard/paseo.js.map +1 -0
  48. package/dist/guard/paths.d.ts +31 -0
  49. package/dist/guard/paths.js +180 -0
  50. package/dist/guard/paths.js.map +1 -0
  51. package/dist/guard/policy.d.ts +65 -0
  52. package/dist/guard/policy.js +1179 -0
  53. package/dist/guard/policy.js.map +1 -0
  54. package/dist/guard/shell.d.ts +55 -0
  55. package/dist/guard/shell.js +727 -0
  56. package/dist/guard/shell.js.map +1 -0
  57. package/dist/index.d.ts +2 -0
  58. package/dist/index.js +2 -0
  59. package/dist/index.js.map +1 -1
  60. package/dist/keys.d.ts +4 -1
  61. package/dist/keys.js +7 -2
  62. package/dist/keys.js.map +1 -1
  63. package/dist/main.js +44 -4
  64. package/dist/main.js.map +1 -1
  65. package/dist/node.d.ts +1 -1
  66. package/dist/node.js +3 -3
  67. package/dist/node.js.map +1 -1
  68. package/dist/notify.d.ts +39 -0
  69. package/dist/notify.js +88 -0
  70. package/dist/notify.js.map +1 -0
  71. package/dist/pause.d.ts +26 -0
  72. package/dist/pause.js +99 -0
  73. package/dist/pause.js.map +1 -0
  74. package/dist/profile.d.ts +3 -3
  75. package/dist/profile.js +12 -12
  76. package/dist/profile.js.map +1 -1
  77. package/dist/wake.d.ts +17 -0
  78. package/dist/wake.js +74 -13
  79. package/dist/wake.js.map +1 -1
  80. package/dist/watch-cmd.d.ts +3 -0
  81. package/dist/watch-cmd.js +56 -2
  82. package/dist/watch-cmd.js.map +1 -1
  83. package/dist/watch.d.ts +70 -0
  84. package/dist/watch.js +292 -11
  85. package/dist/watch.js.map +1 -1
  86. package/package.json +1 -1
  87. package/skills/courier/SKILL.md +94 -8
package/dist/args.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"args.js","sourceRoot":"","sources":["../src/args.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAU3C,gFAAgF;AAChF,MAAM,UAAU,SAAS,CAAC,IAAc;IACtC,MAAM,UAAU,GAAa,EAAE,CAAC;IAChC,MAAM,KAAK,GAAyB,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,iBAAiB,EAAE,IAAI,EAAE,iBAAiB,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;IAC/P,MAAM,KAAK,GAAG,IAAI,GAAG,EAAoB,CAAC;IAC1C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACrC,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC;YACf,UAAU,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;YACtC,MAAM;QACR,CAAC;QACD,IAAI,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;YACvB,MAAM,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;YAC1B,MAAM,IAAI,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;YACpD,IAAI,EAAE,KAAK,CAAC,CAAC,EAAE,CAAC;gBACd,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;YACjE,CAAC;iBAAM,IAAI,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;gBAC/E,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC;YACxD,CAAC;iBAAM,CAAC;gBACN,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;YAC3D,CAAC;QACH,CAAC;aAAM,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC;YACtB,KAAK,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC;QAC9B,CAAC;aAAM,CAAC;YACN,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACrB,CAAC;IACH,CAAC;IACD,OAAO;QACL,UAAU;QACV,KAAK;QACL,GAAG,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC;QACxB,GAAG,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAE,CAAC,MAAM,GAAG,CAAC,CAAC;QACpD,GAAG,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE;KAC/B,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,IAAgB,EAAE,IAAY,EAAE,KAAa;IACvE,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IACzB,IAAI,CAAC,KAAK,SAAS,IAAI,CAAC,KAAK,MAAM;QAAE,MAAM,IAAI,YAAY,CAAC,OAAO,EAAE,KAAK,IAAI,iBAAiB,KAAK,EAAE,CAAC,CAAC;IACxG,OAAO,CAAC,CAAC;AACX,CAAC;AAED,MAAM,UAAU,KAAK,CAAC,IAAgB,EAAE,KAAe;IACrD,MAAM,OAAO,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IACjD,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC;QAAE,MAAM,IAAI,YAAY,CAAC,OAAO,EAAE,SAAS,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,0BAA0B,CAAC,CAAC;IACpI,OAAO,OAAO,CAAC,CAAC,CAAC,CAAC;AACpB,CAAC"}
1
+ {"version":3,"file":"args.js","sourceRoot":"","sources":["../src/args.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ import { type Profile } from './profile.js';
2
+ export declare const TEST_TOKEN: string;
3
+ declare const PINNED: readonly ["host", "openkeyHost", "spaceId", "ownerDid", "courierDid"];
4
+ export interface BrokerConfig {
5
+ v: 2;
6
+ courierHome: string;
7
+ profile: Pick<Profile, typeof PINNED[number]>;
8
+ ghBin: string;
9
+ ghIdentity: {
10
+ dev: number;
11
+ ino: number;
12
+ };
13
+ testToken?: string;
14
+ }
15
+ /** Production discovery uses the OS account database, never HOME/XDG or a Courier pointer. */
16
+ export declare function brokerRoot(testOwnerRoot?: string): string;
17
+ export declare function brokerFile(id: string, testOwnerRoot?: string): string;
18
+ /** The agent may select an opaque profile id, never a path or a host for the broker. */
19
+ export declare function currentProfileId(home?: string): string;
20
+ export declare function pinProfile(profile: Profile): BrokerConfig['profile'];
21
+ export declare function assertPinnedProfile(config: BrokerConfig, profile: Profile): void;
22
+ export declare function saveBrokerConfig(config: BrokerConfig, testOwnerRoot?: string): string;
23
+ export declare function loadBrokerConfig(id: string, testOwnerRoot?: string): BrokerConfig;
24
+ export {};
@@ -0,0 +1,99 @@
1
+ import fs from 'node:fs';
2
+ import os from 'node:os';
3
+ import path from 'node:path';
4
+ import { CourierError } from './errors.js';
5
+ import { loadProfile, profileDir } from './profile.js';
6
+ import { profileId, agentHome } from './guard/install.js';
7
+ import { realpathBest } from './guard/paths.js';
8
+ export const TEST_TOKEN = `ghp_${'d'.repeat(36)}`;
9
+ const ID = /^[a-f0-9]{24}$/;
10
+ const PINNED = ['host', 'openkeyHost', 'spaceId', 'ownerDid', 'courierDid'];
11
+ /** Production discovery uses the OS account database, never HOME/XDG or a Courier pointer. */
12
+ export function brokerRoot(testOwnerRoot) {
13
+ const owner = os.userInfo().homedir;
14
+ if (testOwnerRoot !== undefined) {
15
+ const root = realpathBest(testOwnerRoot);
16
+ const scratch = realpathBest(path.join(owner, 'scratch'));
17
+ if (!path.isAbsolute(testOwnerRoot) || root === realpathBest(owner) || !root.startsWith(`${scratch}${path.sep}`)) {
18
+ throw new CourierError('usage', '--test-owner-root must be a private directory under the real OS user\'s ~/scratch/, never the real owner root');
19
+ }
20
+ if (fs.existsSync(root)) {
21
+ const st = fs.statSync(root);
22
+ if (st.uid !== os.userInfo().uid || (st.mode & 0o077))
23
+ throw new CourierError('usage', '--test-owner-root must be owner-private (0700)');
24
+ }
25
+ const broker = realpathBest(path.join(root, '.config/courier-broker'));
26
+ if (!broker.startsWith(`${root}${path.sep}`))
27
+ throw new CourierError('usage', '--test-owner-root configuration must stay inside its private scratch root');
28
+ return broker;
29
+ }
30
+ return path.join(owner, '.config/courier-broker');
31
+ }
32
+ export function brokerFile(id, testOwnerRoot) {
33
+ if (!ID.test(id))
34
+ throw new CourierError('broker-not-configured', 'Invalid broker profile id');
35
+ return path.join(brokerRoot(testOwnerRoot), id, 'config.json');
36
+ }
37
+ /** The agent may select an opaque profile id, never a path or a host for the broker. */
38
+ export function currentProfileId(home = profileDir()) {
39
+ try {
40
+ const marker = JSON.parse(fs.readFileSync(path.join(path.dirname(home), '.courier-agent.json'), 'utf8'));
41
+ if (marker.v === 1 && ID.test(marker.profileId))
42
+ return marker.profileId;
43
+ }
44
+ catch { /* owner invocation: derive the id from its Courier directory */ }
45
+ return profileId(home);
46
+ }
47
+ export function pinProfile(profile) {
48
+ return Object.fromEntries(PINNED.map(key => [key, profile[key]]));
49
+ }
50
+ export function assertPinnedProfile(config, profile) {
51
+ for (const key of PINNED)
52
+ if (config.profile[key] !== profile[key])
53
+ throw new CourierError('broker-profile-mismatch', 'Courier profile differs from the owner-pinned broker profile; nothing was consumed');
54
+ }
55
+ export function saveBrokerConfig(config, testOwnerRoot) {
56
+ const file = brokerFile(profileId(config.courierHome), testOwnerRoot);
57
+ for (const root of [config.courierHome, agentHome(config.courierHome)]) {
58
+ if (realpathBest(file).startsWith(`${realpathBest(root)}${path.sep}`))
59
+ throw new CourierError('usage', 'Broker configuration must be outside Courier and the agent HOME');
60
+ }
61
+ const dir = path.dirname(file);
62
+ fs.mkdirSync(dir, { recursive: true, mode: 0o700 });
63
+ fs.chmodSync(dir, 0o700);
64
+ const tmp = `${file}.${process.pid}.tmp`;
65
+ try {
66
+ fs.writeFileSync(tmp, `${JSON.stringify(config, null, 2)}\n`, { mode: 0o600, flag: 'wx' });
67
+ fs.renameSync(tmp, file);
68
+ }
69
+ finally {
70
+ fs.rmSync(tmp, { force: true });
71
+ }
72
+ return file;
73
+ }
74
+ export function loadBrokerConfig(id, testOwnerRoot) {
75
+ const file = brokerFile(id, testOwnerRoot);
76
+ try {
77
+ for (const f of [path.dirname(file), file]) {
78
+ const st = fs.lstatSync(f);
79
+ if (st.isSymbolicLink() || st.uid !== os.userInfo().uid || (st.mode & 0o077))
80
+ throw Error('not owner-private');
81
+ }
82
+ const config = JSON.parse(fs.readFileSync(file, 'utf8'));
83
+ if (config.v !== 2 || !path.isAbsolute(config.courierHome) || profileId(config.courierHome) !== id || !path.isAbsolute(config.ghBin) || !config.ghIdentity || !config.profile?.host || !config.profile.spaceId)
84
+ throw Error('malformed');
85
+ if (testOwnerRoot !== undefined ? config.testToken !== TEST_TOKEN : config.testToken !== undefined)
86
+ throw Error('test configuration requires explicit private test owner root and fixed dummy token');
87
+ const st = fs.statSync(config.ghBin);
88
+ if (st.dev !== config.ghIdentity.dev || st.ino !== config.ghIdentity.ino)
89
+ throw Error('gh identity changed');
90
+ assertPinnedProfile(config, loadProfile(config.courierHome));
91
+ return config;
92
+ }
93
+ catch (error) {
94
+ if (error instanceof CourierError)
95
+ throw error;
96
+ throw new CourierError('broker-not-configured', 'Broker is not configured or its owner-private configuration is invalid; your owner runs courier broker set-token');
97
+ }
98
+ }
99
+ //# sourceMappingURL=broker-config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"broker-config.js","sourceRoot":"","sources":["../src/broker-config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,77 @@
1
+ import { type BrokerConfig } from './broker-config.js';
2
+ import { type KV } from './inbox.js';
3
+ import type { ParsedArgs } from './args.js';
4
+ /**
5
+ * The broker: `courier run-approved <requestId>` is the only way a woken agent's gated action runs. The agent says
6
+ * WHEN; the owner's approved request says WHAT. The command is built here from a fixed template out of the approved verb
7
+ * and canonical target only (nothing the agent types reaches it), run without a shell, with the owner's credential that
8
+ * the broker resolves from gh's own auth at run time, never from the agent's environment.
9
+ */
10
+ export declare const MAX_OUTPUT = 4000;
11
+ export interface BrokerCredential {
12
+ /** Absolute path of the `gh` binary, fixed when the credential was set (never looked up on the agent's PATH). */
13
+ ghBin: string;
14
+ token: string;
15
+ }
16
+ export declare const validToken: (token: string) => boolean;
17
+ /** Resolve gh's own credential at run time. No agent variables, shell, token argv or disk copy. */
18
+ export declare function loadBrokerCredential(config: BrokerConfig, exec?: Exec): Promise<BrokerCredential>;
19
+ export interface Template {
20
+ /** Read-only call that pins the state about to be merged. */
21
+ view: string[];
22
+ merge: (headSha: string) => string[];
23
+ display: string;
24
+ }
25
+ /**
26
+ * The fixed command for an approved (verb, target). Only `merge` of a pull request is brokered: publish and deploy run
27
+ * code from the agent's working tree with the owner's token, and `other`/`spend` have no safe fixed form, so their owner
28
+ * runs them. Throws `broker-unsupported` for those.
29
+ */
30
+ export declare function templateFor(verb: string, rawTarget: string): Template;
31
+ /** What the agent may see of a tool's output: secrets redacted, control characters gone, size capped. */
32
+ export declare function sanitizeOutput(text: string, secrets?: readonly string[]): string;
33
+ export interface ExecResult {
34
+ code: number | null;
35
+ stdout: string;
36
+ stderr: string;
37
+ }
38
+ export type Exec = (bin: string, args: string[], options: {
39
+ cwd: string;
40
+ env: NodeJS.ProcessEnv;
41
+ timeoutMs: number;
42
+ }) => Promise<ExecResult>;
43
+ /** argv exec, no shell, bounded output. */
44
+ export declare const execFileRunner: Exec;
45
+ /** The only environment `gh` gets: nothing of the agent's, a throwaway HOME and config dir, the token in `GH_TOKEN`. */
46
+ export declare function brokerEnv(credential: BrokerCredential, scratch: string): NodeJS.ProcessEnv;
47
+ export interface BrokerDeps {
48
+ kv: KV;
49
+ credential(): BrokerCredential | Promise<BrokerCredential>;
50
+ scratchRoot?: string;
51
+ exec: Exec;
52
+ now(): number;
53
+ }
54
+ export interface BrokerResult {
55
+ ok: boolean;
56
+ requestId: string;
57
+ verb: string;
58
+ target: string;
59
+ consumed: boolean;
60
+ headSha?: string;
61
+ command: string;
62
+ exitCode: number | null;
63
+ /** Untrusted text: what `gh` printed, redacted and capped. */
64
+ output: string;
65
+ note?: string;
66
+ }
67
+ /**
68
+ * Run the action the owner approved in request `id`. Order: verify (exact hash, decision, window, fields) → build the
69
+ * fixed command → check the credential and the PR's state (read-only, nothing consumed yet) → mark the approval used
70
+ * (create-only) → run. If the run fails after the marker is written the approval stays used: a retry needs a new request.
71
+ */
72
+ export declare function runApproved(id: string, deps: BrokerDeps): Promise<BrokerResult>;
73
+ export declare const runApprovedUsage: () => string;
74
+ export declare function cmdRunApproved(args: ParsedArgs): Promise<void>;
75
+ export declare const brokerUsage: () => string;
76
+ /** `courier broker …`: the owner installs the credential the broker merges with. Never an agent. */
77
+ export declare function cmdBroker(args: ParsedArgs): Promise<void>;
package/dist/broker.js ADDED
@@ -0,0 +1,253 @@
1
+ import { execFile } from 'node:child_process';
2
+ import fs from 'node:fs';
3
+ import os from 'node:os';
4
+ import { brokerFile, brokerRoot, currentProfileId, loadBrokerConfig, saveBrokerConfig, pinProfile, assertPinnedProfile, TEST_TOKEN } from './broker-config.js';
5
+ import { profileId } from './guard/install.js';
6
+ import path from 'node:path';
7
+ import { CourierError } from './errors.js';
8
+ import { k } from './keys.js';
9
+ import { getJson } from './store.js';
10
+ import { isConsumed, markConsumed } from './consumed.js';
11
+ import { verifyApproval } from './approval.js';
12
+ import { canonicalTarget } from './guard/target.js';
13
+ import { ULID } from './request.js';
14
+ import { loadProfile, profileDir } from './profile.js';
15
+ import { courierNode } from './node.js';
16
+ import { writeOut } from './inbox.js';
17
+ import { defer } from './defer.js';
18
+ import { cmd } from './program.js';
19
+ /**
20
+ * The broker: `courier run-approved <requestId>` is the only way a woken agent's gated action runs. The agent says
21
+ * WHEN; the owner's approved request says WHAT. The command is built here from a fixed template out of the approved verb
22
+ * and canonical target only (nothing the agent types reaches it), run without a shell, with the owner's credential that
23
+ * the broker resolves from gh's own auth at run time, never from the agent's environment.
24
+ */
25
+ export const MAX_OUTPUT = 4000;
26
+ const EXEC_TIMEOUT_MS = 120_000;
27
+ const TOKEN = /^(gh[pousr]_[A-Za-z0-9]{20,255}|github_pat_[A-Za-z0-9_]{20,255})$/;
28
+ export const validToken = (token) => TOKEN.test(token);
29
+ /** Resolve gh's own credential at run time. No agent variables, shell, token argv or disk copy. */
30
+ export async function loadBrokerCredential(config, exec = execFileRunner) {
31
+ if (config.testToken === TEST_TOKEN)
32
+ return { ghBin: config.ghBin, token: TEST_TOKEN };
33
+ const ownerHome = os.userInfo().homedir;
34
+ const result = await exec(config.ghBin, ['auth', 'token', '--hostname', 'github.com'], {
35
+ cwd: ownerHome, timeoutMs: 10_000,
36
+ env: { PATH: '/usr/bin:/bin', HOME: ownerHome, GH_CONFIG_DIR: path.join(ownerHome, '.config/gh'), GH_PROMPT_DISABLED: '1', GH_NO_UPDATE_NOTIFIER: '1', LANG: 'C' },
37
+ });
38
+ const token = result.stdout.trim();
39
+ if (result.code !== 0 || !validToken(token))
40
+ throw new CourierError('broker-not-configured', 'The owner must sign in to github.com with gh; no action was consumed');
41
+ return { ghBin: config.ghBin, token };
42
+ }
43
+ const REPO = /^[a-z0-9_][a-z0-9_.-]{0,99}\/[a-z0-9_][a-z0-9_.-]{0,99}$/;
44
+ /**
45
+ * The fixed command for an approved (verb, target). Only `merge` of a pull request is brokered: publish and deploy run
46
+ * code from the agent's working tree with the owner's token, and `other`/`spend` have no safe fixed form, so their owner
47
+ * runs them. Throws `broker-unsupported` for those.
48
+ */
49
+ export function templateFor(verb, rawTarget) {
50
+ const unsupported = (why) => new CourierError('broker-unsupported', `${why} Your owner runs this action; \`${cmd('run-approved')}\` only merges pull requests.`);
51
+ if (verb !== 'merge')
52
+ throw unsupported(`The broker does not run "${verb}" actions.`);
53
+ let target;
54
+ try {
55
+ target = canonicalTarget('merge', rawTarget);
56
+ }
57
+ catch {
58
+ throw unsupported(`"${rawTarget.slice(0, 60)}" is not a pull request target.`);
59
+ }
60
+ const m = /^([^#@]+)#([1-9][0-9]{0,8})$/.exec(target);
61
+ if (!m || !REPO.test(m[1]))
62
+ throw unsupported('A direct push or branch write is not brokered.');
63
+ const [, repo, number] = m;
64
+ return {
65
+ // `--repo=` as one argument and a digit-only number: nothing here can read as a flag or start a second command.
66
+ view: ['pr', 'view', number, `--repo=${repo}`, '--json', 'state,headRefOid,isDraft,baseRefName'],
67
+ merge: (sha) => ['pr', 'merge', number, `--repo=${repo}`, '--squash', `--match-head-commit=${sha}`],
68
+ display: `gh pr merge ${number} --repo ${repo} --squash`,
69
+ };
70
+ }
71
+ // ---------- output ----------
72
+ const TOKEN_LIKE = /(gh[pousr]_[A-Za-z0-9]{10,}|github_pat_[A-Za-z0-9_]{10,}|(?:Bearer|token|Basic)\s+[A-Za-z0-9._~+/=-]{16,}|Authorization:\s*\S+)/gi;
73
+ // eslint-disable-next-line no-control-regex
74
+ const CONTROL = /[\u0000-\u0008\u000b-\u001f\u007f-\u009f\u202a-\u202e\u2066-\u2069]/g;
75
+ /** What the agent may see of a tool's output: secrets redacted, control characters gone, size capped. */
76
+ export function sanitizeOutput(text, secrets = []) {
77
+ let out = text.replace(CONTROL, '');
78
+ for (const secret of secrets)
79
+ if (secret.length >= 8)
80
+ out = out.split(secret).join('[redacted]');
81
+ out = out.replace(TOKEN_LIKE, '[redacted]');
82
+ return out.length > MAX_OUTPUT ? `${out.slice(0, MAX_OUTPUT)}\n[output truncated at ${MAX_OUTPUT} characters]` : out;
83
+ }
84
+ /** argv exec, no shell, bounded output. */
85
+ export const execFileRunner = (bin, args, { cwd, env, timeoutMs }) => {
86
+ const { promise, resolve } = defer();
87
+ execFile(bin, args, { cwd, env, timeout: timeoutMs, maxBuffer: 1024 * 1024, windowsHide: true, shell: false }, (error, stdout, stderr) => {
88
+ const exit = error ? error.code : 0;
89
+ resolve({ code: typeof exit === 'number' ? exit : 1, stdout: String(stdout ?? ''), stderr: `${String(stderr ?? '')}${error && !stderr ? error.message : ''}` });
90
+ });
91
+ return promise;
92
+ };
93
+ /** The only environment `gh` gets: nothing of the agent's, a throwaway HOME and config dir, the token in `GH_TOKEN`. */
94
+ export function brokerEnv(credential, scratch) {
95
+ return {
96
+ PATH: `${path.dirname(credential.ghBin)}:/usr/bin:/bin`,
97
+ HOME: scratch,
98
+ GH_CONFIG_DIR: path.join(scratch, 'gh'),
99
+ GH_TOKEN: credential.token,
100
+ GH_PROMPT_DISABLED: '1',
101
+ GH_NO_UPDATE_NOTIFIER: '1',
102
+ GH_NO_EXTENSION_UPDATE_NOTIFIER: '1',
103
+ GIT_CONFIG_NOSYSTEM: '1',
104
+ GIT_CONFIG_GLOBAL: '/dev/null',
105
+ GIT_TERMINAL_PROMPT: '0',
106
+ NO_COLOR: '1',
107
+ LANG: 'C',
108
+ };
109
+ }
110
+ function fail(code, message) {
111
+ throw new CourierError(code, message);
112
+ }
113
+ /**
114
+ * Run the action the owner approved in request `id`. Order: verify (exact hash, decision, window, fields) → build the
115
+ * fixed command → check the credential and the PR's state (read-only, nothing consumed yet) → mark the approval used
116
+ * (create-only) → run. If the run fails after the marker is written the approval stays used: a retry needs a new request.
117
+ */
118
+ export async function runApproved(id, deps) {
119
+ if (!ULID.test(id))
120
+ fail('usage', `"${id.slice(0, 40)}" is not a request id (a ULID). Usage: ${cmd('run-approved <requestId>')}`);
121
+ const request = await getJson(deps.kv, k.request(id));
122
+ if (!request)
123
+ fail('approval-mismatch', `No request ${id} in me/requests/.`);
124
+ const approval = await getJson(deps.kv, k.approval(id));
125
+ if (!approval)
126
+ fail('approval-missing', `No approval for request ${id} yet. Your owner decides in the view or in your chat; stop and wait.`);
127
+ const verified = verifyApproval(id, request.value, approval.value, { now: deps.now() });
128
+ if (verified.decision !== 'approved')
129
+ fail('approval-denied', `Your owner denied request ${id}. Do not take the action.`);
130
+ const template = templateFor(verified.verb, verified.target);
131
+ const credential = await deps.credential();
132
+ if (await isConsumed(deps.kv, id))
133
+ fail('approval-used', `Approval ${id} was already used; an approval covers one action.`);
134
+ const scratchRoot = deps.scratchRoot ?? brokerRoot();
135
+ fs.mkdirSync(scratchRoot, { recursive: true, mode: 0o700 });
136
+ const scratch = fs.mkdtempSync(path.join(scratchRoot, 'run-'));
137
+ const env = brokerEnv(credential, scratch);
138
+ const run = (args) => deps.exec(credential.ghBin, args, { cwd: scratch, env, timeoutMs: EXEC_TIMEOUT_MS });
139
+ const clean = (text) => sanitizeOutput(text, [credential.token]);
140
+ const base = { requestId: id, verb: verified.verb, target: verified.target, command: template.display };
141
+ try {
142
+ // Read-only: check mergeability and approved pins before consuming anything.
143
+ const view = await run(template.view);
144
+ if (view.code !== 0)
145
+ fail('broker-view-failed', `Could not read the pull request (nothing was consumed): ${clean(view.stderr || view.stdout).slice(0, 300)}`);
146
+ let state = {};
147
+ try {
148
+ state = JSON.parse(view.stdout);
149
+ }
150
+ catch {
151
+ fail('broker-view-failed', 'Could not read the pull request state (nothing was consumed).');
152
+ }
153
+ if (state.state !== 'OPEN' || state.isDraft === true)
154
+ fail('broker-not-mergeable', `The pull request is ${state.isDraft === true ? 'a draft' : String(state.state).toLowerCase()}; nothing was consumed.`);
155
+ if (typeof state.headRefOid !== 'string' || !/^[0-9a-f]{40}$/.test(state.headRefOid))
156
+ fail('broker-view-failed', 'The pull request has no readable head commit (nothing was consumed).');
157
+ const sha = verified.headSha;
158
+ if (typeof sha !== 'string' || state.headRefOid !== sha || typeof state.baseRefName !== 'string' || !state.baseRefName || state.baseRefName !== verified.base) {
159
+ fail('broker-pin-mismatch', 'The pull request head or base differs from the approved request (nothing was consumed).');
160
+ }
161
+ await markConsumed(deps.kv, id, new Date(deps.now()));
162
+ const merged = await run(template.merge(sha));
163
+ const ok = merged.code === 0;
164
+ return {
165
+ ...base, ok, consumed: true, headSha: sha, exitCode: merged.code,
166
+ output: clean(`${merged.stdout}${merged.stderr ? `\n${merged.stderr}` : ''}`).trim(),
167
+ ...(ok ? {} : { note: 'The approval is used up. If the merge should still happen, file a new request.' }),
168
+ };
169
+ }
170
+ finally {
171
+ fs.rmSync(scratch, { recursive: true, force: true });
172
+ }
173
+ }
174
+ // ---------- commands ----------
175
+ export const runApprovedUsage = () => `Usage: ${cmd('run-approved <requestId>')}`;
176
+ export async function cmdRunApproved(args) {
177
+ const id = args.positional[0] ?? fail('usage', runApprovedUsage());
178
+ if (args.positional.length !== 1 || [...args.flags.keys()].some(k => k !== 'test-owner-root'))
179
+ fail('usage', runApprovedUsage());
180
+ const testOwnerRoot = args.get('test-owner-root');
181
+ const config = loadBrokerConfig(currentProfileId(), testOwnerRoot);
182
+ assertPinnedProfile(config, loadProfile());
183
+ const node = await courierNode(loadProfile(config.courierHome), config.courierHome);
184
+ const result = await runApproved(id, { kv: node.kv, credential: () => loadBrokerCredential(config), scratchRoot: path.dirname(brokerFile(currentProfileId(), testOwnerRoot)), exec: execFileRunner, now: () => Date.now() });
185
+ await writeOut(`${JSON.stringify(result, null, 2)}\n`);
186
+ if (!result.ok)
187
+ throw new CourierError('broker-run-failed', `The approved action ran and failed (exit ${result.exitCode}); the approval is used up.`);
188
+ }
189
+ export const brokerUsage = () => `Usage: ${cmd('broker set-token [--gh-bin <path>]')} (uses the owner's gh auth; humans only)\n` +
190
+ ` ${cmd('broker status')}\n ${cmd('broker clear')}`;
191
+ /** `courier broker …`: the owner installs the credential the broker merges with. Never an agent. */
192
+ export async function cmdBroker(args) {
193
+ const sub = args.positional[0];
194
+ const testOwnerRoot = args.get('test-owner-root');
195
+ const file = brokerFile(profileId(profileDir()), testOwnerRoot);
196
+ if (sub === 'set-token' && args.has('test-token') !== (testOwnerRoot !== undefined))
197
+ fail('usage', '--test-token and --test-owner-root must be used together (dummy tests only)');
198
+ if (sub === 'status') {
199
+ let configured = false;
200
+ let ghBin;
201
+ try {
202
+ ({ ghBin } = loadBrokerConfig(profileId(profileDir()), testOwnerRoot));
203
+ configured = true;
204
+ }
205
+ catch { /* not configured */ }
206
+ await writeOut(`${JSON.stringify({ configured, ...(ghBin ? { ghBin } : {}), file }, null, 2)}\n`);
207
+ return;
208
+ }
209
+ if (sub === 'clear') {
210
+ fs.rmSync(file, { force: true });
211
+ await writeOut('{"configured":false}\n');
212
+ return;
213
+ }
214
+ if (sub !== 'set-token')
215
+ fail('usage', brokerUsage());
216
+ let ghBin = args.get('gh-bin');
217
+ if (ghBin === 'true')
218
+ fail('usage', '--gh-bin needs a path.');
219
+ if (ghBin === undefined) {
220
+ for (const dir of (process.env.PATH ?? '').split(path.delimiter)) {
221
+ const candidate = path.join(dir || '.', 'gh');
222
+ try {
223
+ fs.accessSync(candidate, fs.constants.X_OK);
224
+ ghBin = fs.realpathSync(candidate);
225
+ break;
226
+ }
227
+ catch { /* next */ }
228
+ }
229
+ }
230
+ if (!ghBin || !path.isAbsolute(ghBin))
231
+ fail('usage', 'Could not find gh; pass --gh-bin <absolute path>.');
232
+ try {
233
+ fs.accessSync(ghBin, fs.constants.X_OK);
234
+ }
235
+ catch {
236
+ fail('usage', `${ghBin} is not an executable file.`);
237
+ }
238
+ const profile = loadProfile();
239
+ let testToken;
240
+ if (testOwnerRoot !== undefined) {
241
+ testToken = fs.readFileSync(0, 'utf8').trim();
242
+ if (testToken !== TEST_TOKEN)
243
+ fail('usage', 'Tests accept only the fixed dummy token fixture on stdin');
244
+ }
245
+ ghBin = fs.realpathSync(ghBin);
246
+ const st = fs.statSync(ghBin);
247
+ const config = { v: 2, courierHome: fs.realpathSync(profileDir()), profile: pinProfile(profile), ghBin, ghIdentity: { dev: st.dev, ino: st.ino }, ...(testToken ? { testToken } : {}) };
248
+ if (!testToken)
249
+ await loadBrokerCredential(config);
250
+ saveBrokerConfig(config, testOwnerRoot);
251
+ await writeOut(`${JSON.stringify({ configured: true, ghBin, file }, null, 2)}\n`);
252
+ }
253
+ //# sourceMappingURL=broker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"broker.js","sourceRoot":"","sources":["../src/broker.ts"],"names":[],"mappings":"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"}
package/dist/commands.js CHANGED
@@ -1,3 +1,4 @@
1
+ import { recentNotices } from './notify.js';
1
2
  import fs from 'node:fs';
2
3
  import os from 'node:os';
3
4
  import path from 'node:path';
@@ -453,10 +454,12 @@ export async function cmdInbox(args) {
453
454
  });
454
455
  const output = {
455
456
  notice: COUNTERPARTY_NOTICE,
457
+ notifications: recentNotices(profileDir()),
456
458
  items: collection.items.map((item) => ({ authority: 'counterparty', ...item })),
457
459
  errors: collection.errors,
458
460
  };
459
- await writeOut(args.has('json') ? JSON.stringify(output, null, 2) + '\n' : renderInboxText(collection.items));
461
+ const status = output.notifications.length ? `\nRecent notifications (delivery receipts may already be current):\n${output.notifications.map(n => `${n.title}: ${n.body}`).join('\n')}\n` : '';
462
+ await writeOut(args.has('json') ? JSON.stringify(output, null, 2) + '\n' : renderInboxText(collection.items) + status);
460
463
  for (const error of collection.errors)
461
464
  console.error(`warning: inbox ${error.peer}: ${error.message}`);
462
465
  if (!args.has('peek'))
@@ -637,7 +640,7 @@ export async function cmdRequest(args) {
637
640
  // `requestHash` is what the view's card shows as its fingerprint (first 8 hex digits) and `courier approval` prints in full.
638
641
  printJson({ ok: true, requestId: id, requestHash: hash, taskId, state: 'TASK_STATE_AUTH_REQUIRED' });
639
642
  }
640
- const requestUsage = () => `Usage: ${cmd('request <threadId> --peer <p> --task <id> --verb merge|deploy|publish|spend|other --target <what> --summary "…" --why "…" [--risk "…"] [--action "…"]')}\n${targetHelp()}\nMerge requires --head-sha <40 lowercase hex> and --base <branch> (refused for other verbs).\nRead the PR at request time: gh pr view N --repo owner/repo --json headRefOid,baseRefName\nPass headRefOid as --head-sha and baseRefName as --base; branch case is preserved.\nThe broker (separate PR) will merge only the approved commit and refuse a different base.`;
643
+ const requestUsage = () => `Usage: ${cmd('request <threadId> --peer <p> --task <id> --verb merge|deploy|publish|spend|other --target <what> --summary "…" --why "…" [--risk "…"] [--action "…"]')}\n${targetHelp()}\nMerge requires --head-sha <40 lowercase hex> and --base <branch> (refused for other verbs).\nRead the PR at request time: gh pr view N --repo owner/repo --json headRefOid,baseRefName\nPass headRefOid as --head-sha and baseRefName as --base; branch case is preserved.\nMerge requests include headSha and base in the approval hash.`;
641
644
  /** `courier request --help`: the usage line and every target form. */
642
645
  export const requestHelp = () => `${requestUsage()}\n`;
643
646
  // ---------- orders ----------