feat: add ShareServer console prototype

ShareServer previously existed only as design documents. The repository now includes a standalone Hono service and a responsive React management-console prototype covering administrator and member workflows, with local build, test, and container entry points.

The sharing design now includes organization-scoped digital agents and explicit local partitioned-memory selection for @ calls. Memory documentation consistently uses partitioned memory and treats time or internal events only as optional recall triggers.

This remains an interactive prototype: fixture actions do not persist, and production authentication, PostgreSQL isolation, device connections, routing, relay, and federation still require implementation.

Release note: 新增可独立运行的 ShareServer 管理控制台交互原型,并完善组织数字人与分区记忆共享设计;当前原型数据和操作不会写入生产系统。
This commit is contained in:
mesalogo
2026-09-05 14:01:20 +08:00
parent 482cd0c467
commit 4041edefa8
49 changed files with 8614 additions and 67 deletions
+40
View File
@@ -0,0 +1,40 @@
// @vitest-environment node
import { describe, expect, it } from 'vitest'
import { app } from './app.js'
describe('ShareServer prototype API', () => {
it('reports prototype readiness without claiming production readiness', async () => {
const response = await app.request('/api/v1/public/ready')
expect(response.status).toBe(200)
await expect(response.json()).resolves.toMatchObject({
status: 'ready',
mode: 'interactive-prototype',
productionReady: false
})
})
it('returns the organization-scoped console snapshot', async () => {
const response = await app.request('/api/v1/web/prototype/snapshot')
expect(response.status).toBe(200)
await expect(response.json()).resolves.toMatchObject({
instance: { organization: 'MesaLab' },
pages: {
devices: expect.any(Array),
approvals: expect.any(Array),
myDevices: expect.any(Array)
}
})
})
it('rejects malformed prototype actions', async () => {
const response = await app.request('/api/v1/web/prototype/actions', {
method: 'POST',
headers: { 'content-type': 'application/json' },
body: JSON.stringify({ action: '批准申请' })
})
expect(response.status).toBe(400)
await expect(response.json()).resolves.toMatchObject({
code: 'INVALID_PROTOTYPE_ACTION'
})
})
})
+75
View File
@@ -0,0 +1,75 @@
import { serveStatic } from '@hono/node-server/serve-static'
import { Hono } from 'hono'
import { logger } from 'hono/logger'
import { secureHeaders } from 'hono/secure-headers'
import { prototypeSnapshot } from '../shared/prototype-data.js'
const app = new Hono()
app.use('*', logger())
app.use(
'*',
secureHeaders({
contentSecurityPolicy: {
defaultSrc: ["'self'"],
scriptSrc: ["'self'"],
styleSrc: ["'self'", "'unsafe-inline'"],
imgSrc: ["'self'", 'data:'],
connectSrc: ["'self'"]
},
crossOriginEmbedderPolicy: false
})
)
app.get('/api/v1/public/health', (context) =>
context.json({
status: 'ok',
service: 'shareserver',
version: '0.1.0-prototype.1'
})
)
app.get('/api/v1/public/ready', (context) =>
context.json({
status: 'ready',
mode: 'interactive-prototype',
productionReady: false
})
)
app.get('/api/v1/web/prototype/snapshot', (context) =>
context.json({
...prototypeSnapshot,
instance: {
...prototypeSnapshot.instance,
generatedAt: new Date().toISOString()
}
})
)
app.post('/api/v1/web/prototype/actions', async (context) => {
const body = await context.req.json<{ action?: string; targetId?: string }>().catch(() => null)
if (!body?.action || !body.targetId) {
return context.json(
{
code: 'INVALID_PROTOTYPE_ACTION',
message: '缺少原型操作或目标对象。',
requestId: crypto.randomUUID()
},
400
)
}
return context.json({
accepted: true,
action: body.action,
targetId: body.targetId,
prototypeOnly: true,
requestId: crypto.randomUUID()
})
})
app.use('*', serveStatic({ root: './dist' }))
app.get('*', serveStatic({ path: './dist/index.html' }))
export { app }
+9
View File
@@ -0,0 +1,9 @@
import { serve } from '@hono/node-server'
import { app } from './app.js'
const port = Number(process.env.SHARESERVER_PORT ?? 8787)
const hostname = process.env.SHARESERVER_HOST ?? '127.0.0.1'
serve({ fetch: app.fetch, port, hostname }, (info) => {
console.log(`ShareServer interactive prototype listening on http://${hostname}:${info.port}`)
})