@relayflows/sdk 2.0.18 → 2.0.20

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 (82) hide show
  1. package/dist/authored-flow-error.d.ts +6 -1
  2. package/dist/authored-flow-error.d.ts.map +1 -1
  3. package/dist/authored-flow-error.js.map +1 -1
  4. package/dist/authored-flow-executor.d.ts.map +1 -1
  5. package/dist/authored-flow-executor.js +8 -0
  6. package/dist/authored-flow-executor.js.map +1 -1
  7. package/dist/cli/answer.d.ts.map +1 -1
  8. package/dist/cli/answer.js +2 -1
  9. package/dist/cli/answer.js.map +1 -1
  10. package/dist/cli/build.d.ts +9 -0
  11. package/dist/cli/build.d.ts.map +1 -1
  12. package/dist/cli/build.js +25 -6
  13. package/dist/cli/build.js.map +1 -1
  14. package/dist/cli/cloud-run.d.ts +7 -1
  15. package/dist/cli/cloud-run.d.ts.map +1 -1
  16. package/dist/cli/cloud-run.js +12 -14
  17. package/dist/cli/cloud-run.js.map +1 -1
  18. package/dist/cli/cloud-sync.d.ts +8 -1
  19. package/dist/cli/cloud-sync.d.ts.map +1 -1
  20. package/dist/cli/cloud-sync.js +79 -8
  21. package/dist/cli/cloud-sync.js.map +1 -1
  22. package/dist/cli/deploy.d.ts +6 -0
  23. package/dist/cli/deploy.d.ts.map +1 -1
  24. package/dist/cli/deploy.js +29 -4
  25. package/dist/cli/deploy.js.map +1 -1
  26. package/dist/cli/run.d.ts.map +1 -1
  27. package/dist/cli/run.js +2 -1
  28. package/dist/cli/run.js.map +1 -1
  29. package/dist/cli/serve-webhook.d.ts +7 -1
  30. package/dist/cli/serve-webhook.d.ts.map +1 -1
  31. package/dist/cli/serve-webhook.js +19 -9
  32. package/dist/cli/serve-webhook.js.map +1 -1
  33. package/dist/cli-commands.d.ts +398 -0
  34. package/dist/cli-commands.d.ts.map +1 -0
  35. package/dist/cli-commands.js +254 -0
  36. package/dist/cli-commands.js.map +1 -0
  37. package/dist/cli-watch.d.ts +3 -1
  38. package/dist/cli-watch.d.ts.map +1 -1
  39. package/dist/cli-watch.js +4 -10
  40. package/dist/cli-watch.js.map +1 -1
  41. package/dist/cli.d.ts +127 -1
  42. package/dist/cli.d.ts.map +1 -1
  43. package/dist/cli.js +81 -48
  44. package/dist/cli.js.map +1 -1
  45. package/dist/cloud-sync.d.ts +85 -2
  46. package/dist/cloud-sync.d.ts.map +1 -1
  47. package/dist/cloud-sync.js +123 -10
  48. package/dist/cloud-sync.js.map +1 -1
  49. package/dist/flow-requirements.d.ts +2 -2
  50. package/dist/flow-requirements.d.ts.map +1 -1
  51. package/dist/flow-requirements.js +182 -0
  52. package/dist/flow-requirements.js.map +1 -1
  53. package/dist/human-to.d.ts +45 -0
  54. package/dist/human-to.d.ts.map +1 -0
  55. package/dist/human-to.js +49 -0
  56. package/dist/human-to.js.map +1 -0
  57. package/dist/index.d.ts +2 -1
  58. package/dist/index.d.ts.map +1 -1
  59. package/dist/index.js +2 -1
  60. package/dist/index.js.map +1 -1
  61. package/dist/relay-cli.d.ts +50 -0
  62. package/dist/relay-cli.d.ts.map +1 -0
  63. package/dist/relay-cli.js +64 -0
  64. package/dist/relay-cli.js.map +1 -0
  65. package/package.json +7 -2
  66. package/src/authored-flow-error.ts +5 -0
  67. package/src/authored-flow-executor.ts +8 -0
  68. package/src/cli/answer.ts +2 -1
  69. package/src/cli/build.ts +20 -6
  70. package/src/cli/cloud-run.ts +11 -12
  71. package/src/cli/cloud-sync.ts +85 -8
  72. package/src/cli/deploy.ts +27 -5
  73. package/src/cli/run.ts +2 -1
  74. package/src/cli/serve-webhook.ts +15 -8
  75. package/src/cli-commands.ts +339 -0
  76. package/src/cli-watch.ts +8 -9
  77. package/src/cli.ts +103 -44
  78. package/src/cloud-sync.ts +164 -11
  79. package/src/flow-requirements.ts +143 -2
  80. package/src/human-to.ts +71 -0
  81. package/src/index.ts +5 -2
  82. package/src/relay-cli.ts +117 -0
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Who an `f.human(question, { to })` question is for, parsed from the
3
+ * author's `to` string. This is the delivery contract Cloud reads (the local
4
+ * kit records it, Cloud delivers it), so the forms are fixed here and
5
+ * documented in docs/SURFACE.md §5 Human gates:
6
+ *
7
+ * "slack:#eng" → post in the Slack channel; anyone there may answer
8
+ * "slack:@khaliq" → DM the Slack user; only they may answer
9
+ * "github:@khaliq" → comment on the triggering issue / pull request,
10
+ * mentioning the handle; only they may answer
11
+ * "khaliq" → the deploy's approver, on whichever channel the run
12
+ * was triggered from (Cloud resolves; the local kit
13
+ * only records it)
14
+ *
15
+ * Anything else — an unknown provider (`email:x`), a provider with no target
16
+ * (`slack:`), a GitHub channel (`github:#eng`), a target with whitespace or
17
+ * other characters no handle carries — is refused as `human_to_invalid`
18
+ * rather than turned into a delivery target that would silently reach no one.
19
+ */
20
+ export type HumanRecipient = {
21
+ readonly provider: 'slack';
22
+ readonly kind: 'channel' | 'user';
23
+ readonly target: string;
24
+ } | {
25
+ readonly provider: 'github';
26
+ readonly kind: 'user';
27
+ readonly target: string;
28
+ } | {
29
+ readonly provider: 'approver';
30
+ readonly kind: 'user';
31
+ readonly target: string;
32
+ };
33
+ export type HumanRecipientParse = {
34
+ readonly ok: true;
35
+ readonly recipient: HumanRecipient;
36
+ } | {
37
+ readonly ok: false;
38
+ readonly reason: string;
39
+ };
40
+ export declare function parseHumanTo(to: string): HumanRecipientParse;
41
+ /** The parsed recipient of a `to` already accepted by `f.human` (`parseHumanTo` ok). */
42
+ export declare function parseHumanRecipient(to: string): HumanRecipient;
43
+ /** The Cloud integration a recipient needs connected: none for the approver, none for a malformed `to`. */
44
+ export declare function humanRecipientProvider(to: string): 'slack' | 'github' | undefined;
45
+ //# sourceMappingURL=human-to.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"human-to.d.ts","sourceRoot":"","sources":["../src/human-to.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,MAAM,cAAc,GACtB;IAAE,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,SAAS,GAAG,MAAM,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAC1F;IAAE,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAC/E;IAAE,QAAQ,CAAC,QAAQ,EAAE,UAAU,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAEtF,MAAM,MAAM,mBAAmB,GAC3B;IAAE,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC;IAAC,QAAQ,CAAC,SAAS,EAAE,cAAc,CAAA;CAAE,GACzD;IAAE,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAMpD,wBAAgB,YAAY,CAAC,EAAE,EAAE,MAAM,GAAG,mBAAmB,CAwB5D;AAED,wFAAwF;AACxF,wBAAgB,mBAAmB,CAAC,EAAE,EAAE,MAAM,GAAG,cAAc,CAI9D;AAED,2GAA2G;AAC3G,wBAAgB,sBAAsB,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,GAAG,QAAQ,GAAG,SAAS,CAIjF"}
@@ -0,0 +1,49 @@
1
+ /** A Slack channel name, or a Slack / GitHub / approver handle: one word, no spaces or quotes. */
2
+ const TARGET = /^[A-Za-z0-9][A-Za-z0-9._-]{0,99}$/u;
3
+ const PROVIDER_FORM = /^([A-Za-z][A-Za-z0-9_-]*)\s*:(.*)$/su;
4
+ export function parseHumanTo(to) {
5
+ const trimmed = to.trim();
6
+ if (trimmed === '')
7
+ return { ok: false, reason: 'to is empty' };
8
+ const match = PROVIDER_FORM.exec(trimmed);
9
+ if (match === null) {
10
+ const target = trimmed.replace(/^@/u, '');
11
+ if (!TARGET.test(target))
12
+ return { ok: false, reason: `"${trimmed}" is not a handle (one word: letters, digits, . _ -)` };
13
+ return { ok: true, recipient: { provider: 'approver', kind: 'user', target } };
14
+ }
15
+ const provider = match[1].toLowerCase();
16
+ const rest = match[2].trim();
17
+ if (provider !== 'slack' && provider !== 'github') {
18
+ return { ok: false, reason: `"${provider}:" is not a delivery provider; use "slack:#channel", "slack:@user", "github:@user" or a bare approver handle` };
19
+ }
20
+ if (rest === '')
21
+ return { ok: false, reason: `"${provider}:" names no ${provider === 'slack' ? 'channel or user' : 'user'}` };
22
+ if (rest.startsWith('#')) {
23
+ if (provider === 'github')
24
+ return { ok: false, reason: `"${trimmed}": GitHub has no channels; use "github:@user"` };
25
+ const target = rest.slice(1);
26
+ if (!TARGET.test(target))
27
+ return { ok: false, reason: `"${trimmed}" is not a Slack channel name` };
28
+ return { ok: true, recipient: { provider: 'slack', kind: 'channel', target } };
29
+ }
30
+ const target = rest.replace(/^@/u, '');
31
+ if (!TARGET.test(target))
32
+ return { ok: false, reason: `"${trimmed}" is not a ${provider === 'slack' ? 'Slack' : 'GitHub'} handle` };
33
+ return { ok: true, recipient: { provider, kind: 'user', target } };
34
+ }
35
+ /** The parsed recipient of a `to` already accepted by `f.human` (`parseHumanTo` ok). */
36
+ export function parseHumanRecipient(to) {
37
+ const parsed = parseHumanTo(to);
38
+ if (!parsed.ok)
39
+ throw new Error(`f.human to ${parsed.reason}`);
40
+ return parsed.recipient;
41
+ }
42
+ /** The Cloud integration a recipient needs connected: none for the approver, none for a malformed `to`. */
43
+ export function humanRecipientProvider(to) {
44
+ const parsed = parseHumanTo(to);
45
+ if (!parsed.ok || parsed.recipient.provider === 'approver')
46
+ return undefined;
47
+ return parsed.recipient.provider;
48
+ }
49
+ //# sourceMappingURL=human-to.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"human-to.js","sourceRoot":"","sources":["../src/human-to.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -5,12 +5,13 @@ export type { StepSpend } from './protocol.js';
5
5
  export { SPEC_SCHEMA_VERSION } from './spec.js';
6
6
  export { CloudFlowError, type CloudConnectionOptions } from './cloud-http.js';
7
7
  export { runInCloud, getCloudFlowRun, waitForCloudFlowRun, type CloudFlowSource, type RunInCloudOptions, type CloudRunReceipt, type CloudRunState, } from './cloud-run.js';
8
- export { downloadCloudPatch, applyCloudPatch, packWorkingTree, patchedPaths, MAX_SYNC_BYTES, type CloudPatch, type PackedTree, } from './cloud-sync.js';
8
+ export { downloadCloudPatch, downloadCloudPatchSet, applyCloudPatch, packWorkingTree, patchedPaths, excludedPatchPaths, CLOUD_SYNC_PATCH_EXCLUDES, MAX_SYNC_BYTES, type CloudPatch, type CloudPathPatch, type CloudPatchSet, type PackedTree, type ApplyCloudPatchOptions, type AppliedCloudPatch, } from './cloud-sync.js';
9
9
  export { scheduleInCloud, listCloudSchedules, unscheduleInCloud, everyToCron, declaredScheduleCron, type ScheduleInCloudInput, type CloudSchedule, } from './cloud-schedule.js';
10
10
  export { prepareCloudSubmission, cloudSubmissionBody, type CloudSubmission } from './cloud-run.js';
11
11
  export { deployToCloud, listCloudDeployments, undeployFromCloud, parseRepository, parseTriggerSource, FLOW_TRIGGER_PROVIDERS, type DeployToCloudInput, type CloudDeployment, type CloudDeploymentSummary, type FlowTriggerSource, type FlowTriggerProvider, } from './cloud-deploy.js';
12
12
  export { ensureIntegrationsConnected, integrationConnected, providerLabel, type ConnectPrompt, type EnsureConnectionsOptions, type ConnectionsOutcome, } from './cloud-connect.js';
13
13
  export { flowRequirements, describeFlowRequirements, harnessFromCli, FLOW_HARNESSES, type FlowRequirements, type FlowRequirementsContext, type FlowIntegrationRequirement, type FlowHarnessRequirement, type FlowHarness, } from './flow-requirements.js';
14
+ export { parseHumanTo, parseHumanRecipient, humanRecipientProvider, type HumanRecipient, type HumanRecipientParse } from './human-to.js';
14
15
  export { canonicalize, specHash } from './canonical.js';
15
16
  export { compileAndHash, compileSpec, compileYaml, compileYamlToCanonicalJson, kernelToAuthoring, toKernelSpec, CompileError, } from './compile.js';
16
17
  export { validateSpec, type ValidationResult } from './validate.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -5,12 +5,13 @@ export { MODEL_PRICING } from './model-pricing.js';
5
5
  export { SPEC_SCHEMA_VERSION } from './spec.js';
6
6
  export { CloudFlowError } from './cloud-http.js';
7
7
  export { runInCloud, getCloudFlowRun, waitForCloudFlowRun, } from './cloud-run.js';
8
- export { downloadCloudPatch, applyCloudPatch, packWorkingTree, patchedPaths, MAX_SYNC_BYTES, } from './cloud-sync.js';
8
+ export { downloadCloudPatch, downloadCloudPatchSet, applyCloudPatch, packWorkingTree, patchedPaths, excludedPatchPaths, CLOUD_SYNC_PATCH_EXCLUDES, MAX_SYNC_BYTES, } from './cloud-sync.js';
9
9
  export { scheduleInCloud, listCloudSchedules, unscheduleInCloud, everyToCron, declaredScheduleCron, } from './cloud-schedule.js';
10
10
  export { prepareCloudSubmission, cloudSubmissionBody } from './cloud-run.js';
11
11
  export { deployToCloud, listCloudDeployments, undeployFromCloud, parseRepository, parseTriggerSource, FLOW_TRIGGER_PROVIDERS, } from './cloud-deploy.js';
12
12
  export { ensureIntegrationsConnected, integrationConnected, providerLabel, } from './cloud-connect.js';
13
13
  export { flowRequirements, describeFlowRequirements, harnessFromCli, FLOW_HARNESSES, } from './flow-requirements.js';
14
+ export { parseHumanTo, parseHumanRecipient, humanRecipientProvider } from './human-to.js';
14
15
  export { canonicalize, specHash } from './canonical.js';
15
16
  export { compileAndHash, compileSpec, compileYaml, compileYamlToCanonicalJson, kernelToAuthoring, toKernelSpec, CompileError, } from './compile.js';
16
17
  export { validateSpec } from './validate.js';
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,mEAAmE;AACnE,yEAAyE;AACzE,yBAAyB;AAqDzB,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAGnD,OAAO,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAC;AAEhD,OAAO,EAAE,cAAc,EAA+B,MAAM,iBAAiB,CAAC;AAC9E,OAAO,EACL,UAAU,EAAE,eAAe,EAAE,mBAAmB,GAEjD,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACL,kBAAkB,EAAE,eAAe,EAAE,eAAe,EAAE,YAAY,EAAE,cAAc,GAEnF,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,eAAe,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,WAAW,EAAE,oBAAoB,GAE1F,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,sBAAsB,EAAE,mBAAmB,EAAwB,MAAM,gBAAgB,CAAC;AACnG,OAAO,EACL,aAAa,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,eAAe,EAAE,kBAAkB,EAAE,sBAAsB,GAEpH,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,2BAA2B,EAAE,oBAAoB,EAAE,aAAa,GAEjE,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,gBAAgB,EAAE,wBAAwB,EAAE,cAAc,EAAE,cAAc,GAE3E,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AACxD,OAAO,EACL,cAAc,EACd,WAAW,EACX,WAAW,EACX,0BAA0B,EAC1B,iBAAiB,EACjB,YAAY,EACZ,YAAY,GACb,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,YAAY,EAAyB,MAAM,eAAe,CAAC;AAEpE,OAAO,EACL,yBAAyB,GAG1B,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,SAAS,EACT,gBAAgB,GAUjB,MAAM,gBAAgB,CAAC;AAMxB,OAAO,EACL,mBAAmB,EACnB,yBAAyB,EACzB,uBAAuB,EACvB,uBAAuB,EACvB,kBAAkB,GAInB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,MAAM,EAA2D,MAAM,UAAU,CAAC;AA6C3F,OAAO,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAEvE,OAAO,EAAE,aAAa,EAA6B,MAAM,qBAAqB,CAAC;AAC/E,OAAO,EAAE,WAAW,EAA2B,MAAM,aAAa,CAAC;AAEnE,OAAO,EACL,mBAAmB,EACnB,gBAAgB,GAIjB,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EACL,kBAAkB,GAInB,MAAM,4BAA4B,CAAC;AAEpC,OAAO,EACL,uBAAuB,GAIxB,MAAM,6BAA6B,CAAC;AAErC,iFAAiF;AACjF,OAAO,EACL,kBAAkB,EAClB,qBAAqB,EACrB,kBAAkB,GAInB,MAAM,gBAAgB,CAAC;AAExB,uEAAuE;AACvE,yEAAyE;AACzE,4EAA4E;AAC5E,2BAA2B;AAC3B,OAAO,EACL,iBAAiB,GAGlB,MAAM,yBAAyB,CAAC;AAEjC,2EAA2E;AAC3E,6EAA6E;AAC7E,oEAAoE;AACpE,gCAAgC;AAChC,OAAO,EACL,YAAY,EACZ,cAAc,EACd,aAAa,EACb,OAAO,EACP,aAAa,EACb,oBAAoB,EACpB,wBAAwB,EACxB,eAAe,GAMhB,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EAAE,UAAU,EAA4C,MAAM,kBAAkB,CAAC;AAExF,OAAO,EAAE,cAAc,EAAsB,MAAM,eAAe,CAAC;AACnE,OAAO,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAC3D,OAAO,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,iBAAiB,EAAyB,MAAM,uBAAuB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,mEAAmE;AACnE,yEAAyE;AACzE,yBAAyB;AAqDzB,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAGnD,OAAO,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAC;AAEhD,OAAO,EAAE,cAAc,EAA+B,MAAM,iBAAiB,CAAC;AAC9E,OAAO,EACL,UAAU,EAAE,eAAe,EAAE,mBAAmB,GAEjD,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACL,kBAAkB,EAAE,qBAAqB,EAAE,eAAe,EAAE,eAAe,EAAE,YAAY,EACzF,kBAAkB,EAAE,yBAAyB,EAAE,cAAc,GAG9D,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,eAAe,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,WAAW,EAAE,oBAAoB,GAE1F,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,sBAAsB,EAAE,mBAAmB,EAAwB,MAAM,gBAAgB,CAAC;AACnG,OAAO,EACL,aAAa,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,eAAe,EAAE,kBAAkB,EAAE,sBAAsB,GAEpH,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,2BAA2B,EAAE,oBAAoB,EAAE,aAAa,GAEjE,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,gBAAgB,EAAE,wBAAwB,EAAE,cAAc,EAAE,cAAc,GAE3E,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,YAAY,EAAE,mBAAmB,EAAE,sBAAsB,EAAiD,MAAM,eAAe,CAAC;AAEzI,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AACxD,OAAO,EACL,cAAc,EACd,WAAW,EACX,WAAW,EACX,0BAA0B,EAC1B,iBAAiB,EACjB,YAAY,EACZ,YAAY,GACb,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,YAAY,EAAyB,MAAM,eAAe,CAAC;AAEpE,OAAO,EACL,yBAAyB,GAG1B,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,SAAS,EACT,gBAAgB,GAUjB,MAAM,gBAAgB,CAAC;AAMxB,OAAO,EACL,mBAAmB,EACnB,yBAAyB,EACzB,uBAAuB,EACvB,uBAAuB,EACvB,kBAAkB,GAInB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,MAAM,EAA2D,MAAM,UAAU,CAAC;AA6C3F,OAAO,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAEvE,OAAO,EAAE,aAAa,EAA6B,MAAM,qBAAqB,CAAC;AAC/E,OAAO,EAAE,WAAW,EAA2B,MAAM,aAAa,CAAC;AAEnE,OAAO,EACL,mBAAmB,EACnB,gBAAgB,GAIjB,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EACL,kBAAkB,GAInB,MAAM,4BAA4B,CAAC;AAEpC,OAAO,EACL,uBAAuB,GAIxB,MAAM,6BAA6B,CAAC;AAErC,iFAAiF;AACjF,OAAO,EACL,kBAAkB,EAClB,qBAAqB,EACrB,kBAAkB,GAInB,MAAM,gBAAgB,CAAC;AAExB,uEAAuE;AACvE,yEAAyE;AACzE,4EAA4E;AAC5E,2BAA2B;AAC3B,OAAO,EACL,iBAAiB,GAGlB,MAAM,yBAAyB,CAAC;AAEjC,2EAA2E;AAC3E,6EAA6E;AAC7E,oEAAoE;AACpE,gCAAgC;AAChC,OAAO,EACL,YAAY,EACZ,cAAc,EACd,aAAa,EACb,OAAO,EACP,aAAa,EACb,oBAAoB,EACpB,wBAAwB,EACxB,eAAe,GAMhB,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EAAE,UAAU,EAA4C,MAAM,kBAAkB,CAAC;AAExF,OAAO,EAAE,cAAc,EAAsB,MAAM,eAAe,CAAC;AACnE,OAAO,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAC3D,OAAO,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,iBAAiB,EAAyB,MAAM,uBAAuB,CAAC"}
@@ -0,0 +1,50 @@
1
+ import { type CliCommandSpec } from './cli-commands.js';
2
+ /**
3
+ * The `@relayflows/sdk/relay-cli` entrypoint: a mountable CLI surface.
4
+ *
5
+ * `agent-relay` mounts this as `agent-relay flows`. The surface is a thin
6
+ * projection over the CLI this package already ships -- `commands` comes from
7
+ * the same `CLI_VERBS` table `parseArgs` dispatches on, and `run` delegates
8
+ * straight to `runCli`. No command is reimplemented here, and
9
+ * `packages/relayflows/bin/flows.js` keeps calling `runCli` on the same path.
10
+ *
11
+ * Structurally typed against `@agent-relay/cli-surface` without importing it,
12
+ * so `dist/relay-cli.d.ts` has no dependency on the contract package and this
13
+ * package gains no runtime dependency on relay. `tests/relay-cli-surface.test.ts`
14
+ * asserts the assignability and runs the contract's own conformance checks.
15
+ */
16
+ /** Host-supplied output sink. Mirrors `RelayCliIo`. */
17
+ export interface RelayCliIo {
18
+ stdout(chunk: string): void;
19
+ stderr(chunk: string): void;
20
+ }
21
+ /** A mountable product CLI. Mirrors `RelayCliSurface`. */
22
+ export interface RelayCliSurface {
23
+ id: string;
24
+ version: string;
25
+ contract: 1;
26
+ commands: readonly CliCommandSpec[];
27
+ run(argv: readonly string[], io: RelayCliIo): Promise<number>;
28
+ }
29
+ /** Options for {@link createRelayCliSurface}. */
30
+ export interface CreateRelayCliSurfaceOptions {
31
+ /**
32
+ * Cancellation for the long-running verbs, owned by the host.
33
+ *
34
+ * A surface must install no global signal handlers, so one is always passed
35
+ * to `runCli` -- a never-aborting signal when the host supplies none. Pass a
36
+ * real one to get graceful cancellation (for example, the
37
+ * "Stopped observing; the hosted run has not been cancelled" path on
38
+ * `run --cloud --wait`) instead of the host's SIGINT killing the process.
39
+ */
40
+ signal?: AbortSignal;
41
+ }
42
+ /**
43
+ * Build the relayflows CLI surface.
44
+ *
45
+ * @param options - Host-supplied cancellation.
46
+ * @returns A surface whose `run` resolves to an exit code, writes only through
47
+ * the supplied io, and installs no process signal handlers.
48
+ */
49
+ export declare function createRelayCliSurface(options?: CreateRelayCliSurfaceOptions): RelayCliSurface;
50
+ //# sourceMappingURL=relay-cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"relay-cli.d.ts","sourceRoot":"","sources":["../src/relay-cli.ts"],"names":[],"mappings":"AAGA,OAAO,EAA6B,KAAK,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAEnF;;;;;;;;;;;;;GAaG;AAEH,uDAAuD;AACvD,MAAM,WAAW,UAAU;IACzB,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7B;AAED,0DAA0D;AAC1D,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,CAAC,CAAC;IACZ,QAAQ,EAAE,SAAS,cAAc,EAAE,CAAC;IACpC,GAAG,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,EAAE,EAAE,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;CAC/D;AAED,iDAAiD;AACjD,MAAM,WAAW,4BAA4B;IAC3C;;;;;;;;OAQG;IACH,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AAiCD;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CACnC,OAAO,GAAE,4BAAiC,GACzC,eAAe,CA2BjB"}
@@ -0,0 +1,64 @@
1
+ import { readFileSync } from 'node:fs';
2
+ import { runCli } from './cli.js';
3
+ import { CLI_VERBS, CLI_VERB_NAMES } from './cli-commands.js';
4
+ /** Exit code for an argv the surface cannot route, per the contract. */
5
+ const EXIT_UNKNOWN_COMMAND = 2;
6
+ /** Drop `variants` -- the routing detail the host has no use for. */
7
+ function toCommandSpec(verb) {
8
+ const { variants: _variants, ...spec } = verb;
9
+ return spec;
10
+ }
11
+ /**
12
+ * Read this package's version from its own manifest.
13
+ *
14
+ * Resolved from `import.meta.url` rather than imported, because `package.json`
15
+ * sits outside `rootDir` and a hardcoded literal would silently go stale at the
16
+ * next release. `src/` and `dist/` are both one level below the manifest, so
17
+ * the same relative path is correct before and after a build.
18
+ */
19
+ function packageVersion() {
20
+ try {
21
+ const manifest = JSON.parse(readFileSync(new URL('../package.json', import.meta.url), 'utf8'));
22
+ const version = manifest.version;
23
+ return typeof version === 'string' && version.length > 0 ? version : '0.0.0';
24
+ }
25
+ catch {
26
+ // A surface that cannot read its own manifest is still perfectly runnable;
27
+ // refusing to mount over a cosmetic field would be the worse failure.
28
+ return '0.0.0';
29
+ }
30
+ }
31
+ /**
32
+ * Build the relayflows CLI surface.
33
+ *
34
+ * @param options - Host-supplied cancellation.
35
+ * @returns A surface whose `run` resolves to an exit code, writes only through
36
+ * the supplied io, and installs no process signal handlers.
37
+ */
38
+ export function createRelayCliSurface(options = {}) {
39
+ return {
40
+ id: 'relayflows',
41
+ version: packageVersion(),
42
+ contract: 1,
43
+ commands: CLI_VERBS.map(toCommandSpec),
44
+ async run(argv, io) {
45
+ const verb = argv[0];
46
+ // `runCli` would refuse this too, but with the full usage block. Naming
47
+ // the offending token is the more useful answer when the host has just
48
+ // routed `agent-relay flows <typo>` here.
49
+ if (verb !== undefined && !verb.startsWith('-') && !CLI_VERB_NAMES.has(verb)) {
50
+ io.stderr(`error: '${verb}' is not a command of relayflows\n`);
51
+ io.stderr("Run 'agent-relay flows --help' for the available commands.\n");
52
+ return EXIT_UNKNOWN_COMMAND;
53
+ }
54
+ return runCli(argv,
55
+ // `CliIo` is line-oriented and the contract's io is chunk-oriented, so
56
+ // the terminator is added here rather than by every call site.
57
+ { stdout: (line) => io.stdout(`${line}\n`), stderr: (line) => io.stderr(`${line}\n`) },
58
+ // Always pass a signal: that is what keeps `runCli` from installing the
59
+ // SIGINT/SIGTERM handlers the standalone binary still relies on.
60
+ { signal: options.signal ?? new AbortController().signal });
61
+ },
62
+ };
63
+ }
64
+ //# sourceMappingURL=relay-cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"relay-cli.js","sourceRoot":"","sources":["../src/relay-cli.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAEvC,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAClC,OAAO,EAAE,SAAS,EAAE,cAAc,EAAuB,MAAM,mBAAmB,CAAC;AA8CnF,wEAAwE;AACxE,MAAM,oBAAoB,GAAG,CAAC,CAAC;AAE/B,qEAAqE;AACrE,SAAS,aAAa,CAAC,IAA6C;IAClE,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,GAAG,IAAI,EAAE,GAAG,IAAI,CAAC;IAC9C,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;;;;GAOG;AACH,SAAS,cAAc;IACrB,IAAI,CAAC;QACH,MAAM,QAAQ,GAAY,IAAI,CAAC,KAAK,CAClC,YAAY,CAAC,IAAI,GAAG,CAAC,iBAAiB,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,CAClE,CAAC;QACF,MAAM,OAAO,GAAI,QAAkC,CAAC,OAAO,CAAC;QAC5D,OAAO,OAAO,OAAO,KAAK,QAAQ,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC;IAC/E,CAAC;IAAC,MAAM,CAAC;QACP,2EAA2E;QAC3E,sEAAsE;QACtE,OAAO,OAAO,CAAC;IACjB,CAAC;AACH,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,qBAAqB,CACnC,UAAwC,EAAE;IAE1C,OAAO;QACL,EAAE,EAAE,YAAY;QAChB,OAAO,EAAE,cAAc,EAAE;QACzB,QAAQ,EAAE,CAAC;QACX,QAAQ,EAAE,SAAS,CAAC,GAAG,CAAC,aAAa,CAAC;QACtC,KAAK,CAAC,GAAG,CAAC,IAAuB,EAAE,EAAc;YAC/C,MAAM,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;YACrB,wEAAwE;YACxE,uEAAuE;YACvE,0CAA0C;YAC1C,IAAI,IAAI,KAAK,SAAS,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;gBAC7E,EAAE,CAAC,MAAM,CAAC,WAAW,IAAI,oCAAoC,CAAC,CAAC;gBAC/D,EAAE,CAAC,MAAM,CAAC,8DAA8D,CAAC,CAAC;gBAC1E,OAAO,oBAAoB,CAAC;YAC9B,CAAC;YACD,OAAO,MAAM,CACX,IAAI;YACJ,uEAAuE;YACvE,+DAA+D;YAC/D,EAAE,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,IAAI,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,IAAI,IAAI,CAAC,EAAE;YACtF,wEAAwE;YACxE,iEAAiE;YACjE,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,IAAI,IAAI,eAAe,EAAE,CAAC,MAAM,EAAE,CAC3D,CAAC;QACJ,CAAC;KACF,CAAC;AACJ,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@relayflows/sdk",
3
- "version": "2.0.18",
3
+ "version": "2.0.20",
4
4
  "description": "TypeScript-first authoring SDK for Relayflows. Compiles specs; speaks the journal protocol.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -24,6 +24,10 @@
24
24
  "./cli": {
25
25
  "types": "./dist/cli.d.ts",
26
26
  "import": "./dist/cli.js"
27
+ },
28
+ "./relay-cli": {
29
+ "types": "./dist/relay-cli.d.ts",
30
+ "import": "./dist/relay-cli.js"
27
31
  }
28
32
  },
29
33
  "files": [
@@ -45,7 +49,7 @@
45
49
  "@modelcontextprotocol/sdk": "^1.30.0",
46
50
  "@relayfile/adapter-core": "0.5.26",
47
51
  "@relayfile/relay-helpers": "0.4.11",
48
- "@relayflows/surface": "2.0.18",
52
+ "@relayflows/surface": "2.0.20",
49
53
  "@types/js-yaml": "^4.0.9",
50
54
  "ai-hist": "0.4.1",
51
55
  "ajv": "^8.17.1",
@@ -55,6 +59,7 @@
55
59
  "yaml": "^2.5.1"
56
60
  },
57
61
  "devDependencies": {
62
+ "@agent-relay/cli-surface": "^12.2.4",
58
63
  "@types/node": "^22.7.0",
59
64
  "typescript": "^5.6.0",
60
65
  "vitest": "^2.1.0"
@@ -1,3 +1,4 @@
1
+ import type { HumanRecipient } from './human-to.js';
1
2
  import type {
2
3
  CompletionReason as ProtocolCompletionReason,
3
4
  RunCompletionReason as ProtocolRunCompletionReason,
@@ -28,6 +29,8 @@ export type AuthoredFlowExecutionErrorCode =
28
29
  | 'human_parked'
29
30
  /** A recorded answer to `f.human` was not `{ answer: boolean }`. */
30
31
  | 'human_answer_invalid'
32
+ /** `f.human`'s `to` is not one of the documented recipient forms (human-to.ts). */
33
+ | 'human_to_invalid'
31
34
  | 'unsupported_header'
32
35
  | 'unsettled_derived_work'
33
36
  | 'unsupported_promise_lifecycle'
@@ -52,6 +55,8 @@ export interface AuthoredHumanWait {
52
55
  readonly waitId: string;
53
56
  readonly question: string;
54
57
  readonly to: string;
58
+ /** `to` parsed into its delivery form (human-to.ts); Cloud delivers by it. */
59
+ readonly recipient?: HumanRecipient;
55
60
  }
56
61
 
57
62
  /**
@@ -36,6 +36,7 @@ import {
36
36
  type AuthoredFlowExecutionErrorCode,
37
37
  } from './authored-flow-error.js';
38
38
  import { readHumanAnswer } from './authored-human.js';
39
+ import { parseHumanTo } from './human-to.js';
39
40
  import {
40
41
  AuthoredFlowOperation,
41
42
  stopAuthoredOperations,
@@ -431,6 +432,13 @@ export async function executeAuthoredFlow<Input = undefined>(
431
432
  if (typeof humanOptions?.to !== 'string' || humanOptions.to.trim() === '') {
432
433
  throw new AuthoredFlowExecutionError('human_answer_invalid', 'f.human requires { to } naming who answers');
433
434
  }
435
+ // Refused before an ordinal is consumed or anything is journaled: a
436
+ // malformed `to` would otherwise park the run on a question Cloud can
437
+ // deliver to no one (docs/SURFACE.md §5 lists the four forms).
438
+ const parsedTo = parseHumanTo(humanOptions.to);
439
+ if (!parsedTo.ok) {
440
+ throw new AuthoredFlowExecutionError('human_to_invalid', `f.human to ${parsedTo.reason}`);
441
+ }
434
442
  const id = `human-${nextStep++}`;
435
443
  const to = humanOptions.to;
436
444
  // Hoisted like `llmOp`/`runOp`: the start closure reads the caller's
package/src/cli/answer.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import { parseHumanRecipient } from '../human-to.js';
1
2
  import { userInfo } from 'node:os';
2
3
  import { readAuthoredRootMetadata } from '../authored-root.js';
3
4
  import { HUMAN_WAIT_ID, humanAnswerPayload, readHumanAnswer, readOpenHumanWaits, resumeCommand } from '../authored-human.js';
@@ -75,7 +76,7 @@ export async function answerFlow(
75
76
  report: {
76
77
  ...base, ok: true, runId, socketPath, status: snapshot.status,
77
78
  answer: { waitId, answer, ...(options.note === undefined ? {} : { note: options.note }) },
78
- humanWait: { waitId, question: wait.question, to: wait.to },
79
+ humanWait: { waitId, question: wait.question, to: wait.to, recipient: parseHumanRecipient(wait.to) },
79
80
  next: resumeCommand(runId, dataDir, root?.localAgentStream !== undefined),
80
81
  diagnostics: [],
81
82
  },
package/src/cli/build.ts CHANGED
@@ -12,14 +12,20 @@ import type { FlowSpec } from '../spec.js';
12
12
 
13
13
  export interface BuildArgs { command: 'build'; value: string; out?: string; verify: boolean; json: boolean }
14
14
 
15
+ /**
16
+ * `--verify` is an ordinary flag, not a leading mode token: the command surface
17
+ * lists it beside `--out` and `--json`, so every order the help implies has to
18
+ * parse (`build --verify --json <dir>` and `build <dir> --verify` alike).
19
+ *
20
+ * `--out` is the one combination genuinely refused: it names where a build
21
+ * writes, and a verify builds nothing, so accepting the pair would silently
22
+ * ignore the destination. The surface says so in the option's description.
23
+ */
15
24
  export function parseBuildArgs(args: readonly string[]): BuildArgs | undefined {
16
- if (args[0] === '--verify') {
17
- return args.length === 2 && !args[1]!.startsWith('-')
18
- ? { command: 'build', value: args[1]!, verify: true, json: false } : undefined;
19
- }
20
25
  let out: string | undefined;
21
26
  let value: string | undefined;
22
27
  let json = false;
28
+ let verify = false;
23
29
  for (let i = 0; i < args.length; i++) {
24
30
  const arg = args[i]!;
25
31
  if (arg === '--out') {
@@ -28,10 +34,14 @@ export function parseBuildArgs(args: readonly string[]): BuildArgs | undefined {
28
34
  } else if (arg === '--json') {
29
35
  if (json) return undefined;
30
36
  json = true;
37
+ } else if (arg === '--verify') {
38
+ if (verify) return undefined;
39
+ verify = true;
31
40
  } else if (arg.startsWith('-') || value !== undefined) return undefined;
32
41
  else value = arg;
33
42
  }
34
- return value === undefined ? undefined : { command: 'build', value, out, verify: false, json };
43
+ if (value === undefined || (verify && out !== undefined)) return undefined;
44
+ return { command: 'build', value, out, verify, json };
35
45
  }
36
46
 
37
47
  /**
@@ -49,7 +59,11 @@ function emitBuildCheckReport(report: CheckReport, json: boolean, io: CliIo): vo
49
59
  export async function runBuild(args: BuildArgs, io: CliIo): Promise<0 | 2> {
50
60
  try {
51
61
  if (args.verify) {
52
- io.stdout(`VERIFIED sha256:${await verifyBundle(args.value)}`);
62
+ const digest = `sha256:${await verifyBundle(args.value)}`;
63
+ // `--json` is declared on the verb, not on one of its forms: a verify
64
+ // under it emits the same single object a `--json` consumer parses.
65
+ if (args.json) io.stdout(JSON.stringify({ ok: true, verified: true, bundle: args.value, digest }));
66
+ else io.stdout(`VERIFIED ${digest}`);
53
67
  return 0;
54
68
  }
55
69
  // Gate the build on the same preflight pipeline `flows check` uses.
@@ -11,11 +11,13 @@ export async function runCloudCli(
11
11
  value: string; json: boolean; wait: boolean; input: string | undefined; syncCode: boolean; noConnect?: boolean;
12
12
  },
13
13
  io: CliIo,
14
+ /**
15
+ * Cancellation, owned by the caller. `runCli` supplies either the embedder's
16
+ * signal or one it drives from SIGINT/SIGTERM itself, so no process-wide
17
+ * handler is installed here.
18
+ */
19
+ signal: AbortSignal,
14
20
  ): Promise<0 | 1 | 2> {
15
- const controller = new AbortController();
16
- const abort = (): void => controller.abort();
17
- process.once('SIGINT', abort);
18
- process.once('SIGTERM', abort);
19
21
  let runId: string | undefined;
20
22
  // Flips at the run submission. An interruption before it — during prepare,
21
23
  // packing or upload — admitted nothing and is safe to retry; only an
@@ -23,7 +25,7 @@ export async function runCloudCli(
23
25
  let submitting = false;
24
26
  let harnesses: readonly string[] = [];
25
27
  try {
26
- const options: RunInCloudOptions = { signal: controller.signal, onSubmit: () => { submitting = true; } };
28
+ const options: RunInCloudOptions = { signal, onSubmit: () => { submitting = true; } };
27
29
  if (isAuthoredFlowPath(path)) {
28
30
  // Same parse as a local direct run, so a file-or-inline argument means
29
31
  // the same thing on both sides of `--cloud`.
@@ -40,7 +42,7 @@ export async function runCloudCli(
40
42
  // arguments must not first open a browser.
41
43
  const connections = await ensureFlowConnections({
42
44
  path, prompt: cliConnectPrompt(io, { noConnect, json }),
43
- }, { signal: controller.signal });
45
+ }, { signal });
44
46
  harnesses = connections?.requirements.harnesses ?? [];
45
47
  for (const provider of connections?.outcome.connected ?? []) if (!json) io.stdout(`CONNECTED ${provider}`);
46
48
  // The tree is the invoking directory, as with v1: the flow path is where
@@ -62,16 +64,16 @@ export async function runCloudCli(
62
64
  if (json) io.stdout(JSON.stringify({ ok: true, ...receipt }));
63
65
  return 0;
64
66
  }
65
- const run = await waitForCloudFlowRun(receipt.runId, { signal: controller.signal });
67
+ const run = await waitForCloudFlowRun(receipt.runId, { signal });
66
68
  const ok = run.status === 'completed';
67
69
  if (json) io.stdout(JSON.stringify({ ok, ...receipt, ...run }));
68
70
  else io.stdout(`${run.status.toUpperCase()} ${run.runId} completionReason: ${'completionReason' in run ? run.completionReason : 'unavailable'}`);
69
71
  return ok ? 0 : 1;
70
72
  } catch (error) {
71
- const code = controller.signal.aborted
73
+ const code = signal.aborted
72
74
  ? runId ? 'observation_aborted' : submitting ? 'admission_unknown' : 'submission_aborted'
73
75
  : error instanceof CloudFlowError ? error.code : 'cloud_run_failed';
74
- const message = controller.signal.aborted
76
+ const message = signal.aborted
75
77
  ? runId ? 'Stopped observing; the hosted run has not been cancelled.'
76
78
  : submitting
77
79
  ? 'Submission interrupted before a receipt was received. Admission is unknown; Cloud may have started the run. Do not resubmit blindly.'
@@ -83,8 +85,5 @@ export async function runCloudCli(
83
85
  && (['configuration', 'unsupported_source', 'invalid_input', 'unsupported_storage_backend', 'sync_too_large', 'sync_unsupported',
84
86
  'integration_not_connected'].includes(error.code)
85
87
  || (runId === undefined && error.code === 'http_error' && [401, 403].includes(error.status ?? 0))) ? 2 : 1;
86
- } finally {
87
- process.off('SIGINT', abort);
88
- process.off('SIGTERM', abort);
89
88
  }
90
89
  }
@@ -1,5 +1,7 @@
1
1
  import { CloudFlowError } from '../cloud-http.js';
2
- import { applyCloudPatch, downloadCloudPatch, patchedPaths } from '../cloud-sync.js';
2
+ import {
3
+ applyCloudPatch, downloadCloudPatchSet, excludedPatchPaths, patchedPaths, type CloudPathPatch,
4
+ } from '../cloud-sync.js';
3
5
  import type { CliIo } from '../cli.js';
4
6
 
5
7
  /**
@@ -7,23 +9,50 @@ import type { CliIo } from '../cli.js';
7
9
  * and apply it here. The patch is the sandbox's own `git diff` against the
8
10
  * uploaded baseline, so applying it reproduces exactly what the run's steps
9
11
  * wrote — no re-execution, no re-upload.
12
+ *
13
+ * The agent runtime's own bookkeeping inside that tree is dropped on the way
14
+ * in (`CLOUD_SYNC_PATCH_EXCLUDES`); `--dry-run` prints the patch instead of
15
+ * applying it, and a run that produced one patch per mounted path is shown but
16
+ * never applied, because no single `--dir` is the right destination for all of
17
+ * them.
10
18
  */
11
19
  export async function runCloudSyncCli(
12
- { runId, json, root }: { runId: string; json: boolean; root: string },
20
+ { runId, json, root, dryRun }: { runId: string; json: boolean; root: string; dryRun: boolean },
13
21
  io: CliIo,
14
22
  ): Promise<0 | 1 | 2> {
15
23
  try {
16
- const { patch, hasChanges } = await downloadCloudPatch(runId, {});
17
- if (!hasChanges || !patch.trim()) {
24
+ const set = await downloadCloudPatchSet(runId, {});
25
+ // A single-tree run can answer `hasChanges: true` with an empty body. The
26
+ // multi-path branch already discounts those (`patch.trim() !== ''` in
27
+ // `downloadCloudPatchSet`), and so did `agent-relay cloud sync`, which this
28
+ // command replaces. Without the same guard an empty patch reaches `git
29
+ // apply`, which fails as `patch_conflict` instead of reporting NO CHANGES.
30
+ const hasChanges = set.kind === 'single' ? set.hasChanges && set.patch.trim() !== '' : set.hasChanges;
31
+ if (!hasChanges) {
18
32
  if (json) io.stdout(JSON.stringify({ ok: true, runId, hasChanges: false, applied: false }));
19
33
  else io.stdout(`NO CHANGES ${runId}`);
20
34
  return 0;
21
35
  }
22
- applyCloudPatch(root, patch);
23
- const files = patchedPaths(patch);
24
- if (json) io.stdout(JSON.stringify({ ok: true, runId, hasChanges: true, applied: true, files }));
36
+ if (set.kind === 'multi-path') {
37
+ const changed = set.patches.filter(entry => entry.hasChanges && entry.patch.trim() !== '');
38
+ if (!dryRun) {
39
+ throw new CloudFlowError('sync_unsupported',
40
+ `Run ${runId} produced ${changed.length} path-scoped patch${changed.length === 1 ? '' : 'es'} `
41
+ + `(${changed.map(entry => entry.name).join(', ')}); flows sync applies single-tree runs only. `
42
+ + 'Inspect them with --dry-run, then apply each in its own repository.');
43
+ }
44
+ reportMultiPathDryRun(runId, changed, json, io);
45
+ return 0;
46
+ }
47
+ if (dryRun) {
48
+ reportDryRun(runId, set.patch, json, io);
49
+ return 0;
50
+ }
51
+ const { files, excluded } = applyCloudPatch(root, set.patch);
52
+ if (json) io.stdout(JSON.stringify({ ok: true, runId, hasChanges: true, applied: true, files, excluded }));
25
53
  else {
26
- io.stdout(`APPLIED ${runId}: ${files.length} file${files.length === 1 ? '' : 's'}${files.length ? `\n ${files.join('\n ')}` : ''}`);
54
+ io.stdout(`APPLIED ${runId}: ${files.length} file${files.length === 1 ? '' : 's'}${indented(files)}`);
55
+ if (excluded.length) io.stdout(`SKIPPED agent runtime paths: ${excluded.length}${indented(excluded)}`);
27
56
  io.stdout('Applied to the working tree, uncommitted: review with git diff before keeping it.');
28
57
  }
29
58
  return 0;
@@ -35,3 +64,51 @@ export async function runCloudSyncCli(
35
64
  return error instanceof CloudFlowError && ['configuration', 'sync_unsupported', 'patch_conflict'].includes(error.code) ? 2 : 1;
36
65
  }
37
66
  }
67
+
68
+ /** A single-tree patch, shown rather than applied. */
69
+ function reportDryRun(runId: string, patch: string, json: boolean, io: CliIo): void {
70
+ const excluded = excludedPatchPaths(patch);
71
+ const files = patchedPaths(patch).filter(path => !excluded.includes(path));
72
+ if (json) {
73
+ // The patch travels in the payload, not on stdout beside it: a --json
74
+ // consumer parses one object, and a diff printed alongside it is not JSON.
75
+ io.stdout(JSON.stringify({
76
+ ok: true, runId, hasChanges: true, applied: false, dryRun: true, files, excluded, patch,
77
+ }));
78
+ return;
79
+ }
80
+ io.stdout(`DRY RUN ${runId}: ${files.length} file${files.length === 1 ? '' : 's'} would be written${indented(files)}`);
81
+ if (excluded.length) io.stdout(`Would skip agent runtime paths: ${excluded.length}${indented(excluded)}`);
82
+ emitPatch(patch, io);
83
+ }
84
+
85
+ /** Every changed path-scoped patch, shown; applying them is not this command's call. */
86
+ function reportMultiPathDryRun(
87
+ runId: string, changed: readonly CloudPathPatch[], json: boolean, io: CliIo,
88
+ ): void {
89
+ if (json) {
90
+ io.stdout(JSON.stringify({
91
+ ok: true, runId, hasChanges: true, applied: false, dryRun: true, multiPath: true,
92
+ patches: changed.map(({ name, patch }) => {
93
+ const excluded = excludedPatchPaths(patch);
94
+ return { name, files: patchedPaths(patch).filter(path => !excluded.includes(path)), excluded, patch };
95
+ }),
96
+ }));
97
+ return;
98
+ }
99
+ io.stdout(`DRY RUN ${runId}: ${changed.length} path-scoped patch${changed.length === 1 ? '' : 'es'}`);
100
+ io.stdout('Each targets its own repository; apply them there, not with --dir.');
101
+ for (const { name, patch } of changed) {
102
+ io.stdout(`--- patch for path "${name}" ---`);
103
+ emitPatch(patch, io);
104
+ }
105
+ }
106
+
107
+ /** Write a diff through the line-oriented io without gaining or losing a newline. */
108
+ function emitPatch(patch: string, io: CliIo): void {
109
+ for (const line of patch.replace(/\n$/u, '').split('\n')) io.stdout(line);
110
+ }
111
+
112
+ function indented(paths: readonly string[]): string {
113
+ return paths.length ? `\n ${paths.join('\n ')}` : '';
114
+ }