@openforge-app/plugin-sdk 0.2.5 → 0.2.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.
- package/dist/browserSurfaces.d.ts +4 -0
- package/dist/browserSurfacesTesting.d.ts +3 -2
- package/dist/browserSurfacesTesting.js +18 -0
- package/dist/collapsibleSectionState.d.ts +10 -0
- package/dist/collapsibleSectionState.js +81 -0
- package/dist/domain.d.ts +5 -13
- package/dist/frontend.d.ts +2 -2
- package/dist/index.d.ts +1 -1
- package/dist/prStatusPresentation.d.ts +2 -1
- package/dist/prStatusPresentation.js +11 -0
- package/dist/publicUiExports.mjs +1 -0
- package/dist/testing/commonApiFake.js +2 -1
- package/dist/types.d.ts +6 -0
- package/dist/ui/CollapsibleSection.svelte +79 -0
- package/dist/ui/MarkdownContent.svelte +94 -13
- package/dist/vite.js +1 -0
- package/package.json +7 -2
- package/dist/context.d.ts +0 -15
- package/dist/context.js +0 -33
|
@@ -9,12 +9,14 @@ export interface BrowserSurfaceNavigationError {
|
|
|
9
9
|
message: string;
|
|
10
10
|
url: string;
|
|
11
11
|
}
|
|
12
|
+
export type BrowserDevToolsPanel = 'elements' | 'console';
|
|
12
13
|
export interface TaskBrowserSurfaceState {
|
|
13
14
|
url: string;
|
|
14
15
|
title: string;
|
|
15
16
|
loading: boolean;
|
|
16
17
|
canGoBack: boolean;
|
|
17
18
|
canGoForward: boolean;
|
|
19
|
+
devToolsOpen: boolean;
|
|
18
20
|
error: BrowserSurfaceNavigationError | null;
|
|
19
21
|
}
|
|
20
22
|
export interface BrowserSurfaceCapture {
|
|
@@ -63,6 +65,8 @@ export interface TaskBrowserSurfaceController {
|
|
|
63
65
|
goForward(): Promise<TaskBrowserSurfaceState>;
|
|
64
66
|
reload(): Promise<TaskBrowserSurfaceState>;
|
|
65
67
|
stop(): Promise<TaskBrowserSurfaceState>;
|
|
68
|
+
openDevTools(panel?: BrowserDevToolsPanel): Promise<TaskBrowserSurfaceState>;
|
|
69
|
+
closeDevTools(): Promise<TaskBrowserSurfaceState>;
|
|
66
70
|
selectVisibleRegion(): Promise<BrowserSurfaceFeedbackSelection | null>;
|
|
67
71
|
cancelVisibleRegionSelection(): Promise<void>;
|
|
68
72
|
clearVisualFeedback(): Promise<void>;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { BrowserSurfacesAPI, BrowserSurfaceVisualFeedback, GetOrCreateBrowserSurfaceRequest, TaskBrowserSurfaceState } from './browserSurfaces';
|
|
1
|
+
import type { BrowserSurfacesAPI, BrowserDevToolsPanel, BrowserSurfaceVisualFeedback, GetOrCreateBrowserSurfaceRequest, TaskBrowserSurfaceState } from './browserSurfaces';
|
|
2
2
|
export interface TestingBrowserSurfaceCalls {
|
|
3
3
|
browserSurfaceGetOrCreate: GetOrCreateBrowserSurfaceRequest[];
|
|
4
4
|
browserSurfaceAttachments: Array<{
|
|
@@ -22,7 +22,8 @@ export interface TestingBrowserSurfaceCalls {
|
|
|
22
22
|
browserSurfaceControls: Array<{
|
|
23
23
|
taskId: string;
|
|
24
24
|
id: string;
|
|
25
|
-
action: 'goBack' | 'goForward' | 'reload' | 'stop';
|
|
25
|
+
action: 'goBack' | 'goForward' | 'reload' | 'stop' | 'openDevTools' | 'closeDevTools';
|
|
26
|
+
panel?: BrowserDevToolsPanel;
|
|
26
27
|
}>;
|
|
27
28
|
browserSurfaceSelections: Array<{
|
|
28
29
|
taskId: string;
|
|
@@ -49,6 +49,7 @@ class TestingTaskBrowserSurface {
|
|
|
49
49
|
loading: false,
|
|
50
50
|
canGoBack: false,
|
|
51
51
|
canGoForward: false,
|
|
52
|
+
devToolsOpen: false,
|
|
52
53
|
error: null,
|
|
53
54
|
};
|
|
54
55
|
}
|
|
@@ -124,6 +125,23 @@ class TestingTaskBrowserSurface {
|
|
|
124
125
|
this.publish({ loading: false });
|
|
125
126
|
return this.getState();
|
|
126
127
|
}
|
|
128
|
+
async openDevTools(panel) {
|
|
129
|
+
this.assertLive();
|
|
130
|
+
this.calls.browserSurfaceControls.push({
|
|
131
|
+
taskId: this.taskId,
|
|
132
|
+
id: this.id,
|
|
133
|
+
action: 'openDevTools',
|
|
134
|
+
...(panel ? { panel } : {}),
|
|
135
|
+
});
|
|
136
|
+
this.publish({ devToolsOpen: true });
|
|
137
|
+
return this.getState();
|
|
138
|
+
}
|
|
139
|
+
async closeDevTools() {
|
|
140
|
+
this.assertLive();
|
|
141
|
+
this.calls.browserSurfaceControls.push({ taskId: this.taskId, id: this.id, action: 'closeDevTools' });
|
|
142
|
+
this.publish({ devToolsOpen: false });
|
|
143
|
+
return this.getState();
|
|
144
|
+
}
|
|
127
145
|
async selectVisibleRegion() {
|
|
128
146
|
this.assertLive();
|
|
129
147
|
this.calls.browserSurfaceSelections.push({ taskId: this.taskId, id: this.id });
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export type CollapsedSectionsState = Record<string, boolean>;
|
|
2
|
+
export declare const COLLAPSED_SECTIONS_STORAGE_KEY = "openforge.infoPanelSectionCollapse.v1";
|
|
3
|
+
export declare function pluginSectionKey(pluginId: string, sectionKey: string): string;
|
|
4
|
+
export declare const collapsedSections: {
|
|
5
|
+
subscribe: (this: void, run: import("svelte/store").Subscriber<CollapsedSectionsState>, invalidate?: () => void) => import("svelte/store").Unsubscriber;
|
|
6
|
+
};
|
|
7
|
+
export declare function isSectionCollapsed(state: CollapsedSectionsState, key: string): boolean;
|
|
8
|
+
export declare function setSectionCollapsed(key: string, collapsed: boolean): void;
|
|
9
|
+
export declare function toggleSection(key: string): void;
|
|
10
|
+
export declare function clearCollapsedSections(): void;
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { writable } from 'svelte/store';
|
|
2
|
+
// The store started life in the host app as src/lib/infoPanelSectionState.ts. The key is
|
|
3
|
+
// deliberately unchanged: renaming it would reset every user's collapsed sections.
|
|
4
|
+
export const COLLAPSED_SECTIONS_STORAGE_KEY = 'openforge.infoPanelSectionCollapse.v1';
|
|
5
|
+
export function pluginSectionKey(pluginId, sectionKey) {
|
|
6
|
+
return `plugin:${pluginId}:${sectionKey}`;
|
|
7
|
+
}
|
|
8
|
+
function getLocalStorage() {
|
|
9
|
+
try {
|
|
10
|
+
return globalThis.localStorage ?? null;
|
|
11
|
+
}
|
|
12
|
+
catch {
|
|
13
|
+
return null;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
function readPersisted() {
|
|
17
|
+
const storage = getLocalStorage();
|
|
18
|
+
if (storage === null)
|
|
19
|
+
return {};
|
|
20
|
+
try {
|
|
21
|
+
const rawValue = storage.getItem(COLLAPSED_SECTIONS_STORAGE_KEY);
|
|
22
|
+
if (rawValue === null)
|
|
23
|
+
return {};
|
|
24
|
+
const parsed = JSON.parse(rawValue);
|
|
25
|
+
if (parsed === null || typeof parsed !== 'object' || Array.isArray(parsed))
|
|
26
|
+
return {};
|
|
27
|
+
const state = {};
|
|
28
|
+
for (const [key, value] of Object.entries(parsed)) {
|
|
29
|
+
if (value === true)
|
|
30
|
+
state[key] = true;
|
|
31
|
+
}
|
|
32
|
+
return state;
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
return {};
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
function writePersisted(state) {
|
|
39
|
+
const storage = getLocalStorage();
|
|
40
|
+
if (storage === null)
|
|
41
|
+
return;
|
|
42
|
+
try {
|
|
43
|
+
// Only persist collapsed sections; expanded is the default and needs no entry.
|
|
44
|
+
const collapsedOnly = {};
|
|
45
|
+
for (const [key, value] of Object.entries(state)) {
|
|
46
|
+
if (value === true)
|
|
47
|
+
collapsedOnly[key] = true;
|
|
48
|
+
}
|
|
49
|
+
if (Object.keys(collapsedOnly).length === 0) {
|
|
50
|
+
storage.removeItem(COLLAPSED_SECTIONS_STORAGE_KEY);
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
storage.setItem(COLLAPSED_SECTIONS_STORAGE_KEY, JSON.stringify(collapsedOnly));
|
|
54
|
+
}
|
|
55
|
+
catch {
|
|
56
|
+
// Persistence is best effort and must not block the section from rendering.
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
const { subscribe, set, update } = writable(readPersisted());
|
|
60
|
+
export const collapsedSections = { subscribe };
|
|
61
|
+
export function isSectionCollapsed(state, key) {
|
|
62
|
+
return state[key] === true;
|
|
63
|
+
}
|
|
64
|
+
export function setSectionCollapsed(key, collapsed) {
|
|
65
|
+
update((current) => {
|
|
66
|
+
const next = { ...current, [key]: collapsed };
|
|
67
|
+
writePersisted(next);
|
|
68
|
+
return next;
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
export function toggleSection(key) {
|
|
72
|
+
update((current) => {
|
|
73
|
+
const next = { ...current, [key]: !isSectionCollapsed(current, key) };
|
|
74
|
+
writePersisted(next);
|
|
75
|
+
return next;
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
export function clearCollapsedSections() {
|
|
79
|
+
writePersisted({});
|
|
80
|
+
set({});
|
|
81
|
+
}
|
package/dist/domain.d.ts
CHANGED
|
@@ -117,6 +117,7 @@ export interface PrComment {
|
|
|
117
117
|
outdated: number;
|
|
118
118
|
created_at: number;
|
|
119
119
|
}
|
|
120
|
+
export type PullRequestMergeMethod = 'merge' | 'squash' | 'rebase';
|
|
120
121
|
export interface PullRequestInfo {
|
|
121
122
|
id: number;
|
|
122
123
|
pr_number: number;
|
|
@@ -149,6 +150,9 @@ export interface PullRequestInfo {
|
|
|
149
150
|
merge_queue_required: boolean | null;
|
|
150
151
|
merge_queue_state: string | null;
|
|
151
152
|
readiness_updated_at: number | null;
|
|
153
|
+
merge_methods_policy_known?: boolean | null;
|
|
154
|
+
allowed_merge_methods?: string | PullRequestMergeMethod[] | null;
|
|
155
|
+
default_merge_method?: PullRequestMergeMethod | null;
|
|
152
156
|
}
|
|
153
157
|
export type PollOutcome = 'completed' | 'missing_github_token' | 'github_token_unavailable' | 'failed' | 'rate_limited';
|
|
154
158
|
export interface PollResult {
|
|
@@ -310,7 +314,7 @@ export interface ProjectAttention {
|
|
|
310
314
|
unaddressed_comments: number;
|
|
311
315
|
completed_agents: number;
|
|
312
316
|
}
|
|
313
|
-
export type TaskAttentionState = 'idle' | 'needs-input' | 'paused' | 'agent-done' | 'failed' | 'interrupted' | 'pr-draft' | 'pr-open' | 'ci-failed' | 'changes-requested' | 'unaddressed-comments' | 'ready-to-merge' | 'ready-to-enqueue' | 'pr-queued' | 'pr-merged' | 'pr-closed' | 'ci-running' | 'review-pending' | 'merge-conflict';
|
|
317
|
+
export type TaskAttentionState = 'active' | 'backlog' | 'idle' | 'needs-input' | 'paused' | 'agent-done' | 'failed' | 'interrupted' | 'pr-draft' | 'pr-open' | 'ci-failed' | 'changes-requested' | 'unaddressed-comments' | 'ready-to-merge' | 'ready-to-enqueue' | 'pr-queued' | 'pr-merged' | 'pr-closed' | 'ci-running' | 'review-pending' | 'merge-conflict';
|
|
314
318
|
/** Backend-owned, Task-only Needs Attention read model. */
|
|
315
319
|
export interface TaskAttentionRow {
|
|
316
320
|
task_id: string;
|
|
@@ -495,18 +499,6 @@ export interface ReviewSubmission {
|
|
|
495
499
|
body: string;
|
|
496
500
|
comments: ReviewSubmissionComment[];
|
|
497
501
|
}
|
|
498
|
-
/** Self-review comment for task implementation review */
|
|
499
|
-
export interface SelfReviewComment {
|
|
500
|
-
id: number;
|
|
501
|
-
task_id: string;
|
|
502
|
-
round: number;
|
|
503
|
-
comment_type: string;
|
|
504
|
-
file_path: string | null;
|
|
505
|
-
line_number: number | null;
|
|
506
|
-
body: string;
|
|
507
|
-
created_at: number;
|
|
508
|
-
archived_at: number | null;
|
|
509
|
-
}
|
|
510
502
|
/** One file referenced by a walkthrough step. `hunk_indexes === null` means the entire file's diff belongs to the step. */
|
|
511
503
|
export interface PrWalkthroughStepFile {
|
|
512
504
|
filename: string;
|
package/dist/frontend.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { BrowserSurfaceCapture, BrowserSurfaceFeedbackSelection, BrowserSurfaceVisualFeedback, BrowserSurfaceRegion, BrowserSurfaceErrorCode, BrowserSurfaceNavigationError, BrowserSurfacesAPI, GetOrCreateBrowserSurfaceRequest, TaskBrowserSurfaceController, TaskBrowserSurfaceState } from './browserSurfaces';
|
|
1
|
+
import type { BrowserSurfaceCapture, BrowserDevToolsPanel, BrowserSurfaceFeedbackSelection, BrowserSurfaceVisualFeedback, BrowserSurfaceRegion, BrowserSurfaceErrorCode, BrowserSurfaceNavigationError, BrowserSurfacesAPI, GetOrCreateBrowserSurfaceRequest, TaskBrowserSurfaceController, TaskBrowserSurfaceState } from './browserSurfaces';
|
|
2
2
|
import type { CommandDescriptor, CommandRegistry, CommandRegistration, CommandShortcutMetadata, ComposeTaskRequest, ComposeTaskResult, Disposable, FrontendBackendBridge, FrontendOpenForgeAPI, FrontendPlugin, FrontendPluginContext, FrontendSettingsRegistry, FrontendTaskPaneRegistry, FrontendInjectionPointRegistry, FrontendTaskStartRegistry, FrontendTaskUIRegistry, FrontendViewRegistry, InjectionPointLocation, NavigationAPI, OpenForgeContextChangeHandler, OpenForgeContextSnapshot, OpenForgeNavigationRequest, OpenForgeNavigationSnapshot, TaskLinkHandler, TaskLinkHandlerResult, TaskLinkOpenRequest, TaskLinksAPI, PluginIcon, PluginSidebarNavigationProps, PluginSidebarViewIdentity, PluginInjectionPointProps, PluginInjectionPointRegistration, PluginSettingsSectionProps, PluginSettingsSectionRegistration, PluginSettingsSectionScope, PluginStorageScope, PluginSvgIcon, PluginTaskPaneProps, PluginTaskPaneTabRegistration, PluginTaskUISectionProps, PluginTaskUISectionRegistration, PluginViewProps, PluginViewRegistration, TaskStartPrefixContext, TaskStartPrefixProviderRegistration, PtyBufferState, TerminalImageProtocol } from './types';
|
|
3
3
|
export declare const OPENFORGE_FRONTEND_PLUGIN_MARKER = "__openforgeFrontendPlugin";
|
|
4
4
|
export type MarkedFrontendPlugin<TPlugin extends FrontendPlugin = FrontendPlugin> = TPlugin & {
|
|
@@ -6,5 +6,5 @@ export type MarkedFrontendPlugin<TPlugin extends FrontendPlugin = FrontendPlugin
|
|
|
6
6
|
};
|
|
7
7
|
export declare function defineFrontendPlugin<const TPlugin extends FrontendPlugin>(plugin: TPlugin): MarkedFrontendPlugin<TPlugin>;
|
|
8
8
|
export { BrowserSurfaceError, isAllowedBrowserSurfaceUrl } from './browserSurfaces';
|
|
9
|
-
export type { BrowserSurfaceCapture, BrowserSurfaceFeedbackSelection, BrowserSurfaceVisualFeedback, BrowserSurfaceRegion, BrowserSurfaceErrorCode, BrowserSurfaceNavigationError, BrowserSurfacesAPI, GetOrCreateBrowserSurfaceRequest, TaskBrowserSurfaceController, TaskBrowserSurfaceState, };
|
|
9
|
+
export type { BrowserSurfaceCapture, BrowserDevToolsPanel, BrowserSurfaceFeedbackSelection, BrowserSurfaceVisualFeedback, BrowserSurfaceRegion, BrowserSurfaceErrorCode, BrowserSurfaceNavigationError, BrowserSurfacesAPI, GetOrCreateBrowserSurfaceRequest, TaskBrowserSurfaceController, TaskBrowserSurfaceState, };
|
|
10
10
|
export type { CommandDescriptor, CommandRegistry, CommandRegistration, CommandShortcutMetadata, ComposeTaskRequest, ComposeTaskResult, Disposable, FrontendBackendBridge, FrontendOpenForgeAPI, FrontendPlugin, FrontendPluginContext, FrontendSettingsRegistry, FrontendTaskPaneRegistry, FrontendInjectionPointRegistry, FrontendTaskStartRegistry, FrontendTaskUIRegistry, FrontendViewRegistry, InjectionPointLocation, NavigationAPI, OpenForgeContextChangeHandler, OpenForgeContextSnapshot, OpenForgeNavigationRequest, OpenForgeNavigationSnapshot, TaskLinkHandler, TaskLinkHandlerResult, TaskLinkOpenRequest, TaskLinksAPI, PluginIcon, PluginSidebarNavigationProps, PluginSidebarViewIdentity, PluginInjectionPointProps, PluginInjectionPointRegistration, PluginSettingsSectionProps, PluginSettingsSectionRegistration, PluginSettingsSectionScope, PluginStorageScope, PluginSvgIcon, PluginTaskPaneProps, PluginTaskPaneTabRegistration, PluginTaskUISectionProps, PluginTaskUISectionRegistration, PluginViewProps, PluginViewRegistration, TaskStartPrefixContext, TaskStartPrefixProviderRegistration, PtyBufferState, TerminalImageProtocol, };
|
package/dist/index.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ export type { BrowserSurfaceCapture, BrowserSurfaceFeedbackSelection, BrowserSur
|
|
|
3
3
|
export { OPENFORGE_PACKAGE_METADATA_SCHEMA, OPENFORGE_PLUGIN_CAPABILITIES, isOpenForgePackageMetadata, isPluginPackageMetadata, isSupportedOpenForgeApiVersion, validateOpenForgePackageMetadata, validatePluginPackageMetadata, } from './manifest';
|
|
4
4
|
export { createMemoryPluginStorage, createMockBackendOpenForgeApi, createMockFrontendOpenForgeApi, createMockOpenForgeApi, createMockPluginContext, createOpenForgeRegistryFake, createTestingCalls, TestingOpenForgeRegistryFake, TestingSubscriptionSink, } from './testing';
|
|
5
5
|
export { DEFAULT_EXTERNAL_TEXT_FILE_CHUNK_SIZE_BYTES, MAX_EXTERNAL_TEXT_FILE_CHUNK_SIZE_BYTES, MIN_EXTERNAL_TEXT_FILE_CHUNK_SIZE_BYTES, TaskFollowUpError, MAX_SUPPORTED_API_VERSION, MIN_SUPPORTED_API_VERSION, OPENFORGE_PLUGIN_API_VERSION, SUPPORTED_OPENFORGE_API_VERSIONS, isPluginViewKey, resolveExternalTextFileChunkSize, makePluginViewKey, parsePluginViewKey, } from './types';
|
|
6
|
-
export type { AgentCommandDescriptor, AgentCommandMetadata, AgentCommandRuntime, AttentionAPI, BackendReadyState, CommandDescriptor, CommandRegistry, CommandRegistration, CommandShortcutMetadata, ComposeTaskRequest, ComposeTaskResult, ConfigureStartPromptContributionRequest, CreateTaskRequest, Disposable, BackendFileSystemAPI, ExternalReadDirectoryRequest, ExternalReadFileRequest, ExternalReadTextFileChunksRequest, ExternalReadFileSystemAPI, FileSystemAPI, UserDataDirectoryRequest, UserDataFileRequest, UserDataFileSystemAPI, UserDataFileWriteRequest, ImplementationRun, InjectionPointLocation, JsonObject, JsonPrimitive, JsonSchema, JsonValue, MaybePromise, KeyValueConfigAPI, NotificationRequest, NavigationAPI, NotificationsAPI, OpenForgeCommonAPI, OpenForgeContextChangeHandler, OpenForgeContextSnapshot, OpenForgeNavigationRequest, OpenForgeNavigationSnapshot, OpenForgePackageMetadata, OpenForgePluginCapability, OpenForgePluginContext, OpenForgePluginPackageJson, PluginCommandInvocationContext, PluginCommandInvocationSource, PluginComponentLoader, PluginComponentModule, PluginEntry, PluginIcon, PluginSidebarNavigationProps, PluginSidebarViewIdentity, PluginInjectionPointProps, PluginSettingsSectionProps, PluginState, PluginSvgIcon, PluginTaskPaneProps, PluginTaskUISectionProps, PluginViewProps, PluginStorage, PluginStorageScope, PluginViewKey, ProjectsAPI, PtyBufferState, ShellAPI, ShellResizeRequest, TaskStartPrefixContext, TaskStartPrefixProviderRegistration, TerminalImageProtocol, ShellSessionRequest, ShellSpawnRequest, ShellWriteRequest, StartPromptContribution, SendTaskFollowUpRequest, StartTaskImplementationRequest, TaskFollowUpDisposition, TaskFollowUpErrorCode, TaskFollowUpReceipt, SubscriptionSink, SupportedOpenForgeApiVersion, SystemAPI, TaskLinkHandler, TaskLinkHandlerResult, TaskLinkOpenRequest, TaskLinksAPI, TasksAPI, ValidationError, } from './types';
|
|
6
|
+
export type { AgentCommandDescriptor, AgentCommandMetadata, AgentCommandRuntime, AttentionAPI, BackendReadyState, CommandDescriptor, CommandRegistry, CommandRegistration, CommandShortcutMetadata, ComposeTaskRequest, ComposeTaskResult, ConfigureStartPromptContributionRequest, CreateTaskRequest, Disposable, BackendFileSystemAPI, ExternalReadDirectoryRequest, ExternalReadFileRequest, ExternalReadTextFileChunksRequest, ExternalReadFileSystemAPI, FileSystemAPI, UserDataDirectoryRequest, UserDataFileRequest, UserDataFileSystemAPI, UserDataFileWriteRequest, ImplementationRun, InjectionPointLocation, JsonObject, JsonPrimitive, JsonSchema, JsonValue, MaybePromise, KeyValueConfigAPI, NotificationRequest, NavigationAPI, NotificationsAPI, OpenForgeCommonAPI, OpenForgeContextChangeHandler, OpenForgeContextSnapshot, OpenForgeNavigationRequest, OpenForgeNavigationSnapshot, OpenForgePackageMetadata, OpenForgePluginCapability, OpenForgePluginContext, OpenForgePluginPackageJson, PluginCommandInvocationContext, PluginCommandInvocationSource, PluginComponentLoader, PluginComponentModule, PluginEntry, PluginIcon, PluginSidebarNavigationProps, PluginSidebarViewIdentity, PluginInjectionPointProps, PluginSettingsSectionProps, PluginState, PluginSvgIcon, PluginTaskPaneProps, PluginTaskUISectionProps, PluginViewProps, PluginStorage, PluginStorageScope, PluginViewKey, ProjectsAPI, PtyBufferState, ShellAPI, ShellResizeRequest, TaskStartPrefixContext, TaskStartPrefixProviderRegistration, TerminalImageProtocol, ShellSessionRequest, ShellSpawnRequest, ShellTerminalQueryResponseRequest, ShellWriteRequest, StartPromptContribution, SendTaskFollowUpRequest, StartTaskImplementationRequest, TaskFollowUpDisposition, TaskFollowUpErrorCode, TaskFollowUpReceipt, SubscriptionSink, SupportedOpenForgeApiVersion, SystemAPI, TaskLinkHandler, TaskLinkHandlerResult, TaskLinkOpenRequest, TaskLinksAPI, TasksAPI, ValidationError, } from './types';
|
|
7
7
|
export type { MockBackendOpenForgeAPI, MockFrontendOpenForgeAPI, TestingBackgroundServiceContribution, TestingBackendMethodContribution, TestingCommandContribution, TestingContributionBase, TestingExternalTextFile, TestingExternalTextFileChunksCall, TestingEventListenerContribution, TestingOpenForgeApiCalls, TestingOpenForgeApiOptions, TestingOpenForgeRegistrySnapshot, TestingRuntimeKind, TestingRuntimeScope, TestingSettingsSectionContribution, TestingTaskPaneTabContribution, TestingTaskUISectionContribution, TestingViewContribution, } from './testing';
|
|
8
8
|
export { parseStrictFiniteNumber } from './numberParsing';
|
|
9
9
|
export { buildProjectFileTree, flattenVisibleProjectFileTree, formatProjectFileTreeSize, getProjectFileTreeDepth, getProjectFileTreeItemAccessibility, getProjectFileTreeKeyboardAction, getProjectFileTreeParentPath, hasProjectFileTreeShortcutModifier, projectFileTreePathToId, } from './projectFileTree';
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import { type MergeReadinessAction, type MergeReadinessDetail, type MergeReadinessStatus, type MergeStatusInfo } from './domain';
|
|
1
|
+
import { type MergeReadinessAction, type MergeReadinessDetail, type MergeReadinessStatus, type MergeStatusInfo, type PullRequestMergeMethod } from './domain';
|
|
2
2
|
export type PrChipSurface = 'compact' | 'detail';
|
|
3
3
|
export type PrChipVariant = 'success' | 'error' | 'pending' | 'muted' | 'neutral' | 'done' | 'merged' | 'closed';
|
|
4
4
|
export type PrChipType = 'draft' | 'ci' | 'review' | 'merge';
|
|
5
5
|
export type PrChipIcon = 'check' | 'cross' | 'clock' | null;
|
|
6
|
+
export declare function getPullRequestMergeActionLabel(method: PullRequestMergeMethod, prNumber?: number): string;
|
|
6
7
|
export interface PrStatusChipSpec {
|
|
7
8
|
type: PrChipType;
|
|
8
9
|
label: string;
|
|
@@ -1,4 +1,15 @@
|
|
|
1
1
|
import { getMergeReadiness, isClosedUnmergedPullRequest, isMergedPullRequest } from './domain';
|
|
2
|
+
const PULL_REQUEST_MERGE_ACTION_LABELS = {
|
|
3
|
+
merge: 'Create a merge commit',
|
|
4
|
+
squash: 'Squash and merge',
|
|
5
|
+
rebase: 'Rebase and merge',
|
|
6
|
+
};
|
|
7
|
+
export function getPullRequestMergeActionLabel(method, prNumber) {
|
|
8
|
+
const label = PULL_REQUEST_MERGE_ACTION_LABELS[method];
|
|
9
|
+
if (prNumber === undefined)
|
|
10
|
+
return label;
|
|
11
|
+
return method === 'merge' ? `${label} for PR #${prNumber}` : `${label} PR #${prNumber}`;
|
|
12
|
+
}
|
|
2
13
|
export function getPrStatusChips(pr, surface) {
|
|
3
14
|
const chips = [];
|
|
4
15
|
if (pr.draft && pr.state === 'open') {
|
package/dist/publicUiExports.mjs
CHANGED
|
@@ -146,6 +146,7 @@ export class TestingCommonApiFake {
|
|
|
146
146
|
write: async (request) => {
|
|
147
147
|
this.services.calls.shellWrites.push(request);
|
|
148
148
|
},
|
|
149
|
+
writeTerminalQueryResponse: async () => { },
|
|
149
150
|
resize: async (request) => {
|
|
150
151
|
this.services.calls.shellResizes.push(request);
|
|
151
152
|
},
|
|
@@ -154,7 +155,7 @@ export class TestingCommonApiFake {
|
|
|
154
155
|
},
|
|
155
156
|
getBuffer: async (request) => {
|
|
156
157
|
this.services.calls.shellBuffers.push(request);
|
|
157
|
-
return { buffer: null, isLive: false };
|
|
158
|
+
return { buffer: null, isLive: false, instanceId: null };
|
|
158
159
|
},
|
|
159
160
|
},
|
|
160
161
|
notifications: {
|
package/dist/types.d.ts
CHANGED
|
@@ -432,6 +432,10 @@ export interface ShellSpawnRequest extends ShellSessionRequest {
|
|
|
432
432
|
export interface ShellWriteRequest extends ShellSessionRequest {
|
|
433
433
|
data: string;
|
|
434
434
|
}
|
|
435
|
+
export interface ShellTerminalQueryResponseRequest extends ShellSessionRequest {
|
|
436
|
+
ptyInstanceId: number;
|
|
437
|
+
data: string;
|
|
438
|
+
}
|
|
435
439
|
export interface ShellResizeRequest extends ShellSessionRequest {
|
|
436
440
|
cols: number;
|
|
437
441
|
rows: number;
|
|
@@ -439,10 +443,12 @@ export interface ShellResizeRequest extends ShellSessionRequest {
|
|
|
439
443
|
export interface PtyBufferState {
|
|
440
444
|
buffer: string | null;
|
|
441
445
|
isLive: boolean;
|
|
446
|
+
instanceId: number | null;
|
|
442
447
|
}
|
|
443
448
|
export interface ShellAPI {
|
|
444
449
|
spawn(request: ShellSpawnRequest): Promise<number>;
|
|
445
450
|
write(request: ShellWriteRequest): Promise<void>;
|
|
451
|
+
writeTerminalQueryResponse(request: ShellTerminalQueryResponseRequest): Promise<void>;
|
|
446
452
|
resize(request: ShellResizeRequest): Promise<void>;
|
|
447
453
|
kill(request: ShellSessionRequest): Promise<void>;
|
|
448
454
|
getBuffer(request: ShellSessionRequest): Promise<PtyBufferState>;
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { Snippet } from 'svelte'
|
|
3
|
+
import { collapsedSections, isSectionCollapsed, toggleSection } from '../collapsibleSectionState'
|
|
4
|
+
|
|
5
|
+
interface Props {
|
|
6
|
+
// Stable, global key used to persist the collapsed/expanded state. Plugins must
|
|
7
|
+
// build this with `pluginSectionKey(pluginId, key)` so two plugins cannot collide.
|
|
8
|
+
sectionKey: string
|
|
9
|
+
title: string
|
|
10
|
+
// aria-label for the section landmark (defaults to the title).
|
|
11
|
+
label?: string
|
|
12
|
+
// data-task-info-card value (defaults to the section key).
|
|
13
|
+
cardId?: string
|
|
14
|
+
ariaLive?: 'polite' | 'off'
|
|
15
|
+
// A 14px glyph identifying the section, drawn between the disclosure caret and the
|
|
16
|
+
// title. Keep it decorative: the host hides it from assistive tech so it cannot
|
|
17
|
+
// pollute the toggle's accessible name.
|
|
18
|
+
icon?: Snippet
|
|
19
|
+
// Optional per-section controls (refresh, edit, counts). Rendered as a sibling of
|
|
20
|
+
// the toggle button — never nested inside it — so nested <button>s stay valid.
|
|
21
|
+
actions?: Snippet
|
|
22
|
+
children: Snippet
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
let { sectionKey, title, label, cardId, ariaLive, icon, actions, children }: Props = $props()
|
|
26
|
+
|
|
27
|
+
let collapsed = $derived(isSectionCollapsed($collapsedSections, sectionKey))
|
|
28
|
+
let contentId = $derived(`info-section-${sectionKey}`)
|
|
29
|
+
</script>
|
|
30
|
+
|
|
31
|
+
<!-- `--section-inset` is the distance from the card edge to the caret. Hosts override it
|
|
32
|
+
per surface (the task inspector pushes it out to 1.5rem); the header and the body
|
|
33
|
+
both read it so they can never drift apart. `--section-caret-column` is the caret
|
|
34
|
+
plus the gap after it, so body content lines up with the icon and title rather than
|
|
35
|
+
starting under the caret. Keep it equal to the caret's `w-3` plus the header `gap-2`. -->
|
|
36
|
+
<section
|
|
37
|
+
data-task-info-card={cardId ?? sectionKey}
|
|
38
|
+
data-card-sizing="natural"
|
|
39
|
+
class="rounded-lg border border-base-300/70 bg-base-100 overflow-hidden shrink-0 [--section-inset:0.75rem] [--section-caret-column:1.25rem]"
|
|
40
|
+
aria-label={label ?? title}
|
|
41
|
+
aria-live={ariaLive}
|
|
42
|
+
>
|
|
43
|
+
<div class="flex items-stretch {collapsed ? '' : 'border-b border-base-300/70'}">
|
|
44
|
+
<h3 class="m-0 min-w-0 flex-1">
|
|
45
|
+
<button
|
|
46
|
+
type="button"
|
|
47
|
+
class="flex w-full items-center gap-2 px-[var(--section-inset)] py-2 text-left text-sm font-semibold text-base-content hover:bg-base-200/40 focus-visible:ring-2 focus-visible:ring-primary rounded"
|
|
48
|
+
aria-expanded={!collapsed}
|
|
49
|
+
aria-controls={contentId}
|
|
50
|
+
onclick={() => toggleSection(sectionKey)}
|
|
51
|
+
>
|
|
52
|
+
<!-- Fixed-width caret column so every section title starts at the same x,
|
|
53
|
+
including the single-row cards that render a blank column instead. -->
|
|
54
|
+
<span
|
|
55
|
+
class="w-3 shrink-0 text-center text-[0.7rem] leading-none text-base-content/40 transition-transform duration-150 {collapsed ? '-rotate-90' : ''}"
|
|
56
|
+
aria-hidden="true"
|
|
57
|
+
>▾</span>
|
|
58
|
+
{#if icon}
|
|
59
|
+
<span class="flex shrink-0 items-center text-base-content/50" aria-hidden="true">{@render icon()}</span>
|
|
60
|
+
{/if}
|
|
61
|
+
<span class="truncate">{title}</span>
|
|
62
|
+
</button>
|
|
63
|
+
</h3>
|
|
64
|
+
{#if actions}
|
|
65
|
+
<div class="flex shrink-0 items-center gap-2 pr-2">
|
|
66
|
+
{@render actions()}
|
|
67
|
+
</div>
|
|
68
|
+
{/if}
|
|
69
|
+
</div>
|
|
70
|
+
|
|
71
|
+
{#if !collapsed}
|
|
72
|
+
<div
|
|
73
|
+
id={contentId}
|
|
74
|
+
class="pl-[calc(var(--section-inset)_+_var(--section-caret-column))] pr-[var(--section-inset)]"
|
|
75
|
+
>
|
|
76
|
+
{@render children()}
|
|
77
|
+
</div>
|
|
78
|
+
{/if}
|
|
79
|
+
</section>
|
|
@@ -8,6 +8,12 @@
|
|
|
8
8
|
type ResolvedMarkdownMedia,
|
|
9
9
|
} from '../markdown'
|
|
10
10
|
|
|
11
|
+
interface MarkdownImageOpenRequest {
|
|
12
|
+
src: string
|
|
13
|
+
alt: string
|
|
14
|
+
openLink?: () => void
|
|
15
|
+
}
|
|
16
|
+
|
|
11
17
|
interface Props {
|
|
12
18
|
content: string
|
|
13
19
|
imageBaseUrl?: string | null
|
|
@@ -16,6 +22,7 @@
|
|
|
16
22
|
resolveRemoteMedia?: (url: string) => Promise<ResolvedMarkdownMedia | null>
|
|
17
23
|
onOpenRepositoryPath?: (repositoryPath: string, suffix: string) => void | Promise<void>
|
|
18
24
|
onOpenUrl?: (url: string) => void | Promise<void>
|
|
25
|
+
onOpenImage?: (request: MarkdownImageOpenRequest) => void
|
|
19
26
|
}
|
|
20
27
|
|
|
21
28
|
let {
|
|
@@ -26,6 +33,7 @@
|
|
|
26
33
|
resolveRemoteMedia,
|
|
27
34
|
onOpenRepositoryPath,
|
|
28
35
|
onOpenUrl,
|
|
36
|
+
onOpenImage,
|
|
29
37
|
}: Props = $props()
|
|
30
38
|
|
|
31
39
|
let root = $state<HTMLDivElement | null>(null)
|
|
@@ -37,6 +45,35 @@
|
|
|
37
45
|
deferRemoteMedia: Boolean(resolveRemoteMedia),
|
|
38
46
|
}))
|
|
39
47
|
|
|
48
|
+
function imageTrigger(image: HTMLImageElement): HTMLElement {
|
|
49
|
+
return image.closest('a') ?? image
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function updateInteractiveImage(image: HTMLImageElement) {
|
|
53
|
+
const trigger = imageTrigger(image)
|
|
54
|
+
if (!onOpenImage || !image.getAttribute('src')) {
|
|
55
|
+
if (trigger.dataset.markdownImageTrigger === 'true') {
|
|
56
|
+
trigger.removeAttribute('role')
|
|
57
|
+
trigger.removeAttribute('tabindex')
|
|
58
|
+
trigger.removeAttribute('aria-label')
|
|
59
|
+
delete trigger.dataset.markdownImageTrigger
|
|
60
|
+
}
|
|
61
|
+
image.classList.remove('cursor-zoom-in')
|
|
62
|
+
return
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const imageName = image.alt.trim()
|
|
66
|
+
trigger.setAttribute('role', 'button')
|
|
67
|
+
if (trigger === image) trigger.setAttribute('tabindex', '0')
|
|
68
|
+
trigger.setAttribute('aria-label', imageName ? `Open ${imageName} image` : 'Open image preview')
|
|
69
|
+
trigger.dataset.markdownImageTrigger = 'true'
|
|
70
|
+
image.classList.add('cursor-zoom-in')
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function updateInteractiveImages() {
|
|
74
|
+
if (!root) return
|
|
75
|
+
root.querySelectorAll('img').forEach(updateInteractiveImage)
|
|
76
|
+
}
|
|
40
77
|
async function resolveRepositoryImages(runId: number) {
|
|
41
78
|
if (!root || !markdownFilePath || !resolveRepositoryImage) return
|
|
42
79
|
|
|
@@ -50,6 +87,7 @@
|
|
|
50
87
|
if (runId !== imageResolutionId || !resolvedSrc) return
|
|
51
88
|
image.setAttribute('src', resolvedSrc)
|
|
52
89
|
image.removeAttribute('data-markdown-repository-path')
|
|
90
|
+
updateInteractiveImage(image)
|
|
53
91
|
} catch {
|
|
54
92
|
// Leave the image inert when an asset is missing or cannot be previewed.
|
|
55
93
|
}
|
|
@@ -61,6 +99,7 @@
|
|
|
61
99
|
|
|
62
100
|
if (element instanceof HTMLImageElement) {
|
|
63
101
|
element.setAttribute('src', resolved?.url ?? url)
|
|
102
|
+
updateInteractiveImage(element)
|
|
64
103
|
return
|
|
65
104
|
}
|
|
66
105
|
|
|
@@ -102,6 +141,7 @@
|
|
|
102
141
|
const runId = ++imageResolutionId
|
|
103
142
|
void html
|
|
104
143
|
if (!root) return
|
|
144
|
+
updateInteractiveImages()
|
|
105
145
|
|
|
106
146
|
void resolveRepositoryImages(runId)
|
|
107
147
|
void resolveRemoteMediaElements(runId)
|
|
@@ -111,17 +151,10 @@
|
|
|
111
151
|
imageResolutionId++
|
|
112
152
|
})
|
|
113
153
|
|
|
114
|
-
function
|
|
115
|
-
if (!(event.target instanceof Element)) return
|
|
116
|
-
|
|
117
|
-
const anchor = event.target.closest('a')
|
|
118
|
-
const href = anchor?.getAttribute('href')
|
|
119
|
-
if (!anchor || !href) return
|
|
120
|
-
|
|
154
|
+
function openMarkdownLink(href: string, absoluteHref: string) {
|
|
121
155
|
if (markdownFilePath) {
|
|
122
156
|
const repositoryPath = resolveMarkdownRepositoryPath(href, markdownFilePath)
|
|
123
157
|
if (repositoryPath) {
|
|
124
|
-
event.preventDefault()
|
|
125
158
|
void onOpenRepositoryPath?.(repositoryPath, getMarkdownRepositoryLinkSuffix(href))
|
|
126
159
|
return
|
|
127
160
|
}
|
|
@@ -129,14 +162,62 @@
|
|
|
129
162
|
|
|
130
163
|
if (href.startsWith('#')) return
|
|
131
164
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
void onOpenUrl(href.startsWith('//') ? `https:${href}` : anchor.href)
|
|
165
|
+
if (onOpenUrl && absoluteHref) {
|
|
166
|
+
void onOpenUrl(href.startsWith('//') ? `https:${href}` : absoluteHref)
|
|
135
167
|
}
|
|
136
168
|
}
|
|
169
|
+
|
|
170
|
+
function openImage(image: HTMLImageElement) {
|
|
171
|
+
const src = image.getAttribute('src')
|
|
172
|
+
if (!onOpenImage || !src) return
|
|
173
|
+
|
|
174
|
+
const anchor = image.closest('a')
|
|
175
|
+
const href = anchor?.getAttribute('href')
|
|
176
|
+
onOpenImage({
|
|
177
|
+
src,
|
|
178
|
+
alt: image.alt,
|
|
179
|
+
openLink: href ? () => openMarkdownLink(href, anchor?.href ?? '') : undefined,
|
|
180
|
+
})
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
function findEventImage(target: Element): HTMLImageElement | null {
|
|
184
|
+
const image = target.closest('img')
|
|
185
|
+
if (image instanceof HTMLImageElement) return image
|
|
186
|
+
|
|
187
|
+
return target.closest('a')?.querySelector('img') ?? null
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
function handleClick(event: MouseEvent) {
|
|
191
|
+
if (!(event.target instanceof Element)) return
|
|
192
|
+
|
|
193
|
+
const image = findEventImage(event.target)
|
|
194
|
+
if (image && onOpenImage && image.getAttribute('src')) {
|
|
195
|
+
event.preventDefault()
|
|
196
|
+
imageTrigger(image).focus()
|
|
197
|
+
openImage(image)
|
|
198
|
+
return
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
const anchor = event.target.closest('a')
|
|
202
|
+
const href = anchor?.getAttribute('href')
|
|
203
|
+
if (!anchor || !href) return
|
|
204
|
+
|
|
205
|
+
if (!href.startsWith('#')) event.preventDefault()
|
|
206
|
+
openMarkdownLink(href, anchor.href)
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
function handleKeydown(event: KeyboardEvent) {
|
|
210
|
+
if (event.key !== 'Enter' && event.key !== ' ') return
|
|
211
|
+
if (!(event.target instanceof Element)) return
|
|
212
|
+
|
|
213
|
+
const image = findEventImage(event.target)
|
|
214
|
+
if (!image) return
|
|
215
|
+
|
|
216
|
+
event.preventDefault()
|
|
217
|
+
openImage(image)
|
|
218
|
+
}
|
|
137
219
|
</script>
|
|
138
220
|
|
|
139
|
-
|
|
140
|
-
<div bind:this={root} role="presentation" class="markdown-body" onclick={handleClick}>
|
|
221
|
+
<div bind:this={root} role="presentation" class="markdown-body" onclick={handleClick} onkeydown={handleKeydown}>
|
|
141
222
|
{@html html}
|
|
142
223
|
</div>
|
package/dist/vite.js
CHANGED
|
@@ -39,6 +39,7 @@ const OPENFORGE_PLUGIN_SDK_SOURCE_ENTRYPOINTS = Object.freeze([
|
|
|
39
39
|
['@openforge-app/plugin-sdk/sanitize', 'packages/plugin-sdk/src/sanitize.ts'],
|
|
40
40
|
['@openforge-app/plugin-sdk/pluginIcons', 'packages/plugin-sdk/src/pluginIcons.ts'],
|
|
41
41
|
['@openforge-app/plugin-sdk/fileIcons', 'packages/plugin-sdk/src/fileIcons.ts'],
|
|
42
|
+
['@openforge-app/plugin-sdk/collapsibleSectionState', 'packages/plugin-sdk/src/collapsibleSectionState.ts'],
|
|
42
43
|
...OPENFORGE_PLUGIN_SDK_PUBLIC_UI_EXPORTS.map(({ importSpecifier, workspaceSourcePath }) => [importSpecifier, workspaceSourcePath]),
|
|
43
44
|
['@openforge-app/plugin-sdk', 'packages/plugin-sdk/src/index.ts'],
|
|
44
45
|
]);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openforge-app/plugin-sdk",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.7",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -64,6 +64,10 @@
|
|
|
64
64
|
"types": "./dist/fileIcons.d.ts",
|
|
65
65
|
"default": "./dist/fileIcons.js"
|
|
66
66
|
},
|
|
67
|
+
"./collapsibleSectionState": {
|
|
68
|
+
"types": "./dist/collapsibleSectionState.d.ts",
|
|
69
|
+
"default": "./dist/collapsibleSectionState.js"
|
|
70
|
+
},
|
|
67
71
|
"./ui/Button.svelte": "./dist/ui/Button.svelte",
|
|
68
72
|
"./ui/Checkbox.svelte": "./dist/ui/Checkbox.svelte",
|
|
69
73
|
"./ui/MarkdownContent.svelte": "./dist/ui/MarkdownContent.svelte",
|
|
@@ -72,7 +76,8 @@
|
|
|
72
76
|
"./ui/PluginPageHeader.svelte": "./dist/ui/PluginPageHeader.svelte",
|
|
73
77
|
"./ui/PluginViewState.svelte": "./dist/ui/PluginViewState.svelte",
|
|
74
78
|
"./ui/PluginSidebarLink.svelte": "./dist/ui/PluginSidebarLink.svelte",
|
|
75
|
-
"./ui/FileTypeIcon.svelte": "./dist/ui/FileTypeIcon.svelte"
|
|
79
|
+
"./ui/FileTypeIcon.svelte": "./dist/ui/FileTypeIcon.svelte",
|
|
80
|
+
"./ui/CollapsibleSection.svelte": "./dist/ui/CollapsibleSection.svelte"
|
|
76
81
|
},
|
|
77
82
|
"files": [
|
|
78
83
|
"dist",
|
package/dist/context.d.ts
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import type { Disposable, OpenForgeContextChangeHandler, OpenForgePackageMetadata, OpenForgePluginContext, SubscriptionSink, SupportedOpenForgeApiVersion } from './types';
|
|
2
|
-
declare class SubscriptionSet implements SubscriptionSink {
|
|
3
|
-
private readonly subscriptions;
|
|
4
|
-
add(subscription: Disposable | (() => void)): void;
|
|
5
|
-
disposeAll(): Promise<void>;
|
|
6
|
-
}
|
|
7
|
-
export declare class PluginContextImpl implements OpenForgePluginContext {
|
|
8
|
-
readonly pluginId: string;
|
|
9
|
-
readonly apiVersion: SupportedOpenForgeApiVersion;
|
|
10
|
-
readonly packageMetadata: OpenForgePackageMetadata;
|
|
11
|
-
readonly subscriptions: SubscriptionSet;
|
|
12
|
-
onDidChange(_handler: OpenForgeContextChangeHandler): Disposable;
|
|
13
|
-
constructor(pluginId: string, apiVersion: SupportedOpenForgeApiVersion, packageMetadata: OpenForgePackageMetadata);
|
|
14
|
-
}
|
|
15
|
-
export {};
|
package/dist/context.js
DELETED
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
class SubscriptionSet {
|
|
2
|
-
subscriptions = new Set();
|
|
3
|
-
add(subscription) {
|
|
4
|
-
this.subscriptions.add(subscription);
|
|
5
|
-
}
|
|
6
|
-
async disposeAll() {
|
|
7
|
-
const subscriptions = [...this.subscriptions];
|
|
8
|
-
this.subscriptions.clear();
|
|
9
|
-
await Promise.all(subscriptions.map(async (subscription) => {
|
|
10
|
-
if (typeof subscription === 'function') {
|
|
11
|
-
subscription();
|
|
12
|
-
}
|
|
13
|
-
else {
|
|
14
|
-
await subscription.dispose();
|
|
15
|
-
}
|
|
16
|
-
}));
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
export class PluginContextImpl {
|
|
20
|
-
pluginId;
|
|
21
|
-
apiVersion;
|
|
22
|
-
packageMetadata;
|
|
23
|
-
subscriptions;
|
|
24
|
-
onDidChange(_handler) {
|
|
25
|
-
return { dispose: () => undefined };
|
|
26
|
-
}
|
|
27
|
-
constructor(pluginId, apiVersion, packageMetadata) {
|
|
28
|
-
this.pluginId = pluginId;
|
|
29
|
-
this.apiVersion = apiVersion;
|
|
30
|
-
this.packageMetadata = packageMetadata;
|
|
31
|
-
this.subscriptions = new SubscriptionSet();
|
|
32
|
-
}
|
|
33
|
-
}
|