dsh-plugin-github-issues 0.0.0-stage → 0.4.7

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 (57) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +147 -2
  3. package/cordis.patch.yml +20 -0
  4. package/docs/README.zh.md +134 -0
  5. package/icon.svg +9 -0
  6. package/lib/client.js +3243 -0
  7. package/lib/controller.js +289 -0
  8. package/lib/controller.js.map +1 -0
  9. package/lib/github/auth.js +249 -0
  10. package/lib/github/auth.js.map +1 -0
  11. package/lib/github/client.js +767 -0
  12. package/lib/github/client.js.map +1 -0
  13. package/lib/github/queries.js +479 -0
  14. package/lib/github/queries.js.map +1 -0
  15. package/lib/github/state.js +186 -0
  16. package/lib/github/state.js.map +1 -0
  17. package/lib/github/types.js +29 -0
  18. package/lib/github/types.js.map +1 -0
  19. package/lib/github/vm.js +362 -0
  20. package/lib/github/vm.js.map +1 -0
  21. package/lib/index.js +65 -0
  22. package/lib/index.js.map +1 -0
  23. package/lib/prompt.js +87 -0
  24. package/lib/prompt.js.map +1 -0
  25. package/lib/remote-methods.js +32 -0
  26. package/lib/remote-methods.js.map +1 -0
  27. package/lib/types/controller.d.ts +105 -0
  28. package/lib/types/controller.d.ts.map +1 -0
  29. package/lib/types/github/auth.d.ts +52 -0
  30. package/lib/types/github/auth.d.ts.map +1 -0
  31. package/lib/types/github/client.d.ts +40 -0
  32. package/lib/types/github/client.d.ts.map +1 -0
  33. package/lib/types/github/queries.d.ts +172 -0
  34. package/lib/types/github/queries.d.ts.map +1 -0
  35. package/lib/types/github/state.d.ts +51 -0
  36. package/lib/types/github/state.d.ts.map +1 -0
  37. package/lib/types/github/types.d.ts +79 -0
  38. package/lib/types/github/types.d.ts.map +1 -0
  39. package/lib/types/github/vm.d.ts +260 -0
  40. package/lib/types/github/vm.d.ts.map +1 -0
  41. package/lib/types/index.d.ts +46 -0
  42. package/lib/types/index.d.ts.map +1 -0
  43. package/lib/types/prompt.d.ts +30 -0
  44. package/lib/types/prompt.d.ts.map +1 -0
  45. package/lib/types/remote-methods.d.ts +32 -0
  46. package/lib/types/remote-methods.d.ts.map +1 -0
  47. package/lib/types/vm.d.ts +264 -0
  48. package/lib/types/vm.d.ts.map +1 -0
  49. package/lib/types/workspace.d.ts +43 -0
  50. package/lib/types/workspace.d.ts.map +1 -0
  51. package/lib/vm.js +42 -0
  52. package/lib/vm.js.map +1 -0
  53. package/lib/workspace.js +57 -0
  54. package/lib/workspace.js.map +1 -0
  55. package/locale/en.json +6 -0
  56. package/locale/zh.json +6 -0
  57. package/package.json +97 -4
package/lib/index.js ADDED
@@ -0,0 +1,65 @@
1
+ /**
2
+ * The bundle's Host entry point.
3
+ *
4
+ * A bundle is a configuration layer, so this module exists to do the one thing a
5
+ * layer cannot: own the live GitHub service and the machine-local preferences, and
6
+ * expose them to the browser through the plugin's own Remote namespace.
7
+ *
8
+ * @module dsh-plugin-github-issues
9
+ */
10
+ import { homedir } from 'node:os';
11
+ import { join } from 'node:path';
12
+ import z from '@deepseek-ai/schemastery';
13
+ import { GitHubIssuesController } from "./controller.js";
14
+ import { probeGh, resolveToken } from "./github/auth.js";
15
+ import { createGitHubApi } from "./github/client.js";
16
+ import { PrefsStore } from "./github/state.js";
17
+ /** What this plugin calls itself in diagnostics. */
18
+ export const name = 'github-issues';
19
+ /**
20
+ * Everything an installation may tune.
21
+ *
22
+ * No token lives here on purpose: the deployment's patch and its `.bak` copies
23
+ * would duplicate it. The token is read from the machine's `gh` CLI at call time.
24
+ */
25
+ export const Config = z.object({
26
+ /** How the Host obtains a token; `gh` is the only mode in v0.1. */
27
+ authMode: z.string().default('gh'),
28
+ /** GitHub host, `github.com` or a GitHub Enterprise hostname. */
29
+ host: z.string().default('github.com'),
30
+ /** Explicit `gh` executable path, when the app's PATH cannot find one. */
31
+ ghPath: z.string().default(''),
32
+ /** Default handoff behavior: `draft` fills the composer, `send` submits it. */
33
+ handoffMode: z.string().default('draft'),
34
+ /** Seconds between list refreshes while the panel is visible. */
35
+ pollSeconds: z.number().default(90),
36
+ /** Directory for non-secret UI state; defaults to `$DSH_HOME/github-issues`. */
37
+ stateDir: z.string().default(''),
38
+ /** Default prompt template; empty means the built-in one. */
39
+ promptTemplate: z.string().default(''),
40
+ });
41
+ /**
42
+ * Register the GitHub service.
43
+ * @param ctx - the plugin context.
44
+ * @param config - the installation's configuration.
45
+ */
46
+ export function apply(ctx, config) {
47
+ const stateDir = config.stateDir === ''
48
+ ? join(process.env.DSH_HOME ?? join(homedir(), '.dsh'), 'github-issues')
49
+ : config.stateDir;
50
+ const prefs = new PrefsStore(stateDir, config.handoffMode, config.promptTemplate);
51
+ new GitHubIssuesController(ctx, {
52
+ probeGh,
53
+ resolveToken,
54
+ createApi: createGitHubApi,
55
+ prefs,
56
+ config: {
57
+ authMode: config.authMode,
58
+ host: config.host,
59
+ ghPath: config.ghPath,
60
+ handoffMode: config.handoffMode,
61
+ pollSeconds: config.pollSeconds,
62
+ },
63
+ });
64
+ }
65
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAA;AACjC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAGhC,OAAO,CAAC,MAAM,0BAA0B,CAAA;AAExC,OAAO,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAA;AACxD,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAA;AACxD,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAA;AACpD,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAA;AAE9C,oDAAoD;AACpD,MAAM,CAAC,MAAM,IAAI,GAAG,eAAe,CAAA;AAEnC;;;;;GAKG;AACH,MAAM,CAAC,MAAM,MAAM,GAAG,CAAC,CAAC,MAAM,CAAC;IAC7B,mEAAmE;IACnE,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC;IAClC,iEAAiE;IACjE,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,YAAY,CAAC;IACtC,0EAA0E;IAC1E,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC;IAC9B,+EAA+E;IAC/E,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC;IACxC,iEAAiE;IACjE,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC;IACnC,gFAAgF;IAChF,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC;IAChC,6DAA6D;IAC7D,cAAc,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC;CACvC,CAAC,CAAA;AAaF;;;;GAIG;AACH,MAAM,UAAU,KAAK,CAAC,GAAY,EAAE,MAAc;IAChD,MAAM,QAAQ,GAAG,MAAM,CAAC,QAAQ,KAAK,EAAE;QACrC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,IAAI,IAAI,CAAC,OAAO,EAAE,EAAE,MAAM,CAAC,EAAE,eAAe,CAAC;QACxE,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAA;IAEnB,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,QAAQ,EAAE,MAAM,CAAC,WAAW,EAAE,MAAM,CAAC,cAAc,CAAC,CAAA;IACjF,IAAI,sBAAsB,CAAC,GAAG,EAAE;QAC9B,OAAO;QACP,YAAY;QACZ,SAAS,EAAE,eAAe;QAC1B,KAAK;QACL,MAAM,EAAE;YACN,QAAQ,EAAE,MAAM,CAAC,QAAQ;YACzB,IAAI,EAAE,MAAM,CAAC,IAAI;YACjB,MAAM,EAAE,MAAM,CAAC,MAAM;YACrB,WAAW,EAAE,MAAM,CAAC,WAAW;YAC/B,WAAW,EAAE,MAAM,CAAC,WAAW;SAChC;KACF,CAAC,CAAA;AACJ,CAAC"}
package/lib/prompt.js ADDED
@@ -0,0 +1,87 @@
1
+ /**
2
+ * Turning one issue into the prompt a handoff writes into the composer.
3
+ *
4
+ * Kept apart from the UI so the exact wording is testable, and so the Host can
5
+ * reuse it when it needs to describe an issue without the browser.
6
+ *
7
+ * @module dsh-plugin-github-issues/prompt
8
+ */
9
+ import { DEFAULT_PROMPT_TEMPLATE } from "./vm.js";
10
+ /** Fill one `{{token}}` occurrence. */
11
+ function fill(template, token, value) {
12
+ return template.split(`{{${token}}}`).join(value);
13
+ }
14
+ /** A human-readable state line. */
15
+ function stateText(issue) {
16
+ if (issue.state === 'OPEN')
17
+ return 'Open';
18
+ return issue.stateReason === 'COMPLETED' ? 'Closed (completed)' : `Closed (${issue.stateReason ?? 'no reason'})`;
19
+ }
20
+ /** The linked-PR line, naming each PR's state so the agent knows what exists. */
21
+ function prsText(issue) {
22
+ if (issue.linkedPRs.length === 0)
23
+ return '无';
24
+ return issue.linkedPRs
25
+ .map(pr => {
26
+ const state = pr.merged ? 'merged' : pr.state.toLowerCase();
27
+ return `#${String(pr.number)} (${state}${pr.checks === null ? '' : `, checks ${pr.checks.toLowerCase()}`})`;
28
+ })
29
+ .join('、');
30
+ }
31
+ /** The milestone line. */
32
+ function milestoneText(issue) {
33
+ if (issue.milestone === undefined)
34
+ return '无';
35
+ const due = issue.milestone.dueOn === null ? '' : `, due ${issue.milestone.dueOn}`;
36
+ const progress = issue.milestone.progress === null ? '' : `, ${String(issue.milestone.progress)}%`;
37
+ return `${issue.milestone.title}${due}${progress}`;
38
+ }
39
+ /** The priority line, including where the value came from. */
40
+ function priorityText(issue) {
41
+ if (issue.priority === undefined)
42
+ return '无';
43
+ const source = issue.priority.source === 'project'
44
+ ? 'project field'
45
+ : issue.priority.source === 'issue-field' ? 'issue field' : 'label';
46
+ return `${issue.priority.name} (${source})`;
47
+ }
48
+ /**
49
+ * Render the handoff prompt for one issue.
50
+ * @param issue - the card the user dragged or clicked.
51
+ * @param template - the configured template; `{{token}}` placeholders are replaced.
52
+ * @returns the prompt text, trimmed to a size the composer handles comfortably.
53
+ */
54
+ export function renderPrompt(issue, template) {
55
+ const source = template === '' ? DEFAULT_PROMPT_TEMPLATE : template;
56
+ let text = source;
57
+ text = fill(text, 'repo', issue.repo);
58
+ text = fill(text, 'number', String(issue.number));
59
+ text = fill(text, 'title', issue.title);
60
+ text = fill(text, 'url', issue.url);
61
+ text = fill(text, 'state', stateText(issue));
62
+ text = fill(text, 'milestone', milestoneText(issue));
63
+ text = fill(text, 'priority', priorityText(issue));
64
+ text = fill(text, 'assignees', issue.assignees.length === 0 ? '未指派' : issue.assignees.map(a => a.login).join(', '));
65
+ text = fill(text, 'labels', issue.labels.length === 0 ? '无' : issue.labels.map(l => l.name).join(', '));
66
+ text = fill(text, 'prs', prsText(issue));
67
+ if (text.length > 8_000)
68
+ return `${text.slice(0, 7_990)}\n…(已截断)`;
69
+ return text;
70
+ }
71
+ /** The invisible draft placeholder that keeps the native send enabled. */
72
+ export const EMPTY_DRAFT_HOLD = '\u200b\n';
73
+ /**
74
+ * Compose the message a pending issue card sends.
75
+ *
76
+ * The card carries the issue prompt; the user's own words are optional and are
77
+ * appended after a blank line. The invisible composer placeholder is stripped.
78
+ *
79
+ * @param prompt - the rendered issue prompt from the card.
80
+ * @param memo - the user's text from the composer (may contain the placeholder).
81
+ * @returns the text to submit.
82
+ */
83
+ export function composeHandoffPrompt(prompt, memo) {
84
+ const extra = memo.replace(/\u200b/g, '').replace(/^\n+/, '').trim();
85
+ return extra === '' ? prompt : `${prompt}\n\n${extra}`;
86
+ }
87
+ //# sourceMappingURL=prompt.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prompt.js","sourceRoot":"","sources":["../src/prompt.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * The Remote surface, described once for both halves.
3
+ *
4
+ * The browser half cannot use the generated `ctx.remote.*` aggregate: that is
5
+ * assembled at build time from a fixed list of shipped packages. So the client
6
+ * mounts its own contribution (see `src/client/remote.ts`) built from this table,
7
+ * and the Host half decorates exactly these methods with `@Remote`. A method added
8
+ * to one side and forgotten here fails only when a user clicks.
9
+ *
10
+ * @module dsh-plugin-github-issues/remote-methods
11
+ */
12
+ /** Every method the browser may call. */
13
+ export const REMOTE_METHODS = [
14
+ { method: 'status', parameters: [] },
15
+ { method: 'catalog', parameters: [] },
16
+ { method: 'orgProjects', parameters: [{ wire: 'org' }] },
17
+ { method: 'orgRepos', parameters: [{ wire: 'org' }] },
18
+ { method: 'listIssues', parameters: [{ wire: 'request' }] },
19
+ { method: 'issueDetail', parameters: [{ wire: 'repo' }, { wire: 'number' }] },
20
+ { method: 'issueMentionedPRs', parameters: [{ wire: 'repo' }, { wire: 'number' }] },
21
+ { method: 'loadPrefs', parameters: [] },
22
+ { method: 'savePrefs', parameters: [{ wire: 'patch' }] },
23
+ { method: 'refresh', parameters: [] },
24
+ { method: 'links', parameters: [] },
25
+ { method: 'linkIssue', parameters: [{ wire: 'repo' }, { wire: 'number' }, { wire: 'sessionId' }] },
26
+ { method: 'unlinkIssue', parameters: [{ wire: 'repo' }, { wire: 'number' }, { wire: 'sessionId', optional: true }] },
27
+ ];
28
+ /** The Cordis service key the controller registers, and the descriptor's `service` field. */
29
+ export const REMOTE_SERVICE_KEY = 'githubIssuesController';
30
+ /** The wire namespace both halves address this surface by. */
31
+ export const REMOTE_NAMESPACE = 'githubIssues';
32
+ //# sourceMappingURL=remote-methods.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"remote-methods.js","sourceRoot":"","sources":["../src/remote-methods.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAkBH,yCAAyC;AACzC,MAAM,CAAC,MAAM,cAAc,GAA4B;IACrD,EAAE,MAAM,EAAE,QAAQ,EAAE,UAAU,EAAE,EAAE,EAAE;IACpC,EAAE,MAAM,EAAE,SAAS,EAAE,UAAU,EAAE,EAAE,EAAE;IACrC,EAAE,MAAM,EAAE,aAAa,EAAE,UAAU,EAAE,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,EAAE;IACxD,EAAE,MAAM,EAAE,UAAU,EAAE,UAAU,EAAE,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,EAAE;IACrD,EAAE,MAAM,EAAE,YAAY,EAAE,UAAU,EAAE,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,EAAE;IAC3D,EAAE,MAAM,EAAE,aAAa,EAAE,UAAU,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,EAAE;IAC7E,EAAE,MAAM,EAAE,mBAAmB,EAAE,UAAU,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,EAAE;IACnF,EAAE,MAAM,EAAE,WAAW,EAAE,UAAU,EAAE,EAAE,EAAE;IACvC,EAAE,MAAM,EAAE,WAAW,EAAE,UAAU,EAAE,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,EAAE;IACxD,EAAE,MAAM,EAAE,SAAS,EAAE,UAAU,EAAE,EAAE,EAAE;IACrC,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE,EAAE,EAAE;IACnC,EAAE,MAAM,EAAE,WAAW,EAAE,UAAU,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC,EAAE;IAClG,EAAE,MAAM,EAAE,aAAa,EAAE,UAAU,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,EAAE;CACrH,CAAA;AAED,6FAA6F;AAC7F,MAAM,CAAC,MAAM,kBAAkB,GAAG,wBAAwB,CAAA;AAE1D,8DAA8D;AAC9D,MAAM,CAAC,MAAM,gBAAgB,GAAG,cAAc,CAAA"}
@@ -0,0 +1,105 @@
1
+ /**
2
+ * The browser's way into GitHub.
3
+ *
4
+ * Everything that needs a credential happens here or below: the token is resolved
5
+ * on the Host, cached briefly in memory, and used only in an `Authorization`
6
+ * header. The browser half receives JSON view models and never a token.
7
+ *
8
+ * One `GitHubApi` is created lazily on the first call and re-created after a
9
+ * 401 (the machine's `gh` token may have been refreshed or revoked between
10
+ * sessions) or when the settings page asks for a refresh.
11
+ *
12
+ * @module dsh-plugin-github-issues/controller
13
+ */
14
+ import { TypertRemoteService } from '@deepseek-ai/dsh-typert-protocol';
15
+ import type { GitHubApi, GitHubApiOptions, GhProbe, ResolvedAuth } from './github/types.ts';
16
+ import type { PrefsStore } from './github/state.ts';
17
+ import type { GitHubStatus, IssueBodyVM, IssueLinkRecord, IssueListPage, LinkedPRVM, Prefs, ProjectRefVM, RepoPageVM, ScopeCatalog } from './vm.ts';
18
+ /** The Host-side collaborators the controller forwards to. */
19
+ export interface ControllerOptions {
20
+ /** Probe `gh auth status` without exposing the token. */
21
+ probeGh: (config: {
22
+ host: string;
23
+ ghPath?: string;
24
+ }, signal?: AbortSignal) => Promise<GhProbe>;
25
+ /** Resolve the token from the machine's `gh` CLI. */
26
+ resolveToken: (config: {
27
+ host: string;
28
+ ghPath?: string;
29
+ }, signal?: AbortSignal) => Promise<ResolvedAuth>;
30
+ /** Create one API session for a token. */
31
+ createApi: (options: GitHubApiOptions) => GitHubApi;
32
+ /** Persisted preferences. */
33
+ prefs: PrefsStore;
34
+ /** Deployment configuration as the loader resolved it. */
35
+ config: {
36
+ authMode: string;
37
+ host: string;
38
+ ghPath: string;
39
+ handoffMode: string;
40
+ pollSeconds: number;
41
+ };
42
+ }
43
+ /** Remote owner of the GitHub Issues surface, namespace `githubIssues`. */
44
+ export declare class GitHubIssuesController extends TypertRemoteService {
45
+ private readonly options;
46
+ private api;
47
+ private tokenAt;
48
+ private token;
49
+ /**
50
+ * @param ctx - the plugin context this service lives and dies with.
51
+ * @param options - the Host collaborators.
52
+ */
53
+ constructor(ctx: unknown, options: ControllerOptions);
54
+ /** Resolve one API session, reusing the token briefly. */
55
+ private apiNow;
56
+ /** Forget the cached token and session, so the next call re-resolves them. */
57
+ private forgetAuth;
58
+ private ghPath;
59
+ /** The membership the auth helpers accept, with no `undefined`-valued key. */
60
+ private authConfig;
61
+ /** Run one API operation, retrying once after a 401 with a freshly resolved token. */
62
+ private withApi;
63
+ /** Auth facts for the settings page: no token, only what `gh auth status` reports. */
64
+ status(): Promise<GitHubStatus>;
65
+ /** Repositories, organizations, projects, and the viewer. */
66
+ catalog(): Promise<ScopeCatalog>;
67
+ /** Attach the recorded session links to one card. */
68
+ private decorate;
69
+ /** One page of the list. */
70
+ listIssues(request: unknown): Promise<IssueListPage>;
71
+ /** Projects v2 of one organization; empty and `blocked` without `read:project`. */
72
+ orgProjects(org: string): Promise<{
73
+ projects: ProjectRefVM[];
74
+ blocked: boolean;
75
+ error?: string;
76
+ }>;
77
+ /** One organization's repositories, loaded when the organization is chosen. */
78
+ orgRepos(org: string): Promise<RepoPageVM>;
79
+ /** One issue with body and linked PRs. */
80
+ issueDetail(repo: string, number: number): Promise<IssueBodyVM>;
81
+ /** The issue's cross-referenced pull requests; fetched after the detail shows. */
82
+ issueMentionedPRs(repo: string, number: number): Promise<{
83
+ mentionedPRs: LinkedPRVM[];
84
+ }>;
85
+ /** Every recorded issue → session link (the dock resolves its own session). */
86
+ links(): Promise<IssueLinkRecord[]>;
87
+ /** Record that an issue was handed to one session. */
88
+ linkIssue(repo: string, number: number, sessionId: string): Promise<IssueLinkRecord[]>;
89
+ /** Remove one issue → session link, or all links of the issue. */
90
+ unlinkIssue(repo: string, number: number, sessionId?: string): Promise<IssueLinkRecord[]>;
91
+ /** Preferences persisted on the Host. */
92
+ loadPrefs(): Promise<Prefs>;
93
+ /** Merge one preference patch and persist it. */
94
+ savePrefs(patch: unknown): Promise<Prefs>;
95
+ /**
96
+ * Drop cached GitHub responses and the resolved token so the next request
97
+ * refetches. The token is re-resolved too: the user may have just granted a
98
+ * scope (`gh auth refresh -s read:project`) and the Host must see it at once,
99
+ * not after the five-minute token TTL.
100
+ */
101
+ refresh(): Promise<{
102
+ ok: true;
103
+ }>;
104
+ }
105
+ //# sourceMappingURL=controller.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"controller.d.ts","sourceRoot":"","sources":["../../src/controller.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Resolving the machine's GitHub credential from the `gh` CLI.
3
+ *
4
+ * The plugin never asks for a token in its own UI: a developer machine that can
5
+ * run `gh` can list and read issues, and `gh auth token` hands the Host the same
6
+ * credential. Two invariants matter here:
7
+ *
8
+ * - **The token never leaves this module's success value.** It is not logged, not
9
+ * placed in an error message, and not read from the environment by this code.
10
+ * - **A failure is always actionable.** "gh is missing", "not signed in", and
11
+ * "gh failed" are distinct codes with human messages, so the settings card can
12
+ * tell the user which of the three things to fix.
13
+ *
14
+ * @module dsh-plugin-github-issues/github/auth
15
+ */
16
+ import { type GhProbe, type ResolvedAuth } from './types.ts';
17
+ /** The facts both auth helpers need; matches the controller's collaborator type. */
18
+ export interface GhAuthConfig {
19
+ /** GitHub host to authorize against, e.g. `github.com` or a GHES hostname. */
20
+ host: string;
21
+ /** Explicit `gh` executable path from Config; skips discovery when set. */
22
+ ghPath?: string;
23
+ }
24
+ /**
25
+ * Resolve the `gh` executable to run.
26
+ * An explicit Config value wins outright (the operator may point at a wrapper);
27
+ * otherwise the usual install locations are tried and a bare `gh` is left for
28
+ * PATH to resolve.
29
+ * @param ghPath - explicit path from Config, if any.
30
+ * @returns the executable path or the bare command name.
31
+ */
32
+ export declare function resolveGhPath(ghPath?: string): string;
33
+ /**
34
+ * Read what `gh auth status` says about this machine.
35
+ * Never throws for a missing CLI or a signed-out host — those are described by
36
+ * the returned value, because not being signed in is a normal first-run state.
37
+ * Only an abort is rethrown.
38
+ * @param config - host and optional explicit executable path.
39
+ * @param signal - cancellation signal, forwarded to the child process.
40
+ * @returns the probe facts, with `installed` false when gh cannot be started.
41
+ */
42
+ export declare function probeGh(config: GhAuthConfig, signal?: AbortSignal): Promise<GhProbe>;
43
+ /**
44
+ * Resolve the token for the configured host via `gh auth token`.
45
+ * A token is accepted only from a successful invocation; every failure path
46
+ * throws a {@link GitHubApiError} whose message is safe to render.
47
+ * @param config - host and optional explicit executable path.
48
+ * @param signal - cancellation signal, forwarded to the child process.
49
+ * @returns the token plus the account facts the settings card shows.
50
+ */
51
+ export declare function resolveToken(config: GhAuthConfig, signal?: AbortSignal): Promise<ResolvedAuth>;
52
+ //# sourceMappingURL=auth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../../src/github/auth.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAKH,OAAO,EAAkB,KAAK,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,YAAY,CAAA;AAQ5E,oFAAoF;AACpF,MAAM,WAAW,YAAY;IAC3B,8EAA8E;IAC9E,IAAI,EAAE,MAAM,CAAA;IACZ,2EAA2E;IAC3E,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB;AAkCD;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAarD;AAyHD;;;;;;;;GAQG;AACH,wBAAsB,OAAO,CAAC,MAAM,EAAE,YAAY,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,OAAO,CAAC,CAgC1F;AAED;;;;;;;GAOG;AACH,wBAAsB,YAAY,CAAC,MAAM,EAAE,YAAY,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,YAAY,CAAC,CA+CpG"}
@@ -0,0 +1,40 @@
1
+ /**
2
+ * The Host-side GitHub GraphQL client.
3
+ *
4
+ * This is the only module that talks to api.github.com (or a GHES equivalent).
5
+ * It owns four concerns that the rest of the plugin should not have to know
6
+ * about:
7
+ *
8
+ * - **The credential.** The token lives in this closure and appears only in an
9
+ * `Authorization` header; it is never logged and never placed in an error.
10
+ * - **Failure taxonomy.** GitHub answers GraphQL failures with HTTP 200 plus an
11
+ * `errors[]` array, and transport failures with 401/403/404/429; both are
12
+ * classified into a small set of codes so the UI can say what to fix.
13
+ * - **Scoping quirks.** Projects v2 need `read:project`, which a machine's `gh`
14
+ * token may not have. That is a blocked picker, not a broken plugin, so it
15
+ * degrades to `projectsBlocked` and a notice.
16
+ * - **Caching.** The panel polls, so responses are kept briefly in memory; a
17
+ * refresh drops them. GraphQL has no conditional requests to rely on.
18
+ *
19
+ * The interface itself is defined in `types.ts`; this module only implements it.
20
+ *
21
+ * @module dsh-plugin-github-issues/github/client
22
+ */
23
+ import type { GitHubApi, GitHubApiOptions } from './types.ts';
24
+ /**
25
+ * The GraphQL endpoint for one host.
26
+ * github.com uses the dedicated API host; every GitHub Enterprise Server host
27
+ * serves GraphQL under its own `/api/graphql` path.
28
+ * @param host - configured host, e.g. `github.com` or `ghe.example.com`.
29
+ * @returns the absolute GraphQL endpoint.
30
+ */
31
+ export declare function endpointFor(host: string): string;
32
+ /**
33
+ * Create one GitHub API session.
34
+ * The returned object caches responses for a few minutes and caches the resolved
35
+ * scope catalog for five, so the caller may create it once per resolved token.
36
+ * @param options - the token, host, and optional session-wide abort signal.
37
+ * @returns the API the controller forwards to.
38
+ */
39
+ export declare function createGitHubApi(options: GitHubApiOptions): GitHubApi;
40
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../../src/github/client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAcH,OAAO,KAAK,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAA;AA4M7D;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAOhD;AAwvBD;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,gBAAgB,GAAG,SAAS,CAEpE"}
@@ -0,0 +1,172 @@
1
+ /**
2
+ * The GraphQL documents and variable builders the Host sends to GitHub.
3
+ *
4
+ * Queries are built per view instead of as one mega-document on purpose: a
5
+ * schema mismatch or a missing scope in one view must not break the others, and
6
+ * the search, repository, project, and detail endpoints accept different
7
+ * arguments. All documents are static text plus variables, except the project
8
+ * discovery query, whose organization aliases are generated from the viewer's
9
+ * organization list.
10
+ *
11
+ * Everything here is pure: no fetch, no token, no Node imports.
12
+ *
13
+ * @module dsh-plugin-github-issues/github/queries
14
+ */
15
+ import type { IssueListRequest, IssueState, ListView } from '../vm.ts';
16
+ /** One GraphQL operation ready to POST: the document and its variables. */
17
+ export interface GitHubGraphQLRequest {
18
+ query: string;
19
+ variables: Record<string, unknown>;
20
+ }
21
+ /** The list views that are served by GitHub's search API. */
22
+ export type SearchView = Exclude<ListView, 'project'>;
23
+ /**
24
+ * The scope catalog: the viewer, their organizations, and their repositories.
25
+ * One request is one point at this page size. A second request is issued by the
26
+ * client when the repository connection has more pages (capped at 200 repos).
27
+ * @param after - cursor from the previous page, or `null` for the first page.
28
+ * @returns the operation and its variables.
29
+ */
30
+ export declare function buildScopeQuery(after: string | null): GitHubGraphQLRequest;
31
+ /**
32
+ * Projects v2 discovery for the project picker.
33
+ * Every `ProjectV2` field except `totalCount` needs `read:project`, so the whole
34
+ * request fails with `INSUFFICIENT_SCOPES` on a token without it; the client
35
+ * treats that as a blocked picker rather than an error. One alias per
36
+ * organization keeps the request count at one.
37
+ * @param orgs - organization logins to list projects for (the caller caps this).
38
+ * @returns the operation and its variables.
39
+ */
40
+ export declare function buildProjectsQuery(orgs: readonly string[]): GitHubGraphQLRequest;
41
+ /**
42
+ * The fields of one project, including single-select options.
43
+ * `ProjectV2.fields` returns the `ProjectV2FieldConfiguration` union, so each
44
+ * member has to be selected explicitly rather than through common fields.
45
+ * Kept for the project-view field/priority picker; the items query reads the
46
+ * selected `Priority` value directly.
47
+ * @param projectId - the project's GraphQL node id.
48
+ * @returns the operation and its variables.
49
+ */
50
+ export declare function buildProjectFieldsQuery(projectId: string): GitHubGraphQLRequest;
51
+ /**
52
+ * One page of projects v2 items, with the `Priority` field and the issue or
53
+ * pull-request content each item holds. Drafts are selected only enough to be
54
+ * recognised and skipped.
55
+ * @param input - project id and page window.
56
+ * @returns the operation and its variables.
57
+ */
58
+ export declare function buildProjectItemsQuery(input: {
59
+ projectId: string;
60
+ first: number;
61
+ after: string | null;
62
+ /** Projects v2 filter DSL (`is:open assignee:@me`), evaluated by GitHub. */
63
+ filter?: string;
64
+ }): GitHubGraphQLRequest;
65
+ /**
66
+ * Free-text search for the assigned, created, open, and multi-repository views.
67
+ * Search is the one endpoint that spans all accessible repositories in a single
68
+ * point, so the repo view also uses it when more than one repository is
69
+ * selected; a single repository uses the exact `issues` connection instead.
70
+ * @param input - the search query string and page window.
71
+ * @returns the operation and its variables.
72
+ */
73
+ export declare function buildSearchIssuesQuery(input: {
74
+ search: string;
75
+ first: number;
76
+ after: string | null;
77
+ }): GitHubGraphQLRequest;
78
+ /**
79
+ * One repository's issues, with exact `totalCount` and cursor paging.
80
+ * Used for the repo view's single-repository case; `states` is a list and the
81
+ * order is always most-recently-updated first.
82
+ * @param input - repository, states, and page window.
83
+ * @returns the operation and its variables.
84
+ */
85
+ export declare function buildRepoIssuesQuery(input: {
86
+ owner: string;
87
+ name: string;
88
+ states: readonly IssueState[];
89
+ first: number;
90
+ after: string | null;
91
+ }): GitHubGraphQLRequest;
92
+ /**
93
+ * One issue with its body and card fields.
94
+ *
95
+ * The cross-reference timeline is *not* part of this request: it is the slowest
96
+ * leg of the detail (a timeline scan plus a full PR fragment per entry), so the
97
+ * panel asks for it separately after the detail is already on screen. See
98
+ * {@link buildMentionedPRsQuery}.
99
+ * @param input - repository and issue number.
100
+ * @returns the operation and its variables.
101
+ */
102
+ export declare function buildIssueDetailQuery(input: {
103
+ owner: string;
104
+ name: string;
105
+ number: number;
106
+ }): GitHubGraphQLRequest;
107
+ /**
108
+ * The issue's cross-referenced pull requests (the slow timeline leg).
109
+ * @param input - repository and issue number.
110
+ * @returns the operation and its variables.
111
+ */
112
+ export declare function buildMentionedPRsQuery(input: {
113
+ owner: string;
114
+ name: string;
115
+ number: number;
116
+ }): GitHubGraphQLRequest;
117
+ /**
118
+ * Turn the UI's three-way state filter into the `states` argument value.
119
+ * @param state - the requested filter; absent means open issues.
120
+ * @returns the values for the `[IssueState!]` argument.
121
+ */
122
+ export declare function statesForView(state: IssueListRequest['state']): IssueState[];
123
+ /**
124
+ * The GitHub search string for one search-backed view.
125
+ * `sort:` and `state:` are qualifiers inside the query string, not GraphQL
126
+ * arguments; `is:issue` is mandatory because `type: ISSUE` also matches pull
127
+ * requests. Multiple `repo:` qualifiers are OR-ed by GitHub, which is how the
128
+ * multi-repository view stays a single request.
129
+ * @param view - a search-backed view (the project view is not one).
130
+ * @param request - the normalized list request.
131
+ * @returns the query string, e.g. `is:issue assignee:@me state:open sort:updated-desc`.
132
+ */
133
+ export declare function searchStringFor(view: SearchView, request: Pick<IssueListRequest, 'state' | 'repos'>): string;
134
+ /**
135
+ * Projects v2 discovery for one organization, on demand.
136
+ * @param org - the organization login.
137
+ * @returns the operation and its variables.
138
+ */
139
+ export declare function buildOrgProjectsQuery(org: string): GitHubGraphQLRequest;
140
+ /**
141
+ * One page of an organization's repositories, forks included.
142
+ * GitHub's `organization.repositories` has no search argument, so the browser
143
+ * filters the fetched pages locally.
144
+ * @param input - organization, page window, and page size.
145
+ * @returns the operation and its variables.
146
+ */
147
+ export declare function buildOrgReposQuery(input: {
148
+ org: string;
149
+ first: number;
150
+ after: string | null;
151
+ }): GitHubGraphQLRequest;
152
+ /**
153
+ * The issue search string for a cascade request.
154
+ *
155
+ * `is:issue` is mandatory because `search(type: ISSUE)` also matches pull
156
+ * requests. `org:` and `repo:` are ordinary search qualifiers, so an
157
+ * organization-wide list costs the same one point as a global one.
158
+ * @param request - the scope and filters.
159
+ * @returns e.g. `is:issue org:one2x-ai assignee:@me state:open sort:updated-desc`.
160
+ */
161
+ export declare function searchStringForFilters(request: Pick<IssueListRequest, 'org' | 'repos' | 'assignee' | 'author' | 'state'>): string;
162
+ /**
163
+ * The Projects v2 item filter for a cascade request. GitHub evaluates it
164
+ * server-side, so a state filter on a 126-item board returns the 25 open ones
165
+ * rather than the first page filtered locally.
166
+ * @param request - the state and assignee filters.
167
+ * @returns e.g. `is:open assignee:@me`, or an empty string for no filter.
168
+ */
169
+ export declare function projectItemsFilterFor(request: Pick<IssueListRequest, 'assignee' | 'state'>): string;
170
+ /** The repository filter a project view applies to its item content. */
171
+ export declare function reposFor(request: Pick<IssueListRequest, 'repos'>): string[];
172
+ //# sourceMappingURL=queries.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"queries.d.ts","sourceRoot":"","sources":["../../../src/github/queries.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,51 @@
1
+ /**
2
+ * The plugin's non-secret state file.
3
+ *
4
+ * Preferences (which repo or project the panel shows, the pinned issue, the
5
+ * handoff template) are not credentials, so they live in the plugin's own
6
+ * directory instead of the DSH settings profile: the profile patch is rewritten
7
+ * by upgrades and its `.bak` copies would duplicate whatever is written there.
8
+ *
9
+ * @module dsh-plugin-github-issues/github/state
10
+ */
11
+ import { type IssueLinkRecord, type IssueSessionLinkVM, type Prefs } from '../vm.ts';
12
+ /**
13
+ * Apply a browser-supplied preference patch onto the current preferences.
14
+ * @param current - the preferences currently stored.
15
+ * @param patch - the untrusted patch.
16
+ * @returns the next preferences, with every field validated.
17
+ */
18
+ export declare function applyPrefsPatch(current: Prefs, patch: unknown): Prefs;
19
+ /** File-backed preference storage for one installation. */
20
+ export declare class PrefsStore {
21
+ private readonly stateDir;
22
+ private readonly configureHandoff;
23
+ private readonly configureTemplate;
24
+ private readonly file;
25
+ private readonly directory;
26
+ private cached;
27
+ private cachedLinks;
28
+ /**
29
+ * @param stateDir - owner-only directory this installation's state lives in.
30
+ * @param configureHandoff - the deployment's default handoff mode.
31
+ * @param configureTemplate - the deployment's default prompt template.
32
+ */
33
+ constructor(stateDir: string, configureHandoff: string | undefined, configureTemplate: string | undefined);
34
+ /** Read the current preferences, creating defaults on first use. */
35
+ load(): Prefs;
36
+ /** Every recorded issue → session link, oldest first. */
37
+ links(): IssueLinkRecord[];
38
+ /** The links recorded for one issue, newest last. */
39
+ linksFor(repo: string, number: number): IssueSessionLinkVM[];
40
+ /** Record one issue → session handoff, idempotently. */
41
+ link(repo: string, number: number, sessionId: string): IssueLinkRecord[];
42
+ /** Remove one link (or every link for the issue when `sessionId` is omitted). */
43
+ unlink(repo: string, number: number, sessionId?: string): IssueLinkRecord[];
44
+ /** Read the state file once, tolerating absence, v1 files, and corruption. */
45
+ private readFile;
46
+ /** Merge one patch into the stored preferences and persist them. */
47
+ save(patch: unknown): Prefs;
48
+ /** Write the whole state document atomically with owner-only permissions. */
49
+ private writeFile;
50
+ }
51
+ //# sourceMappingURL=state.d.ts.map