@shadowob/connector
Advanced tools
+2
-2
| { | ||
| "name": "@shadowob/connector", | ||
| "version": "1.1.63", | ||
| "version": "1.1.64", | ||
| "description": "Shadow connector helpers for OpenClaw, Hermes Agent, and cc-connect", | ||
@@ -75,3 +75,3 @@ "type": "module", | ||
| "yaml": "^2.8.4", | ||
| "@shadowob/shared": "1.1.63" | ||
| "@shadowob/shared": "1.1.64" | ||
| }, | ||
@@ -78,0 +78,0 @@ "scripts": { |
@@ -180,3 +180,3 @@ import { serve } from '@hono/node-server' | ||
| app.post('/api/shadow/commands/tickets.list', async (c) => { | ||
| app.post('/.shadow/commands/tickets.list', async (c) => { | ||
| const parsed = await readOAuthEnvelope<Record<string, never>>(c, 'tickets.list') | ||
@@ -193,3 +193,3 @@ if (!parsed.ok) return parsed.response | ||
| app.post('/api/shadow/commands/tickets.create', async (c) => { | ||
| app.post('/.shadow/commands/tickets.create', async (c) => { | ||
| const parsed = await readOAuthEnvelope<unknown>(c, 'tickets.create') | ||
@@ -206,3 +206,3 @@ if (!parsed.ok) return parsed.response | ||
| app.post('/api/shadow/commands/tickets.update_status', async (c) => { | ||
| app.post('/.shadow/commands/tickets.update_status', async (c) => { | ||
| const parsed = await readOAuthEnvelope<unknown>(c, 'tickets.update_status') | ||
@@ -218,3 +218,3 @@ if (!parsed.ok) return parsed.response | ||
| app.post('/api/shadow/commands/files.summarize_upload', async (c) => { | ||
| app.post('/.shadow/commands/files.summarize_upload', async (c) => { | ||
| const auth = await authenticateShadowCommand(c, 'files.summarize_upload') | ||
@@ -221,0 +221,0 @@ if (!auth.ok) return auth.response |
@@ -35,7 +35,7 @@ # Scaffold | ||
| - `shadow-app.local.json` with `shadow.app/1`, an OAuth bearer API, iframe entry, icon route, and one neutral `status.get` command. | ||
| - `shadow-app.local.json` with `shadow.app/1`, an App-owned API base URL, iframe entry, icon route, and one neutral `status.get` command whose ingress is `/.shadow/commands/status.get`. | ||
| - `src/shadow-app.generated.ts`, generated from the manifest so command input types are inferred from JSON Schema. | ||
| - `src/manifest.ts`, using `defineShadowServerApp`. | ||
| - `src/commands.ts`, using `shadowApp.defineCommands` for domain command handlers. | ||
| - `src/server.ts`, using `shadowApp.executeCommand` for server-origin commands and launch-token runtime routes for iframe commands/inbox lookup, while exporting an import-safe Hono app. | ||
| - `src/server.ts`, exporting an import-safe Hono app with App-owned `/api/*` routes and Shadow gateway ingress under `/.shadow/*`. | ||
| - `src/data.ts`, using `createShadowServerAppJsonStore`. | ||
@@ -53,3 +53,3 @@ - `src/ui.ts`, a minimal iframe shell that should be replaced with the user's App experience. | ||
| 4. Implement domain data and commands. | ||
| 5. Replace the iframe shell with the real App UI. | ||
| 5. Replace the iframe shell with the real App UI. The UI must call App-owned `/api/*`, not command ingress routes. | ||
| 6. Run local preview through `shadowob app preview --manifest-file`. | ||
@@ -65,2 +65,3 @@ 7. For Cloud runtime publish, keep the project under `$SHADOWOB_WORKSPACE`, `/workspace`, or `/home/shadow`, then run `PORT=<port> pnpm start:background` and verify `/health` with `curl`. | ||
| - Keep generated files small; add abstractions only after the user's App needs them. | ||
| - Keep platform ingress outside App-owned `/api/*`. | ||
| - Keep the Dockerfile non-root and production-only; do not add runtime docs bundles or app-specific patches to the image. |
@@ -7,5 +7,7 @@ # App Standard | ||
| - Shadow server is the control plane: installation, authorization, OAuth, Buddy grants, command policy, audit, and entry routing. | ||
| - The App backend is the data plane: business logic, iframe launch handling, command execution, event streaming, and App-owned state. | ||
| - Buddies operate Apps through the Shadow App protocol and the `shadowob app` CLI. Do not expose backend routes, App tokens, shared secrets, or container ports to Buddies. | ||
| - Shadow server is the control plane: installation, authorization, Buddy grants, command policy, approvals, audit, and gateway routing. | ||
| - The App backend is the data plane: business logic, App-owned API, App users, App sessions, command handlers, and App-owned state. | ||
| - App UI calls only App-owned `/api/*`. | ||
| - Shadow platform ingress in the App lives only under `/.shadow/*`. | ||
| - Buddies and CLI operate Apps through `shadowob app discover`, `shadowob app skills`, and `shadowob app call`. Do not expose backend routes, App tokens, shared secrets, or container ports to Buddies. | ||
| - Agents may develop and run Apps, but publishing, domain mounting, grants, and backups must go through the Shadow CLI or Cloud control plane. | ||
@@ -47,7 +49,39 @@ | ||
| - Set `iframe.entry` to the user-facing entry URL and `iframe.allowedOrigins` to exact origins. | ||
| - Set `api.baseUrl` to the App backend HTTPS base URL. | ||
| - Use `api.auth.type: "oauth2-bearer"`. | ||
| - Keep commands small and stable. Each command must declare JSON Schema, `permission`, `action`, `dataClass`, and approval behavior when applicable. | ||
| - Set `api.baseUrl` to the App backend HTTPS origin. This is the App origin, not a Shadow protocol namespace. | ||
| - Keep commands small and stable. Each command must declare `ingress.path`, `ingress.auth`, JSON Schema, `permission`, `action`, `dataClass`, and approval behavior when applicable. | ||
| - Command ingress paths must live under `/.shadow/commands/*`. | ||
| - Keep manifest `skills` short and actionable. Do not put full API documentation in the manifest. | ||
| Example command entry: | ||
| ```json | ||
| { | ||
| "name": "tickets.create", | ||
| "ingress": { | ||
| "path": "/.shadow/commands/tickets.create", | ||
| "auth": "shadow-command-jwt" | ||
| }, | ||
| "permission": "ticket_desk.tickets:write", | ||
| "action": "write", | ||
| "dataClass": "server-private", | ||
| "inputSchema": { | ||
| "type": "object", | ||
| "properties": { | ||
| "title": { "type": "string", "minLength": 1 } | ||
| }, | ||
| "required": ["title"], | ||
| "additionalProperties": false | ||
| } | ||
| } | ||
| ``` | ||
| ## API Rules | ||
| - `/api/*` is App-owned. Use it for browser UI and synchronous business operations. | ||
| - `/.shadow/commands/*` is Shadow gateway ingress. It accepts only Shadow-signed command requests. | ||
| - `/.shadow/backup/*` and `/.shadow/restore/*` are platform lifecycle ingress when the App supports backup/restore hooks. | ||
| - Keep platform ingress outside App-owned `/api/*`. | ||
| - Do not read manifest command ingress paths from browser code. | ||
| - Treat `avatarUrl` fields in Shadow identity snapshots as stable public image URLs. Render user avatars, server icons, and Buddy avatars directly; private media delivery is for attachments and workspace files. | ||
| ## SDK And Protocol | ||
@@ -59,6 +93,6 @@ | ||
| - `shadow-server-app typegen` to generate typed command input from the manifest. | ||
| - `shadowApp.defineCommands`, `shadowApp.executeCommand`, `shadowApp.executeLocal`, and `shadowApp.error` for command protocol handling. | ||
| - `shadowApp.defineCommands` and the Shadow command ingress helpers for command handling. | ||
| - `createShadowServerAppJsonStore` for environment-configured JSON persistence. | ||
| Do not hand-roll Bearer token parsing, token introspection, manifest rewriting, command JSON Schema validation, actor display labels, or command error envelopes. | ||
| Do not hand-roll manifest rewriting, Shadow command token validation, command JSON Schema validation, actor display labels, or command error envelopes. | ||
@@ -68,3 +102,4 @@ ## Authorization | ||
| - Treat authentication and authorization as separate concerns. | ||
| - OAuth or PAT scope is not enough. A command must also satisfy App grant, server access, command permission, resource rule, and action policy. | ||
| - App UI authentication is App-owned: App session, App OAuth account link, or explicit anonymous policy. | ||
| - Shadow OAuth or PAT scope is not enough for command execution. Shadow gateway must also satisfy server access, command permission, resource rule, action policy, approval, and Buddy grant. | ||
| - Use `server-private` or `channel-private` for ordinary server data. | ||
@@ -76,4 +111,3 @@ - Do not use `financial`, `secret`, or `cloud-secret` unless the Shadow server policy explicitly supports the use case. | ||
| - Keep iframe launch URLs stable; avoid query strings that force remounts on every launch refresh. | ||
| - Cache launch context until close to expiry. | ||
| - Keep iframe URLs stable. | ||
| - Keep global navigation data warm while refetching. | ||
@@ -93,3 +127,3 @@ - Prefer event streams or App-local patches over iframe remounts. | ||
| Call a command: | ||
| Call a command through Shadow gateway: | ||
@@ -104,3 +138,3 @@ ```bash | ||
| Attach binary input through the command protocol only: | ||
| Attach binary input through Shadow gateway only: | ||
@@ -114,1 +148,3 @@ ```bash | ||
| ``` | ||
| Never call App `/.shadow/*` directly from Buddy or CLI. |
@@ -20,3 +20,4 @@ --- | ||
| - Use the modeled `@shadowob/sdk` App runtime instead of reimplementing manifest rewriting, Bearer token extraction, token introspection, command request parsing, JSON Schema validation, or actor labels. | ||
| - Keep App-owned `/api/*` separate from Shadow gateway ingress. New Apps must expose Shadow platform routes only under `/.shadow/*`. | ||
| - Use the modeled `@shadowob/sdk` App helpers instead of reimplementing manifest rewriting, Shadow command token validation, command request parsing, JSON Schema validation, or actor labels. | ||
| - Use `shadow.app/1` manifests, stable `appKey` values, stable command names, and explicit `permission`, `action`, and `dataClass` on every command. | ||
@@ -27,3 +28,3 @@ - Buddies must operate installed Apps through `shadowob app discover`, `shadowob app skills`, and `shadowob app call`; never hand a Buddy raw HTTP routes, app tokens, or shared secrets. | ||
| - Never load Shadow OAuth inside the App iframe. Use a top-level popup or navigation and include `allow-popups-to-escape-sandbox` on the iframe sandbox. | ||
| - Keep iframe launch URLs stable. Cache launch context until near expiry, keep global navigation data warm while refetching, and prefer event streams or app-local patches over iframe remounts. | ||
| - Keep iframe URLs stable. App UI must call App-owned `/api/*`; it must not call command ingress routes or Shadow gateway routes directly. | ||
| - Declare state paths and backup policy before publishing an agent-hosted app. Runtime code, build output, config, secrets, and mutable app state must have separate ownership and lifecycle. | ||
@@ -30,0 +31,0 @@ - For a new App, start from `shadowob app generate <app-key>` or `node scripts/create-server-app.mjs <app-key>` unless the user asks for a different stack. |
| import { RuntimeSessionState, RuntimeSessionPetReaction, RuntimeSessionPetActivity } from '@shadowob/shared/types'; | ||
| export { RuntimeSessionPetActivity, RuntimeSessionPetReaction, RuntimeSessionState, runtimeSessionPetReactionForState } from '@shadowob/shared/types'; | ||
| type ConnectorRuntimeId = 'openclaw' | 'hermes' | 'claude-code' | 'codex' | 'opencode' | 'cursor' | 'kimi' | 'copilot' | 'antigravity'; | ||
| type RuntimeInstanceStatus = 'running' | 'available' | 'stopped' | 'missing' | 'error'; | ||
| interface RuntimeInstanceInfo { | ||
| runtimeId: ConnectorRuntimeId; | ||
| instanceId: string; | ||
| label: string; | ||
| status: RuntimeInstanceStatus; | ||
| endpoint?: string | null; | ||
| capabilities: string[]; | ||
| error?: string | null; | ||
| metadata?: Record<string, unknown>; | ||
| } | ||
| interface RuntimeSessionInfo { | ||
| runtimeId: ConnectorRuntimeId; | ||
| instanceId: string; | ||
| sessionId: string; | ||
| title?: string | null; | ||
| workDir?: string | null; | ||
| state: RuntimeSessionState; | ||
| petReaction: RuntimeSessionPetReaction; | ||
| petActivity?: RuntimeSessionPetActivity; | ||
| model?: string | null; | ||
| lastActivityAt?: string | null; | ||
| startedAt?: string | null; | ||
| source: 'server' | 'cli' | 'database' | 'storage' | 'transcript'; | ||
| native?: Record<string, unknown>; | ||
| } | ||
| interface RuntimeSessionSnapshot { | ||
| scannedAt: string; | ||
| runtimeIds: ConnectorRuntimeId[]; | ||
| instances: RuntimeInstanceInfo[]; | ||
| sessions: RuntimeSessionInfo[]; | ||
| } | ||
| type RuntimeSessionEventType = 'snapshot' | 'session_added' | 'session_removed' | 'session_changed'; | ||
| interface RuntimeSessionEvent { | ||
| type: RuntimeSessionEventType; | ||
| at: string; | ||
| runtimeId?: ConnectorRuntimeId; | ||
| sessionId?: string; | ||
| previousState?: RuntimeSessionState; | ||
| state?: RuntimeSessionState; | ||
| previousPetReaction?: RuntimeSessionPetReaction; | ||
| petReaction?: RuntimeSessionPetReaction; | ||
| previousPetActivity?: RuntimeSessionPetActivity; | ||
| petActivity?: RuntimeSessionPetActivity; | ||
| session?: RuntimeSessionInfo; | ||
| snapshot?: RuntimeSessionSnapshot; | ||
| } | ||
| interface RuntimeSessionScanOptions { | ||
| runtimeId?: string; | ||
| opencodeUrl?: string; | ||
| homeDir?: string; | ||
| env?: NodeJS.ProcessEnv; | ||
| limit?: number; | ||
| } | ||
| interface RuntimeSessionSendOptions extends RuntimeSessionScanOptions { | ||
| runtimeId: string; | ||
| sessionId: string; | ||
| message: string; | ||
| timeoutMs?: number; | ||
| } | ||
| interface RuntimeSessionSendResult { | ||
| runtimeId: ConnectorRuntimeId; | ||
| sessionId: string; | ||
| accepted: boolean; | ||
| mode: 'server' | 'process'; | ||
| events?: unknown[]; | ||
| stdout?: string; | ||
| stderr?: string; | ||
| exitCode?: number | null; | ||
| } | ||
| declare function runtimeSessionPetReaction(session: Pick<RuntimeSessionInfo, 'state'> & { | ||
| petReaction?: RuntimeSessionPetReaction; | ||
| }): RuntimeSessionPetReaction; | ||
| declare function scanRuntimeSessions(options?: RuntimeSessionScanOptions): Promise<RuntimeSessionSnapshot>; | ||
| declare function diffRuntimeSessionSnapshots(previous: RuntimeSessionSnapshot | null, next: RuntimeSessionSnapshot): RuntimeSessionEvent[]; | ||
| declare function renderRuntimeSessionPanel(snapshot: RuntimeSessionSnapshot): string; | ||
| declare function sendRuntimeSessionMessage(options: RuntimeSessionSendOptions): Promise<RuntimeSessionSendResult>; | ||
| export { type RuntimeInstanceInfo, type RuntimeInstanceStatus, type RuntimeSessionEvent, type RuntimeSessionEventType, type RuntimeSessionInfo, type RuntimeSessionScanOptions, type RuntimeSessionSendOptions, type RuntimeSessionSendResult, type RuntimeSessionSnapshot, diffRuntimeSessionSnapshots, renderRuntimeSessionPanel, runtimeSessionPetReaction, scanRuntimeSessions, sendRuntimeSessionMessage }; |
| import { RuntimeSessionState, RuntimeSessionPetReaction, RuntimeSessionPetActivity } from '@shadowob/shared/types'; | ||
| export { RuntimeSessionPetActivity, RuntimeSessionPetReaction, RuntimeSessionState, runtimeSessionPetReactionForState } from '@shadowob/shared/types'; | ||
| type ConnectorRuntimeId = 'openclaw' | 'hermes' | 'claude-code' | 'codex' | 'opencode' | 'cursor' | 'kimi' | 'copilot' | 'antigravity'; | ||
| type RuntimeInstanceStatus = 'running' | 'available' | 'stopped' | 'missing' | 'error'; | ||
| interface RuntimeInstanceInfo { | ||
| runtimeId: ConnectorRuntimeId; | ||
| instanceId: string; | ||
| label: string; | ||
| status: RuntimeInstanceStatus; | ||
| endpoint?: string | null; | ||
| capabilities: string[]; | ||
| error?: string | null; | ||
| metadata?: Record<string, unknown>; | ||
| } | ||
| interface RuntimeSessionInfo { | ||
| runtimeId: ConnectorRuntimeId; | ||
| instanceId: string; | ||
| sessionId: string; | ||
| title?: string | null; | ||
| workDir?: string | null; | ||
| state: RuntimeSessionState; | ||
| petReaction: RuntimeSessionPetReaction; | ||
| petActivity?: RuntimeSessionPetActivity; | ||
| model?: string | null; | ||
| lastActivityAt?: string | null; | ||
| startedAt?: string | null; | ||
| source: 'server' | 'cli' | 'database' | 'storage' | 'transcript'; | ||
| native?: Record<string, unknown>; | ||
| } | ||
| interface RuntimeSessionSnapshot { | ||
| scannedAt: string; | ||
| runtimeIds: ConnectorRuntimeId[]; | ||
| instances: RuntimeInstanceInfo[]; | ||
| sessions: RuntimeSessionInfo[]; | ||
| } | ||
| type RuntimeSessionEventType = 'snapshot' | 'session_added' | 'session_removed' | 'session_changed'; | ||
| interface RuntimeSessionEvent { | ||
| type: RuntimeSessionEventType; | ||
| at: string; | ||
| runtimeId?: ConnectorRuntimeId; | ||
| sessionId?: string; | ||
| previousState?: RuntimeSessionState; | ||
| state?: RuntimeSessionState; | ||
| previousPetReaction?: RuntimeSessionPetReaction; | ||
| petReaction?: RuntimeSessionPetReaction; | ||
| previousPetActivity?: RuntimeSessionPetActivity; | ||
| petActivity?: RuntimeSessionPetActivity; | ||
| session?: RuntimeSessionInfo; | ||
| snapshot?: RuntimeSessionSnapshot; | ||
| } | ||
| interface RuntimeSessionScanOptions { | ||
| runtimeId?: string; | ||
| opencodeUrl?: string; | ||
| homeDir?: string; | ||
| env?: NodeJS.ProcessEnv; | ||
| limit?: number; | ||
| } | ||
| interface RuntimeSessionSendOptions extends RuntimeSessionScanOptions { | ||
| runtimeId: string; | ||
| sessionId: string; | ||
| message: string; | ||
| timeoutMs?: number; | ||
| } | ||
| interface RuntimeSessionSendResult { | ||
| runtimeId: ConnectorRuntimeId; | ||
| sessionId: string; | ||
| accepted: boolean; | ||
| mode: 'server' | 'process'; | ||
| events?: unknown[]; | ||
| stdout?: string; | ||
| stderr?: string; | ||
| exitCode?: number | null; | ||
| } | ||
| declare function runtimeSessionPetReaction(session: Pick<RuntimeSessionInfo, 'state'> & { | ||
| petReaction?: RuntimeSessionPetReaction; | ||
| }): RuntimeSessionPetReaction; | ||
| declare function scanRuntimeSessions(options?: RuntimeSessionScanOptions): Promise<RuntimeSessionSnapshot>; | ||
| declare function diffRuntimeSessionSnapshots(previous: RuntimeSessionSnapshot | null, next: RuntimeSessionSnapshot): RuntimeSessionEvent[]; | ||
| declare function renderRuntimeSessionPanel(snapshot: RuntimeSessionSnapshot): string; | ||
| declare function sendRuntimeSessionMessage(options: RuntimeSessionSendOptions): Promise<RuntimeSessionSendResult>; | ||
| export { type RuntimeInstanceInfo, type RuntimeInstanceStatus, type RuntimeSessionEvent, type RuntimeSessionEventType, type RuntimeSessionInfo, type RuntimeSessionScanOptions, type RuntimeSessionSendOptions, type RuntimeSessionSendResult, type RuntimeSessionSnapshot, diffRuntimeSessionSnapshots, renderRuntimeSessionPanel, runtimeSessionPetReaction, scanRuntimeSessions, sendRuntimeSessionMessage }; |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
AI-detected potential code anomaly
Supply chain riskAI has identified unusual behaviors that may pose a security risk.
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
AI-detected potential code anomaly
Supply chain riskAI has identified unusual behaviors that may pose a security risk.
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
1034312
-0.49%35
-5.41%22709
-0.32%+ Added
- Removed
Updated