@remogram/cli 0.1.0-beta.0 → 0.1.0-beta.2

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 (2) hide show
  1. package/index.js +95 -18
  2. package/package.json +7 -7
package/index.js CHANGED
@@ -16,6 +16,9 @@ import {
16
16
  sanitizeField,
17
17
  assertGitRef,
18
18
  assertGitRemote,
19
+ getEffectiveIngestMaxBytes,
20
+ FORGE_INGEST_MAX_BYTES_ENV,
21
+ throwIfStaleHeadByNumber,
19
22
  } from '@remogram/core';
20
23
  import { provider as giteaApi } from '@remogram/provider-gitea-api';
21
24
  import { provider as githubApi } from '@remogram/provider-github-api';
@@ -57,6 +60,11 @@ function handleError(err, ctx, asJson) {
57
60
  remoteName: 'origin',
58
61
  repoId: 'unknown/unknown',
59
62
  };
63
+ if (err.staleHeadPacket) {
64
+ output(forgePacket(err.staleHeadPacket.type, baseCtx, err.staleHeadPacket.body, fe), asJson);
65
+ process.exitCode = 1;
66
+ return;
67
+ }
60
68
  output(forgeErrorPacket(baseCtx, fe), asJson);
61
69
  process.exitCode = 1;
62
70
  }
@@ -87,6 +95,24 @@ function contextFromConfig(config, cwd, parsed = null) {
87
95
  };
88
96
  }
89
97
 
98
+ function finalizeDoctorPacket(ctx, checks, providerCapabilities) {
99
+ const summary = doctorSummary(checks);
100
+ const error =
101
+ summary === 'fail'
102
+ ? forgeError(ERROR_CODES.CONFIG_INVALID, 'Doctor checks failed')
103
+ : null;
104
+ return forgePacket(
105
+ PACKET_TYPES.PROVIDER_DOCTOR,
106
+ ctx,
107
+ {
108
+ summary,
109
+ checks,
110
+ provider_capabilities: providerCapabilities,
111
+ },
112
+ error,
113
+ );
114
+ }
115
+
90
116
  async function buildDoctorPacket(cwd, providers) {
91
117
  const checks = [];
92
118
  const configPath = findConfigPath(cwd);
@@ -98,11 +124,7 @@ async function buildDoctorPacket(cwd, providers) {
98
124
 
99
125
  if (!configPath) {
100
126
  checks.push(doctorCheck('config', 'fail', 'No .remogram.json found'));
101
- return forgePacket(PACKET_TYPES.PROVIDER_DOCTOR, ctx, {
102
- summary: doctorSummary(checks),
103
- checks,
104
- provider_capabilities: null,
105
- });
127
+ return finalizeDoctorPacket(ctx, checks, null);
106
128
  }
107
129
 
108
130
  try {
@@ -112,22 +134,30 @@ async function buildDoctorPacket(cwd, providers) {
112
134
  checks.push(doctorCheck('config', 'pass', '.remogram.json is present and valid'));
113
135
  } catch (err) {
114
136
  checks.push(doctorCheck('config', 'fail', err.forgeError?.message || err.message));
115
- return forgePacket(PACKET_TYPES.PROVIDER_DOCTOR, ctx, {
116
- summary: doctorSummary(checks),
117
- checks,
118
- provider_capabilities: null,
119
- });
137
+ return finalizeDoctorPacket(ctx, checks, null);
120
138
  }
121
139
 
122
140
  const provider = providers[config.provider];
123
141
  if (!provider) {
124
142
  checks.push(doctorCheck('provider', 'fail', `Unsupported provider: ${config.provider}`));
125
143
  } else {
126
- checks.push(doctorCheck('provider', 'pass', `${config.provider} is registered`));
127
144
  if (typeof provider.providerCapabilities === 'function') {
128
145
  providerCapabilities = await provider.providerCapabilities(ctx);
146
+ const stubProvider =
147
+ providerCapabilities.commands?.length > 0
148
+ && providerCapabilities.commands.every((command) => command.implemented === false);
149
+ checks.push(
150
+ doctorCheck(
151
+ 'provider',
152
+ stubProvider ? 'warn' : 'pass',
153
+ stubProvider
154
+ ? `${config.provider} is not fully supported in v1; use an *-api provider`
155
+ : `${config.provider} is registered`,
156
+ ),
157
+ );
129
158
  checks.push(doctorCheck('capabilities', 'pass', 'Provider capabilities are available'));
130
159
  } else {
160
+ checks.push(doctorCheck('provider', 'pass', `${config.provider} is registered`));
131
161
  checks.push(doctorCheck('capabilities', 'fail', 'Provider capabilities are not implemented'));
132
162
  }
133
163
  }
@@ -189,13 +219,40 @@ async function buildDoctorPacket(cwd, providers) {
189
219
  }
190
220
  }
191
221
 
222
+ const { bytes: ingestCapBytes, envOverride: ingestEnvOverride, invalidEnv: ingestInvalidEnv } =
223
+ getEffectiveIngestMaxBytes();
224
+ if (ingestInvalidEnv) {
225
+ checks.push(
226
+ doctorCheck(
227
+ 'forge_ingest_cap',
228
+ 'warn',
229
+ `${FORGE_INGEST_MAX_BYTES_ENV} is invalid; using default 8192 bytes`,
230
+ { effective_bytes: ingestCapBytes, env_override: false },
231
+ ),
232
+ );
233
+ } else if (ingestEnvOverride) {
234
+ checks.push(
235
+ doctorCheck(
236
+ 'forge_ingest_cap',
237
+ 'warn',
238
+ `${FORGE_INGEST_MAX_BYTES_ENV} overrides default ingest cap; agent-safe guarantee is weakened`,
239
+ { effective_bytes: ingestCapBytes, env_override: true },
240
+ ),
241
+ );
242
+ } else {
243
+ checks.push(
244
+ doctorCheck(
245
+ 'forge_ingest_cap',
246
+ 'pass',
247
+ 'Forge HTTP ingest cap is default 8192 bytes',
248
+ { effective_bytes: ingestCapBytes, env_override: false },
249
+ ),
250
+ );
251
+ }
252
+
192
253
  checks.push(doctorCheck('api_reachability', 'skipped', 'Live API reachability is not checked by default'));
193
254
 
194
- return forgePacket(PACKET_TYPES.PROVIDER_DOCTOR, ctx, {
195
- summary: doctorSummary(checks),
196
- checks,
197
- provider_capabilities: providerCapabilities,
198
- });
255
+ return finalizeDoctorPacket(ctx, checks, providerCapabilities);
199
256
  }
200
257
 
201
258
  export async function runCli(argv, options = {}) {
@@ -225,7 +282,9 @@ export async function runCli(argv, options = {}) {
225
282
  const [group, sub] = positional;
226
283
 
227
284
  if (group === 'doctor' && sub == null) {
228
- output(await buildDoctorPacket(cwd, providers), asJson);
285
+ const packet = await buildDoctorPacket(cwd, providers);
286
+ output(packet, asJson);
287
+ if (!packet.ok) process.exitCode = 1;
229
288
  return;
230
289
  }
231
290
 
@@ -284,7 +343,15 @@ export async function runCli(argv, options = {}) {
284
343
  forgeError: forgeError(ERROR_CODES.INVALID_ARGS, '--number required for pr view'),
285
344
  });
286
345
  }
287
- packet = forgePacket(PACKET_TYPES.PR_STATUS, ctx, await provider.prView(ctx, { number }));
346
+ const body = await provider.prView(ctx, { number });
347
+ throwIfStaleHeadByNumber(
348
+ ctx,
349
+ PACKET_TYPES.PR_STATUS,
350
+ body,
351
+ body.head_ref,
352
+ body.head_sha,
353
+ );
354
+ packet = forgePacket(PACKET_TYPES.PR_STATUS, ctx, body);
288
355
  } else if (group === 'pr' && sub === 'checks') {
289
356
  const number = parsePositiveInt(flags.number, '--number');
290
357
  if (number == null && !flags.ref) {
@@ -293,6 +360,16 @@ export async function runCli(argv, options = {}) {
293
360
  });
294
361
  }
295
362
  if (flags.ref) assertGitRef(flags.ref, '--ref');
363
+ if (number != null && !flags.ref) {
364
+ const view = await provider.prView(ctx, { number });
365
+ throwIfStaleHeadByNumber(
366
+ ctx,
367
+ PACKET_TYPES.PR_CHECKS,
368
+ { head_sha: view.head_sha },
369
+ view.head_ref,
370
+ view.head_sha,
371
+ );
372
+ }
296
373
  packet = forgePacket(
297
374
  PACKET_TYPES.PR_CHECKS,
298
375
  ctx,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@remogram/cli",
3
- "version": "0.1.0-beta.0",
3
+ "version": "0.1.0-beta.2",
4
4
  "description": "Remogram forge boundary CLI",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -27,11 +27,11 @@
27
27
  "node": ">=20"
28
28
  },
29
29
  "dependencies": {
30
- "@remogram/core": "0.1.0-beta.0",
31
- "@remogram/provider-gitea-api": "0.1.0-beta.0",
32
- "@remogram/provider-github-api": "0.1.0-beta.0",
33
- "@remogram/provider-gitlab-api": "0.1.0-beta.0",
34
- "@remogram/provider-gitea-tea": "0.1.0-beta.0",
35
- "@remogram/provider-github-gh": "0.1.0-beta.0"
30
+ "@remogram/core": "0.1.0-beta.2",
31
+ "@remogram/provider-gitea-api": "0.1.0-beta.2",
32
+ "@remogram/provider-github-api": "0.1.0-beta.2",
33
+ "@remogram/provider-gitlab-api": "0.1.0-beta.2",
34
+ "@remogram/provider-gitea-tea": "0.1.0-beta.2",
35
+ "@remogram/provider-github-gh": "0.1.0-beta.2"
36
36
  }
37
37
  }