@smoothbricks/cli 0.4.2 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAKA,wBAAsB,MAAM,CAAC,IAAI,WAAwB,GAAG,OAAO,CAAC,IAAI,CAAC,CAexE"}
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAMA,wBAAsB,MAAM,CAAC,IAAI,WAAwB,GAAG,OAAO,CAAC,IAAI,CAAC,CAexE"}
package/dist/cli.js CHANGED
@@ -2,6 +2,7 @@ import { Command, CommanderError } from 'commander';
2
2
  import { variants } from './generate/index.js';
3
3
  import { cliPackageVersion } from './lib/cli-package.js';
4
4
  import { findRepoRoot } from './lib/run.js';
5
+ import { resolvePrConflicts } from './pr/index.js';
5
6
  export async function runCli(argv = process.argv.slice(2)) {
6
7
  const program = buildProgram();
7
8
  try {
@@ -278,6 +279,17 @@ function buildProgram() {
278
279
  const { githubCiNxDeploy } = await import('./github-ci/index.js');
279
280
  await githubCiNxDeploy(await findRepoRoot(), options);
280
281
  });
282
+ const pr = program.command('pr').description('Work with GitHub pull requests');
283
+ pr.command('resolve [pr]')
284
+ .description('Resolve conflict markers in a PR (agent-first, two-phase)')
285
+ .option('--remote <name>', 'git remote hosting the PR branch (auto-inferred when omitted)')
286
+ .option('--abort', 'discard an in-progress resolution and return to the original branch')
287
+ .action(async (prArg, options) => {
288
+ const exitCode = await resolvePrConflicts(await findRepoRoot(), prArg, options);
289
+ if (exitCode !== 0) {
290
+ process.exitCode = exitCode;
291
+ }
292
+ });
281
293
  return program;
282
294
  }
283
295
  function booleanOption(value) {
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Shared detection of Git merge-conflict markers.
3
+ *
4
+ * Real conflict markers always sit at column 0 and are a 7-character run of
5
+ * `<`, `|`, or `>` followed by a space (the diff3 base marker `|||||||` and the
6
+ * ours/theirs markers `<<<<<<< ` / `>>>>>>> `). We deliberately do NOT match a
7
+ * bare `=======` separator: it is ambiguous with Markdown h1 underlines and adds
8
+ * no signal (a real conflict always carries the angle/pipe markers too). The
9
+ * column-0 anchor also means quoted marker strings inside source (which are
10
+ * indented) never false-positive.
11
+ */
12
+ export declare const CONFLICT_MARKER_PATTERN = "^(<<<<<<< |\\|\\|\\|\\|\\|\\|\\| |>>>>>>> )";
13
+ export interface ConflictMarkerHit {
14
+ /** Repo-relative path of the offending file. */
15
+ readonly file: string;
16
+ /** 1-based line numbers carrying a conflict marker. */
17
+ readonly lines: number[];
18
+ }
19
+ /** 1-based line numbers of every conflict-marker line in `text`. */
20
+ export declare function findMarkerLines(text: string): number[];
21
+ export interface MarkerScanShell {
22
+ runResult(command: string, args: string[], cwd: string): Promise<{
23
+ exitCode: number;
24
+ stdout: string;
25
+ stderr: string;
26
+ }>;
27
+ }
28
+ /**
29
+ * Scan tracked files in the working tree for conflict markers via `git grep`.
30
+ * `pathspecs` optionally restricts the scan (e.g. release package roots).
31
+ */
32
+ export declare function scanTrackedForMarkers(shell: MarkerScanShell, root: string, pathspecs?: string[]): Promise<ConflictMarkerHit[]>;
33
+ /** Thrown by {@link assertNoConflictMarkers} so callers/tests can inspect the hits. */
34
+ export declare class ConflictMarkersError extends Error {
35
+ readonly hits: ConflictMarkerHit[];
36
+ constructor(hits: ConflictMarkerHit[], context: string);
37
+ }
38
+ /**
39
+ * Reusable publish/merge guard: throw {@link ConflictMarkersError} when any
40
+ * tracked file carries conflict markers. `context` names the blocked operation
41
+ * (e.g. `'publish'`) for the message.
42
+ */
43
+ export declare function assertNoConflictMarkers(shell: MarkerScanShell, root: string, context: string): Promise<void>;
44
+ /**
45
+ * Scan the files changed between `baseRef` and `headRef` (three-dot, i.e. since
46
+ * their merge base) for conflict markers, reading blobs at `headRef` — no
47
+ * checkout or working-tree mutation required.
48
+ */
49
+ export declare function scanRefChangedForMarkers(shell: MarkerScanShell, root: string, baseRef: string, headRef: string): Promise<ConflictMarkerHit[]>;
50
+ /** Parse `path:line:content` rows from `git grep -n` into per-file hits. */
51
+ export declare function parseGitGrep(stdout: string): ConflictMarkerHit[];
52
+ /** Human-readable one-liner summary of marker hits, e.g. for CLI output. */
53
+ export declare function formatMarkerHits(hits: ConflictMarkerHit[]): string;
54
+ //# sourceMappingURL=conflict-markers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"conflict-markers.d.ts","sourceRoot":"","sources":["../../src/lib/conflict-markers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,eAAO,MAAM,uBAAuB,gDAAgD,CAAC;AAIrF,MAAM,WAAW,iBAAiB;IAChC,gDAAgD;IAChD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,uDAAuD;IACvD,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,CAAC;CAC1B;AAED,oEAAoE;AACpE,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAStD;AAED,MAAM,WAAW,eAAe;IAC9B,SAAS,CACP,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EAAE,EACd,GAAG,EAAE,MAAM,GACV,OAAO,CAAC;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAClE;AAED;;;GAGG;AACH,wBAAsB,qBAAqB,CACzC,KAAK,EAAE,eAAe,EACtB,IAAI,EAAE,MAAM,EACZ,SAAS,GAAE,MAAM,EAAO,GACvB,OAAO,CAAC,iBAAiB,EAAE,CAAC,CAW9B;AAED,uFAAuF;AACvF,qBAAa,oBAAqB,SAAQ,KAAK;IAE3C,QAAQ,CAAC,IAAI,EAAE,iBAAiB,EAAE;gBAAzB,IAAI,EAAE,iBAAiB,EAAE,EAClC,OAAO,EAAE,MAAM;CAKlB;AAED;;;;GAIG;AACH,wBAAsB,uBAAuB,CAAC,KAAK,EAAE,eAAe,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAKlH;AAED;;;;GAIG;AACH,wBAAsB,wBAAwB,CAC5C,KAAK,EAAE,eAAe,EACtB,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,iBAAiB,EAAE,CAAC,CAkB9B;AAED,4EAA4E;AAC5E,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,iBAAiB,EAAE,CA2BhE;AAED,4EAA4E;AAC5E,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,iBAAiB,EAAE,GAAG,MAAM,CAElE"}
@@ -0,0 +1,118 @@
1
+ /**
2
+ * Shared detection of Git merge-conflict markers.
3
+ *
4
+ * Real conflict markers always sit at column 0 and are a 7-character run of
5
+ * `<`, `|`, or `>` followed by a space (the diff3 base marker `|||||||` and the
6
+ * ours/theirs markers `<<<<<<< ` / `>>>>>>> `). We deliberately do NOT match a
7
+ * bare `=======` separator: it is ambiguous with Markdown h1 underlines and adds
8
+ * no signal (a real conflict always carries the angle/pipe markers too). The
9
+ * column-0 anchor also means quoted marker strings inside source (which are
10
+ * indented) never false-positive.
11
+ */
12
+ export const CONFLICT_MARKER_PATTERN = '^(<<<<<<< |\\|\\|\\|\\|\\|\\|\\| |>>>>>>> )';
13
+ const conflictMarkerRe = new RegExp(CONFLICT_MARKER_PATTERN);
14
+ /** 1-based line numbers of every conflict-marker line in `text`. */
15
+ export function findMarkerLines(text) {
16
+ const hits = [];
17
+ const lines = text.split('\n');
18
+ for (let i = 0; i < lines.length; i++) {
19
+ if (conflictMarkerRe.test(lines[i])) {
20
+ hits.push(i + 1);
21
+ }
22
+ }
23
+ return hits;
24
+ }
25
+ /**
26
+ * Scan tracked files in the working tree for conflict markers via `git grep`.
27
+ * `pathspecs` optionally restricts the scan (e.g. release package roots).
28
+ */
29
+ export async function scanTrackedForMarkers(shell, root, pathspecs = []) {
30
+ const args = ['grep', '-nI', '-E', CONFLICT_MARKER_PATTERN];
31
+ if (pathspecs.length > 0) {
32
+ args.push('--', ...pathspecs);
33
+ }
34
+ const { exitCode, stdout, stderr } = await shell.runResult('git', args, root);
35
+ // git grep: 0 = matches found, 1 = no matches, >1 = error.
36
+ if (exitCode > 1) {
37
+ throw new Error(`git grep for conflict markers failed: ${stderr.trim() || `exit ${exitCode}`}`);
38
+ }
39
+ return parseGitGrep(stdout);
40
+ }
41
+ /** Thrown by {@link assertNoConflictMarkers} so callers/tests can inspect the hits. */
42
+ export class ConflictMarkersError extends Error {
43
+ hits;
44
+ constructor(hits, context) {
45
+ super(`Refusing to ${context}: conflict markers found in ${hits.length} file(s):\n${formatMarkerHits(hits)}`);
46
+ this.hits = hits;
47
+ this.name = 'ConflictMarkersError';
48
+ }
49
+ }
50
+ /**
51
+ * Reusable publish/merge guard: throw {@link ConflictMarkersError} when any
52
+ * tracked file carries conflict markers. `context` names the blocked operation
53
+ * (e.g. `'publish'`) for the message.
54
+ */
55
+ export async function assertNoConflictMarkers(shell, root, context) {
56
+ const hits = await scanTrackedForMarkers(shell, root);
57
+ if (hits.length > 0) {
58
+ throw new ConflictMarkersError(hits, context);
59
+ }
60
+ }
61
+ /**
62
+ * Scan the files changed between `baseRef` and `headRef` (three-dot, i.e. since
63
+ * their merge base) for conflict markers, reading blobs at `headRef` — no
64
+ * checkout or working-tree mutation required.
65
+ */
66
+ export async function scanRefChangedForMarkers(shell, root, baseRef, headRef) {
67
+ const diff = await shell.runResult('git', ['diff', '--name-only', `${baseRef}...${headRef}`], root);
68
+ if (diff.exitCode !== 0) {
69
+ throw new Error(`git diff ${baseRef}...${headRef} failed: ${diff.stderr.trim() || `exit ${diff.exitCode}`}`);
70
+ }
71
+ const files = diff.stdout.split('\n').filter((line) => line.length > 0);
72
+ const hits = [];
73
+ for (const file of files) {
74
+ const show = await shell.runResult('git', ['show', `${headRef}:${file}`, '--textconv'], root);
75
+ if (show.exitCode !== 0) {
76
+ continue; // deleted at head / binary / unreadable — not a marker source
77
+ }
78
+ const lines = findMarkerLines(show.stdout);
79
+ if (lines.length > 0) {
80
+ hits.push({ file, lines });
81
+ }
82
+ }
83
+ return hits;
84
+ }
85
+ /** Parse `path:line:content` rows from `git grep -n` into per-file hits. */
86
+ export function parseGitGrep(stdout) {
87
+ const byFile = new Map();
88
+ for (const row of stdout.split('\n')) {
89
+ if (row.length === 0) {
90
+ continue;
91
+ }
92
+ const firstColon = row.indexOf(':');
93
+ if (firstColon < 0) {
94
+ continue;
95
+ }
96
+ const secondColon = row.indexOf(':', firstColon + 1);
97
+ if (secondColon < 0) {
98
+ continue;
99
+ }
100
+ const file = row.slice(0, firstColon);
101
+ const line = Number.parseInt(row.slice(firstColon + 1, secondColon), 10);
102
+ if (!Number.isFinite(line)) {
103
+ continue;
104
+ }
105
+ const existing = byFile.get(file);
106
+ if (existing) {
107
+ existing.push(line);
108
+ }
109
+ else {
110
+ byFile.set(file, [line]);
111
+ }
112
+ }
113
+ return [...byFile.entries()].map(([file, lines]) => ({ file, lines }));
114
+ }
115
+ /** Human-readable one-liner summary of marker hits, e.g. for CLI output. */
116
+ export function formatMarkerHits(hits) {
117
+ return hits.map((hit) => ` ${hit.file} (lines ${hit.lines.join(', ')})`).join('\n');
118
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../src/lib/run.ts"],"names":[],"mappings":"AAMA,wBAAsB,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAKnH;AAED,wBAAsB,SAAS,CAC7B,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EAAE,EACd,GAAG,EAAE,MAAM,EACX,KAAK,UAAQ,EACb,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC3B,OAAO,CAAC,MAAM,CAAC,CAQjB;AAED,wBAAsB,oBAAoB,CACxC,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EAAE,EACd,GAAG,EAAE,MAAM,EACX,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC3B,OAAO,CAAC,MAAM,CAAC,CAiBjB;AAED,wBAAsB,SAAS,CAC7B,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EAAE,EACd,GAAG,EAAE,MAAM,EACX,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC3B,OAAO,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CAY/D;AAED,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAOvE;AAuCD,wBAAsB,YAAY,IAAI,OAAO,CAAC,MAAM,CAAC,CAMpD;AAED,wBAAgB,MAAM,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAEhD"}
1
+ {"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../src/lib/run.ts"],"names":[],"mappings":"AAMA,wBAAsB,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAKnH;AAED,wBAAsB,SAAS,CAC7B,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EAAE,EACd,GAAG,EAAE,MAAM,EACX,KAAK,UAAQ,EACb,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC3B,OAAO,CAAC,MAAM,CAAC,CAQjB;AAED,wBAAsB,oBAAoB,CACxC,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EAAE,EACd,GAAG,EAAE,MAAM,EACX,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC3B,OAAO,CAAC,MAAM,CAAC,CAiBjB;AAED,wBAAsB,SAAS,CAC7B,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EAAE,EACd,GAAG,EAAE,MAAM,EACX,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC3B,OAAO,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CAY/D;AAED,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAOvE;AAmCD,wBAAsB,YAAY,IAAI,OAAO,CAAC,MAAM,CAAC,CAMpD;AAED,wBAAgB,MAAM,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAEhD"}
package/dist/lib/run.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { spawn } from 'node:child_process';
2
2
  import { existsSync } from 'node:fs';
3
- import { dirname, join } from 'node:path';
3
+ import { join } from 'node:path';
4
4
  import { fileURLToPath } from 'node:url';
5
5
  import { $ } from 'bun';
6
6
  export async function run(command, args, cwd, env) {
@@ -82,10 +82,6 @@ function resolveBundledCommand(command) {
82
82
  if (command === 'sherif') {
83
83
  return fileURLToPath(import.meta.resolve('sherif'));
84
84
  }
85
- if (command === 'attw') {
86
- const packageJson = fileURLToPath(import.meta.resolve('@arethetypeswrong/cli/package.json'));
87
- return join(dirname(packageJson), 'dist', 'index.js');
88
- }
89
85
  }
90
86
  catch {
91
87
  return null;
@@ -1 +1 @@
1
- {"version":3,"file":"packed-package.d.ts","sourceRoot":"","sources":["../../src/monorepo/packed-package.ts"],"names":[],"mappings":"AAUA,wBAAsB,4BAA4B,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAMhF;AAED,wBAAsB,kCAAkC,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAMtF;AAED,wBAAsB,mCAAmC,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAMvF;AAED,wBAAsB,gCAAgC,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAMpF"}
1
+ {"version":3,"file":"packed-package.d.ts","sourceRoot":"","sources":["../../src/monorepo/packed-package.ts"],"names":[],"mappings":"AAYA,wBAAsB,4BAA4B,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAMhF;AAED,wBAAsB,kCAAkC,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAMtF;AAED,wBAAsB,mCAAmC,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAMvF;AAED,wBAAsB,gCAAgC,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAMpF"}
@@ -1,5 +1,7 @@
1
- import { readFileSync, rmSync, unlinkSync } from 'node:fs';
2
- import { join } from 'node:path';
1
+ import { mkdtempSync, readdirSync, readFileSync, rmSync, statSync, unlinkSync } from 'node:fs';
2
+ import { tmpdir } from 'node:os';
3
+ import { dirname, join, relative } from 'node:path';
4
+ import { fileURLToPath, pathToFileURL } from 'node:url';
3
5
  import { publint } from 'publint';
4
6
  import { formatMessage } from 'publint/utils';
5
7
  import { isRecord } from '../lib/json.js';
@@ -65,37 +67,143 @@ async function validatePackedManifest(root, pkg, packed) {
65
67
  return failures;
66
68
  }
67
69
  async function validateAttw(root, pkg, packed) {
68
- const attwArgs = [
69
- packed.path,
70
- '--format',
71
- 'ascii',
72
- '--no-color',
73
- '--profile',
74
- 'node16',
75
- '--ignore-rules',
76
- 'cjs-resolves-to-esm',
77
- ...attwExcludedEntrypointArgs(pkg),
78
- ];
79
- const attw = await runResult('attw', attwArgs, root);
80
- if (attw.exitCode === 0) {
70
+ const attw = await loadAttwCore();
71
+ const analysis = await attw.checkPackage(await createAttwPackageFromTarball(attw, root, packed.path), {
72
+ excludeEntrypoints: wasmExportEntrypoints(pkg.json.exports),
73
+ });
74
+ if (!isRecord(analysis) || analysis.types === false) {
81
75
  return 0;
82
76
  }
83
- printAttwOutput(attw.stdout);
84
- printAttwOutput(attw.stderr);
77
+ const rawProblems = Array.isArray(analysis.problems) ? analysis.problems : [];
78
+ const problems = rawProblems.filter(isReportedAttwProblem);
79
+ if (problems.length === 0) {
80
+ return 0;
81
+ }
82
+ for (const problem of problems) {
83
+ console.error(`${pkg.path}: are-the-types-wrong ${problem.kind}${formatProblemLocation(problem)}`);
84
+ }
85
85
  console.error(`${pkg.path}: are-the-types-wrong validation failed`);
86
86
  return 1;
87
87
  }
88
- function printAttwOutput(output) {
89
- for (const line of output.split('\n')) {
90
- if (!line || line.includes('(ignored)')) {
88
+ async function loadAttwCore() {
89
+ const packageJson = fileURLToPath(import.meta.resolve('@arethetypeswrong/core/package.json'));
90
+ const core = await import(pathToFileURL(join(dirname(packageJson), 'dist', 'index.js')).href);
91
+ if (!isRecord(core)) {
92
+ throw new Error('@arethetypeswrong/core does not expose the expected API');
93
+ }
94
+ const PackageConstructor = core.Package;
95
+ const checkPackage = core.checkPackage;
96
+ if (typeof PackageConstructor !== 'function' || typeof checkPackage !== 'function') {
97
+ throw new Error('@arethetypeswrong/core does not expose the expected API');
98
+ }
99
+ return {
100
+ createPackage: (files, packageName, packageVersion) => Reflect.construct(PackageConstructor, [files, packageName, packageVersion]),
101
+ checkPackage: (pkg, options) => Promise.resolve(checkPackage(pkg, options)),
102
+ };
103
+ }
104
+ async function createAttwPackageFromTarball(attw, root, tarballPath) {
105
+ const temp = mkdtempSync(join(tmpdir(), 'smoo-attw-'));
106
+ try {
107
+ const extract = await runResult('tar', ['-xzf', tarballPath, '-C', temp], root);
108
+ if (extract.exitCode !== 0) {
109
+ printCommandOutput(extract.stdout, extract.stderr);
110
+ throw new Error('unable to extract packed package for are-the-types-wrong');
111
+ }
112
+ return createAttwPackageFromDirectory(attw, join(temp, 'package'));
113
+ }
114
+ finally {
115
+ rmSync(temp, { recursive: true, force: true });
116
+ }
117
+ }
118
+ function createAttwPackageFromDirectory(attw, packageDir) {
119
+ const packageJson = readJsonFile(join(packageDir, 'package.json'));
120
+ const packageName = typeof packageJson.name === 'string' ? packageJson.name : null;
121
+ const packageVersion = typeof packageJson.version === 'string' ? packageJson.version : null;
122
+ if (!packageName || !packageVersion) {
123
+ throw new Error('packed package.json must contain name and version');
124
+ }
125
+ const files = {};
126
+ collectAttwFiles(packageDir, packageDir, packageName, files);
127
+ return attw.createPackage(files, packageName, packageVersion);
128
+ }
129
+ function collectAttwFiles(root, current, packageName, files) {
130
+ for (const entry of readdirSync(current)) {
131
+ const path = join(current, entry);
132
+ const stat = statSync(path);
133
+ if (stat.isDirectory()) {
134
+ collectAttwFiles(root, path, packageName, files);
91
135
  continue;
92
136
  }
93
- console.error(line);
137
+ if (!stat.isFile()) {
138
+ continue;
139
+ }
140
+ const packageRelativePath = relative(root, path).split('\\').join('/');
141
+ files[`/node_modules/${packageName}/${packageRelativePath}`] = new Uint8Array(readFileSync(path));
142
+ }
143
+ }
144
+ function readJsonFile(path) {
145
+ const parsed = JSON.parse(readFileSync(path, 'utf8'));
146
+ if (!isRecord(parsed)) {
147
+ throw new Error(`${path} is not a JSON object`);
148
+ }
149
+ return parsed;
150
+ }
151
+ function isReportedAttwProblem(problem) {
152
+ if (!isRecord(problem) || typeof problem.kind !== 'string') {
153
+ return false;
154
+ }
155
+ const flag = attwProblemFlag(problem.kind);
156
+ if (flag === 'cjs-resolves-to-esm') {
157
+ return false;
94
158
  }
159
+ return problem.resolutionKind !== 'node10';
95
160
  }
96
- function attwExcludedEntrypointArgs(pkg) {
97
- const excluded = wasmExportEntrypoints(pkg.json.exports);
98
- return excluded.length === 0 ? [] : ['--exclude-entrypoints', ...excluded];
161
+ function attwProblemFlag(kind) {
162
+ switch (kind) {
163
+ case 'NoResolution':
164
+ return 'no-resolution';
165
+ case 'UntypedResolution':
166
+ return 'untyped-resolution';
167
+ case 'FalseCJS':
168
+ return 'false-cjs';
169
+ case 'FalseESM':
170
+ return 'false-esm';
171
+ case 'CJSResolvesToESM':
172
+ return 'cjs-resolves-to-esm';
173
+ case 'FallbackCondition':
174
+ return 'fallback-condition';
175
+ case 'CJSOnlyExportsDefault':
176
+ return 'cjs-only-exports-default';
177
+ case 'NamedExports':
178
+ return 'named-exports';
179
+ case 'FalseExportDefault':
180
+ return 'false-export-default';
181
+ case 'MissingExportEquals':
182
+ return 'missing-export-equals';
183
+ case 'UnexpectedModuleSyntax':
184
+ return 'unexpected-module-syntax';
185
+ case 'InternalResolutionError':
186
+ return 'internal-resolution-error';
187
+ default:
188
+ return null;
189
+ }
190
+ }
191
+ function formatProblemLocation(problem) {
192
+ if (!isRecord(problem)) {
193
+ return '';
194
+ }
195
+ const entrypoint = typeof problem.entrypoint === 'string' ? ` ${problem.entrypoint}` : '';
196
+ const resolution = typeof problem.resolutionKind === 'string' ? ` ${formatResolutionKind(problem.resolutionKind)}` : '';
197
+ return `${entrypoint}${resolution}`;
198
+ }
199
+ function formatResolutionKind(kind) {
200
+ if (kind === 'node16-cjs') {
201
+ return 'node16 (from CJS)';
202
+ }
203
+ if (kind === 'node16-esm') {
204
+ return 'node16 (from ESM)';
205
+ }
206
+ return kind;
99
207
  }
100
208
  function wasmExportEntrypoints(exports) {
101
209
  if (!isRecord(exports)) {
@@ -0,0 +1,27 @@
1
+ /** 0 = clean/done, 2 = action required (conflicts to resolve), 1 = usage/error. */
2
+ export type PrResolveExit = 0 | 1 | 2;
3
+ export interface PrResolveOptions {
4
+ /** Git remote hosting the PR branch. Auto-inferred from the PR repo when omitted. */
5
+ remote?: string;
6
+ /** Abort an in-progress resolution: restore the original branch, drop state. */
7
+ abort?: boolean;
8
+ }
9
+ export interface PrResolveShell {
10
+ runResult(command: string, args: string[], cwd: string): Promise<{
11
+ exitCode: number;
12
+ stdout: string;
13
+ stderr: string;
14
+ }>;
15
+ run(command: string, args: string[], cwd: string): Promise<void>;
16
+ }
17
+ /**
18
+ * Agent-first conflict resolution for a GitHub PR.
19
+ *
20
+ * First run (pointed at a PR): reports the conflict markers and, if any, checks
21
+ * out the PR branch and instructs the next step. Second run (on that branch,
22
+ * after the human/agent has resolved + committed): verifies no markers remain,
23
+ * pushes, and returns to the original branch. Idempotent via a state file under
24
+ * the git dir.
25
+ */
26
+ export declare function resolvePrConflicts(root: string, prArg: string | undefined, options: PrResolveOptions, shell?: PrResolveShell): Promise<PrResolveExit>;
27
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/pr/index.ts"],"names":[],"mappings":"AAMA,mFAAmF;AACnF,MAAM,MAAM,aAAa,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;AAEtC,MAAM,WAAW,gBAAgB;IAC/B,qFAAqF;IACrF,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,gFAAgF;IAChF,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED,MAAM,WAAW,cAAc;IAC7B,SAAS,CACP,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EAAE,EACd,GAAG,EAAE,MAAM,GACV,OAAO,CAAC;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACjE,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAClE;AA6BD;;;;;;;;GAQG;AACH,wBAAsB,kBAAkB,CACtC,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,GAAG,SAAS,EACzB,OAAO,EAAE,gBAAgB,EACzB,KAAK,GAAE,cAA6B,GACnC,OAAO,CAAC,aAAa,CAAC,CAWxB"}