@rynx-ai/daemon 0.1.10 → 0.1.11-beta.2
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/bundled-plugins/.rynx-plugin/marketplace.json +10 -0
- package/bundled-plugins/plugins/lark/.rynx-plugin/plugin.json +37 -0
- package/bundled-plugins/plugins/lark/dist/cli-mirror/mirror-index.d.ts +48 -0
- package/bundled-plugins/plugins/lark/dist/cli-mirror/mirror-index.js +54 -0
- package/bundled-plugins/plugins/lark/dist/cli-mirror/rollout-mirror.d.ts +85 -0
- package/bundled-plugins/plugins/lark/dist/cli-mirror/rollout-mirror.js +333 -0
- package/bundled-plugins/plugins/lark/dist/cli-mirror/rollout-watcher.d.ts +109 -0
- package/bundled-plugins/plugins/lark/dist/cli-mirror/rollout-watcher.js +347 -0
- package/bundled-plugins/plugins/lark/dist/host-adapters.d.ts +95 -0
- package/bundled-plugins/plugins/lark/dist/host-adapters.js +504 -0
- package/bundled-plugins/plugins/lark/dist/index.d.ts +7 -0
- package/bundled-plugins/plugins/lark/dist/index.js +7 -0
- package/bundled-plugins/plugins/lark/dist/lark-card-stream.d.ts +363 -0
- package/bundled-plugins/plugins/lark/dist/lark-card-stream.js +1335 -0
- package/bundled-plugins/plugins/lark/dist/lark-config-store.d.ts +30 -0
- package/bundled-plugins/plugins/lark/dist/lark-config-store.js +135 -0
- package/bundled-plugins/plugins/lark/dist/lark-content.d.ts +30 -0
- package/bundled-plugins/plugins/lark/dist/lark-content.js +138 -0
- package/bundled-plugins/plugins/lark/dist/lark-conversation-directory.d.ts +65 -0
- package/bundled-plugins/plugins/lark/dist/lark-conversation-directory.js +106 -0
- package/bundled-plugins/plugins/lark/dist/lark-diff-card.d.ts +25 -0
- package/bundled-plugins/plugins/lark/dist/lark-diff-card.js +58 -0
- package/bundled-plugins/plugins/lark/dist/lark-fork-transcript.d.ts +16 -0
- package/bundled-plugins/plugins/lark/dist/lark-fork-transcript.js +141 -0
- package/bundled-plugins/plugins/lark/dist/lark-resume-card.d.ts +31 -0
- package/bundled-plugins/plugins/lark/dist/lark-resume-card.js +105 -0
- package/bundled-plugins/plugins/lark/dist/lark-runtime-state-store.d.ts +18 -0
- package/bundled-plugins/plugins/lark/dist/lark-runtime-state-store.js +95 -0
- package/bundled-plugins/plugins/lark/dist/lark-sdk/client.d.ts +8 -0
- package/bundled-plugins/plugins/lark/dist/lark-sdk/client.js +32 -0
- package/bundled-plugins/plugins/lark/dist/lark-sdk/index.d.ts +1 -0
- package/bundled-plugins/plugins/lark/dist/lark-sdk/index.js +1 -0
- package/bundled-plugins/plugins/lark/dist/lark-sender.d.ts +114 -0
- package/bundled-plugins/plugins/lark/dist/lark-sender.js +323 -0
- package/bundled-plugins/plugins/lark/dist/lark-session-store.d.ts +13 -0
- package/bundled-plugins/plugins/lark/dist/lark-session-store.js +14 -0
- package/bundled-plugins/plugins/lark/dist/lark-settings-card.d.ts +55 -0
- package/bundled-plugins/plugins/lark/dist/lark-settings-card.js +158 -0
- package/bundled-plugins/plugins/lark/dist/lark-setup.d.ts +39 -0
- package/bundled-plugins/plugins/lark/dist/lark-setup.js +103 -0
- package/bundled-plugins/plugins/lark/dist/lark.d.ts +507 -0
- package/bundled-plugins/plugins/lark/dist/lark.js +1977 -0
- package/bundled-plugins/plugins/lark/dist/runtime.d.ts +13 -0
- package/bundled-plugins/plugins/lark/dist/runtime.js +131316 -0
- package/bundled-plugins/plugins/lark/dist/settings.d.ts +7 -0
- package/bundled-plugins/plugins/lark/dist/settings.js +126958 -0
- package/bundled-plugins/plugins/lark/package.json +57 -0
- package/bundled-plugins/plugins/lark/ui/assets/index-B2dhMlMU.css +1 -0
- package/bundled-plugins/plugins/lark/ui/assets/index-D9N-AkLX.js +201 -0
- package/bundled-plugins/plugins/lark/ui/assets/inter-cyrillic-ext-wght-normal-BOeWTOD4.woff2 +0 -0
- package/bundled-plugins/plugins/lark/ui/assets/inter-cyrillic-wght-normal-DqGufNeO.woff2 +0 -0
- package/bundled-plugins/plugins/lark/ui/assets/inter-greek-ext-wght-normal-DlzME5K_.woff2 +0 -0
- package/bundled-plugins/plugins/lark/ui/assets/inter-greek-wght-normal-CkhJZR-_.woff2 +0 -0
- package/bundled-plugins/plugins/lark/ui/assets/inter-latin-ext-wght-normal-DO1Apj_S.woff2 +0 -0
- package/bundled-plugins/plugins/lark/ui/assets/inter-latin-wght-normal-Dx4kXJAl.woff2 +0 -0
- package/bundled-plugins/plugins/lark/ui/assets/inter-vietnamese-wght-normal-CBcvBZtf.woff2 +0 -0
- package/bundled-plugins/plugins/lark/ui/assets/jetbrains-mono-cyrillic-wght-normal-D73BlboJ.woff2 +0 -0
- package/bundled-plugins/plugins/lark/ui/assets/jetbrains-mono-greek-wght-normal-Bw9x6K1M.woff2 +0 -0
- package/bundled-plugins/plugins/lark/ui/assets/jetbrains-mono-latin-ext-wght-normal-DBQx-q_a.woff2 +0 -0
- package/bundled-plugins/plugins/lark/ui/assets/jetbrains-mono-latin-wght-normal-B9CIFXIH.woff2 +0 -0
- package/bundled-plugins/plugins/lark/ui/assets/jetbrains-mono-vietnamese-wght-normal-Bt-aOZkq.woff2 +0 -0
- package/bundled-plugins/plugins/lark/ui/index.html +13 -0
- package/dist/bundled-plugins.d.ts +15 -0
- package/dist/bundled-plugins.js +134 -0
- package/dist/cli.js +26 -208
- package/dist/control-deps.js +2 -79
- package/dist/daemon-server.d.ts +4 -1
- package/dist/daemon-server.js +167 -57
- package/dist/db.js +145 -124
- package/dist/index-daemon.js +25 -4
- package/dist/migrations/cleanup-legacy-sessions.d.ts +1 -1
- package/dist/migrations/cleanup-legacy-sessions.js +33 -15
- package/dist/official-plugins.d.ts +2 -0
- package/dist/official-plugins.js +2 -0
- package/dist/plugin-cli.d.ts +1 -3
- package/dist/plugin-cli.js +56 -45
- package/dist/plugin-host-leases.d.ts +4 -0
- package/dist/plugin-host-leases.js +7 -0
- package/dist/plugin-host-rpc.d.ts +42 -4
- package/dist/plugin-host-rpc.js +144 -34
- package/dist/plugin-installer.d.ts +24 -55
- package/dist/plugin-installer.js +202 -415
- package/dist/plugin-management-service.d.ts +30 -23
- package/dist/plugin-management-service.js +290 -105
- package/dist/plugin-marketplace.d.ts +35 -0
- package/dist/plugin-marketplace.js +299 -0
- package/dist/plugin-package.d.ts +22 -24
- package/dist/plugin-package.js +520 -571
- package/dist/plugin-skill-context.d.ts +4 -0
- package/dist/plugin-skill-context.js +35 -0
- package/dist/plugin-store.d.ts +36 -37
- package/dist/plugin-store.js +140 -92
- package/dist/plugin-supervisor.d.ts +45 -125
- package/dist/plugin-supervisor.js +516 -1053
- package/dist/pm2.js +15 -10
- package/dist/runtime-project-store.d.ts +9 -0
- package/dist/runtime-project-store.js +83 -0
- package/dist/session-fallback-workspace.d.ts +22 -0
- package/dist/session-fallback-workspace.js +120 -0
- package/dist/session-fork-store.d.ts +41 -0
- package/dist/session-fork-store.js +288 -0
- package/dist/session-launch-operations.d.ts +14 -2
- package/dist/session-launch-operations.js +34 -2
- package/dist/session-meta-store.d.ts +7 -9
- package/dist/session-meta-store.js +28 -49
- package/dist/setup.js +26 -14
- package/package.json +14 -11
- package/dist/channel-store.d.ts +0 -22
- package/dist/channel-store.js +0 -65
- package/dist/instance-store.d.ts +0 -38
- package/dist/instance-store.js +0 -85
- package/dist/plugin-install-restart.d.ts +0 -13
- package/dist/plugin-install-restart.js +0 -24
- package/dist/plugin-runtime-control.d.ts +0 -2
- package/dist/plugin-runtime-control.js +0 -37
- package/dist/registry.d.ts +0 -10
- package/dist/registry.js +0 -52
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { type ResolvedPluginSkillSourceSnapshot } from "@rynx-ai/core";
|
|
2
|
+
/** Capture enabled plugin skill roots for persistence in a Session snapshot. */
|
|
3
|
+
export declare function snapshotEnabledPluginSkillSources(): ResolvedPluginSkillSourceSnapshot[];
|
|
4
|
+
export declare function removeLegacyPluginSkillSnapshot(sessionId: string): void;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { rmSync } from "node:fs";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { rynxHome } from "@rynx-ai/core";
|
|
5
|
+
import { resolvePackagePath } from "./plugin-package.js";
|
|
6
|
+
import { listEnabledPlugins } from "./plugin-store.js";
|
|
7
|
+
/** Capture enabled plugin skill roots for persistence in a Session snapshot. */
|
|
8
|
+
export function snapshotEnabledPluginSkillSources() {
|
|
9
|
+
return listEnabledPlugins().flatMap((record) => {
|
|
10
|
+
if (!record.manifest.skills)
|
|
11
|
+
return [];
|
|
12
|
+
return [{
|
|
13
|
+
installationId: record.canonicalId,
|
|
14
|
+
integrity: record.integrity,
|
|
15
|
+
packageRoot: record.installPath,
|
|
16
|
+
root: resolvePackagePath(record.installPath, record.manifest.skills, "skills", "directory"),
|
|
17
|
+
namespace: pluginSkillNamespace(record.canonicalId),
|
|
18
|
+
}];
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
export function removeLegacyPluginSkillSnapshot(sessionId) {
|
|
22
|
+
const digest = createHash("sha256").update(sessionId).digest("hex");
|
|
23
|
+
rmSync(join(rynxHome(), "plugins", "task-skill-snapshots", `${digest}.json`), {
|
|
24
|
+
force: true,
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
function pluginSkillNamespace(canonicalId) {
|
|
28
|
+
const slug = canonicalId
|
|
29
|
+
.toLowerCase()
|
|
30
|
+
.replace(/[^a-z0-9-]+/g, "-")
|
|
31
|
+
.replace(/^-+|-+$/g, "")
|
|
32
|
+
.slice(0, 96);
|
|
33
|
+
const digest = createHash("sha256").update(canonicalId).digest("hex").slice(0, 12);
|
|
34
|
+
return `plugin-${slug || "package"}-${digest}`;
|
|
35
|
+
}
|
package/dist/plugin-store.d.ts
CHANGED
|
@@ -1,56 +1,55 @@
|
|
|
1
|
-
/**
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
* installation path. Runtime modules are never imported while reading this
|
|
6
|
-
* table. Rows from the pre-v1 executable-manifest format remain visible to the
|
|
7
|
-
* CLI, but are not runnable and must be reinstalled.
|
|
8
|
-
*/
|
|
9
|
-
import { type PluginCapability, type PluginManifestV1 } from "@rynx-ai/plugin-sdk";
|
|
10
|
-
export type PluginSource = "npm" | "local" | "git" | "url";
|
|
1
|
+
/** Durable source-qualified inventory of installed plugin packages. */
|
|
2
|
+
import { type PluginManifestV1, type PluginPackageSourceV1 } from "@rynx-ai/plugin-sdk";
|
|
3
|
+
export type PluginSource = "local" | "git";
|
|
4
|
+
export type PluginRuntimeState = "absent" | "starting" | "running" | "degraded" | "failed" | "stopped";
|
|
11
5
|
export interface PluginRecord {
|
|
12
|
-
/**
|
|
6
|
+
/** Canonical installation identity: `<plugin-id>@<marketplace-id>`. */
|
|
7
|
+
canonicalId: string;
|
|
8
|
+
/** Canonical display/CLI value; always equals canonicalId. */
|
|
13
9
|
name: string;
|
|
14
|
-
|
|
15
|
-
|
|
10
|
+
marketplaceId: string;
|
|
11
|
+
pluginId: string;
|
|
16
12
|
source: PluginSource;
|
|
17
|
-
|
|
18
|
-
|
|
13
|
+
requestedSource: PluginPackageSourceV1;
|
|
14
|
+
resolvedRevision: string;
|
|
15
|
+
sourceFingerprint: string;
|
|
16
|
+
/** Stable serialized source used for explicit updates. */
|
|
17
|
+
spec: string;
|
|
18
|
+
version: string;
|
|
19
19
|
enabled: boolean;
|
|
20
20
|
installedAt: string;
|
|
21
21
|
updatedAt: string;
|
|
22
|
-
/** Host-generated immutable installation root. Missing only on legacy rows. */
|
|
23
|
-
installPath?: string;
|
|
24
|
-
/** Validated, pure-data manifest. Missing only on legacy rows. */
|
|
25
|
-
manifest?: PluginManifestV1;
|
|
26
|
-
/** sha256 integrity string for the materialized package. */
|
|
27
|
-
integrity?: string;
|
|
28
|
-
/** Capabilities approved for this installation. */
|
|
29
|
-
grants: PluginCapability[];
|
|
30
|
-
}
|
|
31
|
-
export interface RunnablePluginRecord extends PluginRecord {
|
|
32
22
|
installPath: string;
|
|
33
23
|
manifest: PluginManifestV1;
|
|
34
24
|
integrity: string;
|
|
25
|
+
runtimeState: PluginRuntimeState;
|
|
26
|
+
runtimeError?: string;
|
|
35
27
|
}
|
|
36
|
-
|
|
28
|
+
export type RunnablePluginRecord = PluginRecord;
|
|
29
|
+
export declare function canonicalPluginId(pluginId: string, marketplaceId: string): string;
|
|
30
|
+
export declare function parseCanonicalPluginId(value: string): {
|
|
31
|
+
pluginId: string;
|
|
32
|
+
marketplaceId: string;
|
|
33
|
+
};
|
|
37
34
|
export declare function listPlugins(): PluginRecord[];
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
export declare function getPlugin(
|
|
41
|
-
/** Atomically point a plugin id at a completely materialized installation. */
|
|
35
|
+
export declare function listEnabledPlugins(): PluginRecord[];
|
|
36
|
+
/** Exact canonical lookup. Unqualified ids are accepted only when unambiguous. */
|
|
37
|
+
export declare function getPlugin(identity: string): PluginRecord | undefined;
|
|
42
38
|
export declare function upsertPlugin(rec: {
|
|
43
|
-
|
|
44
|
-
|
|
39
|
+
canonicalId: string;
|
|
40
|
+
marketplaceId: string;
|
|
41
|
+
pluginId: string;
|
|
45
42
|
source: PluginSource;
|
|
46
|
-
|
|
43
|
+
requestedSource: PluginPackageSourceV1;
|
|
44
|
+
resolvedRevision: string;
|
|
45
|
+
sourceFingerprint: string;
|
|
46
|
+
version: string;
|
|
47
47
|
installPath: string;
|
|
48
48
|
manifest: PluginManifestV1;
|
|
49
49
|
integrity: string;
|
|
50
|
-
grants: readonly PluginCapability[];
|
|
51
50
|
enabled?: boolean;
|
|
52
51
|
}): void;
|
|
53
|
-
export declare function setPluginEnabled(
|
|
54
|
-
|
|
55
|
-
export declare function removePlugin(
|
|
52
|
+
export declare function setPluginEnabled(identity: string, enabled: boolean): void;
|
|
53
|
+
export declare function setPluginRuntimeState(identity: string, state: PluginRuntimeState, error?: string): void;
|
|
54
|
+
export declare function removePlugin(identity: string): boolean;
|
|
56
55
|
export declare function isRunnablePluginRecord(record: PluginRecord): record is RunnablePluginRecord;
|
package/dist/plugin-store.js
CHANGED
|
@@ -1,121 +1,169 @@
|
|
|
1
|
-
/**
|
|
2
|
-
|
|
3
|
-
*
|
|
4
|
-
* The registry stores only static, validated manifest data and a host-owned
|
|
5
|
-
* installation path. Runtime modules are never imported while reading this
|
|
6
|
-
* table. Rows from the pre-v1 executable-manifest format remain visible to the
|
|
7
|
-
* CLI, but are not runnable and must be reinstalled.
|
|
8
|
-
*/
|
|
9
|
-
import { parsePluginManifest, } from "@rynx-ai/plugin-sdk";
|
|
1
|
+
/** Durable source-qualified inventory of installed plugin packages. */
|
|
2
|
+
import { MARKETPLACE_ID_PATTERN, PLUGIN_ID_PATTERN, parsePluginManifest, } from "@rynx-ai/plugin-sdk";
|
|
10
3
|
import { db } from "./db.js";
|
|
11
|
-
function
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
4
|
+
export function canonicalPluginId(pluginId, marketplaceId) {
|
|
5
|
+
if (!PLUGIN_ID_PATTERN.test(pluginId))
|
|
6
|
+
throw new Error(`invalid plugin id "${pluginId}"`);
|
|
7
|
+
if (!MARKETPLACE_ID_PATTERN.test(marketplaceId)) {
|
|
8
|
+
throw new Error(`invalid marketplace id "${marketplaceId}"`);
|
|
9
|
+
}
|
|
10
|
+
return `${pluginId}@${marketplaceId}`;
|
|
11
|
+
}
|
|
12
|
+
export function parseCanonicalPluginId(value) {
|
|
13
|
+
const separator = value.lastIndexOf("@");
|
|
14
|
+
if (separator <= 0 || separator === value.length - 1) {
|
|
15
|
+
throw new Error("plugin identity must be <plugin-id>@<marketplace-id>");
|
|
16
|
+
}
|
|
17
|
+
const pluginId = value.slice(0, separator);
|
|
18
|
+
const marketplaceId = value.slice(separator + 1);
|
|
19
|
+
canonicalPluginId(pluginId, marketplaceId);
|
|
20
|
+
return { pluginId, marketplaceId };
|
|
26
21
|
}
|
|
27
|
-
/** All installed plugins, including incompatible legacy rows. */
|
|
28
22
|
export function listPlugins() {
|
|
29
|
-
const rows = db()
|
|
23
|
+
const rows = db()
|
|
24
|
+
.prepare("SELECT * FROM plugin_installations ORDER BY marketplace_id, plugin_id")
|
|
25
|
+
.all();
|
|
30
26
|
return rows.map(toRecord);
|
|
31
27
|
}
|
|
32
|
-
/** Enabled v1 installations that are safe for the runner to consider. */
|
|
33
28
|
export function listEnabledPlugins() {
|
|
34
|
-
return listPlugins().filter(
|
|
29
|
+
return listPlugins().filter((plugin) => plugin.enabled);
|
|
35
30
|
}
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
31
|
+
/** Exact canonical lookup. Unqualified ids are accepted only when unambiguous. */
|
|
32
|
+
export function getPlugin(identity) {
|
|
33
|
+
if (identity.includes("@")) {
|
|
34
|
+
const row = db()
|
|
35
|
+
.prepare("SELECT * FROM plugin_installations WHERE canonical_id = ?")
|
|
36
|
+
.get(identity);
|
|
37
|
+
return row ? toRecord(row) : undefined;
|
|
38
|
+
}
|
|
39
|
+
if (!PLUGIN_ID_PATTERN.test(identity))
|
|
40
|
+
return undefined;
|
|
41
|
+
const rows = db()
|
|
42
|
+
.prepare("SELECT * FROM plugin_installations WHERE plugin_id = ? ORDER BY marketplace_id")
|
|
43
|
+
.all(identity);
|
|
44
|
+
if (rows.length > 1) {
|
|
45
|
+
throw new Error(`plugin id "${identity}" is ambiguous; use <plugin-id>@<marketplace-id>`);
|
|
46
|
+
}
|
|
47
|
+
return rows[0] ? toRecord(rows[0]) : undefined;
|
|
39
48
|
}
|
|
40
|
-
/** Atomically point a plugin id at a completely materialized installation. */
|
|
41
49
|
export function upsertPlugin(rec) {
|
|
42
|
-
if (rec.
|
|
43
|
-
throw new Error(`plugin registry id mismatch: ${rec.
|
|
50
|
+
if (rec.pluginId !== rec.manifest.id) {
|
|
51
|
+
throw new Error(`plugin registry id mismatch: ${rec.pluginId} != ${rec.manifest.id}`);
|
|
44
52
|
}
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
if (!requested.has(grant))
|
|
48
|
-
throw new Error(`plugin grant was not requested: ${grant}`);
|
|
53
|
+
if (rec.canonicalId !== canonicalPluginId(rec.pluginId, rec.marketplaceId)) {
|
|
54
|
+
throw new Error("plugin canonical identity mismatch");
|
|
49
55
|
}
|
|
50
56
|
const now = new Date().toISOString();
|
|
51
|
-
db()
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
57
|
+
db().prepare(`INSERT INTO plugin_installations (
|
|
58
|
+
canonical_id, marketplace_id, plugin_id, source_type, requested_source,
|
|
59
|
+
resolved_revision, source_fingerprint, version, enabled, installed_at,
|
|
60
|
+
updated_at, install_path, manifest, integrity, capabilities, runtime_state, runtime_error
|
|
61
|
+
) VALUES (
|
|
62
|
+
@canonicalId, @marketplaceId, @pluginId, @source, @requestedSource,
|
|
63
|
+
@resolvedRevision, @sourceFingerprint, @version, @enabled, @now,
|
|
64
|
+
@now, @installPath, @manifest, @integrity, @capabilities, 'stopped', NULL
|
|
65
|
+
)
|
|
66
|
+
ON CONFLICT(canonical_id) DO UPDATE SET
|
|
67
|
+
source_type = excluded.source_type,
|
|
68
|
+
requested_source = excluded.requested_source,
|
|
69
|
+
resolved_revision = excluded.resolved_revision,
|
|
70
|
+
source_fingerprint = excluded.source_fingerprint,
|
|
71
|
+
version = excluded.version,
|
|
72
|
+
enabled = excluded.enabled,
|
|
73
|
+
updated_at = excluded.updated_at,
|
|
74
|
+
install_path = excluded.install_path,
|
|
75
|
+
manifest = excluded.manifest,
|
|
76
|
+
integrity = excluded.integrity,
|
|
77
|
+
capabilities = excluded.capabilities,
|
|
78
|
+
runtime_state = 'stopped',
|
|
79
|
+
runtime_error = NULL`).run({
|
|
80
|
+
canonicalId: rec.canonicalId,
|
|
81
|
+
marketplaceId: rec.marketplaceId,
|
|
82
|
+
pluginId: rec.pluginId,
|
|
73
83
|
source: rec.source,
|
|
74
|
-
|
|
84
|
+
requestedSource: JSON.stringify(rec.requestedSource),
|
|
85
|
+
resolvedRevision: rec.resolvedRevision,
|
|
86
|
+
sourceFingerprint: rec.sourceFingerprint,
|
|
87
|
+
version: rec.version,
|
|
75
88
|
enabled: rec.enabled === false ? 0 : 1,
|
|
76
89
|
now,
|
|
77
90
|
installPath: rec.installPath,
|
|
78
91
|
manifest: JSON.stringify(rec.manifest),
|
|
79
92
|
integrity: rec.integrity,
|
|
80
|
-
|
|
93
|
+
capabilities: JSON.stringify(rec.manifest.capabilities),
|
|
81
94
|
});
|
|
82
95
|
}
|
|
83
|
-
export function setPluginEnabled(
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
96
|
+
export function setPluginEnabled(identity, enabled) {
|
|
97
|
+
const record = getPlugin(identity);
|
|
98
|
+
if (!record)
|
|
99
|
+
return;
|
|
100
|
+
db().prepare("UPDATE plugin_installations SET enabled = ?, updated_at = ? WHERE canonical_id = ?").run(enabled ? 1 : 0, new Date().toISOString(), record.canonicalId);
|
|
87
101
|
}
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
102
|
+
export function setPluginRuntimeState(identity, state, error) {
|
|
103
|
+
const record = getPlugin(identity);
|
|
104
|
+
if (!record)
|
|
105
|
+
return;
|
|
106
|
+
db().prepare(`UPDATE plugin_installations
|
|
107
|
+
SET runtime_state = ?, runtime_error = ?
|
|
108
|
+
WHERE canonical_id = ?`).run(state, error ?? null, record.canonicalId);
|
|
109
|
+
}
|
|
110
|
+
export function removePlugin(identity) {
|
|
111
|
+
const record = getPlugin(identity);
|
|
112
|
+
if (!record)
|
|
113
|
+
return false;
|
|
114
|
+
return db()
|
|
115
|
+
.prepare("DELETE FROM plugin_installations WHERE canonical_id = ?")
|
|
116
|
+
.run(record.canonicalId).changes > 0;
|
|
91
117
|
}
|
|
92
118
|
export function isRunnablePluginRecord(record) {
|
|
93
119
|
return Boolean(record.installPath && record.manifest && record.integrity);
|
|
94
120
|
}
|
|
95
|
-
function
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
121
|
+
function toRecord(row) {
|
|
122
|
+
const manifest = parsePluginManifest(JSON.parse(row.manifest));
|
|
123
|
+
const requestedSource = JSON.parse(row.requested_source);
|
|
124
|
+
return {
|
|
125
|
+
canonicalId: row.canonical_id,
|
|
126
|
+
name: row.canonical_id,
|
|
127
|
+
marketplaceId: row.marketplace_id,
|
|
128
|
+
pluginId: row.plugin_id,
|
|
129
|
+
source: row.source_type === "local" ? "local" : "git",
|
|
130
|
+
requestedSource,
|
|
131
|
+
resolvedRevision: row.resolved_revision,
|
|
132
|
+
sourceFingerprint: row.source_fingerprint,
|
|
133
|
+
spec: serializeRequestedSource(requestedSource),
|
|
134
|
+
version: row.version,
|
|
135
|
+
enabled: row.enabled !== 0,
|
|
136
|
+
installedAt: row.installed_at,
|
|
137
|
+
updatedAt: row.updated_at,
|
|
138
|
+
installPath: row.install_path,
|
|
139
|
+
manifest,
|
|
140
|
+
integrity: row.integrity,
|
|
141
|
+
runtimeState: parseRuntimeState(row.runtime_state),
|
|
142
|
+
...(row.runtime_error ? { runtimeError: row.runtime_error } : {}),
|
|
143
|
+
};
|
|
104
144
|
}
|
|
105
|
-
function
|
|
106
|
-
if (
|
|
107
|
-
return
|
|
108
|
-
try {
|
|
109
|
-
const values = JSON.parse(raw);
|
|
110
|
-
if (!Array.isArray(values))
|
|
111
|
-
return [];
|
|
112
|
-
const requested = new Set(manifest.requestedCapabilities);
|
|
113
|
-
return values.filter((value) => typeof value === "string" && requested.has(value));
|
|
114
|
-
}
|
|
115
|
-
catch {
|
|
116
|
-
return [];
|
|
145
|
+
function serializeRequestedSource(source) {
|
|
146
|
+
if (source.type === "local") {
|
|
147
|
+
return `${source.path}${source.subdir ? `#path=${source.subdir}` : ""}`;
|
|
117
148
|
}
|
|
149
|
+
const params = new URLSearchParams();
|
|
150
|
+
if (source.subdir)
|
|
151
|
+
params.set("path", source.subdir);
|
|
152
|
+
if (source.ref)
|
|
153
|
+
params.set("ref", source.ref);
|
|
154
|
+
if (source.commit)
|
|
155
|
+
params.set("ref", source.commit);
|
|
156
|
+
const fragment = params.toString();
|
|
157
|
+
return `${source.url}${fragment ? `#${fragment}` : ""}`;
|
|
118
158
|
}
|
|
119
|
-
function
|
|
120
|
-
|
|
159
|
+
function parseRuntimeState(value) {
|
|
160
|
+
if (value === "absent" ||
|
|
161
|
+
value === "starting" ||
|
|
162
|
+
value === "running" ||
|
|
163
|
+
value === "degraded" ||
|
|
164
|
+
value === "failed")
|
|
165
|
+
return value;
|
|
166
|
+
if (value === "needs_setup")
|
|
167
|
+
return "running";
|
|
168
|
+
return "stopped";
|
|
121
169
|
}
|
|
@@ -1,35 +1,8 @@
|
|
|
1
|
-
import { type
|
|
2
|
-
import { type SpawnPluginRunnerOptions } from "@rynx-ai/plugin-runner";
|
|
3
|
-
import { type PluginAuthMaterial, type PluginContributionStatus, type PluginContributionTarget, type PluginJsonValue, type PluginRunnerHandshake, type PluginRuntimeStatus, type PluginStartContributionRequest } from "@rynx-ai/plugin-sdk";
|
|
1
|
+
import { type PluginHealth, type PluginJsonValue } from "@rynx-ai/plugin-sdk";
|
|
2
|
+
import { type SpawnedPluginRunner, type SpawnPluginRunnerOptions } from "@rynx-ai/plugin-runner";
|
|
4
3
|
import { type PluginHostServices } from "./plugin-host-rpc.js";
|
|
5
|
-
import type
|
|
6
|
-
export
|
|
7
|
-
startContribution(request: PluginStartContributionRequest): Promise<void>;
|
|
8
|
-
stopContribution(target: PluginContributionTarget): Promise<void>;
|
|
9
|
-
status(target: PluginContributionTarget): Promise<PluginContributionStatus>;
|
|
10
|
-
runtimeStatus(): Promise<PluginRuntimeStatus>;
|
|
11
|
-
authorize(request: {
|
|
12
|
-
kind: "chat-channel";
|
|
13
|
-
contributionId: string;
|
|
14
|
-
instanceId?: string;
|
|
15
|
-
config: Readonly<Record<string, PluginJsonValue>>;
|
|
16
|
-
}, onMaterial: (material: PluginAuthMaterial) => void, options?: {
|
|
17
|
-
signal?: AbortSignal;
|
|
18
|
-
timeoutMs?: number;
|
|
19
|
-
}): Promise<Record<string, PluginJsonValue>>;
|
|
20
|
-
emitHostEvent(event: string, payload?: unknown): Promise<void>;
|
|
21
|
-
}
|
|
22
|
-
/** The subset of a spawned runner the supervisor owns. Kept structural for tests. */
|
|
23
|
-
export interface SupervisedPluginRunner {
|
|
24
|
-
readonly client: PluginRunnerClientHandle;
|
|
25
|
-
readonly handshake: PluginRunnerHandshake;
|
|
26
|
-
readonly completion: Promise<{
|
|
27
|
-
code: number | null;
|
|
28
|
-
signal: NodeJS.Signals | null;
|
|
29
|
-
}>;
|
|
30
|
-
close(): Promise<void>;
|
|
31
|
-
}
|
|
32
|
-
export type PluginRunnerSpawnFactory = (options: SpawnPluginRunnerOptions) => Promise<SupervisedPluginRunner>;
|
|
4
|
+
import { type PluginRecord, type PluginRuntimeState, type RunnablePluginRecord } from "./plugin-store.js";
|
|
5
|
+
export type PluginRunnerSpawnFactory = (options: SpawnPluginRunnerOptions) => Promise<SpawnedPluginRunner>;
|
|
33
6
|
export interface PluginSupervisorLogEntry {
|
|
34
7
|
level: "info" | "warn" | "error";
|
|
35
8
|
event: string;
|
|
@@ -40,121 +13,68 @@ export interface PluginSupervisorLogEntry {
|
|
|
40
13
|
signal?: NodeJS.Signals | null;
|
|
41
14
|
}
|
|
42
15
|
export interface PluginSupervisorOptions {
|
|
43
|
-
/**
|
|
44
|
-
* Trusted daemon-owned services. May be bound later because the composition
|
|
45
|
-
* root needs the static channel catalog before startServer constructs them.
|
|
46
|
-
*/
|
|
47
16
|
services?: PluginHostServices;
|
|
48
17
|
spawnRunner?: PluginRunnerSpawnFactory;
|
|
49
18
|
log?: (entry: PluginSupervisorLogEntry) => void;
|
|
50
|
-
/** Test knobs; production restart delay is always capped at 30 seconds. */
|
|
51
19
|
restartBaseMs?: number;
|
|
52
20
|
restartMaxMs?: number;
|
|
53
|
-
|
|
54
|
-
/** Test override. Production generates one identity per supervisor process lifetime. */
|
|
21
|
+
healthPollMs?: number;
|
|
55
22
|
daemonInstanceId?: string;
|
|
56
|
-
|
|
57
|
-
export interface PluginContributionRuntimeSnapshot {
|
|
58
|
-
key: string;
|
|
59
|
-
target: PluginContributionTarget;
|
|
60
|
-
desired: boolean;
|
|
61
|
-
generation?: number;
|
|
62
|
-
failureCount: number;
|
|
63
|
-
status: PluginContributionStatus;
|
|
64
|
-
}
|
|
65
|
-
export interface PluginRunnerRuntimeSnapshot {
|
|
66
|
-
state: "stopped" | "starting" | "running" | "backoff" | "failed";
|
|
67
|
-
generation: number;
|
|
68
|
-
failureCount: number;
|
|
69
|
-
lastError?: string;
|
|
23
|
+
verifyPackage?: (record: RunnablePluginRecord) => Promise<void>;
|
|
70
24
|
}
|
|
71
25
|
export interface PluginRuntimeStatusSnapshot {
|
|
72
|
-
capturedAt: string;
|
|
73
26
|
plugins: Array<{
|
|
74
27
|
pluginId: string;
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
28
|
+
generation: number;
|
|
29
|
+
state: PluginRuntimeState;
|
|
30
|
+
health?: PluginHealth;
|
|
31
|
+
error?: string;
|
|
32
|
+
settings: boolean;
|
|
78
33
|
}>;
|
|
79
34
|
}
|
|
80
35
|
/**
|
|
81
|
-
*
|
|
82
|
-
*
|
|
83
|
-
*
|
|
84
|
-
* There is at most one resident child per enabled plugin. Chat-channel
|
|
85
|
-
* instances are independent desired-state entries inside that child, so
|
|
86
|
-
* stopping the final channel does not tear down the plugin runtime itself.
|
|
36
|
+
* Supervises exactly one language-neutral runtime process per enabled plugin.
|
|
37
|
+
* It has no channel-instance API and never interprets plugin-owned state.
|
|
87
38
|
*/
|
|
88
39
|
export declare class PluginSupervisor {
|
|
89
40
|
private readonly states;
|
|
90
|
-
private
|
|
41
|
+
private readonly queues;
|
|
91
42
|
private readonly spawnRunner;
|
|
92
|
-
private readonly
|
|
43
|
+
private readonly log;
|
|
44
|
+
private readonly daemonInstanceId;
|
|
93
45
|
private readonly restartBaseMs;
|
|
94
46
|
private readonly restartMaxMs;
|
|
95
|
-
private readonly
|
|
96
|
-
private readonly
|
|
97
|
-
private
|
|
47
|
+
private readonly healthPollMs;
|
|
48
|
+
private readonly verifyPackage;
|
|
49
|
+
private services?;
|
|
98
50
|
private disposed;
|
|
99
|
-
constructor(
|
|
100
|
-
|
|
101
|
-
createChannelTypeDescriptors(): ChannelTypeDescriptor[];
|
|
102
|
-
/** Bind the trusted host once, after the server composition root constructs it. */
|
|
103
|
-
bindHostServices(services: PluginHostServices): this;
|
|
104
|
-
/** Cached, non-blocking runner/contribution health for the generic control API. */
|
|
105
|
-
statusSnapshot(): PluginRuntimeStatusSnapshot;
|
|
106
|
-
/** Start one resident runner for every enabled runtime plugin. */
|
|
51
|
+
constructor(records: readonly RunnablePluginRecord[], options?: PluginSupervisorOptions);
|
|
52
|
+
bindHostServices(services: PluginHostServices): void;
|
|
107
53
|
startPluginRuntimes(): Promise<void>;
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
*/
|
|
121
|
-
ensurePluginRuntime(record: RunnablePluginRecord, { readyTimeoutMs }?: {
|
|
122
|
-
readyTimeoutMs?: number;
|
|
123
|
-
}): Promise<PluginRuntimeStatus>;
|
|
124
|
-
private enqueueRuntimeOperation;
|
|
125
|
-
private performPluginRuntimeEnsure;
|
|
126
|
-
private performPluginRuntimeReload;
|
|
127
|
-
/** Permanently stop all children and cancel every pending automatic restart. */
|
|
54
|
+
ensurePluginRuntime(record: RunnablePluginRecord): Promise<PluginRuntimeState>;
|
|
55
|
+
/** Strict cutover: stop current generation, then start the supplied generation. */
|
|
56
|
+
reloadPluginRuntime(record: RunnablePluginRecord): Promise<PluginRuntimeState>;
|
|
57
|
+
stopPluginRuntime(identity: string): Promise<void>;
|
|
58
|
+
changeEnabled(record: PluginRecord, enabled: boolean, mutateRegistry: () => PluginRecord): Promise<PluginRuntimeState>;
|
|
59
|
+
cutoverInstallation(identity: string, commitRegistry: () => Promise<PluginRecord>): Promise<PluginRuntimeState>;
|
|
60
|
+
uninstallInstallation(identity: string, removeRegistry: () => Promise<boolean>): Promise<boolean>;
|
|
61
|
+
settingsCall(identity: string, expectedGeneration: string, method: string, params?: PluginJsonValue, options?: {
|
|
62
|
+
signal?: AbortSignal;
|
|
63
|
+
}): Promise<PluginJsonValue>;
|
|
64
|
+
supportsSettings(identity: string): boolean;
|
|
65
|
+
statusSnapshot(): PluginRuntimeStatusSnapshot;
|
|
128
66
|
dispose(): Promise<void>;
|
|
129
|
-
private
|
|
130
|
-
private
|
|
131
|
-
private
|
|
132
|
-
private
|
|
133
|
-
private
|
|
134
|
-
private
|
|
135
|
-
private
|
|
136
|
-
private
|
|
137
|
-
private refreshRuntimeStatus;
|
|
138
|
-
private waitForRuntimeReady;
|
|
139
|
-
private runtimeReadyTimeoutError;
|
|
140
|
-
private ensureRunner;
|
|
141
|
-
private spawnAndBind;
|
|
142
|
-
private trackRunnerExit;
|
|
143
|
-
private runnerExited;
|
|
144
|
-
private joinExitTransition;
|
|
67
|
+
private upsertState;
|
|
68
|
+
private startState;
|
|
69
|
+
private startSettingsState;
|
|
70
|
+
private stopSettingsState;
|
|
71
|
+
private handleSettingsExit;
|
|
72
|
+
private stopState;
|
|
73
|
+
private handleExit;
|
|
74
|
+
private failState;
|
|
145
75
|
private scheduleRestart;
|
|
146
|
-
private
|
|
147
|
-
private
|
|
148
|
-
private
|
|
149
|
-
private
|
|
150
|
-
private cancelRestart;
|
|
151
|
-
private markRunnerUnavailable;
|
|
152
|
-
private markContributionFailed;
|
|
153
|
-
private stderrSink;
|
|
154
|
-
private writeLog;
|
|
155
|
-
private assertOpen;
|
|
156
|
-
private assertReady;
|
|
157
|
-
private requireHostServices;
|
|
76
|
+
private scheduleHealthPoll;
|
|
77
|
+
private refreshHealth;
|
|
78
|
+
private failRunningState;
|
|
79
|
+
private runSerialized;
|
|
158
80
|
}
|
|
159
|
-
/** Convenience export for composition roots that only need the static catalog. */
|
|
160
|
-
export declare function createChannelTypeDescriptors(supervisor: PluginSupervisor): ChannelTypeDescriptor[];
|