@agent-native/dispatch 0.3.0 → 0.5.0
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/actions/archive-workspace-app.d.ts +3 -0
- package/dist/actions/archive-workspace-app.d.ts.map +1 -0
- package/dist/actions/archive-workspace-app.js +15 -0
- package/dist/actions/archive-workspace-app.js.map +1 -0
- package/dist/actions/index.d.ts.map +1 -1
- package/dist/actions/index.js +10 -0
- package/dist/actions/index.js.map +1 -1
- package/dist/actions/list-available-workspace-templates.d.ts +3 -0
- package/dist/actions/list-available-workspace-templates.d.ts.map +1 -0
- package/dist/actions/list-available-workspace-templates.js +10 -0
- package/dist/actions/list-available-workspace-templates.js.map +1 -0
- package/dist/actions/remove-pending-workspace-app.d.ts +3 -0
- package/dist/actions/remove-pending-workspace-app.d.ts.map +1 -0
- package/dist/actions/remove-pending-workspace-app.js +15 -0
- package/dist/actions/remove-pending-workspace-app.js.map +1 -0
- package/dist/actions/scaffold-workspace-app.d.ts +3 -0
- package/dist/actions/scaffold-workspace-app.d.ts.map +1 -0
- package/dist/actions/scaffold-workspace-app.js +27 -0
- package/dist/actions/scaffold-workspace-app.js.map +1 -0
- package/dist/actions/unarchive-workspace-app.d.ts +3 -0
- package/dist/actions/unarchive-workspace-app.d.ts.map +1 -0
- package/dist/actions/unarchive-workspace-app.js +15 -0
- package/dist/actions/unarchive-workspace-app.js.map +1 -0
- package/dist/components/workspace-app-card.d.ts.map +1 -1
- package/dist/components/workspace-app-card.js +33 -2
- package/dist/components/workspace-app-card.js.map +1 -1
- package/dist/lib/workspace-apps.d.ts +1 -0
- package/dist/lib/workspace-apps.d.ts.map +1 -1
- package/dist/lib/workspace-apps.js.map +1 -1
- package/dist/routes/pages/apps.d.ts.map +1 -1
- package/dist/routes/pages/apps.js +41 -8
- package/dist/routes/pages/apps.js.map +1 -1
- package/dist/server/lib/app-creation-store.d.ts +40 -0
- package/dist/server/lib/app-creation-store.d.ts.map +1 -1
- package/dist/server/lib/app-creation-store.js +245 -6
- package/dist/server/lib/app-creation-store.js.map +1 -1
- package/dist/server/lib/thread-debug-store.d.ts +2 -2
- package/package.json +2 -2
- package/src/actions/archive-workspace-app.ts +16 -0
- package/src/actions/index.ts +10 -0
- package/src/actions/list-available-workspace-templates.ts +11 -0
- package/src/actions/remove-pending-workspace-app.ts +16 -0
- package/src/actions/scaffold-workspace-app.ts +34 -0
- package/src/actions/unarchive-workspace-app.ts +16 -0
- package/src/components/workspace-app-card.tsx +95 -5
- package/src/lib/workspace-apps.ts +1 -0
- package/src/routes/pages/apps.tsx +159 -6
- package/src/server/lib/app-creation-store.ts +312 -15
|
@@ -15,9 +15,25 @@ export interface WorkspaceAppSummary {
|
|
|
15
15
|
a2aEndpointUrl?: string | null;
|
|
16
16
|
agentName?: string | null;
|
|
17
17
|
agentSkillsCount?: number | null;
|
|
18
|
+
archived?: boolean;
|
|
18
19
|
}
|
|
19
20
|
export interface ListWorkspaceAppsOptions {
|
|
20
21
|
includeAgentCards?: boolean;
|
|
22
|
+
/**
|
|
23
|
+
* Include apps the current viewer has hidden (archived). Defaults to false
|
|
24
|
+
* so polling/UI callers see only the visible set; the apps page passes true
|
|
25
|
+
* when rendering the "Hidden apps" expander.
|
|
26
|
+
*/
|
|
27
|
+
includeArchived?: boolean;
|
|
28
|
+
}
|
|
29
|
+
export interface AvailableWorkspaceTemplate {
|
|
30
|
+
name: string;
|
|
31
|
+
label: string;
|
|
32
|
+
hint: string;
|
|
33
|
+
icon: string;
|
|
34
|
+
color: string;
|
|
35
|
+
colorRgb: string;
|
|
36
|
+
core: boolean;
|
|
21
37
|
}
|
|
22
38
|
export interface AppCreationSettings {
|
|
23
39
|
builderProjectId: string | null;
|
|
@@ -36,6 +52,21 @@ export interface WorkspaceInfo {
|
|
|
36
52
|
/** Number of apps currently scaffolded under apps/. */
|
|
37
53
|
appCount: number;
|
|
38
54
|
}
|
|
55
|
+
export declare function archiveWorkspaceApp(input: {
|
|
56
|
+
appId: string;
|
|
57
|
+
}): Promise<{
|
|
58
|
+
archivedAppIds: string[];
|
|
59
|
+
}>;
|
|
60
|
+
export declare function unarchiveWorkspaceApp(input: {
|
|
61
|
+
appId: string;
|
|
62
|
+
}): Promise<{
|
|
63
|
+
archivedAppIds: string[];
|
|
64
|
+
}>;
|
|
65
|
+
export declare function removePendingWorkspaceApp(input: {
|
|
66
|
+
appId: string;
|
|
67
|
+
}): Promise<{
|
|
68
|
+
removed: boolean;
|
|
69
|
+
}>;
|
|
39
70
|
export declare function getEnvBuilderProjectId(): string | null;
|
|
40
71
|
/**
|
|
41
72
|
* Read the workspace's identity from the workspace root's package.json. Used to
|
|
@@ -45,6 +76,15 @@ export declare function getEnvBuilderProjectId(): string | null;
|
|
|
45
76
|
*/
|
|
46
77
|
export declare function getWorkspaceInfo(): WorkspaceInfo;
|
|
47
78
|
export declare function listWorkspaceApps(options?: ListWorkspaceAppsOptions): Promise<WorkspaceAppSummary[]>;
|
|
79
|
+
export declare function listAvailableWorkspaceTemplates(): Promise<AvailableWorkspaceTemplate[]>;
|
|
80
|
+
export declare function scaffoldWorkspaceAppFromTemplate(input: {
|
|
81
|
+
template: string;
|
|
82
|
+
appId?: string | null;
|
|
83
|
+
}): Promise<{
|
|
84
|
+
appId: string;
|
|
85
|
+
template: string;
|
|
86
|
+
output: string;
|
|
87
|
+
}>;
|
|
48
88
|
export declare function getAppCreationSettings(): Promise<AppCreationSettings>;
|
|
49
89
|
export declare function setAppCreationSettings(input: {
|
|
50
90
|
builderProjectId?: string | null;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"app-creation-store.d.ts","sourceRoot":"","sources":["../../../src/server/lib/app-creation-store.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"app-creation-store.d.ts","sourceRoot":"","sources":["../../../src/server/lib/app-creation-store.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
1
2
|
import fs from "node:fs";
|
|
2
3
|
import path from "node:path";
|
|
3
4
|
import { fileURLToPath } from "node:url";
|
|
@@ -178,6 +179,69 @@ async function listPendingWorkspaceApps() {
|
|
|
178
179
|
const raw = await readSettingsRecord();
|
|
179
180
|
return parsePendingWorkspaceApps(raw.pendingApps);
|
|
180
181
|
}
|
|
182
|
+
function parseArchivedAppIds(value) {
|
|
183
|
+
if (!Array.isArray(value))
|
|
184
|
+
return [];
|
|
185
|
+
const ids = value
|
|
186
|
+
.map((entry) => (typeof entry === "string" ? entry.trim() : ""))
|
|
187
|
+
.filter(Boolean);
|
|
188
|
+
return Array.from(new Set(ids));
|
|
189
|
+
}
|
|
190
|
+
async function listArchivedAppIds() {
|
|
191
|
+
const raw = await readSettingsRecord();
|
|
192
|
+
return parseArchivedAppIds(raw.archivedAppIds);
|
|
193
|
+
}
|
|
194
|
+
export async function archiveWorkspaceApp(input) {
|
|
195
|
+
const appId = input.appId.trim();
|
|
196
|
+
if (!appId)
|
|
197
|
+
throw new Error("appId is required");
|
|
198
|
+
const raw = await readSettingsRecord();
|
|
199
|
+
const current = parseArchivedAppIds(raw.archivedAppIds);
|
|
200
|
+
if (!current.includes(appId))
|
|
201
|
+
current.push(appId);
|
|
202
|
+
await putSetting(scopedSettingsKey(), { ...raw, archivedAppIds: current });
|
|
203
|
+
await recordAudit({
|
|
204
|
+
action: "workspace-app.archived",
|
|
205
|
+
targetType: "workspace-app",
|
|
206
|
+
targetId: appId,
|
|
207
|
+
summary: "Hid workspace app from the Apps list",
|
|
208
|
+
});
|
|
209
|
+
return { archivedAppIds: current };
|
|
210
|
+
}
|
|
211
|
+
export async function unarchiveWorkspaceApp(input) {
|
|
212
|
+
const appId = input.appId.trim();
|
|
213
|
+
if (!appId)
|
|
214
|
+
throw new Error("appId is required");
|
|
215
|
+
const raw = await readSettingsRecord();
|
|
216
|
+
const current = parseArchivedAppIds(raw.archivedAppIds).filter((id) => id !== appId);
|
|
217
|
+
await putSetting(scopedSettingsKey(), { ...raw, archivedAppIds: current });
|
|
218
|
+
await recordAudit({
|
|
219
|
+
action: "workspace-app.unarchived",
|
|
220
|
+
targetType: "workspace-app",
|
|
221
|
+
targetId: appId,
|
|
222
|
+
summary: "Restored workspace app to the Apps list",
|
|
223
|
+
});
|
|
224
|
+
return { archivedAppIds: current };
|
|
225
|
+
}
|
|
226
|
+
export async function removePendingWorkspaceApp(input) {
|
|
227
|
+
const appId = input.appId.trim();
|
|
228
|
+
if (!appId)
|
|
229
|
+
throw new Error("appId is required");
|
|
230
|
+
const raw = await readSettingsRecord();
|
|
231
|
+
const pending = parsePendingWorkspaceApps(raw.pendingApps);
|
|
232
|
+
const next = pending.filter((app) => app.id !== appId);
|
|
233
|
+
const removed = next.length !== pending.length;
|
|
234
|
+
if (!removed)
|
|
235
|
+
return { removed: false };
|
|
236
|
+
await putSetting(scopedSettingsKey(), { ...raw, pendingApps: next });
|
|
237
|
+
await recordAudit({
|
|
238
|
+
action: "workspace-app.pending-removed",
|
|
239
|
+
targetType: "workspace-app",
|
|
240
|
+
targetId: appId,
|
|
241
|
+
summary: "Removed pending Builder app from the Apps list",
|
|
242
|
+
});
|
|
243
|
+
return { removed: true };
|
|
244
|
+
}
|
|
181
245
|
function pendingAppToSummary(app) {
|
|
182
246
|
return {
|
|
183
247
|
id: app.id,
|
|
@@ -459,24 +523,35 @@ export function getWorkspaceInfo() {
|
|
|
459
523
|
appCount,
|
|
460
524
|
};
|
|
461
525
|
}
|
|
526
|
+
async function applyArchivedAndPending(apps, options) {
|
|
527
|
+
const [withPending, archivedIds] = await Promise.all([
|
|
528
|
+
appendPendingWorkspaceApps(apps),
|
|
529
|
+
listArchivedAppIds(),
|
|
530
|
+
]);
|
|
531
|
+
const archivedSet = new Set(archivedIds);
|
|
532
|
+
const annotated = withPending.map((app) => archivedSet.has(app.id) ? { ...app, archived: true } : app);
|
|
533
|
+
return options.includeArchived
|
|
534
|
+
? annotated
|
|
535
|
+
: annotated.filter((app) => !app.archived);
|
|
536
|
+
}
|
|
462
537
|
export async function listWorkspaceApps(options = {}) {
|
|
463
538
|
const gatewayApps = await readWorkspaceAppsFromGateway();
|
|
464
539
|
if (gatewayApps) {
|
|
465
|
-
return maybeIncludeAgentCards(await
|
|
540
|
+
return maybeIncludeAgentCards(await applyArchivedAndPending(gatewayApps, options), options);
|
|
466
541
|
}
|
|
467
542
|
const workspaceRoot = findWorkspaceRoot();
|
|
468
543
|
const localFilesystemApps = workspaceRoot && isLocalAppCreationRuntime()
|
|
469
544
|
? readWorkspaceAppsFromFilesystem(workspaceRoot)
|
|
470
545
|
: null;
|
|
471
546
|
if (localFilesystemApps) {
|
|
472
|
-
return maybeIncludeAgentCards(await
|
|
547
|
+
return maybeIncludeAgentCards(await applyArchivedAndPending(localFilesystemApps, options), options);
|
|
473
548
|
}
|
|
474
549
|
const manifestApps = readWorkspaceAppsFromEnv() ?? readWorkspaceAppsFromManifestFile();
|
|
475
550
|
if (manifestApps) {
|
|
476
|
-
return maybeIncludeAgentCards(await
|
|
551
|
+
return maybeIncludeAgentCards(await applyArchivedAndPending(manifestApps, options), options);
|
|
477
552
|
}
|
|
478
553
|
if (!workspaceRoot) {
|
|
479
|
-
return maybeIncludeAgentCards(await
|
|
554
|
+
return maybeIncludeAgentCards(await applyArchivedAndPending([
|
|
480
555
|
{
|
|
481
556
|
id: "dispatch",
|
|
482
557
|
name: "Dispatch",
|
|
@@ -486,10 +561,174 @@ export async function listWorkspaceApps(options = {}) {
|
|
|
486
561
|
isDispatch: true,
|
|
487
562
|
status: "ready",
|
|
488
563
|
},
|
|
489
|
-
]), options);
|
|
564
|
+
], options), options);
|
|
490
565
|
}
|
|
491
566
|
const apps = readWorkspaceAppsFromFilesystem(workspaceRoot) ?? [];
|
|
492
|
-
return maybeIncludeAgentCards(await
|
|
567
|
+
return maybeIncludeAgentCards(await applyArchivedAndPending(apps, options), options);
|
|
568
|
+
}
|
|
569
|
+
/**
|
|
570
|
+
* First-party templates the user can scaffold into this workspace via the
|
|
571
|
+
* Apps page tiles. Inlined here (rather than importing from
|
|
572
|
+
* `@agent-native/shared-app-config`) because the published `@agent-native/dispatch`
|
|
573
|
+
* package has no `workspace:*` runtime dependencies. Keep in sync with
|
|
574
|
+
* `packages/core/src/cli/templates-meta.ts`.
|
|
575
|
+
*/
|
|
576
|
+
const ADDABLE_TEMPLATES = [
|
|
577
|
+
{
|
|
578
|
+
name: "mail",
|
|
579
|
+
label: "Mail",
|
|
580
|
+
hint: "Email client with keyboard shortcuts and AI triage",
|
|
581
|
+
icon: "Mail",
|
|
582
|
+
color: "#3B82F6",
|
|
583
|
+
colorRgb: "59 130 246",
|
|
584
|
+
core: true,
|
|
585
|
+
},
|
|
586
|
+
{
|
|
587
|
+
name: "calendar",
|
|
588
|
+
label: "Calendar",
|
|
589
|
+
hint: "Manage events, sync, and public booking",
|
|
590
|
+
icon: "CalendarMonth",
|
|
591
|
+
color: "#8B5CF6",
|
|
592
|
+
colorRgb: "139 92 246",
|
|
593
|
+
core: true,
|
|
594
|
+
},
|
|
595
|
+
{
|
|
596
|
+
name: "content",
|
|
597
|
+
label: "Content",
|
|
598
|
+
hint: "Write and organize with agent assistance",
|
|
599
|
+
icon: "FileText",
|
|
600
|
+
color: "#10B981",
|
|
601
|
+
colorRgb: "16 185 129",
|
|
602
|
+
core: true,
|
|
603
|
+
},
|
|
604
|
+
{
|
|
605
|
+
name: "slides",
|
|
606
|
+
label: "Slides",
|
|
607
|
+
hint: "Generate and edit React presentations",
|
|
608
|
+
icon: "Presentation",
|
|
609
|
+
color: "#EC4899",
|
|
610
|
+
colorRgb: "236 72 153",
|
|
611
|
+
core: true,
|
|
612
|
+
},
|
|
613
|
+
{
|
|
614
|
+
name: "clips",
|
|
615
|
+
label: "Clips",
|
|
616
|
+
hint: "Screen recording, meeting notes, and voice dictation",
|
|
617
|
+
icon: "ScreenShare",
|
|
618
|
+
color: "#625DF5",
|
|
619
|
+
colorRgb: "98 93 245",
|
|
620
|
+
core: true,
|
|
621
|
+
},
|
|
622
|
+
{
|
|
623
|
+
name: "analytics",
|
|
624
|
+
label: "Analytics",
|
|
625
|
+
hint: "Connect data sources, prompt for charts",
|
|
626
|
+
icon: "ChartBar",
|
|
627
|
+
color: "#F59E0B",
|
|
628
|
+
colorRgb: "245 158 11",
|
|
629
|
+
core: true,
|
|
630
|
+
},
|
|
631
|
+
{
|
|
632
|
+
name: "forms",
|
|
633
|
+
label: "Forms",
|
|
634
|
+
hint: "Create, edit, and manage forms",
|
|
635
|
+
icon: "ClipboardList",
|
|
636
|
+
color: "#06B6D4",
|
|
637
|
+
colorRgb: "6 182 212",
|
|
638
|
+
core: true,
|
|
639
|
+
},
|
|
640
|
+
{
|
|
641
|
+
name: "design",
|
|
642
|
+
label: "Design",
|
|
643
|
+
hint: "Create and edit visual designs with agent assistance",
|
|
644
|
+
icon: "Brush",
|
|
645
|
+
color: "#F472B6",
|
|
646
|
+
colorRgb: "244 114 182",
|
|
647
|
+
core: true,
|
|
648
|
+
},
|
|
649
|
+
{
|
|
650
|
+
name: "videos",
|
|
651
|
+
label: "Video",
|
|
652
|
+
hint: "Video editing with Remotion",
|
|
653
|
+
icon: "Video",
|
|
654
|
+
color: "#EF4444",
|
|
655
|
+
colorRgb: "239 68 68",
|
|
656
|
+
core: false,
|
|
657
|
+
},
|
|
658
|
+
];
|
|
659
|
+
export async function listAvailableWorkspaceTemplates() {
|
|
660
|
+
const installed = new Set((await listWorkspaceApps({ includeArchived: true })).map((app) => app.id));
|
|
661
|
+
return ADDABLE_TEMPLATES.filter((tpl) => !installed.has(tpl.name));
|
|
662
|
+
}
|
|
663
|
+
const SCAFFOLD_TIMEOUT_MS = 90_000;
|
|
664
|
+
export async function scaffoldWorkspaceAppFromTemplate(input) {
|
|
665
|
+
if (!isLocalAppCreationRuntime()) {
|
|
666
|
+
throw new Error("Scaffolding from Dispatch is only available in local development. " +
|
|
667
|
+
"Use the Builder branch flow on a deployed workspace.");
|
|
668
|
+
}
|
|
669
|
+
const template = input.template.trim();
|
|
670
|
+
if (!template)
|
|
671
|
+
throw new Error("template is required");
|
|
672
|
+
if (!ADDABLE_TEMPLATES.some((tpl) => tpl.name === template)) {
|
|
673
|
+
throw new Error(`Unknown template "${template}".`);
|
|
674
|
+
}
|
|
675
|
+
const appId = (input.appId?.trim() || template).toLowerCase();
|
|
676
|
+
assertValidWorkspaceAppId(appId);
|
|
677
|
+
const workspaceRoot = findWorkspaceRoot();
|
|
678
|
+
if (!workspaceRoot) {
|
|
679
|
+
throw new Error("No agent-native workspace detected for scaffolding.");
|
|
680
|
+
}
|
|
681
|
+
const appDir = path.join(workspaceRoot, "apps", appId);
|
|
682
|
+
if (fs.existsSync(appDir)) {
|
|
683
|
+
throw new Error(`apps/${appId} already exists.`);
|
|
684
|
+
}
|
|
685
|
+
const output = await runScaffoldCli({
|
|
686
|
+
cwd: workspaceRoot,
|
|
687
|
+
args: ["add-app", appId, "--template", template],
|
|
688
|
+
});
|
|
689
|
+
await recordAudit({
|
|
690
|
+
action: "workspace-app.scaffolded",
|
|
691
|
+
targetType: "workspace-app",
|
|
692
|
+
targetId: appId,
|
|
693
|
+
summary: `Scaffolded apps/${appId} from ${template}`,
|
|
694
|
+
metadata: { template },
|
|
695
|
+
});
|
|
696
|
+
return { appId, template, output };
|
|
697
|
+
}
|
|
698
|
+
function runScaffoldCli(input) {
|
|
699
|
+
return new Promise((resolve, reject) => {
|
|
700
|
+
const child = spawn("pnpm", ["exec", "agent-native", ...input.args], {
|
|
701
|
+
cwd: input.cwd,
|
|
702
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
703
|
+
env: { ...process.env, CI: "1", FORCE_COLOR: "0" },
|
|
704
|
+
});
|
|
705
|
+
let stdout = "";
|
|
706
|
+
let stderr = "";
|
|
707
|
+
child.stdout?.on("data", (chunk) => {
|
|
708
|
+
stdout += String(chunk);
|
|
709
|
+
});
|
|
710
|
+
child.stderr?.on("data", (chunk) => {
|
|
711
|
+
stderr += String(chunk);
|
|
712
|
+
});
|
|
713
|
+
const timer = setTimeout(() => {
|
|
714
|
+
child.kill("SIGTERM");
|
|
715
|
+
reject(new Error(`Scaffold timed out after ${Math.round(SCAFFOLD_TIMEOUT_MS / 1000)}s`));
|
|
716
|
+
}, SCAFFOLD_TIMEOUT_MS);
|
|
717
|
+
timer.unref();
|
|
718
|
+
child.on("error", (err) => {
|
|
719
|
+
clearTimeout(timer);
|
|
720
|
+
reject(err);
|
|
721
|
+
});
|
|
722
|
+
child.on("exit", (code) => {
|
|
723
|
+
clearTimeout(timer);
|
|
724
|
+
if (code === 0) {
|
|
725
|
+
resolve([stdout, stderr].filter(Boolean).join("\n").trim());
|
|
726
|
+
return;
|
|
727
|
+
}
|
|
728
|
+
const detail = (stderr || stdout || "").trim() || `exit code ${code}`;
|
|
729
|
+
reject(new Error(`Scaffold failed: ${detail}`));
|
|
730
|
+
});
|
|
731
|
+
});
|
|
493
732
|
}
|
|
494
733
|
export async function getAppCreationSettings() {
|
|
495
734
|
const envBuilderProjectId = getEnvBuilderProjectId();
|