@rho-workspace/rho 0.5.4 → 0.5.6
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/agent-connect.d.ts +8 -0
- package/dist/agent-connect.js +15 -0
- package/dist/browser-access.js +3 -2
- package/dist/capabilities.d.ts +2 -2
- package/dist/capabilities.js +6 -1
- package/dist/cli.js +219 -176
- package/dist/contract.generated.d.ts +472 -4
- package/dist/contract.generated.js +1 -1
- package/dist/contracts/owners.generated.js +455 -6
- package/dist/conversations.d.ts +157 -4
- package/dist/conversations.js +69 -6
- package/dist/discovery.d.ts +1 -0
- package/dist/discovery.js +3 -3
- package/dist/extension-contract.d.ts +99 -0
- package/dist/extension-contract.js +52 -0
- package/dist/extension-directory.d.ts +9 -0
- package/dist/extension-directory.js +11 -0
- package/dist/extension-worker.d.ts +1 -0
- package/dist/extension-worker.js +36 -0
- package/dist/extensions.d.ts +157 -0
- package/dist/extensions.js +349 -0
- package/dist/plugin-cli.d.ts +1 -0
- package/dist/plugin-cli.js +139 -0
- package/dist/plugin-inventory.json +18 -0
- package/dist/plugins.d.ts +3 -3
- package/dist/project-work.d.ts +3 -1
- package/dist/project-work.js +15 -2
- package/dist/protocol.d.ts +8 -0
- package/dist/protocol.js +16 -7
- package/dist/server.d.ts +5 -10
- package/dist/server.js +122 -12
- package/dist/web/.vite/manifest.json +67 -67
- package/dist/web/assets/{canvas-BXhC8RDZ.js → canvas-D8rDdfDz.js} +1 -1
- package/dist/web/assets/choices-D-YfnFP6.js +1 -0
- package/dist/web/assets/{console-Dbdo-5oO.js → console-Trqc0swD.js} +1 -1
- package/dist/web/assets/{dist-B2V0VDO0.js → dist-DZmszrjG.js} +2 -2
- package/dist/web/assets/dist-DpIHRk3B.js +1 -0
- package/dist/web/assets/{dist-D25Vn17i.js → dist-eMx6b8N1.js} +1 -1
- package/dist/web/assets/dist-pF902jHA.js +3 -0
- package/dist/web/assets/explore-in-BCHqjJ7B.js +1 -0
- package/dist/web/assets/graph-lENgfQNH.js +2 -0
- package/dist/web/assets/index-B3_OVy91.css +1 -0
- package/dist/web/assets/{index-BHQIaDsx.js → index-BpL_Kl_s.js} +87 -86
- package/dist/web/assets/{notes-meaning-DdPbtNzJ.js → notes-meaning-DcVGUBBY.js} +1 -1
- package/dist/web/assets/overview-CDnVKlOt.js +6 -0
- package/dist/web/assets/preview-BEC1E9MK.js +1 -0
- package/dist/web/assets/{review-CmWou4Iv.js → review-DYP0aCXb.js} +1 -1
- package/dist/web/assets/{skills-Dy7n3L9d.js → skills-1ec0Z-jx.js} +1 -1
- package/dist/web/assets/{skills-work-Cj0W6b-I.js → skills-work-DNexV4OJ.js} +1 -1
- package/dist/web/assets/{studio-process-QOY_n2_8.js → studio-process-EYQgikxq.js} +2 -2
- package/dist/web/assets/{timeline-events-DmX1BCh3.js → timeline-events-Chj2Gbx7.js} +1 -1
- package/dist/web/assets/{work-turns-Co0C71rJ.js → work-turns-CT9RVcWY.js} +1 -1
- package/dist/web/assets/workspace-COmCbGV3.js +5 -0
- package/dist/web/composition.json +65 -65
- package/dist/web/index.html +3 -3
- package/dist/web/renderer.json +1 -1
- package/dist/web-assets.d.ts +2 -1
- package/dist/web-assets.js +3 -2
- package/dist/work-contract.js +2 -2
- package/docs/FRONTEND.md +26 -18
- package/docs/HEADLESS.md +38 -28
- package/docs/PLUGIN-AUTHORING.md +4 -0
- package/docs/THIRD-PARTY-PLUGINS.md +190 -0
- package/node_modules/@rho-workspace/plugin-agent/README.md +68 -0
- package/node_modules/@rho-workspace/plugin-agent/dist/acp-command.d.ts +1 -0
- package/node_modules/@rho-workspace/plugin-agent/dist/acp-command.js +9 -1
- package/node_modules/@rho-workspace/plugin-agent/dist/acp-conversation.d.ts +1 -0
- package/node_modules/@rho-workspace/plugin-agent/dist/acp-conversation.js +10 -0
- package/node_modules/@rho-workspace/plugin-agent/dist/activity-normalize.d.ts +1 -0
- package/node_modules/@rho-workspace/plugin-agent/dist/activity-normalize.js +2 -2
- package/node_modules/@rho-workspace/plugin-agent/dist/dsh-session.d.ts +6 -0
- package/node_modules/@rho-workspace/plugin-agent/dist/dsh-session.js +174 -0
- package/node_modules/@rho-workspace/plugin-agent/dist/external-session-contract.d.ts +82 -0
- package/node_modules/@rho-workspace/plugin-agent/dist/external-session-contract.js +20 -0
- package/node_modules/@rho-workspace/plugin-agent/dist/external-session.d.ts +84 -0
- package/node_modules/@rho-workspace/plugin-agent/dist/external-session.js +190 -0
- package/node_modules/@rho-workspace/plugin-agent/dist/index.d.ts +373 -0
- package/node_modules/@rho-workspace/plugin-agent/dist/index.js +1 -0
- package/node_modules/@rho-workspace/plugin-agent/dist/native-sessions.d.ts +70 -0
- package/node_modules/@rho-workspace/plugin-agent/dist/native-sessions.js +538 -0
- package/node_modules/@rho-workspace/plugin-agent/dist/operations.d.ts +33 -0
- package/node_modules/@rho-workspace/plugin-agent/dist/operations.js +3 -0
- package/node_modules/@rho-workspace/plugin-agent/dist/presentation.d.ts +14 -0
- package/node_modules/@rho-workspace/plugin-agent/dist/presentation.js +2 -0
- package/node_modules/@rho-workspace/plugin-agent/dist/ui-external-session.d.ts +15 -0
- package/node_modules/@rho-workspace/plugin-agent/dist/ui-external-session.js +37 -0
- package/node_modules/@rho-workspace/plugin-agent/package.json +6 -1
- package/node_modules/hono/dist/adapter/aws-lambda/handler.js +1 -1
- package/node_modules/hono/dist/cjs/adapter/aws-lambda/handler.js +1 -1
- package/node_modules/hono/dist/cjs/adapter/bun/serve-static.js +1 -1
- package/node_modules/hono/dist/cjs/adapter/bun/websocket.js +1 -1
- package/node_modules/hono/dist/cjs/client/fetch-result-please.js +1 -1
- package/node_modules/hono/dist/cjs/helper/accepts/accepts.js +2 -1
- package/node_modules/hono/dist/cjs/helper/ssg/ssg.js +5 -3
- package/node_modules/hono/dist/cjs/jsx/base.js +49 -30
- package/node_modules/hono/dist/cjs/jsx/components.js +2 -2
- package/node_modules/hono/dist/cjs/jsx/constants.js +2 -0
- package/node_modules/hono/dist/cjs/jsx/jsx-runtime.js +13 -17
- package/node_modules/hono/dist/cjs/middleware/etag/index.js +3 -1
- package/node_modules/hono/dist/cjs/middleware/pretty-json/index.js +1 -0
- package/node_modules/hono/dist/cjs/middleware/timing/timing.js +4 -3
- package/node_modules/hono/dist/cjs/utils/cookie.js +2 -2
- package/node_modules/hono/dist/cjs/utils/mime.js +1 -1
- package/node_modules/hono/dist/cjs/utils/url.js +1 -1
- package/node_modules/hono/dist/client/fetch-result-please.js +1 -1
- package/node_modules/hono/dist/helper/accepts/accepts.js +2 -1
- package/node_modules/hono/dist/helper/ssg/ssg.js +5 -3
- package/node_modules/hono/dist/jsx/base.js +49 -32
- package/node_modules/hono/dist/jsx/components.js +2 -2
- package/node_modules/hono/dist/jsx/constants.js +2 -1
- package/node_modules/hono/dist/jsx/jsx-runtime.js +15 -19
- package/node_modules/hono/dist/middleware/etag/index.js +3 -1
- package/node_modules/hono/dist/middleware/language/language.js +1 -1
- package/node_modules/hono/dist/middleware/pretty-json/index.js +1 -0
- package/node_modules/hono/dist/middleware/timing/timing.js +4 -3
- package/node_modules/hono/dist/utils/cookie.js +2 -2
- package/node_modules/hono/dist/utils/mime.js +1 -1
- package/node_modules/hono/dist/utils/url.js +1 -1
- package/node_modules/hono/package.json +1 -1
- package/package.json +5 -3
- package/protocol/index.json +93 -33
- package/protocol/operations/agent.sessions.list.json +146 -0
- package/protocol/operations/agent.sessions.read.json +315 -0
- package/protocol/operations/conversation.configure.json +29 -0
- package/protocol/operations/conversation.decide.json +29 -0
- package/protocol/operations/conversation.list.json +29 -0
- package/protocol/operations/conversation.permission.json +29 -0
- package/protocol/operations/conversation.read.json +29 -0
- package/protocol/operations/conversation.restore.json +29 -0
- package/protocol/operations/conversation.send.json +29 -0
- package/protocol/operations/conversation.settings.check.json +92 -0
- package/protocol/operations/conversation.settings.read.json +92 -0
- package/protocol/operations/conversation.settings.update.json +92 -0
- package/protocol/operations/conversation.start.json +46 -1
- package/protocol/operations/conversation.stop.json +29 -0
- package/protocol/operations/conversation.trash.json +29 -0
- package/protocol/operations/extension.call.json +132 -0
- package/protocol/operations/extension.content.json +78 -0
- package/protocol/operations/extension.describe.json +195 -0
- package/protocol/operations/extension.install.json +198 -0
- package/protocol/operations/extension.list.json +123 -0
- package/protocol/operations/extension.manage.json +55 -0
- package/protocol/operations/extension.read.json +112 -0
- package/protocol/operations/observation.snapshot.json +29 -0
- package/protocol/operations/project.work.read.json +3 -2
- package/protocol/operations/session.grant.json +9 -0
- package/protocol/operations/session.instructions.json +43 -0
- package/scripts/third-party-acceptance.mjs +77 -0
- package/vendor/composition.json +83 -83
- package/vendor/rho-workspace-plugin-agent-0.4.30.tgz +0 -0
- package/web/theme.css +12 -0
- package/dist/web/assets/choices-DU9kHlyQ.js +0 -1
- package/dist/web/assets/dist-BV3hWfn_.js +0 -3
- package/dist/web/assets/dist-CLNF2g-E.js +0 -1
- package/dist/web/assets/explore-in-8Q5ftt-E.js +0 -1
- package/dist/web/assets/graph-hS2kvHTI.js +0 -2
- package/dist/web/assets/index-Cj1_iqyK.css +0 -1
- package/dist/web/assets/overview-BV6ZO5TO.js +0 -6
- package/dist/web/assets/preview-n5lOOdjN.js +0 -1
- package/dist/web/assets/workspace-BKFefRfJ.js +0 -5
- package/vendor/rho-workspace-plugin-agent-0.4.28.tgz +0 -0
package/dist/conversations.d.ts
CHANGED
|
@@ -165,6 +165,22 @@ export interface ConversationPorts {
|
|
|
165
165
|
listed: string;
|
|
166
166
|
} | null>;
|
|
167
167
|
notebook?(): boolean;
|
|
168
|
+
nativeSession?(project: Project, producer: 'claude-code' | 'codex', sessionId: string): Promise<{
|
|
169
|
+
open: {
|
|
170
|
+
where: string;
|
|
171
|
+
since?: string;
|
|
172
|
+
pid?: number;
|
|
173
|
+
} | null;
|
|
174
|
+
lastAt: string;
|
|
175
|
+
} | null>;
|
|
176
|
+
}
|
|
177
|
+
export interface ContinueSession {
|
|
178
|
+
producer: 'claude-code' | 'codex' | 'dsh';
|
|
179
|
+
sessionId: string;
|
|
180
|
+
title: string;
|
|
181
|
+
where: string;
|
|
182
|
+
copy: boolean;
|
|
183
|
+
backend: 'claude-acp' | 'codex-acp' | 'acp';
|
|
168
184
|
}
|
|
169
185
|
export interface DescribeRequest {
|
|
170
186
|
path: string;
|
|
@@ -256,6 +272,11 @@ export declare class Conversations {
|
|
|
256
272
|
costUsd?: number | null;
|
|
257
273
|
sessionId?: string | null;
|
|
258
274
|
trashedAt?: string | null;
|
|
275
|
+
origin?: {
|
|
276
|
+
producer: string;
|
|
277
|
+
where: string;
|
|
278
|
+
copyOf?: string;
|
|
279
|
+
} | null;
|
|
259
280
|
}[]>;
|
|
260
281
|
private relist;
|
|
261
282
|
reviewEvidence(project: Project, annotationId: string): Promise<{
|
|
@@ -319,6 +340,11 @@ export declare class Conversations {
|
|
|
319
340
|
costUsd?: number | null;
|
|
320
341
|
sessionId?: string | null;
|
|
321
342
|
trashedAt?: string | null;
|
|
343
|
+
origin?: {
|
|
344
|
+
producer: string;
|
|
345
|
+
where: string;
|
|
346
|
+
copyOf?: string;
|
|
347
|
+
} | null;
|
|
322
348
|
};
|
|
323
349
|
}>;
|
|
324
350
|
restore(project: Project, input: {
|
|
@@ -356,6 +382,11 @@ export declare class Conversations {
|
|
|
356
382
|
costUsd?: number | null;
|
|
357
383
|
sessionId?: string | null;
|
|
358
384
|
trashedAt?: string | null;
|
|
385
|
+
origin?: {
|
|
386
|
+
producer: string;
|
|
387
|
+
where: string;
|
|
388
|
+
copyOf?: string;
|
|
389
|
+
} | null;
|
|
359
390
|
};
|
|
360
391
|
}>;
|
|
361
392
|
delete(project: Project, by: string, input: {
|
|
@@ -401,6 +432,11 @@ export declare class Conversations {
|
|
|
401
432
|
costUsd?: number | null;
|
|
402
433
|
sessionId?: string | null;
|
|
403
434
|
trashedAt?: string | null;
|
|
435
|
+
origin?: {
|
|
436
|
+
producer: string;
|
|
437
|
+
where: string;
|
|
438
|
+
copyOf?: string;
|
|
439
|
+
} | null;
|
|
404
440
|
};
|
|
405
441
|
observation: SessionObservation | null;
|
|
406
442
|
config: Choices;
|
|
@@ -410,7 +446,7 @@ export declare class Conversations {
|
|
|
410
446
|
private sessionObservation;
|
|
411
447
|
work(project: Project, limit?: number): Promise<{
|
|
412
448
|
sessions: {
|
|
413
|
-
backend: "acp" | "
|
|
449
|
+
backend: "claude-acp" | "codex-acp" | "acp" | "claude-cli";
|
|
414
450
|
sessionId: string | null;
|
|
415
451
|
observation: SessionObservation | null;
|
|
416
452
|
state: string;
|
|
@@ -442,6 +478,11 @@ export declare class Conversations {
|
|
|
442
478
|
} | null;
|
|
443
479
|
costUsd?: number | null;
|
|
444
480
|
trashedAt?: string | null;
|
|
481
|
+
origin?: {
|
|
482
|
+
producer: string;
|
|
483
|
+
where: string;
|
|
484
|
+
copyOf?: string;
|
|
485
|
+
} | null;
|
|
445
486
|
}[];
|
|
446
487
|
omitted: number;
|
|
447
488
|
}>;
|
|
@@ -451,6 +492,7 @@ export declare class Conversations {
|
|
|
451
492
|
contexts?: string[];
|
|
452
493
|
backend?: Backend;
|
|
453
494
|
config?: Choices;
|
|
495
|
+
continue?: ContinueSession;
|
|
454
496
|
}): Promise<{
|
|
455
497
|
conversation: {
|
|
456
498
|
state: string;
|
|
@@ -484,9 +526,18 @@ export declare class Conversations {
|
|
|
484
526
|
costUsd?: number | null;
|
|
485
527
|
sessionId?: string | null;
|
|
486
528
|
trashedAt?: string | null;
|
|
529
|
+
origin?: {
|
|
530
|
+
producer: string;
|
|
531
|
+
where: string;
|
|
532
|
+
copyOf?: string;
|
|
533
|
+
} | null;
|
|
487
534
|
};
|
|
488
535
|
turn: Turn;
|
|
489
536
|
}>;
|
|
537
|
+
/** Whether a process holding a session open is Rho's own connection to this conversation: the
|
|
538
|
+
* Agent its adapter started. */
|
|
539
|
+
owns(project: Project, conversationId: string, pid: number | undefined): Promise<boolean>;
|
|
540
|
+
private notHeld;
|
|
490
541
|
send(project: Project, by: string, input: {
|
|
491
542
|
conversationId: string;
|
|
492
543
|
changeId: string;
|
|
@@ -526,6 +577,11 @@ export declare class Conversations {
|
|
|
526
577
|
costUsd?: number | null;
|
|
527
578
|
sessionId?: string | null;
|
|
528
579
|
trashedAt?: string | null;
|
|
580
|
+
origin?: {
|
|
581
|
+
producer: string;
|
|
582
|
+
where: string;
|
|
583
|
+
copyOf?: string;
|
|
584
|
+
} | null;
|
|
529
585
|
};
|
|
530
586
|
turn: Turn;
|
|
531
587
|
}>;
|
|
@@ -566,6 +622,11 @@ export declare class Conversations {
|
|
|
566
622
|
costUsd?: number | null;
|
|
567
623
|
sessionId?: string | null;
|
|
568
624
|
trashedAt?: string | null;
|
|
625
|
+
origin?: {
|
|
626
|
+
producer: string;
|
|
627
|
+
where: string;
|
|
628
|
+
copyOf?: string;
|
|
629
|
+
} | null;
|
|
569
630
|
};
|
|
570
631
|
observation: SessionObservation | null;
|
|
571
632
|
config: Choices;
|
|
@@ -574,17 +635,43 @@ export declare class Conversations {
|
|
|
574
635
|
private offers;
|
|
575
636
|
private readSettings;
|
|
576
637
|
private settingsView;
|
|
638
|
+
private agents;
|
|
577
639
|
settings(): Promise<{
|
|
578
640
|
version: number;
|
|
579
641
|
updatedAt: string | null;
|
|
580
642
|
backend: Backend | null;
|
|
581
|
-
serviceBackend: "acp" | "
|
|
643
|
+
serviceBackend: "claude-acp" | "codex-acp" | "acp" | "claude-cli";
|
|
582
644
|
choices: Partial<Record<Backend, Choices>>;
|
|
583
645
|
offered: Partial<Record<Backend, Offered>>;
|
|
584
646
|
checking: Backend[];
|
|
585
647
|
describe: {
|
|
586
648
|
enabled: boolean;
|
|
587
649
|
};
|
|
650
|
+
agents: {
|
|
651
|
+
'claude-acp': {
|
|
652
|
+
found: boolean;
|
|
653
|
+
problem: string;
|
|
654
|
+
} | {
|
|
655
|
+
found: boolean;
|
|
656
|
+
problem?: undefined;
|
|
657
|
+
};
|
|
658
|
+
'codex-acp': {
|
|
659
|
+
found: boolean;
|
|
660
|
+
problem: string;
|
|
661
|
+
} | {
|
|
662
|
+
found: boolean;
|
|
663
|
+
problem?: undefined;
|
|
664
|
+
};
|
|
665
|
+
acp: {
|
|
666
|
+
found: boolean;
|
|
667
|
+
name: string | null;
|
|
668
|
+
problem?: undefined;
|
|
669
|
+
} | {
|
|
670
|
+
found: boolean;
|
|
671
|
+
problem: string;
|
|
672
|
+
name?: undefined;
|
|
673
|
+
};
|
|
674
|
+
};
|
|
588
675
|
}>;
|
|
589
676
|
updateSettings(input: {
|
|
590
677
|
expectedVersion: number;
|
|
@@ -597,13 +684,38 @@ export declare class Conversations {
|
|
|
597
684
|
version: number;
|
|
598
685
|
updatedAt: string | null;
|
|
599
686
|
backend: Backend | null;
|
|
600
|
-
serviceBackend: "acp" | "
|
|
687
|
+
serviceBackend: "claude-acp" | "codex-acp" | "acp" | "claude-cli";
|
|
601
688
|
choices: Partial<Record<Backend, Choices>>;
|
|
602
689
|
offered: Partial<Record<Backend, Offered>>;
|
|
603
690
|
checking: Backend[];
|
|
604
691
|
describe: {
|
|
605
692
|
enabled: boolean;
|
|
606
693
|
};
|
|
694
|
+
agents: {
|
|
695
|
+
'claude-acp': {
|
|
696
|
+
found: boolean;
|
|
697
|
+
problem: string;
|
|
698
|
+
} | {
|
|
699
|
+
found: boolean;
|
|
700
|
+
problem?: undefined;
|
|
701
|
+
};
|
|
702
|
+
'codex-acp': {
|
|
703
|
+
found: boolean;
|
|
704
|
+
problem: string;
|
|
705
|
+
} | {
|
|
706
|
+
found: boolean;
|
|
707
|
+
problem?: undefined;
|
|
708
|
+
};
|
|
709
|
+
acp: {
|
|
710
|
+
found: boolean;
|
|
711
|
+
name: string | null;
|
|
712
|
+
problem?: undefined;
|
|
713
|
+
} | {
|
|
714
|
+
found: boolean;
|
|
715
|
+
problem: string;
|
|
716
|
+
name?: undefined;
|
|
717
|
+
};
|
|
718
|
+
};
|
|
607
719
|
}>;
|
|
608
720
|
check(project: Project, input: {
|
|
609
721
|
backend: Backend;
|
|
@@ -611,13 +723,38 @@ export declare class Conversations {
|
|
|
611
723
|
version: number;
|
|
612
724
|
updatedAt: string | null;
|
|
613
725
|
backend: Backend | null;
|
|
614
|
-
serviceBackend: "acp" | "
|
|
726
|
+
serviceBackend: "claude-acp" | "codex-acp" | "acp" | "claude-cli";
|
|
615
727
|
choices: Partial<Record<Backend, Choices>>;
|
|
616
728
|
offered: Partial<Record<Backend, Offered>>;
|
|
617
729
|
checking: Backend[];
|
|
618
730
|
describe: {
|
|
619
731
|
enabled: boolean;
|
|
620
732
|
};
|
|
733
|
+
agents: {
|
|
734
|
+
'claude-acp': {
|
|
735
|
+
found: boolean;
|
|
736
|
+
problem: string;
|
|
737
|
+
} | {
|
|
738
|
+
found: boolean;
|
|
739
|
+
problem?: undefined;
|
|
740
|
+
};
|
|
741
|
+
'codex-acp': {
|
|
742
|
+
found: boolean;
|
|
743
|
+
problem: string;
|
|
744
|
+
} | {
|
|
745
|
+
found: boolean;
|
|
746
|
+
problem?: undefined;
|
|
747
|
+
};
|
|
748
|
+
acp: {
|
|
749
|
+
found: boolean;
|
|
750
|
+
name: string | null;
|
|
751
|
+
problem?: undefined;
|
|
752
|
+
} | {
|
|
753
|
+
found: boolean;
|
|
754
|
+
problem: string;
|
|
755
|
+
name?: undefined;
|
|
756
|
+
};
|
|
757
|
+
};
|
|
621
758
|
}>;
|
|
622
759
|
private inspect;
|
|
623
760
|
private offer;
|
|
@@ -657,6 +794,11 @@ export declare class Conversations {
|
|
|
657
794
|
costUsd?: number | null;
|
|
658
795
|
sessionId?: string | null;
|
|
659
796
|
trashedAt?: string | null;
|
|
797
|
+
origin?: {
|
|
798
|
+
producer: string;
|
|
799
|
+
where: string;
|
|
800
|
+
copyOf?: string;
|
|
801
|
+
} | null;
|
|
660
802
|
};
|
|
661
803
|
turn: Turn;
|
|
662
804
|
}>;
|
|
@@ -699,6 +841,11 @@ export declare class Conversations {
|
|
|
699
841
|
costUsd?: number | null;
|
|
700
842
|
sessionId?: string | null;
|
|
701
843
|
trashedAt?: string | null;
|
|
844
|
+
origin?: {
|
|
845
|
+
producer: string;
|
|
846
|
+
where: string;
|
|
847
|
+
copyOf?: string;
|
|
848
|
+
} | null;
|
|
702
849
|
};
|
|
703
850
|
turn: Turn;
|
|
704
851
|
}>;
|
|
@@ -740,6 +887,11 @@ export declare class Conversations {
|
|
|
740
887
|
costUsd?: number | null;
|
|
741
888
|
sessionId?: string | null;
|
|
742
889
|
trashedAt?: string | null;
|
|
890
|
+
origin?: {
|
|
891
|
+
producer: string;
|
|
892
|
+
where: string;
|
|
893
|
+
copyOf?: string;
|
|
894
|
+
} | null;
|
|
743
895
|
};
|
|
744
896
|
turn: Turn;
|
|
745
897
|
}>;
|
|
@@ -747,6 +899,7 @@ export declare class Conversations {
|
|
|
747
899
|
private retire;
|
|
748
900
|
private cancelPermissions;
|
|
749
901
|
private launch;
|
|
902
|
+
private changedElsewhere;
|
|
750
903
|
private driver;
|
|
751
904
|
private capture;
|
|
752
905
|
private observe;
|
package/dist/conversations.js
CHANGED
|
@@ -8,6 +8,7 @@ import path from 'node:path';
|
|
|
8
8
|
import { createHash, randomBytes, randomUUID } from 'node:crypto';
|
|
9
9
|
import { fileURLToPath } from 'node:url';
|
|
10
10
|
import { atomicJson, canonical, digest, Fault, now, readJson, requireThat } from '@rho-workspace/plugin-contracts';
|
|
11
|
+
import { acpEnvironment, missingClient } from '@rho-workspace/plugin-agent/acp-command';
|
|
11
12
|
// Rho holds user messages and their original identities. The selected Agent plugin
|
|
12
13
|
// owns the connection, native session and protocol. Reads never start a driver.
|
|
13
14
|
// A new Claude Code session opens in Manual mode unless the person's Claude settings name another.
|
|
@@ -234,7 +235,8 @@ export class Conversations {
|
|
|
234
235
|
return { conversationId: c.id, changeId: c.changeId, requestDigest: c.requestDigest, title: c.title, client: c.client, principal: c.principal, createdAt: c.createdAt, updatedAt: c.updatedAt, version: c.version, turns: c.turns.length, state: last?.state ?? 'idle', lastAt: last?.endedAt ?? last?.sentAt ?? c.createdAt,
|
|
235
236
|
listed: 2, turnLimit: !!last && agentTurnLimit(last), waitingPermission: last?.state === 'running' && !!last.permissions?.some(p => p.state === 'pending'), backend: c.backend ?? 'claude-cli', agentTitle: c.observation?.info?.title ?? null, adapter: c.adapter ?? null, model: [...c.turns].reverse().find(t => t.model)?.model ?? null, config: c.config ?? {},
|
|
236
237
|
usage: usage ? { used: usage.used, size: usage.size, cost: usage.cost ?? null } : null, costUsd: costs.length ? costs.reduce((a, b) => a + b, 0) : null,
|
|
237
|
-
sessionId: c.acpSessionId ?? c.nativeSessionId ?? null, trashedAt: c.trashedAt ?? null
|
|
238
|
+
sessionId: c.acpSessionId ?? c.nativeSessionId ?? null, trashedAt: c.trashedAt ?? null,
|
|
239
|
+
origin: c.origin ? { producer: c.origin.producer, where: c.origin.where, ...(c.origin.copy ? { copyOf: c.origin.sessionId } : {}) } : null };
|
|
238
240
|
}
|
|
239
241
|
async write(project, c) {
|
|
240
242
|
const directory = await this.folder(project);
|
|
@@ -394,7 +396,9 @@ export class Conversations {
|
|
|
394
396
|
requireThat(!input.backend || backends.includes(input.backend), 'invalid', 'Choose Claude Code or Codex.');
|
|
395
397
|
if (input.config)
|
|
396
398
|
this.choices(input.config);
|
|
397
|
-
const
|
|
399
|
+
const from = input.continue;
|
|
400
|
+
const text = this.message(input.text), requestDigest = digest(canonical({ text, ...(input.contexts?.length ? { contexts: input.contexts } : {}), ...(input.backend ? { backend: input.backend } : {}), ...(input.config ? { config: input.config } : {}),
|
|
401
|
+
...(from ? { continue: { producer: from.producer, sessionId: from.sessionId, copy: from.copy } } : {}) }));
|
|
398
402
|
return this.serial(project.id, async () => {
|
|
399
403
|
const index = await this.index(project), existing = index.conversations.find(x => x.changeId === input.changeId);
|
|
400
404
|
requireThat(!index.deleted?.some(x => x.changeId === input.changeId), 'conflict', 'That request started a conversation that was later deleted. It is not started again.');
|
|
@@ -404,13 +408,26 @@ export class Conversations {
|
|
|
404
408
|
return this.reply(project, c, c.turns[0]);
|
|
405
409
|
}
|
|
406
410
|
requireThat(index.conversations.filter(x => !x.trashedAt).length < this.limits.maxConversations, 'limit', `This project keeps at most ${this.limits.maxConversations} conversations started in Rho. Move one to the trash to start another.`, { limit: 'maxConversations', maximum: this.limits.maxConversations });
|
|
411
|
+
if (from && !from.copy) {
|
|
412
|
+
const already = index.conversations.find(x => x.sessionId === from.sessionId);
|
|
413
|
+
requireThat(!already, 'conflict', already?.trashedAt ? 'This session is a conversation in the trash. Restore it to continue.' : 'This session already continues as a conversation here. Open it to send your message.');
|
|
414
|
+
await this.notHeld(project, from.producer, from.sessionId, false);
|
|
415
|
+
}
|
|
407
416
|
this.capacity();
|
|
408
417
|
const saved = await this.readSettings();
|
|
409
|
-
const backend = input.backend ?? saved.backend ?? this.config.backend ?? 'claude-acp';
|
|
418
|
+
const backend = from?.backend ?? input.backend ?? saved.backend ?? this.config.backend ?? 'claude-acp';
|
|
410
419
|
const config = backend === 'claude-cli' ? undefined : input.config ?? saved.choices[backend];
|
|
411
420
|
const at = now(), c = { format: 2, backend, id: 'c-' + randomBytes(8).toString('hex'), changeId: input.changeId, requestDigest, createdAt: at, createdBy: by, updatedAt: at, version: 0, client: backend === 'codex-acp' ? 'codex' : backend === 'acp' ? 'acp' : 'claude-code', nativeSessionId: backend === 'claude-cli' ? randomUUID() : null, confirmed: false, principal: null, title: titleOf(text), turns: [], ...(config && Object.keys(config).length ? { config } : {}) };
|
|
412
421
|
for (const id of input.contexts ?? [])
|
|
413
422
|
await this.ports.context?.(project, id);
|
|
423
|
+
if (from) {
|
|
424
|
+
c.origin = { producer: from.producer, sessionId: from.sessionId, where: from.where, copy: from.copy };
|
|
425
|
+
if (from.copy)
|
|
426
|
+
c.forkFrom = from.sessionId;
|
|
427
|
+
else
|
|
428
|
+
c.acpSessionId = from.sessionId;
|
|
429
|
+
c.title = from.title;
|
|
430
|
+
}
|
|
414
431
|
const turn = this.turn(input.changeId, requestDigest, by, text, 1);
|
|
415
432
|
if (input.contexts?.length)
|
|
416
433
|
turn.contexts = [...input.contexts];
|
|
@@ -421,6 +438,29 @@ export class Conversations {
|
|
|
421
438
|
return this.reply(project, c, turn);
|
|
422
439
|
});
|
|
423
440
|
}
|
|
441
|
+
/** Whether a process holding a session open is Rho's own connection to this conversation: the
|
|
442
|
+
* Agent its adapter started. */
|
|
443
|
+
async owns(project, conversationId, pid) {
|
|
444
|
+
const adapter = this.drivers.get(project.id + '/' + conversationId)?.driver?.pid;
|
|
445
|
+
if (!adapter || !pid || process.platform === 'win32')
|
|
446
|
+
return false;
|
|
447
|
+
const { execFile } = await import('node:child_process');
|
|
448
|
+
let current = pid;
|
|
449
|
+
for (let depth = 0; depth < 4 && current > 1; depth++) {
|
|
450
|
+
const parent = await new Promise(resolve => execFile('ps', ['-o', 'ppid=', '-p', String(current)], { timeout: 2000 }, (error, out) => resolve(error ? 0 : Number(String(out).trim()))));
|
|
451
|
+
if (parent === adapter)
|
|
452
|
+
return true;
|
|
453
|
+
current = parent;
|
|
454
|
+
}
|
|
455
|
+
return false;
|
|
456
|
+
}
|
|
457
|
+
async notHeld(project, producer, sessionId, existing, conversationId) {
|
|
458
|
+
if (producer !== 'claude-code' && producer !== 'codex')
|
|
459
|
+
return;
|
|
460
|
+
const found = await this.ports.nativeSession?.(project, producer, sessionId) ?? null;
|
|
461
|
+
const holder = found?.open && !(conversationId && await this.owns(project, conversationId, found.open.pid)) ? found.open : null;
|
|
462
|
+
requireThat(!holder, 'condition', `This session is open in ${holder?.where ?? 'another window'}. Close it there to continue here${existing ? '' : ', or continue a copy'}. Nothing was sent.`, { heldBy: holder?.where ?? null });
|
|
463
|
+
}
|
|
424
464
|
async send(project, by, input) {
|
|
425
465
|
const text = this.message(input.text), requestDigest = digest(canonical({ text, ...(input.contexts?.length ? { contexts: input.contexts } : {}), ...(input.continuationOf ? { continuationOf: input.continuationOf } : {}) }));
|
|
426
466
|
return this.serial(project.id, async () => {
|
|
@@ -444,6 +484,9 @@ export class Conversations {
|
|
|
444
484
|
requireThat(!alive, 'conflict', `The Agent from before Rho restarted may still be answering (process ${last.pid}). End that process before sending another message.`);
|
|
445
485
|
}
|
|
446
486
|
requireThat(c.turns.length < this.limits.maxTurns, 'limit', `A conversation keeps at most ${this.limits.maxTurns} messages. Start a new conversation.`, { limit: 'maxTurns', maximum: this.limits.maxTurns });
|
|
487
|
+
// A session continued in a terminal or another app may be open there now.
|
|
488
|
+
if (c.acpSessionId && (c.client === 'claude-code' || c.client === 'codex'))
|
|
489
|
+
await this.notHeld(project, c.client, c.acpSessionId, true, c.id);
|
|
447
490
|
requireThat(Buffer.byteLength(JSON.stringify({ ...c, observation: undefined })) + this.limits.maxObservationBytes + this.limits.maxTurnBytes + this.limits.maxMessageBytes <= this.limits.maxRecordBytes, 'limit', 'This conversation has reached the size Rho keeps. Start a new conversation.', { limit: 'maxRecordBytes', maximum: this.limits.maxRecordBytes });
|
|
448
491
|
this.capacity();
|
|
449
492
|
for (const old of c.turns)
|
|
@@ -510,7 +553,19 @@ export class Conversations {
|
|
|
510
553
|
}
|
|
511
554
|
settingsView(s) {
|
|
512
555
|
const service = this.config.backend ?? 'claude-acp';
|
|
513
|
-
return { version: s.version, updatedAt: s.updatedAt, backend: s.backend, serviceBackend: service, choices: s.choices, offered: s.offered, checking: [...this.checks.keys()], describe: { enabled: s.describe?.enabled !== false } };
|
|
556
|
+
return { version: s.version, updatedAt: s.updatedAt, backend: s.backend, serviceBackend: service, choices: s.choices, offered: s.offered, checking: [...this.checks.keys()], describe: { enabled: s.describe?.enabled !== false }, agents: this.agents() };
|
|
557
|
+
}
|
|
558
|
+
// Which Agents this service can start: the person's installed clients, found as the adapters
|
|
559
|
+
// find them, and an ACP command the person named. Looking starts nothing.
|
|
560
|
+
agents() {
|
|
561
|
+
const found = (problem) => problem ? { found: false, problem } : { found: true };
|
|
562
|
+
const command = this.config.acpCommand;
|
|
563
|
+
return {
|
|
564
|
+
// A command the embedding names is its own choice and is not looked for, as the adapters do.
|
|
565
|
+
'claude-acp': found(this.config.claudeAcp?.command ? null : missingClient('claude', acpEnvironment('claude', { ...process.env }, this.binary))),
|
|
566
|
+
'codex-acp': found(this.config.codexAcp?.command ? null : missingClient('codex', acpEnvironment('codex', { ...process.env }, this.config.codex))),
|
|
567
|
+
acp: command ? { found: true, name: /(^|[\\/])dsh(\.[a-z]+)?$/i.test(command.file) || command.args.some(a => /(^|[\\/])dsh(\.[a-z]+)?$/i.test(a)) ? 'DeepSeek Harness' : null } : { found: false, problem: 'Start Rho with --agent-backend acp --acp-command to use another ACP Agent.' }
|
|
568
|
+
};
|
|
514
569
|
}
|
|
515
570
|
async settings() { return this.settingsView(await this.readSettings()); }
|
|
516
571
|
// The person's Agent and settings for new conversations. Each Agent's choices are replaced as a
|
|
@@ -733,12 +788,20 @@ export class Conversations {
|
|
|
733
788
|
}
|
|
734
789
|
});
|
|
735
790
|
}
|
|
791
|
+
async changedElsewhere(project, c) {
|
|
792
|
+
if (!c.acpSessionId || (c.client !== 'claude-code' && c.client !== 'codex'))
|
|
793
|
+
return false;
|
|
794
|
+
const previous = c.turns.at(-2), found = await this.ports.nativeSession?.(project, c.client, c.acpSessionId).catch(() => null);
|
|
795
|
+
return !!found && !!previous?.endedAt && Date.parse(found.lastAt) > Date.parse(previous.endedAt) + 5000;
|
|
796
|
+
}
|
|
736
797
|
async driver(project, c) {
|
|
737
798
|
return this.serial('driver-pool', async () => {
|
|
738
799
|
const key = project.id + '/' + c.id, old = this.drivers.get(key);
|
|
739
800
|
if (old?.timer)
|
|
740
801
|
clearTimeout(old.timer);
|
|
741
|
-
|
|
802
|
+
// An open connection keeps the session as it last saw it. When the session went on in
|
|
803
|
+
// another window since, it is opened again from the Agent's own record.
|
|
804
|
+
if (old?.driver.connected && !await this.changedElsewhere(project, c))
|
|
742
805
|
return old.driver;
|
|
743
806
|
if (old)
|
|
744
807
|
await this.retire(key);
|
|
@@ -770,7 +833,7 @@ export class Conversations {
|
|
|
770
833
|
} };
|
|
771
834
|
// Every session started here is told about the project's shared notes and its section.
|
|
772
835
|
const instructions = notesInstructions(c.id, { notebook: !!this.ports.notebook?.() });
|
|
773
|
-
const common = { cwd: project.root, mcpServers, limits: this.limits, sessionId: c.acpSessionId, config: c.config, instructions, ...observed };
|
|
836
|
+
const common = { cwd: project.root, mcpServers, limits: this.limits, sessionId: c.acpSessionId, ...(!c.acpSessionId && c.forkFrom ? { forkFrom: c.forkFrom } : {}), config: c.config, instructions, ...observed };
|
|
774
837
|
const driver = c.backend === 'codex-acp'
|
|
775
838
|
? new CodexAcpConversation({ ...this.config.codexAcp, ...common, codex: this.config.codex })
|
|
776
839
|
: c.backend === 'claude-acp'
|
package/dist/discovery.d.ts
CHANGED
package/dist/discovery.js
CHANGED
|
@@ -3,11 +3,11 @@ import { Capabilities, rhoWorkspaceSkill } from './capabilities.js';
|
|
|
3
3
|
import { protocol } from './protocol.js';
|
|
4
4
|
import { schemaClosure } from './protocol-discovery.js';
|
|
5
5
|
const size = (v) => Buffer.byteLength(JSON.stringify(v)) + 64;
|
|
6
|
-
const applicationEffects = Object.fromEntries([
|
|
7
|
-
...['protocol.describe', 'protocol.validate', 'project.entries', 'capability.list', 'skill.list', 'skill.read', 'action.lookup', 'action.observe', 'action.output', 'action.list', 'composition.read', 'observation.snapshot', 'interaction.selection.read', 'workspace.observe', 'task.map.read'].map(m => [m, 'read']),
|
|
6
|
+
export const applicationEffects = Object.fromEntries([
|
|
7
|
+
...['session.instructions', 'extension.list', 'extension.describe', 'extension.content', 'extension.read', 'protocol.describe', 'protocol.validate', 'project.entries', 'capability.list', 'skill.list', 'skill.read', 'action.lookup', 'action.observe', 'action.output', 'action.list', 'composition.read', 'observation.snapshot', 'interaction.selection.read', 'workspace.observe', 'task.map.read'].map(m => [m, 'read']),
|
|
8
8
|
...['composition.put', 'view.close', 'capability.configure', 'composition.apply', 'composition.undo', 'view.protection.set', 'interaction.selection.set', 'selection.set', 'workspace.enhance', 'task.map.declare', 'task.map.present', 'task.map.respond'].map(m => [m, 'metadata']),
|
|
9
9
|
...['workspace.save', 'workspace.export', 'workspace.restore', 'action.export'].map(m => [m, 'file']),
|
|
10
|
-
...['action.retry', 'action.cancel'].map(m => [m, 'native']),
|
|
10
|
+
...['extension.call', 'extension.install', 'extension.manage', 'action.retry', 'action.cancel'].map(m => [m, 'native']),
|
|
11
11
|
]);
|
|
12
12
|
const rhoSummary = 'The project in Rho: its folder\'s entries, managed runs, the views on the person\'s screen and what is selected in them, the task map, and which plugins are on.';
|
|
13
13
|
const metadata = new Set(['capability.index', 'capability.resolve', 'binding.activity.append', 'task.routing.put', 'feedback.submit', 'view.observe', 'view.observations.read']);
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
export declare const extensionOperations: {
|
|
2
|
+
'extension.list': {
|
|
3
|
+
type: string;
|
|
4
|
+
properties: Record<string, unknown>;
|
|
5
|
+
required: string[];
|
|
6
|
+
additionalProperties: boolean;
|
|
7
|
+
};
|
|
8
|
+
'extension.describe': {
|
|
9
|
+
type: string;
|
|
10
|
+
properties: Record<string, unknown>;
|
|
11
|
+
required: string[];
|
|
12
|
+
additionalProperties: boolean;
|
|
13
|
+
};
|
|
14
|
+
'extension.content': {
|
|
15
|
+
type: string;
|
|
16
|
+
properties: Record<string, unknown>;
|
|
17
|
+
required: string[];
|
|
18
|
+
additionalProperties: boolean;
|
|
19
|
+
};
|
|
20
|
+
'extension.call': {
|
|
21
|
+
type: string;
|
|
22
|
+
properties: Record<string, unknown>;
|
|
23
|
+
required: string[];
|
|
24
|
+
additionalProperties: boolean;
|
|
25
|
+
};
|
|
26
|
+
'extension.read': {
|
|
27
|
+
type: string;
|
|
28
|
+
properties: Record<string, unknown>;
|
|
29
|
+
required: string[];
|
|
30
|
+
additionalProperties: boolean;
|
|
31
|
+
};
|
|
32
|
+
'extension.install': {
|
|
33
|
+
type: string;
|
|
34
|
+
properties: Record<string, unknown>;
|
|
35
|
+
required: string[];
|
|
36
|
+
additionalProperties: boolean;
|
|
37
|
+
};
|
|
38
|
+
'extension.manage': {
|
|
39
|
+
type: string;
|
|
40
|
+
properties: Record<string, unknown>;
|
|
41
|
+
required: string[];
|
|
42
|
+
additionalProperties: boolean;
|
|
43
|
+
};
|
|
44
|
+
};
|
|
45
|
+
export declare const extensionResponses: {
|
|
46
|
+
'extension.list': {
|
|
47
|
+
type: string;
|
|
48
|
+
properties: Record<string, unknown>;
|
|
49
|
+
required: string[];
|
|
50
|
+
additionalProperties: boolean;
|
|
51
|
+
};
|
|
52
|
+
'extension.describe': {
|
|
53
|
+
type: string;
|
|
54
|
+
properties: Record<string, unknown>;
|
|
55
|
+
required: string[];
|
|
56
|
+
additionalProperties: boolean;
|
|
57
|
+
};
|
|
58
|
+
'extension.install': {
|
|
59
|
+
type: string;
|
|
60
|
+
properties: Record<string, unknown>;
|
|
61
|
+
required: string[];
|
|
62
|
+
additionalProperties: boolean;
|
|
63
|
+
};
|
|
64
|
+
'extension.content': {
|
|
65
|
+
type: string;
|
|
66
|
+
properties: Record<string, unknown>;
|
|
67
|
+
required: string[];
|
|
68
|
+
additionalProperties: boolean;
|
|
69
|
+
};
|
|
70
|
+
'extension.call': {
|
|
71
|
+
type: string;
|
|
72
|
+
properties: Record<string, unknown>;
|
|
73
|
+
required: string[];
|
|
74
|
+
additionalProperties: boolean;
|
|
75
|
+
};
|
|
76
|
+
'extension.read': {
|
|
77
|
+
type: string;
|
|
78
|
+
properties: Record<string, unknown>;
|
|
79
|
+
required: string[];
|
|
80
|
+
additionalProperties: boolean;
|
|
81
|
+
};
|
|
82
|
+
'extension.manage': {
|
|
83
|
+
type: string;
|
|
84
|
+
properties: Record<string, unknown>;
|
|
85
|
+
required: string[];
|
|
86
|
+
additionalProperties: boolean;
|
|
87
|
+
};
|
|
88
|
+
};
|
|
89
|
+
export declare const extensionDescriptions: {
|
|
90
|
+
'extension.list': string;
|
|
91
|
+
'extension.describe': string;
|
|
92
|
+
'extension.content': string;
|
|
93
|
+
'extension.call': string;
|
|
94
|
+
'extension.read': string;
|
|
95
|
+
'extension.install': string;
|
|
96
|
+
'extension.manage': string;
|
|
97
|
+
};
|
|
98
|
+
export declare const extensionManagement: string[];
|
|
99
|
+
export declare const extensionMethods: string[];
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
// Installed third-party packages are application assembly, independent of the
|
|
2
|
+
// functional owners compiled into Rho. This protocol never imports their code.
|
|
3
|
+
const str = { type: 'string', minLength: 1, maxLength: 1024 };
|
|
4
|
+
const id = { type: 'string', pattern: '^[a-z0-9][a-z0-9._-]{0,95}$' };
|
|
5
|
+
const sha = { type: 'string', pattern: '^[a-f0-9]{64}$' };
|
|
6
|
+
const object = (properties, required = Object.keys(properties)) => ({ type: 'object', properties, required, additionalProperties: false });
|
|
7
|
+
const json = { type: 'object', additionalProperties: true };
|
|
8
|
+
const project = { projectId: str };
|
|
9
|
+
const selected = { ...project, pluginId: id, expectedDigest: sha };
|
|
10
|
+
export const extensionOperations = {
|
|
11
|
+
'extension.list': object(project, []),
|
|
12
|
+
'extension.describe': object({ ...project, pluginId: id }),
|
|
13
|
+
'extension.content': object({ ...selected, kind: { enum: ['skill', 'view'] }, entryId: id }),
|
|
14
|
+
'extension.call': object({ ...selected, operation: id, input: json, changeId: { type: 'string', pattern: '^[A-Za-z0-9._:@-]{1,128}$' } }),
|
|
15
|
+
'extension.read': object({ ...project, invocationId: sha }),
|
|
16
|
+
'extension.install': object({ source: str, replace: id, expectedDigest: sha }, ['source']),
|
|
17
|
+
'extension.manage': object({ pluginId: id, expectedDigest: sha, action: { enum: ['enable', 'disable', 'remove'] } }),
|
|
18
|
+
};
|
|
19
|
+
const array = (items) => ({ type: 'array', items });
|
|
20
|
+
const text = { type: 'string' };
|
|
21
|
+
const entry = { ...object({ id, title: text, file: text }), additionalProperties: true };
|
|
22
|
+
const manifest = { ...object({ apiVersion: { const: 1 }, id, title: text, description: text, host: text,
|
|
23
|
+
operations: array({ ...object({ id, title: text, description: text, effect: { enum: ['read', 'native'] }, methods: array(text), inputSchema: json }), additionalProperties: true }),
|
|
24
|
+
skills: array(entry), views: array(entry),
|
|
25
|
+
}, ['apiVersion', 'id', 'title', 'description', 'operations', 'skills', 'views']), additionalProperties: true };
|
|
26
|
+
const installed = { id, name: text, version: text, title: text, description: text, digest: sha, source: text, sourceCommit: text, enabled: { type: 'boolean' }, installedAt: text };
|
|
27
|
+
const installedRequired = Object.keys(installed).filter(key => key !== 'sourceCommit');
|
|
28
|
+
const descriptor = object({ ...installed, manifest }, [...installedRequired, 'manifest']);
|
|
29
|
+
const receipt = object({ invocationId: sha, caller: text, projectId: text, pluginId: id, packageDigest: sha, operation: id, requestDigest: sha,
|
|
30
|
+
state: { enum: ['pending', 'completed', 'unknown'] }, startedAt: text, endedAt: text, value: {}, error: text,
|
|
31
|
+
delegations: array(object({ method: text, request: {}, state: { enum: ['pending', 'completed', 'unknown'] }, value: {}, error: text }, ['method', 'request', 'state'])),
|
|
32
|
+
}, ['invocationId', 'caller', 'projectId', 'pluginId', 'packageDigest', 'operation', 'requestDigest', 'state', 'startedAt']);
|
|
33
|
+
export const extensionResponses = {
|
|
34
|
+
'extension.list': object({ plugins: array(object(installed, installedRequired)), directory: array(object({ id, title: text, version: text, description: text, source: text, repository: text, needs: text })), limits: json }),
|
|
35
|
+
'extension.describe': descriptor,
|
|
36
|
+
'extension.install': descriptor,
|
|
37
|
+
'extension.content': object({ pluginId: id, packageDigest: sha, entryId: id, kind: { enum: ['skill', 'view'] }, title: text, text }),
|
|
38
|
+
'extension.call': receipt,
|
|
39
|
+
'extension.read': receipt,
|
|
40
|
+
'extension.manage': object({ pluginId: id, action: { enum: ['enable', 'disable', 'remove'] }, retained: text }),
|
|
41
|
+
};
|
|
42
|
+
export const extensionDescriptions = {
|
|
43
|
+
'extension.list': 'List independently installed third-party packages and their enabled state, source and immutable digest. Reads start no plugin or runtime. Use extension.describe to discover operation schemas and Skills.',
|
|
44
|
+
'extension.describe': 'Read an installed third-party package manifest, operation input schemas, required Rho methods, Skills and views. Read its Skill with extension.content before use. Disabled packages cannot run.',
|
|
45
|
+
'extension.content': 'Read one installed plugin Skill or standalone HTML view at its selected package digest. Reading starts no plugin or runtime.',
|
|
46
|
+
'extension.call': 'Call an enabled third-party operation at the described package digest, under the caller and project. The package runs trusted native code. Non-read calls retain the original changeId: repeat observes that invocation, including unknown outcomes, without re-execution. Completion is not scientific validity.',
|
|
47
|
+
'extension.read': 'Observe an original plugin invocation, including pending or unknown outcomes. Never reruns code. Only its original caller can read it.',
|
|
48
|
+
'extension.install': 'Local person/operator: install a trusted prebuilt npm package, local folder, tarball, or Git source. Lifecycle scripts are disabled. Replacement stages and checks the new package before switching; use replace and expectedDigest for updates.',
|
|
49
|
+
'extension.manage': 'Local person/operator: enable, disable or remove an installed third-party package at the expected digest. Existing native tasks, R sessions, project files and retained receipts are preserved.',
|
|
50
|
+
};
|
|
51
|
+
export const extensionManagement = ['extension.install', 'extension.manage'];
|
|
52
|
+
export const extensionMethods = Object.keys(extensionOperations);
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
// Optional discovery, not a registration requirement. Packages keep their own
|
|
2
|
+
// repositories/releases; an entry records the source a maintainer actually checked.
|
|
3
|
+
export const extensionDirectory = [
|
|
4
|
+
{
|
|
5
|
+
id: 'yulab.sclet', title: 'sclet', version: '0.1.0',
|
|
6
|
+
description: 'State-aware single-cell analysis using sclet in your shared R Notebook.',
|
|
7
|
+
source: 'git+https://github.com/YuLab-SMU/Rho-plugins.git#82df99f8cbab868c30949692172c6cf11db2f5c0:examples/sclet-plugin',
|
|
8
|
+
repository: 'https://github.com/YuLab-SMU/Rho-plugins/tree/82df99f8cbab868c30949692172c6cf11db2f5c0/examples/sclet-plugin',
|
|
9
|
+
needs: 'R, sclet, SingleCellExperiment and jsonlite in the selected R environment.',
|
|
10
|
+
},
|
|
11
|
+
];
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|