@arnilo/prism-tools 0.0.0-stage → 0.13.1
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/CHANGELOG.md +418 -0
- package/LICENSE +21 -0
- package/README.md +44 -2
- package/browser/README.md +98 -0
- package/browser/skills/browser-automation/SKILL.md +14 -0
- package/browser/src/actions/cdp.ts +131 -0
- package/browser/src/actions/dialog.ts +25 -0
- package/browser/src/actions/download_release.ts +22 -0
- package/browser/src/actions/index.ts +37 -0
- package/browser/src/actions/locator.ts +70 -0
- package/browser/src/actions/navigate.ts +23 -0
- package/browser/src/actions/screenshot.ts +27 -0
- package/browser/src/actions/scroll.ts +24 -0
- package/browser/src/actions/select_page.ts +21 -0
- package/browser/src/actions/types.ts +114 -0
- package/browser/src/actions/upload.ts +44 -0
- package/browser/src/actions/wait.ts +45 -0
- package/browser/src/browser.ts +197 -0
- package/browser/src/cdp.ts +178 -0
- package/browser/src/checkpoint.ts +189 -0
- package/browser/src/config.ts +72 -0
- package/browser/src/downloads.ts +253 -0
- package/browser/src/errors.ts +31 -0
- package/browser/src/evaluate.ts +101 -0
- package/browser/src/index.ts +129 -0
- package/browser/src/limits.ts +271 -0
- package/browser/src/manager.ts +730 -0
- package/browser/src/network.ts +263 -0
- package/browser/src/observe.ts +178 -0
- package/browser/src/policy.ts +133 -0
- package/browser/src/screenshot.ts +107 -0
- package/browser/src/shared-sandbox.ts +53 -0
- package/browser/src/snapshot.ts +99 -0
- package/browser/src/targets.ts +165 -0
- package/browser/src/tools.ts +480 -0
- package/browser/src/types.ts +316 -0
- package/browser/src/uploads.ts +174 -0
- package/coding/README.md +337 -0
- package/coding/src/agent/acp-operations.ts +146 -0
- package/coding/src/agent/artifacts.ts +38 -0
- package/coding/src/agent/ask-user-decision.ts +623 -0
- package/coding/src/agent/atomic-write.ts +23 -0
- package/coding/src/agent/bounded-file.ts +21 -0
- package/coding/src/agent/checks.ts +301 -0
- package/coding/src/agent/coding-checkpoint.ts +828 -0
- package/coding/src/agent/delete.ts +237 -0
- package/coding/src/agent/diagnostics-tool.ts +163 -0
- package/coding/src/agent/diagnostics.ts +262 -0
- package/coding/src/agent/edit-diff.ts +382 -0
- package/coding/src/agent/edit.ts +322 -0
- package/coding/src/agent/effects.ts +102 -0
- package/coding/src/agent/env.ts +28 -0
- package/coding/src/agent/execution-policy.ts +89 -0
- package/coding/src/agent/file-mutation-queue.ts +72 -0
- package/coding/src/agent/forge/github.ts +603 -0
- package/coding/src/agent/forge/index.ts +16 -0
- package/coding/src/agent/forge/types.ts +185 -0
- package/coding/src/agent/git-aware-repository.ts +305 -0
- package/coding/src/agent/git-exec.ts +326 -0
- package/coding/src/agent/git-status.ts +177 -0
- package/coding/src/agent/git-tools.ts +360 -0
- package/coding/src/agent/git.ts +1074 -0
- package/coding/src/agent/glob-match.ts +146 -0
- package/coding/src/agent/glob.ts +182 -0
- package/coding/src/agent/goal-verify.ts +385 -0
- package/coding/src/agent/grep-worker.ts +74 -0
- package/coding/src/agent/grep.ts +459 -0
- package/coding/src/agent/identity.ts +48 -0
- package/coding/src/agent/index.ts +676 -0
- package/coding/src/agent/language/client.ts +429 -0
- package/coding/src/agent/language/framing.ts +190 -0
- package/coding/src/agent/language/index.ts +23 -0
- package/coding/src/agent/language/intelligence.ts +682 -0
- package/coding/src/agent/language/types.ts +187 -0
- package/coding/src/agent/lifecycle-events.ts +121 -0
- package/coding/src/agent/lifecycle.ts +166 -0
- package/coding/src/agent/limits.ts +214 -0
- package/coding/src/agent/move.ts +178 -0
- package/coding/src/agent/mutation-path.ts +52 -0
- package/coding/src/agent/output-accumulator.ts +304 -0
- package/coding/src/agent/path-utils.ts +120 -0
- package/coding/src/agent/process/index.ts +58 -0
- package/coding/src/agent/process/recovery.ts +508 -0
- package/coding/src/agent/process/sessions-host.ts +222 -0
- package/coding/src/agent/process/sessions-monitor.ts +141 -0
- package/coding/src/agent/process/sessions-recovery.ts +241 -0
- package/coding/src/agent/process/sessions-spawn.ts +613 -0
- package/coding/src/agent/process/sessions-teardown.ts +281 -0
- package/coding/src/agent/process/sessions.ts +30 -0
- package/coding/src/agent/process/types.ts +358 -0
- package/coding/src/agent/read-path-set.ts +126 -0
- package/coding/src/agent/read.ts +713 -0
- package/coding/src/agent/repository/glob.ts +147 -0
- package/coding/src/agent/repository/indexed-search.ts +480 -0
- package/coding/src/agent/repository/list.ts +131 -0
- package/coding/src/agent/repository/operations.ts +22 -0
- package/coding/src/agent/repository/path.ts +98 -0
- package/coding/src/agent/repository/search.ts +277 -0
- package/coding/src/agent/repository/types.ts +243 -0
- package/coding/src/agent/repository/walk.ts +126 -0
- package/coding/src/agent/repository.ts +12 -0
- package/coding/src/agent/shell-background.ts +264 -0
- package/coding/src/agent/shell-output.ts +75 -0
- package/coding/src/agent/shell.ts +526 -0
- package/coding/src/agent/todo.ts +399 -0
- package/coding/src/agent/truncate.ts +251 -0
- package/coding/src/agent/write.ts +170 -0
- package/coding/src/ask-user-host.ts +48 -0
- package/coding/src/config.ts +278 -0
- package/coding/src/hard-deny.ts +97 -0
- package/coding/src/index.ts +318 -0
- package/coding/src/principal-guard.ts +84 -0
- package/coding/src/sandbox.ts +92 -0
- package/coding/src/security/approval.ts +144 -0
- package/coding/src/security/command-rules.ts +57 -0
- package/coding/src/security/docker-cli.ts +222 -0
- package/coding/src/security/docker-sandbox.ts +1205 -0
- package/coding/src/security/e2b-sandbox.ts +853 -0
- package/coding/src/security/egress/dns-pin.ts +88 -0
- package/coding/src/security/egress/index.ts +32 -0
- package/coding/src/security/egress/limits.ts +57 -0
- package/coding/src/security/egress/policy.ts +137 -0
- package/coding/src/security/egress/proxy.ts +599 -0
- package/coding/src/security/egress/types.ts +30 -0
- package/coding/src/security/index.ts +199 -0
- package/coding/src/security/native-sandbox.ts +639 -0
- package/coding/src/security/path-containment.ts +55 -0
- package/coding/src/security/sandbox-coding-operations.ts +392 -0
- package/coding/src/security/sandbox-fs-operations.ts +644 -0
- package/coding/src/security/sandbox-limits.ts +147 -0
- package/coding/src/security/sandbox-tar.ts +308 -0
- package/coding/src/security/sandbox.ts +179 -0
- package/coding/src/security/semaphore.ts +55 -0
- package/coding/src/targets.ts +110 -0
- package/coding/src/workspace/diff.ts +78 -0
- package/coding/src/workspace/errors.ts +29 -0
- package/coding/src/workspace/index.ts +5 -0
- package/coding/src/workspace/merge.ts +151 -0
- package/coding/src/workspace/routing.ts +76 -0
- package/coding/src/workspace/service.ts +584 -0
- package/computer-use/README.md +105 -0
- package/computer-use/skills/computer-use-linux/SKILL.md +17 -0
- package/computer-use/src/classify.ts +53 -0
- package/computer-use/src/command.ts +29 -0
- package/computer-use/src/config.ts +69 -0
- package/computer-use/src/create.ts +170 -0
- package/computer-use/src/devices.ts +247 -0
- package/computer-use/src/env.ts +28 -0
- package/computer-use/src/index.ts +157 -0
- package/computer-use/src/skill.ts +21 -0
- package/openapi/README.md +97 -0
- package/openapi/src/compile.ts +386 -0
- package/openapi/src/config.ts +73 -0
- package/openapi/src/errors.ts +16 -0
- package/openapi/src/execute.ts +241 -0
- package/openapi/src/index.ts +124 -0
- package/openapi/src/limits.ts +63 -0
- package/openapi/src/specs.ts +86 -0
- package/openapi/src/tools.ts +60 -0
- package/openapi/src/types.ts +61 -0
- package/package.json +171 -4
- package/research/README.md +72 -0
- package/research/skills/research-report/SKILL.md +12 -0
- package/research/skills/research-scoping/SKILL.md +10 -0
- package/research/skills/research-synthesis/SKILL.md +10 -0
- package/research/skills/source-triage/SKILL.md +10 -0
- package/research/src/check.ts +71 -0
- package/research/src/config.ts +41 -0
- package/research/src/index.ts +147 -0
- package/research/src/ledger.ts +157 -0
- package/research/src/urls.ts +21 -0
- package/web/README.md +287 -0
- package/web/skills/web-research/SKILL.md +17 -0
- package/web/src/brave.ts +66 -0
- package/web/src/cache.ts +151 -0
- package/web/src/config.ts +210 -0
- package/web/src/controls.ts +128 -0
- package/web/src/domains.ts +114 -0
- package/web/src/exa.ts +60 -0
- package/web/src/firecrawl.ts +160 -0
- package/web/src/index.ts +387 -0
- package/web/src/kagi.ts +73 -0
- package/web/src/limits.ts +55 -0
- package/web/src/native/convert.ts +84 -0
- package/web/src/native/fetch.ts +226 -0
- package/web/src/normalize.ts +131 -0
- package/web/src/obscura/cdp.ts +201 -0
- package/web/src/obscura/classify.ts +35 -0
- package/web/src/obscura/cli.ts +254 -0
- package/web/src/obscura/errors.ts +8 -0
- package/web/src/obscura/index.ts +59 -0
- package/web/src/obscura/limits.ts +92 -0
- package/web/src/obscura/mcp.ts +104 -0
- package/web/src/obscura/playwright.ts +133 -0
- package/web/src/obscura/process.ts +235 -0
- package/web/src/obscura/search-profile.ts +73 -0
- package/web/src/obscura/types.ts +48 -0
- package/web/src/obscura/web.ts +419 -0
- package/web/src/prompt-fetch.ts +88 -0
- package/web/src/render.ts +75 -0
- package/web/src/searxng.ts +78 -0
- package/web/src/slice.ts +139 -0
- package/web/src/tavily.ts +77 -0
- package/web/src/tools.ts +182 -0
- package/web/src/transport.ts +310 -0
- package/web/src/types.ts +199 -0
- package/work/README.md +77 -0
- package/work/THIRD_PARTY_NOTICES +24 -0
- package/work/docling/ocr.py +150 -0
- package/work/sandbox/Dockerfile +36 -0
- package/work/sandbox/soffice.sh +12 -0
- package/work/src/command.ts +29 -0
- package/work/src/config.ts +138 -0
- package/work/src/connectors/cli.ts +343 -0
- package/work/src/connectors/drafts.ts +647 -0
- package/work/src/connectors/errors.ts +8 -0
- package/work/src/connectors/file-bytes.ts +149 -0
- package/work/src/connectors/google-workspace-http.ts +399 -0
- package/work/src/connectors/google-workspace.ts +465 -0
- package/work/src/connectors/gws-tools.ts +378 -0
- package/work/src/connectors/http.ts +123 -0
- package/work/src/connectors/idempotency.ts +235 -0
- package/work/src/connectors/identity.ts +34 -0
- package/work/src/connectors/index.ts +93 -0
- package/work/src/connectors/limits.ts +50 -0
- package/work/src/connectors/m365-tools.ts +308 -0
- package/work/src/connectors/microsoft365-http.ts +428 -0
- package/work/src/connectors/microsoft365.ts +402 -0
- package/work/src/connectors/normalize.ts +120 -0
- package/work/src/connectors/tool-helpers.ts +398 -0
- package/work/src/connectors/tools.ts +42 -0
- package/work/src/connectors/types.ts +399 -0
- package/work/src/diagrams/canonicalize.ts +166 -0
- package/work/src/diagrams/caps.ts +52 -0
- package/work/src/diagrams/embed.ts +340 -0
- package/work/src/diagrams/errors.ts +76 -0
- package/work/src/diagrams/index.ts +81 -0
- package/work/src/diagrams/messages.ts +150 -0
- package/work/src/diagrams/origin.ts +52 -0
- package/work/src/diagrams/telemetry.ts +34 -0
- package/work/src/diagrams/xml.ts +267 -0
- package/work/src/document-extraction/index.ts +563 -0
- package/work/src/document-reader/ambient.d.ts +2 -0
- package/work/src/document-reader/errors.ts +7 -0
- package/work/src/document-reader/index.ts +181 -0
- package/work/src/document-reader/mistral-ocr.ts +318 -0
- package/work/src/document-reader/parsers.ts +171 -0
- package/work/src/documents/caps.ts +135 -0
- package/work/src/documents/diff.ts +269 -0
- package/work/src/documents/errors.ts +44 -0
- package/work/src/documents/fidelity.ts +98 -0
- package/work/src/documents/generate.ts +96 -0
- package/work/src/documents/hash.ts +8 -0
- package/work/src/documents/index.ts +14 -0
- package/work/src/documents/model-schema.ts +639 -0
- package/work/src/documents/parse.ts +252 -0
- package/work/src/documents/patch-history.ts +81 -0
- package/work/src/documents/patch.ts +476 -0
- package/work/src/documents/preview-html.ts +245 -0
- package/work/src/documents/preview.ts +227 -0
- package/work/src/documents/telemetry.ts +36 -0
- package/work/src/documents/translate/docx.ts +292 -0
- package/work/src/documents/translate/pptx.ts +304 -0
- package/work/src/documents/translate/xlsx.ts +137 -0
- package/work/src/documents/types.ts +188 -0
- package/work/src/index.ts +311 -0
- package/work/src/runtime/worker-pool-entry.ts +102 -0
- package/work/src/runtime/worker-pool.ts +267 -0
- package/work/src/sandbox/composition.ts +212 -0
- package/work/src/sandbox/image.ts +6 -0
- package/work/src/sandbox/index.ts +14 -0
- package/work/src/sheets/caps.ts +68 -0
- package/work/src/sheets/csv.ts +351 -0
- package/work/src/sheets/decimal.ts +388 -0
- package/work/src/sheets/errors.ts +52 -0
- package/work/src/sheets/index.ts +62 -0
- package/work/src/sheets/inference.ts +378 -0
- package/work/src/sheets/telemetry.ts +34 -0
- package/work/src/sheets/types.ts +162 -0
- package/work/src/sheets/xlsx.ts +388 -0
- package/work/src/skills/index.ts +8 -0
- package/work/src/skills/load.ts +43 -0
- package/work/src/tools/filesystem.ts +21 -0
- package/work/src/tools/index.ts +1 -0
- package/work/src/tools/local-filesystem.ts +33 -0
- package/work/src/tools/office.ts +311 -0
- package/work/vendor/hermes-agent/LICENSE +21 -0
- package/work/vendor/hermes-agent/skills/productivity/docx/LICENSE +21 -0
- package/work/vendor/hermes-agent/skills/productivity/docx/SKILL.md +196 -0
- package/work/vendor/hermes-agent/skills/productivity/docx/scripts/docx_comments.py +289 -0
- package/work/vendor/hermes-agent/skills/productivity/docx/scripts/docx_common.py +94 -0
- package/work/vendor/hermes-agent/skills/productivity/docx/scripts/docx_create.py +177 -0
- package/work/vendor/hermes-agent/skills/productivity/docx/scripts/docx_edit.py +250 -0
- package/work/vendor/hermes-agent/skills/productivity/docx/scripts/docx_read.py +149 -0
- package/work/vendor/hermes-agent/skills/productivity/docx/scripts/docx_revisions.py +147 -0
- package/work/vendor/hermes-agent/skills/productivity/docx/scripts/docx_template.py +70 -0
- package/work/vendor/hermes-agent/skills/productivity/docx/scripts/docx_validate.py +156 -0
- package/work/vendor/hermes-agent/skills/productivity/pdf/LICENSE +21 -0
- package/work/vendor/hermes-agent/skills/productivity/pdf/SKILL.md +125 -0
- package/work/vendor/hermes-agent/skills/productivity/pdf/scripts/_raster.py +76 -0
- package/work/vendor/hermes-agent/skills/productivity/pdf/scripts/extract_marker.py +88 -0
- package/work/vendor/hermes-agent/skills/productivity/pdf/scripts/extract_pymupdf.py +101 -0
- package/work/vendor/hermes-agent/skills/productivity/pdf/scripts/pdf_create.py +130 -0
- package/work/vendor/hermes-agent/skills/productivity/pdf/scripts/pdf_fill_form.py +97 -0
- package/work/vendor/hermes-agent/skills/productivity/pdf/scripts/pdf_form_layout.py +168 -0
- package/work/vendor/hermes-agent/skills/productivity/pdf/scripts/pdf_make_form.py +145 -0
- package/work/vendor/hermes-agent/skills/productivity/pdf/scripts/pdf_merge.py +50 -0
- package/work/vendor/hermes-agent/skills/productivity/pdf/scripts/pdf_meta.py +115 -0
- package/work/vendor/hermes-agent/skills/productivity/pdf/scripts/pdf_page_image.py +99 -0
- package/work/vendor/hermes-agent/skills/productivity/pdf/scripts/pdf_read.py +153 -0
- package/work/vendor/hermes-agent/skills/productivity/pdf/scripts/pdf_secure.py +71 -0
- package/work/vendor/hermes-agent/skills/productivity/pdf/scripts/pdf_split.py +84 -0
- package/work/vendor/hermes-agent/skills/productivity/pdf/scripts/pdf_stamp.py +143 -0
- package/work/vendor/hermes-agent/skills/productivity/pdf/scripts/pdf_watermark.py +51 -0
- package/work/vendor/hermes-agent/skills/productivity/powerpoint/LICENSE +21 -0
- package/work/vendor/hermes-agent/skills/productivity/powerpoint/SKILL.md +220 -0
- package/work/vendor/hermes-agent/skills/productivity/powerpoint/scripts/pptx_create.py +214 -0
- package/work/vendor/hermes-agent/skills/productivity/powerpoint/scripts/pptx_edit.py +436 -0
- package/work/vendor/hermes-agent/skills/productivity/powerpoint/scripts/pptx_from_template.py +88 -0
- package/work/vendor/hermes-agent/skills/productivity/powerpoint/scripts/pptx_read.py +131 -0
- package/work/vendor/hermes-agent/skills/productivity/powerpoint/scripts/pptx_render.py +93 -0
- package/work/vendor/hermes-agent/skills/productivity/xlsx/LICENSE +21 -0
- package/work/vendor/hermes-agent/skills/productivity/xlsx/SKILL.md +196 -0
- package/work/vendor/hermes-agent/skills/productivity/xlsx/scripts/csv_to_xlsx.py +104 -0
- package/work/vendor/hermes-agent/skills/productivity/xlsx/scripts/xlsx_create.py +259 -0
- package/work/vendor/hermes-agent/skills/productivity/xlsx/scripts/xlsx_edit.py +263 -0
- package/work/vendor/hermes-agent/skills/productivity/xlsx/scripts/xlsx_read.py +160 -0
- package/work/vendor/hermes-agent/skills/productivity/xlsx/scripts/xlsx_recalc.py +111 -0
- package/work/vendor/hermes-agent/skills/productivity/xlsx/scripts/xlsx_restructure.py +337 -0
- package/work/vendor/hermes-agent/skills/productivity/xlsx/scripts/xlsx_to_csv.py +69 -0
- package/work/vendor-lock.json +11 -0
|
@@ -0,0 +1,402 @@
|
|
|
1
|
+
import { type JsonObject } from "@arnilo/prism";
|
|
2
|
+
import { type ArtifactBodyStore } from "@arnilo/prism/artifacts";
|
|
3
|
+
import type { CheckpointStore } from "@arnilo/prism-extensions/workflows";
|
|
4
|
+
import { assertSafeArgv, createCliRunner, parseCliJson } from "./cli.js";
|
|
5
|
+
import { createCheckpointWorkDraftStore, createMemoryWorkDraftStore } from "./drafts.js";
|
|
6
|
+
import { WorkToolError } from "./errors.js";
|
|
7
|
+
import { type AgentIdentity, assertIdentityActive } from "./identity.js";
|
|
8
|
+
import { resolveWorkLimits } from "./limits.js";
|
|
9
|
+
import type { Microsoft365Adapter, Microsoft365Op, WorkCliRunner, WorkDraftStore, WorkLimits, WorkTokenProvider } from "./types.js";
|
|
10
|
+
/** Default ops enabled without capability gates. Teams/Planner/To Do stay opt-in. */
|
|
11
|
+
export const DEFAULT_M365_OPS: readonly Microsoft365Op[] = [
|
|
12
|
+
"version",
|
|
13
|
+
"mail.list",
|
|
14
|
+
"mail.get",
|
|
15
|
+
"mail.send",
|
|
16
|
+
"calendar.list",
|
|
17
|
+
"calendar.add",
|
|
18
|
+
"file.list",
|
|
19
|
+
"file.add",
|
|
20
|
+
"file.copy",
|
|
21
|
+
"file.share",
|
|
22
|
+
];
|
|
23
|
+
|
|
24
|
+
const GATED_DEFAULT_EXCLUDED: ReadonlySet<Microsoft365Op> = new Set([
|
|
25
|
+
"todo.list",
|
|
26
|
+
"todo.add",
|
|
27
|
+
"todo.complete",
|
|
28
|
+
"planner.list",
|
|
29
|
+
"planner.add",
|
|
30
|
+
"planner.complete",
|
|
31
|
+
]);
|
|
32
|
+
|
|
33
|
+
/** Ops excluded from DEFAULT_M365_OPS; host must pass them in allowedOps. */
|
|
34
|
+
export const GATED_M365_OPS = GATED_DEFAULT_EXCLUDED;
|
|
35
|
+
|
|
36
|
+
function reqString(args: JsonObject, key: string): string {
|
|
37
|
+
const value = args[key];
|
|
38
|
+
if (typeof value !== "string" || !value) throw new WorkToolError("ERR_PRISM_WORK_INPUT", `${key} must be a non-empty string`);
|
|
39
|
+
return value;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function optString(args: JsonObject, key: string): string | undefined {
|
|
43
|
+
const value = args[key];
|
|
44
|
+
if (value === undefined) return undefined;
|
|
45
|
+
if (typeof value !== "string" || !value) throw new WorkToolError("ERR_PRISM_WORK_INPUT", `${key} must be a non-empty string`);
|
|
46
|
+
return value;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Hard-coded argv templates for @pnp/cli-microsoft365 (verified 2026-07-23 docs):
|
|
51
|
+
* - outlook message list/get, outlook mail send
|
|
52
|
+
* - outlook event list; outlook event add (newer CLI; draft path still requires approval)
|
|
53
|
+
* - file list/add/copy; spo file sharinglink add
|
|
54
|
+
* - todo task list/add/set (gated); planner task * (gated)
|
|
55
|
+
*/
|
|
56
|
+
export function buildMicrosoft365Argv(op: Microsoft365Op, args: JsonObject): string[] {
|
|
57
|
+
switch (op) {
|
|
58
|
+
case "version":
|
|
59
|
+
return ["version", "--output", "json"];
|
|
60
|
+
case "mail.list": {
|
|
61
|
+
const argv = ["outlook", "message", "list", "--output", "json"];
|
|
62
|
+
const folderName = optString(args, "folderName");
|
|
63
|
+
const folderId = optString(args, "folderId");
|
|
64
|
+
if (folderName && folderId) throw new WorkToolError("ERR_PRISM_WORK_INPUT", "Specify folderName or folderId, not both");
|
|
65
|
+
if (folderName) argv.push("--folderName", folderName);
|
|
66
|
+
else if (folderId) argv.push("--folderId", folderId);
|
|
67
|
+
else argv.push("--folderName", "inbox");
|
|
68
|
+
const userName = optString(args, "userName");
|
|
69
|
+
const userId = optString(args, "userId");
|
|
70
|
+
if (userName && userId) throw new WorkToolError("ERR_PRISM_WORK_INPUT", "Specify userName or userId, not both");
|
|
71
|
+
if (userName) argv.push("--userName", userName);
|
|
72
|
+
if (userId) argv.push("--userId", userId);
|
|
73
|
+
return argv;
|
|
74
|
+
}
|
|
75
|
+
case "mail.get": {
|
|
76
|
+
const argv = ["outlook", "message", "get", "--output", "json", "--id", reqString(args, "id")];
|
|
77
|
+
const userName = optString(args, "userName");
|
|
78
|
+
const userId = optString(args, "userId");
|
|
79
|
+
if (userName && userId) throw new WorkToolError("ERR_PRISM_WORK_INPUT", "Specify userName or userId, not both");
|
|
80
|
+
if (userName) argv.push("--userName", userName);
|
|
81
|
+
if (userId) argv.push("--userId", userId);
|
|
82
|
+
return argv;
|
|
83
|
+
}
|
|
84
|
+
case "mail.send": {
|
|
85
|
+
const argv = [
|
|
86
|
+
"outlook",
|
|
87
|
+
"mail",
|
|
88
|
+
"send",
|
|
89
|
+
"--output",
|
|
90
|
+
"json",
|
|
91
|
+
"--to",
|
|
92
|
+
reqString(args, "to"),
|
|
93
|
+
"--subject",
|
|
94
|
+
reqString(args, "subject"),
|
|
95
|
+
"--bodyContents",
|
|
96
|
+
reqString(args, "bodyContents"),
|
|
97
|
+
];
|
|
98
|
+
const cc = optString(args, "cc");
|
|
99
|
+
const bcc = optString(args, "bcc");
|
|
100
|
+
const bodyContentType = optString(args, "bodyContentType");
|
|
101
|
+
if (cc) argv.push("--cc", cc);
|
|
102
|
+
if (bcc) argv.push("--bcc", bcc);
|
|
103
|
+
if (bodyContentType) argv.push("--bodyContentType", bodyContentType);
|
|
104
|
+
return argv;
|
|
105
|
+
}
|
|
106
|
+
case "calendar.list": {
|
|
107
|
+
const argv = ["outlook", "event", "list", "--output", "json"];
|
|
108
|
+
const calendarId = optString(args, "calendarId");
|
|
109
|
+
const calendarName = optString(args, "calendarName");
|
|
110
|
+
if (calendarId && calendarName) throw new WorkToolError("ERR_PRISM_WORK_INPUT", "Specify calendarId or calendarName, not both");
|
|
111
|
+
if (calendarId) argv.push("--calendarId", calendarId);
|
|
112
|
+
else argv.push("--calendarName", calendarName ?? "Calendar");
|
|
113
|
+
const userName = optString(args, "userName");
|
|
114
|
+
const userId = optString(args, "userId");
|
|
115
|
+
if (userName && userId) throw new WorkToolError("ERR_PRISM_WORK_INPUT", "Specify userName or userId, not both");
|
|
116
|
+
if (userName) argv.push("--userName", userName);
|
|
117
|
+
if (userId) argv.push("--userId", userId);
|
|
118
|
+
const start = optString(args, "startDateTime");
|
|
119
|
+
const end = optString(args, "endDateTime");
|
|
120
|
+
if (start) argv.push("--startDateTime", start);
|
|
121
|
+
if (end) argv.push("--endDateTime", end);
|
|
122
|
+
return argv;
|
|
123
|
+
}
|
|
124
|
+
case "calendar.add": {
|
|
125
|
+
// Docs: m365 outlook event add --subject --start --end (CLI ≥ issue #7123).
|
|
126
|
+
const argv = [
|
|
127
|
+
"outlook",
|
|
128
|
+
"event",
|
|
129
|
+
"add",
|
|
130
|
+
"--output",
|
|
131
|
+
"json",
|
|
132
|
+
"--subject",
|
|
133
|
+
reqString(args, "subject"),
|
|
134
|
+
"--start",
|
|
135
|
+
reqString(args, "start"),
|
|
136
|
+
"--end",
|
|
137
|
+
reqString(args, "end"),
|
|
138
|
+
];
|
|
139
|
+
const calendarId = optString(args, "calendarId");
|
|
140
|
+
const calendarName = optString(args, "calendarName");
|
|
141
|
+
if (calendarId && calendarName) throw new WorkToolError("ERR_PRISM_WORK_INPUT", "Specify calendarId or calendarName, not both");
|
|
142
|
+
if (calendarId) argv.push("--calendarId", calendarId);
|
|
143
|
+
if (calendarName) argv.push("--calendarName", calendarName);
|
|
144
|
+
return argv;
|
|
145
|
+
}
|
|
146
|
+
case "file.list":
|
|
147
|
+
return ["file", "list", "--output", "json", "--webUrl", reqString(args, "webUrl"), "--folderUrl", reqString(args, "folderUrl")];
|
|
148
|
+
case "file.get":
|
|
149
|
+
throw new WorkToolError("ERR_PRISM_WORK_CAPABILITY", "file.get requires the Microsoft 365 HTTP adapter");
|
|
150
|
+
case "file.add":
|
|
151
|
+
return [
|
|
152
|
+
"file",
|
|
153
|
+
"add",
|
|
154
|
+
"--output",
|
|
155
|
+
"json",
|
|
156
|
+
"--folderUrl",
|
|
157
|
+
reqString(args, "folderUrl"),
|
|
158
|
+
"--filePath",
|
|
159
|
+
reqString(args, "filePath"),
|
|
160
|
+
...(optString(args, "siteUrl") ? ["--siteUrl", optString(args, "siteUrl")!] : []),
|
|
161
|
+
];
|
|
162
|
+
case "file.copy":
|
|
163
|
+
return [
|
|
164
|
+
"file",
|
|
165
|
+
"copy",
|
|
166
|
+
"--output",
|
|
167
|
+
"json",
|
|
168
|
+
"--webUrl",
|
|
169
|
+
reqString(args, "webUrl"),
|
|
170
|
+
"--sourceUrl",
|
|
171
|
+
reqString(args, "sourceUrl"),
|
|
172
|
+
"--targetUrl",
|
|
173
|
+
reqString(args, "targetUrl"),
|
|
174
|
+
];
|
|
175
|
+
case "file.share": {
|
|
176
|
+
const fileUrl = optString(args, "fileUrl");
|
|
177
|
+
const fileId = optString(args, "fileId");
|
|
178
|
+
if ((fileUrl ? 1 : 0) + (fileId ? 1 : 0) !== 1) {
|
|
179
|
+
throw new WorkToolError("ERR_PRISM_WORK_INPUT", "Specify fileUrl or fileId");
|
|
180
|
+
}
|
|
181
|
+
const type = reqString(args, "type");
|
|
182
|
+
if (type !== "view" && type !== "edit") throw new WorkToolError("ERR_PRISM_WORK_INPUT", "type must be view or edit");
|
|
183
|
+
const scope = optString(args, "scope") ?? "organization";
|
|
184
|
+
if (scope === "anonymous")
|
|
185
|
+
throw new WorkToolError("ERR_PRISM_WORK_POLICY", "Anonymous share denied; host must allow explicitly via policy override");
|
|
186
|
+
if (scope !== "organization") throw new WorkToolError("ERR_PRISM_WORK_INPUT", "scope must be organization");
|
|
187
|
+
const argv = [
|
|
188
|
+
"spo",
|
|
189
|
+
"file",
|
|
190
|
+
"sharinglink",
|
|
191
|
+
"add",
|
|
192
|
+
"--output",
|
|
193
|
+
"json",
|
|
194
|
+
"--webUrl",
|
|
195
|
+
reqString(args, "webUrl"),
|
|
196
|
+
"--type",
|
|
197
|
+
type,
|
|
198
|
+
"--scope",
|
|
199
|
+
scope,
|
|
200
|
+
];
|
|
201
|
+
if (fileUrl) argv.push("--fileUrl", fileUrl);
|
|
202
|
+
if (fileId) argv.push("--fileId", fileId);
|
|
203
|
+
return argv;
|
|
204
|
+
}
|
|
205
|
+
case "todo.list": {
|
|
206
|
+
const listName = optString(args, "listName");
|
|
207
|
+
const listId = optString(args, "listId");
|
|
208
|
+
if ((listName ? 1 : 0) + (listId ? 1 : 0) !== 1) throw new WorkToolError("ERR_PRISM_WORK_INPUT", "Specify listName or listId");
|
|
209
|
+
return ["todo", "task", "list", "--output", "json", ...(listName ? ["--listName", listName] : ["--listId", listId!])];
|
|
210
|
+
}
|
|
211
|
+
case "todo.add": {
|
|
212
|
+
const listName = optString(args, "listName");
|
|
213
|
+
const listId = optString(args, "listId");
|
|
214
|
+
if ((listName ? 1 : 0) + (listId ? 1 : 0) !== 1) throw new WorkToolError("ERR_PRISM_WORK_INPUT", "Specify listName or listId");
|
|
215
|
+
return [
|
|
216
|
+
"todo",
|
|
217
|
+
"task",
|
|
218
|
+
"add",
|
|
219
|
+
"--output",
|
|
220
|
+
"json",
|
|
221
|
+
"--title",
|
|
222
|
+
reqString(args, "title"),
|
|
223
|
+
...(listName ? ["--listName", listName] : ["--listId", listId!]),
|
|
224
|
+
];
|
|
225
|
+
}
|
|
226
|
+
case "todo.complete": {
|
|
227
|
+
const listName = optString(args, "listName");
|
|
228
|
+
const listId = optString(args, "listId");
|
|
229
|
+
if ((listName ? 1 : 0) + (listId ? 1 : 0) !== 1) throw new WorkToolError("ERR_PRISM_WORK_INPUT", "Specify listName or listId");
|
|
230
|
+
return [
|
|
231
|
+
"todo",
|
|
232
|
+
"task",
|
|
233
|
+
"set",
|
|
234
|
+
"--output",
|
|
235
|
+
"json",
|
|
236
|
+
"--id",
|
|
237
|
+
reqString(args, "id"),
|
|
238
|
+
"--status",
|
|
239
|
+
"completed",
|
|
240
|
+
...(listName ? ["--listName", listName] : ["--listId", listId!]),
|
|
241
|
+
];
|
|
242
|
+
}
|
|
243
|
+
case "planner.list":
|
|
244
|
+
return ["planner", "task", "list", "--output", "json", "--planId", reqString(args, "planId")];
|
|
245
|
+
case "planner.add":
|
|
246
|
+
return [
|
|
247
|
+
"planner",
|
|
248
|
+
"task",
|
|
249
|
+
"add",
|
|
250
|
+
"--output",
|
|
251
|
+
"json",
|
|
252
|
+
"--title",
|
|
253
|
+
reqString(args, "title"),
|
|
254
|
+
"--planId",
|
|
255
|
+
reqString(args, "planId"),
|
|
256
|
+
"--bucketId",
|
|
257
|
+
reqString(args, "bucketId"),
|
|
258
|
+
];
|
|
259
|
+
case "planner.complete":
|
|
260
|
+
return ["planner", "task", "set", "--output", "json", "--id", reqString(args, "id"), "--percentComplete", "100"];
|
|
261
|
+
default: {
|
|
262
|
+
const _exhaustive: never = op;
|
|
263
|
+
throw new WorkToolError("ERR_PRISM_WORK_OP", `Unknown op ${_exhaustive}`);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
export interface Microsoft365CliAdapterOptions {
|
|
269
|
+
readonly binary: string;
|
|
270
|
+
readonly identity: AgentIdentity;
|
|
271
|
+
readonly configDir: string;
|
|
272
|
+
readonly allowedOps?: readonly Microsoft365Op[];
|
|
273
|
+
readonly limits?: WorkLimits;
|
|
274
|
+
readonly runner?: WorkCliRunner;
|
|
275
|
+
readonly env?: Readonly<Record<string, string>>;
|
|
276
|
+
readonly minVersion?: string;
|
|
277
|
+
/** Late-bound per-identity token source; undefined token fails the call closed. */
|
|
278
|
+
readonly tokenProvider?: WorkTokenProvider;
|
|
279
|
+
readonly draftStore?: WorkDraftStore;
|
|
280
|
+
readonly checkpoints?: CheckpointStore;
|
|
281
|
+
readonly bodies?: ArtifactBodyStore;
|
|
282
|
+
readonly ephemeralDrafts?: boolean;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
export function createMicrosoft365CliAdapter(options: Microsoft365CliAdapterOptions): Microsoft365Adapter {
|
|
286
|
+
assertIdentityActive(options.identity);
|
|
287
|
+
const allowedOps = new Set(options.allowedOps ?? DEFAULT_M365_OPS);
|
|
288
|
+
if (allowedOps.has("file.get")) throw new WorkToolError("ERR_PRISM_WORK_CAPABILITY", "file.get requires the Microsoft 365 HTTP adapter");
|
|
289
|
+
const limits = resolveWorkLimits(options.limits);
|
|
290
|
+
const runner =
|
|
291
|
+
options.runner ??
|
|
292
|
+
createCliRunner({
|
|
293
|
+
binary: options.binary,
|
|
294
|
+
configDir: options.configDir,
|
|
295
|
+
limits: options.limits,
|
|
296
|
+
env: options.env,
|
|
297
|
+
});
|
|
298
|
+
const draftStore: WorkDraftStore =
|
|
299
|
+
options.draftStore ??
|
|
300
|
+
(options.checkpoints
|
|
301
|
+
? createCheckpointWorkDraftStore({
|
|
302
|
+
checkpoints: options.checkpoints,
|
|
303
|
+
bodies: options.bodies,
|
|
304
|
+
limits: options.limits,
|
|
305
|
+
})
|
|
306
|
+
: createMemoryWorkDraftStore({ ephemeral: options.ephemeralDrafts ?? true }));
|
|
307
|
+
let readyVersion: string | undefined;
|
|
308
|
+
|
|
309
|
+
const assertAllowed = (op: Microsoft365Op) => {
|
|
310
|
+
if (!allowedOps.has(op)) throw new WorkToolError("ERR_PRISM_WORK_CAPABILITY", `Operation ${op} not allowed for this identity`);
|
|
311
|
+
};
|
|
312
|
+
|
|
313
|
+
// Resolve the per-identity token env; a configured provider returning undefined means the
|
|
314
|
+
// credential is missing/expired/revoked, so the call fails closed before any side effect.
|
|
315
|
+
const tokenEnv = async (signal?: AbortSignal): Promise<Readonly<Record<string, string>> | undefined> => {
|
|
316
|
+
if (!options.tokenProvider) return undefined;
|
|
317
|
+
const envVars = await options.tokenProvider.tokenEnv(options.identity, signal);
|
|
318
|
+
if (!envVars) throw new WorkToolError("ERR_PRISM_WORK_CREDENTIAL", "Connector credential unavailable, expired, or revoked");
|
|
319
|
+
return envVars;
|
|
320
|
+
};
|
|
321
|
+
|
|
322
|
+
return {
|
|
323
|
+
provider: "microsoft365",
|
|
324
|
+
identity: options.identity,
|
|
325
|
+
allowedOps,
|
|
326
|
+
draftStore,
|
|
327
|
+
async ensureReady(signal) {
|
|
328
|
+
if (readyVersion) return readyVersion;
|
|
329
|
+
assertAllowed("version");
|
|
330
|
+
const argv = buildMicrosoft365Argv("version", {});
|
|
331
|
+
assertSafeArgv(argv);
|
|
332
|
+
const result = await runner.exec(argv, { signal, env: await tokenEnv(signal) });
|
|
333
|
+
if (result.exitCode !== 0) throw new WorkToolError("ERR_PRISM_WORK_CLI", `m365 version failed: ${result.stderr.slice(0, 200)}`);
|
|
334
|
+
const parsed = parseCliJson(result.stdout, limits);
|
|
335
|
+
const version =
|
|
336
|
+
typeof parsed === "string"
|
|
337
|
+
? parsed
|
|
338
|
+
: typeof (parsed as { version?: string })?.version === "string"
|
|
339
|
+
? (parsed as { version: string }).version
|
|
340
|
+
: String(parsed);
|
|
341
|
+
if (options.minVersion && version.replace(/^v/, "") < options.minVersion.replace(/^v/, "")) {
|
|
342
|
+
throw new WorkToolError("ERR_PRISM_WORK_VERSION", `CLI version ${version} below required ${options.minVersion}`);
|
|
343
|
+
}
|
|
344
|
+
readyVersion = version;
|
|
345
|
+
return version;
|
|
346
|
+
},
|
|
347
|
+
async runOp(op, args, signal) {
|
|
348
|
+
assertAllowed(op);
|
|
349
|
+
await this.ensureReady(signal);
|
|
350
|
+
const argv = buildMicrosoft365Argv(op, args);
|
|
351
|
+
assertSafeArgv(argv);
|
|
352
|
+
// Body/request size check for send payloads.
|
|
353
|
+
const body = typeof args.bodyContents === "string" ? args.bodyContents : "";
|
|
354
|
+
if (Buffer.byteLength(body) > limits.maxRequestBytes) {
|
|
355
|
+
throw new WorkToolError("ERR_PRISM_WORK_LIMIT", "Request body exceeds byte limit");
|
|
356
|
+
}
|
|
357
|
+
const result = await runner.exec(argv, { signal, env: await tokenEnv(signal) });
|
|
358
|
+
if (result.exitCode !== 0) {
|
|
359
|
+
throw new WorkToolError("ERR_PRISM_WORK_CLI", `m365 ${op} failed (exit ${result.exitCode})`);
|
|
360
|
+
}
|
|
361
|
+
return parseCliJson(result.stdout, limits);
|
|
362
|
+
},
|
|
363
|
+
createDraft(op, payload, draftOpts) {
|
|
364
|
+
assertAllowed(op);
|
|
365
|
+
return draftStore.createDraft({
|
|
366
|
+
draftId: draftOpts?.draftId,
|
|
367
|
+
provider: "microsoft365",
|
|
368
|
+
op,
|
|
369
|
+
identity: options.identity,
|
|
370
|
+
payload,
|
|
371
|
+
policyRevision: draftOpts?.policyRevision,
|
|
372
|
+
});
|
|
373
|
+
},
|
|
374
|
+
getDraft(draftId) {
|
|
375
|
+
return draftStore.getDraft({ draftId, identity: options.identity, provider: "microsoft365" });
|
|
376
|
+
},
|
|
377
|
+
updateDraft(draftId, payload, draftOpts) {
|
|
378
|
+
return draftStore.updateDraft({
|
|
379
|
+
draftId,
|
|
380
|
+
identity: options.identity,
|
|
381
|
+
payload,
|
|
382
|
+
expectedRevision: draftOpts?.expectedRevision,
|
|
383
|
+
expectedConcurrencyToken: draftOpts?.concurrencyToken,
|
|
384
|
+
});
|
|
385
|
+
},
|
|
386
|
+
approveDraft(approval) {
|
|
387
|
+
return draftStore.approveDraft({
|
|
388
|
+
draftId: approval.draftId,
|
|
389
|
+
identity: options.identity,
|
|
390
|
+
approval,
|
|
391
|
+
});
|
|
392
|
+
},
|
|
393
|
+
markDraft(draftId, status, concurrencyToken) {
|
|
394
|
+
return draftStore.markDraft({
|
|
395
|
+
draftId,
|
|
396
|
+
identity: options.identity,
|
|
397
|
+
status,
|
|
398
|
+
concurrencyToken,
|
|
399
|
+
});
|
|
400
|
+
},
|
|
401
|
+
};
|
|
402
|
+
}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import type { WorkCalendarEvent, WorkFileItem, WorkMailMessage, WorkPage, WorkProvider, WorkTaskItem } from "./types.js";
|
|
2
|
+
|
|
3
|
+
function asRecord(value: unknown): Record<string, unknown> | undefined {
|
|
4
|
+
return value !== null && typeof value === "object" && !Array.isArray(value) ? (value as Record<string, unknown>) : undefined;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
function str(value: unknown): string | undefined {
|
|
8
|
+
return typeof value === "string" && value ? value : undefined;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function num(value: unknown): number | undefined {
|
|
12
|
+
return typeof value === "number" && Number.isFinite(value) ? value : undefined;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/** Map provider-specific mail payloads onto the shared WorkMailMessage shape. */
|
|
16
|
+
export function normalizeMailMessage(provider: WorkProvider, raw: unknown, citationId?: string): WorkMailMessage {
|
|
17
|
+
const obj = asRecord(raw) ?? {};
|
|
18
|
+
const resourceId = str(obj.id) ?? str(obj.messageId) ?? citationId;
|
|
19
|
+
return {
|
|
20
|
+
citationId: citationId ?? resourceId ?? `${provider}:mail`,
|
|
21
|
+
provider,
|
|
22
|
+
resourceId,
|
|
23
|
+
subject: str(obj.subject) ?? str(obj.Subject),
|
|
24
|
+
preview: str(obj.preview) ?? str(obj.snippet) ?? str(obj.bodyPreview),
|
|
25
|
+
from: (() => {
|
|
26
|
+
const direct = str(obj.from);
|
|
27
|
+
if (direct) return direct;
|
|
28
|
+
const nested = asRecord(obj.from);
|
|
29
|
+
const addr = asRecord(nested?.emailAddress);
|
|
30
|
+
return str(addr?.address) ?? str(nested?.email);
|
|
31
|
+
})(),
|
|
32
|
+
to: Array.isArray(obj.to) ? obj.to.filter((v): v is string => typeof v === "string") : undefined,
|
|
33
|
+
receivedAt: str(obj.receivedAt) ?? str(obj.receivedDateTime) ?? str(obj.internalDate),
|
|
34
|
+
isDraft: typeof obj.isDraft === "boolean" ? obj.isDraft : undefined,
|
|
35
|
+
changeKey: str(obj.changeKey) ?? str(obj.etag) ?? str(obj.historyId),
|
|
36
|
+
untrusted: true,
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/** Map provider-specific calendar payloads onto WorkCalendarEvent. */
|
|
41
|
+
export function normalizeCalendarEvent(provider: WorkProvider, raw: unknown, citationId?: string): WorkCalendarEvent {
|
|
42
|
+
const obj = asRecord(raw) ?? {};
|
|
43
|
+
const start = asRecord(obj.start);
|
|
44
|
+
const end = asRecord(obj.end);
|
|
45
|
+
const resourceId = str(obj.id) ?? citationId;
|
|
46
|
+
return {
|
|
47
|
+
citationId: citationId ?? resourceId ?? `${provider}:event`,
|
|
48
|
+
provider,
|
|
49
|
+
resourceId,
|
|
50
|
+
subject: str(obj.subject) ?? str(obj.summary),
|
|
51
|
+
start: str(obj.start) ?? str(start?.dateTime) ?? str(start?.date),
|
|
52
|
+
end: str(obj.end) ?? str(end?.dateTime) ?? str(end?.date),
|
|
53
|
+
changeKey: str(obj.changeKey) ?? str(obj.etag),
|
|
54
|
+
untrusted: true,
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/** Map provider-specific file payloads onto WorkFileItem. */
|
|
59
|
+
export function normalizeFileItem(provider: WorkProvider, raw: unknown, citationId?: string): WorkFileItem {
|
|
60
|
+
const obj = asRecord(raw) ?? {};
|
|
61
|
+
const resourceId = str(obj.id) ?? citationId;
|
|
62
|
+
return {
|
|
63
|
+
citationId: citationId ?? resourceId ?? `${provider}:file`,
|
|
64
|
+
provider,
|
|
65
|
+
resourceId,
|
|
66
|
+
name: str(obj.name) ?? str(obj.Name),
|
|
67
|
+
size: num(obj.size) ?? num(obj.Size),
|
|
68
|
+
eTag: str(obj.eTag) ?? str(obj.etag),
|
|
69
|
+
mimeType: str(obj.mimeType) ?? str(obj.MimeType),
|
|
70
|
+
untrusted: true,
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/** Map provider-specific task payloads onto WorkTaskItem. */
|
|
75
|
+
export function normalizeTaskItem(provider: WorkProvider, raw: unknown, citationId?: string): WorkTaskItem {
|
|
76
|
+
const obj = asRecord(raw) ?? {};
|
|
77
|
+
const resourceId = str(obj.id) ?? citationId;
|
|
78
|
+
return {
|
|
79
|
+
citationId: citationId ?? resourceId ?? `${provider}:task`,
|
|
80
|
+
provider,
|
|
81
|
+
resourceId,
|
|
82
|
+
title: str(obj.title) ?? str(obj.Title),
|
|
83
|
+
status: str(obj.status) ?? str(obj.Status),
|
|
84
|
+
changeKey: str(obj.changeKey) ?? str(obj.etag),
|
|
85
|
+
untrusted: true,
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function extractArray(raw: unknown, keys: readonly string[]): unknown[] {
|
|
90
|
+
if (Array.isArray(raw)) return raw;
|
|
91
|
+
const obj = asRecord(raw);
|
|
92
|
+
if (!obj) return [];
|
|
93
|
+
for (const key of keys) {
|
|
94
|
+
const value = obj[key];
|
|
95
|
+
if (Array.isArray(value)) return value;
|
|
96
|
+
}
|
|
97
|
+
return [];
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export function normalizeMailPage(provider: WorkProvider, raw: unknown, nextCursor?: string): WorkPage<WorkMailMessage> {
|
|
101
|
+
const items = extractArray(raw, ["messages", "value", "items"]).map((item, i) =>
|
|
102
|
+
normalizeMailMessage(provider, item, `${provider}:mail:${i}`),
|
|
103
|
+
);
|
|
104
|
+
return { items, nextCursor, untrusted: true };
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export function normalizeCalendarPage(provider: WorkProvider, raw: unknown, nextCursor?: string): WorkPage<WorkCalendarEvent> {
|
|
108
|
+
const items = extractArray(raw, ["items", "value"]).map((item, i) => normalizeCalendarEvent(provider, item, `${provider}:event:${i}`));
|
|
109
|
+
return { items, nextCursor, untrusted: true };
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export function normalizeFilePage(provider: WorkProvider, raw: unknown, nextCursor?: string): WorkPage<WorkFileItem> {
|
|
113
|
+
const items = extractArray(raw, ["files", "value", "items"]).map((item, i) => normalizeFileItem(provider, item, `${provider}:file:${i}`));
|
|
114
|
+
return { items, nextCursor, untrusted: true };
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
export function normalizeTaskPage(provider: WorkProvider, raw: unknown, nextCursor?: string): WorkPage<WorkTaskItem> {
|
|
118
|
+
const items = extractArray(raw, ["items", "value"]).map((item, i) => normalizeTaskItem(provider, item, `${provider}:task:${i}`));
|
|
119
|
+
return { items, nextCursor, untrusted: true };
|
|
120
|
+
}
|