sh3-core 0.25.0 → 0.25.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/artifact.d.ts +7 -0
- package/dist/build.d.ts +8 -0
- package/dist/build.js +17 -7
- package/dist/build.test.js +27 -1
- package/dist/platform/localSidecar.d.ts +7 -0
- package/dist/platform/localSidecar.js +24 -0
- package/dist/platform/localSidecar.test.d.ts +1 -0
- package/dist/platform/localSidecar.test.js +39 -0
- package/dist/sh3core-shard/folderActions.d.ts +15 -0
- package/dist/sh3core-shard/folderActions.js +109 -0
- package/dist/sh3core-shard/folderActions.test.d.ts +1 -0
- package/dist/sh3core-shard/folderActions.test.js +43 -0
- package/dist/sh3core-shard/sh3coreShard.svelte.js +2 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
package/dist/artifact.d.ts
CHANGED
|
@@ -10,6 +10,13 @@ export interface ArtifactManifest {
|
|
|
10
10
|
id: string;
|
|
11
11
|
/** Whether this is a shard or app (or both via combo bundle). */
|
|
12
12
|
type: 'shard' | 'app' | 'combo';
|
|
13
|
+
/**
|
|
14
|
+
* Shard kind. Carried over from the source shard manifest so the server's
|
|
15
|
+
* project-allowlist middleware can auto-allow system-kind shards and
|
|
16
|
+
* resolve service-kind shards from `project.shardAllowlist`. Only set
|
|
17
|
+
* for `type: 'shard'`; apps and combos omit it.
|
|
18
|
+
*/
|
|
19
|
+
kind?: 'system' | 'service';
|
|
13
20
|
/** Human-readable display name. */
|
|
14
21
|
label: string;
|
|
15
22
|
/** Version string (semver). */
|
package/dist/build.d.ts
CHANGED
|
@@ -82,6 +82,14 @@ export declare function composeArtifactVersion(pkgVersion: string, suffix: strin
|
|
|
82
82
|
* Exported for testing; used internally by sh3Artifact.
|
|
83
83
|
*/
|
|
84
84
|
export declare function extractRequiredShardsFromBundle(bundleSource: string): string[];
|
|
85
|
+
/**
|
|
86
|
+
* Read a shard `kind` field (`system` or `service`) from a single manifest
|
|
87
|
+
* block. Returns undefined when absent or set to any other value. Exported
|
|
88
|
+
* for testing; used by `sh3Artifact` to propagate the shard's runtime kind
|
|
89
|
+
* into the emitted `manifest.json` so server-side allowlist resolution can
|
|
90
|
+
* see it.
|
|
91
|
+
*/
|
|
92
|
+
export declare function extractShardKindFromBlock(block: string): 'system' | 'service' | undefined;
|
|
85
93
|
/**
|
|
86
94
|
* Collect all shard ids present in a bundle by scanning every `views: [` block.
|
|
87
95
|
* Exported for testing.
|
package/dist/build.js
CHANGED
|
@@ -159,6 +159,17 @@ export function extractRequiredShardsFromBundle(bundleSource) {
|
|
|
159
159
|
ids.push(m[1]);
|
|
160
160
|
return ids;
|
|
161
161
|
}
|
|
162
|
+
/**
|
|
163
|
+
* Read a shard `kind` field (`system` or `service`) from a single manifest
|
|
164
|
+
* block. Returns undefined when absent or set to any other value. Exported
|
|
165
|
+
* for testing; used by `sh3Artifact` to propagate the shard's runtime kind
|
|
166
|
+
* into the emitted `manifest.json` so server-side allowlist resolution can
|
|
167
|
+
* see it.
|
|
168
|
+
*/
|
|
169
|
+
export function extractShardKindFromBlock(block) {
|
|
170
|
+
const m = block.match(/\bkind\s*:\s*["'](system|service)["']/);
|
|
171
|
+
return m ? m[1] : undefined;
|
|
172
|
+
}
|
|
162
173
|
/**
|
|
163
174
|
* Collect all shard ids present in a bundle by scanning every `views: [` block.
|
|
164
175
|
* Exported for testing.
|
|
@@ -301,15 +312,14 @@ export function sh3Artifact(options = {}) {
|
|
|
301
312
|
};
|
|
302
313
|
// Extract the requiredShards string-id array from the app manifest block.
|
|
303
314
|
const requiredShards = extractRequiredShardsFromBundle(block);
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
};
|
|
315
|
+
// Extract shard `kind` (system/service). Only meaningful when the
|
|
316
|
+
// anchored block is a shard block; app blocks won't carry it.
|
|
317
|
+
const kind = extractShardKindFromBlock(block);
|
|
318
|
+
return Object.assign(Object.assign({ id: get(/\bid\s*:\s*["']([^"']+)["']/), label: get(/\blabel\s*:\s*["']([^"']+)["']/) }, (kind ? { kind } : {})), { requiredShards });
|
|
309
319
|
}
|
|
310
320
|
// App first, then Shard.
|
|
311
321
|
const extracted = (_a = extractFromBlock(/\brequiredShards\s*:\s*\[/)) !== null && _a !== void 0 ? _a : extractFromBlock(/\bviews\s*:\s*\[/);
|
|
312
|
-
const { id, label } = extracted;
|
|
322
|
+
const { id, label, kind } = extracted;
|
|
313
323
|
let { requiredShards } = extracted;
|
|
314
324
|
// Strip any shard ids that are bundled in this artifact from requiredShards.
|
|
315
325
|
const bundledShardIds = extractBundledShardIds(source);
|
|
@@ -362,7 +372,7 @@ export function sh3Artifact(options = {}) {
|
|
|
362
372
|
if (!finalAuthor) {
|
|
363
373
|
throw new Error('[sh3-artifact] Missing "author". Add it to package.json or pass it via sh3Artifact({ manifest: { author } }).');
|
|
364
374
|
}
|
|
365
|
-
const manifest = Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({ id: id || 'unknown', type, label: label || id || 'unknown', version: artifactVersion, contractVersion: 1 }, (hasServer ? { server: 'server.js' } : {})), { description: finalDescription, author: finalAuthor }), ((type === 'app' || type === 'combo') ? { requiredShards } : {})), (type === 'combo' && bundledShardIds.size > 0 ? { bundledShards: [...bundledShardIds] } : {})), overrides);
|
|
375
|
+
const manifest = Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({ id: id || 'unknown', type, label: label || id || 'unknown', version: artifactVersion, contractVersion: 1 }, (type === 'shard' && kind ? { kind } : {})), (hasServer ? { server: 'server.js' } : {})), { description: finalDescription, author: finalAuthor }), ((type === 'app' || type === 'combo') ? { requiredShards } : {})), (type === 'combo' && bundledShardIds.size > 0 ? { bundledShards: [...bundledShardIds] } : {})), overrides);
|
|
366
376
|
// Read the emitted JS files as bytes for the archive
|
|
367
377
|
const clientBytes = readFileSync(join(outDir, 'client.js'));
|
|
368
378
|
const serverBytes = hasServer ? readFileSync(join(outDir, 'server.js')) : undefined;
|
package/dist/build.test.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { describe, it, expect } from 'vitest';
|
|
2
|
-
import { composeArtifactVersion, extractRequiredShardsFromBundle, extractBundledShardIds } from './build';
|
|
2
|
+
import { composeArtifactVersion, extractRequiredShardsFromBundle, extractBundledShardIds, extractShardKindFromBlock } from './build';
|
|
3
3
|
describe('composeArtifactVersion', () => {
|
|
4
4
|
it('returns pkgVersion unchanged when suffix is undefined', () => {
|
|
5
5
|
expect(composeArtifactVersion('1.2.3', undefined)).toBe('1.2.3');
|
|
@@ -84,3 +84,29 @@ describe('extractBundledShardIds', () => {
|
|
|
84
84
|
expect(filtered).toEqual(['external-dep']);
|
|
85
85
|
});
|
|
86
86
|
});
|
|
87
|
+
describe('extractShardKindFromBlock', () => {
|
|
88
|
+
it('extracts kind: "system"', () => {
|
|
89
|
+
const block = `{ id: "ai", label: "AI", kind: "system", views: [] }`;
|
|
90
|
+
expect(extractShardKindFromBlock(block)).toBe('system');
|
|
91
|
+
});
|
|
92
|
+
it('extracts kind: "service"', () => {
|
|
93
|
+
const block = `{ id: "registry", kind: "service", views: [] }`;
|
|
94
|
+
expect(extractShardKindFromBlock(block)).toBe('service');
|
|
95
|
+
});
|
|
96
|
+
it('handles single-quoted kind', () => {
|
|
97
|
+
const block = `{ id: 'ai', kind: 'system', views: [] }`;
|
|
98
|
+
expect(extractShardKindFromBlock(block)).toBe('system');
|
|
99
|
+
});
|
|
100
|
+
it('handles minified format without spaces', () => {
|
|
101
|
+
const block = `{id:"ai",kind:"system",views:[]}`;
|
|
102
|
+
expect(extractShardKindFromBlock(block)).toBe('system');
|
|
103
|
+
});
|
|
104
|
+
it('returns undefined when kind is absent', () => {
|
|
105
|
+
const block = `{ id: "plain-shard", label: "Plain", views: [] }`;
|
|
106
|
+
expect(extractShardKindFromBlock(block)).toBeUndefined();
|
|
107
|
+
});
|
|
108
|
+
it('returns undefined for unrecognized kind values', () => {
|
|
109
|
+
const block = `{ id: "weird", kind: "widget", views: [] }`;
|
|
110
|
+
expect(extractShardKindFromBlock(block)).toBeUndefined();
|
|
111
|
+
});
|
|
112
|
+
});
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* isLocalTauriDesktop — true iff we're in a Tauri webview AND the page
|
|
3
|
+
* was served by the local sh3-server sidecar (not the bundled frontend
|
|
4
|
+
* in remote-mode, and not Android's http://tauri.localhost shim).
|
|
5
|
+
*
|
|
6
|
+
* Synchronous: safe to call from action `disabled` predicates that run
|
|
7
|
+
* on every palette render. Logic is exposed via the pure
|
|
8
|
+
* `checkLocalTauriDesktop` so it can be unit-tested in the node project
|
|
9
|
+
* without a window/location shim.
|
|
10
|
+
*/
|
|
11
|
+
export function checkLocalTauriDesktop(env) {
|
|
12
|
+
return env.hasTauriInternals
|
|
13
|
+
&& env.protocol === 'http:'
|
|
14
|
+
&& env.hostname === 'localhost';
|
|
15
|
+
}
|
|
16
|
+
export function isLocalTauriDesktop() {
|
|
17
|
+
if (typeof window === 'undefined' || typeof location === 'undefined')
|
|
18
|
+
return false;
|
|
19
|
+
return checkLocalTauriDesktop({
|
|
20
|
+
hasTauriInternals: '__TAURI_INTERNALS__' in window,
|
|
21
|
+
protocol: location.protocol,
|
|
22
|
+
hostname: location.hostname,
|
|
23
|
+
});
|
|
24
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { checkLocalTauriDesktop } from './localSidecar';
|
|
3
|
+
describe('checkLocalTauriDesktop', () => {
|
|
4
|
+
it('returns true for Tauri desktop sidecar (http://localhost)', () => {
|
|
5
|
+
expect(checkLocalTauriDesktop({
|
|
6
|
+
hasTauriInternals: true,
|
|
7
|
+
protocol: 'http:',
|
|
8
|
+
hostname: 'localhost',
|
|
9
|
+
})).toBe(true);
|
|
10
|
+
});
|
|
11
|
+
it('returns false in pure web (no Tauri)', () => {
|
|
12
|
+
expect(checkLocalTauriDesktop({
|
|
13
|
+
hasTauriInternals: false,
|
|
14
|
+
protocol: 'https:',
|
|
15
|
+
hostname: 'example.com',
|
|
16
|
+
})).toBe(false);
|
|
17
|
+
});
|
|
18
|
+
it('returns false in Tauri remote-mode desktop (tauri://localhost)', () => {
|
|
19
|
+
expect(checkLocalTauriDesktop({
|
|
20
|
+
hasTauriInternals: true,
|
|
21
|
+
protocol: 'tauri:',
|
|
22
|
+
hostname: 'localhost',
|
|
23
|
+
})).toBe(false);
|
|
24
|
+
});
|
|
25
|
+
it('returns false on Tauri Android (http://tauri.localhost)', () => {
|
|
26
|
+
expect(checkLocalTauriDesktop({
|
|
27
|
+
hasTauriInternals: true,
|
|
28
|
+
protocol: 'http:',
|
|
29
|
+
hostname: 'tauri.localhost',
|
|
30
|
+
})).toBe(false);
|
|
31
|
+
});
|
|
32
|
+
it('returns false for https://localhost (not the sidecar)', () => {
|
|
33
|
+
expect(checkLocalTauriDesktop({
|
|
34
|
+
hasTauriInternals: true,
|
|
35
|
+
protocol: 'https:',
|
|
36
|
+
hostname: 'localhost',
|
|
37
|
+
})).toBe(false);
|
|
38
|
+
});
|
|
39
|
+
});
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { ShardContext } from '../shards/types';
|
|
2
|
+
/** Build the docs path for a user-or-project tenant id. Pure. */
|
|
3
|
+
export declare function buildDocumentsPath(root: string, tenantId: string, join: (...parts: string[]) => string): string;
|
|
4
|
+
export declare function disabledForApp(g: {
|
|
5
|
+
isLocal: boolean;
|
|
6
|
+
}): boolean;
|
|
7
|
+
export declare function disabledForUser(g: {
|
|
8
|
+
isLocal: boolean;
|
|
9
|
+
userId: string | null;
|
|
10
|
+
}): boolean;
|
|
11
|
+
export declare function disabledForProject(g: {
|
|
12
|
+
isLocal: boolean;
|
|
13
|
+
projectId: string | null;
|
|
14
|
+
}): boolean;
|
|
15
|
+
export declare function registerFolderActions(ctx: ShardContext): () => void;
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Palette-only "Open X folder" actions for the Tauri desktop sidecar.
|
|
3
|
+
* All three actions are registered unconditionally; visibility is gated
|
|
4
|
+
* by per-frame `disabled` predicates so changes in project scope or auth
|
|
5
|
+
* state take effect without re-registration.
|
|
6
|
+
*
|
|
7
|
+
* Targets:
|
|
8
|
+
* sh3.openAppDataFolder → appDataDir()
|
|
9
|
+
* sh3.openUserDocumentsFolder → appDataDir()/server/docs/<userId>
|
|
10
|
+
* sh3.openProjectDocumentsFolder → appDataDir()/server/docs/<activeProjectId>
|
|
11
|
+
*
|
|
12
|
+
* The `server/docs/<tenant>` layout matches sh3-server's doc-store on
|
|
13
|
+
* disk (see packages/sh3-server/src/doc-store/store.ts). The Tauri
|
|
14
|
+
* sidecar passes `appDataDir()/server` as sh3-server's --data arg.
|
|
15
|
+
*
|
|
16
|
+
* The runner uses dynamic `import()` for `@tauri-apps/api/path` and
|
|
17
|
+
* `@tauri-apps/plugin-opener` so Vite code-splits the Tauri deps into
|
|
18
|
+
* a separate chunk that only loads when the action runs. Mirrors the
|
|
19
|
+
* pattern used by `platform/index.ts` and `sh3Api/window.ts`.
|
|
20
|
+
*/
|
|
21
|
+
import { isLocalTauriDesktop } from '../platform/localSidecar';
|
|
22
|
+
import { getUser } from '../auth/auth.svelte';
|
|
23
|
+
import { sessionState } from '../projects/session-state.svelte';
|
|
24
|
+
import { toastManager } from '../overlays/toast';
|
|
25
|
+
/** Build the docs path for a user-or-project tenant id. Pure. */
|
|
26
|
+
export function buildDocumentsPath(root, tenantId, join) {
|
|
27
|
+
return join(root, 'server', 'docs', tenantId);
|
|
28
|
+
}
|
|
29
|
+
export function disabledForApp(g) {
|
|
30
|
+
return !g.isLocal;
|
|
31
|
+
}
|
|
32
|
+
export function disabledForUser(g) {
|
|
33
|
+
return !g.isLocal || g.userId == null;
|
|
34
|
+
}
|
|
35
|
+
export function disabledForProject(g) {
|
|
36
|
+
return !g.isLocal || g.projectId == null;
|
|
37
|
+
}
|
|
38
|
+
async function openFolder(kind) {
|
|
39
|
+
try {
|
|
40
|
+
const [{ appDataDir, join }, { openPath }] = await Promise.all([
|
|
41
|
+
import('@tauri-apps/api/path'),
|
|
42
|
+
import('@tauri-apps/plugin-opener'),
|
|
43
|
+
]);
|
|
44
|
+
const root = await appDataDir();
|
|
45
|
+
let target = root;
|
|
46
|
+
if (kind === 'user') {
|
|
47
|
+
const u = getUser();
|
|
48
|
+
if (!u)
|
|
49
|
+
return;
|
|
50
|
+
target = await join(root, 'server', 'docs', u.id);
|
|
51
|
+
}
|
|
52
|
+
else if (kind === 'project') {
|
|
53
|
+
const id = sessionState.activeProjectId;
|
|
54
|
+
if (!id)
|
|
55
|
+
return;
|
|
56
|
+
target = await join(root, 'server', 'docs', id);
|
|
57
|
+
}
|
|
58
|
+
await openPath(target);
|
|
59
|
+
}
|
|
60
|
+
catch (e) {
|
|
61
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
62
|
+
toastManager.notify(`Couldn't open folder: ${msg}`, { level: 'error', duration: 4000 });
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
export function registerFolderActions(ctx) {
|
|
66
|
+
const actions = [
|
|
67
|
+
{
|
|
68
|
+
id: 'sh3.openAppDataFolder',
|
|
69
|
+
label: 'Open SH3 data folder',
|
|
70
|
+
scope: ['home', 'app'],
|
|
71
|
+
contextItem: false,
|
|
72
|
+
paletteItem: true,
|
|
73
|
+
group: 'folders',
|
|
74
|
+
disabled: () => disabledForApp({ isLocal: isLocalTauriDesktop() }),
|
|
75
|
+
run: (_ctx) => openFolder('app'),
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
id: 'sh3.openUserDocumentsFolder',
|
|
79
|
+
label: 'Open user documents folder',
|
|
80
|
+
scope: ['home', 'app'],
|
|
81
|
+
contextItem: false,
|
|
82
|
+
paletteItem: true,
|
|
83
|
+
group: 'folders',
|
|
84
|
+
disabled: () => {
|
|
85
|
+
var _a, _b;
|
|
86
|
+
return disabledForUser({
|
|
87
|
+
isLocal: isLocalTauriDesktop(),
|
|
88
|
+
userId: (_b = (_a = getUser()) === null || _a === void 0 ? void 0 : _a.id) !== null && _b !== void 0 ? _b : null,
|
|
89
|
+
});
|
|
90
|
+
},
|
|
91
|
+
run: (_ctx) => openFolder('user'),
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
id: 'sh3.openProjectDocumentsFolder',
|
|
95
|
+
label: 'Open project documents folder',
|
|
96
|
+
scope: ['home', 'app'],
|
|
97
|
+
contextItem: false,
|
|
98
|
+
paletteItem: true,
|
|
99
|
+
group: 'folders',
|
|
100
|
+
disabled: () => disabledForProject({
|
|
101
|
+
isLocal: isLocalTauriDesktop(),
|
|
102
|
+
projectId: sessionState.activeProjectId,
|
|
103
|
+
}),
|
|
104
|
+
run: (_ctx) => openFolder('project'),
|
|
105
|
+
},
|
|
106
|
+
];
|
|
107
|
+
const disposers = actions.map((a) => ctx.actions.register(a));
|
|
108
|
+
return () => disposers.forEach((d) => d());
|
|
109
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { posix } from 'node:path';
|
|
3
|
+
import { buildDocumentsPath, disabledForApp, disabledForUser, disabledForProject, } from './folderActions';
|
|
4
|
+
const join = (...p) => posix.join(...p);
|
|
5
|
+
describe('buildDocumentsPath', () => {
|
|
6
|
+
it('joins server/docs/<tenantId> under root', () => {
|
|
7
|
+
expect(buildDocumentsPath('/data', 'alice', join)).toBe('/data/server/docs/alice');
|
|
8
|
+
});
|
|
9
|
+
it('uses the supplied join, not posix hard-coding', () => {
|
|
10
|
+
const out = buildDocumentsPath('C:\\data', 'bob', (...p) => p.join('\\'));
|
|
11
|
+
expect(out).toBe('C:\\data\\server\\docs\\bob');
|
|
12
|
+
});
|
|
13
|
+
});
|
|
14
|
+
describe('disabledForApp', () => {
|
|
15
|
+
it('disabled when not local Tauri desktop', () => {
|
|
16
|
+
expect(disabledForApp({ isLocal: false })).toBe(true);
|
|
17
|
+
});
|
|
18
|
+
it('enabled when local Tauri desktop', () => {
|
|
19
|
+
expect(disabledForApp({ isLocal: true })).toBe(false);
|
|
20
|
+
});
|
|
21
|
+
});
|
|
22
|
+
describe('disabledForUser', () => {
|
|
23
|
+
it('disabled when not local Tauri desktop', () => {
|
|
24
|
+
expect(disabledForUser({ isLocal: false, userId: 'alice' })).toBe(true);
|
|
25
|
+
});
|
|
26
|
+
it('disabled when no signed-in user', () => {
|
|
27
|
+
expect(disabledForUser({ isLocal: true, userId: null })).toBe(true);
|
|
28
|
+
});
|
|
29
|
+
it('enabled when local + user present', () => {
|
|
30
|
+
expect(disabledForUser({ isLocal: true, userId: 'alice' })).toBe(false);
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
describe('disabledForProject', () => {
|
|
34
|
+
it('disabled when not local Tauri desktop', () => {
|
|
35
|
+
expect(disabledForProject({ isLocal: false, projectId: 'acme' })).toBe(true);
|
|
36
|
+
});
|
|
37
|
+
it('disabled when no active project', () => {
|
|
38
|
+
expect(disabledForProject({ isLocal: true, projectId: null })).toBe(true);
|
|
39
|
+
});
|
|
40
|
+
it('enabled when local + project active', () => {
|
|
41
|
+
expect(disabledForProject({ isLocal: true, projectId: 'acme' })).toBe(false);
|
|
42
|
+
});
|
|
43
|
+
});
|
|
@@ -33,6 +33,7 @@ import { resetActivePresetToDefault } from '../layout/store.svelte';
|
|
|
33
33
|
import { modalManager } from '../overlays/modal';
|
|
34
34
|
import { floatManager } from '../overlays/float';
|
|
35
35
|
import { registerAppActions } from './appActions';
|
|
36
|
+
import { registerFolderActions } from './folderActions';
|
|
36
37
|
import { openPalette } from '../actions/listeners';
|
|
37
38
|
/**
|
|
38
39
|
* Build the palette-only float-maximize toggle action. Targets the topmost
|
|
@@ -122,6 +123,7 @@ export const sh3coreShard = {
|
|
|
122
123
|
ctx.registerView('sh3core:home', factory);
|
|
123
124
|
ctx.registerView('sh3:keys-and-peers', keysFactory);
|
|
124
125
|
registerAppActions(ctx);
|
|
126
|
+
registerFolderActions(ctx);
|
|
125
127
|
// Launcher parent — submenu drill host. No `run` needed: the
|
|
126
128
|
// dispatcher's default behavior opens a sub-palette filtered to
|
|
127
129
|
// `submenuOf === 'sh3.app.launch'`. The single parent replaces the
|
package/dist/version.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
/** Auto-generated from package.json — do not edit manually. */
|
|
2
|
-
export declare const VERSION = "0.25.
|
|
2
|
+
export declare const VERSION = "0.25.1";
|
package/dist/version.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
/** Auto-generated from package.json — do not edit manually. */
|
|
2
|
-
export const VERSION = '0.25.
|
|
2
|
+
export const VERSION = '0.25.1';
|