@klarkxy/dsh-deep-view 0.1.0 → 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.
package/lib/client.js CHANGED
@@ -1033,6 +1033,281 @@ function validateForm(node, values) {
1033
1033
  return { fields };
1034
1034
  }
1035
1035
  //#endregion
1036
+ //#region ../dsh-plugin-kit/src/log-shared.ts
1037
+ const PLUGIN_LOG_LEVELS = [
1038
+ "debug",
1039
+ "info",
1040
+ "warn",
1041
+ "error",
1042
+ "fault"
1043
+ ];
1044
+ const DEFAULT_PLUGIN_LOG_LEVEL = "info";
1045
+ const PLUGIN_LOG_MAX_MESSAGE_CHARS = 16e3;
1046
+ const SOURCE_RE = /^[a-z][a-z0-9-]{0,63}$/;
1047
+ const EVENT_RE = /^[a-z][a-z0-9._-]{0,127}$/;
1048
+ const CONTEXT_KEY_RE = /^[a-zA-Z][a-zA-Z0-9._-]{0,63}$/;
1049
+ const SECRET_KEY_RE = /(?:api[_-]?key|access[_-]?token|refresh[_-]?token|bearer|authorization|cookie|set[_-]?cookie|nonce|credential|private[_-]?key|password|secret|app[_-]?secret|client[_-]?secret|z_c0|d_c0)$/i;
1050
+ const CHAT_PAYLOAD_RE = /"role"\s*:\s*"(?:system|user|assistant|tool)"|"(?:messages|content|prompt|input_text|input_image|image_url)"\s*:\s*[\[{"']/i;
1051
+ const CREDENTIAL_BODY_RE = /-----BEGIN (?:RSA |EC |OPENSSH |PRIVATE )?PRIVATE KEY-----|"type"\s*:\s*"service_account"|credentials\.json|\.dsh[/\\](?:credentials|auth)/i;
1052
+ const AUTH_HEADER_RE = /\b(Authorization|Proxy-Authorization|Cookie|Set-Cookie)\s*:\s*[^\r\n]*/gi;
1053
+ const BEARER_RE = /\bBearer\s+[A-Za-z0-9._\-+=/]{8,}/g;
1054
+ const SECRET_FIELD_RE = /(["']?(?:api[_-]?key|access[_-]?token|refresh[_-]?token|token|bearer|authorization|cookie|set-cookie|nonce|credential|private[_-]?key|password|secret|app[_-]?secret|client[_-]?secret|password|z_c0|d_c0)["']?\s*[:=]\s*)(?:"(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'|[^\s,&;}]+)/gi;
1055
+ const SECRET_QUERY_RE = /([?&](?:token|api[_-]?key|key|secret|password|bootstrap|code|sig|signature|credential|password)=)[^\s&#"']+/gi;
1056
+ const URL_CREDENTIAL_RE = /\b(https?:\/\/)[^\s/:@]+:[^\s/@]+@/gi;
1057
+ const BOOTSTRAP_RE = /\/bootstrap\/[^\s"'?&#]+/gi;
1058
+ const KNOWN_TOKEN_RE = /\b(?:sk-[A-Za-z0-9_-]{10,}|gh[pousr]_[A-Za-z0-9_]{16,}|github_pat_[A-Za-z0-9_]{20,}|tvly-[A-Za-z0-9_-]{10,}|AKIA[0-9A-Z]{16})\b/g;
1059
+ const PATH_RE = /(?:[A-Za-z]:\\|\\\\)[^\s"'`<>|]+|(?:\/(?:home|Users|tmp|var|root)\/|~\/)[^\s"'`<>|]+/g;
1060
+ function isPluginLogLevel(value) {
1061
+ return typeof value === "string" && PLUGIN_LOG_LEVELS.includes(value);
1062
+ }
1063
+ function pluginLogLevelEnabled(level, minimum) {
1064
+ return PLUGIN_LOG_LEVELS.indexOf(level) >= PLUGIN_LOG_LEVELS.indexOf(minimum);
1065
+ }
1066
+ function normalizePluginLogSource(raw) {
1067
+ const stripped = String(raw || "").trim().replace(/^@[^/]+\//, "").toLowerCase().replace(/[^a-z0-9-]+/g, "-").replace(/^-+|-+$/g, "");
1068
+ const bounded = (/^[a-z]/.test(stripped) ? stripped : `p-${stripped}`).slice(0, 64).replace(/-+$/g, "");
1069
+ return SOURCE_RE.test(bounded) ? bounded : "dsh-plugin";
1070
+ }
1071
+ function normalizePluginLogEvent(raw) {
1072
+ const cleaned = String(raw || "").trim().toLowerCase().replace(/[^a-z0-9._-]+/g, "-").replace(/^[^a-z]+/, "").slice(0, 128);
1073
+ return EVENT_RE.test(cleaned) ? cleaned : "plugin.event";
1074
+ }
1075
+ /**
1076
+ * Parse a level specification like `debug` or `dsh-zhihu=debug,dsh-dot:warn,info`.
1077
+ * Source-specific rules win over a bare fallback level.
1078
+ */
1079
+ function parsePluginLogLevel(spec, source, fallback = DEFAULT_PLUGIN_LOG_LEVEL) {
1080
+ if (!spec || typeof spec !== "string") return fallback;
1081
+ const normalizedSource = source ? normalizePluginLogSource(source) : void 0;
1082
+ let wildcard;
1083
+ for (const token of spec.split(",").map((part) => part.trim()).filter(Boolean)) {
1084
+ const lowered = token.toLowerCase();
1085
+ if (isPluginLogLevel(lowered)) {
1086
+ wildcard = lowered;
1087
+ continue;
1088
+ }
1089
+ const match = /^([^=:]+)[=:]([a-z]+)$/i.exec(token);
1090
+ if (!match) continue;
1091
+ const target = match[1].trim();
1092
+ const candidate = match[2].trim().toLowerCase();
1093
+ if (!isPluginLogLevel(candidate)) continue;
1094
+ if (target === "*") {
1095
+ wildcard = candidate;
1096
+ continue;
1097
+ }
1098
+ if (normalizedSource && normalizePluginLogSource(target) === normalizedSource) return candidate;
1099
+ }
1100
+ return wildcard ?? fallback;
1101
+ }
1102
+ function sanitizePluginLogText(text, maxChars = PLUGIN_LOG_MAX_MESSAGE_CHARS) {
1103
+ if (!text) return "";
1104
+ if (CREDENTIAL_BODY_RE.test(text)) return "[omitted credential material]";
1105
+ if (CHAT_PAYLOAD_RE.test(text)) return "[omitted chat payload]";
1106
+ return truncateLogText(text.replace(AUTH_HEADER_RE, "$1: [redacted]").replace(BEARER_RE, "Bearer [redacted]").replace(SECRET_FIELD_RE, (full, prefix) => {
1107
+ const value = full.slice(prefix.length);
1108
+ if (value.startsWith("\"")) return `${prefix}"[redacted]"`;
1109
+ if (value.startsWith("'")) return `${prefix}'[redacted]'`;
1110
+ return `${prefix}[redacted]`;
1111
+ }).replace(SECRET_QUERY_RE, "$1[redacted]").replace(URL_CREDENTIAL_RE, "$1[redacted]@").replace(BOOTSTRAP_RE, "/bootstrap/[redacted]").replace(KNOWN_TOKEN_RE, "[redacted]").replace(PATH_RE, "[path]"), maxChars);
1112
+ }
1113
+ function sanitizePluginLogContext(input) {
1114
+ if (!input) return void 0;
1115
+ const output = {};
1116
+ for (const [key, value] of Object.entries(input).slice(0, 32)) {
1117
+ if (value === void 0 || !CONTEXT_KEY_RE.test(key)) continue;
1118
+ if (typeof value === "number" && !Number.isFinite(value)) continue;
1119
+ if (SECRET_KEY_RE.test(key)) {
1120
+ output[key] = "[redacted]";
1121
+ continue;
1122
+ }
1123
+ output[key] = typeof value === "string" ? sanitizePluginLogText(value, 1e3) : value;
1124
+ }
1125
+ if (!Object.keys(output).length) return void 0;
1126
+ if (JSON.stringify(output).length <= 8e3) return output;
1127
+ return {
1128
+ omitted: true,
1129
+ reason: "Diagnostic context exceeded its size limit."
1130
+ };
1131
+ }
1132
+ function sanitizePluginLogError(error) {
1133
+ if (error === void 0) return void 0;
1134
+ const row = error && typeof error === "object" ? error : {};
1135
+ const rawMessage = typeof row.message === "string" ? row.message : String(error);
1136
+ const result = {
1137
+ name: typeof row.name === "string" && row.name.trim() ? truncateLogText(row.name.trim(), 100) : "Error",
1138
+ message: sanitizePluginLogText(rawMessage) || "Unknown error"
1139
+ };
1140
+ if (typeof row.stack === "string" && row.stack.trim()) result.stack = sanitizePluginLogText(row.stack, 24e3);
1141
+ if (typeof row.code === "string" && /^[A-Za-z0-9_./:-]{1,100}$/.test(row.code)) result.code = row.code;
1142
+ else if (typeof row.code === "number" && Number.isFinite(row.code)) result.code = String(row.code);
1143
+ return result;
1144
+ }
1145
+ function mergePluginLogContext(base, extra) {
1146
+ if (!base) return extra;
1147
+ if (!extra) return base;
1148
+ return {
1149
+ ...base,
1150
+ ...extra
1151
+ };
1152
+ }
1153
+ function buildPluginLogEntry(input, meta) {
1154
+ const entry = {
1155
+ version: 1,
1156
+ at: meta.at.toISOString(),
1157
+ level: isPluginLogLevel(input.level) ? input.level : "info",
1158
+ source: normalizePluginLogSource(meta.source),
1159
+ surface: meta.surface,
1160
+ ...meta.profile ? { profile: meta.profile } : {},
1161
+ event: normalizePluginLogEvent(input.event),
1162
+ message: sanitizePluginLogText(input.message || "No diagnostic message was provided.", PLUGIN_LOG_MAX_MESSAGE_CHARS),
1163
+ ...meta.pid !== void 0 ? { pid: meta.pid } : {}
1164
+ };
1165
+ const context = sanitizePluginLogContext(mergePluginLogContext(meta.correlation, input.context));
1166
+ if (context) entry.context = context;
1167
+ const error = sanitizePluginLogError(input.error);
1168
+ if (error) entry.error = error;
1169
+ return entry;
1170
+ }
1171
+ function createChildPluginLogger(parent, bound) {
1172
+ return {
1173
+ get source() {
1174
+ return parent.source;
1175
+ },
1176
+ get file() {
1177
+ return parent.file;
1178
+ },
1179
+ get lastWriteError() {
1180
+ return parent.lastWriteError;
1181
+ },
1182
+ debug: (event, message, context) => parent.debug(event, message, mergePluginLogContext(bound, context)),
1183
+ info: (event, message, context) => parent.info(event, message, mergePluginLogContext(bound, context)),
1184
+ warn: (event, message, error, context) => parent.warn(event, message, error, mergePluginLogContext(bound, context)),
1185
+ error: (event, message, error, context) => parent.error(event, message, error, mergePluginLogContext(bound, context)),
1186
+ fault: (event, message, error, context) => parent.fault(event, message, error, mergePluginLogContext(bound, context)),
1187
+ write: (input) => parent.write({
1188
+ ...input,
1189
+ context: mergePluginLogContext(bound, input.context)
1190
+ }),
1191
+ child: (next) => createChildPluginLogger(parent, mergePluginLogContext(bound, next) ?? {})
1192
+ };
1193
+ }
1194
+ function truncateLogText(text, maxChars) {
1195
+ if (text.length <= maxChars) return text;
1196
+ const marker = "[truncated]\n";
1197
+ if (maxChars <= 12) return text.slice(0, Math.max(0, maxChars));
1198
+ return `${marker}${text.slice(-(maxChars - 12))}`;
1199
+ }
1200
+ //#endregion
1201
+ //#region ../dsh-plugin-kit/src/client-logger.ts
1202
+ const CLIENT_PLUGIN_LOG_GLOBAL = "__KLARKXY_PLUGIN_LOGS__";
1203
+ function readStorageFlag(key) {
1204
+ try {
1205
+ const value = (globalThis.window?.localStorage)?.getItem?.(key);
1206
+ return typeof value === "string" && value.trim() ? value.trim() : void 0;
1207
+ } catch {
1208
+ return;
1209
+ }
1210
+ }
1211
+ function sharedClientBuffer(limit) {
1212
+ const carrier = globalThis;
1213
+ if (!Array.isArray(carrier["__KLARKXY_PLUGIN_LOGS__"])) try {
1214
+ carrier[CLIENT_PLUGIN_LOG_GLOBAL] = [];
1215
+ } catch {
1216
+ return [];
1217
+ }
1218
+ const list = carrier[CLIENT_PLUGIN_LOG_GLOBAL];
1219
+ const overflow = list.length - limit;
1220
+ if (overflow > 0) list.splice(0, overflow);
1221
+ return list;
1222
+ }
1223
+ function createClientPluginLogger(source, ctx, options = {}) {
1224
+ const normalized = normalizePluginLogSource(source);
1225
+ const now = options.now ?? (() => /* @__PURE__ */ new Date());
1226
+ const limit = Math.max(10, options.bufferLimit ?? 500);
1227
+ const browserCtx = ctx && typeof ctx === "object" ? ctx : void 0;
1228
+ const resolveMinimum = () => {
1229
+ if (options.minimumLevel) return options.minimumLevel;
1230
+ return parsePluginLogLevel(readStorageFlag("dsh-plugin-log-level"), normalized, DEFAULT_PLUGIN_LOG_LEVEL);
1231
+ };
1232
+ const logger = {
1233
+ source: normalized,
1234
+ file: null,
1235
+ lastWriteError: null,
1236
+ debug: (event, message, context) => logger.write({
1237
+ level: "debug",
1238
+ event,
1239
+ message,
1240
+ ...context ? { context } : {}
1241
+ }),
1242
+ info: (event, message, context) => logger.write({
1243
+ level: "info",
1244
+ event,
1245
+ message,
1246
+ ...context ? { context } : {}
1247
+ }),
1248
+ warn: (event, message, error, context) => logger.write({
1249
+ level: "warn",
1250
+ event,
1251
+ message,
1252
+ ...error !== void 0 ? { error } : {},
1253
+ ...context ? { context } : {}
1254
+ }),
1255
+ error: (event, message, error, context) => logger.write({
1256
+ level: "error",
1257
+ event,
1258
+ message,
1259
+ ...error !== void 0 ? { error } : {},
1260
+ ...context ? { context } : {}
1261
+ }),
1262
+ fault: (event, message, error, context) => logger.write({
1263
+ level: "fault",
1264
+ event,
1265
+ message,
1266
+ ...error !== void 0 ? { error } : {},
1267
+ ...context ? { context } : {}
1268
+ }),
1269
+ child: (context) => createChildPluginLogger(logger, context),
1270
+ write(input) {
1271
+ try {
1272
+ if (!pluginLogLevelEnabled(input.level, resolveMinimum())) return false;
1273
+ const entry = buildPluginLogEntry(input, {
1274
+ at: now(),
1275
+ source: normalized,
1276
+ surface: "client"
1277
+ });
1278
+ const buffer = sharedClientBuffer(limit);
1279
+ buffer.push(entry);
1280
+ const overflow = buffer.length - limit;
1281
+ if (overflow > 0) buffer.splice(0, overflow);
1282
+ if (options.forwardToHostLogger !== false && browserCtx?.logger) {
1283
+ const summary = sanitizePluginLogText(`${normalized} [${entry.event}]: ${entry.message}`, 500);
1284
+ if (entry.level === "warn" && typeof browserCtx.logger.warn === "function") browserCtx.logger.warn(summary);
1285
+ else if ((entry.level === "error" || entry.level === "fault") && typeof browserCtx.logger.error === "function") browserCtx.logger.error(summary);
1286
+ }
1287
+ if (readStorageFlag("dsh-plugin-log-console") === "1") {
1288
+ const con = globalThis.console;
1289
+ (entry.level === "debug" ? con?.debug : entry.level === "info" ? con?.info : entry.level === "warn" ? con?.warn : con?.error)?.call(con, `[${normalized}] ${entry.event}: ${entry.message}`, entry);
1290
+ }
1291
+ return true;
1292
+ } catch {
1293
+ return false;
1294
+ }
1295
+ }
1296
+ };
1297
+ return logger;
1298
+ }
1299
+ function installClientPluginLogger(ctx, source, options = {}) {
1300
+ const logger = createClientPluginLogger(source, ctx, options);
1301
+ logger.info("client.loaded", "Client plugin initialized.", options.loadedContext);
1302
+ const browserCtx = ctx && typeof ctx === "object" ? ctx : void 0;
1303
+ if (typeof browserCtx?.effect === "function") try {
1304
+ browserCtx.effect(() => () => {
1305
+ logger.debug("client.disposed", "Client plugin disposed.");
1306
+ }, `${logger.source}.client-logger`);
1307
+ } catch {}
1308
+ return logger;
1309
+ }
1310
+ //#endregion
1036
1311
  //#region src/contracts.ts
1037
1312
  const PLUGIN_NAME = "@klarkxy/dsh-deep-view";
1038
1313
  const RPC_CHANNEL = "/dsh-deep-view";
@@ -2699,14 +2974,7 @@ function sameAnswers(left, right) {
2699
2974
  });
2700
2975
  }
2701
2976
  //#endregion
2702
- //#region src/client.tsx
2703
- const name = "dsh-deep-view-client";
2704
- const inject = [
2705
- "slots",
2706
- "connection",
2707
- "locale"
2708
- ];
2709
- const LOCALE = "deep-view";
2977
+ //#region src/copy.ts
2710
2978
  const uiZh = {
2711
2979
  copy: "复制",
2712
2980
  copied: "已复制",
@@ -2771,6 +3039,15 @@ const uiEn = {
2771
3039
  send: "Send",
2772
3040
  selected: "Selected"
2773
3041
  };
3042
+ //#endregion
3043
+ //#region src/client.tsx
3044
+ const name = "dsh-deep-view-client";
3045
+ const inject = [
3046
+ "slots",
3047
+ "connection",
3048
+ "locale"
3049
+ ];
3050
+ const LOCALE = "deep-view";
2774
3051
  const viewT = (t) => (key, params) => {
2775
3052
  const keys = {
2776
3053
  Copy: "copy",
@@ -2927,15 +3204,29 @@ function ToolCallView(props) {
2927
3204
  action,
2928
3205
  values
2929
3206
  }).then((result) => {
2930
- if (result?.ok) {
3207
+ const envelope = result;
3208
+ if (envelope?.ok) {
2931
3209
  setAnswer({
2932
3210
  id: pending.id,
2933
3211
  action,
2934
3212
  values
2935
3213
  });
2936
3214
  setPending(null);
2937
- } else setFailed(true);
2938
- }).catch(() => setFailed(true)).finally(() => setBusy(false));
3215
+ } else {
3216
+ createClientPluginLogger(PLUGIN_NAME).warn("reply.rejected", "Deep View reply was rejected by host.", void 0, {
3217
+ sessionId: props.sessionId,
3218
+ viewId: pending.id,
3219
+ code: envelope && !envelope.ok ? envelope.error.code : null
3220
+ });
3221
+ setFailed(true);
3222
+ }
3223
+ }).catch((error) => {
3224
+ createClientPluginLogger(PLUGIN_NAME).error("reply.transport-error", "Deep View reply RPC failed.", error, {
3225
+ sessionId: props.sessionId,
3226
+ viewId: pending.id
3227
+ });
3228
+ setFailed(true);
3229
+ }).finally(() => setBusy(false));
2939
3230
  }, [
2940
3231
  props.call,
2941
3232
  props.sessionId,
@@ -2967,7 +3258,7 @@ function ToolCallView(props) {
2967
3258
  view: shown.view,
2968
3259
  onSubmit: canAnswer ? submit : void 0,
2969
3260
  busy,
2970
- settled: answer !== null || !canAnswer,
3261
+ settled: answer !== null || shown.awaitReply && !canAnswer,
2971
3262
  answer,
2972
3263
  t: viewT(t),
2973
3264
  labels,
@@ -3035,8 +3326,65 @@ function ToolCallStatus(props) {
3035
3326
  children: props.t(read.isError ? "error" : read.phase === "result" && !read.presentation ? "invalid" : read.phase === "result" ? "prepared" : "preparing")
3036
3327
  });
3037
3328
  }
3329
+ /** Client service name other plugins read to draw show_view cards in their own surfaces. */
3330
+ const CARDS_SERVICE = "dshDeepView";
3331
+ function staticArgs(values) {
3332
+ return {
3333
+ has: (key) => values[key] !== void 0,
3334
+ complete: (key) => values[key] !== void 0,
3335
+ text: (key) => typeof values[key] === "string" ? values[key] : void 0,
3336
+ value: (key) => values[key]
3337
+ };
3338
+ }
3339
+ /** One show_view card for a plugin-drawn chat: same card, same answer channel as the host chat. */
3340
+ function createCards(call, locale) {
3341
+ const subscribe = (listener) => locale?.subscribe?.(listener) ?? (() => {});
3342
+ const active = () => locale?.getSnapshot?.().active ?? "en";
3343
+ function Card(props) {
3344
+ const language = (0, react.useSyncExternalStore)(subscribe, active);
3345
+ const t = (0, react.useMemo)(() => {
3346
+ const table = language.toLowerCase().startsWith("zh") ? uiZh : uiEn;
3347
+ return (key, params) => (table[key] ?? key).replace(/\{(\w+)\}/g, (_, name) => String(params?.[name] ?? `{${name}}`));
3348
+ }, [language]);
3349
+ const block = (0, react.useMemo)(() => props.presentation !== void 0 ? {
3350
+ callId: props.callId,
3351
+ kind: "tool-result",
3352
+ meta: props.presentation,
3353
+ isError: false
3354
+ } : props.failed ? {
3355
+ callId: props.callId,
3356
+ kind: "tool-result",
3357
+ isError: true
3358
+ } : {
3359
+ callId: props.callId,
3360
+ args: staticArgs({
3361
+ title: props.title,
3362
+ view: props.view
3363
+ })
3364
+ }, [
3365
+ props.callId,
3366
+ props.presentation,
3367
+ props.failed,
3368
+ props.title,
3369
+ props.view
3370
+ ]);
3371
+ const phase = props.presentation !== void 0 || props.failed ? "result" : "start";
3372
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ToolCallView, {
3373
+ sessionId: props.sessionId,
3374
+ callId: props.callId,
3375
+ phase,
3376
+ block,
3377
+ t,
3378
+ call,
3379
+ ...props.answer ? { restoredAnswer: props.answer } : {}
3380
+ });
3381
+ }
3382
+ return { Card };
3383
+ }
3038
3384
  function apply(ctx) {
3039
3385
  const client = ctx;
3386
+ installClientPluginLogger(ctx, PLUGIN_NAME);
3387
+ client.provide(CARDS_SERVICE, createCards((endpoint, payload) => client.connection.rpc.call(RPC_CHANNEL, endpoint, payload), client.locale));
3040
3388
  ctx.effect(() => client.locale.register(LOCALE, {
3041
3389
  zh: { ...uiZh },
3042
3390
  en: { ...uiEn }
@@ -3063,11 +3411,13 @@ function apply(ctx) {
3063
3411
  }, ReplyView)), "deep-view.reply");
3064
3412
  }
3065
3413
  //#endregion
3414
+ exports.CARDS_SERVICE = CARDS_SERVICE;
3066
3415
  exports.LOCALE = LOCALE;
3067
3416
  exports.ReplyView = ReplyView;
3068
3417
  exports.ToolCallStatus = ToolCallStatus;
3069
3418
  exports.ToolCallView = ToolCallView;
3070
3419
  exports.apply = apply;
3420
+ exports.createCards = createCards;
3071
3421
  exports.inject = inject;
3072
3422
  exports.name = name;
3073
3423
  exports.readToolCall = readToolCall;
@@ -1,98 +1,2 @@
1
- import { RpcResult as RpcResult$1 } from "@klarkxy/dsh-plugin-kit/contracts";
2
- //#region src/contracts.d.ts
3
- type RpcResult<T = unknown> = RpcResult$1<T>;
4
- declare const PLUGIN_NAME = "@klarkxy/dsh-deep-view";
5
- declare const RPC_CHANNEL = "/dsh-deep-view";
6
- declare const VIEW_OWNER = "dsh-deep-view";
7
- type Scalar = string | number | boolean;
8
- type Formula = {
9
- '=': string;
10
- };
11
- type Value = Scalar | Formula;
12
- type ChoiceOption = {
13
- label: string;
14
- value?: Scalar;
15
- };
16
- type ViewNode = {
17
- type: 'stack' | 'row' | 'text' | 'metric' | 'table' | 'chart' | 'progress' | 'callout' | 'sources' | 'slider' | 'number' | 'choice' | 'toggle' | 'options' | 'confirm' | 'form' | 'submit';
18
- id?: string;
19
- children?: ViewNode[];
20
- let?: Record<string, string>;
21
- text?: Value;
22
- label?: string;
23
- value?: Value;
24
- tone?: Value;
25
- caption?: Value;
26
- columns?: {
27
- key: string;
28
- label: string;
29
- }[];
30
- rows?: Value[][];
31
- kind?: 'bar' | 'hbar' | 'line' | 'area' | 'donut';
32
- categories?: Scalar[];
33
- series?: {
34
- name?: string;
35
- values: (number | Formula)[];
36
- }[];
37
- unit?: string;
38
- percent?: Value;
39
- max?: Value;
40
- valueLabel?: Value;
41
- items?: {
42
- label: string;
43
- url: string;
44
- }[];
45
- min?: number;
46
- step?: number;
47
- options?: ChoiceOption[] | {
48
- label: string;
49
- description?: string;
50
- }[];
51
- multi?: boolean;
52
- confirmLabel?: string;
53
- cancelLabel?: string;
54
- fields?: {
55
- id: string;
56
- label: string;
57
- placeholder?: string;
58
- }[];
59
- submitLabel?: string;
60
- };
61
- type ShownView = {
62
- title: string;
63
- view: ViewNode;
64
- interactive: boolean;
65
- };
66
- type ViewFailure = {
67
- error: string;
68
- };
69
- type PendingView = {
70
- id: string;
71
- sessionId: string;
72
- callId?: string;
73
- title: string;
74
- view: ViewNode;
75
- };
76
- type ViewAnswer = {
77
- id: string;
78
- action: string;
79
- values: Record<string, unknown>;
80
- };
81
- /** Stored on the same user message as its readable answer, outside model text. */
82
- type ViewAnswerMetadata = {
83
- owner: typeof VIEW_OWNER;
84
- version: 1;
85
- answer: ViewAnswer;
86
- };
87
- type ViewPresentation = {
88
- owner: typeof VIEW_OWNER;
89
- viewId?: string;
90
- title: string;
91
- view: ViewNode;
92
- interactive: boolean;
93
- awaitReply: boolean;
94
- };
95
- declare function isRecord(value: unknown): value is Record<string, unknown>;
96
- //#endregion
97
- export { ChoiceOption, Formula, PLUGIN_NAME, PendingView, RPC_CHANNEL, RpcResult, Scalar, ShownView, VIEW_OWNER, Value, ViewAnswer, ViewAnswerMetadata, ViewFailure, ViewNode, ViewPresentation, isRecord };
98
- //# sourceMappingURL=contracts.d.ts.map
1
+ import { _ as ViewPresentation, a as PLUGIN_NAME, c as RpcResult, d as VIEW_OWNER, f as Value, g as ViewNode, h as ViewFailure, i as HOST_SERVICE, l as Scalar, m as ViewAnswerMetadata, n as DeepViewHost, o as PendingView, p as ViewAnswer, r as Formula, s as RPC_CHANNEL, t as ChoiceOption, u as ShownView, v as isRecord } from "./contracts2.js";
2
+ export { ChoiceOption, DeepViewHost, Formula, HOST_SERVICE, PLUGIN_NAME, PendingView, RPC_CHANNEL, RpcResult, Scalar, ShownView, VIEW_OWNER, Value, ViewAnswer, ViewAnswerMetadata, ViewFailure, ViewNode, ViewPresentation, isRecord };
package/lib/contracts.js CHANGED
@@ -2,10 +2,11 @@
2
2
  const PLUGIN_NAME = "@klarkxy/dsh-deep-view";
3
3
  const RPC_CHANNEL = "/dsh-deep-view";
4
4
  const VIEW_OWNER = "dsh-deep-view";
5
+ const HOST_SERVICE = "dshDeepView";
5
6
  function isRecord(value) {
6
7
  return value !== null && typeof value === "object" && !Array.isArray(value);
7
8
  }
8
9
  //#endregion
9
- export { PLUGIN_NAME, RPC_CHANNEL, VIEW_OWNER, isRecord };
10
+ export { HOST_SERVICE, PLUGIN_NAME, RPC_CHANNEL, VIEW_OWNER, isRecord };
10
11
 
11
12
  //# sourceMappingURL=contracts.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"contracts.js","names":[],"sources":["../src/contracts.ts"],"sourcesContent":["import type { RpcResult as SharedRpcResult } from '@klarkxy/dsh-plugin-kit/contracts'\nexport type RpcResult<T = unknown> = SharedRpcResult<T>\nexport const PLUGIN_NAME = '@klarkxy/dsh-deep-view'\nexport const RPC_CHANNEL = '/dsh-deep-view'\nexport const VIEW_OWNER = 'dsh-deep-view'\n\nexport type Scalar = string | number | boolean\nexport type Formula = { '=': string }\nexport type Value = Scalar | Formula\nexport type ChoiceOption = { label: string; value?: Scalar }\nexport type ViewNode = {\n type: 'stack' | 'row' | 'text' | 'metric' | 'table' | 'chart' | 'progress' | 'callout' | 'sources'\n | 'slider' | 'number' | 'choice' | 'toggle' | 'options' | 'confirm' | 'form' | 'submit'\n id?: string\n children?: ViewNode[]\n let?: Record<string, string>\n text?: Value\n label?: string\n value?: Value\n tone?: Value\n caption?: Value\n columns?: { key: string; label: string }[]\n rows?: Value[][]\n kind?: 'bar' | 'hbar' | 'line' | 'area' | 'donut'\n categories?: Scalar[]\n series?: { name?: string; values: (number | Formula)[] }[]\n unit?: string\n percent?: Value\n max?: Value\n valueLabel?: Value\n items?: { label: string; url: string }[]\n min?: number\n step?: number\n options?: ChoiceOption[] | { label: string; description?: string }[]\n multi?: boolean\n confirmLabel?: string\n cancelLabel?: string\n fields?: { id: string; label: string; placeholder?: string }[]\n submitLabel?: string\n}\nexport type ShownView = { title: string; view: ViewNode; interactive: boolean }\nexport type ViewFailure = { error: string }\nexport type PendingView = { id: string; sessionId: string; callId?: string; title: string; view: ViewNode }\nexport type ViewAnswer = { id: string; action: string; values: Record<string, unknown> }\n/** Stored on the same user message as its readable answer, outside model text. */\nexport type ViewAnswerMetadata = { owner: typeof VIEW_OWNER; version: 1; answer: ViewAnswer }\nexport type ViewPresentation = {\n owner: typeof VIEW_OWNER\n viewId?: string\n title: string\n view: ViewNode\n interactive: boolean\n awaitReply: boolean\n}\nexport function isRecord(value: unknown): value is Record<string, unknown> {\n return value !== null && typeof value === 'object' && !Array.isArray(value)\n}\n"],"mappings":";AAEA,MAAa,cAAc;AAC3B,MAAa,cAAc;AAC3B,MAAa,aAAa;AAkD1B,SAAgB,SAAS,OAAkD;CACzE,OAAO,UAAU,QAAQ,OAAO,UAAU,YAAY,CAAC,MAAM,QAAQ,KAAK;AAC5E"}
1
+ {"version":3,"file":"contracts.js","names":[],"sources":["../src/contracts.ts"],"sourcesContent":["import type { RpcResult as SharedRpcResult } from '@klarkxy/dsh-plugin-kit/contracts'\nexport type RpcResult<T = unknown> = SharedRpcResult<T>\nexport const PLUGIN_NAME = '@klarkxy/dsh-deep-view'\nexport const RPC_CHANNEL = '/dsh-deep-view'\nexport const VIEW_OWNER = 'dsh-deep-view'\nexport const HOST_SERVICE = 'dshDeepView'\nexport type DeepViewHost = {\n /** Move an open card and route stale session lookups to a replacement root session. */\n handoffSession(fromSessionId: string, toSessionId: string): boolean\n}\n\nexport type Scalar = string | number | boolean\nexport type Formula = { '=': string }\nexport type Value = Scalar | Formula\nexport type ChoiceOption = { label: string; value?: Scalar }\nexport type ViewNode = {\n type: 'stack' | 'row' | 'text' | 'metric' | 'table' | 'chart' | 'progress' | 'callout' | 'sources'\n | 'slider' | 'number' | 'choice' | 'toggle' | 'options' | 'confirm' | 'form' | 'submit'\n id?: string\n children?: ViewNode[]\n let?: Record<string, string>\n text?: Value\n label?: string\n value?: Value\n tone?: Value\n caption?: Value\n columns?: { key: string; label: string }[]\n rows?: Value[][]\n kind?: 'bar' | 'hbar' | 'line' | 'area' | 'donut'\n categories?: Scalar[]\n series?: { name?: string; values: (number | Formula)[] }[]\n unit?: string\n percent?: Value\n max?: Value\n valueLabel?: Value\n items?: { label: string; url: string }[]\n min?: number\n step?: number\n options?: ChoiceOption[] | { label: string; description?: string }[]\n multi?: boolean\n confirmLabel?: string\n cancelLabel?: string\n fields?: { id: string; label: string; placeholder?: string }[]\n submitLabel?: string\n}\nexport type ShownView = { title: string; view: ViewNode; interactive: boolean }\nexport type ViewFailure = { error: string }\nexport type PendingView = { id: string; sessionId: string; callId?: string; title: string; view: ViewNode }\nexport type ViewAnswer = { id: string; action: string; values: Record<string, unknown> }\n/** Stored on the same user message as its readable answer, outside model text. */\nexport type ViewAnswerMetadata = { owner: typeof VIEW_OWNER; version: 1; answer: ViewAnswer }\nexport type ViewPresentation = {\n owner: typeof VIEW_OWNER\n viewId?: string\n title: string\n view: ViewNode\n interactive: boolean\n awaitReply: boolean\n}\nexport function isRecord(value: unknown): value is Record<string, unknown> {\n return value !== null && typeof value === 'object' && !Array.isArray(value)\n}\n"],"mappings":";AAEA,MAAa,cAAc;AAC3B,MAAa,cAAc;AAC3B,MAAa,aAAa;AAC1B,MAAa,eAAe;AAsD5B,SAAgB,SAAS,OAAkD;CACzE,OAAO,UAAU,QAAQ,OAAO,UAAU,YAAY,CAAC,MAAM,QAAQ,KAAK;AAC5E"}
@@ -0,0 +1,103 @@
1
+ import { RpcResult } from "@klarkxy/dsh-plugin-kit/contracts";
2
+ //#region src/contracts.d.ts
3
+ type RpcResult$1<T = unknown> = RpcResult<T>;
4
+ declare const PLUGIN_NAME = "@klarkxy/dsh-deep-view";
5
+ declare const RPC_CHANNEL = "/dsh-deep-view";
6
+ declare const VIEW_OWNER = "dsh-deep-view";
7
+ declare const HOST_SERVICE = "dshDeepView";
8
+ type DeepViewHost = {
9
+ /** Move an open card and route stale session lookups to a replacement root session. */
10
+ handoffSession(fromSessionId: string, toSessionId: string): boolean;
11
+ };
12
+ type Scalar = string | number | boolean;
13
+ type Formula = {
14
+ '=': string;
15
+ };
16
+ type Value = Scalar | Formula;
17
+ type ChoiceOption = {
18
+ label: string;
19
+ value?: Scalar;
20
+ };
21
+ type ViewNode = {
22
+ type: 'stack' | 'row' | 'text' | 'metric' | 'table' | 'chart' | 'progress' | 'callout' | 'sources' | 'slider' | 'number' | 'choice' | 'toggle' | 'options' | 'confirm' | 'form' | 'submit';
23
+ id?: string;
24
+ children?: ViewNode[];
25
+ let?: Record<string, string>;
26
+ text?: Value;
27
+ label?: string;
28
+ value?: Value;
29
+ tone?: Value;
30
+ caption?: Value;
31
+ columns?: {
32
+ key: string;
33
+ label: string;
34
+ }[];
35
+ rows?: Value[][];
36
+ kind?: 'bar' | 'hbar' | 'line' | 'area' | 'donut';
37
+ categories?: Scalar[];
38
+ series?: {
39
+ name?: string;
40
+ values: (number | Formula)[];
41
+ }[];
42
+ unit?: string;
43
+ percent?: Value;
44
+ max?: Value;
45
+ valueLabel?: Value;
46
+ items?: {
47
+ label: string;
48
+ url: string;
49
+ }[];
50
+ min?: number;
51
+ step?: number;
52
+ options?: ChoiceOption[] | {
53
+ label: string;
54
+ description?: string;
55
+ }[];
56
+ multi?: boolean;
57
+ confirmLabel?: string;
58
+ cancelLabel?: string;
59
+ fields?: {
60
+ id: string;
61
+ label: string;
62
+ placeholder?: string;
63
+ }[];
64
+ submitLabel?: string;
65
+ };
66
+ type ShownView = {
67
+ title: string;
68
+ view: ViewNode;
69
+ interactive: boolean;
70
+ };
71
+ type ViewFailure = {
72
+ error: string;
73
+ };
74
+ type PendingView = {
75
+ id: string;
76
+ sessionId: string;
77
+ callId?: string;
78
+ title: string;
79
+ view: ViewNode;
80
+ };
81
+ type ViewAnswer = {
82
+ id: string;
83
+ action: string;
84
+ values: Record<string, unknown>;
85
+ };
86
+ /** Stored on the same user message as its readable answer, outside model text. */
87
+ type ViewAnswerMetadata = {
88
+ owner: typeof VIEW_OWNER;
89
+ version: 1;
90
+ answer: ViewAnswer;
91
+ };
92
+ type ViewPresentation = {
93
+ owner: typeof VIEW_OWNER;
94
+ viewId?: string;
95
+ title: string;
96
+ view: ViewNode;
97
+ interactive: boolean;
98
+ awaitReply: boolean;
99
+ };
100
+ declare function isRecord(value: unknown): value is Record<string, unknown>;
101
+ //#endregion
102
+ export { ViewPresentation as _, PLUGIN_NAME as a, RpcResult$1 as c, VIEW_OWNER as d, Value as f, ViewNode as g, ViewFailure as h, HOST_SERVICE as i, Scalar as l, ViewAnswerMetadata as m, DeepViewHost as n, PendingView as o, ViewAnswer as p, Formula as r, RPC_CHANNEL as s, ChoiceOption as t, ShownView as u, isRecord as v };
103
+ //# sourceMappingURL=contracts2.d.ts.map