@zonease/aiworker-cli 0.12.2 → 0.13.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.
Files changed (117) hide show
  1. package/README.md +158 -350
  2. package/aiworker-bun.js +614 -694
  3. package/drizzle/worker/0000_polite_stellaris.sql +219 -0
  4. package/drizzle/worker/0001_red_lady_mastermind.sql +29 -0
  5. package/drizzle/worker/0002_concerned_slyde.sql +45 -0
  6. package/drizzle/worker/meta/0000_snapshot.json +1055 -194
  7. package/drizzle/worker/meta/0001_snapshot.json +1244 -222
  8. package/drizzle/worker/meta/0002_snapshot.json +1557 -273
  9. package/drizzle/worker/meta/_journal.json +6 -48
  10. package/official-apps/aiworker-hr/README.md +16 -0
  11. package/official-apps/aiworker-hr/capabilities/candidate-screen/prompt.md +3 -0
  12. package/official-apps/aiworker-hr/capabilities/candidate-screen/review.md +5 -0
  13. package/official-apps/aiworker-hr/capabilities/person-profile/prompt.md +3 -0
  14. package/official-apps/aiworker-hr/capabilities/person-profile/review.md +5 -0
  15. package/official-apps/aiworker-hr/dist/host-mounted.js +15677 -0
  16. package/official-apps/aiworker-hr/dist/index.js +15411 -0
  17. package/official-apps/aiworker-hr/dist/standalone.js +15451 -0
  18. package/official-apps/aiworker-hr/migrations/0001_hr.sql +2 -0
  19. package/official-apps/aiworker-hr/package.json +31 -0
  20. package/official-apps/aiworker-hr/packs/hr-recruiting/SOUL.md +7 -0
  21. package/official-apps/aiworker-hr/review/candidate-screen.md +5 -0
  22. package/official-apps/aiworker-hr/review/person-profile.md +5 -0
  23. package/official-apps/aiworker-hr/schemas/candidate-screen.schema.json +50 -0
  24. package/official-apps/aiworker-hr/schemas/person-profile.schema.json +50 -0
  25. package/official-apps/aiworker-hr/soul-app.manifest.json +374 -0
  26. package/official-apps/aiworker-hr/src/api.ts +1 -0
  27. package/official-apps/aiworker-hr/src/host-mounted.ts +308 -0
  28. package/official-apps/aiworker-hr/src/index.ts +152 -0
  29. package/official-apps/aiworker-hr/src/protocol/artifact.ts +2 -0
  30. package/official-apps/aiworker-hr/src/protocol/connectors.ts +2 -0
  31. package/official-apps/aiworker-hr/src/protocol/lifecycle.ts +2 -0
  32. package/official-apps/aiworker-hr/src/protocol/review.ts +2 -0
  33. package/official-apps/aiworker-hr/src/protocol/runtime.ts +2 -0
  34. package/official-apps/aiworker-hr/src/protocol/ui.ts +2 -0
  35. package/official-apps/aiworker-hr/src/standalone.ts +43 -0
  36. package/official-apps/aiworker-hr/src/ui/candidate-screen-preview.tsx +2 -0
  37. package/official-apps/aiworker-hr/src/ui/hr-route.tsx +1 -0
  38. package/official-apps/aiworker-hr/src/ui/people-widget.tsx +1 -0
  39. package/official-apps/aiworker-hr/src/ui/person-profile-preview.tsx +2 -0
  40. package/official-apps/aiworker-hr/src/ui/profile-panel.tsx +1 -0
  41. package/official-apps/aiworker-hr/src/ui/review-panel.tsx +1 -0
  42. package/official-apps/aiworker-hr/tsconfig.json +20 -0
  43. package/official-apps/aiworker-qa/README.md +14 -0
  44. package/official-apps/aiworker-qa/capabilities/regression-matrix/prompt.md +3 -0
  45. package/official-apps/aiworker-qa/capabilities/regression-matrix/review.md +5 -0
  46. package/official-apps/aiworker-qa/capabilities/release-gate/prompt.md +3 -0
  47. package/official-apps/aiworker-qa/capabilities/release-gate/review.md +5 -0
  48. package/official-apps/aiworker-qa/dist/host-mounted.js +15655 -0
  49. package/official-apps/aiworker-qa/dist/index.js +15395 -0
  50. package/official-apps/aiworker-qa/dist/standalone.js +15435 -0
  51. package/official-apps/aiworker-qa/migrations/0001_qa.sql +2 -0
  52. package/official-apps/aiworker-qa/package.json +31 -0
  53. package/official-apps/aiworker-qa/packs/qa-reviewer/SOUL.md +7 -0
  54. package/official-apps/aiworker-qa/review/regression-matrix.md +5 -0
  55. package/official-apps/aiworker-qa/review/release-gate.md +5 -0
  56. package/official-apps/aiworker-qa/schemas/regression-matrix.schema.json +50 -0
  57. package/official-apps/aiworker-qa/schemas/release-gate.schema.json +50 -0
  58. package/official-apps/aiworker-qa/soul-app.manifest.json +356 -0
  59. package/official-apps/aiworker-qa/src/api.ts +1 -0
  60. package/official-apps/aiworker-qa/src/host-mounted.ts +302 -0
  61. package/official-apps/aiworker-qa/src/index.ts +152 -0
  62. package/official-apps/aiworker-qa/src/protocol/artifact.ts +2 -0
  63. package/official-apps/aiworker-qa/src/protocol/connectors.ts +2 -0
  64. package/official-apps/aiworker-qa/src/protocol/lifecycle.ts +2 -0
  65. package/official-apps/aiworker-qa/src/protocol/review.ts +2 -0
  66. package/official-apps/aiworker-qa/src/protocol/runtime.ts +2 -0
  67. package/official-apps/aiworker-qa/src/protocol/ui.ts +2 -0
  68. package/official-apps/aiworker-qa/src/standalone.ts +43 -0
  69. package/official-apps/aiworker-qa/src/ui/qa-route.tsx +1 -0
  70. package/official-apps/aiworker-qa/src/ui/regression-matrix-preview.tsx +2 -0
  71. package/official-apps/aiworker-qa/src/ui/release-gate-preview.tsx +2 -0
  72. package/official-apps/aiworker-qa/src/ui/release-panel.tsx +1 -0
  73. package/official-apps/aiworker-qa/src/ui/release-review-panel.tsx +1 -0
  74. package/official-apps/aiworker-qa/src/ui/release-widget.tsx +1 -0
  75. package/official-apps/aiworker-qa/src/ui/review-panel.tsx +1 -0
  76. package/official-apps/aiworker-qa/tsconfig.json +20 -0
  77. package/package.json +5 -4
  78. package/web/worker/assets/index-ByOwFiyz.js +18 -0
  79. package/web/worker/assets/index-K-y56wrL.css +2 -0
  80. package/web/worker/assets/markdown-preview-DFe-rfff.js +29 -0
  81. package/web/worker/assets/people-workbench-V1Ajqfzv.js +1 -0
  82. package/web/worker/engine-icons/claude.svg +1 -0
  83. package/web/worker/engine-icons/cursor.svg +1 -0
  84. package/web/worker/engine-icons/gemini.svg +1 -0
  85. package/web/worker/engine-icons/hermesagent.svg +1 -0
  86. package/web/worker/engine-icons/openai.svg +1 -0
  87. package/web/worker/engine-icons/opencode.svg +1 -0
  88. package/web/worker/engine-icons/qwen.svg +1 -0
  89. package/web/worker/fonts/inter-latin-wght-normal.woff2 +0 -0
  90. package/web/worker/fonts/jetbrains-mono-latin-wght-normal.woff2 +0 -0
  91. package/web/worker/fonts/nunito-latin-wght-normal.woff2 +0 -0
  92. package/web/worker/index.html +8 -4
  93. package/web/worker/logo.svg +8 -0
  94. package/drizzle/fleet/0000_fine_havok.sql +0 -23
  95. package/drizzle/fleet/meta/0000_snapshot.json +0 -165
  96. package/drizzle/fleet/meta/_journal.json +0 -13
  97. package/drizzle/worker/0000_spooky_kat_farrell.sql +0 -112
  98. package/drizzle/worker/0001_secret_dagger.sql +0 -1
  99. package/drizzle/worker/0002_jazzy_moondragon.sql +0 -13
  100. package/drizzle/worker/0003_rare_cloak.sql +0 -7
  101. package/drizzle/worker/0004_daffy_thing.sql +0 -26
  102. package/drizzle/worker/0005_worthless_whiplash.sql +0 -20
  103. package/drizzle/worker/0006_fair_jetstream.sql +0 -34
  104. package/drizzle/worker/0007_solid_bromley.sql +0 -11
  105. package/drizzle/worker/0008_peaceful_titanium_man.sql +0 -14
  106. package/drizzle/worker/meta/0003_snapshot.json +0 -873
  107. package/drizzle/worker/meta/0004_snapshot.json +0 -1058
  108. package/drizzle/worker/meta/0005_snapshot.json +0 -1192
  109. package/drizzle/worker/meta/0006_snapshot.json +0 -1420
  110. package/drizzle/worker/meta/0007_snapshot.json +0 -1489
  111. package/drizzle/worker/meta/0008_snapshot.json +0 -1593
  112. package/web/fleet/assets/index-BTknRPEg.js +0 -1372
  113. package/web/fleet/assets/index-lu-9OhC0.css +0 -2
  114. package/web/fleet/favicon.svg +0 -4
  115. package/web/fleet/index.html +0 -14
  116. package/web/worker/assets/index-DuxsPbd7.js +0 -1382
  117. package/web/worker/assets/index-lu-9OhC0.css +0 -2
@@ -0,0 +1,308 @@
1
+ import { Buffer } from 'node:buffer'
2
+ import process from 'node:process'
3
+
4
+ import { createSoulAppClient } from '@zonease/aiworker-soul-app-sdk'
5
+
6
+ import { hrReferenceSoulApp, hrSoulAppManifest } from './index'
7
+
8
+ interface MountContext {
9
+ brokerUrl?: string
10
+ hostUrl?: string
11
+ operatorId?: string | null
12
+ sessionId?: string | null
13
+ surface?: {
14
+ id?: string
15
+ scope?: string
16
+ }
17
+ workerId?: string | null
18
+ workspaceId?: string | null
19
+ }
20
+
21
+ interface BrokerSearchResult {
22
+ items?: Array<Record<string, unknown>>
23
+ }
24
+
25
+ export function serveHostMounted(port = Number(Bun.env.PORT ?? 0)) {
26
+ return Bun.serve({
27
+ async fetch(request) {
28
+ const url = new URL(request.url)
29
+ if (url.pathname === '/health') {
30
+ return Response.json({
31
+ appId: hrSoulAppManifest.id,
32
+ mode: 'host-mounted',
33
+ status: 'ok',
34
+ })
35
+ }
36
+ const tokenError = verifyMountToken(request)
37
+ if (tokenError)
38
+ return tokenError
39
+ if (url.pathname === '/domain') {
40
+ return Response.json({
41
+ appId: hrSoulAppManifest.id,
42
+ capabilities: hrSoulAppManifest.capabilities.map(capability => capability.id),
43
+ mounted: true,
44
+ soul: hrSoulAppManifest.soul.id,
45
+ workspaceTypes: hrSoulAppManifest.workspaceTypes.map(type => type.id),
46
+ })
47
+ }
48
+ if (url.pathname === '/surfaces/routes/hr-home' || url.pathname === '/surfaces/panels/hr-profile-panel') {
49
+ return Response.json(hrDescriptorSurface(request, url.pathname))
50
+ }
51
+ if (url.pathname === '/frames/widgets/hr-people-widget') {
52
+ return new Response(hrWidgetFrameHtml(request), {
53
+ headers: { 'content-type': 'text/html; charset=utf-8' },
54
+ })
55
+ }
56
+ if (url.pathname === '/protocol/actions' && request.method === 'POST') {
57
+ const body = await request.json().catch(() => ({})) as Record<string, unknown>
58
+ return Response.json(await hrProtocolAction(request, String(body.protocolAction ?? '')))
59
+ }
60
+ if (url.pathname === '/protocol/search' && request.method === 'GET') {
61
+ return Response.json(await hrProtocolSearch(request, url))
62
+ }
63
+ if (url.pathname === '/broker/permissions') {
64
+ const hostUrl = request.headers.get('x-aiworker-host-url') ?? Bun.env.AIWORKER_HOST_URL
65
+ if (!hostUrl)
66
+ return Response.json({ appId: hrSoulAppManifest.id, broker: 'not-configured', permissions: [] })
67
+ const client = createSoulAppClient({ appId: hrSoulAppManifest.id, baseUrl: hostUrl })
68
+ return Response.json(await client.broker.permissions.list())
69
+ }
70
+ if (url.pathname === '/protocol/capabilities') {
71
+ return Response.json({
72
+ capabilities: await hrReferenceSoulApp.ui?.capabilities({
73
+ appId: hrSoulAppManifest.id,
74
+ permissions: hrSoulAppManifest.permissions,
75
+ }),
76
+ })
77
+ }
78
+ return Response.json({ error: { code: 'NOT_FOUND', message: `Unknown HR app route: ${url.pathname}` } }, { status: 404 })
79
+ },
80
+ hostname: Bun.env.HOST ?? '127.0.0.1',
81
+ port,
82
+ })
83
+ }
84
+
85
+ if (import.meta.main) {
86
+ const server = serveHostMounted()
87
+ process.stdout.write(`${JSON.stringify({ appId: hrSoulAppManifest.id, mode: 'host-mounted', url: `http://${server.hostname}:${server.port}` })}\n`)
88
+ }
89
+
90
+ function verifyMountToken(request: Request): Response | null {
91
+ const expected = Bun.env.AIWORKER_MOUNT_TOKEN
92
+ if (!expected)
93
+ return null
94
+ const actual = request.headers.get('x-aiworker-mount-token')
95
+ return actual === expected
96
+ ? null
97
+ : Response.json({ error: { code: 'INVALID_MOUNT_TOKEN', message: 'Host mount token is required.' } }, { status: 401 })
98
+ }
99
+
100
+ function hrDescriptorSurface(request: Request, pathname: string) {
101
+ const context = readMountContext(request)
102
+ return {
103
+ actions: [
104
+ {
105
+ id: 'create-profile-review',
106
+ label: 'Create review',
107
+ method: 'POST',
108
+ target: `${context?.brokerUrl ?? '/broker'}/reviews`,
109
+ },
110
+ ],
111
+ appId: hrSoulAppManifest.id,
112
+ authority: 'soul-app',
113
+ cache: {
114
+ freshness: 'non-authoritative',
115
+ },
116
+ context: {
117
+ signed: Boolean(request.headers.get('x-aiworker-mount-signature')),
118
+ surfaceId: context?.surface?.id ?? null,
119
+ workspaceId: context?.workspaceId ?? null,
120
+ },
121
+ fields: [
122
+ { label: 'Domain', value: hrSoulAppManifest.soul.domain },
123
+ { label: 'Workspace types', value: hrSoulAppManifest.workspaceTypes.map(type => type.name).join(', ') },
124
+ { label: 'Evidence broker', value: hrSoulAppManifest.connectors.required.map(connector => connector.id).join(', ') },
125
+ ],
126
+ path: pathname,
127
+ renderer: 'host-descriptor',
128
+ status: 'ready',
129
+ title: pathname.includes('/routes/') ? 'HR Mounted Workbench' : 'People Profile Panel',
130
+ type: 'aiworker.surface.descriptor.v1',
131
+ }
132
+ }
133
+
134
+ function hrWidgetFrameHtml(request: Request): string {
135
+ const context = readMountContext(request)
136
+ return [
137
+ '<!doctype html>',
138
+ '<html lang="en">',
139
+ '<head><meta charset="utf-8"><title>HR People Widget</title></head>',
140
+ '<body>',
141
+ '<main>',
142
+ '<h1>People Widget</h1>',
143
+ `<p data-soul-app-id="${hrSoulAppManifest.id}">Mounted HR frame surface</p>`,
144
+ `<p data-surface-id="${context?.surface?.id ?? 'unknown'}">Scope ${context?.surface?.scope ?? 'workspace'}</p>`,
145
+ '</main>',
146
+ '</body>',
147
+ '</html>',
148
+ ].join('')
149
+ }
150
+
151
+ async function hrProtocolAction(request: Request, protocolAction: string) {
152
+ if (protocolAction === 'peopleProfiles.create') {
153
+ const persisted = await persistPeopleProfileDraft(request)
154
+ if (!persisted.ok)
155
+ return persisted
156
+ return {
157
+ message: 'People profile draft opened by HR app.',
158
+ ok: true,
159
+ redirectTo: '/hr/people',
160
+ refresh: true,
161
+ }
162
+ }
163
+ if (protocolAction === 'people.refresh') {
164
+ return {
165
+ message: 'People data refreshed by HR app.',
166
+ ok: true,
167
+ refresh: true,
168
+ }
169
+ }
170
+ if (protocolAction === 'drawers.evidence.toggle') {
171
+ return {
172
+ message: 'Evidence drawer intent emitted by HR app.',
173
+ ok: true,
174
+ }
175
+ }
176
+ if (protocolAction === 'settings.open') {
177
+ return {
178
+ message: 'HR settings are owned by the HR app.',
179
+ ok: true,
180
+ }
181
+ }
182
+ return {
183
+ message: `Unknown HR protocol action: ${protocolAction}`,
184
+ ok: false,
185
+ }
186
+ }
187
+
188
+ async function persistPeopleProfileDraft(request: Request): Promise<{ message: string, ok: false } | { ok: true }> {
189
+ const context = readMountContext(request)
190
+ if (!context?.hostUrl)
191
+ return { ok: true }
192
+
193
+ const draftKey = `drafts/people-profile/${context.workspaceId ?? 'app'}`
194
+ const workspaceRef = context.workspaceId ?? 'app'
195
+ const client = createSoulAppClient({ appId: hrSoulAppManifest.id, baseUrl: context.hostUrl })
196
+ try {
197
+ await client.broker.storage.put(draftKey, {
198
+ appId: hrSoulAppManifest.id,
199
+ kind: 'people-profile',
200
+ source: 'hr-mounted-action',
201
+ status: 'draft',
202
+ workspaceId: context.workspaceId ?? null,
203
+ }, brokerScope(context))
204
+ await client.broker.search.upsert(draftKey, {
205
+ kind: 'people-profile',
206
+ reference: {
207
+ id: workspaceRef,
208
+ type: context.workspaceId ? 'workspace' : 'app',
209
+ },
210
+ sessionId: context.sessionId ?? null,
211
+ summary: `HR app-owned people profile draft for workspace ${workspaceRef}.`,
212
+ title: 'People profile draft',
213
+ workspaceId: context.workspaceId ?? null,
214
+ }, brokerScope(context))
215
+ return { ok: true }
216
+ }
217
+ catch (error) {
218
+ return {
219
+ message: error instanceof Error ? error.message : String(error),
220
+ ok: false,
221
+ }
222
+ }
223
+ }
224
+
225
+ async function hrProtocolSearch(request: Request, url: URL) {
226
+ const query = url.searchParams.get('query') ?? ''
227
+ const brokerItems = await queryBrokerPeopleProfileSearch(request, query)
228
+ if (brokerItems?.length) {
229
+ return {
230
+ items: brokerItems,
231
+ providerId: 'peopleProfiles.search',
232
+ }
233
+ }
234
+
235
+ return {
236
+ items: [{
237
+ appId: hrSoulAppManifest.id,
238
+ authority: 'soul-app' as const,
239
+ id: 'people-profile-draft',
240
+ kind: 'people-profile',
241
+ openAction: {
242
+ id: 'create-people-profile',
243
+ input: { query },
244
+ },
245
+ status: 'draft',
246
+ summary: query ? `HR app-owned profile match for ${query}` : 'Open HR profile workspace',
247
+ title: query ? `People profile: ${query}` : 'People profile draft',
248
+ }],
249
+ providerId: 'peopleProfiles.search',
250
+ }
251
+ }
252
+
253
+ async function queryBrokerPeopleProfileSearch(request: Request, query: string): Promise<Array<Record<string, unknown>> | null> {
254
+ const context = readMountContext(request)
255
+ if (!context?.hostUrl)
256
+ return null
257
+
258
+ const client = createSoulAppClient({ appId: hrSoulAppManifest.id, baseUrl: context.hostUrl })
259
+ try {
260
+ const result = await client.broker.search.query(query, brokerScope(context)) as BrokerSearchResult
261
+ return Array.isArray(result.items) ? result.items : null
262
+ }
263
+ catch {
264
+ return null
265
+ }
266
+ }
267
+
268
+ function readMountContext(request: Request): MountContext | null {
269
+ const payload = request.headers.get('x-aiworker-mount-context')
270
+ if (!payload)
271
+ return null
272
+ try {
273
+ const parsed = JSON.parse(Buffer.from(payload, 'base64url').toString('utf8')) as unknown
274
+ if (!isRecord(parsed))
275
+ return null
276
+ const surface = isRecord(parsed.surface) ? parsed.surface : null
277
+ return {
278
+ brokerUrl: typeof parsed.brokerUrl === 'string' ? parsed.brokerUrl : undefined,
279
+ hostUrl: request.headers.get('x-aiworker-host-url') ?? undefined,
280
+ operatorId: typeof parsed.operatorId === 'string' ? parsed.operatorId : null,
281
+ sessionId: typeof parsed.sessionId === 'string' ? parsed.sessionId : null,
282
+ surface: surface
283
+ ? {
284
+ id: typeof surface.id === 'string' ? surface.id : undefined,
285
+ scope: typeof surface.scope === 'string' ? surface.scope : undefined,
286
+ }
287
+ : undefined,
288
+ workerId: typeof parsed.workerId === 'string' ? parsed.workerId : null,
289
+ workspaceId: typeof parsed.workspaceId === 'string' ? parsed.workspaceId : null,
290
+ }
291
+ }
292
+ catch {
293
+ return null
294
+ }
295
+ }
296
+
297
+ function brokerScope(context: MountContext) {
298
+ return {
299
+ operatorId: context.operatorId ?? undefined,
300
+ sessionId: context.sessionId ?? undefined,
301
+ workerId: context.workerId ?? undefined,
302
+ workspaceId: context.workspaceId ?? undefined,
303
+ }
304
+ }
305
+
306
+ function isRecord(value: unknown): value is Record<string, unknown> {
307
+ return typeof value === 'object' && value !== null && !Array.isArray(value)
308
+ }
@@ -0,0 +1,152 @@
1
+ import type {
2
+ SoulAppArtifactValidationResult,
3
+ SoulAppCapability,
4
+ SoulAppDefinition,
5
+ SoulAppProtocolResult,
6
+ SoulAppScopedContext,
7
+ SoulAppSessionContext,
8
+ } from '@zonease/aiworker-soul-app-sdk'
9
+
10
+ import { createSoulAppManifest, defineSoulApp, parseNamespacedSoulAppCapabilityId } from '@zonease/aiworker-soul-app-sdk'
11
+
12
+ import manifestJson from '../soul-app.manifest.json' with { type: 'json' }
13
+
14
+ export const hrSoulAppManifest = createSoulAppManifest(manifestJson)
15
+
16
+ export const HR_REFERENCE_APP_BOUNDARY = {
17
+ hostMountedEntry: './src/host-mounted.ts',
18
+ packageName: '@zonease/aiworker-hr',
19
+ primaryWorkbench: 'People/Profile Workbench',
20
+ standaloneEntry: './src/standalone.ts',
21
+ } as const
22
+
23
+ export const hrReferenceSoulApp: SoulAppDefinition = defineSoulApp({
24
+ artifact: {
25
+ async artifactSchemas() {
26
+ return hrSoulAppManifest.artifactTypes
27
+ },
28
+ async extractMetadata(_context, artifact) {
29
+ return {
30
+ appId: hrSoulAppManifest.id,
31
+ contentRef: artifact.contentRef,
32
+ kind: artifact.type,
33
+ lifecycle: artifact.type === 'person-profile' ? 'people-profile' : 'recruiting',
34
+ }
35
+ },
36
+ async validateArtifact(_context, artifact) {
37
+ return validateArtifactType(artifact.type)
38
+ },
39
+ },
40
+ connector: {
41
+ async declareConnectorNeeds() {
42
+ return [
43
+ ...hrSoulAppManifest.connectors.required,
44
+ ...hrSoulAppManifest.connectors.optional,
45
+ ]
46
+ },
47
+ },
48
+ lifecycle: lifecycleHandlers('HR reference app ready.'),
49
+ manifest: hrSoulAppManifest,
50
+ review: {
51
+ async createReviewRubric(_context, artifactType) {
52
+ return {
53
+ checks: [
54
+ `Artifact type ${artifactType} cites source evidence.`,
55
+ 'Missing candidate or employee facts are explicit.',
56
+ 'Human review notes separate risks, next actions, and memory candidates.',
57
+ ],
58
+ policyRef: hrSoulAppManifest.artifactTypes.find(type => type.id === artifactType)?.reviewPolicyRef,
59
+ }
60
+ },
61
+ async proposeMemoryCandidate(context, review) {
62
+ return {
63
+ evidence: [{
64
+ appId: context.appId,
65
+ artifactId: review.artifactId,
66
+ reviewId: review.reviewId,
67
+ source: 'hr-reference-app',
68
+ }],
69
+ statement: 'Promote reviewed HR evidence handling guidance into the HR Soul namespace.',
70
+ }
71
+ },
72
+ },
73
+ runtime: {
74
+ async prepareSessionContext(context, input) {
75
+ const capability = resolveHrCapability(input.capabilityId)
76
+ return sessionContext(context, capability, input.workspaceType)
77
+ },
78
+ async resolveCapability(_context, input) {
79
+ return resolveHrCapability(input.capabilityId ?? input.intent)
80
+ },
81
+ },
82
+ ui: {
83
+ async artifactTypes() {
84
+ return hrSoulAppManifest.artifactTypes
85
+ },
86
+ async capabilities() {
87
+ return hrSoulAppManifest.capabilities
88
+ },
89
+ async ui() {
90
+ return hrSoulAppManifest.ui
91
+ },
92
+ async workspaceTypes() {
93
+ return hrSoulAppManifest.workspaceTypes
94
+ },
95
+ },
96
+ })
97
+
98
+ function resolveHrCapability(input?: string): SoulAppCapability {
99
+ const id = normalizeCapabilityId(input) ?? hrSoulAppManifest.capabilities[0]!.id
100
+ const capability = hrSoulAppManifest.capabilities.find(item => item.id === id)
101
+ if (!capability)
102
+ throw new Error(`HR capability not found: ${input}`)
103
+ return capability
104
+ }
105
+
106
+ function normalizeCapabilityId(input?: string): string | null {
107
+ if (!input)
108
+ return null
109
+ return parseNamespacedSoulAppCapabilityId(input)?.capabilityId ?? input
110
+ }
111
+
112
+ function sessionContext(context: SoulAppScopedContext, capability: SoulAppCapability, workspaceType: string): SoulAppSessionContext {
113
+ return {
114
+ artifactTypes: capability.artifactTypes,
115
+ capabilityId: capability.id,
116
+ contextMarkdown: [
117
+ '# HR Soul App Context',
118
+ `App: ${context.appId}`,
119
+ `Workspace type: ${workspaceType}`,
120
+ 'Use people-profile, candidate-screen, review notes, and source-backed evidence language.',
121
+ ].join('\n'),
122
+ promptFragments: [
123
+ `Use HR capability ${capability.name}.`,
124
+ 'Preserve candidate or employee evidence provenance and mark missing facts.',
125
+ 'Return a reviewable HR business artifact, not a generic chat answer.',
126
+ ],
127
+ reviewRubric: [
128
+ 'Evidence is source-backed.',
129
+ 'Risk and missing evidence are separated.',
130
+ 'Next action is concrete for a human HR reviewer.',
131
+ ],
132
+ }
133
+ }
134
+
135
+ function validateArtifactType(type: string): SoulAppArtifactValidationResult {
136
+ const known = hrSoulAppManifest.artifactTypes.some(item => item.id === type)
137
+ return {
138
+ issues: known ? [] : [{ message: `Unknown HR artifact type: ${type}`, severity: 'error' }],
139
+ ok: known,
140
+ }
141
+ }
142
+
143
+ function lifecycleHandlers(message: string) {
144
+ const ok = async (): Promise<SoulAppProtocolResult> => ({ message, ok: true })
145
+ return {
146
+ disable: ok,
147
+ enable: ok,
148
+ healthcheck: ok,
149
+ install: ok,
150
+ upgrade: ok,
151
+ }
152
+ }
@@ -0,0 +1,2 @@
1
+ export const protocolSurface = 'artifact'
2
+ export { hrReferenceSoulApp as soulApp } from '../index'
@@ -0,0 +1,2 @@
1
+ export const protocolSurface = 'connectors'
2
+ export { hrReferenceSoulApp as soulApp } from '../index'
@@ -0,0 +1,2 @@
1
+ export const protocolSurface = 'lifecycle'
2
+ export { hrReferenceSoulApp as soulApp } from '../index'
@@ -0,0 +1,2 @@
1
+ export const protocolSurface = 'review'
2
+ export { hrReferenceSoulApp as soulApp } from '../index'
@@ -0,0 +1,2 @@
1
+ export const protocolSurface = 'runtime'
2
+ export { hrReferenceSoulApp as soulApp } from '../index'
@@ -0,0 +1,2 @@
1
+ export const protocolSurface = 'ui'
2
+ export { hrReferenceSoulApp as soulApp } from '../index'
@@ -0,0 +1,43 @@
1
+ import process from 'node:process'
2
+
3
+ import { hrSoulAppManifest } from './index'
4
+
5
+ export function renderStandaloneHtml(): string {
6
+ return [
7
+ '<!doctype html>',
8
+ '<html lang="en">',
9
+ '<head><meta charset="utf-8"><title>AIWorker HR</title></head>',
10
+ `<body data-soul-app-id="${hrSoulAppManifest.id}">`,
11
+ '<main>',
12
+ `<h1>${hrSoulAppManifest.name}</h1>`,
13
+ `<p>${hrSoulAppManifest.description}</p>`,
14
+ '</main>',
15
+ '</body>',
16
+ '</html>',
17
+ ].join('')
18
+ }
19
+
20
+ export function serveStandalone(port = Number(Bun.env.PORT ?? 0)) {
21
+ return Bun.serve({
22
+ fetch(request) {
23
+ const url = new URL(request.url)
24
+ if (url.pathname === '/health') {
25
+ return Response.json({
26
+ appId: hrSoulAppManifest.id,
27
+ mode: 'standalone',
28
+ status: 'ok',
29
+ })
30
+ }
31
+ return new Response(renderStandaloneHtml(), {
32
+ headers: { 'content-type': 'text/html; charset=utf-8' },
33
+ })
34
+ },
35
+ hostname: Bun.env.HOST ?? '127.0.0.1',
36
+ port,
37
+ })
38
+ }
39
+
40
+ if (import.meta.main) {
41
+ const server = serveStandalone()
42
+ process.stdout.write(`${JSON.stringify({ appId: hrSoulAppManifest.id, mode: 'standalone', url: `http://${server.hostname}:${server.port}` })}\n`)
43
+ }
@@ -0,0 +1,2 @@
1
+ export const artifactPreviewId = 'candidate-screen'
2
+ export const artifactPreviewLabel = 'Candidate Screen'
@@ -0,0 +1 @@
1
+ export const routeId = 'hr-home'
@@ -0,0 +1 @@
1
+ export const widgetId = 'hr-people-widget'
@@ -0,0 +1,2 @@
1
+ export const artifactPreviewId = 'person-profile'
2
+ export const artifactPreviewLabel = 'Person Profile'
@@ -0,0 +1 @@
1
+ export const panelId = 'hr-profile-panel'
@@ -0,0 +1 @@
1
+ export const panelId = 'hr-review-panel'
@@ -0,0 +1,20 @@
1
+ {
2
+ "extends": "../../tsconfig.json",
3
+ "compilerOptions": {
4
+ "paths": {
5
+ "@/*": [
6
+ "./src/*"
7
+ ]
8
+ },
9
+ "types": [
10
+ "@types/bun"
11
+ ]
12
+ },
13
+ "include": [
14
+ "src/**/*.ts"
15
+ ],
16
+ "exclude": [
17
+ "node_modules",
18
+ "dist"
19
+ ]
20
+ }
@@ -0,0 +1,14 @@
1
+ # AIWorker QA Reference Soul App
2
+
3
+ `@zonease/aiworker-qa` is the reference QA Soul App workspace. It owns the QA
4
+ manifest, protocol handlers, standalone service, Host-mounted service, schemas,
5
+ capabilities, review policy, and release-focused app definition for regression
6
+ matrices, defect evidence, and release gate review.
7
+
8
+ The app depends on the Soul App SDK only. It does not import Host API, CLI,
9
+ Worker Web private modules, raw DB handles, engine adapters, connector tokens,
10
+ vault internals, or sibling Soul Apps.
11
+
12
+ The app is intentionally different from HR: QA workspaces are release/test-suite
13
+ oriented, and its primary artifact is a release gate decision with explicit
14
+ test evidence and residual risk.
@@ -0,0 +1,3 @@
1
+ # Regression Matrix
2
+
3
+ Use AIWorker QA domain evidence to create a reviewable regression-matrix artifact. Keep provenance, missing facts, risks, and next actions explicit.
@@ -0,0 +1,5 @@
1
+ # Regression Matrix Review Rubric
2
+
3
+ - Evidence references are present.
4
+ - Missing information is explicit.
5
+ - Risks and next actions are concrete.
@@ -0,0 +1,3 @@
1
+ # Release Gate
2
+
3
+ Use AIWorker QA domain evidence to create a reviewable release-gate artifact. Keep provenance, missing facts, risks, and next actions explicit.
@@ -0,0 +1,5 @@
1
+ # Release Gate Review Rubric
2
+
3
+ - Evidence references are present.
4
+ - Missing information is explicit.
5
+ - Risks and next actions are concrete.