@on-par/factory-core 0.9.27 → 0.9.28-next.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 (89) hide show
  1. package/dist/blockers/declared-prerequisites.d.ts +4 -1
  2. package/dist/blockers/declared-prerequisites.d.ts.map +1 -1
  3. package/dist/blockers/declared-prerequisites.js +10 -5
  4. package/dist/blockers/declared-prerequisites.js.map +1 -1
  5. package/dist/config/example.d.ts.map +1 -1
  6. package/dist/config/example.js +6 -0
  7. package/dist/config/example.js.map +1 -1
  8. package/dist/config/index.d.ts +18 -0
  9. package/dist/config/index.d.ts.map +1 -1
  10. package/dist/config/index.js +3 -0
  11. package/dist/config/index.js.map +1 -1
  12. package/dist/config/runtime-config-keys.d.ts.map +1 -1
  13. package/dist/config/runtime-config-keys.js +1 -0
  14. package/dist/config/runtime-config-keys.js.map +1 -1
  15. package/dist/config/tracker-section.d.ts +39 -0
  16. package/dist/config/tracker-section.d.ts.map +1 -0
  17. package/dist/config/tracker-section.js +31 -0
  18. package/dist/config/tracker-section.js.map +1 -0
  19. package/dist/events/queue-traits.d.ts +1 -1
  20. package/dist/events/queue-traits.d.ts.map +1 -1
  21. package/dist/events/queue-traits.js +5 -1
  22. package/dist/events/queue-traits.js.map +1 -1
  23. package/dist/filing/redact.d.ts +1 -0
  24. package/dist/filing/redact.d.ts.map +1 -1
  25. package/dist/filing/redact.js +1 -1
  26. package/dist/filing/redact.js.map +1 -1
  27. package/dist/internal.d.ts +5 -0
  28. package/dist/internal.d.ts.map +1 -1
  29. package/dist/internal.js +5 -0
  30. package/dist/internal.js.map +1 -1
  31. package/dist/phases/ship-ci-watch.d.ts +25 -0
  32. package/dist/phases/ship-ci-watch.d.ts.map +1 -0
  33. package/dist/phases/ship-ci-watch.js +53 -0
  34. package/dist/phases/ship-ci-watch.js.map +1 -0
  35. package/dist/phases/ship-pr-lookup.d.ts +8 -0
  36. package/dist/phases/ship-pr-lookup.d.ts.map +1 -0
  37. package/dist/phases/ship-pr-lookup.js +41 -0
  38. package/dist/phases/ship-pr-lookup.js.map +1 -0
  39. package/dist/phases/ship-recovery.d.ts +16 -0
  40. package/dist/phases/ship-recovery.d.ts.map +1 -0
  41. package/dist/phases/ship-recovery.js +81 -0
  42. package/dist/phases/ship-recovery.js.map +1 -0
  43. package/dist/phases/ship-types.d.ts +36 -0
  44. package/dist/phases/ship-types.d.ts.map +1 -0
  45. package/dist/phases/ship-types.js +2 -0
  46. package/dist/phases/ship-types.js.map +1 -0
  47. package/dist/phases/ship.d.ts +6 -41
  48. package/dist/phases/ship.d.ts.map +1 -1
  49. package/dist/phases/ship.js +33 -171
  50. package/dist/phases/ship.js.map +1 -1
  51. package/dist/queue/linear-queue-lifecycle.d.ts +62 -0
  52. package/dist/queue/linear-queue-lifecycle.d.ts.map +1 -0
  53. package/dist/queue/linear-queue-lifecycle.js +139 -0
  54. package/dist/queue/linear-queue-lifecycle.js.map +1 -0
  55. package/dist/queue/linear-queue.d.ts +49 -0
  56. package/dist/queue/linear-queue.d.ts.map +1 -0
  57. package/dist/queue/linear-queue.js +258 -0
  58. package/dist/queue/linear-queue.js.map +1 -0
  59. package/dist/queue/queue-backend.d.ts +25 -6
  60. package/dist/queue/queue-backend.d.ts.map +1 -1
  61. package/dist/queue/queue-backend.js +35 -6
  62. package/dist/queue/queue-backend.js.map +1 -1
  63. package/dist/run/pr-run-state.d.ts +99 -0
  64. package/dist/run/pr-run-state.d.ts.map +1 -0
  65. package/dist/run/pr-run-state.js +235 -0
  66. package/dist/run/pr-run-state.js.map +1 -0
  67. package/dist/run/state.d.ts +9 -5
  68. package/dist/run/state.d.ts.map +1 -1
  69. package/dist/run/state.js +37 -13
  70. package/dist/run/state.js.map +1 -1
  71. package/dist/types/index.d.ts +3 -0
  72. package/dist/types/index.d.ts.map +1 -1
  73. package/dist/work/index.d.ts +2 -2
  74. package/dist/work/index.d.ts.map +1 -1
  75. package/dist/work/index.js +4 -2
  76. package/dist/work/index.js.map +1 -1
  77. package/dist/work/linear-client.d.ts +21 -0
  78. package/dist/work/linear-client.d.ts.map +1 -0
  79. package/dist/work/linear-client.js +69 -0
  80. package/dist/work/linear-client.js.map +1 -0
  81. package/dist/work/linear-issue.d.ts +11 -0
  82. package/dist/work/linear-issue.d.ts.map +1 -0
  83. package/dist/work/linear-issue.js +69 -0
  84. package/dist/work/linear-issue.js.map +1 -0
  85. package/dist/work/linear-preflight.d.ts +21 -0
  86. package/dist/work/linear-preflight.d.ts.map +1 -0
  87. package/dist/work/linear-preflight.js +67 -0
  88. package/dist/work/linear-preflight.js.map +1 -0
  89. package/package.json +5 -5
@@ -0,0 +1,69 @@
1
+ // packages/core/src/work/linear-client.ts — read-only Linear GraphQL client (#3889).
2
+ import { z } from 'zod';
3
+ const LINEAR_GRAPHQL_ENDPOINT = 'https://api.linear.app/graphql';
4
+ const ISSUE_QUERY = `query FactoryIssue($id: String!) {
5
+ issue(id: $id) {
6
+ id identifier title description url
7
+ state { type }
8
+ labels { nodes { name } }
9
+ }
10
+ }`;
11
+ const IssueSchema = z.object({
12
+ id: z.string().min(1),
13
+ identifier: z.string().min(1),
14
+ title: z.string(),
15
+ description: z.string().nullable().optional(),
16
+ url: z.url(),
17
+ state: z.object({ type: z.string() }),
18
+ labels: z.object({ nodes: z.array(z.object({ name: z.string() })) }),
19
+ });
20
+ const ResponseSchema = z.object({
21
+ data: z.object({ issue: IssueSchema.nullable() }).nullable().optional(),
22
+ errors: z.array(z.object({ message: z.string() })).optional(),
23
+ });
24
+ export class LinearApiError extends Error {
25
+ constructor(message) {
26
+ super(message);
27
+ this.name = 'LinearApiError';
28
+ }
29
+ }
30
+ export function createLinearClient(opts) {
31
+ const fetchImpl = opts.fetch ?? globalThis.fetch;
32
+ return {
33
+ async fetchIssue(ref) {
34
+ const res = await fetchImpl(opts.endpoint ?? LINEAR_GRAPHQL_ENDPOINT, {
35
+ method: 'POST',
36
+ headers: { 'Content-Type': 'application/json', Authorization: opts.apiKey },
37
+ body: JSON.stringify({ query: ISSUE_QUERY, variables: { id: ref } }),
38
+ signal: AbortSignal.timeout(opts.timeoutMs ?? 30_000),
39
+ });
40
+ if (!res.ok) {
41
+ throw new LinearApiError(`Linear API returned HTTP ${res.status} for ${ref}`);
42
+ }
43
+ const parsed = ResponseSchema.safeParse(await res.json());
44
+ if (!parsed.success) {
45
+ const first = parsed.error.issues[0];
46
+ const where = first ? `${first.path.join('.')}: ${first.message}` : 'unknown';
47
+ throw new LinearApiError(`malformed Linear response for ${ref}: ${where}`);
48
+ }
49
+ const { data, errors } = parsed.data;
50
+ if (errors && errors.length > 0) {
51
+ throw new LinearApiError(`Linear API error for ${ref}: ${errors.map((e) => e.message).join('; ')}`);
52
+ }
53
+ const issue = data?.issue;
54
+ if (issue == null) {
55
+ throw new LinearApiError(`Linear issue ${ref} not found`);
56
+ }
57
+ return {
58
+ id: issue.id,
59
+ identifier: issue.identifier,
60
+ title: issue.title,
61
+ description: issue.description ?? '',
62
+ url: issue.url,
63
+ stateType: issue.state.type,
64
+ labels: issue.labels.nodes.map((l) => l.name),
65
+ };
66
+ },
67
+ };
68
+ }
69
+ //# sourceMappingURL=linear-client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"linear-client.js","sourceRoot":"","sources":["../../src/work/linear-client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ import { type WorkSourceAdapter } from './index.js';
2
+ export declare const LINEAR_ISSUE_SOURCE = "linear-issue";
3
+ export interface LinearIssueSourceDeps {
4
+ fetch?: typeof globalThis.fetch;
5
+ env?: Readonly<Record<string, string | undefined>>;
6
+ endpoint?: string;
7
+ }
8
+ /** Turns "ON-12" or a linear.app issue URL into the upper-cased issue key. */
9
+ export declare function parseLinearIssueRef(input: string): string;
10
+ export declare function createLinearIssueAdapter(deps?: LinearIssueSourceDeps): WorkSourceAdapter;
11
+ //# sourceMappingURL=linear-issue.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"linear-issue.d.ts","sourceRoot":"","sources":["../../src/work/linear-issue.ts"],"names":[],"mappings":"AAGA,OAAO,EAAkD,KAAK,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAIpG,eAAO,MAAM,mBAAmB,iBAAiB,CAAC;AAOlD,MAAM,WAAW,qBAAqB;IACpC,KAAK,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,CAAC;IAChC,GAAG,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC,CAAC;IACnD,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAOD,8EAA8E;AAC9E,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAazD;AAUD,wBAAgB,wBAAwB,CAAC,IAAI,GAAE,qBAA0B,GAAG,iBAAiB,CA2B5F"}
@@ -0,0 +1,69 @@
1
+ // packages/core/src/work/linear-issue.ts — read-only Linear issue input-source adapter (#3889).
2
+ import { extractAcceptanceCriteria } from './acceptance.js';
3
+ import { InvalidWorkRequestInputError } from './index.js';
4
+ import { createLinearClient } from './linear-client.js';
5
+ import { toWorkKey } from './work-key.js';
6
+ export const LINEAR_ISSUE_SOURCE = 'linear-issue';
7
+ const EXPECTED_FORM = 'expected a Linear issue key like "ON-12" or a URL like https://linear.app/<workspace>/issue/ON-12';
8
+ const KEY_RE = /^[A-Za-z][A-Za-z0-9]*-[1-9]\d*$/;
9
+ const CLOSED_STATE_TYPES = new Set(['completed', 'canceled']);
10
+ function usageError(input) {
11
+ const shown = input.length > 200 ? `${input.slice(0, 200)}…` : input;
12
+ return new InvalidWorkRequestInputError(LINEAR_ISSUE_SOURCE, `${EXPECTED_FORM}, got "${shown}"`);
13
+ }
14
+ /** Turns "ON-12" or a linear.app issue URL into the upper-cased issue key. */
15
+ export function parseLinearIssueRef(input) {
16
+ const trimmed = input.trim();
17
+ if (KEY_RE.test(trimmed))
18
+ return trimmed.toUpperCase();
19
+ let url;
20
+ try {
21
+ url = new URL(trimmed);
22
+ }
23
+ catch {
24
+ throw usageError(trimmed);
25
+ }
26
+ if (url.protocol !== 'https:' || url.hostname !== 'linear.app')
27
+ throw usageError(trimmed);
28
+ const [workspace, segment, key] = url.pathname.split('/').filter((s) => s !== '');
29
+ if (!workspace || segment !== 'issue' || key === undefined || !KEY_RE.test(key))
30
+ throw usageError(trimmed);
31
+ return key.toUpperCase();
32
+ }
33
+ function rawRef(params) {
34
+ if (typeof params === 'string')
35
+ return params;
36
+ if (typeof params === 'object' && params !== null && 'ref' in params && typeof params.ref === 'string') {
37
+ return params.ref;
38
+ }
39
+ return undefined;
40
+ }
41
+ export function createLinearIssueAdapter(deps = {}) {
42
+ return {
43
+ kind: LINEAR_ISSUE_SOURCE,
44
+ async resolve(params) {
45
+ const raw = rawRef(params);
46
+ if (raw === undefined) {
47
+ throw new InvalidWorkRequestInputError(LINEAR_ISSUE_SOURCE, EXPECTED_FORM);
48
+ }
49
+ const ref = parseLinearIssueRef(raw);
50
+ const apiKey = (deps.env ?? process.env).LINEAR_API_KEY?.trim();
51
+ if (!apiKey) {
52
+ throw new Error('LINEAR_API_KEY is not set — export a Linear personal API key to resolve Linear issues');
53
+ }
54
+ const issue = await createLinearClient({ apiKey, fetch: deps.fetch, endpoint: deps.endpoint }).fetchIssue(ref);
55
+ return {
56
+ id: `${LINEAR_ISSUE_SOURCE}:${issue.identifier}`,
57
+ kind: LINEAR_ISSUE_SOURCE,
58
+ key: toWorkKey(issue.identifier),
59
+ title: issue.title,
60
+ brief: issue.description,
61
+ acceptanceCriteria: extractAcceptanceCriteria(issue.description),
62
+ state: CLOSED_STATE_TYPES.has(issue.stateType) ? 'closed' : 'open',
63
+ labels: issue.labels,
64
+ reference: { externalId: issue.id, url: issue.url },
65
+ };
66
+ },
67
+ };
68
+ }
69
+ //# sourceMappingURL=linear-issue.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"linear-issue.js","sourceRoot":"","sources":["../../src/work/linear-issue.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ import type { LinearTrackerConfig } from '../config/tracker-section.js';
2
+ export declare const LINEAR_API_KEY_ENV = "LINEAR_API_KEY";
3
+ export declare const LINEAR_GRAPHQL_URL = "https://api.linear.app/graphql";
4
+ export type LinearPreflightResult = {
5
+ kind: 'unauthorized';
6
+ } | {
7
+ kind: 'team-missing';
8
+ teamKey: string;
9
+ } | {
10
+ kind: 'error';
11
+ message: string;
12
+ } | {
13
+ kind: 'ok';
14
+ readyIssues: number;
15
+ unmappedProjects: string[];
16
+ };
17
+ export declare function probeLinearSetup(input: {
18
+ apiKey: string;
19
+ linear: LinearTrackerConfig;
20
+ }, fetchFn?: typeof fetch): Promise<LinearPreflightResult>;
21
+ //# sourceMappingURL=linear-preflight.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"linear-preflight.d.ts","sourceRoot":"","sources":["../../src/work/linear-preflight.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AAExE,eAAO,MAAM,kBAAkB,mBAAmB,CAAC;AACnD,eAAO,MAAM,kBAAkB,mCAAmC,CAAC;AAEnE,MAAM,MAAM,qBAAqB,GAC7B;IAAE,IAAI,EAAE,cAAc,CAAA;CAAE,GACxB;IAAE,IAAI,EAAE,cAAc,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GACzC;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAClC;IAAE,IAAI,EAAE,IAAI,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,gBAAgB,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC;AA2BpE,wBAAsB,gBAAgB,CACpC,KAAK,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,mBAAmB,CAAA;CAAE,EACtD,OAAO,GAAE,OAAO,KAAa,GAC5B,OAAO,CAAC,qBAAqB,CAAC,CA+ChC"}
@@ -0,0 +1,67 @@
1
+ export const LINEAR_API_KEY_ENV = 'LINEAR_API_KEY';
2
+ export const LINEAR_GRAPHQL_URL = 'https://api.linear.app/graphql';
3
+ const MAX_PAGES = 10;
4
+ const QUERY = `query($team: String!, $label: String!, $state: String!, $after: String) {
5
+ teams(filter: { key: { eq: $team } }) { nodes { id } }
6
+ issues(first: 100, after: $after, filter: { team: { key: { eq: $team } }, state: { name: { eq: $state } }, labels: { some: { name: { eq: $label } } } }) {
7
+ nodes { project { id name } }
8
+ pageInfo { hasNextPage endCursor }
9
+ }
10
+ }`;
11
+ export async function probeLinearSetup(input, fetchFn = fetch) {
12
+ const { apiKey, linear } = input;
13
+ const redact = (text) => text.split(apiKey).join('***');
14
+ const fail = (message) => ({ kind: 'error', message: redact(message) });
15
+ const projects = new Set();
16
+ let readyIssues = 0;
17
+ let after = null;
18
+ for (let page = 0; page < MAX_PAGES; page++) {
19
+ let res;
20
+ try {
21
+ res = await fetchFn(LINEAR_GRAPHQL_URL, {
22
+ method: 'POST',
23
+ headers: { 'Content-Type': 'application/json', Authorization: apiKey },
24
+ body: JSON.stringify({
25
+ query: QUERY,
26
+ variables: { team: linear.teamKey, label: linear.readyLabel, state: linear.states.ready, after },
27
+ }),
28
+ signal: AbortSignal.timeout(15_000),
29
+ });
30
+ }
31
+ catch (err) {
32
+ return fail(err instanceof Error ? err.message : String(err));
33
+ }
34
+ let body;
35
+ try {
36
+ body = (await res.json());
37
+ }
38
+ catch {
39
+ body = undefined;
40
+ }
41
+ const errors = body?.errors ?? [];
42
+ if (res.status === 401 || res.status === 403 || errors.some((e) => e.extensions?.code === 'AUTHENTICATION_ERROR')) {
43
+ return { kind: 'unauthorized' };
44
+ }
45
+ if (!res.ok)
46
+ return fail(`HTTP ${res.status}`);
47
+ if (body === undefined)
48
+ return fail('Linear returned a non-JSON response');
49
+ if (errors.length > 0)
50
+ return fail(errors[0]?.message ?? 'Linear returned a GraphQL error');
51
+ if ((body.data?.teams?.nodes ?? []).length === 0)
52
+ return { kind: 'team-missing', teamKey: linear.teamKey };
53
+ const issues = body.data?.issues;
54
+ for (const node of issues?.nodes ?? []) {
55
+ readyIssues++;
56
+ const project = node.project;
57
+ if (project && !(project.name in linear.projects) && !(project.id in linear.projects))
58
+ projects.add(project.name);
59
+ }
60
+ const info = issues?.pageInfo;
61
+ if (!info?.hasNextPage || !info.endCursor)
62
+ break;
63
+ after = info.endCursor;
64
+ }
65
+ return { kind: 'ok', readyIssues, unmappedProjects: [...projects].sort() };
66
+ }
67
+ //# sourceMappingURL=linear-preflight.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"linear-preflight.js","sourceRoot":"","sources":["../../src/work/linear-preflight.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@on-par/factory-core",
3
- "version": "0.9.27",
3
+ "version": "0.9.28-next.10",
4
4
  "description": "Core engine: model router, constitutions, checkers, and pipeline phases for the Software Factory.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -54,10 +54,10 @@
54
54
  "prepack": "node ../../scripts/pack-hygiene-cli.ts prepack"
55
55
  },
56
56
  "dependencies": {
57
- "@on-par/adr-kit": "0.9.27",
58
- "@on-par/contracts": "0.9.27",
59
- "@on-par/factory-config": "0.9.27",
60
- "@on-par/repo-context": "0.9.27",
57
+ "@on-par/adr-kit": "0.9.28-next.10",
58
+ "@on-par/contracts": "0.9.28-next.10",
59
+ "@on-par/factory-config": "0.9.28-next.10",
60
+ "@on-par/repo-context": "0.9.28-next.10",
61
61
  "@octokit/rest": "^22.0.0",
62
62
  "execa": "^10.2.1",
63
63
  "gray-matter": "^4.0.3",