looply-cli 0.5.8 → 0.5.10

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 (119) hide show
  1. package/dist/.src-hash +1 -1
  2. package/dist/account-failover.d.ts +30 -0
  3. package/dist/account-failover.d.ts.map +1 -0
  4. package/dist/account-failover.js +32 -0
  5. package/dist/account-failover.js.map +1 -0
  6. package/dist/bin.d.ts.map +1 -1
  7. package/dist/bin.js +9 -1
  8. package/dist/bin.js.map +1 -1
  9. package/dist/branch-delivery-wiring.d.ts +41 -0
  10. package/dist/branch-delivery-wiring.d.ts.map +1 -0
  11. package/dist/branch-delivery-wiring.js +85 -0
  12. package/dist/branch-delivery-wiring.js.map +1 -0
  13. package/dist/branch-delivery.d.ts +275 -0
  14. package/dist/branch-delivery.d.ts.map +1 -0
  15. package/dist/branch-delivery.js +659 -0
  16. package/dist/branch-delivery.js.map +1 -0
  17. package/dist/config.d.ts +20 -1
  18. package/dist/config.d.ts.map +1 -1
  19. package/dist/config.js +24 -0
  20. package/dist/config.js.map +1 -1
  21. package/dist/coordinator-state.d.ts.map +1 -1
  22. package/dist/coordinator-state.js +28 -18
  23. package/dist/coordinator-state.js.map +1 -1
  24. package/dist/daemon-cmd.d.ts.map +1 -1
  25. package/dist/daemon-cmd.js +93 -6
  26. package/dist/daemon-cmd.js.map +1 -1
  27. package/dist/daemon-lock.d.ts +65 -2
  28. package/dist/daemon-lock.d.ts.map +1 -1
  29. package/dist/daemon-lock.js +149 -5
  30. package/dist/daemon-lock.js.map +1 -1
  31. package/dist/daemon.d.ts +21 -1
  32. package/dist/daemon.d.ts.map +1 -1
  33. package/dist/daemon.js +49 -3
  34. package/dist/daemon.js.map +1 -1
  35. package/dist/deliver-cmd.d.ts +41 -0
  36. package/dist/deliver-cmd.d.ts.map +1 -0
  37. package/dist/deliver-cmd.js +189 -0
  38. package/dist/deliver-cmd.js.map +1 -0
  39. package/dist/delivery-rules.d.ts +71 -0
  40. package/dist/delivery-rules.d.ts.map +1 -0
  41. package/dist/delivery-rules.js +186 -0
  42. package/dist/delivery-rules.js.map +1 -0
  43. package/dist/delivery-settings-cache.d.ts +35 -0
  44. package/dist/delivery-settings-cache.d.ts.map +1 -0
  45. package/dist/delivery-settings-cache.js +119 -0
  46. package/dist/delivery-settings-cache.js.map +1 -0
  47. package/dist/github-api.d.ts +99 -0
  48. package/dist/github-api.d.ts.map +1 -0
  49. package/dist/github-api.js +226 -0
  50. package/dist/github-api.js.map +1 -0
  51. package/dist/goal-runs.d.ts +2 -2
  52. package/dist/goal-runs.d.ts.map +1 -1
  53. package/dist/goal-runs.js +13 -11
  54. package/dist/goal-runs.js.map +1 -1
  55. package/dist/machine-settings.d.ts +188 -0
  56. package/dist/machine-settings.d.ts.map +1 -0
  57. package/dist/machine-settings.js +658 -0
  58. package/dist/machine-settings.js.map +1 -0
  59. package/dist/model-transport.d.ts +13 -0
  60. package/dist/model-transport.d.ts.map +1 -1
  61. package/dist/model-transport.js +70 -9
  62. package/dist/model-transport.js.map +1 -1
  63. package/dist/project-terminal.d.ts +6 -0
  64. package/dist/project-terminal.d.ts.map +1 -1
  65. package/dist/project-terminal.js +3 -0
  66. package/dist/project-terminal.js.map +1 -1
  67. package/dist/provider-accounts-cmd.d.ts +58 -0
  68. package/dist/provider-accounts-cmd.d.ts.map +1 -0
  69. package/dist/provider-accounts-cmd.js +247 -0
  70. package/dist/provider-accounts-cmd.js.map +1 -0
  71. package/dist/provider-accounts.d.ts +157 -0
  72. package/dist/provider-accounts.d.ts.map +1 -0
  73. package/dist/provider-accounts.js +423 -0
  74. package/dist/provider-accounts.js.map +1 -0
  75. package/dist/provider-cmd.d.ts +3 -0
  76. package/dist/provider-cmd.d.ts.map +1 -1
  77. package/dist/provider-cmd.js +25 -0
  78. package/dist/provider-cmd.js.map +1 -1
  79. package/dist/provider-limit.d.ts +6 -0
  80. package/dist/provider-limit.d.ts.map +1 -1
  81. package/dist/provider-limit.js +12 -0
  82. package/dist/provider-limit.js.map +1 -1
  83. package/dist/provider-state.d.ts +3 -0
  84. package/dist/provider-state.d.ts.map +1 -1
  85. package/dist/provider-state.js +4 -1
  86. package/dist/provider-state.js.map +1 -1
  87. package/dist/run-cmd.d.ts.map +1 -1
  88. package/dist/run-cmd.js +41 -5
  89. package/dist/run-cmd.js.map +1 -1
  90. package/dist/run-ending-locator.d.ts.map +1 -1
  91. package/dist/run-ending-locator.js +5 -3
  92. package/dist/run-ending-locator.js.map +1 -1
  93. package/dist/serve-cmd.d.ts +8 -0
  94. package/dist/serve-cmd.d.ts.map +1 -1
  95. package/dist/serve-cmd.js +12 -0
  96. package/dist/serve-cmd.js.map +1 -1
  97. package/dist/server-client.d.ts +45 -1
  98. package/dist/server-client.d.ts.map +1 -1
  99. package/dist/server-client.js +54 -2
  100. package/dist/server-client.js.map +1 -1
  101. package/dist/spend-ledger.d.ts +7 -0
  102. package/dist/spend-ledger.d.ts.map +1 -1
  103. package/dist/spend-ledger.js +1 -0
  104. package/dist/spend-ledger.js.map +1 -1
  105. package/dist/stale-run-sweep.js +11 -10
  106. package/dist/stale-run-sweep.js.map +1 -1
  107. package/dist/untrusted-exec.d.ts +11 -0
  108. package/dist/untrusted-exec.d.ts.map +1 -1
  109. package/dist/untrusted-exec.js +1 -0
  110. package/dist/untrusted-exec.js.map +1 -1
  111. package/dist/workspace-provisioner.d.ts +8 -0
  112. package/dist/workspace-provisioner.d.ts.map +1 -1
  113. package/dist/workspace-provisioner.js +18 -0
  114. package/dist/workspace-provisioner.js.map +1 -1
  115. package/dist/workspace.d.ts +33 -13
  116. package/dist/workspace.d.ts.map +1 -1
  117. package/dist/workspace.js +89 -92
  118. package/dist/workspace.js.map +1 -1
  119. package/package.json +2 -2
@@ -0,0 +1,186 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ALWAYS_PROTECTED = exports.DELIVERY_REMOTE = void 0;
4
+ exports.isDeployRemoteUrl = isDeployRemoteUrl;
5
+ exports.githubRepoOf = githubRepoOf;
6
+ exports.redactUrl = redactUrl;
7
+ exports.shortBranch = shortBranch;
8
+ exports.pushRefusal = pushRefusal;
9
+ exports.deployPushArgv = deployPushArgv;
10
+ exports.unsafeDeployPushArgv = unsafeDeployPushArgv;
11
+ exports.deliveryPushArgv = deliveryPushArgv;
12
+ exports.unsafePushArgv = unsafePushArgv;
13
+ const integrator_1 = require("./integrator");
14
+ /**
15
+ * THE HARD RULES FOR EVERY PUSH LOOPLY MAKES OF A FINISHED BRANCH.
16
+ *
17
+ * ─────────────────────────────────────────────────────────────────────────────
18
+ * Not settings. Nothing in config.yaml, nothing from the server and nothing a
19
+ * goal says can loosen any of them:
20
+ *
21
+ * 1. ONLY `origin`. Several of the owner's repositories have remotes that
22
+ * DEPLOY ON PUSH (`heroku`, `heroku-qa`); a push to one of them is a
23
+ * release, not a review. And an `origin` that itself points at Heroku is
24
+ * refused for the same reason.
25
+ * 2. ONLY a `looply/run-*` branch — the goal's own work. Never the base
26
+ * branch, never `main`/`master`, never a branch the project or GitHub
27
+ * marks protected.
28
+ * 3. NEVER FORCED. The argv is built here and checked here again just before
29
+ * it runs: no `--force` in any spelling, no `+` refspec, no deletes, no
30
+ * `--mirror`/`--all`/`--tags`. A branch origin already has at a commit
31
+ * this one does not contain is reported, not overwritten.
32
+ *
33
+ * Merging into the base branch (`deliver: merge`) is a GitHub merge of a pull
34
+ * request whose checks are green — never a push — and lives in
35
+ * `branch-delivery.ts`.
36
+ */
37
+ /** The one remote Looply pushes to. */
38
+ exports.DELIVERY_REMOTE = 'origin';
39
+ /** Branches never pushed whatever else is configured. */
40
+ exports.ALWAYS_PROTECTED = ['main', 'master'];
41
+ /** A remote URL whose push deploys an app: a push there is a release. */
42
+ function isDeployRemoteUrl(url) {
43
+ let host;
44
+ try {
45
+ host = new URL(asUrl(url.trim())).hostname.toLowerCase();
46
+ }
47
+ catch {
48
+ // Unreadable: refuse anything that even mentions heroku rather than guess.
49
+ return /heroku/i.test(url);
50
+ }
51
+ return host === 'heroku.com' || host.endsWith('.heroku.com') || host.endsWith('.herokuapp.com');
52
+ }
53
+ function asUrl(url) {
54
+ // scp-like `git@host:owner/repo.git` → ssh://git@host/owner/repo.git, so URL can read the host.
55
+ const scp = /^([^@/]+@)?([^:/]+):(.+)$/.exec(url);
56
+ if (scp && !/^[a-z]+:\/\//i.test(url))
57
+ return `ssh://${scp[1] ?? ''}${scp[2]}/${scp[3]}`;
58
+ return url;
59
+ }
60
+ /** `owner/repo` for a github.com remote, else null (another host gets a push but no pull request). */
61
+ function githubRepoOf(url) {
62
+ let u;
63
+ try {
64
+ u = new URL(asUrl(url.trim()));
65
+ }
66
+ catch {
67
+ return null;
68
+ }
69
+ if (u.hostname.toLowerCase() !== 'github.com')
70
+ return null;
71
+ const parts = u.pathname.replace(/^\/+/, '').replace(/\.git$/i, '').replace(/\/+$/, '').split('/');
72
+ if (parts.length !== 2 || !parts[0] || !parts[1])
73
+ return null;
74
+ if (!/^[A-Za-z0-9_.-]+$/.test(parts[0]) || !/^[A-Za-z0-9_.-]+$/.test(parts[1]))
75
+ return null;
76
+ return { owner: parts[0], repo: parts[1] };
77
+ }
78
+ /** A remote URL with any embedded credentials removed, for a sentence a person reads. */
79
+ function redactUrl(url) {
80
+ return url.replace(/(\b[a-z][a-z0-9+.-]*:\/\/)[^@/\s]+@/gi, '$1');
81
+ }
82
+ /** The branch name without a leading `origin/` or `refs/heads/`. */
83
+ function shortBranch(ref) {
84
+ return ref.replace(/^refs\/heads\//, '').replace(/^refs\/remotes\/[^/]+\//, '').replace(/^origin\//, '');
85
+ }
86
+ /** Why this push may not happen, or null when every rule allows it. */
87
+ function pushRefusal(input) {
88
+ if (input.remote !== exports.DELIVERY_REMOTE) {
89
+ return `Looply pushes only to ${exports.DELIVERY_REMOTE}, never to "${input.remote}" (a remote like heroku deploys on push)`;
90
+ }
91
+ if (input.remoteUrl === null || input.remoteUrl.trim() === '') {
92
+ return `this repository has no ${exports.DELIVERY_REMOTE} remote to push to`;
93
+ }
94
+ if (isDeployRemoteUrl(input.remoteUrl)) {
95
+ return `${exports.DELIVERY_REMOTE} points at ${redactUrl(input.remoteUrl)}, where a push deploys; Looply does not push there`;
96
+ }
97
+ const b = input.branch;
98
+ if (!b.startsWith(integrator_1.RUN_BRANCH_PREFIX) || b.length <= integrator_1.RUN_BRANCH_PREFIX.length) {
99
+ return `only a goal's own ${integrator_1.RUN_BRANCH_PREFIX}* branch is pushed, and "${b}" is not one`;
100
+ }
101
+ if (!/^[A-Za-z0-9._/-]+$/.test(b) || b.includes('..') || b.endsWith('/') || b.endsWith('.lock') || b.includes('//')) {
102
+ return `"${b}" is not a branch name Looply will push`;
103
+ }
104
+ const lower = b.toLowerCase();
105
+ if (exports.ALWAYS_PROTECTED.includes(lower))
106
+ return `"${b}" is protected; Looply never pushes it`;
107
+ if (input.base !== null && lower === shortBranch(input.base).toLowerCase()) {
108
+ return `"${b}" is the project's base branch; Looply never pushes it`;
109
+ }
110
+ if (input.protectedBranches.some((p) => shortBranch(p).toLowerCase() === lower)) {
111
+ return `"${b}" is a protected branch; Looply never pushes it`;
112
+ }
113
+ return null;
114
+ }
115
+ /**
116
+ * THE ONE EXCEPTION TO "ORIGIN ONLY": a `push` deploy step, which the project
117
+ * configured explicitly (remote + branch). Exactly `push --porcelain <remote>
118
+ * <merged sha>:refs/heads/<branch>` — the configured remote and branch and
119
+ * nothing else, never forced, never a delete.
120
+ */
121
+ function deployPushArgv(remote, branch, sha) {
122
+ return ['push', '--porcelain', remote, `${sha}:refs/heads/${branch}`];
123
+ }
124
+ function unsafeDeployPushArgv(argv, allowed) {
125
+ if (argv[0] !== 'push')
126
+ return 'not a push';
127
+ const rest = argv.slice(1);
128
+ const flags = rest.filter((a) => a.startsWith('-'));
129
+ if (flags.some((f) => f !== '--porcelain'))
130
+ return `only --porcelain is allowed, not ${flags.join(' ')}`;
131
+ const positional = rest.filter((a) => !a.startsWith('-'));
132
+ if (positional.length !== 2)
133
+ return 'a deploy push names exactly one remote and one refspec';
134
+ const [remote, spec] = positional;
135
+ if (remote !== allowed.remote)
136
+ return `the deploy remote is ${allowed.remote}, not "${remote}"`;
137
+ if (spec.startsWith('+'))
138
+ return 'a forced refspec (+) is never used';
139
+ const m = /^([0-9a-f]{40}):refs\/heads\/(.+)$/.exec(spec);
140
+ if (m === null)
141
+ return 'the refspec must be <full sha>:refs/heads/<branch>';
142
+ if (m[2] !== allowed.branch)
143
+ return `the deploy branch is ${allowed.branch}, not "${m[2]}"`;
144
+ return null;
145
+ }
146
+ /** The exact argv of a delivery push: `<sha>:refs/heads/<branch>` to origin, nothing else. */
147
+ function deliveryPushArgv(branch, sha) {
148
+ return ['push', '--porcelain', exports.DELIVERY_REMOTE, `${sha}:refs/heads/${branch}`];
149
+ }
150
+ const FORBIDDEN_PUSH_FLAGS = /^(-f|--force.*|--mirror|--all|--tags|--follow-tags|--delete|-d|--prune|--set-upstream|-u|--receive-pack.*|--exec.*|--repo.*|-o|--push-option.*|--no-verify)$/;
151
+ /**
152
+ * THE LAST LOOK BEFORE GIT RUNS. Refuses any argv that is not exactly a
153
+ * non-forced push of one sha to one `refs/heads/looply/run-*` on origin — so a
154
+ * future caller that builds its own argv cannot reach a force, a delete, a
155
+ * second remote or a protected branch through this module.
156
+ */
157
+ function unsafePushArgv(argv) {
158
+ if (argv[0] !== 'push')
159
+ return 'not a push';
160
+ const rest = argv.slice(1);
161
+ for (const a of rest) {
162
+ if (FORBIDDEN_PUSH_FLAGS.test(a) || /^-[a-z]*f[a-z]*$/i.test(a) && !a.startsWith('--'))
163
+ return `"${a}" is not allowed in a delivery push`;
164
+ }
165
+ const positional = rest.filter((a) => !a.startsWith('-'));
166
+ const flags = rest.filter((a) => a.startsWith('-'));
167
+ if (flags.some((f) => f !== '--porcelain'))
168
+ return `only --porcelain is allowed, not ${flags.join(' ')}`;
169
+ if (positional.length !== 2)
170
+ return 'a delivery push names exactly one remote and one refspec';
171
+ const [remote, spec] = positional;
172
+ if (remote !== exports.DELIVERY_REMOTE)
173
+ return `the remote must be ${exports.DELIVERY_REMOTE}, not "${remote}"`;
174
+ if (spec.startsWith('+'))
175
+ return 'a forced refspec (+) is never used';
176
+ const m = /^([0-9a-f]{40}):refs\/heads\/(.+)$/.exec(spec);
177
+ if (m === null)
178
+ return 'the refspec must be <full sha>:refs/heads/<branch>';
179
+ const branch = m[2];
180
+ if (!branch.startsWith(integrator_1.RUN_BRANCH_PREFIX))
181
+ return `only ${integrator_1.RUN_BRANCH_PREFIX}* is pushed, not "${branch}"`;
182
+ if (exports.ALWAYS_PROTECTED.includes(branch.toLowerCase()))
183
+ return `"${branch}" is protected`;
184
+ return null;
185
+ }
186
+ //# sourceMappingURL=delivery-rules.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"delivery-rules.js","sourceRoot":"","sources":["../src/delivery-rules.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,35 @@
1
+ import { type DeliverMode, type DeployConfig } from '@looply/core';
2
+ /**
3
+ * THE PROJECT'S REMOTE DELIVERY CHOICE, AS THIS MACHINE LAST HEARD IT.
4
+ *
5
+ * Set in AutoRyn's software-execution settings or the Looply console; pulled by
6
+ * the daemon with the model settings (every five minutes) and written here. A
7
+ * failed pull keeps the last answer, so an offline machine keeps doing what it
8
+ * was last told — never silently switches to merging or back.
9
+ *
10
+ * Precedence: config.yaml `deliver.mode` → this cache → `pr`.
11
+ */
12
+ export declare const DELIVERY_SETTINGS_FILE = "delivery-settings.json";
13
+ export interface DeliverySettingsCache {
14
+ deliver: DeliverMode | null;
15
+ /** The project's deploy step as set remotely; null when none. */
16
+ deploy: DeployConfig | null;
17
+ updatedAt: string | null;
18
+ fetchedAt: string;
19
+ }
20
+ export declare function readDeliverySettingsCache(stateDir: string): DeliverySettingsCache | null;
21
+ /** The mode in force, and where it came from. */
22
+ export declare function resolveDeliverMode(local: DeliverMode | undefined, stateDir: string): {
23
+ mode: DeliverMode;
24
+ from: 'config.yaml' | 'remote' | 'default';
25
+ };
26
+ /** The deploy step in force: config.yaml `deliver.deploy` → the remote setting → none (null). */
27
+ export declare function resolveDeploy(local: DeployConfig | undefined, stateDir: string): DeployConfig | null;
28
+ /** One pull: ask the server, write the cache when the answer changed. Never throws. */
29
+ export declare function makeDeliverySettingsPull(deps: {
30
+ fetch(): Promise<unknown>;
31
+ stateDir: string;
32
+ log(line: string): void;
33
+ now(): number;
34
+ }): () => Promise<'updated' | 'unchanged' | 'failed'>;
35
+ //# sourceMappingURL=delivery-settings-cache.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"delivery-settings-cache.d.ts","sourceRoot":"","sources":["../src/delivery-settings-cache.ts"],"names":[],"mappings":"AAEA,OAAO,EAAkD,KAAK,WAAW,EAAE,KAAK,YAAY,EAAE,MAAM,cAAc,CAAC;AAGnH;;;;;;;;;GASG;AAEH,eAAO,MAAM,sBAAsB,2BAA2B,CAAC;AAE/D,MAAM,WAAW,qBAAqB;IACpC,OAAO,EAAE,WAAW,GAAG,IAAI,CAAC;IAC5B,iEAAiE;IACjE,MAAM,EAAE,YAAY,GAAG,IAAI,CAAC;IAC5B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,wBAAgB,yBAAyB,CAAC,QAAQ,EAAE,MAAM,GAAG,qBAAqB,GAAG,IAAI,CAoBxF;AAUD,iDAAiD;AACjD,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,WAAW,GAAG,SAAS,EAC9B,QAAQ,EAAE,MAAM,GACf;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,IAAI,EAAE,aAAa,GAAG,QAAQ,GAAG,SAAS,CAAA;CAAE,CAKnE;AAED,iGAAiG;AACjG,wBAAgB,aAAa,CAAC,KAAK,EAAE,YAAY,GAAG,SAAS,EAAE,QAAQ,EAAE,MAAM,GAAG,YAAY,GAAG,IAAI,CAGpG;AAED,uFAAuF;AACvF,wBAAgB,wBAAwB,CAAC,IAAI,EAAE;IAC7C,KAAK,IAAI,OAAO,CAAC,OAAO,CAAC,CAAC;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,GAAG,IAAI,MAAM,CAAC;CACf,GAAG,MAAM,OAAO,CAAC,SAAS,GAAG,WAAW,GAAG,QAAQ,CAAC,CA4CpD"}
@@ -0,0 +1,119 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DELIVERY_SETTINGS_FILE = void 0;
4
+ exports.readDeliverySettingsCache = readDeliverySettingsCache;
5
+ exports.resolveDeliverMode = resolveDeliverMode;
6
+ exports.resolveDeploy = resolveDeploy;
7
+ exports.makeDeliverySettingsPull = makeDeliverySettingsPull;
8
+ const node_fs_1 = require("node:fs");
9
+ const node_path_1 = require("node:path");
10
+ const core_1 = require("@looply/core");
11
+ const server_client_1 = require("./server-client");
12
+ /**
13
+ * THE PROJECT'S REMOTE DELIVERY CHOICE, AS THIS MACHINE LAST HEARD IT.
14
+ *
15
+ * Set in AutoRyn's software-execution settings or the Looply console; pulled by
16
+ * the daemon with the model settings (every five minutes) and written here. A
17
+ * failed pull keeps the last answer, so an offline machine keeps doing what it
18
+ * was last told — never silently switches to merging or back.
19
+ *
20
+ * Precedence: config.yaml `deliver.mode` → this cache → `pr`.
21
+ */
22
+ exports.DELIVERY_SETTINGS_FILE = 'delivery-settings.json';
23
+ function readDeliverySettingsCache(stateDir) {
24
+ try {
25
+ const raw = JSON.parse((0, node_fs_1.readFileSync)((0, node_path_1.join)(stateDir, exports.DELIVERY_SETTINGS_FILE), 'utf8'));
26
+ let deliver = null;
27
+ let deploy = null;
28
+ if (raw['deliver'] !== null && raw['deliver'] !== undefined) {
29
+ const v = (0, core_1.validateDeliverySettings)({ deliver: raw['deliver'], ...(raw['deploy'] ? { deploy: raw['deploy'] } : {}) });
30
+ if (!v.ok)
31
+ return null;
32
+ deliver = v.settings.deliver;
33
+ deploy = v.settings.deploy ?? null;
34
+ }
35
+ return {
36
+ deliver,
37
+ deploy,
38
+ updatedAt: typeof raw['updatedAt'] === 'string' ? raw['updatedAt'] : null,
39
+ fetchedAt: typeof raw['fetchedAt'] === 'string' ? raw['fetchedAt'] : '',
40
+ };
41
+ }
42
+ catch {
43
+ return null;
44
+ }
45
+ }
46
+ function writeCache(stateDir, value) {
47
+ (0, node_fs_1.mkdirSync)(stateDir, { recursive: true });
48
+ const target = (0, node_path_1.join)(stateDir, exports.DELIVERY_SETTINGS_FILE);
49
+ const tmp = `${target}.${process.pid}.tmp`;
50
+ (0, node_fs_1.writeFileSync)(tmp, JSON.stringify(value, null, 2) + '\n', 'utf8');
51
+ (0, node_fs_1.renameSync)(tmp, target);
52
+ }
53
+ /** The mode in force, and where it came from. */
54
+ function resolveDeliverMode(local, stateDir) {
55
+ if (local !== undefined)
56
+ return { mode: local, from: 'config.yaml' };
57
+ const remote = readDeliverySettingsCache(stateDir)?.deliver ?? null;
58
+ if (remote !== null)
59
+ return { mode: remote, from: 'remote' };
60
+ return { mode: core_1.DEFAULT_DELIVER_MODE, from: 'default' };
61
+ }
62
+ /** The deploy step in force: config.yaml `deliver.deploy` → the remote setting → none (null). */
63
+ function resolveDeploy(local, stateDir) {
64
+ if (local !== undefined)
65
+ return local;
66
+ return readDeliverySettingsCache(stateDir)?.deploy ?? null;
67
+ }
68
+ /** One pull: ask the server, write the cache when the answer changed. Never throws. */
69
+ function makeDeliverySettingsPull(deps) {
70
+ let failureReported = false;
71
+ const reportOnce = (why) => {
72
+ if (failureReported)
73
+ return;
74
+ failureReported = true;
75
+ deps.log(`deliver : could not refresh the project's delivery setting — ${why}`);
76
+ };
77
+ return async () => {
78
+ let body;
79
+ try {
80
+ body = await deps.fetch();
81
+ }
82
+ catch (e) {
83
+ if (!(e instanceof server_client_1.ServerError && (e.isOffline || e.isAuth)))
84
+ reportOnce(e.message);
85
+ return 'failed';
86
+ }
87
+ const b = body;
88
+ if (typeof b !== 'object' || b === null || !('settings' in b)) {
89
+ reportOnce('the server answered with something that is not a settings envelope');
90
+ return 'failed';
91
+ }
92
+ let deliver = null;
93
+ let deploy = null;
94
+ if (b.settings !== null) {
95
+ const v = (0, core_1.validateDeliverySettings)(b.settings);
96
+ if (!v.ok) {
97
+ reportOnce(`the server sent a setting this build refuses (${v.key}: ${v.because})`);
98
+ return 'failed';
99
+ }
100
+ deliver = v.settings.deliver;
101
+ deploy = v.settings.deploy ?? null;
102
+ }
103
+ failureReported = false;
104
+ const updatedAt = typeof b.updatedAt === 'string' ? b.updatedAt : null;
105
+ const before = readDeliverySettingsCache(deps.stateDir);
106
+ if (before !== null && before.deliver === deliver && JSON.stringify(before.deploy) === JSON.stringify(deploy) && before.updatedAt === updatedAt)
107
+ return 'unchanged';
108
+ try {
109
+ writeCache(deps.stateDir, { deliver, deploy, updatedAt, fetchedAt: new Date(deps.now()).toISOString() });
110
+ }
111
+ catch (e) {
112
+ deps.log(`deliver : could not write the delivery setting cache (${e.message})`);
113
+ return 'failed';
114
+ }
115
+ deps.log(`deliver : project delivery setting is ${deliver ?? `the default (${core_1.DEFAULT_DELIVER_MODE})`}`);
116
+ return 'updated';
117
+ };
118
+ }
119
+ //# sourceMappingURL=delivery-settings-cache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"delivery-settings-cache.js","sourceRoot":"","sources":["../src/delivery-settings-cache.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,99 @@
1
+ /**
2
+ * THE SLICE OF GITHUB A FINISHED BRANCH NEEDS: find or open its pull request,
3
+ * ask whether a branch is protected, read its checks, and merge it.
4
+ *
5
+ * ─────────────────────────────────────────────────────────────────────────────
6
+ * 🔴 THE MACHINE'S OWN CREDENTIALS, AND NOTHING NEW. The token is whatever this
7
+ * machine already pushes with: `gh auth token` when the GitHub CLI is installed
8
+ * and signed in, else git's own credential helper (`git credential fill` for
9
+ * github.com — Git Credential Manager on Windows). Nothing is stored, printed or
10
+ * sent anywhere but api.github.com. Neither may prompt: a daemon has nobody to
11
+ * answer, so `GIT_TERMINAL_PROMPT=0` and `GCM_INTERACTIVE=never` are set, and
12
+ * every child is hidden (`windowsHide`).
13
+ *
14
+ * When neither yields a token the answer is null, and the caller says so
15
+ * plainly: "pushed, but no pull request could be opened because …".
16
+ */
17
+ export interface PullInfo {
18
+ readonly number: number;
19
+ /** The address a person opens. */
20
+ readonly url: string;
21
+ readonly state: 'open' | 'closed';
22
+ readonly merged: boolean;
23
+ /** The branch it targets. */
24
+ readonly base: string;
25
+ readonly headSha: string;
26
+ }
27
+ export type CheckState = 'success' | 'failure' | 'pending';
28
+ export interface CheckResult {
29
+ readonly name: string;
30
+ readonly state: CheckState;
31
+ }
32
+ export interface GitHubApi {
33
+ /** The pull request whose head is `branch`, in any state, newest first; null when none. */
34
+ findPull(branch: string): Promise<PullInfo | null>;
35
+ getPull(n: number): Promise<PullInfo>;
36
+ createPull(input: {
37
+ title: string;
38
+ head: string;
39
+ base: string;
40
+ body: string;
41
+ }): Promise<PullInfo>;
42
+ /** True/false from GitHub; null when it would not say (no rights to read it). */
43
+ branchProtected(branch: string): Promise<boolean | null>;
44
+ /** True when origin has the branch. */
45
+ branchExists(branch: string): Promise<boolean>;
46
+ /** The required status-check names for `base`; null when unknown (unprotected, or not readable). */
47
+ requiredChecks(base: string): Promise<string[] | null>;
48
+ /** Every check run and commit status on `sha`, by name (newest wins). */
49
+ checksFor(sha: string): Promise<CheckResult[]>;
50
+ /** Merge, only if the head is still `sha`. Never a squash of somebody else's commits behind their back. */
51
+ merge(n: number, sha: string, title: string): Promise<{
52
+ merged: boolean;
53
+ message: string;
54
+ sha?: string;
55
+ }>;
56
+ setBase(n: number, base: string): Promise<void>;
57
+ /** Close a pull request a fix-up replaced, with a comment saying by what. */
58
+ closePull(n: number, comment: string): Promise<void>;
59
+ }
60
+ export declare class GitHubError extends Error {
61
+ readonly status: number;
62
+ constructor(message: string, status: number);
63
+ }
64
+ type Fetch = (url: string, init: {
65
+ method: string;
66
+ headers: Record<string, string>;
67
+ body?: string;
68
+ }) => Promise<{
69
+ status: number;
70
+ text(): Promise<string>;
71
+ }>;
72
+ /** A client for one repository, with a token already in hand. */
73
+ export declare function makeGitHubApi(deps: {
74
+ owner: string;
75
+ repo: string;
76
+ token: string;
77
+ fetch?: Fetch;
78
+ }): GitHubApi;
79
+ export type RunText = (bin: string, args: readonly string[], stdin: string, cwd: string) => Promise<{
80
+ code: number;
81
+ stdout: string;
82
+ }>;
83
+ /** `gh` on PATH, as an absolute path (never resolved from the cwd), or null. */
84
+ export declare function ghBinary(env?: NodeJS.ProcessEnv): string | null;
85
+ /**
86
+ * A token for github.com, and where it came from; null when this machine has
87
+ * none Looply can use. Order: `gh auth token`, then git's credential helper.
88
+ */
89
+ export declare function githubToken(deps?: {
90
+ run?: RunText;
91
+ gh?: string | null;
92
+ git?: string | null;
93
+ cwd?: string;
94
+ }): Promise<{
95
+ token: string;
96
+ from: 'gh' | 'git-credential';
97
+ } | null>;
98
+ export {};
99
+ //# sourceMappingURL=github-api.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"github-api.d.ts","sourceRoot":"","sources":["../src/github-api.ts"],"names":[],"mappings":"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"}