@agimon-ai/po-approval 0.0.0-alpha.43
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.
- package/LICENSE +149 -0
- package/README.md +33 -0
- package/dist/apiContracts.cjs +53 -0
- package/dist/apiContracts.cjs.map +1 -0
- package/dist/apiContracts.d.mts +53 -0
- package/dist/apiContracts.d.mts.map +1 -0
- package/dist/apiContracts.mjs +48 -0
- package/dist/apiContracts.mjs.map +1 -0
- package/dist/approvalCoordinator-Be6utzFg.cjs +73 -0
- package/dist/approvalCoordinator-Be6utzFg.cjs.map +1 -0
- package/dist/approvalCoordinator-CRbOm-PY.mjs +62 -0
- package/dist/approvalCoordinator-CRbOm-PY.mjs.map +1 -0
- package/dist/extensions/native.mjs +250 -0
- package/dist/extensions/native.mjs.map +1 -0
- package/dist/extensions/server.cjs +122 -0
- package/dist/extensions/server.cjs.map +1 -0
- package/dist/extensions/server.d.mts +5 -0
- package/dist/extensions/server.d.mts.map +1 -0
- package/dist/extensions/server.mjs +117 -0
- package/dist/extensions/server.mjs.map +1 -0
- package/dist/extensions/web.mjs +187 -0
- package/dist/extensions/web.mjs.map +1 -0
- package/dist/index.cjs +4 -0
- package/dist/index.d.mts +19 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +1 -0
- package/llms.txt +7 -0
- package/package.json +145 -0
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
import { defineFill, defineSlotFile, defineWebPlugin } from "@agimon-ai/po-core/web";
|
|
2
|
+
import { Button } from "@agimon-ai/po-web-components";
|
|
3
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
4
|
+
import { useEffect, useState, useSyncExternalStore } from "react";
|
|
5
|
+
//#region src/extensions/workspaces/sessions/(frontend)/_components/ApprovalPromptView.tsx
|
|
6
|
+
function ApprovalPromptView({ title, summary, details, requirement, seconds, expired, decision, disabled, onApprove, onDeny, onCancel, voiceHint }) {
|
|
7
|
+
const inactive = disabled || expired || Boolean(decision);
|
|
8
|
+
return /* @__PURE__ */ jsxs("section", {
|
|
9
|
+
"aria-label": "Approval request",
|
|
10
|
+
onKeyDown: (event) => {
|
|
11
|
+
if (event.key === "Escape" && !inactive) onCancel();
|
|
12
|
+
},
|
|
13
|
+
className: "mx-auto flex max-w-2xl flex-col gap-4 rounded-lg border border-po-edge-magenta bg-po-panel p-4",
|
|
14
|
+
children: [
|
|
15
|
+
/* @__PURE__ */ jsxs("div", {
|
|
16
|
+
className: "flex flex-col gap-1",
|
|
17
|
+
children: [
|
|
18
|
+
/* @__PURE__ */ jsx("span", {
|
|
19
|
+
className: "text-sm font-medium text-po-magenta",
|
|
20
|
+
children: "Your approval"
|
|
21
|
+
}),
|
|
22
|
+
/* @__PURE__ */ jsx("h2", {
|
|
23
|
+
className: "text-lg font-semibold text-po-hi",
|
|
24
|
+
children: title
|
|
25
|
+
}),
|
|
26
|
+
/* @__PURE__ */ jsx("p", {
|
|
27
|
+
className: "text-lg leading-relaxed",
|
|
28
|
+
children: summary
|
|
29
|
+
})
|
|
30
|
+
]
|
|
31
|
+
}),
|
|
32
|
+
/* @__PURE__ */ jsx("dl", {
|
|
33
|
+
className: "flex flex-col gap-2 text-base",
|
|
34
|
+
children: details.map(({ label, value }) => /* @__PURE__ */ jsxs("div", {
|
|
35
|
+
className: "grid grid-cols-1 gap-1 sm:grid-cols-3 sm:gap-3",
|
|
36
|
+
children: [/* @__PURE__ */ jsx("dt", {
|
|
37
|
+
className: "text-po-dim",
|
|
38
|
+
children: label
|
|
39
|
+
}), /* @__PURE__ */ jsx("dd", {
|
|
40
|
+
className: "break-words text-po-hi sm:col-span-2",
|
|
41
|
+
children: value
|
|
42
|
+
})]
|
|
43
|
+
}, label))
|
|
44
|
+
}),
|
|
45
|
+
/* @__PURE__ */ jsxs("div", {
|
|
46
|
+
className: "flex flex-col gap-3 border-t border-po-border-soft pt-3",
|
|
47
|
+
children: [/* @__PURE__ */ jsx("p", {
|
|
48
|
+
className: "text-sm text-po-dim",
|
|
49
|
+
role: "status",
|
|
50
|
+
"aria-live": "polite",
|
|
51
|
+
children: decision || (expired ? "This request expired. Nothing ran." : seconds !== void 0 ? `${seconds} seconds remaining. Nothing runs if time runs out.` : requirement === "human" ? "Only you can approve this in the app." : "Po will wait for your decision.")
|
|
52
|
+
}), /* @__PURE__ */ jsxs("div", {
|
|
53
|
+
className: "flex flex-wrap items-center gap-2",
|
|
54
|
+
children: [
|
|
55
|
+
/* @__PURE__ */ jsx(Button, {
|
|
56
|
+
variant: "primary",
|
|
57
|
+
disabled: inactive,
|
|
58
|
+
onClick: onApprove,
|
|
59
|
+
children: "Approve"
|
|
60
|
+
}),
|
|
61
|
+
/* @__PURE__ */ jsx(Button, {
|
|
62
|
+
variant: "outline",
|
|
63
|
+
disabled: inactive,
|
|
64
|
+
onClick: onDeny,
|
|
65
|
+
children: "Deny"
|
|
66
|
+
}),
|
|
67
|
+
requirement === "ask" && voiceHint && !inactive ? /* @__PURE__ */ jsx("span", {
|
|
68
|
+
className: "text-sm text-po-dim",
|
|
69
|
+
children: voiceHint
|
|
70
|
+
}) : null
|
|
71
|
+
]
|
|
72
|
+
})]
|
|
73
|
+
})
|
|
74
|
+
]
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
//#endregion
|
|
78
|
+
//#region src/types/voiceHint.ts
|
|
79
|
+
function parseApprovalVoiceHintSource(input) {
|
|
80
|
+
const source = input;
|
|
81
|
+
return typeof source?.subscribe === "function" && typeof source.isActive === "function" ? source : null;
|
|
82
|
+
}
|
|
83
|
+
/** Voice fills this while installed; the hint shows only for `ask` approvals and only while a source is active. */
|
|
84
|
+
const approvalVoiceHintSlot = {
|
|
85
|
+
slot: "approval.voice-hint",
|
|
86
|
+
parse: parseApprovalVoiceHintSource
|
|
87
|
+
};
|
|
88
|
+
//#endregion
|
|
89
|
+
//#region src/extensions/workspaces/sessions/(frontend)/_lib/approvalDeadline.ts
|
|
90
|
+
/** Whole seconds left before `expiresAt`, or undefined when the request has no deadline. */
|
|
91
|
+
function remainingSeconds(expiresAt, now) {
|
|
92
|
+
return expiresAt === void 0 ? void 0 : Math.max(0, Math.ceil((expiresAt - now) / 1e3));
|
|
93
|
+
}
|
|
94
|
+
//#endregion
|
|
95
|
+
//#region src/extensions/workspaces/sessions/(frontend)/_components/useApprovalPrompt.ts
|
|
96
|
+
const VOICE_HINT = "Or say “approve” or “deny”.";
|
|
97
|
+
const NO_SOURCES = () => () => void 0;
|
|
98
|
+
/** Display-only countdown. The server's deadline decides; this only stops offering a stale choice. */
|
|
99
|
+
function useDeadline(expiresAt) {
|
|
100
|
+
const [seconds, setSeconds] = useState(() => remainingSeconds(expiresAt, Date.now()));
|
|
101
|
+
useEffect(() => {
|
|
102
|
+
setSeconds(remainingSeconds(expiresAt, Date.now()));
|
|
103
|
+
if (expiresAt === void 0) return void 0;
|
|
104
|
+
const timer = setInterval(() => {
|
|
105
|
+
const next = remainingSeconds(expiresAt, Date.now());
|
|
106
|
+
setSeconds(next);
|
|
107
|
+
if (next === 0) clearInterval(timer);
|
|
108
|
+
}, 1e3);
|
|
109
|
+
return () => clearInterval(timer);
|
|
110
|
+
}, [expiresAt]);
|
|
111
|
+
return seconds;
|
|
112
|
+
}
|
|
113
|
+
function useVoiceActive(sources, sessionId) {
|
|
114
|
+
const subscribe = sources.length === 0 ? NO_SOURCES : (listener) => {
|
|
115
|
+
const stops = sources.map((source) => source.subscribe(listener));
|
|
116
|
+
return () => {
|
|
117
|
+
for (const stop of stops) stop();
|
|
118
|
+
};
|
|
119
|
+
};
|
|
120
|
+
const read = () => sources.some((source) => source.isActive(sessionId));
|
|
121
|
+
return useSyncExternalStore(subscribe, read, read);
|
|
122
|
+
}
|
|
123
|
+
/** The approved view's props for one live dialog. Callbacks answer with the exact select labels. */
|
|
124
|
+
function useApprovalPrompt(props) {
|
|
125
|
+
const approval = props.dialog.approval;
|
|
126
|
+
const seconds = useDeadline(approval?.expiresAt);
|
|
127
|
+
const voice = useVoiceActive(props.slotData(approvalVoiceHintSlot).map((fill) => fill.data), props.sessionId);
|
|
128
|
+
if (approval === void 0) return void 0;
|
|
129
|
+
return {
|
|
130
|
+
title: approval.title,
|
|
131
|
+
summary: approval.summary,
|
|
132
|
+
details: approval.details ?? [],
|
|
133
|
+
requirement: approval.requirement,
|
|
134
|
+
...seconds === void 0 || seconds === 0 ? {} : { seconds },
|
|
135
|
+
expired: seconds === 0,
|
|
136
|
+
onApprove: () => props.answer("Approve"),
|
|
137
|
+
onDeny: () => props.answer("Deny"),
|
|
138
|
+
onCancel: props.cancel,
|
|
139
|
+
...approval.requirement === "ask" && voice ? { voiceHint: VOICE_HINT } : {}
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
//#endregion
|
|
143
|
+
//#region src/extensions/workspaces/sessions/(frontend)/_components/ApprovalDialogPrompt.tsx
|
|
144
|
+
/** The approved inline prompt, replacing the composer while the session waits on one approval. */
|
|
145
|
+
function ApprovalDialogPrompt(props) {
|
|
146
|
+
const view = useApprovalPrompt(props);
|
|
147
|
+
return view === void 0 ? null : /* @__PURE__ */ jsx(ApprovalPromptView, { ...view });
|
|
148
|
+
}
|
|
149
|
+
//#endregion
|
|
150
|
+
//#region src/extensions/workspaces/sessions/(frontend)/_lib/approvalClaim.ts
|
|
151
|
+
/** Only a select carrying a parsed approval envelope with both exact choices. */
|
|
152
|
+
function claimsApproval(dialog) {
|
|
153
|
+
return dialog.method === "select" && dialog.approval !== void 0 && dialog.options.includes("Approve") && dialog.options.includes("Deny");
|
|
154
|
+
}
|
|
155
|
+
//#endregion
|
|
156
|
+
//#region src/extensions/workspaces/sessions/(frontend)/fill/Approval.dialog-prompt.web.tsx
|
|
157
|
+
var Approval_dialog_prompt_web_default = defineFill({ data: {
|
|
158
|
+
claims: claimsApproval,
|
|
159
|
+
component: ApprovalDialogPrompt
|
|
160
|
+
} });
|
|
161
|
+
//#endregion
|
|
162
|
+
//#region src/extensions/workspaces/sessions/(frontend)/slot/voice-hint.web.ts
|
|
163
|
+
var voice_hint_web_default = defineSlotFile(approvalVoiceHintSlot);
|
|
164
|
+
//#endregion
|
|
165
|
+
//#region generated/web.ts
|
|
166
|
+
const via = (identity, value) => value === void 0 ? void 0 : {
|
|
167
|
+
...identity,
|
|
168
|
+
...value
|
|
169
|
+
};
|
|
170
|
+
const webPlugin = defineWebPlugin({
|
|
171
|
+
id: "approval",
|
|
172
|
+
session: {
|
|
173
|
+
get fills() {
|
|
174
|
+
return [via({
|
|
175
|
+
slot: "dialog-prompt",
|
|
176
|
+
id: "approval"
|
|
177
|
+
}, Approval_dialog_prompt_web_default)];
|
|
178
|
+
},
|
|
179
|
+
get slots() {
|
|
180
|
+
return [via({ slot: "approval.voice-hint" }, voice_hint_web_default)];
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
});
|
|
184
|
+
//#endregion
|
|
185
|
+
export { webPlugin };
|
|
186
|
+
|
|
187
|
+
//# sourceMappingURL=web.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"web.mjs","names":["fillApproval","slotVoiceHint"],"sources":["../../src/extensions/workspaces/sessions/(frontend)/_components/ApprovalPromptView.tsx","../../src/types/voiceHint.ts","../../src/extensions/workspaces/sessions/(frontend)/_lib/approvalDeadline.ts","../../src/extensions/workspaces/sessions/(frontend)/_components/useApprovalPrompt.ts","../../src/extensions/workspaces/sessions/(frontend)/_components/ApprovalDialogPrompt.tsx","../../src/extensions/workspaces/sessions/(frontend)/_lib/approvalClaim.ts","../../src/extensions/workspaces/sessions/(frontend)/fill/Approval.dialog-prompt.web.tsx","../../src/extensions/workspaces/sessions/(frontend)/slot/voice-hint.web.ts","../../generated/web.ts"],"sourcesContent":["import { Button } from '@agimon-ai/po-web-components';\n\nimport type { ApprovalPromptViewProps } from './ApprovalPromptView.types';\n\nexport function ApprovalPromptView({\n title,\n summary,\n details,\n requirement,\n seconds,\n expired,\n decision,\n disabled,\n onApprove,\n onDeny,\n onCancel,\n voiceHint,\n}: ApprovalPromptViewProps) {\n const inactive = disabled || expired || Boolean(decision);\n return (\n <section\n aria-label=\"Approval request\"\n onKeyDown={(event) => {\n if (event.key === 'Escape' && !inactive) onCancel();\n }}\n className=\"mx-auto flex max-w-2xl flex-col gap-4 rounded-lg border border-po-edge-magenta bg-po-panel p-4\"\n >\n <div className=\"flex flex-col gap-1\">\n <span className=\"text-sm font-medium text-po-magenta\">Your approval</span>\n <h2 className=\"text-lg font-semibold text-po-hi\">{title}</h2>\n <p className=\"text-lg leading-relaxed\">{summary}</p>\n </div>\n <dl className=\"flex flex-col gap-2 text-base\">\n {details.map(({ label, value }) => (\n <div key={label} className=\"grid grid-cols-1 gap-1 sm:grid-cols-3 sm:gap-3\">\n <dt className=\"text-po-dim\">{label}</dt>\n <dd className=\"break-words text-po-hi sm:col-span-2\">{value}</dd>\n </div>\n ))}\n </dl>\n <div className=\"flex flex-col gap-3 border-t border-po-border-soft pt-3\">\n <p className=\"text-sm text-po-dim\" role=\"status\" aria-live=\"polite\">\n {decision ||\n (expired\n ? 'This request expired. Nothing ran.'\n : seconds !== undefined\n ? `${seconds} seconds remaining. Nothing runs if time runs out.`\n : requirement === 'human'\n ? 'Only you can approve this in the app.'\n : 'Po will wait for your decision.')}\n </p>\n <div className=\"flex flex-wrap items-center gap-2\">\n <Button variant=\"primary\" disabled={inactive} onClick={onApprove}>\n Approve\n </Button>\n <Button variant=\"outline\" disabled={inactive} onClick={onDeny}>\n Deny\n </Button>\n {requirement === 'ask' && voiceHint && !inactive ? (\n <span className=\"text-sm text-po-dim\">{voiceHint}</span>\n ) : null}\n </div>\n </div>\n </section>\n );\n}\n","import type { SlotDeclaration } from '@agimon-ai/po-core/web';\n\n/** Whether a voice surface can take a spoken approve or deny for a session right now. */\nexport interface ApprovalVoiceHintSource {\n subscribe(listener: () => void): () => void;\n isActive(sessionId: string | null): boolean;\n}\n\nfunction parseApprovalVoiceHintSource(input: unknown): ApprovalVoiceHintSource | null {\n const source = input as Partial<ApprovalVoiceHintSource> | null;\n return typeof source?.subscribe === 'function' && typeof source.isActive === 'function'\n ? (source as ApprovalVoiceHintSource)\n : null;\n}\n\n/** Voice fills this while installed; the hint shows only for `ask` approvals and only while a source is active. */\nexport const approvalVoiceHintSlot: SlotDeclaration<ApprovalVoiceHintSource> = {\n slot: 'approval.voice-hint',\n parse: parseApprovalVoiceHintSource,\n};\n","/** Whole seconds left before `expiresAt`, or undefined when the request has no deadline. */\nexport function remainingSeconds(expiresAt: number | undefined, now: number): number | undefined {\n return expiresAt === undefined ? undefined : Math.max(0, Math.ceil((expiresAt - now) / 1000));\n}\n","import type { DialogPromptRenderProps } from '@agimon-ai/po-core/web';\nimport { useEffect, useState, useSyncExternalStore } from 'react';\n\nimport type { ApprovalVoiceHintSource } from '../../../../../types/voiceHint';\nimport { approvalVoiceHintSlot } from '../../../../../types/voiceHint';\nimport { remainingSeconds } from '../_lib/approvalDeadline';\nimport type { ApprovalPromptViewProps } from './ApprovalPromptView.types';\n\nconst VOICE_HINT = 'Or say “approve” or “deny”.';\nconst NO_SOURCES = (): (() => void) => () => undefined;\n\n/** Display-only countdown. The server's deadline decides; this only stops offering a stale choice. */\nfunction useDeadline(expiresAt: number | undefined): number | undefined {\n const [seconds, setSeconds] = useState(() => remainingSeconds(expiresAt, Date.now()));\n useEffect(() => {\n setSeconds(remainingSeconds(expiresAt, Date.now()));\n if (expiresAt === undefined) return undefined;\n const timer = setInterval(() => {\n const next = remainingSeconds(expiresAt, Date.now());\n setSeconds(next);\n if (next === 0) clearInterval(timer);\n }, 1000);\n return () => clearInterval(timer);\n }, [expiresAt]);\n return seconds;\n}\n\nfunction useVoiceActive(sources: readonly ApprovalVoiceHintSource[], sessionId: string | null): boolean {\n const subscribe =\n sources.length === 0\n ? NO_SOURCES\n : (listener: () => void) => {\n const stops = sources.map((source) => source.subscribe(listener));\n return () => {\n for (const stop of stops) stop();\n };\n };\n const read = () => sources.some((source) => source.isActive(sessionId));\n return useSyncExternalStore(subscribe, read, read);\n}\n\n/** The approved view's props for one live dialog. Callbacks answer with the exact select labels. */\nexport function useApprovalPrompt(props: DialogPromptRenderProps): ApprovalPromptViewProps | undefined {\n const approval = props.dialog.approval;\n const seconds = useDeadline(approval?.expiresAt);\n const voice = useVoiceActive(\n props.slotData(approvalVoiceHintSlot).map((fill) => fill.data),\n props.sessionId,\n );\n if (approval === undefined) return undefined;\n return {\n title: approval.title,\n summary: approval.summary,\n details: approval.details ?? [],\n requirement: approval.requirement,\n ...(seconds === undefined || seconds === 0 ? {} : { seconds }),\n expired: seconds === 0,\n onApprove: () => props.answer('Approve'),\n onDeny: () => props.answer('Deny'),\n onCancel: props.cancel,\n ...(approval.requirement === 'ask' && voice ? { voiceHint: VOICE_HINT } : {}),\n };\n}\n","import type { DialogPromptRenderProps } from '@agimon-ai/po-core/web';\n\nimport { ApprovalPromptView } from './ApprovalPromptView';\nimport { useApprovalPrompt } from './useApprovalPrompt';\n\n/** The approved inline prompt, replacing the composer while the session waits on one approval. */\nexport function ApprovalDialogPrompt(props: DialogPromptRenderProps) {\n const view = useApprovalPrompt(props);\n return view === undefined ? null : <ApprovalPromptView {...view} />;\n}\n","import type { ToolPromptDialog } from '@agimon-ai/po-core/web';\n\n/** Only a select carrying a parsed approval envelope with both exact choices. */\nexport function claimsApproval(dialog: ToolPromptDialog): boolean {\n return (\n dialog.method === 'select' &&\n dialog.approval !== undefined &&\n dialog.options.includes('Approve') &&\n dialog.options.includes('Deny')\n );\n}\n","import { defineFill } from '@agimon-ai/po-core/web';\n\nimport { ApprovalDialogPrompt } from '../_components/ApprovalDialogPrompt';\nimport { claimsApproval } from '../_lib/approvalClaim';\n\nexport default defineFill({ data: { claims: claimsApproval, component: ApprovalDialogPrompt } });\n","import { defineSlotFile } from '@agimon-ai/po-core/web';\n\nimport { approvalVoiceHintSlot } from '../../../../../types/voiceHint';\n\nexport default defineSlotFile(approvalVoiceHintSlot);\n","// Generated by @agimon-ai/po-build. Do not edit by hand.\nimport { defineWebPlugin, type WebPluginContributions } from '@agimon-ai/po-core/web';\n\nimport fillApproval from '../src/extensions/workspaces/sessions/(frontend)/fill/Approval.dialog-prompt.web';\nimport slotVoiceHint from '../src/extensions/workspaces/sessions/(frontend)/slot/voice-hint.web';\n\nconst via = <T>(identity: Record<string, unknown>, value: unknown): T =>\n (value === undefined ? undefined : { ...identity, ...(value as object) }) as T;\n\nexport const webPlugin = defineWebPlugin({\n id: 'approval',\n session: {\n get fills(): WebPluginContributions['fills'] { return [via({ slot: 'dialog-prompt', id: 'approval' }, fillApproval)]; },\n get slots(): WebPluginContributions['slots'] { return [via({ slot: 'approval.voice-hint' }, slotVoiceHint)]; },\n },\n});\n"],"mappings":"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"}
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
const require_approvalCoordinator = require("./approvalCoordinator-Be6utzFg.cjs");
|
|
3
|
+
exports.APPROVAL_OPTIONS = require_approvalCoordinator.APPROVAL_OPTIONS;
|
|
4
|
+
exports.createApprovalCoordinator = require_approvalCoordinator.createApprovalCoordinator;
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { PoApprovalService } from "@agimon-ai/po-core/approval";
|
|
2
|
+
import { PoHeadlessClient } from "@agimon-ai/po-core/headless";
|
|
3
|
+
//#region src/services/approvalCoordinator/index.d.ts
|
|
4
|
+
/** The options of every approval dialog. Clients match the labels; the values come back as the decision. */
|
|
5
|
+
export declare const APPROVAL_OPTIONS: readonly (Readonly<{
|
|
6
|
+
label: "Approve";
|
|
7
|
+
value: "approved";
|
|
8
|
+
}> | Readonly<{
|
|
9
|
+
label: "Deny";
|
|
10
|
+
value: "denied";
|
|
11
|
+
}>)[];
|
|
12
|
+
/**
|
|
13
|
+
* Asks the person through the session's dialog channel: one Approve/Deny `select` per call, carrying the bounded
|
|
14
|
+
* approval card and never the call's arguments. Resolves `approved` only from an explicit Approve that arrived before
|
|
15
|
+
* abort or expiry; everything else, including a closed client, is `cancelled` or `denied`, so nothing runs.
|
|
16
|
+
*/
|
|
17
|
+
export declare function createApprovalCoordinator(client: () => PoHeadlessClient | undefined): PoApprovalService;
|
|
18
|
+
//#endregion
|
|
19
|
+
//# sourceMappingURL=index.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/services/approvalCoordinator/index.ts"],"mappings":";;;;qBAYa,4BAAgB;;;KAAA;;;;;;;;;wBAUb,0BAA0B,cAAc,+BAA+B"}
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { t as APPROVAL_OPTIONS, n as createApprovalCoordinator } from "./approvalCoordinator-CRbOm-PY.mjs";
|
package/llms.txt
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# Po Approval
|
|
2
|
+
|
|
3
|
+
Asks the person before a tool or code-mode method that declares approval runs in a Po session.
|
|
4
|
+
|
|
5
|
+
## Resources
|
|
6
|
+
|
|
7
|
+
- [Package README](./README.md): the `po/approval` session service, how a call is asked, approved, denied, cancelled or expired, and where nobody can answer.
|
package/package.json
ADDED
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@agimon-ai/po-approval",
|
|
3
|
+
"version": "0.0.0-alpha.43",
|
|
4
|
+
"description": "Asks the person before a tool or code-mode method that declares approval runs in a Po session.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"agent-safety",
|
|
7
|
+
"ai",
|
|
8
|
+
"approval",
|
|
9
|
+
"coding-agent",
|
|
10
|
+
"developer-tools",
|
|
11
|
+
"human-in-the-loop",
|
|
12
|
+
"po"
|
|
13
|
+
],
|
|
14
|
+
"homepage": "https://agimon.ai",
|
|
15
|
+
"bugs": {
|
|
16
|
+
"url": "https://github.com/AgiFlow/po/issues"
|
|
17
|
+
},
|
|
18
|
+
"license": "BUSL-1.1",
|
|
19
|
+
"author": "Vuong Ngo",
|
|
20
|
+
"repository": {
|
|
21
|
+
"type": "git",
|
|
22
|
+
"url": "git+https://github.com/AgiFlow/po.git",
|
|
23
|
+
"directory": "packages/foundations/po-approval"
|
|
24
|
+
},
|
|
25
|
+
"files": [
|
|
26
|
+
"dist",
|
|
27
|
+
"llms.txt",
|
|
28
|
+
"README.md",
|
|
29
|
+
"LICENSE",
|
|
30
|
+
"package.json"
|
|
31
|
+
],
|
|
32
|
+
"type": "module",
|
|
33
|
+
"main": "./dist/index.cjs",
|
|
34
|
+
"module": "./dist/index.mjs",
|
|
35
|
+
"types": "./dist/index.d.mts",
|
|
36
|
+
"jsnext:main": "./dist/index.mjs",
|
|
37
|
+
"exports": {
|
|
38
|
+
".": {
|
|
39
|
+
"types": "./dist/index.d.mts",
|
|
40
|
+
"import": "./dist/index.mjs",
|
|
41
|
+
"require": "./dist/index.cjs"
|
|
42
|
+
},
|
|
43
|
+
"./apiContracts": {
|
|
44
|
+
"types": "./dist/apiContracts.d.mts",
|
|
45
|
+
"import": "./dist/apiContracts.mjs",
|
|
46
|
+
"require": "./dist/apiContracts.cjs"
|
|
47
|
+
},
|
|
48
|
+
"./extensions/native": {
|
|
49
|
+
"import": "./dist/extensions/native.mjs"
|
|
50
|
+
},
|
|
51
|
+
"./extensions/server": {
|
|
52
|
+
"types": "./dist/extensions/server.d.mts",
|
|
53
|
+
"import": "./dist/extensions/server.mjs",
|
|
54
|
+
"require": "./dist/extensions/server.cjs"
|
|
55
|
+
},
|
|
56
|
+
"./extensions/web": {
|
|
57
|
+
"import": "./dist/extensions/web.mjs"
|
|
58
|
+
},
|
|
59
|
+
"./package.json": "./package.json"
|
|
60
|
+
},
|
|
61
|
+
"publishConfig": {
|
|
62
|
+
"access": "public"
|
|
63
|
+
},
|
|
64
|
+
"dependencies": {
|
|
65
|
+
"@agimon-ai/po-core": "0.0.0-alpha.43",
|
|
66
|
+
"@agimon-ai/po-web-components": "0.0.0-alpha.43",
|
|
67
|
+
"@deepseek-ai/cordis": "4.0.5",
|
|
68
|
+
"typebox": "1.4.2"
|
|
69
|
+
},
|
|
70
|
+
"devDependencies": {
|
|
71
|
+
"@agimon-ai/po-build": "0.0.0-alpha.43",
|
|
72
|
+
"@agimon-ai/po-native-components": "0.0.0-alpha.43",
|
|
73
|
+
"@agimon-ai/vibe-lint-plugin-po-extension": "0.0.0-alpha.43",
|
|
74
|
+
"@types/node": "26.6.5",
|
|
75
|
+
"@types/react": "19.3.0",
|
|
76
|
+
"@types/react-dom": "19.3.0",
|
|
77
|
+
"@vitest/coverage-v8": "5.0.4",
|
|
78
|
+
"react": "19.3.1",
|
|
79
|
+
"react-dom": "19.3.1",
|
|
80
|
+
"react-native": "0.88.0",
|
|
81
|
+
"react-native-unistyles": "3.5.3",
|
|
82
|
+
"react-native-web": "0.21.4",
|
|
83
|
+
"tsdown": "0.23.1",
|
|
84
|
+
"typescript": "7.0.2",
|
|
85
|
+
"vitest": "5.0.4"
|
|
86
|
+
},
|
|
87
|
+
"peerDependencies": {
|
|
88
|
+
"@agimon-ai/po-native-components": "0.0.0-alpha.43",
|
|
89
|
+
"react-native": "0.88.0",
|
|
90
|
+
"react-native-unistyles": "^3.5.3"
|
|
91
|
+
},
|
|
92
|
+
"peerDependenciesMeta": {
|
|
93
|
+
"@agimon-ai/po-native-components": {
|
|
94
|
+
"optional": true
|
|
95
|
+
},
|
|
96
|
+
"react-native": {
|
|
97
|
+
"optional": true
|
|
98
|
+
},
|
|
99
|
+
"react-native-unistyles": {
|
|
100
|
+
"optional": true
|
|
101
|
+
}
|
|
102
|
+
},
|
|
103
|
+
"engines": {
|
|
104
|
+
"node": ">=24"
|
|
105
|
+
},
|
|
106
|
+
"poNative": {
|
|
107
|
+
"pluginId": "approval",
|
|
108
|
+
"channels": [],
|
|
109
|
+
"client": "./dist/extensions/native.mjs",
|
|
110
|
+
"scopes": [
|
|
111
|
+
"session"
|
|
112
|
+
]
|
|
113
|
+
},
|
|
114
|
+
"poServer": {
|
|
115
|
+
"entry": "./generated/server.ts",
|
|
116
|
+
"dist": "./dist/extensions/server.mjs",
|
|
117
|
+
"scopes": [
|
|
118
|
+
"session"
|
|
119
|
+
],
|
|
120
|
+
"contracts": {
|
|
121
|
+
"entry": "./src/exports/apiContracts.ts",
|
|
122
|
+
"dist": "./dist/apiContracts.mjs"
|
|
123
|
+
},
|
|
124
|
+
"provides": {
|
|
125
|
+
"session": [
|
|
126
|
+
"po/approval"
|
|
127
|
+
]
|
|
128
|
+
}
|
|
129
|
+
},
|
|
130
|
+
"poWeb": {
|
|
131
|
+
"pluginId": "approval",
|
|
132
|
+
"channels": [],
|
|
133
|
+
"client": "./dist/extensions/web.mjs",
|
|
134
|
+
"scopes": [
|
|
135
|
+
"session"
|
|
136
|
+
]
|
|
137
|
+
},
|
|
138
|
+
"scripts": {
|
|
139
|
+
"build": "tsdown",
|
|
140
|
+
"test": "vitest --run",
|
|
141
|
+
"typecheck": "tsc --noEmit && tsc --noEmit -p tsconfig.web.json && tsc --noEmit -p tsconfig.native.json",
|
|
142
|
+
"lint": "oxlint . && oxfmt . --check",
|
|
143
|
+
"fixcode": "oxlint . --fix && oxfmt ."
|
|
144
|
+
}
|
|
145
|
+
}
|