@h-rig/github-provider-plugin 0.0.6-alpha.156 → 0.0.6-alpha.158
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/src/identity-env.d.ts +16 -0
- package/dist/src/identity-env.js +239 -0
- package/dist/src/identity.d.ts +17 -0
- package/dist/src/identity.js +134 -0
- package/dist/src/index.d.ts +1 -4
- package/dist/src/index.js +360 -740
- package/dist/src/issue-analysis.d.ts +5 -5
- package/dist/src/issue-analysis.js +6 -6
- package/dist/src/lib.d.ts +16 -0
- package/dist/src/lib.js +485 -0
- package/dist/src/plugin.d.ts +6 -2
- package/dist/src/plugin.js +792 -31
- package/dist/src/profile-ops.d.ts +8 -0
- package/dist/src/profile-ops.js +9 -0
- package/dist/src/service.js +1 -35
- package/dist/src/token-env.d.ts +3 -0
- package/dist/src/token-env.js +26 -0
- package/dist/src/triage-run.js +12 -10
- package/package.json +24 -4
- package/dist/src/auth-store.d.ts +0 -42
- package/dist/src/auth-store.js +0 -226
- package/dist/src/credentials.d.ts +0 -20
- package/dist/src/credentials.js +0 -118
- package/dist/src/github-api.d.ts +0 -107
- package/dist/src/github-api.js +0 -451
- package/dist/src/projects.d.ts +0 -31
- package/dist/src/projects.js +0 -147
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* profile-ops.ts — re-export shim. The execution/review profile read/write IO
|
|
3
|
+
* was relocated to the floor (`@rig/core/profile-ops`) so the CLI seed,
|
|
4
|
+
* cli-surface, and bundle lifecycle use it as DATA without a cross-plugin impl
|
|
5
|
+
* import. This shim preserves the `@rig/github-provider-plugin/profile-ops`
|
|
6
|
+
* subpath; implementation now lives in @rig/core.
|
|
7
|
+
*/
|
|
8
|
+
export { setProfile, setReviewProfile, showProfile, showReviewProfile } from "@rig/core/profile-ops";
|
package/dist/src/service.js
CHANGED
|
@@ -1,40 +1,6 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
// packages/github-provider-plugin/src/credentials.ts
|
|
3
|
-
function selectedRepoTokenKey(input) {
|
|
4
|
-
return `user:${input.userId}|repo:${input.owner}/${input.repo}|workspace:${input.workspaceId}`;
|
|
5
|
-
}
|
|
6
|
-
function cleanToken(value) {
|
|
7
|
-
const trimmed = value?.trim() ?? "";
|
|
8
|
-
return trimmed.length > 0 ? trimmed : null;
|
|
9
|
-
}
|
|
10
|
-
function createGitHubCredentialProvider(options = {}) {
|
|
11
|
-
const sessionTokens = options.sessionTokens ?? {};
|
|
12
|
-
const hostToken = cleanToken(options.hostToken ?? process.env.GH_TOKEN ?? null);
|
|
13
|
-
return {
|
|
14
|
-
async resolveGitHubToken(input) {
|
|
15
|
-
const owner = input.owner.trim();
|
|
16
|
-
const repo = input.repo.trim();
|
|
17
|
-
const workspaceId = input.workspaceId.trim();
|
|
18
|
-
const userId = input.userId?.trim() ?? "";
|
|
19
|
-
if (input.purpose === "selected-repo") {
|
|
20
|
-
if (!owner || !repo || !workspaceId || !userId) {
|
|
21
|
-
throw new Error("No signed-in GitHub token is available for the selected repo; sign in to GitHub for this workspace.");
|
|
22
|
-
}
|
|
23
|
-
const token = cleanToken(sessionTokens[selectedRepoTokenKey({ owner, repo, workspaceId, userId })]);
|
|
24
|
-
if (!token) {
|
|
25
|
-
throw new Error("No signed-in GitHub token is available for the selected repo; sign in to GitHub for this workspace.");
|
|
26
|
-
}
|
|
27
|
-
return { token, source: "signed-in-user" };
|
|
28
|
-
}
|
|
29
|
-
if (hostToken) {
|
|
30
|
-
return { token: hostToken, source: "host-admin-fallback" };
|
|
31
|
-
}
|
|
32
|
-
throw new Error("No host GitHub token is configured for the explicit admin fallback operation.");
|
|
33
|
-
}
|
|
34
|
-
};
|
|
35
|
-
}
|
|
36
|
-
|
|
37
2
|
// packages/github-provider-plugin/src/service.ts
|
|
3
|
+
import { createGitHubCredentialProvider } from "@rig/github-lib";
|
|
38
4
|
var githubProviderService = {
|
|
39
5
|
createCredentialProvider: (options) => createGitHubCredentialProvider(options)
|
|
40
6
|
};
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export declare function cleanToken(value: string | null | undefined): string | null;
|
|
2
|
+
export declare function authStateToken(env?: Record<string, string | undefined>): string | null;
|
|
3
|
+
export declare function resolveGitHubAuthToken(env?: Record<string, string | undefined>): string | null;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
// packages/github-provider-plugin/src/token-env.ts
|
|
3
|
+
import { existsSync, readFileSync } from "fs";
|
|
4
|
+
function cleanToken(value) {
|
|
5
|
+
const trimmed = value?.trim() ?? "";
|
|
6
|
+
return trimmed.length > 0 ? trimmed : null;
|
|
7
|
+
}
|
|
8
|
+
function authStateToken(env = process.env) {
|
|
9
|
+
const file = env.RIG_GITHUB_AUTH_STATE_FILE?.trim();
|
|
10
|
+
if (!file || !existsSync(file))
|
|
11
|
+
return null;
|
|
12
|
+
try {
|
|
13
|
+
const parsed = JSON.parse(readFileSync(file, "utf8"));
|
|
14
|
+
return cleanToken(typeof parsed.token === "string" ? parsed.token : undefined);
|
|
15
|
+
} catch {
|
|
16
|
+
return null;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
function resolveGitHubAuthToken(env = process.env) {
|
|
20
|
+
return cleanToken(env.RIG_GITHUB_TOKEN) ?? cleanToken(env.GH_TOKEN) ?? cleanToken(env.GITHUB_TOKEN) ?? authStateToken(env);
|
|
21
|
+
}
|
|
22
|
+
export {
|
|
23
|
+
resolveGitHubAuthToken,
|
|
24
|
+
cleanToken,
|
|
25
|
+
authStateToken
|
|
26
|
+
};
|
package/dist/src/triage-run.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// @bun
|
|
2
2
|
// packages/github-provider-plugin/src/triage-run.ts
|
|
3
|
-
import { buildPluginHostContext } from "@rig/
|
|
3
|
+
import { buildPluginHostContext } from "@rig/core/plugin-host-context";
|
|
4
4
|
|
|
5
5
|
// packages/github-provider-plugin/src/issue-analysis.ts
|
|
6
6
|
import { createHash } from "crypto";
|
|
@@ -223,7 +223,7 @@ function createIssueAnalysisWriteBack(input) {
|
|
|
223
223
|
throw new Error("Issue analysis writeback requires removeLabels for labelsToRemove.");
|
|
224
224
|
await input.target.removeLabels(issue.id, uniqueLabels(result.labelsToRemove));
|
|
225
225
|
}
|
|
226
|
-
const comment = (input.buildStatusComment ?? defaultStatusComment)({ issue, result, reason });
|
|
226
|
+
const comment = (input.buildStatusComment ?? defaultStatusComment)({ issue, result, ...reason !== undefined ? { reason } : {} });
|
|
227
227
|
if (comment?.trim()) {
|
|
228
228
|
if (!input.target.updateTask)
|
|
229
229
|
throw new Error("Issue analysis writeback requires updateTask for sticky status comments.");
|
|
@@ -248,7 +248,7 @@ function sourceWithWriteBackCapabilities(source) {
|
|
|
248
248
|
if (typeof candidate.updateTask !== "function")
|
|
249
249
|
return null;
|
|
250
250
|
return {
|
|
251
|
-
get: candidate.get
|
|
251
|
+
...typeof candidate.get === "function" ? { get: candidate.get.bind(candidate) } : {},
|
|
252
252
|
updateTask: candidate.updateTask.bind(candidate),
|
|
253
253
|
...typeof candidate.addLabels === "function" ? { addLabels: candidate.addLabels.bind(candidate) } : {},
|
|
254
254
|
...typeof candidate.removeLabels === "function" ? { removeLabels: candidate.removeLabels.bind(candidate) } : {},
|
|
@@ -277,8 +277,8 @@ function createConfiguredIssueAnalysisRunner(input) {
|
|
|
277
277
|
if (!target)
|
|
278
278
|
return null;
|
|
279
279
|
const analyzer = input.analyzer ?? createPiIssueAnalyzer({
|
|
280
|
-
runCommand: input.runCommand,
|
|
281
|
-
model: input.context.config.issueAnalysis
|
|
280
|
+
...input.runCommand ? { runCommand: input.runCommand } : {},
|
|
281
|
+
...input.context.config.issueAnalysis?.model ? { model: input.context.config.issueAnalysis.model } : {}
|
|
282
282
|
});
|
|
283
283
|
const baseWriteBack = createIssueAnalysisWriteBack({ target });
|
|
284
284
|
const service = createIssueAnalysisService({
|
|
@@ -291,7 +291,7 @@ function createConfiguredIssueAnalysisRunner(input) {
|
|
|
291
291
|
return createContinuousIssueAnalysisRunner({
|
|
292
292
|
loadIssues: async () => [...await source.list()],
|
|
293
293
|
service,
|
|
294
|
-
intervalMs: input.intervalMs,
|
|
294
|
+
...input.intervalMs !== undefined ? { intervalMs: input.intervalMs } : {},
|
|
295
295
|
reason: "continuous-issue-analysis",
|
|
296
296
|
...input.setIntervalFn ? { setIntervalFn: input.setIntervalFn } : {},
|
|
297
297
|
...input.clearIntervalFn ? { clearIntervalFn: input.clearIntervalFn } : {},
|
|
@@ -312,7 +312,7 @@ function createIssueAnalysisService(input) {
|
|
|
312
312
|
const result = await input.analyzer({ issue, neighbors, prompt });
|
|
313
313
|
analyzedHashes.set(issue.id, hash);
|
|
314
314
|
if (result.metadataPatch || result.labelsToAdd?.length || result.labelsToRemove?.length || result.generatedIssues?.length) {
|
|
315
|
-
await input.writeBack?.({ issue, result, reason: options.reason });
|
|
315
|
+
await input.writeBack?.({ issue, result, ...options.reason !== undefined ? { reason: options.reason } : {} });
|
|
316
316
|
}
|
|
317
317
|
results.push({ issue, result });
|
|
318
318
|
}
|
|
@@ -390,7 +390,9 @@ async function loadContext(projectRoot) {
|
|
|
390
390
|
if (!context)
|
|
391
391
|
return null;
|
|
392
392
|
return {
|
|
393
|
-
config:
|
|
393
|
+
config: {
|
|
394
|
+
...context.config.issueAnalysis ? { issueAnalysis: context.config.issueAnalysis } : {}
|
|
395
|
+
},
|
|
394
396
|
taskSourceRegistry: context.taskSourceRegistry
|
|
395
397
|
};
|
|
396
398
|
}
|
|
@@ -448,8 +450,8 @@ async function runIssueAnalysisTriage(options) {
|
|
|
448
450
|
const runner = createConfiguredIssueAnalysisRunner({
|
|
449
451
|
projectRoot: options.projectRoot,
|
|
450
452
|
context,
|
|
451
|
-
analyzer: options.analyzer,
|
|
452
|
-
runCommand: options.runCommand,
|
|
453
|
+
...options.analyzer ? { analyzer: options.analyzer } : {},
|
|
454
|
+
...options.runCommand ? { runCommand: options.runCommand } : {},
|
|
453
455
|
onWriteBack: refreshSnapshotAfterWriteBack
|
|
454
456
|
});
|
|
455
457
|
if (!runner) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@h-rig/github-provider-plugin",
|
|
3
|
-
"version": "0.0.6-alpha.
|
|
3
|
+
"version": "0.0.6-alpha.158",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Swappable GitHub SCM-provider capability plugin for Rig (auth, credentials, Projects, issue analysis).",
|
|
6
6
|
"license": "UNLICENSED",
|
|
@@ -17,9 +17,29 @@
|
|
|
17
17
|
"types": "./dist/src/plugin.d.ts",
|
|
18
18
|
"import": "./dist/src/plugin.js"
|
|
19
19
|
},
|
|
20
|
+
"./lib": {
|
|
21
|
+
"types": "./dist/src/lib.d.ts",
|
|
22
|
+
"import": "./dist/src/lib.js"
|
|
23
|
+
},
|
|
20
24
|
"./index": {
|
|
21
25
|
"types": "./dist/src/index.d.ts",
|
|
22
26
|
"import": "./dist/src/index.js"
|
|
27
|
+
},
|
|
28
|
+
"./identity": {
|
|
29
|
+
"types": "./dist/src/identity.d.ts",
|
|
30
|
+
"import": "./dist/src/identity.js"
|
|
31
|
+
},
|
|
32
|
+
"./identity-env": {
|
|
33
|
+
"types": "./dist/src/identity-env.d.ts",
|
|
34
|
+
"import": "./dist/src/identity-env.js"
|
|
35
|
+
},
|
|
36
|
+
"./token-env": {
|
|
37
|
+
"types": "./dist/src/token-env.d.ts",
|
|
38
|
+
"import": "./dist/src/token-env.js"
|
|
39
|
+
},
|
|
40
|
+
"./profile-ops": {
|
|
41
|
+
"types": "./dist/src/profile-ops.d.ts",
|
|
42
|
+
"import": "./dist/src/profile-ops.js"
|
|
23
43
|
}
|
|
24
44
|
},
|
|
25
45
|
"engines": {
|
|
@@ -29,8 +49,8 @@
|
|
|
29
49
|
"module": "./dist/src/index.js",
|
|
30
50
|
"types": "./dist/src/index.d.ts",
|
|
31
51
|
"dependencies": {
|
|
32
|
-
"@rig/contracts": "npm:@h-rig/contracts@0.0.6-alpha.
|
|
33
|
-
"@rig/core": "npm:@h-rig/core@0.0.6-alpha.
|
|
34
|
-
"@rig/
|
|
52
|
+
"@rig/contracts": "npm:@h-rig/contracts@0.0.6-alpha.158",
|
|
53
|
+
"@rig/core": "npm:@h-rig/core@0.0.6-alpha.158",
|
|
54
|
+
"@rig/github-lib": "npm:@h-rig/github-lib@0.0.6-alpha.158"
|
|
35
55
|
}
|
|
36
56
|
}
|
package/dist/src/auth-store.d.ts
DELETED
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
import type { GitHubAuthStatus } from "@rig/contracts";
|
|
2
|
-
export type { GitHubAuthStatus };
|
|
3
|
-
type PendingDeviceFlow = {
|
|
4
|
-
readonly pollId: string;
|
|
5
|
-
readonly deviceCode: string;
|
|
6
|
-
readonly expiresAt: string;
|
|
7
|
-
readonly intervalSeconds: number;
|
|
8
|
-
};
|
|
9
|
-
export type GitHubAuthStore = {
|
|
10
|
-
readonly stateFile: string;
|
|
11
|
-
readonly status: (options?: {
|
|
12
|
-
oauthConfigured?: boolean;
|
|
13
|
-
}) => GitHubAuthStatus;
|
|
14
|
-
readonly readToken: () => string | null;
|
|
15
|
-
readonly saveToken: (input: {
|
|
16
|
-
readonly token: string;
|
|
17
|
-
readonly tokenSource: "oauth-device" | "manual-token";
|
|
18
|
-
readonly login?: string | null;
|
|
19
|
-
readonly userId?: string | null;
|
|
20
|
-
readonly scopes?: readonly string[];
|
|
21
|
-
readonly selectedRepo?: string | null;
|
|
22
|
-
}) => void;
|
|
23
|
-
readonly createApiSession: () => {
|
|
24
|
-
token: string;
|
|
25
|
-
login: string | null;
|
|
26
|
-
userId: string | null;
|
|
27
|
-
};
|
|
28
|
-
readonly readApiSession: (token: string) => {
|
|
29
|
-
login: string | null;
|
|
30
|
-
userId: string | null;
|
|
31
|
-
} | null;
|
|
32
|
-
readonly copyToProjectRoot: (projectRoot: string) => void;
|
|
33
|
-
readonly copyToLocalProjectRoot: (projectRoot: string) => void;
|
|
34
|
-
readonly savePendingDevice: (input: PendingDeviceFlow) => void;
|
|
35
|
-
readonly saveSelectedRepo: (selectedRepo: string | null) => void;
|
|
36
|
-
readonly readPendingDevice: (pollId: string) => PendingDeviceFlow | null;
|
|
37
|
-
readonly clearPendingDevice: (pollId?: string) => void;
|
|
38
|
-
};
|
|
39
|
-
export declare function resolveGitHubAuthStateFile(projectRoot: string): string;
|
|
40
|
-
export declare function copyGitHubAuthStateToLocalProjectRoot(stateFile: string, projectRoot: string): void;
|
|
41
|
-
export declare function createGitHubAuthStoreFromStateFile(stateFile: string): GitHubAuthStore;
|
|
42
|
-
export declare function createGitHubAuthStore(projectRoot: string): GitHubAuthStore;
|
package/dist/src/auth-store.js
DELETED
|
@@ -1,226 +0,0 @@
|
|
|
1
|
-
// @bun
|
|
2
|
-
// packages/github-provider-plugin/src/auth-store.ts
|
|
3
|
-
import { randomBytes } from "crypto";
|
|
4
|
-
import { chmodSync, copyFileSync, existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
|
|
5
|
-
import { dirname, resolve } from "path";
|
|
6
|
-
import { resolveRigStatePaths } from "@rig/runtime/control-plane/server-paths";
|
|
7
|
-
function cleanString(value) {
|
|
8
|
-
return typeof value === "string" && value.trim().length > 0 ? value.trim() : null;
|
|
9
|
-
}
|
|
10
|
-
function cleanScopes(value) {
|
|
11
|
-
if (!Array.isArray(value))
|
|
12
|
-
return [];
|
|
13
|
-
return value.flatMap((entry) => {
|
|
14
|
-
const clean = cleanString(entry);
|
|
15
|
-
return clean ? [clean] : [];
|
|
16
|
-
});
|
|
17
|
-
}
|
|
18
|
-
function parseApiSessions(value) {
|
|
19
|
-
if (!Array.isArray(value))
|
|
20
|
-
return [];
|
|
21
|
-
return value.flatMap((entry) => {
|
|
22
|
-
if (!entry || typeof entry !== "object" || Array.isArray(entry))
|
|
23
|
-
return [];
|
|
24
|
-
const record = entry;
|
|
25
|
-
const token = cleanString(record.token);
|
|
26
|
-
if (!token)
|
|
27
|
-
return [];
|
|
28
|
-
return [{
|
|
29
|
-
token,
|
|
30
|
-
login: cleanString(record.login),
|
|
31
|
-
userId: cleanString(record.userId),
|
|
32
|
-
createdAt: cleanString(record.createdAt) ?? undefined
|
|
33
|
-
}];
|
|
34
|
-
});
|
|
35
|
-
}
|
|
36
|
-
function parsePendingDevice(value) {
|
|
37
|
-
if (!value || typeof value !== "object")
|
|
38
|
-
return null;
|
|
39
|
-
const record = value;
|
|
40
|
-
const pollId = cleanString(record.pollId);
|
|
41
|
-
const deviceCode = cleanString(record.deviceCode);
|
|
42
|
-
const expiresAt = cleanString(record.expiresAt);
|
|
43
|
-
const intervalSeconds = typeof record.intervalSeconds === "number" && Number.isFinite(record.intervalSeconds) ? Math.max(1, Math.floor(record.intervalSeconds)) : null;
|
|
44
|
-
if (!pollId || !deviceCode || !expiresAt || !intervalSeconds)
|
|
45
|
-
return null;
|
|
46
|
-
return { pollId, deviceCode, expiresAt, intervalSeconds };
|
|
47
|
-
}
|
|
48
|
-
function parsePendingDevices(value) {
|
|
49
|
-
if (!Array.isArray(value))
|
|
50
|
-
return [];
|
|
51
|
-
return value.flatMap((entry) => {
|
|
52
|
-
const pending = parsePendingDevice(entry);
|
|
53
|
-
return pending ? [pending] : [];
|
|
54
|
-
});
|
|
55
|
-
}
|
|
56
|
-
function readStoredAuth(stateFile) {
|
|
57
|
-
if (!existsSync(stateFile))
|
|
58
|
-
return {};
|
|
59
|
-
try {
|
|
60
|
-
const parsed = JSON.parse(readFileSync(stateFile, "utf8"));
|
|
61
|
-
return {
|
|
62
|
-
...cleanString(parsed.token) ? { token: cleanString(parsed.token) } : {},
|
|
63
|
-
login: cleanString(parsed.login),
|
|
64
|
-
userId: cleanString(parsed.userId),
|
|
65
|
-
scopes: cleanScopes(parsed.scopes),
|
|
66
|
-
selectedRepo: cleanString(parsed.selectedRepo),
|
|
67
|
-
tokenSource: parsed.tokenSource === "oauth-device" || parsed.tokenSource === "manual-token" || parsed.tokenSource === "env" ? parsed.tokenSource : undefined,
|
|
68
|
-
pendingDevice: parsePendingDevice(parsed.pendingDevice),
|
|
69
|
-
pendingDevices: parsePendingDevices(parsed.pendingDevices),
|
|
70
|
-
apiSessions: parseApiSessions(parsed.apiSessions),
|
|
71
|
-
updatedAt: cleanString(parsed.updatedAt) ?? undefined
|
|
72
|
-
};
|
|
73
|
-
} catch {
|
|
74
|
-
return {};
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
function newApiSessionToken() {
|
|
78
|
-
return `rig_${randomBytes(32).toString("base64url")}`;
|
|
79
|
-
}
|
|
80
|
-
function writeStoredAuth(stateFile, payload) {
|
|
81
|
-
mkdirSync(dirname(stateFile), { recursive: true });
|
|
82
|
-
writeFileSync(stateFile, `${JSON.stringify(payload, null, 2)}
|
|
83
|
-
`, { encoding: "utf8", mode: 384 });
|
|
84
|
-
try {
|
|
85
|
-
chmodSync(stateFile, 384);
|
|
86
|
-
} catch {}
|
|
87
|
-
}
|
|
88
|
-
function localProjectAuthStateFile(projectRoot) {
|
|
89
|
-
return resolve(projectRoot, ".rig", "state", "github-auth.json");
|
|
90
|
-
}
|
|
91
|
-
function resolveGitHubAuthStateFile(projectRoot) {
|
|
92
|
-
return resolve(resolveRigStatePaths(projectRoot).stateDir, "github-auth.json");
|
|
93
|
-
}
|
|
94
|
-
function copyGitHubAuthStateToLocalProjectRoot(stateFile, projectRoot) {
|
|
95
|
-
const targetFile = localProjectAuthStateFile(projectRoot);
|
|
96
|
-
mkdirSync(dirname(targetFile), { recursive: true });
|
|
97
|
-
if (existsSync(stateFile)) {
|
|
98
|
-
copyFileSync(stateFile, targetFile);
|
|
99
|
-
try {
|
|
100
|
-
chmodSync(targetFile, 384);
|
|
101
|
-
} catch {}
|
|
102
|
-
return;
|
|
103
|
-
}
|
|
104
|
-
writeStoredAuth(targetFile, {});
|
|
105
|
-
}
|
|
106
|
-
function createGitHubAuthStoreFromStateFile(stateFile) {
|
|
107
|
-
return {
|
|
108
|
-
stateFile,
|
|
109
|
-
status(options) {
|
|
110
|
-
const stored = readStoredAuth(stateFile);
|
|
111
|
-
const token = cleanString(stored.token);
|
|
112
|
-
return {
|
|
113
|
-
signedIn: Boolean(token),
|
|
114
|
-
login: cleanString(stored.login),
|
|
115
|
-
userId: cleanString(stored.userId),
|
|
116
|
-
scopes: cleanScopes(stored.scopes),
|
|
117
|
-
selectedRepo: cleanString(stored.selectedRepo),
|
|
118
|
-
oauthConfigured: options?.oauthConfigured === true,
|
|
119
|
-
tokenSource: token ? stored.tokenSource ?? "manual-token" : null
|
|
120
|
-
};
|
|
121
|
-
},
|
|
122
|
-
readToken() {
|
|
123
|
-
return cleanString(readStoredAuth(stateFile).token);
|
|
124
|
-
},
|
|
125
|
-
saveToken(input) {
|
|
126
|
-
const previous = readStoredAuth(stateFile);
|
|
127
|
-
writeStoredAuth(stateFile, {
|
|
128
|
-
...previous,
|
|
129
|
-
token: input.token,
|
|
130
|
-
tokenSource: input.tokenSource,
|
|
131
|
-
login: input.login ?? null,
|
|
132
|
-
userId: input.userId ?? null,
|
|
133
|
-
scopes: input.scopes ?? [],
|
|
134
|
-
selectedRepo: input.selectedRepo ?? previous.selectedRepo ?? null,
|
|
135
|
-
pendingDevice: null,
|
|
136
|
-
pendingDevices: [],
|
|
137
|
-
apiSessions: previous.apiSessions ?? [],
|
|
138
|
-
updatedAt: new Date().toISOString()
|
|
139
|
-
});
|
|
140
|
-
},
|
|
141
|
-
createApiSession() {
|
|
142
|
-
const previous = readStoredAuth(stateFile);
|
|
143
|
-
const token = newApiSessionToken();
|
|
144
|
-
const session = {
|
|
145
|
-
token,
|
|
146
|
-
login: cleanString(previous.login),
|
|
147
|
-
userId: cleanString(previous.userId),
|
|
148
|
-
createdAt: new Date().toISOString()
|
|
149
|
-
};
|
|
150
|
-
writeStoredAuth(stateFile, {
|
|
151
|
-
...previous,
|
|
152
|
-
apiSessions: [...(previous.apiSessions ?? []).slice(-9), session],
|
|
153
|
-
updatedAt: new Date().toISOString()
|
|
154
|
-
});
|
|
155
|
-
return { token, login: session.login ?? null, userId: session.userId ?? null };
|
|
156
|
-
},
|
|
157
|
-
readApiSession(token) {
|
|
158
|
-
const clean = cleanString(token);
|
|
159
|
-
if (!clean)
|
|
160
|
-
return null;
|
|
161
|
-
const previous = readStoredAuth(stateFile);
|
|
162
|
-
const session = (previous.apiSessions ?? []).find((candidate) => candidate.token === clean);
|
|
163
|
-
return session ? { login: cleanString(session.login), userId: cleanString(session.userId) } : null;
|
|
164
|
-
},
|
|
165
|
-
copyToProjectRoot(projectRoot) {
|
|
166
|
-
const targetFile = resolveGitHubAuthStateFile(projectRoot);
|
|
167
|
-
writeStoredAuth(targetFile, readStoredAuth(stateFile));
|
|
168
|
-
},
|
|
169
|
-
copyToLocalProjectRoot(projectRoot) {
|
|
170
|
-
copyGitHubAuthStateToLocalProjectRoot(stateFile, projectRoot);
|
|
171
|
-
},
|
|
172
|
-
savePendingDevice(input) {
|
|
173
|
-
const previous = readStoredAuth(stateFile);
|
|
174
|
-
const pendingDevices = [
|
|
175
|
-
...previous.pendingDevice ? [previous.pendingDevice] : [],
|
|
176
|
-
...previous.pendingDevices ?? [],
|
|
177
|
-
input
|
|
178
|
-
].filter((entry, index, entries) => entries.findIndex((candidate) => candidate.pollId === entry.pollId) === index);
|
|
179
|
-
writeStoredAuth(stateFile, {
|
|
180
|
-
...previous,
|
|
181
|
-
pendingDevice: null,
|
|
182
|
-
pendingDevices,
|
|
183
|
-
updatedAt: new Date().toISOString()
|
|
184
|
-
});
|
|
185
|
-
},
|
|
186
|
-
saveSelectedRepo(selectedRepo) {
|
|
187
|
-
const previous = readStoredAuth(stateFile);
|
|
188
|
-
writeStoredAuth(stateFile, {
|
|
189
|
-
...previous,
|
|
190
|
-
selectedRepo: selectedRepo ?? null,
|
|
191
|
-
updatedAt: new Date().toISOString()
|
|
192
|
-
});
|
|
193
|
-
},
|
|
194
|
-
readPendingDevice(pollId) {
|
|
195
|
-
const previous = readStoredAuth(stateFile);
|
|
196
|
-
const pending = [
|
|
197
|
-
...previous.pendingDevice ? [previous.pendingDevice] : [],
|
|
198
|
-
...previous.pendingDevices ?? []
|
|
199
|
-
].find((entry) => entry.pollId === pollId) ?? null;
|
|
200
|
-
if (!pending)
|
|
201
|
-
return null;
|
|
202
|
-
if (Date.parse(pending.expiresAt) <= Date.now())
|
|
203
|
-
return null;
|
|
204
|
-
return pending;
|
|
205
|
-
},
|
|
206
|
-
clearPendingDevice(pollId) {
|
|
207
|
-
const previous = readStoredAuth(stateFile);
|
|
208
|
-
const remaining = pollId ? (previous.pendingDevices ?? []).filter((entry) => entry.pollId !== pollId) : [];
|
|
209
|
-
writeStoredAuth(stateFile, {
|
|
210
|
-
...previous,
|
|
211
|
-
pendingDevice: null,
|
|
212
|
-
pendingDevices: remaining,
|
|
213
|
-
updatedAt: new Date().toISOString()
|
|
214
|
-
});
|
|
215
|
-
}
|
|
216
|
-
};
|
|
217
|
-
}
|
|
218
|
-
function createGitHubAuthStore(projectRoot) {
|
|
219
|
-
return createGitHubAuthStoreFromStateFile(resolveGitHubAuthStateFile(projectRoot));
|
|
220
|
-
}
|
|
221
|
-
export {
|
|
222
|
-
resolveGitHubAuthStateFile,
|
|
223
|
-
createGitHubAuthStoreFromStateFile,
|
|
224
|
-
createGitHubAuthStore,
|
|
225
|
-
copyGitHubAuthStateToLocalProjectRoot
|
|
226
|
-
};
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import type { GitHubCredentialProvider, GitHubCredentialProviderOptions, GitHubStateCredentialProviderOptions } from "@rig/contracts";
|
|
2
|
-
export type { GitHubCredentialProvider, GitHubCredentialProviderOptions, GitHubCredentialPurpose, GitHubCredentialSource, GitHubStateCredentialProviderOptions, ResolveGitHubTokenInput, ResolvedGitHubToken, } from "@rig/contracts";
|
|
3
|
-
/**
|
|
4
|
-
* Session-token-map credential provider. Selected-repo operations resolve from
|
|
5
|
-
* the per-session token map; admin-fallback resolves from the host token.
|
|
6
|
-
*/
|
|
7
|
-
export declare function createGitHubCredentialProvider(options?: GitHubCredentialProviderOptions): GitHubCredentialProvider;
|
|
8
|
-
/**
|
|
9
|
-
* Env-only credential provider. Selected-repo reads `RIG_GITHUB_SELECTED_TOKEN`
|
|
10
|
-
* (browser-selected public repos read without a token); admin-fallback reads the
|
|
11
|
-
* host token env vars. Consolidated here from task-sources so the credential
|
|
12
|
-
* abstraction has a single home.
|
|
13
|
-
*/
|
|
14
|
-
export declare function createEnvGitHubCredentialProvider(): GitHubCredentialProvider;
|
|
15
|
-
/**
|
|
16
|
-
* State-file-backed credential provider. Resolves the signed-in token from a
|
|
17
|
-
* `github-auth.json` discovered across explicit/state/project-root candidates,
|
|
18
|
-
* falling back to host token env vars. Consolidated here from task-sources.
|
|
19
|
-
*/
|
|
20
|
-
export declare function createStateGitHubCredentialProvider(options?: GitHubStateCredentialProviderOptions): GitHubCredentialProvider;
|
package/dist/src/credentials.js
DELETED
|
@@ -1,118 +0,0 @@
|
|
|
1
|
-
// @bun
|
|
2
|
-
// packages/github-provider-plugin/src/credentials.ts
|
|
3
|
-
import { existsSync, readFileSync } from "fs";
|
|
4
|
-
import { resolve } from "path";
|
|
5
|
-
function selectedRepoTokenKey(input) {
|
|
6
|
-
return `user:${input.userId}|repo:${input.owner}/${input.repo}|workspace:${input.workspaceId}`;
|
|
7
|
-
}
|
|
8
|
-
function cleanToken(value) {
|
|
9
|
-
const trimmed = value?.trim() ?? "";
|
|
10
|
-
return trimmed.length > 0 ? trimmed : null;
|
|
11
|
-
}
|
|
12
|
-
function createGitHubCredentialProvider(options = {}) {
|
|
13
|
-
const sessionTokens = options.sessionTokens ?? {};
|
|
14
|
-
const hostToken = cleanToken(options.hostToken ?? process.env.GH_TOKEN ?? null);
|
|
15
|
-
return {
|
|
16
|
-
async resolveGitHubToken(input) {
|
|
17
|
-
const owner = input.owner.trim();
|
|
18
|
-
const repo = input.repo.trim();
|
|
19
|
-
const workspaceId = input.workspaceId.trim();
|
|
20
|
-
const userId = input.userId?.trim() ?? "";
|
|
21
|
-
if (input.purpose === "selected-repo") {
|
|
22
|
-
if (!owner || !repo || !workspaceId || !userId) {
|
|
23
|
-
throw new Error("No signed-in GitHub token is available for the selected repo; sign in to GitHub for this workspace.");
|
|
24
|
-
}
|
|
25
|
-
const token = cleanToken(sessionTokens[selectedRepoTokenKey({ owner, repo, workspaceId, userId })]);
|
|
26
|
-
if (!token) {
|
|
27
|
-
throw new Error("No signed-in GitHub token is available for the selected repo; sign in to GitHub for this workspace.");
|
|
28
|
-
}
|
|
29
|
-
return { token, source: "signed-in-user" };
|
|
30
|
-
}
|
|
31
|
-
if (hostToken) {
|
|
32
|
-
return { token: hostToken, source: "host-admin-fallback" };
|
|
33
|
-
}
|
|
34
|
-
throw new Error("No host GitHub token is configured for the explicit admin fallback operation.");
|
|
35
|
-
}
|
|
36
|
-
};
|
|
37
|
-
}
|
|
38
|
-
function createEnvGitHubCredentialProvider() {
|
|
39
|
-
return {
|
|
40
|
-
async resolveGitHubToken(input) {
|
|
41
|
-
if (input.purpose === "selected-repo") {
|
|
42
|
-
return { token: cleanToken(process.env.RIG_GITHUB_SELECTED_TOKEN ?? null) ?? "", source: "signed-in-user" };
|
|
43
|
-
}
|
|
44
|
-
const token = cleanToken(process.env.RIG_GITHUB_TOKEN ?? process.env.GH_TOKEN ?? process.env.GITHUB_TOKEN ?? null);
|
|
45
|
-
if (!token) {
|
|
46
|
-
throw new Error("No host GitHub token is configured for admin fallback.");
|
|
47
|
-
}
|
|
48
|
-
return { token, source: "host-admin-fallback" };
|
|
49
|
-
}
|
|
50
|
-
};
|
|
51
|
-
}
|
|
52
|
-
function createStateGitHubCredentialProvider(options = {}) {
|
|
53
|
-
const addCandidate = (candidates, path) => {
|
|
54
|
-
const trimmed = path?.trim();
|
|
55
|
-
if (!trimmed)
|
|
56
|
-
return;
|
|
57
|
-
const resolved = resolve(trimmed);
|
|
58
|
-
if (!candidates.includes(resolved))
|
|
59
|
-
candidates.push(resolved);
|
|
60
|
-
};
|
|
61
|
-
const addStateDir = (candidates, dir) => {
|
|
62
|
-
const trimmed = dir?.trim();
|
|
63
|
-
if (!trimmed)
|
|
64
|
-
return;
|
|
65
|
-
addCandidate(candidates, resolve(trimmed, "github-auth.json"));
|
|
66
|
-
};
|
|
67
|
-
const addProjectStateDir = (candidates, root) => {
|
|
68
|
-
const trimmed = root?.trim();
|
|
69
|
-
if (!trimmed)
|
|
70
|
-
return;
|
|
71
|
-
addStateDir(candidates, resolve(trimmed, ".rig", "state"));
|
|
72
|
-
};
|
|
73
|
-
const stateFileCandidates = () => {
|
|
74
|
-
const candidates = [];
|
|
75
|
-
addCandidate(candidates, options.stateFile ?? process.env.RIG_GITHUB_AUTH_STATE_FILE);
|
|
76
|
-
addStateDir(candidates, options.stateDir);
|
|
77
|
-
addStateDir(candidates, process.env.RIG_STATE_DIR);
|
|
78
|
-
addProjectStateDir(candidates, process.env.PROJECT_RIG_ROOT);
|
|
79
|
-
addProjectStateDir(candidates, process.env.RIG_PROJECT_ROOT);
|
|
80
|
-
addProjectStateDir(candidates, process.env.RIG_HOST_PROJECT_ROOT);
|
|
81
|
-
addProjectStateDir(candidates, process.cwd());
|
|
82
|
-
return candidates;
|
|
83
|
-
};
|
|
84
|
-
const readToken = () => {
|
|
85
|
-
for (const stateFile of stateFileCandidates()) {
|
|
86
|
-
if (!existsSync(stateFile))
|
|
87
|
-
continue;
|
|
88
|
-
try {
|
|
89
|
-
const parsed = JSON.parse(readFileSync(stateFile, "utf8"));
|
|
90
|
-
const token = typeof parsed.token === "string" ? cleanToken(parsed.token) : null;
|
|
91
|
-
if (token)
|
|
92
|
-
return token;
|
|
93
|
-
} catch {}
|
|
94
|
-
}
|
|
95
|
-
return null;
|
|
96
|
-
};
|
|
97
|
-
return {
|
|
98
|
-
async resolveGitHubToken(input) {
|
|
99
|
-
const token = readToken();
|
|
100
|
-
if (input.purpose === "selected-repo") {
|
|
101
|
-
return { token: token ?? cleanToken(process.env.RIG_GITHUB_SELECTED_TOKEN ?? null) ?? "", source: "signed-in-user" };
|
|
102
|
-
}
|
|
103
|
-
if (token) {
|
|
104
|
-
return { token, source: "signed-in-user" };
|
|
105
|
-
}
|
|
106
|
-
const fallback = cleanToken(process.env.RIG_GITHUB_TOKEN ?? process.env.GH_TOKEN ?? process.env.GITHUB_TOKEN ?? null);
|
|
107
|
-
if (!fallback) {
|
|
108
|
-
throw new Error("No signed-in GitHub token is stored for Rig and no host admin fallback token is configured.");
|
|
109
|
-
}
|
|
110
|
-
return { token: fallback, source: "host-admin-fallback" };
|
|
111
|
-
}
|
|
112
|
-
};
|
|
113
|
-
}
|
|
114
|
-
export {
|
|
115
|
-
createStateGitHubCredentialProvider,
|
|
116
|
-
createGitHubCredentialProvider,
|
|
117
|
-
createEnvGitHubCredentialProvider
|
|
118
|
-
};
|