@clipboard-health/groundcrew 4.1.0 → 4.2.1
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/README.md +25 -9
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +16 -42
- package/dist/commands/cleaner.d.ts +1 -1
- package/dist/commands/cleaner.d.ts.map +1 -1
- package/dist/commands/cleaner.js +4 -2
- package/dist/commands/dispatcher.d.ts +6 -6
- package/dist/commands/dispatcher.d.ts.map +1 -1
- package/dist/commands/dispatcher.js +43 -27
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +18 -22
- package/dist/commands/eligibility.d.ts +1 -1
- package/dist/commands/eligibility.d.ts.map +1 -1
- package/dist/commands/eligibility.js +7 -6
- package/dist/commands/orchestrator.d.ts.map +1 -1
- package/dist/commands/orchestrator.js +18 -14
- package/dist/commands/resumeWorkspace.d.ts.map +1 -1
- package/dist/commands/resumeWorkspace.js +3 -2
- package/dist/commands/setupWorkspace.d.ts +2 -4
- package/dist/commands/setupWorkspace.d.ts.map +1 -1
- package/dist/commands/setupWorkspace.js +27 -27
- package/dist/commands/status.d.ts.map +1 -1
- package/dist/commands/status.js +6 -3
- package/dist/commands/upgrade.d.ts +0 -11
- package/dist/commands/upgrade.d.ts.map +1 -1
- package/dist/commands/upgrade.js +14 -100
- package/dist/index.d.ts +3 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/lib/adapters/linear/client.d.ts +22 -0
- package/dist/lib/adapters/linear/client.d.ts.map +1 -0
- package/dist/lib/adapters/linear/client.js +36 -0
- package/dist/lib/adapters/linear/factory.d.ts +24 -14
- package/dist/lib/adapters/linear/factory.d.ts.map +1 -1
- package/dist/lib/adapters/linear/factory.js +113 -46
- package/dist/lib/{boardSource.d.ts → adapters/linear/fetch.d.ts} +19 -71
- package/dist/lib/adapters/linear/fetch.d.ts.map +1 -0
- package/dist/lib/{boardSource.js → adapters/linear/fetch.js} +21 -133
- package/dist/lib/adapters/linear/index.d.ts +1 -0
- package/dist/lib/adapters/linear/index.d.ts.map +1 -1
- package/dist/lib/adapters/linear/parsing.d.ts +44 -0
- package/dist/lib/adapters/linear/parsing.d.ts.map +1 -0
- package/dist/lib/adapters/linear/parsing.js +144 -0
- package/dist/lib/{linearIssueStatus.d.ts → adapters/linear/writeback.d.ts} +1 -2
- package/dist/lib/adapters/linear/writeback.d.ts.map +1 -0
- package/dist/lib/{linearIssueStatus.js → adapters/linear/writeback.js} +16 -17
- package/dist/lib/adapters/shell/factory.d.ts +1 -1
- package/dist/lib/adapters/shell/factory.d.ts.map +1 -1
- package/dist/lib/adapters/shell/factory.js +8 -4
- package/dist/lib/adapters/shell/invoke.d.ts +4 -7
- package/dist/lib/adapters/shell/invoke.d.ts.map +1 -1
- package/dist/lib/adapters/shell/invoke.js +46 -75
- package/dist/lib/adapters/shell/schema.d.ts +10 -0
- package/dist/lib/adapters/shell/schema.d.ts.map +1 -1
- package/dist/lib/adapters/shell/schema.js +9 -5
- package/dist/lib/board.d.ts.map +1 -1
- package/dist/lib/board.js +43 -4
- package/dist/lib/buildSources.d.ts +11 -0
- package/dist/lib/buildSources.d.ts.map +1 -1
- package/dist/lib/buildSources.js +41 -0
- package/dist/lib/repositoryValidation.d.ts +13 -0
- package/dist/lib/repositoryValidation.d.ts.map +1 -0
- package/dist/lib/repositoryValidation.js +20 -0
- package/dist/lib/testing/canonicalFixtures.d.ts +19 -0
- package/dist/lib/testing/canonicalFixtures.d.ts.map +1 -0
- package/dist/lib/testing/canonicalFixtures.js +62 -0
- package/dist/lib/ticketSource.d.ts +71 -1
- package/dist/lib/ticketSource.d.ts.map +1 -1
- package/dist/lib/ticketSource.js +31 -0
- package/dist/lib/util.d.ts +0 -20
- package/dist/lib/util.d.ts.map +1 -1
- package/dist/lib/util.js +0 -35
- package/package.json +1 -1
- package/dist/commands/setupRepos.d.ts +0 -44
- package/dist/commands/setupRepos.d.ts.map +0 -1
- package/dist/commands/setupRepos.js +0 -212
- package/dist/lib/boardSource.d.ts.map +0 -1
- package/dist/lib/linearIssueStatus.d.ts.map +0 -1
- package/dist/lib/upgrade.d.ts +0 -66
- package/dist/lib/upgrade.d.ts.map +0 -1
- package/dist/lib/upgrade.js +0 -178
|
@@ -4,12 +4,12 @@
|
|
|
4
4
|
* the cleaner, and runs the dispatcher; logging from those modules is the
|
|
5
5
|
* orchestrator's user-facing output.
|
|
6
6
|
*/
|
|
7
|
-
import { createBoardSource } from "../lib/boardSource.js";
|
|
8
7
|
import { createBoard } from "../lib/board.js";
|
|
9
|
-
import { buildSources } from "../lib/buildSources.js";
|
|
8
|
+
import { buildSources, sourcesFromConfig } from "../lib/buildSources.js";
|
|
10
9
|
import { loadConfig } from "../lib/config.js";
|
|
10
|
+
import { RepositoryResolutionError } from "../lib/ticketSource.js";
|
|
11
11
|
import { getUsageByModel } from "../lib/usage.js";
|
|
12
|
-
import { errorMessage,
|
|
12
|
+
import { errorMessage, log, sleep } from "../lib/util.js";
|
|
13
13
|
import { worktrees } from "../lib/worktrees.js";
|
|
14
14
|
import { createCleaner } from "./cleaner.js";
|
|
15
15
|
import { createDispatcher } from "./dispatcher.js";
|
|
@@ -24,6 +24,10 @@ async function withRetry(function_, signal, maxRetries = RETRY_MAX_ATTEMPTS, bas
|
|
|
24
24
|
return await function_();
|
|
25
25
|
}
|
|
26
26
|
catch (error) {
|
|
27
|
+
/* v8 ignore next 2 @preserve -- fetch() warns-and-skips since PR#88; guard is a defensive no-op in practice */
|
|
28
|
+
if (error instanceof RepositoryResolutionError) {
|
|
29
|
+
throw error;
|
|
30
|
+
}
|
|
27
31
|
if (attempt === maxRetries) {
|
|
28
32
|
throw error;
|
|
29
33
|
}
|
|
@@ -61,25 +65,21 @@ async function fetchUsageOrEmpty(config, signal) {
|
|
|
61
65
|
}
|
|
62
66
|
export async function orchestrate(options) {
|
|
63
67
|
const config = await loadConfig();
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
// boardSource.fetch in the main loop; shell-source dispatch is a follow-up.
|
|
70
|
-
// An empty config.sources resolves to an empty Board and verify() is a no-op.
|
|
71
|
-
const extraSources = await buildSources(config.sources, { globalConfig: config });
|
|
72
|
-
const board = createBoard(extraSources);
|
|
68
|
+
// Build all sources (Linear implicit + any user-declared shell adapters).
|
|
69
|
+
// sourcesFromConfig synthesizes the implicit linear source from the config;
|
|
70
|
+
// this ensures the Linear adapter's markInProgress is reachable via board.
|
|
71
|
+
const allSources = await buildSources(sourcesFromConfig(config), { globalConfig: config });
|
|
72
|
+
const board = createBoard(allSources);
|
|
73
73
|
await board.verify();
|
|
74
74
|
const cleaner = createCleaner({ config });
|
|
75
|
-
const dispatcher = createDispatcher({ config,
|
|
75
|
+
const dispatcher = createDispatcher({ config, board });
|
|
76
76
|
// Folded into the dispatcher's idle log lines in watch mode so each idle
|
|
77
77
|
// tick prints one combined line instead of "<reason>" + "Next poll in Xs".
|
|
78
78
|
const idleSuffix = options.watch
|
|
79
79
|
? `; next poll in ${config.orchestrator.pollIntervalMilliseconds / MS_PER_SECOND}s`
|
|
80
80
|
: undefined;
|
|
81
81
|
const tick = async (signal) => {
|
|
82
|
-
const state = await withRetry(async () => await
|
|
82
|
+
const state = await withRetry(async () => await board.fetch(), signal);
|
|
83
83
|
const worktreeEntries = worktrees.list(config);
|
|
84
84
|
const tickArguments = {
|
|
85
85
|
state,
|
|
@@ -147,6 +147,10 @@ async function runWatchLoop(tick, config) {
|
|
|
147
147
|
if (error instanceof WatchLoopShutdownError) {
|
|
148
148
|
break;
|
|
149
149
|
}
|
|
150
|
+
/* v8 ignore next 2 @preserve -- fetch() warns-and-skips since PR#88; guard is a defensive no-op in practice */
|
|
151
|
+
if (error instanceof RepositoryResolutionError) {
|
|
152
|
+
throw error;
|
|
153
|
+
}
|
|
150
154
|
const message = errorMessage(error);
|
|
151
155
|
if (message.includes("Signal: SIGINT")) {
|
|
152
156
|
if (!shutdown.signal.aborted) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resumeWorkspace.d.ts","sourceRoot":"","sources":["../../src/commands/resumeWorkspace.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"resumeWorkspace.d.ts","sourceRoot":"","sources":["../../src/commands/resumeWorkspace.ts"],"names":[],"mappings":"AAEA,OAAO,EAAc,KAAK,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAcnE,MAAM,WAAW,sBAAsB;IACrC,MAAM,EAAE,MAAM,CAAC;CAChB;AA6HD,wBAAsB,eAAe,CACnC,MAAM,EAAE,cAAc,EACtB,OAAO,EAAE,sBAAsB,GAC9B,OAAO,CAAC,IAAI,CAAC,CA4Df;AAED,wBAAsB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAGtE"}
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import { fetchResolvedIssue } from "../lib/
|
|
1
|
+
import { fetchResolvedIssue } from "../lib/adapters/linear/fetch.js";
|
|
2
|
+
import { getLinearClient } from "../lib/adapters/linear/client.js";
|
|
2
3
|
import { loadConfig } from "../lib/config.js";
|
|
3
4
|
import { openAgentWorkspace, prepareAgentLaunch } from "../lib/agentLaunch.js";
|
|
4
5
|
import { buildLaunchCommand } from "../lib/launchCommand.js";
|
|
5
6
|
import { readRunState, recordRunState } from "../lib/runState.js";
|
|
6
7
|
import { removeStagedPrompt, stageBuildSecrets, stagePromptText, stageWorkspaceLaunchCommand, } from "../lib/stagedLaunch.js";
|
|
7
|
-
import { errorMessage,
|
|
8
|
+
import { errorMessage, log } from "../lib/util.js";
|
|
8
9
|
import { workspaces } from "../lib/workspaces.js";
|
|
9
10
|
import { worktrees } from "../lib/worktrees.js";
|
|
10
11
|
function parseArguments(argv) {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type ResolvedConfig } from "../lib/config.ts";
|
|
2
|
-
interface TicketDetails {
|
|
2
|
+
export interface TicketDetails {
|
|
3
3
|
title: string;
|
|
4
4
|
description: string;
|
|
5
5
|
}
|
|
@@ -7,8 +7,7 @@ export interface SetupWorkspaceOptions {
|
|
|
7
7
|
ticket: string;
|
|
8
8
|
repository: string;
|
|
9
9
|
model: string;
|
|
10
|
-
|
|
11
|
-
details?: TicketDetails;
|
|
10
|
+
details: TicketDetails;
|
|
12
11
|
}
|
|
13
12
|
export interface SetupWorkspaceRunOptions {
|
|
14
13
|
signal?: AbortSignal;
|
|
@@ -17,5 +16,4 @@ export declare function setupWorkspace(config: ResolvedConfig, options: SetupWor
|
|
|
17
16
|
export declare function setupWorkspaceCli(ticket: string, options?: {
|
|
18
17
|
dryRun?: boolean;
|
|
19
18
|
}): Promise<void>;
|
|
20
|
-
export {};
|
|
21
19
|
//# sourceMappingURL=setupWorkspace.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"setupWorkspace.d.ts","sourceRoot":"","sources":["../../src/commands/setupWorkspace.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"setupWorkspace.d.ts","sourceRoot":"","sources":["../../src/commands/setupWorkspace.ts"],"names":[],"mappings":"AACA,OAAO,EAAc,KAAK,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAiBnE,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,qBAAqB;IACpC,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,aAAa,CAAC;CACxB;AAED,MAAM,WAAW,wBAAwB;IACvC,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AAqBD,wBAAsB,cAAc,CAClC,MAAM,EAAE,cAAc,EACtB,OAAO,EAAE,qBAAqB,EAC9B,UAAU,GAAE,wBAA6B,GACxC,OAAO,CAAC,IAAI,CAAC,CAgGf;AAwHD,wBAAsB,iBAAiB,CACrC,MAAM,EAAE,MAAM,EACd,OAAO,GAAE;IAAE,MAAM,CAAC,EAAE,OAAO,CAAA;CAAO,GACjC,OAAO,CAAC,IAAI,CAAC,CAwCf"}
|
|
@@ -1,22 +1,15 @@
|
|
|
1
1
|
import { rmSync } from "node:fs";
|
|
2
|
-
import { fetchResolvedIssue } from "../lib/boardSource.js";
|
|
3
2
|
import { loadConfig } from "../lib/config.js";
|
|
4
3
|
import { openAgentWorkspace, prepareAgentLaunch } from "../lib/agentLaunch.js";
|
|
4
|
+
import { createBoard } from "../lib/board.js";
|
|
5
|
+
import { buildSources, sourcesFromConfig } from "../lib/buildSources.js";
|
|
5
6
|
import { buildLaunchCommand } from "../lib/launchCommand.js";
|
|
6
|
-
import { createLinearIssueStatusUpdater } from "../lib/linearIssueStatus.js";
|
|
7
7
|
import { recordRunState } from "../lib/runState.js";
|
|
8
8
|
import { stageBuildSecrets, stagePromptFromTemplate, stageWorkspaceLaunchCommand, } from "../lib/stagedLaunch.js";
|
|
9
|
-
import {
|
|
9
|
+
import { naturalIdFromCanonical } from "../lib/ticketSource.js";
|
|
10
|
+
import { errorMessage, log } from "../lib/util.js";
|
|
10
11
|
import { workspaces } from "../lib/workspaces.js";
|
|
11
12
|
import { isWorktreeAlreadyExistsError, worktrees } from "../lib/worktrees.js";
|
|
12
|
-
async function fetchTicket(ticket) {
|
|
13
|
-
const client = getLinearClient();
|
|
14
|
-
const issue = await client.issue(ticket.toUpperCase());
|
|
15
|
-
return {
|
|
16
|
-
title: issue.title,
|
|
17
|
-
description: issue.description ?? "",
|
|
18
|
-
};
|
|
19
|
-
}
|
|
20
13
|
function stagePrompt(input) {
|
|
21
14
|
return stagePromptFromTemplate({
|
|
22
15
|
config: input.config,
|
|
@@ -69,14 +62,7 @@ export async function setupWorkspace(config, options, runOptions = {}) {
|
|
|
69
62
|
// the ticket strands forever.
|
|
70
63
|
let promptDir;
|
|
71
64
|
try {
|
|
72
|
-
|
|
73
|
-
if (options.details === undefined) {
|
|
74
|
-
log(`Fetching ${ticket} from Linear...`);
|
|
75
|
-
ticketDetails = await fetchTicket(ticket);
|
|
76
|
-
}
|
|
77
|
-
else {
|
|
78
|
-
ticketDetails = options.details;
|
|
79
|
-
}
|
|
65
|
+
const ticketDetails = options.details;
|
|
80
66
|
const stagedPrompt = stagePrompt({ config, ticket, ticketDetails, worktreeName });
|
|
81
67
|
promptDir = stagedPrompt.directory;
|
|
82
68
|
const secretsFile = stageBuildSecrets(promptDir);
|
|
@@ -218,22 +204,36 @@ async function rollbackWorktree(arguments_) {
|
|
|
218
204
|
}
|
|
219
205
|
export async function setupWorkspaceCli(ticket, options = {}) {
|
|
220
206
|
const config = await loadConfig();
|
|
221
|
-
|
|
222
|
-
|
|
207
|
+
let sources;
|
|
208
|
+
try {
|
|
209
|
+
sources = await buildSources(sourcesFromConfig(config), { globalConfig: config });
|
|
210
|
+
}
|
|
211
|
+
catch (error) {
|
|
212
|
+
/* v8 ignore next @preserve -- catch re-throw always receives an Error; String(error) is an unreachable fallback */
|
|
213
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
214
|
+
throw new Error(`Could not initialize ticket sources for 'crew setup ${ticket}': ${message}`, {
|
|
215
|
+
cause: error,
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
const board = createBoard(sources);
|
|
219
|
+
const resolved = await board.resolveOne(ticket);
|
|
220
|
+
if (resolved === undefined) {
|
|
221
|
+
throw new Error(`Ticket ${ticket} not found across configured sources.`);
|
|
222
|
+
}
|
|
223
|
+
if (resolved.repository === undefined || resolved.model === undefined) {
|
|
224
|
+
throw new Error(`Ticket ${ticket} resolved but isn't groundcrew-eligible (missing agent-* label or repository/model).`);
|
|
225
|
+
}
|
|
223
226
|
log(`Resolved ${ticket}: repository=${resolved.repository}, model=${resolved.model}`);
|
|
224
227
|
if (options.dryRun === true) {
|
|
225
228
|
log(`[dry-run] Would launch ${ticket} in ${resolved.repository} (${resolved.model})`);
|
|
226
229
|
return;
|
|
227
230
|
}
|
|
231
|
+
const naturalId = naturalIdFromCanonical(resolved.id);
|
|
228
232
|
await setupWorkspace(config, {
|
|
229
|
-
ticket:
|
|
233
|
+
ticket: naturalId,
|
|
230
234
|
repository: resolved.repository,
|
|
231
235
|
model: resolved.model,
|
|
232
236
|
details: { title: resolved.title, description: resolved.description },
|
|
233
237
|
});
|
|
234
|
-
await
|
|
235
|
-
id: ticket.toLowerCase(),
|
|
236
|
-
uuid: resolved.uuid,
|
|
237
|
-
teamId: resolved.teamId,
|
|
238
|
-
});
|
|
238
|
+
await board.markInProgress(resolved);
|
|
239
239
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../src/commands/status.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../src/commands/status.ts"],"names":[],"mappings":"AAIA,OAAO,EAAc,KAAK,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAMnE,MAAM,WAAW,aAAa;IAC5B,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAyLD,wBAAsB,MAAM,CAAC,MAAM,EAAE,cAAc,EAAE,OAAO,GAAE,aAAkB,GAAG,OAAO,CAAC,IAAI,CAAC,CAU/F;AAED,wBAAsB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAI7D"}
|
package/dist/commands/status.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { readFileSync } from "node:fs";
|
|
2
|
-
import {
|
|
2
|
+
import { getLinearClient } from "../lib/adapters/linear/client.js";
|
|
3
|
+
import { fetchRawLinearIssue } from "../lib/adapters/linear/fetch.js";
|
|
3
4
|
import { loadConfig } from "../lib/config.js";
|
|
4
5
|
import { readRunState } from "../lib/runState.js";
|
|
5
|
-
import { errorMessage,
|
|
6
|
+
import { errorMessage, withLogOutputSuppressed, writeOutput } from "../lib/util.js";
|
|
6
7
|
import { workspaces } from "../lib/workspaces.js";
|
|
7
8
|
import { worktrees } from "../lib/worktrees.js";
|
|
8
9
|
const RECENT_LOG_LINE_COUNT = 10;
|
|
@@ -95,7 +96,9 @@ function recentTicketLogLines(config, ticket) {
|
|
|
95
96
|
async function linearStatus(ticket) {
|
|
96
97
|
try {
|
|
97
98
|
const issue = await fetchRawLinearIssue({ client: getLinearClient(), ticket });
|
|
98
|
-
|
|
99
|
+
// `stateType` is "" when Linear returned a stateless ticket; surface that
|
|
100
|
+
// as "unknown" rather than an empty token.
|
|
101
|
+
return `${issue.stateName} (state.type=${issue.stateType || "unknown"}) — ${issue.title}`;
|
|
99
102
|
}
|
|
100
103
|
catch (error) {
|
|
101
104
|
return `unavailable: ${errorMessage(error)}`;
|
|
@@ -1,22 +1,12 @@
|
|
|
1
1
|
import { type InstallKind, type NpmRunResult } from "../lib/npmGlobal.ts";
|
|
2
|
-
import { type VersionFetcher } from "../lib/upgrade.ts";
|
|
3
2
|
export interface UpgradeCliOptions {
|
|
4
|
-
currentVersion: string;
|
|
5
3
|
packageName: string;
|
|
6
4
|
resolveInstall: () => Promise<UpgradeInstallDetails>;
|
|
7
|
-
fetcher: VersionFetcher;
|
|
8
5
|
runInstall: (options: {
|
|
9
6
|
packageName: string;
|
|
10
7
|
version: string;
|
|
11
8
|
npmBin: string;
|
|
12
9
|
}) => Promise<NpmRunResult>;
|
|
13
|
-
registry?: string | undefined;
|
|
14
|
-
fetchTimeoutMs: number;
|
|
15
|
-
/** Path of the upgrade-availability cache that the nudge reads. We prime
|
|
16
|
-
* it from `--check` and the default install path so the next non-upgrade
|
|
17
|
-
* subcommand can render the nudge without paying the network cost. */
|
|
18
|
-
cachePath: string;
|
|
19
|
-
now: () => number;
|
|
20
10
|
}
|
|
21
11
|
export interface UpgradeInstallDetails {
|
|
22
12
|
installKind: InstallKind;
|
|
@@ -26,7 +16,6 @@ export interface UpgradeInstallDetails {
|
|
|
26
16
|
export type UpgradeCliOptionsInput = UpgradeCliOptions | (() => Promise<UpgradeCliOptions>);
|
|
27
17
|
export declare function upgradeCli(argv: string[], optionsInput: UpgradeCliOptionsInput): Promise<void>;
|
|
28
18
|
export interface CreateUpgradeOptionsArgs {
|
|
29
|
-
currentVersion: string;
|
|
30
19
|
packageName: string;
|
|
31
20
|
cliMetaUrl: string;
|
|
32
21
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"upgrade.d.ts","sourceRoot":"","sources":["../../src/commands/upgrade.ts"],"names":[],"mappings":"AAEA,OAAO,EAML,KAAK,WAAW,EAChB,KAAK,YAAY,EAElB,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"upgrade.d.ts","sourceRoot":"","sources":["../../src/commands/upgrade.ts"],"names":[],"mappings":"AAEA,OAAO,EAML,KAAK,WAAW,EAChB,KAAK,YAAY,EAElB,MAAM,qBAAqB,CAAC;AAK7B,MAAM,WAAW,iBAAiB;IAChC,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,EAAE,MAAM,OAAO,CAAC,qBAAqB,CAAC,CAAC;IACrD,UAAU,EAAE,CAAC,OAAO,EAAE;QACpB,WAAW,EAAE,MAAM,CAAC;QACpB,OAAO,EAAE,MAAM,CAAC;QAChB,MAAM,EAAE,MAAM,CAAC;KAChB,KAAK,OAAO,CAAC,YAAY,CAAC,CAAC;CAC7B;AAED,MAAM,WAAW,qBAAqB;IACpC,WAAW,EAAE,WAAW,CAAC;IACzB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;CAC5B;AAOD,MAAM,MAAM,sBAAsB,GAAG,iBAAiB,GAAG,CAAC,MAAM,OAAO,CAAC,iBAAiB,CAAC,CAAC,CAAC;AAiD5F,wBAAsB,UAAU,CAC9B,IAAI,EAAE,MAAM,EAAE,EACd,YAAY,EAAE,sBAAsB,GACnC,OAAO,CAAC,IAAI,CAAC,CAkBf;AAsCD,MAAM,WAAW,wBAAwB;IACvC,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,wBAAsB,8BAA8B,CAClD,IAAI,EAAE,wBAAwB,GAC7B,OAAO,CAAC,iBAAiB,CAAC,CAqB5B"}
|
package/dist/commands/upgrade.js
CHANGED
|
@@ -1,46 +1,36 @@
|
|
|
1
1
|
import { runCommand } from "../lib/commandRunner.js";
|
|
2
2
|
import { which } from "../lib/host.js";
|
|
3
3
|
import { classifyInstall, createDefaultNpmSpawner, detectInstallPath, detectIsSymlink, detectNpmRootGlobal, runNpmInstallGlobal, } from "../lib/npmGlobal.js";
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
const EXPLICIT_FETCH_TIMEOUT_MS = 5000;
|
|
4
|
+
import { writeError, writeOutput } from "../lib/util.js";
|
|
5
|
+
const DEFAULT_UPGRADE_TARGET = "latest";
|
|
7
6
|
function parseArgs(argv) {
|
|
8
|
-
let
|
|
9
|
-
let pinnedVersion;
|
|
7
|
+
let version;
|
|
10
8
|
for (const arg of argv) {
|
|
11
9
|
if (arg === "--help" || arg === "-h") {
|
|
12
10
|
return { kind: "help" };
|
|
13
11
|
}
|
|
14
|
-
if (arg === "--check") {
|
|
15
|
-
check = true;
|
|
16
|
-
continue;
|
|
17
|
-
}
|
|
18
12
|
if (arg.startsWith("-")) {
|
|
19
13
|
return { kind: "error", message: `crew upgrade: unknown argument: ${arg}` };
|
|
20
14
|
}
|
|
21
|
-
if (
|
|
15
|
+
if (arg.length === 0) {
|
|
16
|
+
return { kind: "error", message: "crew upgrade: version cannot be empty" };
|
|
17
|
+
}
|
|
18
|
+
if (version !== undefined) {
|
|
22
19
|
return { kind: "error", message: "crew upgrade: too many positional arguments" };
|
|
23
20
|
}
|
|
24
|
-
|
|
25
|
-
}
|
|
26
|
-
if (check && pinnedVersion !== undefined) {
|
|
27
|
-
return { kind: "error", message: "crew upgrade: --check does not accept a version argument" };
|
|
28
|
-
}
|
|
29
|
-
if (check) {
|
|
30
|
-
return { kind: "check" };
|
|
21
|
+
version = arg;
|
|
31
22
|
}
|
|
32
|
-
return { kind: "install",
|
|
23
|
+
return { kind: "install", version: version ?? DEFAULT_UPGRADE_TARGET };
|
|
33
24
|
}
|
|
34
25
|
function printHelp() {
|
|
35
|
-
writeOutput("Usage: crew upgrade [<version>]
|
|
26
|
+
writeOutput("Usage: crew upgrade [<version>]");
|
|
36
27
|
writeOutput("");
|
|
37
|
-
writeOutput("Install
|
|
28
|
+
writeOutput("Install crew globally through npm.");
|
|
38
29
|
writeOutput("");
|
|
39
30
|
writeOutput("Arguments:");
|
|
40
|
-
writeOutput(" <version> Install an exact version (
|
|
31
|
+
writeOutput(" <version> Install an exact version or npm tag (default: latest)");
|
|
41
32
|
writeOutput("");
|
|
42
33
|
writeOutput("Options:");
|
|
43
|
-
writeOutput(" --check Report availability without installing");
|
|
44
34
|
writeOutput(" -h, --help Show this help");
|
|
45
35
|
}
|
|
46
36
|
function refusalMessage(kind, installPath, packageName) {
|
|
@@ -64,34 +54,11 @@ export async function upgradeCli(argv, optionsInput) {
|
|
|
64
54
|
return;
|
|
65
55
|
}
|
|
66
56
|
const options = await resolveOptions(optionsInput);
|
|
67
|
-
if (parsed.kind === "check") {
|
|
68
|
-
await runCheck(options);
|
|
69
|
-
return;
|
|
70
|
-
}
|
|
71
|
-
let targetVersion;
|
|
72
|
-
if (parsed.pinnedVersion === undefined) {
|
|
73
|
-
const fetched = await fetchOrFail(options);
|
|
74
|
-
if (fetched === undefined) {
|
|
75
|
-
return;
|
|
76
|
-
}
|
|
77
|
-
if (compareVersions(options.currentVersion, fetched) >= 0) {
|
|
78
|
-
writeOutput(`crew is up to date (${fetched})`);
|
|
79
|
-
return;
|
|
80
|
-
}
|
|
81
|
-
targetVersion = fetched;
|
|
82
|
-
}
|
|
83
|
-
else {
|
|
84
|
-
const resolved = resolvePinnedVersion(options, parsed.pinnedVersion);
|
|
85
|
-
if (resolved === undefined) {
|
|
86
|
-
return;
|
|
87
|
-
}
|
|
88
|
-
targetVersion = resolved;
|
|
89
|
-
}
|
|
90
57
|
const npmBin = await resolveGlobalNpmBin(options);
|
|
91
58
|
if (npmBin === undefined) {
|
|
92
59
|
return;
|
|
93
60
|
}
|
|
94
|
-
await runInstallAndReport(options, npmBin,
|
|
61
|
+
await runInstallAndReport(options, npmBin, parsed.version);
|
|
95
62
|
}
|
|
96
63
|
async function resolveGlobalNpmBin(options) {
|
|
97
64
|
const install = await options.resolveInstall();
|
|
@@ -107,53 +74,6 @@ async function resolveGlobalNpmBin(options) {
|
|
|
107
74
|
}
|
|
108
75
|
return install.npmBin;
|
|
109
76
|
}
|
|
110
|
-
async function runCheck(options) {
|
|
111
|
-
const latest = await fetchOrFail(options);
|
|
112
|
-
if (latest === undefined) {
|
|
113
|
-
return;
|
|
114
|
-
}
|
|
115
|
-
if (compareVersions(options.currentVersion, latest) >= 0) {
|
|
116
|
-
writeOutput(`crew is up to date (${latest})`);
|
|
117
|
-
return;
|
|
118
|
-
}
|
|
119
|
-
writeOutput(`${latest} available (you are on ${options.currentVersion}); run \`crew upgrade\``);
|
|
120
|
-
}
|
|
121
|
-
async function fetchOrFail(options) {
|
|
122
|
-
try {
|
|
123
|
-
return await fetchAndPrimeUpgradeCheckCache({
|
|
124
|
-
packageName: options.packageName,
|
|
125
|
-
cachePath: options.cachePath,
|
|
126
|
-
fetchTimeoutMs: options.fetchTimeoutMs,
|
|
127
|
-
registry: options.registry,
|
|
128
|
-
now: options.now,
|
|
129
|
-
fetcher: options.fetcher,
|
|
130
|
-
});
|
|
131
|
-
}
|
|
132
|
-
catch (error) {
|
|
133
|
-
writeError(`crew upgrade: could not reach npm registry: ${errorMessage(error)}`);
|
|
134
|
-
process.exitCode = 1;
|
|
135
|
-
return undefined;
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
function resolvePinnedVersion(options, pinnedVersion) {
|
|
139
|
-
try {
|
|
140
|
-
parseVersion(pinnedVersion);
|
|
141
|
-
}
|
|
142
|
-
catch (error) {
|
|
143
|
-
writeError(`crew upgrade: ${errorMessage(error)}`);
|
|
144
|
-
process.exitCode = 1;
|
|
145
|
-
return undefined;
|
|
146
|
-
}
|
|
147
|
-
if (options.currentVersion === pinnedVersion) {
|
|
148
|
-
writeOutput(`crew is already on ${pinnedVersion}`);
|
|
149
|
-
return undefined;
|
|
150
|
-
}
|
|
151
|
-
const cmp = compareVersions(options.currentVersion, pinnedVersion);
|
|
152
|
-
if (cmp > 0) {
|
|
153
|
-
writeOutput(`downgrading ${options.currentVersion} → ${pinnedVersion}`);
|
|
154
|
-
}
|
|
155
|
-
return pinnedVersion;
|
|
156
|
-
}
|
|
157
77
|
async function runInstallAndReport(options, npmBin, version) {
|
|
158
78
|
const result = await options.runInstall({
|
|
159
79
|
packageName: options.packageName,
|
|
@@ -164,13 +84,12 @@ async function runInstallAndReport(options, npmBin, version) {
|
|
|
164
84
|
return;
|
|
165
85
|
}
|
|
166
86
|
if (result.sawEacces) {
|
|
167
|
-
writeError("crew upgrade: install failed with EACCES (permission denied). Your global npm prefix may require elevated permissions
|
|
87
|
+
writeError("crew upgrade: install failed with EACCES (permission denied). Your global npm prefix may require elevated permissions - see https://docs.npmjs.com/resolving-eacces-permissions-errors-when-installing-packages-globally");
|
|
168
88
|
}
|
|
169
89
|
process.exitCode = result.exitCode;
|
|
170
90
|
}
|
|
171
91
|
export async function createDefaultUpgradeCliOptions(args) {
|
|
172
92
|
return {
|
|
173
|
-
currentVersion: args.currentVersion,
|
|
174
93
|
packageName: args.packageName,
|
|
175
94
|
resolveInstall: async () => {
|
|
176
95
|
const installPath = detectInstallPath(args.cliMetaUrl);
|
|
@@ -183,14 +102,9 @@ export async function createDefaultUpgradeCliOptions(args) {
|
|
|
183
102
|
});
|
|
184
103
|
return { installKind, installPath, npmBin };
|
|
185
104
|
},
|
|
186
|
-
fetcher: fetchLatestVersion,
|
|
187
105
|
runInstall: async (options) => await runNpmInstallGlobal({
|
|
188
106
|
...options,
|
|
189
107
|
spawner: createDefaultNpmSpawner(process.stderr),
|
|
190
108
|
}),
|
|
191
|
-
fetchTimeoutMs: EXPLICIT_FETCH_TIMEOUT_MS,
|
|
192
|
-
registry: readEnvironmentVariable("npm_config_registry"),
|
|
193
|
-
cachePath: defaultUpgradeCheckCachePath(),
|
|
194
|
-
now: Date.now,
|
|
195
109
|
};
|
|
196
110
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -9,11 +9,12 @@ export { status, type StatusOptions } from "./commands/status.ts";
|
|
|
9
9
|
export type { Config, ModelDefinition, ResolvedConfig, SourceConfig } from "./lib/config.ts";
|
|
10
10
|
export { loadConfig } from "./lib/config.ts";
|
|
11
11
|
export { readRunState, recordRunState, removeRunState, runStateDirectory, runStatePath, updateRunState, type RunLifecycleState, type RunState, } from "./lib/runState.ts";
|
|
12
|
-
export { fetchBlockersForTicket, fetchInProgressIssueCount, fetchRawLinearIssue, fetchResolvedIssue, isIssueInProgress, isIssueTodo, isTerminalStateType, isTerminalStatusForBlocker, isTerminalStatusForIssue,
|
|
12
|
+
export { fetchBlockersForTicket, fetchInProgressIssueCount, fetchRawLinearIssue, fetchResolvedIssue, isIssueInProgress, isIssueTodo, isTerminalStateType, isTerminalStatusForBlocker, isTerminalStatusForIssue, type RawLinearIssue, } from "./lib/adapters/linear/fetch.ts";
|
|
13
|
+
export { resolveModelFor, resolveRepositoryFor, type ModelResolution, type RepositoryResolution, } from "./lib/adapters/linear/parsing.ts";
|
|
13
14
|
export { getUsageByModel, type UsageByModel } from "./lib/usage.ts";
|
|
14
15
|
export { type Board, createBoard } from "./lib/board.ts";
|
|
15
16
|
export { buildSources, buildSourcesWith } from "./lib/buildSources.ts";
|
|
16
17
|
export type { AdapterContext, AdapterDefinition } from "./lib/adapterDefinition.ts";
|
|
17
18
|
export { adapterRegistry, type AdapterLoader, buildRegistry, buildSourceConfigSchema, listAdapterDirectories, } from "./lib/adapters/registry.ts";
|
|
18
|
-
export { AmbiguousTicketError, type Blocker as CanonicalBlocker, type BoardState as CanonicalBoardState, type CanonicalStatus, type GroundcrewIssue as CanonicalGroundcrewIssue, type Issue as CanonicalIssue, isGroundcrewIssue as isCanonicalGroundcrewIssue, type TicketSource, } from "./lib/ticketSource.ts";
|
|
19
|
+
export { AmbiguousTicketError, type Blocker as CanonicalBlocker, type BoardState as CanonicalBoardState, type CanonicalStatus, type GroundcrewIssue as CanonicalGroundcrewIssue, type Issue as CanonicalIssue, isGroundcrewIssue as isCanonicalGroundcrewIssue, type ParentSkip as CanonicalParentSkip, type TicketSource, } from "./lib/ticketSource.ts";
|
|
19
20
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAC/B,OAAO,EAAE,gBAAgB,EAAE,KAAK,uBAAuB,EAAE,MAAM,gCAAgC,CAAC;AAChG,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAC9C,OAAO,EACL,kBAAkB,EAClB,KAAK,yBAAyB,GAC/B,MAAM,kCAAkC,CAAC;AAC1C,OAAO,EAAE,WAAW,EAAE,KAAK,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AACnF,OAAO,EAAE,eAAe,EAAE,KAAK,sBAAsB,EAAE,MAAM,+BAA+B,CAAC;AAC7F,OAAO,EAAE,cAAc,EAAE,KAAK,qBAAqB,EAAE,MAAM,8BAA8B,CAAC;AAC1F,OAAO,EAAE,MAAM,EAAE,KAAK,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAClE,YAAY,EAAE,MAAM,EAAE,eAAe,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC7F,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EACL,YAAY,EACZ,cAAc,EACd,cAAc,EACd,iBAAiB,EACjB,YAAY,EACZ,cAAc,EACd,KAAK,iBAAiB,EACtB,KAAK,QAAQ,GACd,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,sBAAsB,EACtB,yBAAyB,EACzB,mBAAmB,EACnB,kBAAkB,EAClB,iBAAiB,EACjB,WAAW,EACX,mBAAmB,EACnB,0BAA0B,EAC1B,wBAAwB,EACxB,eAAe,EACf,oBAAoB,EACpB,KAAK,eAAe,EACpB,KAAK,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAC/B,OAAO,EAAE,gBAAgB,EAAE,KAAK,uBAAuB,EAAE,MAAM,gCAAgC,CAAC;AAChG,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAC9C,OAAO,EACL,kBAAkB,EAClB,KAAK,yBAAyB,GAC/B,MAAM,kCAAkC,CAAC;AAC1C,OAAO,EAAE,WAAW,EAAE,KAAK,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AACnF,OAAO,EAAE,eAAe,EAAE,KAAK,sBAAsB,EAAE,MAAM,+BAA+B,CAAC;AAC7F,OAAO,EAAE,cAAc,EAAE,KAAK,qBAAqB,EAAE,MAAM,8BAA8B,CAAC;AAC1F,OAAO,EAAE,MAAM,EAAE,KAAK,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAClE,YAAY,EAAE,MAAM,EAAE,eAAe,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC7F,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EACL,YAAY,EACZ,cAAc,EACd,cAAc,EACd,iBAAiB,EACjB,YAAY,EACZ,cAAc,EACd,KAAK,iBAAiB,EACtB,KAAK,QAAQ,GACd,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,sBAAsB,EACtB,yBAAyB,EACzB,mBAAmB,EACnB,kBAAkB,EAClB,iBAAiB,EACjB,WAAW,EACX,mBAAmB,EACnB,0BAA0B,EAC1B,wBAAwB,EACxB,KAAK,cAAc,GACpB,MAAM,gCAAgC,CAAC;AACxC,OAAO,EACL,eAAe,EACf,oBAAoB,EACpB,KAAK,eAAe,EACpB,KAAK,oBAAoB,GAC1B,MAAM,kCAAkC,CAAC;AAC1C,OAAO,EAAE,eAAe,EAAE,KAAK,YAAY,EAAE,MAAM,gBAAgB,CAAC;AACpE,OAAO,EAAE,KAAK,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AACzD,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AACvE,YAAY,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AACpF,OAAO,EACL,eAAe,EACf,KAAK,aAAa,EAClB,aAAa,EACb,uBAAuB,EACvB,sBAAsB,GACvB,MAAM,4BAA4B,CAAC;AACpC,OAAO,EACL,oBAAoB,EACpB,KAAK,OAAO,IAAI,gBAAgB,EAChC,KAAK,UAAU,IAAI,mBAAmB,EACtC,KAAK,eAAe,EACpB,KAAK,eAAe,IAAI,wBAAwB,EAChD,KAAK,KAAK,IAAI,cAAc,EAC5B,iBAAiB,IAAI,0BAA0B,EAC/C,KAAK,UAAU,IAAI,mBAAmB,EACtC,KAAK,YAAY,GAClB,MAAM,uBAAuB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -8,10 +8,10 @@ export { setupWorkspace } from "./commands/setupWorkspace.js";
|
|
|
8
8
|
export { status } from "./commands/status.js";
|
|
9
9
|
export { loadConfig } from "./lib/config.js";
|
|
10
10
|
export { readRunState, recordRunState, removeRunState, runStateDirectory, runStatePath, updateRunState, } from "./lib/runState.js";
|
|
11
|
-
export { fetchBlockersForTicket, fetchInProgressIssueCount, fetchRawLinearIssue, fetchResolvedIssue, isIssueInProgress, isIssueTodo, isTerminalStateType, isTerminalStatusForBlocker, isTerminalStatusForIssue,
|
|
11
|
+
export { fetchBlockersForTicket, fetchInProgressIssueCount, fetchRawLinearIssue, fetchResolvedIssue, isIssueInProgress, isIssueTodo, isTerminalStateType, isTerminalStatusForBlocker, isTerminalStatusForIssue, } from "./lib/adapters/linear/fetch.js";
|
|
12
|
+
export { resolveModelFor, resolveRepositoryFor, } from "./lib/adapters/linear/parsing.js";
|
|
12
13
|
export { getUsageByModel } from "./lib/usage.js";
|
|
13
14
|
export { createBoard } from "./lib/board.js";
|
|
14
15
|
export { buildSources, buildSourcesWith } from "./lib/buildSources.js";
|
|
15
16
|
export { adapterRegistry, buildRegistry, buildSourceConfigSchema, listAdapterDirectories, } from "./lib/adapters/registry.js";
|
|
16
17
|
export { AmbiguousTicketError, isGroundcrewIssue as isCanonicalGroundcrewIssue, } from "./lib/ticketSource.js";
|
|
17
|
-
// RepositoryResolutionError is exported via boardSource.ts above (single canonical location).
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { LinearClient } from "@linear/sdk";
|
|
2
|
+
declare const LINEAR_API_KEY_SOURCES: readonly ["GROUNDCREW_LINEAR_API_KEY", "LINEAR_API_KEY"];
|
|
3
|
+
export type LinearApiKeySource = (typeof LINEAR_API_KEY_SOURCES)[number];
|
|
4
|
+
export interface ResolvedLinearApiKey {
|
|
5
|
+
value: string;
|
|
6
|
+
source: LinearApiKeySource;
|
|
7
|
+
}
|
|
8
|
+
export declare function resolveLinearApiKey(): ResolvedLinearApiKey | undefined;
|
|
9
|
+
export declare function getLinearClient(): LinearClient;
|
|
10
|
+
/**
|
|
11
|
+
* Returns a zero-arg getter that lazily constructs (and caches) a Linear
|
|
12
|
+
* client on first call. Used by CLI entry points that may not need the
|
|
13
|
+
* client at all (e.g. `--no-linear`), so we avoid blowing up on a missing
|
|
14
|
+
* API key when no Linear call is actually made. The factory is taken as a
|
|
15
|
+
* parameter (rather than calling `getLinearClient` directly) so callers can
|
|
16
|
+
* pass their own module-level import of `getLinearClient` — that binding
|
|
17
|
+
* respects `vi.mock` intercepts, whereas an intra-module reference would
|
|
18
|
+
* not.
|
|
19
|
+
*/
|
|
20
|
+
export declare function lazyLinearClient(factory: () => LinearClient): () => LinearClient;
|
|
21
|
+
export {};
|
|
22
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../../../src/lib/adapters/linear/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAI3C,QAAA,MAAM,sBAAsB,YAAI,2BAA2B,EAAE,gBAAgB,CAAU,CAAC;AAExF,MAAM,MAAM,kBAAkB,GAAG,CAAC,OAAO,sBAAsB,CAAC,CAAC,MAAM,CAAC,CAAC;AAEzE,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,kBAAkB,CAAC;CAC5B;AAED,wBAAgB,mBAAmB,IAAI,oBAAoB,GAAG,SAAS,CAQtE;AAED,wBAAgB,eAAe,IAAI,YAAY,CAQ9C;AAED;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,YAAY,GAAG,MAAM,YAAY,CAMhF"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { LinearClient } from "@linear/sdk";
|
|
2
|
+
import { readEnvironmentVariable } from "../../util.js";
|
|
3
|
+
const LINEAR_API_KEY_SOURCES = ["GROUNDCREW_LINEAR_API_KEY", "LINEAR_API_KEY"];
|
|
4
|
+
export function resolveLinearApiKey() {
|
|
5
|
+
for (const source of LINEAR_API_KEY_SOURCES) {
|
|
6
|
+
const value = readEnvironmentVariable(source);
|
|
7
|
+
if (value !== undefined && value.length > 0) {
|
|
8
|
+
return { value, source };
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
return undefined;
|
|
12
|
+
}
|
|
13
|
+
export function getLinearClient() {
|
|
14
|
+
const resolved = resolveLinearApiKey();
|
|
15
|
+
if (resolved === undefined) {
|
|
16
|
+
throw new Error("Linear API key not set. Set GROUNDCREW_LINEAR_API_KEY or LINEAR_API_KEY in your environment.");
|
|
17
|
+
}
|
|
18
|
+
return new LinearClient({ apiKey: resolved.value });
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Returns a zero-arg getter that lazily constructs (and caches) a Linear
|
|
22
|
+
* client on first call. Used by CLI entry points that may not need the
|
|
23
|
+
* client at all (e.g. `--no-linear`), so we avoid blowing up on a missing
|
|
24
|
+
* API key when no Linear call is actually made. The factory is taken as a
|
|
25
|
+
* parameter (rather than calling `getLinearClient` directly) so callers can
|
|
26
|
+
* pass their own module-level import of `getLinearClient` — that binding
|
|
27
|
+
* respects `vi.mock` intercepts, whereas an intra-module reference would
|
|
28
|
+
* not.
|
|
29
|
+
*/
|
|
30
|
+
export function lazyLinearClient(factory) {
|
|
31
|
+
let client;
|
|
32
|
+
return () => {
|
|
33
|
+
client ??= factory();
|
|
34
|
+
return client;
|
|
35
|
+
};
|
|
36
|
+
}
|
|
@@ -1,23 +1,33 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Linear `TicketSource` factory.
|
|
3
|
-
* (createBoardSource
|
|
4
|
-
*
|
|
5
|
-
*
|
|
2
|
+
* Linear `TicketSource` factory. Assembles the adapter from sibling modules
|
|
3
|
+
* (createBoardSource + fetchResolvedIssue from ./fetch.ts;
|
|
4
|
+
* createLinearIssueStatusUpdater from ./writeback.ts; getLinearClient from
|
|
5
|
+
* ./client.ts) and converts Linear-specific shapes into the canonical
|
|
6
|
+
* Issue/Blocker types consumers (via Board) speak.
|
|
6
7
|
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* correctly without any per-team config.
|
|
8
|
+
* State classification is driven by Linear's workflow `state.type` — never
|
|
9
|
+
* by status name — so workspaces with renamed columns Just Work without
|
|
10
|
+
* per-team config.
|
|
11
11
|
*
|
|
12
|
-
* Description is
|
|
13
|
-
* doesn't include it); `resolveOne()` Issues carry the full description
|
|
14
|
-
* because `fetchResolvedIssue` fetches it explicitly.
|
|
12
|
+
* Description is populated on both `fetch()` Issues and `resolveOne()` Issues.
|
|
15
13
|
*/
|
|
16
14
|
import type { AdapterContext } from "../../adapterDefinition.ts";
|
|
17
|
-
import { type Issue as
|
|
18
|
-
import type { CanonicalStatus, Issue as CanonicalIssue, TicketSource } from "../../ticketSource.ts";
|
|
15
|
+
import { type Issue as CanonicalIssue, type TicketSource } from "../../ticketSource.ts";
|
|
19
16
|
import type { LinearAdapterConfig } from "./schema.ts";
|
|
20
|
-
|
|
17
|
+
import { type Issue as LinearIssue } from "./fetch.ts";
|
|
18
|
+
/**
|
|
19
|
+
* Adapter-private payload threaded through `Issue.sourceRef`. Consumers
|
|
20
|
+
* MUST NOT inspect; only the Linear adapter reads it.
|
|
21
|
+
*/
|
|
22
|
+
export interface LinearSourceRef {
|
|
23
|
+
uuid: string;
|
|
24
|
+
statusId: string;
|
|
25
|
+
teamId: string;
|
|
26
|
+
/** Linear workflow `state.type` for the issue at fetch time. */
|
|
27
|
+
stateType: string;
|
|
28
|
+
/** Human-readable native status name, e.g. "In Progress", "Shipped". Diagnostic display only. */
|
|
29
|
+
nativeStatus: string;
|
|
30
|
+
}
|
|
21
31
|
export declare function toCanonicalIssue(linearIssue: LinearIssue, sourceName: string): CanonicalIssue;
|
|
22
32
|
export declare function createLinearTicketSource(config: LinearAdapterConfig, context: AdapterContext): TicketSource;
|
|
23
33
|
//# sourceMappingURL=factory.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"factory.d.ts","sourceRoot":"","sources":["../../../../src/lib/adapters/linear/factory.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"factory.d.ts","sourceRoot":"","sources":["../../../../src/lib/adapters/linear/factory.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AACjE,OAAO,EAIL,KAAK,KAAK,IAAI,cAAc,EAE5B,KAAK,YAAY,EAClB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAEvD,OAAO,EAKL,KAAK,KAAK,IAAI,WAAW,EAE1B,MAAM,YAAY,CAAC;AAGpB;;;GAGG;AACH,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,gEAAgE;IAChE,SAAS,EAAE,MAAM,CAAC;IAClB,iGAAiG;IACjG,YAAY,EAAE,MAAM,CAAC;CACtB;AAkFD,wBAAgB,gBAAgB,CAAC,WAAW,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,GAAG,cAAc,CAsB7F;AAED,wBAAgB,wBAAwB,CACtC,MAAM,EAAE,mBAAmB,EAC3B,OAAO,EAAE,cAAc,GACtB,YAAY,CA+Ed"}
|