@eduwork/dsh-oidc 0.1.0-alpha.11 → 0.2.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 (72) hide show
  1. package/CHANGELOG.en.md +58 -1
  2. package/CHANGELOG.md +58 -1
  3. package/CODE_OF_CONDUCT.en.md +17 -0
  4. package/CODE_OF_CONDUCT.md +17 -0
  5. package/CONTRIBUTING.en.md +56 -0
  6. package/CONTRIBUTING.md +56 -0
  7. package/GOVERNANCE.en.md +41 -0
  8. package/GOVERNANCE.md +41 -0
  9. package/MAINTAINERS.en.md +13 -0
  10. package/MAINTAINERS.md +13 -0
  11. package/README.en.md +24 -22
  12. package/README.md +18 -16
  13. package/SECURITY.en.md +45 -0
  14. package/SECURITY.md +45 -0
  15. package/SUPPORT.en.md +15 -0
  16. package/SUPPORT.md +15 -0
  17. package/THIRD_PARTY_NOTICES.en.md +7 -5
  18. package/THIRD_PARTY_NOTICES.md +7 -5
  19. package/cordis.patch.yml +2 -1
  20. package/docs/EDUWORK-MIGRATION.en.md +17 -5
  21. package/docs/EDUWORK-MIGRATION.md +17 -5
  22. package/docs/account-extensions.en.md +40 -0
  23. package/docs/account-extensions.md +42 -0
  24. package/docs/architecture.en.md +9 -9
  25. package/docs/architecture.md +11 -10
  26. package/docs/compatibility.en.md +13 -3
  27. package/docs/compatibility.md +13 -3
  28. package/docs/decisions/0001-one-plugin-composition-boundary.en.md +1 -1
  29. package/docs/decisions/0001-one-plugin-composition-boundary.md +1 -1
  30. package/docs/desktop-host.en.md +69 -0
  31. package/docs/desktop-host.md +79 -0
  32. package/docs/development.en.md +42 -0
  33. package/docs/development.md +42 -0
  34. package/docs/dsh-integration.en.md +24 -8
  35. package/docs/dsh-integration.md +24 -8
  36. package/docs/ecnu-reference.en.md +3 -3
  37. package/docs/ecnu-reference.md +3 -3
  38. package/docs/enterprise-profile.en.md +21 -13
  39. package/docs/enterprise-profile.md +20 -12
  40. package/docs/getting-started.en.md +13 -17
  41. package/docs/getting-started.md +17 -19
  42. package/docs/key-binding-protocol.en.md +2 -2
  43. package/docs/key-binding-protocol.md +2 -2
  44. package/docs/oidc-interoperability.en.md +3 -3
  45. package/docs/oidc-interoperability.md +2 -2
  46. package/docs/public-resource-protocol.en.md +51 -0
  47. package/docs/public-resource-protocol.md +50 -0
  48. package/docs/release-checklist.en.md +13 -8
  49. package/docs/release-checklist.md +13 -8
  50. package/docs/server-integration-contract.en.md +124 -8
  51. package/docs/server-integration-contract.md +136 -8
  52. package/examples/ecnu.enterprise-profile.example.json +2 -2
  53. package/examples/enterprise-profile.example.json +78 -77
  54. package/examples/identity-only.example.json +10 -0
  55. package/examples/resources-discovery.example.json +20 -0
  56. package/lib/callback-page.js +42 -0
  57. package/lib/client.js +938 -294
  58. package/lib/desktop-oidc.js +205 -0
  59. package/lib/index.js +148 -18
  60. package/lib/oidc.js +314 -58
  61. package/lib/profile.js +96 -39
  62. package/lib/provider/core.js +76 -15
  63. package/lib/provider/index.js +54 -22
  64. package/lib/provider/transform-adapter.js +32 -11
  65. package/lib/resources.js +23 -0
  66. package/lib/typert-schemas.js +34 -3
  67. package/lib/typert.host.js +42 -36
  68. package/lib/typert.remote-client.js +41 -35
  69. package/package.json +117 -23
  70. package/protocol/openapi.yaml +2 -2
  71. package/protocol/resources.openapi.yaml +51 -0
  72. package/schema/enterprise-profile.v1alpha1.schema.json +193 -174
@@ -0,0 +1,23 @@
1
+ import { normalizeModels } from './profile.js'
2
+
3
+ // The public resource contract extends the deployed worker wire protocol. OIDC
4
+ // access tokens remain on the management plane; these calls use the model key.
5
+ export function normalizeResourceModels(raw, profile) {
6
+ if (!Array.isArray(raw?.data) || raw.data.length > 128) throw new Error('invalid model catalog')
7
+ const reviewed = new Map(profile.provider.models.map(model => [model.id, model]))
8
+ const models = raw.data.map(row => {
9
+ const id = typeof row?.id === 'string' ? row.id.trim() : ''
10
+ // A plain /models response does not prove reasoning or vision support.
11
+ return reviewed.get(id) ?? { id, name: id, input: ['text'], reasoning: false }
12
+ })
13
+ return normalizeModels(models, profile.provider.id)
14
+ }
15
+
16
+ export function emptyResources(profile) {
17
+ return {
18
+ profileID: profile.id,
19
+ modelSource: profile.provider?.modelSource ?? 'none',
20
+ models: profile.provider?.models ?? [],
21
+ issues: [],
22
+ }
23
+ }
@@ -2,9 +2,20 @@ import { z } from 'zod'
2
2
 
3
3
  const pkg = '@eduwork/dsh-oidc'
4
4
  export const profileIdSchema = z.string().min(1).max(64)
5
+ export const loginIdSchema = z.string().regex(/^[A-Za-z0-9_-]{32}$/)
5
6
  export const reconcileOptionsSchema = z.object({ allowProvision: z.boolean().optional() }).strict()
6
7
  export const baseURLSchema = z.string().min(1).max(2048)
7
8
  export const modelCatalogModeSchema = z.enum(['discovery', 'manual'])
9
+ export const configurationTargetSchema = z.enum(['config', 'examples'])
10
+ export const openConfigurationResult = Object.freeze({
11
+ mode: 'strict', typeSymbol: `${pkg}#OpenConfigurationResult`,
12
+ schema: z.object({ opened: z.literal(true) }).strict(),
13
+ })
14
+ export const enterpriseSelectionResult = Object.freeze({
15
+ mode: 'strict', typeSymbol: `${pkg}#EnterpriseSelectionResult`,
16
+ schema: z.object({ changed: z.boolean(), selection: z.object({ provider: z.string(), model: z.string(), reasoningEffort: z.string().optional() }).strict().optional() }).strict(),
17
+ })
18
+ export const enterpriseSelectionOptionsSchema = z.object({ onlyIfMissing: z.boolean().optional() }).strict()
8
19
 
9
20
  const brandSchema = z.object({
10
21
  productName: z.string().optional(), organizationName: z.string().optional(), mark: z.string().optional(),
@@ -18,7 +29,7 @@ const publicProfileSchema = z.object({
18
29
  provider: z.object({
19
30
  id: z.string(), displayName: z.string(),
20
31
  models: z.array(z.object({ id: z.string(), name: z.string(), input: z.array(z.enum(['text', 'image'])) }).strict()),
21
- }).strict(),
32
+ }).strict().optional(),
22
33
  }).strict()
23
34
 
24
35
  const accountSchema = z.object({
@@ -33,12 +44,20 @@ export const runtimeModelSchema = z.object({
33
44
  upstreamModelID: z.string().max(256).optional(), contextWindow: z.number().int().positive().optional(),
34
45
  maxTokens: z.number().int().positive().optional(),
35
46
  input: z.array(z.enum(['text', 'image', 'audio', 'video'])).optional(),
36
- reasoning: z.boolean().optional(), reasoningEfforts: z.record(z.string(), z.string().nullable()).optional(),
47
+ reasoning: z.boolean().optional(), reasoningEfforts: z.union([z.literal(false), z.record(z.string(), z.string().nullable())]).optional(),
48
+ defaultReasoningEffort: z.enum(['off', 'minimal', 'low', 'medium', 'high', 'xhigh', 'max']).optional(),
37
49
  compat: z.record(z.string(), z.unknown()).optional(),
38
50
  }).strict()
39
51
 
40
52
  export const runtimeModelsSchema = z.array(runtimeModelSchema).max(128)
41
53
 
54
+ export const resourcesResult = Object.freeze({
55
+ mode: 'strict', typeSymbol: `${pkg}#Resources`,
56
+ schema: z.object({
57
+ profileID: z.string(), modelSource: z.string(), models: runtimeModelsSchema, issues: z.array(z.string()),
58
+ }).strict(),
59
+ })
60
+
42
61
  const managementProfileSchema = z.object({
43
62
  id: z.string(), displayName: z.string(), organization: z.string(), baseURL: z.string(),
44
63
  builtIn: z.boolean(), configured: z.boolean(), enabled: z.boolean(), providerID: z.string(),
@@ -51,7 +70,9 @@ const managementProfileSchema = z.object({
51
70
 
52
71
  export const configurationResult = Object.freeze({
53
72
  mode: 'strict', typeSymbol: `${pkg}#Configuration`,
54
- schema: z.object({ schemaVersion: z.literal('dsh-oidc/v1alpha1'), uiMode: z.enum(['standard', 'models-only', 'external']), profiles: z.array(publicProfileSchema) }).strict(),
73
+ schema: z.object({ schemaVersion: z.literal('dsh-oidc/v1alpha1'), uiMode: z.enum(['standard', 'models-only', 'external']), profiles: z.array(publicProfileSchema),
74
+ manageProductBrand: z.boolean().optional(), configFile: z.object({ path: z.string(), examplesPath: z.string(), canOpen: z.boolean() }).strict().optional(),
75
+ }).strict(),
55
76
  })
56
77
 
57
78
  export const managementResult = Object.freeze({
@@ -76,9 +97,19 @@ export const beginResult = Object.freeze({
76
97
  schema: z.union([
77
98
  z.object({ mode: z.literal('redirect'), authorizationURL: z.string().url() }).strict(),
78
99
  z.object({ mode: z.literal('completed'), status: accountSchema }).strict(),
100
+ z.object({ mode: z.literal('external'), loginID: loginIdSchema, expiresAt: z.string().datetime() }).strict(),
79
101
  ]),
80
102
  })
81
103
 
104
+ export const loginResult = Object.freeze({
105
+ mode: 'strict', typeSymbol: `${pkg}#LoginResult`,
106
+ schema: z.object({
107
+ loginID: loginIdSchema, profileID: profileIdSchema, expiresAt: z.string().datetime(),
108
+ state: z.enum(['pending', 'completed', 'cancelled', 'expired', 'failed']),
109
+ status: accountSchema.optional(), errorCode: z.string().optional(),
110
+ }).strict(),
111
+ })
112
+
82
113
  export function jsonParameter(name, schema, typeSymbol) {
83
114
  return Object.freeze({ name, wire: name, source: 'json', codec: Object.freeze({ mode: 'strict', typeSymbol, schema }) })
84
115
  }
@@ -1,38 +1,44 @@
1
- import {
2
- accountResult, baseURLSchema, beginResult, configurationResult, jsonParameter, managementResult,
3
- modelCatalogModeSchema, profileIdSchema, reconcileOptionsSchema, restartResult, runtimeModelsSchema,
4
- } from './typert-schemas.js'
5
-
6
- const pkg = '@eduwork/dsh-oidc'
7
- const source = { file: 'lib/index.js', line: 1, column: 1 }
8
- const profile = () => jsonParameter('profileID', profileIdSchema, `${pkg}#ProfileID`)
9
- const options = () => jsonParameter('options', reconcileOptionsSchema, `${pkg}#ReconcileOptions`)
10
- const baseURL = () => jsonParameter('baseURL', baseURLSchema, `${pkg}#BaseURL`)
11
- const modelMode = () => jsonParameter('modelMode', modelCatalogModeSchema, `${pkg}#ModelCatalogMode`)
12
- const models = () => jsonParameter('models', runtimeModelsSchema, `${pkg}#RuntimeModels`)
13
- const descriptor = (method, parameters, result) => ({
14
- id: `${pkg}#oidcAccounts/${method}`, service: 'oidcAccounts', namespace: 'oidcAccounts', method,
15
- invocation: { kind: 'direct' }, parameters, result, sourceLocation: source,
16
- })
17
-
18
- export const TYPERT = {
19
- package: pkg, face: 'host', schemas: [],
20
- invocations: [
1
+ import {
2
+ accountResult, baseURLSchema, beginResult, configurationResult, configurationTargetSchema, openConfigurationResult, jsonParameter, managementResult, loginIdSchema, loginResult,
3
+ modelCatalogModeSchema, profileIdSchema, reconcileOptionsSchema, restartResult, runtimeModelsSchema, resourcesResult, enterpriseSelectionResult, enterpriseSelectionOptionsSchema,
4
+ } from './typert-schemas.js'
5
+
6
+ const pkg = '@eduwork/dsh-oidc'
7
+ const source = { file: 'lib/index.js', line: 1, column: 1 }
8
+ const profile = () => jsonParameter('profileID', profileIdSchema, `${pkg}#ProfileID`)
9
+ const login = () => jsonParameter('loginID', loginIdSchema, `${pkg}#LoginID`)
10
+ const options = () => jsonParameter('options', reconcileOptionsSchema, `${pkg}#ReconcileOptions`)
11
+ const baseURL = () => jsonParameter('baseURL', baseURLSchema, `${pkg}#BaseURL`)
12
+ const modelMode = () => jsonParameter('modelMode', modelCatalogModeSchema, `${pkg}#ModelCatalogMode`)
13
+ const models = () => jsonParameter('models', runtimeModelsSchema, `${pkg}#RuntimeModels`)
14
+ const descriptor = (method, parameters, result) => ({
15
+ id: `${pkg}#oidcAccounts/${method}`, service: 'oidcAccounts', namespace: 'oidcAccounts', method,
16
+ invocation: { kind: 'direct' }, parameters, result, sourceLocation: source,
17
+ })
18
+
19
+ export const TYPERT = {
20
+ package: pkg, face: 'host', schemas: [],
21
+ invocations: [
21
22
  descriptor('configuration', [], configurationResult),
22
- descriptor('status', [profile()], accountResult),
23
- descriptor('begin', [profile()], beginResult),
23
+ descriptor('openConfiguration', [jsonParameter('target', configurationTargetSchema, `${pkg}#ConfigurationTarget`)], openConfigurationResult),
24
+ descriptor('status', [profile()], accountResult),
25
+ descriptor('resources', [profile()], resourcesResult),
26
+ descriptor('begin', [profile()], beginResult),
27
+ descriptor('loginStatus', [login()], loginResult),
28
+ descriptor('cancelLogin', [login()], loginResult),
24
29
  descriptor('reconcile', [profile(), options()], accountResult),
25
- descriptor('logout', [profile()], accountResult),
26
- descriptor('management', [], managementResult),
27
- descriptor('activate', [profile()], managementResult),
28
- descriptor('configure', [profile()], managementResult),
29
- descriptor('addCustom', [baseURL()], managementResult),
30
- descriptor('updateCustom', [profile(), baseURL()], managementResult),
31
- descriptor('removeProfile', [profile()], managementResult),
32
- descriptor('configureModels', [profile(), modelMode(), models()], managementResult),
33
- descriptor('restart', [], restartResult),
34
- ],
35
- model: { services: [], events: [], objects: [] },
36
- }
37
-
38
- export default TYPERT
30
+ descriptor('selectEnterpriseModel', [profile(), jsonParameter('options', enterpriseSelectionOptionsSchema, `${pkg}#EnterpriseSelectionOptions`)], enterpriseSelectionResult),
31
+ descriptor('logout', [profile()], accountResult),
32
+ descriptor('management', [], managementResult),
33
+ descriptor('activate', [profile()], managementResult),
34
+ descriptor('configure', [profile()], managementResult),
35
+ descriptor('addCustom', [baseURL()], managementResult),
36
+ descriptor('updateCustom', [profile(), baseURL()], managementResult),
37
+ descriptor('removeProfile', [profile()], managementResult),
38
+ descriptor('configureModels', [profile(), modelMode(), models()], managementResult),
39
+ descriptor('restart', [], restartResult),
40
+ ],
41
+ model: { services: [], events: [], objects: [] },
42
+ }
43
+
44
+ export default TYPERT
@@ -1,37 +1,43 @@
1
- import {
2
- accountResult, baseURLSchema, beginResult, configurationResult, jsonParameter, managementResult,
3
- modelCatalogModeSchema, profileIdSchema, reconcileOptionsSchema, restartResult, runtimeModelsSchema,
4
- } from './typert-schemas.js'
5
-
6
- const pkg = '@eduwork/dsh-oidc'
7
- const source = { file: 'lib/index.js', line: 1, column: 1 }
8
- const profile = () => jsonParameter('profileID', profileIdSchema, `${pkg}#ProfileID`)
9
- const options = () => jsonParameter('options', reconcileOptionsSchema, `${pkg}#ReconcileOptions`)
10
- const baseURL = () => jsonParameter('baseURL', baseURLSchema, `${pkg}#BaseURL`)
11
- const modelMode = () => jsonParameter('modelMode', modelCatalogModeSchema, `${pkg}#ModelCatalogMode`)
12
- const models = () => jsonParameter('models', runtimeModelsSchema, `${pkg}#RuntimeModels`)
13
- const descriptor = (method, parameters, result) => ({
14
- id: `${pkg}#oidcAccounts/${method}`, service: 'oidcAccounts', namespace: 'oidcAccounts', method,
15
- invocation: { kind: 'direct' }, parameters, result, sourceLocation: source,
16
- })
17
-
18
- export const TYPERT_REMOTE = {
19
- package: pkg,
20
- descriptors: [
1
+ import {
2
+ accountResult, baseURLSchema, beginResult, configurationResult, configurationTargetSchema, openConfigurationResult, jsonParameter, managementResult, loginIdSchema, loginResult,
3
+ modelCatalogModeSchema, profileIdSchema, reconcileOptionsSchema, restartResult, runtimeModelsSchema, resourcesResult, enterpriseSelectionResult, enterpriseSelectionOptionsSchema,
4
+ } from './typert-schemas.js'
5
+
6
+ const pkg = '@eduwork/dsh-oidc'
7
+ const source = { file: 'lib/index.js', line: 1, column: 1 }
8
+ const profile = () => jsonParameter('profileID', profileIdSchema, `${pkg}#ProfileID`)
9
+ const login = () => jsonParameter('loginID', loginIdSchema, `${pkg}#LoginID`)
10
+ const options = () => jsonParameter('options', reconcileOptionsSchema, `${pkg}#ReconcileOptions`)
11
+ const baseURL = () => jsonParameter('baseURL', baseURLSchema, `${pkg}#BaseURL`)
12
+ const modelMode = () => jsonParameter('modelMode', modelCatalogModeSchema, `${pkg}#ModelCatalogMode`)
13
+ const models = () => jsonParameter('models', runtimeModelsSchema, `${pkg}#RuntimeModels`)
14
+ const descriptor = (method, parameters, result) => ({
15
+ id: `${pkg}#oidcAccounts/${method}`, service: 'oidcAccounts', namespace: 'oidcAccounts', method,
16
+ invocation: { kind: 'direct' }, parameters, result, sourceLocation: source,
17
+ })
18
+
19
+ export const TYPERT_REMOTE = {
20
+ package: pkg,
21
+ descriptors: [
21
22
  descriptor('configuration', [], configurationResult),
22
- descriptor('status', [profile()], accountResult),
23
- descriptor('begin', [profile()], beginResult),
23
+ descriptor('openConfiguration', [jsonParameter('target', configurationTargetSchema, `${pkg}#ConfigurationTarget`)], openConfigurationResult),
24
+ descriptor('status', [profile()], accountResult),
25
+ descriptor('resources', [profile()], resourcesResult),
26
+ descriptor('begin', [profile()], beginResult),
27
+ descriptor('loginStatus', [login()], loginResult),
28
+ descriptor('cancelLogin', [login()], loginResult),
24
29
  descriptor('reconcile', [profile(), options()], accountResult),
25
- descriptor('logout', [profile()], accountResult),
26
- descriptor('management', [], managementResult),
27
- descriptor('activate', [profile()], managementResult),
28
- descriptor('configure', [profile()], managementResult),
29
- descriptor('addCustom', [baseURL()], managementResult),
30
- descriptor('updateCustom', [profile(), baseURL()], managementResult),
31
- descriptor('removeProfile', [profile()], managementResult),
32
- descriptor('configureModels', [profile(), modelMode(), models()], managementResult),
33
- descriptor('restart', [], restartResult),
34
- ],
35
- }
36
-
37
- export default TYPERT_REMOTE
30
+ descriptor('selectEnterpriseModel', [profile(), jsonParameter('options', enterpriseSelectionOptionsSchema, `${pkg}#EnterpriseSelectionOptions`)], enterpriseSelectionResult),
31
+ descriptor('logout', [profile()], accountResult),
32
+ descriptor('management', [], managementResult),
33
+ descriptor('activate', [profile()], managementResult),
34
+ descriptor('configure', [profile()], managementResult),
35
+ descriptor('addCustom', [baseURL()], managementResult),
36
+ descriptor('updateCustom', [profile(), baseURL()], managementResult),
37
+ descriptor('removeProfile', [profile()], managementResult),
38
+ descriptor('configureModels', [profile(), modelMode(), models()], managementResult),
39
+ descriptor('restart', [], restartResult),
40
+ ],
41
+ }
42
+
43
+ export default TYPERT_REMOTE
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eduwork/dsh-oidc",
3
- "version": "0.1.0-alpha.11",
3
+ "version": "0.2.0",
4
4
  "description": "Standards-based OIDC identity, enterprise API-key binding, declarative branding, and OpenAI-compatible model integration for DeepSeek Harness",
5
5
  "keywords": [
6
6
  "deepseek-harness",
@@ -31,8 +31,21 @@
31
31
  "examples/**/*.json",
32
32
  "schema/**/*.json",
33
33
  "protocol/openapi.yaml",
34
+ "protocol/resources.openapi.yaml",
34
35
  "README.md",
35
36
  "README.en.md",
37
+ "CODE_OF_CONDUCT.md",
38
+ "CODE_OF_CONDUCT.en.md",
39
+ "CONTRIBUTING.md",
40
+ "CONTRIBUTING.en.md",
41
+ "GOVERNANCE.md",
42
+ "GOVERNANCE.en.md",
43
+ "MAINTAINERS.md",
44
+ "MAINTAINERS.en.md",
45
+ "SECURITY.md",
46
+ "SECURITY.en.md",
47
+ "SUPPORT.md",
48
+ "SUPPORT.en.md",
36
49
  "LICENSE",
37
50
  "THIRD_PARTY_NOTICES.md",
38
51
  "THIRD_PARTY_NOTICES.en.md",
@@ -49,6 +62,7 @@
49
62
  "@deepseek-ai/dsh-api-remotes",
50
63
  "@deepseek-ai/dsh-client-ui-conversation",
51
64
  "@deepseek-ai/dsh-client-ui-settings",
65
+ "@deepseek-ai/dsh-client-ui-settings-general",
52
66
  "@deepseek-ai/dsh-client-ui-settings-models",
53
67
  "@deepseek-ai/dsh-client-ui-sidebar",
54
68
  "@deepseek-ai/dsh-client-ui-theme"
@@ -62,22 +76,24 @@
62
76
  "build:client": "tsdown",
63
77
  "build": "npm run build:host && npm run build:client",
64
78
  "typecheck": "tsc --noEmit",
65
- "test": "node --test",
66
- "test:coverage": "node --test --experimental-test-coverage",
79
+ "test": "node --test \"test/*.test.js\"",
80
+ "test:coverage": "node --test --experimental-test-coverage \"test/*.test.js\"",
67
81
  "check:schemas": "node scripts/check-schemas.mjs",
68
82
  "check:secrets": "node scripts/check-secrets.mjs",
69
83
  "check:licenses": "node scripts/check-licenses.mjs",
70
84
  "check:docs": "node scripts/check-doc-links.mjs",
85
+ "check:dsh": "npm run check:lock && node scripts/check-dsh-rc1.mjs",
71
86
  "check:build": "node scripts/smoke-build.mjs",
72
- "check": "npm run typecheck && npm run build && npm run check:build && npm test && npm run check:schemas && npm run check:docs && npm run check:secrets && npm run check:licenses && npm pack --dry-run",
73
- "prepare": "npm run build"
87
+ "check": "npm run typecheck && npm run check:dsh && npm run build && npm run check:build && npm test && npm run check:schemas && npm run check:docs && npm run check:secrets && npm run check:licenses && npm pack --dry-run",
88
+ "prepare": "npm run build",
89
+ "check:browser": "node scripts/check-account-menu-browser.mjs",
90
+ "check:lock": "node scripts/check-dependency-lock.mjs"
74
91
  },
75
92
  "engines": {
76
93
  "node": ">=22.0.0"
77
94
  },
78
95
  "publishConfig": {
79
- "access": "public",
80
- "provenance": true
96
+ "access": "public"
81
97
  },
82
98
  "repository": {
83
99
  "type": "git",
@@ -93,26 +109,104 @@
93
109
  },
94
110
  "peerDependencies": {
95
111
  "@deepseek-ai/cordis": "4.0.2",
96
- "@deepseek-ai/dsh-api-remotes": "0.1.2-alpha.2",
97
- "@deepseek-ai/dsh-client-ui-renderer": "0.1.2-alpha.2",
98
- "@deepseek-ai/dsh-client-ui-conversation": "0.1.2-alpha.2",
99
- "@deepseek-ai/dsh-client-ui-settings": "0.1.2-alpha.2",
100
- "@deepseek-ai/dsh-client-ui-settings-models": "0.1.2-alpha.2",
101
- "@deepseek-ai/dsh-client-ui-sidebar": "0.1.2-alpha.2",
102
- "@deepseek-ai/dsh-client-ui-theme": "0.1.2-alpha.2",
103
- "@deepseek-ai/dsh-credentials": "0.1.2-alpha.2",
104
- "@deepseek-ai/dsh-host-webserver": "0.1.2-alpha.2",
105
- "@deepseek-ai/dsh-launch-environment": "0.1.2-alpha.2",
106
- "@deepseek-ai/dsh-llm": "0.1.2-alpha.2",
107
- "@deepseek-ai/dsh-llm-pi-ai": "0.1.2-alpha.2",
108
- "@deepseek-ai/dsh-settings": "0.1.2-alpha.2",
109
- "@deepseek-ai/dsh-typert-protocol": "0.1.2-alpha.2",
110
- "@earendil-works/pi-ai": "^0.84.2",
111
- "react": "^18.2.0"
112
+ "@deepseek-ai/dsh-api-remotes": "0.1.2-rc.1 || 0.1.3-alpha.1 || 0.1.3-alpha.2 || 0.1.5-alpha.1 || 0.1.5-rc.1",
113
+ "@deepseek-ai/dsh-attachment": "0.1.2-rc.1 || 0.1.3-alpha.1 || 0.1.3-alpha.2 || 0.1.5-alpha.1 || 0.1.5-rc.1",
114
+ "@deepseek-ai/dsh-authorization": "0.1.2-rc.1 || 0.1.3-alpha.1 || 0.1.3-alpha.2 || 0.1.5-alpha.1 || 0.1.5-rc.1",
115
+ "@deepseek-ai/dsh-brand": "0.1.2-rc.1 || 0.1.3-alpha.1 || 0.1.3-alpha.2 || 0.1.5-alpha.1 || 0.1.5-rc.1",
116
+ "@deepseek-ai/dsh-client-ui-conversation": "0.1.2-rc.1 || 0.1.3-alpha.1 || 0.1.3-alpha.2 || 0.1.5-alpha.1 || 0.1.5-rc.1",
117
+ "@deepseek-ai/dsh-client-ui-renderer": "0.1.2-rc.1 || 0.1.3-alpha.1 || 0.1.3-alpha.2 || 0.1.5-alpha.1 || 0.1.5-rc.1",
118
+ "@deepseek-ai/dsh-client-ui-settings": "0.1.2-rc.1 || 0.1.3-alpha.1 || 0.1.3-alpha.2 || 0.1.5-alpha.1 || 0.1.5-rc.1",
119
+ "@deepseek-ai/dsh-client-ui-settings-general": "0.1.2-rc.1 || 0.1.3-alpha.1 || 0.1.3-alpha.2 || 0.1.5-alpha.1 || 0.1.5-rc.1",
120
+ "@deepseek-ai/dsh-client-ui-settings-models": "0.1.2-rc.1 || 0.1.3-alpha.1 || 0.1.3-alpha.2 || 0.1.5-alpha.1 || 0.1.5-rc.1",
121
+ "@deepseek-ai/dsh-client-ui-sidebar": "0.1.2-rc.1 || 0.1.3-alpha.1 || 0.1.3-alpha.2 || 0.1.5-alpha.1 || 0.1.5-rc.1",
122
+ "@deepseek-ai/dsh-client-ui-theme": "0.1.2-rc.1 || 0.1.3-alpha.1 || 0.1.3-alpha.2 || 0.1.5-alpha.1 || 0.1.5-rc.1",
123
+ "@deepseek-ai/dsh-credentials": "0.1.2-rc.1 || 0.1.3-alpha.1 || 0.1.3-alpha.2 || 0.1.5-alpha.1 || 0.1.5-rc.1",
124
+ "@deepseek-ai/dsh-fs": "0.1.2-rc.1 || 0.1.3-alpha.1 || 0.1.3-alpha.2 || 0.1.5-alpha.1 || 0.1.5-rc.1",
125
+ "@deepseek-ai/dsh-host-webserver": "0.1.2-rc.1 || 0.1.3-alpha.1 || 0.1.3-alpha.2 || 0.1.5-alpha.1 || 0.1.5-rc.1",
126
+ "@deepseek-ai/dsh-invariants": "0.1.2-rc.1 || 0.1.3-alpha.1 || 0.1.3-alpha.2 || 0.1.5-alpha.1 || 0.1.5-rc.1",
127
+ "@deepseek-ai/dsh-launch-environment": "0.1.2-rc.1 || 0.1.3-alpha.1 || 0.1.3-alpha.2 || 0.1.5-alpha.1 || 0.1.5-rc.1",
128
+ "@deepseek-ai/dsh-llm": "0.1.2-rc.1 || 0.1.3-alpha.1 || 0.1.3-alpha.2 || 0.1.5-alpha.1 || 0.1.5-rc.1",
129
+ "@deepseek-ai/dsh-llm-pi-ai": "0.1.2-rc.1 || 0.1.3-alpha.1 || 0.1.3-alpha.2 || 0.1.5-alpha.1 || 0.1.5-rc.1",
130
+ "@deepseek-ai/dsh-sandbox": "0.1.2-rc.1 || 0.1.3-alpha.1 || 0.1.3-alpha.2 || 0.1.5-alpha.1 || 0.1.5-rc.1",
131
+ "@deepseek-ai/dsh-scope": "0.1.2-rc.1 || 0.1.3-alpha.1 || 0.1.3-alpha.2 || 0.1.5-alpha.1 || 0.1.5-rc.1",
132
+ "@deepseek-ai/dsh-session": "0.1.2-rc.1 || 0.1.3-alpha.1 || 0.1.3-alpha.2 || 0.1.5-alpha.1 || 0.1.5-rc.1",
133
+ "@deepseek-ai/dsh-settings": "0.1.2-rc.1 || 0.1.3-alpha.1 || 0.1.3-alpha.2 || 0.1.5-alpha.1 || 0.1.5-rc.1",
134
+ "@deepseek-ai/dsh-timeout": "0.1.2-rc.1 || 0.1.3-alpha.1 || 0.1.3-alpha.2 || 0.1.5-alpha.1 || 0.1.5-rc.1",
135
+ "@deepseek-ai/dsh-typert-protocol": "0.1.2-rc.1 || 0.1.3-alpha.1 || 0.1.3-alpha.2 || 0.1.5-alpha.1 || 0.1.5-rc.1",
136
+ "@earendil-works/pi-ai": "^0.84.2 || ^0.85.1",
137
+ "react": "^18.2.0",
138
+ "react-dom": "^18.2.0"
112
139
  },
113
140
  "devDependencies": {
141
+ "@deepseek-ai/cordis": "4.0.2",
142
+ "@deepseek-ai/dsh-agent": "0.1.5-rc.1",
143
+ "@deepseek-ai/dsh-agent-default-model": "0.1.5-rc.1",
144
+ "@deepseek-ai/dsh-agent-presets": "0.1.5-rc.1",
145
+ "@deepseek-ai/dsh-api-gateway": "0.1.5-rc.1",
146
+ "@deepseek-ai/dsh-api-remotes": "0.1.5-rc.1",
147
+ "@deepseek-ai/dsh-api-session-controller": "0.1.5-rc.1",
148
+ "@deepseek-ai/dsh-atomic-write": "0.1.5-rc.1",
149
+ "@deepseek-ai/dsh-attachment": "0.1.5-rc.1",
150
+ "@deepseek-ai/dsh-authorization": "0.1.5-rc.1",
151
+ "@deepseek-ai/dsh-brand": "0.1.5-rc.1",
152
+ "@deepseek-ai/dsh-chunked-list": "0.1.5-rc.1",
153
+ "@deepseek-ai/dsh-client-connection": "0.1.5-rc.1",
154
+ "@deepseek-ai/dsh-client-file-upload": "0.1.5-rc.1",
155
+ "@deepseek-ai/dsh-client-ui-conversation": "0.1.5-rc.1",
156
+ "@deepseek-ai/dsh-client-ui-model-selection": "0.1.5-rc.1",
157
+ "@deepseek-ai/dsh-client-ui-renderer": "0.1.5-rc.1",
158
+ "@deepseek-ai/dsh-client-ui-settings": "0.1.5-rc.1",
159
+ "@deepseek-ai/dsh-client-ui-settings-general": "0.1.5-rc.1",
160
+ "@deepseek-ai/dsh-client-ui-settings-models": "0.1.5-rc.1",
161
+ "@deepseek-ai/dsh-client-ui-sidebar": "0.1.5-rc.1",
162
+ "@deepseek-ai/dsh-client-ui-theme": "0.1.5-rc.1",
163
+ "@deepseek-ai/dsh-code-runtime": "0.1.5-rc.1",
164
+ "@deepseek-ai/dsh-commands": "0.1.5-rc.1",
165
+ "@deepseek-ai/dsh-credentials": "0.1.5-rc.1",
166
+ "@deepseek-ai/dsh-deque": "0.1.5-rc.1",
167
+ "@deepseek-ai/dsh-file-reference": "0.1.5-rc.1",
168
+ "@deepseek-ai/dsh-fs": "0.1.5-rc.1",
169
+ "@deepseek-ai/dsh-home-paths": "0.1.5-rc.1",
170
+ "@deepseek-ai/dsh-host-webserver": "0.1.5-rc.1",
171
+ "@deepseek-ai/dsh-invariants": "0.1.5-rc.1",
172
+ "@deepseek-ai/dsh-jobs": "0.1.5-rc.1",
173
+ "@deepseek-ai/dsh-launch-environment": "0.1.5-rc.1",
174
+ "@deepseek-ai/dsh-llm": "0.1.5-rc.1",
175
+ "@deepseek-ai/dsh-llm-pi-ai": "0.1.5-rc.1",
176
+ "@deepseek-ai/dsh-native-command": "0.1.5-rc.1",
177
+ "@deepseek-ai/dsh-sandbox": "0.1.5-rc.1",
178
+ "@deepseek-ai/dsh-sandbox-policy": "0.1.5-rc.1",
179
+ "@deepseek-ai/dsh-scope": "0.1.5-rc.1",
180
+ "@deepseek-ai/dsh-session": "0.1.5-rc.1",
181
+ "@deepseek-ai/dsh-session-persistence": "0.1.5-rc.1",
182
+ "@deepseek-ai/dsh-session-projection": "0.1.5-rc.1",
183
+ "@deepseek-ai/dsh-session-projection-cache": "0.1.5-rc.1",
184
+ "@deepseek-ai/dsh-session-query": "0.1.5-rc.1",
185
+ "@deepseek-ai/dsh-session-title": "0.1.5-rc.1",
186
+ "@deepseek-ai/dsh-settings": "0.1.5-rc.1",
187
+ "@deepseek-ai/dsh-skill": "0.1.5-rc.1",
188
+ "@deepseek-ai/dsh-storage": "0.1.5-rc.1",
189
+ "@deepseek-ai/dsh-storage-domain": "0.1.5-rc.1",
190
+ "@deepseek-ai/dsh-subagent": "0.1.5-rc.1",
191
+ "@deepseek-ai/dsh-system-prompt": "0.1.5-rc.1",
192
+ "@deepseek-ai/dsh-timeout": "0.1.5-rc.1",
193
+ "@deepseek-ai/dsh-tool-todo": "0.1.5-rc.1",
194
+ "@deepseek-ai/dsh-tools": "0.1.5-rc.1",
195
+ "@deepseek-ai/dsh-typert-protocol": "0.1.5-rc.1",
196
+ "@deepseek-ai/dsh-typert-registry": "0.1.5-rc.1",
197
+ "@deepseek-ai/dsh-user-approval": "0.1.5-rc.1",
198
+ "@deepseek-ai/dsh-util-crypto": "0.1.5-rc.1",
199
+ "@deepseek-ai/dsh-util-time": "0.1.5-rc.1",
200
+ "@deepseek-ai/dsh-util-values": "0.1.5-rc.1",
201
+ "@deepseek-ai/dsh-util-workspace-path": "0.1.5-rc.1",
202
+ "@deepseek-ai/dsh-workspace": "0.1.5-rc.1",
203
+ "@earendil-works/pi-ai": "0.85.1",
114
204
  "@types/react": "^18.3.28",
205
+ "@types/react-dom": "^18.3.7",
115
206
  "ajv": "^8.17.1",
207
+ "playwright-core": "1.63.0",
208
+ "react": "18.3.1",
209
+ "react-dom": "18.3.1",
116
210
  "tsdown": "0.22.14",
117
211
  "typescript": "^5.9.3",
118
212
  "yaml": "^2.8.1"
@@ -123,8 +123,8 @@ components:
123
123
  properties:
124
124
  protocol_version:
125
125
  type: string
126
- const: worker-user-center/v1
127
- description: Optional during v1 adoption; if present it MUST equal this value.
126
+ enum: [worker.user-center.v1, worker-user-center/v1, eduwork-resources/v1]
127
+ description: Optional during v1 adoption; all three version labels share the deployed credential lifecycle wire.
128
128
  subject:
129
129
  $ref: '#/components/schemas/InformationalSubject'
130
130
  provider:
@@ -0,0 +1,51 @@
1
+ openapi: 3.1.0
2
+ info:
3
+ title: EduWork Identity and Resource Protocol
4
+ version: 1.0.0
5
+ description: >-
6
+ Optional resource integration for a local single-user OIDC client.
7
+ Management uses worker-user-center-v1 bootstrap and credential operations. Quota and activity heartbeat are institution extensions, absent from this contract.
8
+ Model discovery uses the resulting runtime API key, never the
9
+ identity token. Pure OIDC deployments may omit resource integration.
10
+ license: { name: MIT, identifier: MIT }
11
+ servers:
12
+ - url: https://ai.example.edu/open/api/v1
13
+ security:
14
+ - runtimeKey: []
15
+ paths:
16
+ /models:
17
+ get:
18
+ operationId: listResourceModels
19
+ responses:
20
+ '200':
21
+ description: Available model identifiers; reviewed capabilities remain in the client Profile
22
+ content:
23
+ application/json:
24
+ schema:
25
+ type: object
26
+ required: [data]
27
+ properties:
28
+ data:
29
+ type: array
30
+ minItems: 1
31
+ maxItems: 128
32
+ items:
33
+ type: object
34
+ required: [id]
35
+ properties:
36
+ id: { type: string, minLength: 1, maxLength: 256 }
37
+ '401': { description: Runtime key is invalid or expired }
38
+ '403': { description: Model discovery is not permitted; keep the reviewed catalog }
39
+ '404': { description: Discovery not supported; client keeps reviewed model catalog }
40
+ '429': { $ref: '#/components/responses/RateLimited' }
41
+ '5XX': { $ref: '#/components/responses/Unavailable' }
42
+ components:
43
+ responses:
44
+ RateLimited:
45
+ description: Temporarily limited; current client reports unavailable and allows a later manual refresh
46
+ headers:
47
+ Retry-After: { schema: { type: string }, description: Seconds or HTTP date for a future retry; never a refresh-token grant }
48
+ Unavailable:
49
+ description: Temporary resource failure; do not clear identity or the model key
50
+ securitySchemes:
51
+ runtimeKey: { type: http, scheme: bearer, description: Model runtime credential }