@things-factory/auth-base 10.1.157 → 10.1.165

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.
@@ -39,7 +39,6 @@ export declare function accessToolCategory(): AccessToolCategory;
39
39
  export declare function accessAssistantMode(): {
40
40
  kind: string;
41
41
  subjects: string[];
42
- defaultFor: string[];
43
42
  labelKey: string;
44
43
  systemPrompt: string;
45
44
  toolCategories: string[];
@@ -133,7 +133,6 @@ function accessAssistantMode() {
133
133
  return {
134
134
  kind: exports.AUTH_ACCESS_MODE,
135
135
  subjects: [exports.ACCESS_REQUESTS_SUBJECT],
136
- defaultFor: [exports.ACCESS_REQUESTS_SUBJECT],
137
136
  labelKey: 'access-request.dock.mode',
138
137
  systemPrompt: 'You help the person deciding access requests in this domain. You draft decisions as a card the person reviews and presses; the server checks each decision and the card shows what it found.',
139
138
  toolCategories: [exports.AUTH_ACCESS_TOOLS],
@@ -1 +1 @@
1
- {"version":3,"file":"access-assistant.js","sourceRoot":"","sources":["../../server/ai-entry/access-assistant.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * What the assistant reads to draft access decisions, and the mode an application registers (ADR-0103 decision 6).\n *\n * ── Why a read tool and not the screen's context ─────────────────────────\n * The screen's `hostContext` goes to the tools (`toolContext.host`), never into the model's prompt\n * (ai-client-base registry-assistant.ts: the prompt is `systemPrompt + guidance`). Pending requests put there\n * would be invisible to the model. So the model reads them through this tool, run on the server as the caller:\n * this domain only, only for someone who may decide, and never the caller's own requests.\n *\n * ── Plain data ────────────────────────────────────────────────────────────\n * Like the entry targets: no dependency on the assistant. An application that runs it registers the category,\n * the mode and the two targets. One that does not register them has no tool - whether colleagues' names and\n * reasons go to an external model is that product's decision.\n */\nimport { AUTH_ACCESS_DECISION } from './access-entry-targets.js'\n\nexport const AUTH_ACCESS_TOOLS = 'auth-access'\nexport const AUTH_ACCESS_MODE = 'auth.access'\n/** The subject the access request list stands for - the application sets its surface to this on that screen. */\nexport const ACCESS_REQUESTS_SUBJECT = 'access-requests'\n/** The screen an application recognises (auth-ui's page tag and route). */\nexport const ACCESS_REQUESTS_PAGE = { tagname: 'access-requests-page', route: 'access-requests' }\n\n/** The declaration the decision door carries - who may read pending requests to decide them. */\nconst DECIDER = { category: 'user', privilege: 'mutation', owner: true }\n\ntype ReadSpec = {\n kind: 'read'\n name: string\n description: string\n doors: string[]\n schema: any\n builder: (args: any, context: { state?: any }) => any | Promise<any>\n}\n\nexport type AccessToolCategory = { name: string; description?: string; guidance: string; specs: ReadSpec[] }\n\n/**\n * The pending requests the caller may decide, each with the roles that would grant it, smallest first.\n * Refuses a caller who may not decide - the gate in front of it says the same, and this says it again on the server.\n */\nexport async function pendingRequestsToDecide(state: any) {\n const [{ judgePermission }, access, { getRepository }, { AccessRequest, AccessRequestStatus }, { effectiveState }] = await Promise.all([\n import('../utils/check-permission.js'),\n import('../controllers/access-request.js'),\n import('@things-factory/shell'),\n import('../service/access-request/access-request.js'),\n import('../utils/access-request-review.js')\n ])\n const { domain, user } = state || {}\n if (!domain?.id || !user?.id) return { refused: 'no-domain' }\n\n const judgement = await judgePermission(DECIDER, user, domain, state.unsafeIP, state.prohibitedPrivileges)\n if (judgement.permitted !== true) return { refused: 'not-a-decider' }\n\n const now = new Date()\n const rows = await getRepository(AccessRequest).find({\n where: { domain: { id: domain.id }, state: AccessRequestStatus.PENDING },\n relations: ['requester'],\n order: { createdAt: 'ASC' },\n take: 200\n })\n\n const requests = []\n for (const row of rows) {\n if (row.requester?.id === user.id) continue\n if (effectiveState(row.state as any, row.expiresAt, now) !== 'PENDING') continue\n const candidates = await access.rolesGranting(row.category, row.privilege, domain)\n requests.push({\n request: `${row.requester?.name || row.requester?.email || ''} · ${row.category}:${row.privilege}`,\n requester: row.requester?.name || row.requester?.email || '',\n privilege: `${row.category}:${row.privilege}`,\n refusedAt: row.operationName || null,\n reason: row.reason || null,\n timesAsked: row.count,\n askedAt: row.createdAt,\n roles: candidates.map(({ name, privilegeCount }) => ({ name, privilegeCount }))\n })\n }\n return { requests }\n}\n\nexport function accessToolCategory(): AccessToolCategory {\n return {\n name: AUTH_ACCESS_TOOLS,\n description: 'access requests waiting for a decision in this domain',\n guidance: [\n 'To draft decisions on access requests, call listPendingAccessRequests first and draft only from what it returns.',\n 'Propose GRANT with the role that has the fewest privileges among the roles listed for that request; name another role only when the person asks.',\n 'Never write a reason to deny - ask the person for it. Never say a request was granted or denied: the person presses the card.',\n 'If a request lists no roles, say no role in this domain grants it and that a role must hold it first; do not propose it.'\n ].join('\\n'),\n specs: [\n {\n kind: 'read',\n name: 'listPendingAccessRequests',\n description:\n 'Lists the access requests in this domain that are waiting for a decision the caller may make, each with the roles that would grant it (fewest privileges first).',\n /* Reading requests and their candidate roles - both doors; the second carries the deciding declaration. */\n doors: ['Query.accessRequests', 'Query.rolesGranting'],\n schema: { type: 'object', properties: {} },\n builder: (_args, context) => pendingRequestsToDecide(context?.state)\n }\n ]\n }\n}\n\n/** The mode an application registers for the access request list. Words are auth-ui's. */\nexport function accessAssistantMode() {\n return {\n kind: AUTH_ACCESS_MODE,\n subjects: [ACCESS_REQUESTS_SUBJECT],\n defaultFor: [ACCESS_REQUESTS_SUBJECT],\n labelKey: 'access-request.dock.mode',\n systemPrompt:\n 'You help the person deciding access requests in this domain. You draft decisions as a card the person reviews and presses; the server checks each decision and the card shows what it found.',\n toolCategories: [AUTH_ACCESS_TOOLS],\n entryTargets: [AUTH_ACCESS_DECISION],\n requireToolOnFirstTurn: true,\n placeholderKey: 'access-request.dock.placeholder',\n /* The empty conversation says what this one is for - without it the dock fell back to board authoring. */\n introKeys: { title: 'access-request.dock.intro title', subtitle: 'access-request.dock.intro subtitle' },\n exampleKeys: [\n {\n labelKey: 'access-request.dock.examples',\n itemKeys: ['access-request.dock.example today', 'access-request.dock.example smallest', 'access-request.dock.example one person']\n }\n ]\n }\n}\n"]}
1
+ {"version":3,"file":"access-assistant.js","sourceRoot":"","sources":["../../server/ai-entry/access-assistant.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * What the assistant reads to draft access decisions, and the mode an application registers (ADR-0103 decision 6).\n *\n * ── Why a read tool and not the screen's context ─────────────────────────\n * The screen's `hostContext` goes to the tools (`toolContext.host`), never into the model's prompt\n * (ai-client-base registry-assistant.ts: the prompt is `systemPrompt + guidance`). Pending requests put there\n * would be invisible to the model. So the model reads them through this tool, run on the server as the caller:\n * this domain only, only for someone who may decide, and never the caller's own requests.\n *\n * ── Plain data ────────────────────────────────────────────────────────────\n * Like the entry targets: no dependency on the assistant. An application that runs it registers the category,\n * the mode and the two targets. One that does not register them has no tool - whether colleagues' names and\n * reasons go to an external model is that product's decision.\n */\nimport { AUTH_ACCESS_DECISION } from './access-entry-targets.js'\n\nexport const AUTH_ACCESS_TOOLS = 'auth-access'\nexport const AUTH_ACCESS_MODE = 'auth.access'\n/** The subject the access request list stands for - the application sets its surface to this on that screen. */\nexport const ACCESS_REQUESTS_SUBJECT = 'access-requests'\n/** The screen an application recognises (auth-ui's page tag and route). */\nexport const ACCESS_REQUESTS_PAGE = { tagname: 'access-requests-page', route: 'access-requests' }\n\n/** The declaration the decision door carries - who may read pending requests to decide them. */\nconst DECIDER = { category: 'user', privilege: 'mutation', owner: true }\n\ntype ReadSpec = {\n kind: 'read'\n name: string\n description: string\n doors: string[]\n schema: any\n builder: (args: any, context: { state?: any }) => any | Promise<any>\n}\n\nexport type AccessToolCategory = { name: string; description?: string; guidance: string; specs: ReadSpec[] }\n\n/**\n * The pending requests the caller may decide, each with the roles that would grant it, smallest first.\n * Refuses a caller who may not decide - the gate in front of it says the same, and this says it again on the server.\n */\nexport async function pendingRequestsToDecide(state: any) {\n const [{ judgePermission }, access, { getRepository }, { AccessRequest, AccessRequestStatus }, { effectiveState }] = await Promise.all([\n import('../utils/check-permission.js'),\n import('../controllers/access-request.js'),\n import('@things-factory/shell'),\n import('../service/access-request/access-request.js'),\n import('../utils/access-request-review.js')\n ])\n const { domain, user } = state || {}\n if (!domain?.id || !user?.id) return { refused: 'no-domain' }\n\n const judgement = await judgePermission(DECIDER, user, domain, state.unsafeIP, state.prohibitedPrivileges)\n if (judgement.permitted !== true) return { refused: 'not-a-decider' }\n\n const now = new Date()\n const rows = await getRepository(AccessRequest).find({\n where: { domain: { id: domain.id }, state: AccessRequestStatus.PENDING },\n relations: ['requester'],\n order: { createdAt: 'ASC' },\n take: 200\n })\n\n const requests = []\n for (const row of rows) {\n if (row.requester?.id === user.id) continue\n if (effectiveState(row.state as any, row.expiresAt, now) !== 'PENDING') continue\n const candidates = await access.rolesGranting(row.category, row.privilege, domain)\n requests.push({\n request: `${row.requester?.name || row.requester?.email || ''} · ${row.category}:${row.privilege}`,\n requester: row.requester?.name || row.requester?.email || '',\n privilege: `${row.category}:${row.privilege}`,\n refusedAt: row.operationName || null,\n reason: row.reason || null,\n timesAsked: row.count,\n askedAt: row.createdAt,\n roles: candidates.map(({ name, privilegeCount }) => ({ name, privilegeCount }))\n })\n }\n return { requests }\n}\n\nexport function accessToolCategory(): AccessToolCategory {\n return {\n name: AUTH_ACCESS_TOOLS,\n description: 'access requests waiting for a decision in this domain',\n guidance: [\n 'To draft decisions on access requests, call listPendingAccessRequests first and draft only from what it returns.',\n 'Propose GRANT with the role that has the fewest privileges among the roles listed for that request; name another role only when the person asks.',\n 'Never write a reason to deny - ask the person for it. Never say a request was granted or denied: the person presses the card.',\n 'If a request lists no roles, say no role in this domain grants it and that a role must hold it first; do not propose it.'\n ].join('\\n'),\n specs: [\n {\n kind: 'read',\n name: 'listPendingAccessRequests',\n description:\n 'Lists the access requests in this domain that are waiting for a decision the caller may make, each with the roles that would grant it (fewest privileges first).',\n /* Reading requests and their candidate roles - both doors; the second carries the deciding declaration. */\n doors: ['Query.accessRequests', 'Query.rolesGranting'],\n schema: { type: 'object', properties: {} },\n builder: (_args, context) => pendingRequestsToDecide(context?.state)\n }\n ]\n }\n}\n\n/** The mode an application registers for the access request list. Words are auth-ui's. */\nexport function accessAssistantMode() {\n return {\n kind: AUTH_ACCESS_MODE,\n subjects: [ACCESS_REQUESTS_SUBJECT],\n labelKey: 'access-request.dock.mode',\n systemPrompt:\n 'You help the person deciding access requests in this domain. You draft decisions as a card the person reviews and presses; the server checks each decision and the card shows what it found.',\n toolCategories: [AUTH_ACCESS_TOOLS],\n entryTargets: [AUTH_ACCESS_DECISION],\n requireToolOnFirstTurn: true,\n placeholderKey: 'access-request.dock.placeholder',\n /* The empty conversation says what this one is for - without it the dock fell back to board authoring. */\n introKeys: { title: 'access-request.dock.intro title', subtitle: 'access-request.dock.intro subtitle' },\n exampleKeys: [\n {\n labelKey: 'access-request.dock.examples',\n itemKeys: ['access-request.dock.example today', 'access-request.dock.example smallest', 'access-request.dock.example one person']\n }\n ]\n }\n}\n"]}