@rubytech/create-maxy-code 0.1.174 → 0.1.175

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/package.json +1 -1
  2. package/payload/platform/neo4j/schema.cypher +49 -10
  3. package/payload/platform/plugins/docs/references/voice-mirror-guide.md +18 -16
  4. package/payload/platform/scripts/setup-account.sh +8 -0
  5. package/payload/platform/scripts/verify-skill-tool-surface.sh +27 -8
  6. package/payload/premium-plugins/writer-craft/PLUGIN.md +11 -7
  7. package/payload/premium-plugins/writer-craft/hooks/__tests__/voice-session-end-text.test.sh +284 -0
  8. package/payload/premium-plugins/writer-craft/hooks/voice-session-end-text.sh +75 -0
  9. package/payload/premium-plugins/writer-craft/mcp/dist/cli/ingest-session-text.d.ts +3 -0
  10. package/payload/premium-plugins/writer-craft/mcp/dist/cli/ingest-session-text.d.ts.map +1 -0
  11. package/payload/premium-plugins/writer-craft/mcp/dist/cli/ingest-session-text.js +58 -0
  12. package/payload/premium-plugins/writer-craft/mcp/dist/cli/ingest-session-text.js.map +1 -0
  13. package/payload/premium-plugins/writer-craft/mcp/dist/index.d.ts.map +1 -1
  14. package/payload/premium-plugins/writer-craft/mcp/dist/index.js +95 -18
  15. package/payload/premium-plugins/writer-craft/mcp/dist/index.js.map +1 -1
  16. package/payload/premium-plugins/writer-craft/mcp/dist/lib/voice-corpus.d.ts +47 -6
  17. package/payload/premium-plugins/writer-craft/mcp/dist/lib/voice-corpus.d.ts.map +1 -1
  18. package/payload/premium-plugins/writer-craft/mcp/dist/lib/voice-corpus.js +69 -6
  19. package/payload/premium-plugins/writer-craft/mcp/dist/lib/voice-corpus.js.map +1 -1
  20. package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-distil-profile.d.ts +8 -2
  21. package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-distil-profile.d.ts.map +1 -1
  22. package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-distil-profile.js +82 -53
  23. package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-distil-profile.js.map +1 -1
  24. package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-ingest-session-text.d.ts +23 -0
  25. package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-ingest-session-text.d.ts.map +1 -0
  26. package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-ingest-session-text.js +191 -0
  27. package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-ingest-session-text.js.map +1 -0
  28. package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-record-feedback.d.ts +6 -0
  29. package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-record-feedback.d.ts.map +1 -1
  30. package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-record-feedback.js +14 -6
  31. package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-record-feedback.js.map +1 -1
  32. package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-retrieve-conditioning.d.ts +12 -1
  33. package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-retrieve-conditioning.d.ts.map +1 -1
  34. package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-retrieve-conditioning.js +23 -12
  35. package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-retrieve-conditioning.js.map +1 -1
  36. package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-tag-content.d.ts +3 -0
  37. package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-tag-content.d.ts.map +1 -1
  38. package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-tag-content.js +33 -5
  39. package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-tag-content.js.map +1 -1
  40. package/payload/premium-plugins/writer-craft/mcp/scripts/smoke.mjs +289 -28
  41. package/payload/premium-plugins/writer-craft/mcp/src/cli/ingest-session-text.ts +65 -0
  42. package/payload/premium-plugins/writer-craft/mcp/src/index.ts +108 -18
  43. package/payload/premium-plugins/writer-craft/mcp/src/lib/voice-corpus.ts +78 -6
  44. package/payload/premium-plugins/writer-craft/mcp/src/tools/voice-distil-profile.ts +115 -56
  45. package/payload/premium-plugins/writer-craft/mcp/src/tools/voice-ingest-session-text.ts +229 -0
  46. package/payload/premium-plugins/writer-craft/mcp/src/tools/voice-record-feedback.ts +20 -6
  47. package/payload/premium-plugins/writer-craft/mcp/src/tools/voice-retrieve-conditioning.ts +38 -13
  48. package/payload/premium-plugins/writer-craft/mcp/src/tools/voice-tag-content.ts +42 -5
  49. package/payload/premium-plugins/writer-craft/skills/voice-mirror/SKILL.md +65 -31
@@ -0,0 +1,75 @@
1
+ #!/usr/bin/env bash
2
+ # SessionEnd hook — auto-ingests operator PTY turns as :Message {format:'text'}
3
+ # corpus nodes in the writer-craft voice corpus.
4
+ #
5
+ # Fired by Claude Code after each PTY session terminates. Receives the full
6
+ # session envelope from stdin:
7
+ # { "session_id": "...", "transcript_path": "...", "hook_event_name": "SessionEnd", ... }
8
+ #
9
+ # Guards (shared logic via admin-graph-pass-common.sh):
10
+ # - role != admin → exit 0 (trigger-skipped reason=role-not-admin)
11
+ # - MAXY_SPECIALIST set → exit 0 (trigger-skipped reason=is-specialist)
12
+ # - empty stdin → exit 0 (trigger-skipped reason=empty-stdin)
13
+ # - missing transcript → exit 0 (trigger-skipped reason=missing-transcript)
14
+ #
15
+ # Additional guard:
16
+ # - CLI not found → exit 0 (trigger-skipped reason=cli-not-found)
17
+ # Graceful: accounts without writer-craft installed skip silently.
18
+ #
19
+ # Environment (inherited from PTY spawn — set by session manager systemd unit):
20
+ # PLATFORM_ROOT — used to locate the admin hooks lib and the CLI
21
+ # ACCOUNT_ID — operator's account identifier
22
+ # USER_ID — operator's userId
23
+ # SESSION_ID — parsed from stdin envelope by agp_parse_stdin
24
+ # NEO4J_URI — bolt URI (propagated from systemd unit env)
25
+ # NEO4J_USER — neo4j username
26
+ # NEO4J_PASSWORD — neo4j password
27
+ #
28
+ # Observability:
29
+ # [voice-session-end-hook] trigger-skipped sessionId=<id> reason=<reason>
30
+ # [voice-session-end-hook] trigger sessionId=<id>
31
+ # [voice-session-end-hook] result=ok sessionId=<id> turns=<n> skipped=<m>
32
+ # [voice-session-end-hook] result=err sessionId=<id> reason=<detail>
33
+
34
+ set -uo pipefail
35
+
36
+ AGP_LOG_TAG="voice-session-end-hook"
37
+
38
+ # Locate the shared plumbing library via PLATFORM_ROOT (set at PTY spawn).
39
+ # This is more robust than a relative path from the hook's own directory.
40
+ AGP_LIB="${PLATFORM_ROOT:-}/plugins/admin/hooks/lib/admin-graph-pass-common.sh"
41
+ if [ ! -f "$AGP_LIB" ]; then
42
+ echo "[${AGP_LOG_TAG}] trigger-skipped sessionId=unknown reason=missing-helper path=${AGP_LIB}" >&2
43
+ exit 0
44
+ fi
45
+ # shellcheck source=../../../platform/plugins/admin/hooks/lib/admin-graph-pass-common.sh
46
+ source "$AGP_LIB"
47
+
48
+ agp_setup_logging
49
+ agp_read_stdin
50
+ agp_parse_stdin
51
+ agp_guard_role_specialist
52
+ agp_guard_transcript require-stdin
53
+
54
+ # Locate the ingest CLI. Built alongside the MCP server — lives in dist/cli/.
55
+ CLI_PATH="${PLATFORM_ROOT:-}/../premium-plugins/writer-craft/mcp/dist/cli/ingest-session-text.js"
56
+ if [ ! -f "$CLI_PATH" ]; then
57
+ agp_emit_log "trigger-skipped sessionId=${SESSION_ID_REPORTED} reason=cli-not-found path=${CLI_PATH}"
58
+ exit 0
59
+ fi
60
+
61
+ agp_emit_log "trigger sessionId=${SESSION_ID_REPORTED}"
62
+
63
+ # Invoke the CLI. All required context is in the inherited env:
64
+ # ACCOUNT_ID, USER_ID, NEO4J_URI, NEO4J_USER, NEO4J_PASSWORD
65
+ # SESSION_ID is passed explicitly since agp_parse_stdin sets it from stdin.
66
+ result=$(SESSION_ID="${SESSION_ID}" node "$CLI_PATH" "$TRANSCRIPT_PATH" 2>&1)
67
+ exit_code=$?
68
+
69
+ if [ "$exit_code" -eq 0 ]; then
70
+ agp_emit_log "result=ok sessionId=${SESSION_ID_REPORTED} ${result}"
71
+ else
72
+ agp_emit_log "result=err sessionId=${SESSION_ID_REPORTED} reason=${result}"
73
+ fi
74
+
75
+ exit 0
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=ingest-session-text.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ingest-session-text.d.ts","sourceRoot":"","sources":["../../src/cli/ingest-session-text.ts"],"names":[],"mappings":""}
@@ -0,0 +1,58 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * CLI wrapper for voice-ingest-session-text.
4
+ *
5
+ * Invoked by the SessionEnd hook after each admin PTY session:
6
+ * node dist/cli/ingest-session-text.js <transcript_path>
7
+ *
8
+ * All other parameters are read from environment variables inherited from
9
+ * the PTY session (which inherits from the session manager's systemd unit):
10
+ *
11
+ * ACCOUNT_ID — operator's account identifier
12
+ * USER_ID — operator's userId (= adminUserId)
13
+ * SESSION_ID — session identifier (parsed by hook from stdin)
14
+ * NEO4J_URI — neo4j bolt URI
15
+ * NEO4J_USER — neo4j username
16
+ * NEO4J_PASSWORD — neo4j password
17
+ *
18
+ * Exit codes:
19
+ * 0 — success (includes no-new-turns case)
20
+ * 1 — error (missing required env, JSONL not found, DB error)
21
+ *
22
+ * stdout: one-line result summary ("turns=N skipped=M") for the hook to
23
+ * capture and forward to the log-ingest endpoint.
24
+ * stderr: detailed diagnostics (tool log lines).
25
+ */
26
+ import { voiceIngestSessionText } from "../tools/voice-ingest-session-text.js";
27
+ import { closeDriver } from "../lib/neo4j.js";
28
+ const transcriptPath = process.argv[2];
29
+ if (!transcriptPath) {
30
+ process.stderr.write("[ingest-session-text] error: transcript path required as argv[2]\n");
31
+ process.exit(1);
32
+ }
33
+ const accountId = process.env.ACCOUNT_ID ?? "";
34
+ const userId = process.env.USER_ID ?? "";
35
+ const sessionId = process.env.SESSION_ID ?? undefined;
36
+ if (!accountId || !userId) {
37
+ process.stderr.write(`[ingest-session-text] error: ACCOUNT_ID and USER_ID must be set in env (accountId=${accountId || "empty"} userId=${userId || "empty"})\n`);
38
+ process.exit(1);
39
+ }
40
+ try {
41
+ const result = await voiceIngestSessionText({
42
+ sessionJsonlPath: transcriptPath,
43
+ accountId,
44
+ userId,
45
+ sessionId,
46
+ });
47
+ // Emit one-line summary to stdout for the hook to capture.
48
+ process.stdout.write(`turns=${result.ingestedCount} skipped=${result.skippedCount} sessionId=${result.sessionId ?? "unknown"}\n`);
49
+ process.exit(0);
50
+ }
51
+ catch (err) {
52
+ process.stderr.write(`[ingest-session-text] error: ${err instanceof Error ? err.message : String(err)}\n`);
53
+ process.exit(1);
54
+ }
55
+ finally {
56
+ await closeDriver();
57
+ }
58
+ //# sourceMappingURL=ingest-session-text.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ingest-session-text.js","sourceRoot":"","sources":["../../src/cli/ingest-session-text.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,OAAO,EAAE,sBAAsB,EAAE,MAAM,uCAAuC,CAAC;AAC/E,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAE9C,MAAM,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AACvC,IAAI,CAAC,cAAc,EAAE,CAAC;IACpB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,oEAAoE,CAAC,CAAC;IAC3F,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC;AAED,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,UAAU,IAAI,EAAE,CAAC;AAC/C,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,OAAO,IAAI,EAAE,CAAC;AACzC,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,UAAU,IAAI,SAAS,CAAC;AAEtD,IAAI,CAAC,SAAS,IAAI,CAAC,MAAM,EAAE,CAAC;IAC1B,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,qFAAqF,SAAS,IAAI,OAAO,WAAW,MAAM,IAAI,OAAO,KAAK,CAC3I,CAAC;IACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC;AAED,IAAI,CAAC;IACH,MAAM,MAAM,GAAG,MAAM,sBAAsB,CAAC;QAC1C,gBAAgB,EAAE,cAAc;QAChC,SAAS;QACT,MAAM;QACN,SAAS;KACV,CAAC,CAAC;IACH,2DAA2D;IAC3D,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,SAAS,MAAM,CAAC,aAAa,YAAY,MAAM,CAAC,YAAY,cAAc,MAAM,CAAC,SAAS,IAAI,SAAS,IAAI,CAC5G,CAAC;IACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC;AAAC,OAAO,GAAG,EAAE,CAAC;IACb,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,gCAAgC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CACrF,CAAC;IACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC;QAAS,CAAC;IACT,MAAM,WAAW,EAAE,CAAC;AACtB,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAMA,OAAO,EAAmB,gBAAgB,EAAuB,MAAM,8BAA8B,CAAC;AA0RtG,OAAO,EAAE,gBAAgB,EAAE,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAMA,OAAO,EAAmB,gBAAgB,EAAuB,MAAM,8BAA8B,CAAC;AAoXtG,OAAO,EAAE,gBAAgB,EAAE,CAAC"}
@@ -7,6 +7,8 @@ import { voiceTagContent, AUTHORSHIP_MODES } from "./tools/voice-tag-content.js"
7
7
  import { voiceDistilProfile } from "./tools/voice-distil-profile.js";
8
8
  import { voiceRetrieveConditioning } from "./tools/voice-retrieve-conditioning.js";
9
9
  import { voiceRecordFeedback } from "./tools/voice-record-feedback.js";
10
+ import { voiceIngestSessionText } from "./tools/voice-ingest-session-text.js";
11
+ import { FORMAT_VALUES } from "./lib/voice-corpus.js";
10
12
  import { closeDriver } from "./lib/neo4j.js";
11
13
  const server = new McpServer({
12
14
  name: "maxy-writer-craft",
@@ -36,7 +38,9 @@ function resolveUserId() {
36
38
  // a tool argument or the tools refuse rather than orphan a profile.
37
39
  return userIdEnv;
38
40
  }
39
- server.tool("voice-tag-content", "Stamp authorshipMode on one or many content nodes (:KnowledgeDocument | :Message | :SocialPost) the operator owns. Email threads live as :KnowledgeDocument {source:'email'} since Task 321. Valid modes: human-only, human-led-agent-assisted, agent-led-human-reviewed, agent-only, unknown.", {
41
+ // Format enum schema shared across tools that accept VoiceFormat.
42
+ const zFormat = z.enum([...FORMAT_VALUES]).describe("Writing format: text | email | social-post | article | marketing-copy | note. One :VoiceProfile per (accountId, userId, format).");
43
+ server.tool("voice-tag-content", "Stamp authorshipMode (and optionally format) on one or many content nodes (:KnowledgeDocument | :Message | :SocialPost) the operator owns. Email threads live as :KnowledgeDocument {source:'email'} since Task 321. Valid modes: human-only, human-led-agent-assisted, agent-led-human-reviewed, agent-only, unknown. Valid formats: text, email, social-post, article, marketing-copy, note. When format is omitted, it is derived per-node from labels and source property.", {
40
44
  nodeIds: z.array(z.string()).min(1).describe("Element IDs of nodes to tag"),
41
45
  mode: z
42
46
  .enum([
@@ -47,7 +51,8 @@ server.tool("voice-tag-content", "Stamp authorshipMode on one or many content no
47
51
  "unknown",
48
52
  ])
49
53
  .describe("Authorship mode to apply"),
50
- }, async ({ nodeIds, mode }) => {
54
+ format: zFormat.optional().describe("Writing format. When omitted, derived from each node's labels and source property."),
55
+ }, async ({ nodeIds, mode, format }) => {
51
56
  if (!accountId)
52
57
  return refuseNoAccount("voice-tag-content");
53
58
  try {
@@ -55,12 +60,13 @@ server.tool("voice-tag-content", "Stamp authorshipMode on one or many content no
55
60
  nodeIds,
56
61
  mode: mode,
57
62
  accountId,
63
+ format: format,
58
64
  });
59
65
  return {
60
66
  content: [
61
67
  {
62
68
  type: "text",
63
- text: `voice-tag: mode=${mode} updated=${result.updated} skipped=${result.skipped}`,
69
+ text: `voice-tag: mode=${mode} format=${format ?? "derived"} updated=${result.updated} skipped=${result.skipped}`,
64
70
  },
65
71
  ],
66
72
  };
@@ -77,11 +83,12 @@ server.tool("voice-tag-content", "Stamp authorshipMode on one or many content no
77
83
  };
78
84
  }
79
85
  });
80
- server.tool("voice-distil-profile", "Two-mode tool (Task 424). mode='sample' (default) walks the operator's human-only corpus, returns the exemplars + recent operator-edit intents for the agent to read. mode='write' persists the YAML style card the agent composed from the sample-mode response. Cadence-guarded: returns skip in 'write' mode without writing if corpus didn't grow ≥20% AND <30 days passed (pass force=true to override).", {
86
+ server.tool("voice-distil-profile", "Two-mode tool (Task 424). mode='sample' (default) walks the operator's per-format human-only corpus, returns exemplars + recent edit intents for the agent to read. mode='write' persists the YAML style card the agent composed. Cadence-guarded: skips in 'write' mode without writing if corpus didn't grow ≥20% AND <30 days passed (pass force=true to override). When format is omitted, enumerates all formats in the corpus and distils each.", {
81
87
  userId: z
82
88
  .string()
83
89
  .optional()
84
90
  .describe("Operator AdminUser identifier. Defaults to ADMIN_USER_ID env from spawn context."),
91
+ format: zFormat.optional().describe("Writing format to distil. When omitted, enumerates corpus formats and distils each that fires the cadence guard."),
85
92
  force: z
86
93
  .boolean()
87
94
  .optional()
@@ -94,7 +101,7 @@ server.tool("voice-distil-profile", "Two-mode tool (Task 424). mode='sample' (de
94
101
  .string()
95
102
  .optional()
96
103
  .describe("Required for mode='write'. The YAML style card the agent composed from the sample-mode exemplars + feedback intents."),
97
- }, async ({ userId, force, mode, styleCardYaml }) => {
104
+ }, async ({ userId, format, force, mode, styleCardYaml }) => {
98
105
  if (!accountId)
99
106
  return refuseNoAccount("voice-distil-profile");
100
107
  const resolvedUserId = userId ?? resolveUserId();
@@ -113,15 +120,29 @@ server.tool("voice-distil-profile", "Two-mode tool (Task 424). mode='sample' (de
113
120
  const result = await voiceDistilProfile({
114
121
  accountId,
115
122
  userId: resolvedUserId,
123
+ format: format,
116
124
  force: force === true,
117
125
  mode,
118
126
  styleCardYaml,
119
127
  });
120
- const summary = result.skipped
121
- ? (result.exemplars
122
- ? `voice-distil sample: corpusSize=${result.corpusSize} exemplars=${result.exemplars.length} feedbackEntries=${result.feedbackEntries}\n${JSON.stringify({ exemplars: result.exemplars, feedbackIntents: result.feedbackIntents }, null, 2)}`
123
- : `voice-distil: skipped reason=${result.skipReason} corpusSize=${result.corpusSize}`)
124
- : `voice-distil: ok profileId=${result.profileId} corpusSize=${result.corpusSize} feedbackEntries=${result.feedbackEntries} generatedAt=${result.generatedAt}`;
128
+ // Summarise single-format or multi-format result.
129
+ const summariseOne = (r, fmt) => {
130
+ const tag = fmt ? ` format=${fmt}` : "";
131
+ if (r.skipped && r.exemplars) {
132
+ return `voice-distil sample${tag}: corpusSize=${r.corpusSize} exemplars=${r.exemplars.length} feedbackEntries=${r.feedbackEntries}\n${JSON.stringify({ exemplars: r.exemplars, feedbackIntents: r.feedbackIntents }, null, 2)}`;
133
+ }
134
+ if (r.skipped) {
135
+ return `voice-distil${tag}: skipped reason=${r.skipReason} corpusSize=${r.corpusSize}`;
136
+ }
137
+ return `voice-distil${tag}: ok profileId=${r.profileId} corpusSize=${r.corpusSize} feedbackEntries=${r.feedbackEntries} generatedAt=${r.generatedAt}`;
138
+ };
139
+ let summary;
140
+ if (Array.isArray(result)) {
141
+ summary = result.map((r, i) => summariseOne(r)).join("\n---\n");
142
+ }
143
+ else {
144
+ summary = summariseOne(result, format);
145
+ }
125
146
  return { content: [{ type: "text", text: summary }] };
126
147
  }
127
148
  catch (err) {
@@ -136,21 +157,23 @@ server.tool("voice-distil-profile", "Two-mode tool (Task 424). mode='sample' (de
136
157
  };
137
158
  }
138
159
  });
139
- server.tool("voice-retrieve-conditioning", "Return the operator's style card and K voice-matched exemplars for a drafting brief. K=5 short-form, K=15 long-form. Token-budget bounded. Returns empty {styleCard:null,exemplars:[]} when no profile exists.", {
160
+ server.tool("voice-retrieve-conditioning", "Return the operator's per-format style card and K voice-matched exemplars for a drafting brief. K=5 short-form (length='short'), K=15 long-form (length='long'). Token-budget bounded. format is required (the writing type: text|email|social-post|article|marketing-copy|note). Returns empty {styleCard:null,exemplars:[]} when no profile exists.", {
140
161
  userId: z
141
162
  .string()
142
163
  .optional()
143
164
  .describe("Operator AdminUser identifier. Defaults to ADMIN_USER_ID env."),
165
+ format: zFormat.describe("Writing format for corpus and profile scoping."),
144
166
  topic: z
145
167
  .string()
146
168
  .optional()
147
169
  .describe("Drafting topic keyword (filters exemplars to relevant ones)"),
148
- format: z
170
+ length: z
149
171
  .enum(["short", "long"])
150
- .describe("Short = email/post (K=5, 16k tokens); long = brochure/prospectus (K=15, 96k tokens)"),
172
+ .optional()
173
+ .describe("K-selector: short = K=5 (16k tokens, email/post); long = K=15 (96k tokens, brochure/prospectus). Defaults to short."),
151
174
  register: z.string().optional().describe("Optional register hint"),
152
175
  tokenBudget: z.number().int().positive().optional(),
153
- }, async ({ userId, topic, format, register, tokenBudget }) => {
176
+ }, async ({ userId, format, topic, length, register, tokenBudget }) => {
154
177
  if (!accountId)
155
178
  return refuseNoAccount("voice-retrieve-conditioning");
156
179
  const resolvedUserId = userId ?? resolveUserId();
@@ -168,7 +191,12 @@ server.tool("voice-retrieve-conditioning", "Return the operator's style card and
168
191
  const result = await voiceRetrieveConditioning({
169
192
  accountId,
170
193
  userId: resolvedUserId,
171
- brief: { topic, format, register },
194
+ brief: {
195
+ format: format,
196
+ topic,
197
+ length: length,
198
+ register,
199
+ },
172
200
  tokenBudget,
173
201
  });
174
202
  return {
@@ -191,8 +219,9 @@ server.tool("voice-retrieve-conditioning", "Return the operator's style card and
191
219
  };
192
220
  }
193
221
  });
194
- server.tool("voice-record-feedback", "Capture an operator's edit on an agent draft. Writes :VoiceEdit linked to :VoiceProfile via :FEEDBACK_FOR. The calling agent supplies `intent` (one sentence describing what the operator changed and what voice preference it reveals); Task 424 moved the diff-intent summarisation into the agent's turn.", {
222
+ server.tool("voice-record-feedback", "Capture an operator's edit on an agent draft. Writes :VoiceEdit linked to the per-format :VoiceProfile via :FEEDBACK_FOR. The calling agent supplies `intent` (one sentence describing what changed and what voice preference it reveals Task 424) and `format` (the writing format of the draft).", {
195
223
  userId: z.string().optional(),
224
+ format: zFormat.describe("Writing format of the draft being edited."),
196
225
  originalText: z.string().min(1),
197
226
  editedText: z.string().min(1),
198
227
  intent: z
@@ -201,7 +230,7 @@ server.tool("voice-record-feedback", "Capture an operator's edit on an agent dra
201
230
  .describe("One sentence summarising what changed and what voice preference it reveals — produced by the calling agent in-turn from originalText vs editedText (Task 424)."),
202
231
  skill: z.string().optional().describe("Calling skill name, for provenance"),
203
232
  brief: z.string().optional().describe("Drafting brief that produced the original"),
204
- }, async ({ userId, originalText, editedText, intent, skill, brief }) => {
233
+ }, async ({ userId, format, originalText, editedText, intent, skill, brief }) => {
205
234
  if (!accountId)
206
235
  return refuseNoAccount("voice-record-feedback");
207
236
  const resolvedUserId = userId ?? resolveUserId();
@@ -220,6 +249,7 @@ server.tool("voice-record-feedback", "Capture an operator's edit on an agent dra
220
249
  const result = await voiceRecordFeedback({
221
250
  accountId,
222
251
  userId: resolvedUserId,
252
+ format: format,
223
253
  originalText,
224
254
  editedText,
225
255
  intent,
@@ -229,7 +259,7 @@ server.tool("voice-record-feedback", "Capture an operator's edit on an agent dra
229
259
  content: [
230
260
  {
231
261
  type: "text",
232
- text: `voice-record-feedback: editId=${result.editId} intent="${result.intent}" hadProfile=${result.hadProfile}`,
262
+ text: `voice-record-feedback: editId=${result.editId} format=${format} intent="${result.intent}" hadProfile=${result.hadProfile}`,
233
263
  },
234
264
  ],
235
265
  };
@@ -246,6 +276,53 @@ server.tool("voice-record-feedback", "Capture an operator's edit on an agent dra
246
276
  };
247
277
  }
248
278
  });
279
+ server.tool("voice-ingest-session-text", "Ingest operator PTY turns from a Claude Code session JSONL as :Message {format:'text', source:'admin-pty', authorshipMode:'human-only'} corpus nodes. Deduplication via SHA256 contentHash — re-running against the same JSONL is a no-op. Triggers voice-distil-profile {format:'text'} after ingest (cadence guard decides whether distillation runs). Called automatically by the SessionEnd hook; can also be invoked manually.", {
280
+ sessionJsonlPath: z.string().min(1).describe("Absolute path to the Claude Code session JSONL file"),
281
+ sessionId: z.string().optional().describe("Session ID for provenance; read from the SessionEnd envelope"),
282
+ userId: z.string().optional().describe("Operator AdminUser identifier. Defaults to ADMIN_USER_ID env."),
283
+ }, async ({ sessionJsonlPath, sessionId, userId }) => {
284
+ if (!accountId)
285
+ return refuseNoAccount("voice-ingest-session-text");
286
+ const resolvedUserId = userId ?? resolveUserId();
287
+ if (!resolvedUserId) {
288
+ return {
289
+ content: [
290
+ {
291
+ type: "text",
292
+ text: "voice-ingest-session-text: userId required (no ADMIN_USER_ID in spawn env).",
293
+ },
294
+ ],
295
+ isError: true,
296
+ };
297
+ }
298
+ try {
299
+ const result = await voiceIngestSessionText({
300
+ sessionJsonlPath,
301
+ accountId,
302
+ userId: resolvedUserId,
303
+ sessionId,
304
+ });
305
+ return {
306
+ content: [
307
+ {
308
+ type: "text",
309
+ text: `voice-ingest-session-text: ingestedCount=${result.ingestedCount} skippedCount=${result.skippedCount} sessionId=${result.sessionId ?? "unknown"}`,
310
+ },
311
+ ],
312
+ };
313
+ }
314
+ catch (err) {
315
+ return {
316
+ content: [
317
+ {
318
+ type: "text",
319
+ text: `voice-ingest-session-text failed: ${err instanceof Error ? err.message : String(err)}`,
320
+ },
321
+ ],
322
+ isError: true,
323
+ };
324
+ }
325
+ });
249
326
  const transport = new StdioServerTransport();
250
327
  await server.connect(transport);
251
328
  process.on("SIGTERM", async () => {
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,uDAAuD,CAAC;AACtF,aAAa,CAAC,cAAc,CAAC,CAAC;AAE9B,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAuB,MAAM,8BAA8B,CAAC;AACtG,OAAO,EAAE,kBAAkB,EAAE,MAAM,iCAAiC,CAAC;AACrE,OAAO,EAAE,yBAAyB,EAAE,MAAM,wCAAwC,CAAC;AACnF,OAAO,EAAE,mBAAmB,EAAE,MAAM,kCAAkC,CAAC;AACvE,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAE7C,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC;IAC3B,IAAI,EAAE,mBAAmB;IACzB,OAAO,EAAE,OAAO;CACjB,CAAC,CAAC;AAEH,wEAAwE;AACxE,mEAAmE;AACnE,sBAAsB;AACtB,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,UAAU,IAAI,IAAI,CAAC;AACjD,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,aAAa,IAAI,IAAI,CAAC;AACpD,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,iCAAiC,SAAS,IAAI,MAAM,WAAW,SAAS,IAAI,MAAM,IAAI,CACvF,CAAC;AAEF,SAAS,eAAe,CAAC,QAAgB;IACvC,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,uBAAuB,QAAQ,qCAAqC,CACrE,CAAC;IACF,OAAO;QACL,OAAO,EAAE;YACP;gBACE,IAAI,EAAE,MAAe;gBACrB,IAAI,EAAE,GAAG,QAAQ,4HAA4H;aAC9I;SACF;QACD,OAAO,EAAE,IAAa;KACvB,CAAC;AACJ,CAAC;AAED,SAAS,aAAa;IACpB,uEAAuE;IACvE,wEAAwE;IACxE,oEAAoE;IACpE,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,MAAM,CAAC,IAAI,CACT,mBAAmB,EACnB,gSAAgS,EAChS;IACE,OAAO,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,6BAA6B,CAAC;IAC3E,IAAI,EAAE,CAAC;SACJ,IAAI,CAAC;QACJ,YAAY;QACZ,0BAA0B;QAC1B,0BAA0B;QAC1B,YAAY;QACZ,SAAS;KACV,CAAC;SACD,QAAQ,CAAC,0BAA0B,CAAC;CACxC,EACD,KAAK,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,EAAE;IAC1B,IAAI,CAAC,SAAS;QAAE,OAAO,eAAe,CAAC,mBAAmB,CAAC,CAAC;IAC5D,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,eAAe,CAAC;YACnC,OAAO;YACP,IAAI,EAAE,IAAsB;YAC5B,SAAS;SACV,CAAC,CAAC;QACH,OAAO;YACL,OAAO,EAAE;gBACP;oBACE,IAAI,EAAE,MAAe;oBACrB,IAAI,EAAE,mBAAmB,IAAI,YAAY,MAAM,CAAC,OAAO,YAAY,MAAM,CAAC,OAAO,EAAE;iBACpF;aACF;SACF,CAAC;IACJ,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO;YACL,OAAO,EAAE;gBACP;oBACE,IAAI,EAAE,MAAe;oBACrB,IAAI,EAAE,6BAA6B,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE;iBACtF;aACF;YACD,OAAO,EAAE,IAAI;SACd,CAAC;IACJ,CAAC;AACH,CAAC,CACF,CAAC;AAEF,MAAM,CAAC,IAAI,CACT,sBAAsB,EACtB,+YAA+Y,EAC/Y;IACE,MAAM,EAAE,CAAC;SACN,MAAM,EAAE;SACR,QAAQ,EAAE;SACV,QAAQ,CACP,kFAAkF,CACnF;IACH,KAAK,EAAE,CAAC;SACL,OAAO,EAAE;SACT,QAAQ,EAAE;SACV,QAAQ,CAAC,iDAAiD,CAAC;IAC9D,IAAI,EAAE,CAAC;SACJ,IAAI,CAAC,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;SACzB,QAAQ,EAAE;SACV,QAAQ,CAAC,2HAA2H,CAAC;IACxI,aAAa,EAAE,CAAC;SACb,MAAM,EAAE;SACR,QAAQ,EAAE;SACV,QAAQ,CAAC,sHAAsH,CAAC;CACpI,EACD,KAAK,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,aAAa,EAAE,EAAE,EAAE;IAC/C,IAAI,CAAC,SAAS;QAAE,OAAO,eAAe,CAAC,sBAAsB,CAAC,CAAC;IAC/D,MAAM,cAAc,GAAG,MAAM,IAAI,aAAa,EAAE,CAAC;IACjD,IAAI,CAAC,cAAc,EAAE,CAAC;QACpB,OAAO;YACL,OAAO,EAAE;gBACP;oBACE,IAAI,EAAE,MAAe;oBACrB,IAAI,EACF,wEAAwE;iBAC3E;aACF;YACD,OAAO,EAAE,IAAI;SACd,CAAC;IACJ,CAAC;IACD,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,kBAAkB,CAAC;YACtC,SAAS;YACT,MAAM,EAAE,cAAc;YACtB,KAAK,EAAE,KAAK,KAAK,IAAI;YACrB,IAAI;YACJ,aAAa;SACd,CAAC,CAAC;QACH,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO;YAC5B,CAAC,CAAC,CAAC,MAAM,CAAC,SAAS;gBACf,CAAC,CAAC,mCAAmC,MAAM,CAAC,UAAU,cAAc,MAAM,CAAC,SAAS,CAAC,MAAM,oBAAoB,MAAM,CAAC,eAAe,KAAK,IAAI,CAAC,SAAS,CAAC,EAAE,SAAS,EAAE,MAAM,CAAC,SAAS,EAAE,eAAe,EAAE,MAAM,CAAC,eAAe,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE;gBAC7O,CAAC,CAAC,gCAAgC,MAAM,CAAC,UAAU,eAAe,MAAM,CAAC,UAAU,EAAE,CAAC;YAC1F,CAAC,CAAC,8BAA8B,MAAM,CAAC,SAAS,eAAe,MAAM,CAAC,UAAU,oBAAoB,MAAM,CAAC,eAAe,gBAAgB,MAAM,CAAC,WAAW,EAAE,CAAC;QACjK,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC;IACjE,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO;YACL,OAAO,EAAE;gBACP;oBACE,IAAI,EAAE,MAAe;oBACrB,IAAI,EAAE,gCAAgC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE;iBACzF;aACF;YACD,OAAO,EAAE,IAAI;SACd,CAAC;IACJ,CAAC;AACH,CAAC,CACF,CAAC;AAEF,MAAM,CAAC,IAAI,CACT,6BAA6B,EAC7B,gNAAgN,EAChN;IACE,MAAM,EAAE,CAAC;SACN,MAAM,EAAE;SACR,QAAQ,EAAE;SACV,QAAQ,CAAC,+DAA+D,CAAC;IAC5E,KAAK,EAAE,CAAC;SACL,MAAM,EAAE;SACR,QAAQ,EAAE;SACV,QAAQ,CAAC,6DAA6D,CAAC;IAC1E,MAAM,EAAE,CAAC;SACN,IAAI,CAAC,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;SACvB,QAAQ,CAAC,qFAAqF,CAAC;IAClG,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,wBAAwB,CAAC;IAClE,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE;CACpD,EACD,KAAK,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,WAAW,EAAE,EAAE,EAAE;IACzD,IAAI,CAAC,SAAS;QAAE,OAAO,eAAe,CAAC,6BAA6B,CAAC,CAAC;IACtE,MAAM,cAAc,GAAG,MAAM,IAAI,aAAa,EAAE,CAAC;IACjD,IAAI,CAAC,cAAc,EAAE,CAAC;QACpB,OAAO;YACL,OAAO,EAAE;gBACP;oBACE,IAAI,EAAE,MAAe;oBACrB,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC;iBACzD;aACF;SACF,CAAC;IACJ,CAAC;IACD,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,yBAAyB,CAAC;YAC7C,SAAS;YACT,MAAM,EAAE,cAAc;YACtB,KAAK,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE;YAClC,WAAW;SACZ,CAAC,CAAC;QACH,OAAO;YACL,OAAO,EAAE;gBACP,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE;aACxD;SACF,CAAC;IACJ,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,qEAAqE;QACrE,uCAAuC;QACvC,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,gCAAgC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CACrF,CAAC;QACF,OAAO;YACL,OAAO,EAAE;gBACP;oBACE,IAAI,EAAE,MAAe;oBACrB,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC;iBACzD;aACF;SACF,CAAC;IACJ,CAAC;AACH,CAAC,CACF,CAAC;AAEF,MAAM,CAAC,IAAI,CACT,uBAAuB,EACvB,8SAA8S,EAC9S;IACE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC7B,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IAC/B,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IAC7B,MAAM,EAAE,CAAC;SACN,MAAM,EAAE;SACR,GAAG,CAAC,CAAC,CAAC;SACN,QAAQ,CAAC,gKAAgK,CAAC;IAC7K,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,oCAAoC,CAAC;IAC3E,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,2CAA2C,CAAC;CACnF,EACD,KAAK,EAAE,EAAE,MAAM,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,EAAE;IACnE,IAAI,CAAC,SAAS;QAAE,OAAO,eAAe,CAAC,uBAAuB,CAAC,CAAC;IAChE,MAAM,cAAc,GAAG,MAAM,IAAI,aAAa,EAAE,CAAC;IACjD,IAAI,CAAC,cAAc,EAAE,CAAC;QACpB,OAAO;YACL,OAAO,EAAE;gBACP;oBACE,IAAI,EAAE,MAAe;oBACrB,IAAI,EAAE,yEAAyE;iBAChF;aACF;YACD,OAAO,EAAE,IAAI;SACd,CAAC;IACJ,CAAC;IACD,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,mBAAmB,CAAC;YACvC,SAAS;YACT,MAAM,EAAE,cAAc;YACtB,YAAY;YACZ,UAAU;YACV,MAAM;YACN,OAAO,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE;SAC1B,CAAC,CAAC;QACH,OAAO;YACL,OAAO,EAAE;gBACP;oBACE,IAAI,EAAE,MAAe;oBACrB,IAAI,EAAE,iCAAiC,MAAM,CAAC,MAAM,YAAY,MAAM,CAAC,MAAM,gBAAgB,MAAM,CAAC,UAAU,EAAE;iBACjH;aACF;SACF,CAAC;IACJ,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO;YACL,OAAO,EAAE;gBACP;oBACE,IAAI,EAAE,MAAe;oBACrB,IAAI,EAAE,iCAAiC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE;iBAC1F;aACF;YACD,OAAO,EAAE,IAAI;SACd,CAAC;IACJ,CAAC;AACH,CAAC,CACF,CAAC;AAEF,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;AAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;AAEhC,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,KAAK,IAAI,EAAE;IAC/B,MAAM,WAAW,EAAE,CAAC;IACpB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC;AAEH,0DAA0D;AAC1D,OAAO,EAAE,gBAAgB,EAAE,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,uDAAuD,CAAC;AACtF,aAAa,CAAC,cAAc,CAAC,CAAC;AAE9B,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAuB,MAAM,8BAA8B,CAAC;AACtG,OAAO,EAAE,kBAAkB,EAAE,MAAM,iCAAiC,CAAC;AACrE,OAAO,EAAE,yBAAyB,EAAE,MAAM,wCAAwC,CAAC;AACnF,OAAO,EAAE,mBAAmB,EAAE,MAAM,kCAAkC,CAAC;AACvE,OAAO,EAAE,sBAAsB,EAAE,MAAM,sCAAsC,CAAC;AAC9E,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AACtD,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAE7C,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC;IAC3B,IAAI,EAAE,mBAAmB;IACzB,OAAO,EAAE,OAAO;CACjB,CAAC,CAAC;AAEH,wEAAwE;AACxE,mEAAmE;AACnE,sBAAsB;AACtB,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,UAAU,IAAI,IAAI,CAAC;AACjD,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,aAAa,IAAI,IAAI,CAAC;AACpD,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,iCAAiC,SAAS,IAAI,MAAM,WAAW,SAAS,IAAI,MAAM,IAAI,CACvF,CAAC;AAEF,SAAS,eAAe,CAAC,QAAgB;IACvC,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,uBAAuB,QAAQ,qCAAqC,CACrE,CAAC;IACF,OAAO;QACL,OAAO,EAAE;YACP;gBACE,IAAI,EAAE,MAAe;gBACrB,IAAI,EAAE,GAAG,QAAQ,4HAA4H;aAC9I;SACF;QACD,OAAO,EAAE,IAAa;KACvB,CAAC;AACJ,CAAC;AAED,SAAS,aAAa;IACpB,uEAAuE;IACvE,wEAAwE;IACxE,oEAAoE;IACpE,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,oEAAoE;AACpE,MAAM,OAAO,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,aAAa,CAA0B,CAAC,CAAC,QAAQ,CAC1E,kIAAkI,CACnI,CAAC;AAEF,MAAM,CAAC,IAAI,CACT,mBAAmB,EACnB,gdAAgd,EAChd;IACE,OAAO,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,6BAA6B,CAAC;IAC3E,IAAI,EAAE,CAAC;SACJ,IAAI,CAAC;QACJ,YAAY;QACZ,0BAA0B;QAC1B,0BAA0B;QAC1B,YAAY;QACZ,SAAS;KACV,CAAC;SACD,QAAQ,CAAC,0BAA0B,CAAC;IACvC,MAAM,EAAE,OAAO,CAAC,QAAQ,EAAE,CAAC,QAAQ,CACjC,oFAAoF,CACrF;CACF,EACD,KAAK,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE;IAClC,IAAI,CAAC,SAAS;QAAE,OAAO,eAAe,CAAC,mBAAmB,CAAC,CAAC;IAC5D,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,eAAe,CAAC;YACnC,OAAO;YACP,IAAI,EAAE,IAAsB;YAC5B,SAAS;YACT,MAAM,EAAE,MAAiE;SAC1E,CAAC,CAAC;QACH,OAAO;YACL,OAAO,EAAE;gBACP;oBACE,IAAI,EAAE,MAAe;oBACrB,IAAI,EAAE,mBAAmB,IAAI,WAAW,MAAM,IAAI,SAAS,YAAY,MAAM,CAAC,OAAO,YAAY,MAAM,CAAC,OAAO,EAAE;iBAClH;aACF;SACF,CAAC;IACJ,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO;YACL,OAAO,EAAE;gBACP;oBACE,IAAI,EAAE,MAAe;oBACrB,IAAI,EAAE,6BAA6B,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE;iBACtF;aACF;YACD,OAAO,EAAE,IAAI;SACd,CAAC;IACJ,CAAC;AACH,CAAC,CACF,CAAC;AAEF,MAAM,CAAC,IAAI,CACT,sBAAsB,EACtB,ubAAub,EACvb;IACE,MAAM,EAAE,CAAC;SACN,MAAM,EAAE;SACR,QAAQ,EAAE;SACV,QAAQ,CACP,kFAAkF,CACnF;IACH,MAAM,EAAE,OAAO,CAAC,QAAQ,EAAE,CAAC,QAAQ,CACjC,kHAAkH,CACnH;IACD,KAAK,EAAE,CAAC;SACL,OAAO,EAAE;SACT,QAAQ,EAAE;SACV,QAAQ,CAAC,iDAAiD,CAAC;IAC9D,IAAI,EAAE,CAAC;SACJ,IAAI,CAAC,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;SACzB,QAAQ,EAAE;SACV,QAAQ,CAAC,2HAA2H,CAAC;IACxI,aAAa,EAAE,CAAC;SACb,MAAM,EAAE;SACR,QAAQ,EAAE;SACV,QAAQ,CAAC,sHAAsH,CAAC;CACpI,EACD,KAAK,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,aAAa,EAAE,EAAE,EAAE;IACvD,IAAI,CAAC,SAAS;QAAE,OAAO,eAAe,CAAC,sBAAsB,CAAC,CAAC;IAC/D,MAAM,cAAc,GAAG,MAAM,IAAI,aAAa,EAAE,CAAC;IACjD,IAAI,CAAC,cAAc,EAAE,CAAC;QACpB,OAAO;YACL,OAAO,EAAE;gBACP;oBACE,IAAI,EAAE,MAAe;oBACrB,IAAI,EACF,wEAAwE;iBAC3E;aACF;YACD,OAAO,EAAE,IAAI;SACd,CAAC;IACJ,CAAC;IACD,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,kBAAkB,CAAC;YACtC,SAAS;YACT,MAAM,EAAE,cAAc;YACtB,MAAM,EAAE,MAAiE;YACzE,KAAK,EAAE,KAAK,KAAK,IAAI;YACrB,IAAI;YACJ,aAAa;SACd,CAAC,CAAC;QAEH,kDAAkD;QAClD,MAAM,YAAY,GAAG,CAAC,CAAqE,EAAE,GAAY,EAAU,EAAE;YACnH,MAAM,GAAG,GAAG,GAAG,CAAC,CAAC,CAAC,WAAW,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACxC,IAAI,CAAC,CAAC,OAAO,IAAI,CAAC,CAAC,SAAS,EAAE,CAAC;gBAC7B,OAAO,sBAAsB,GAAG,gBAAgB,CAAC,CAAC,UAAU,cAAc,CAAC,CAAC,SAAS,CAAC,MAAM,oBAAoB,CAAC,CAAC,eAAe,KAAK,IAAI,CAAC,SAAS,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC,SAAS,EAAE,eAAe,EAAE,CAAC,CAAC,eAAe,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;YAClO,CAAC;YACD,IAAI,CAAC,CAAC,OAAO,EAAE,CAAC;gBACd,OAAO,eAAe,GAAG,oBAAoB,CAAC,CAAC,UAAU,eAAe,CAAC,CAAC,UAAU,EAAE,CAAC;YACzF,CAAC;YACD,OAAO,eAAe,GAAG,kBAAkB,CAAC,CAAC,SAAS,eAAe,CAAC,CAAC,UAAU,oBAAoB,CAAC,CAAC,eAAe,gBAAgB,CAAC,CAAC,WAAW,EAAE,CAAC;QACxJ,CAAC,CAAC;QAEF,IAAI,OAAe,CAAC;QACpB,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;YAC1B,OAAO,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QAClE,CAAC;aAAM,CAAC;YACN,OAAO,GAAG,YAAY,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QACzC,CAAC;QAED,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC;IACjE,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO;YACL,OAAO,EAAE;gBACP;oBACE,IAAI,EAAE,MAAe;oBACrB,IAAI,EAAE,gCAAgC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE;iBACzF;aACF;YACD,OAAO,EAAE,IAAI;SACd,CAAC;IACJ,CAAC;AACH,CAAC,CACF,CAAC;AAEF,MAAM,CAAC,IAAI,CACT,6BAA6B,EAC7B,uVAAuV,EACvV;IACE,MAAM,EAAE,CAAC;SACN,MAAM,EAAE;SACR,QAAQ,EAAE;SACV,QAAQ,CAAC,+DAA+D,CAAC;IAC5E,MAAM,EAAE,OAAO,CAAC,QAAQ,CAAC,gDAAgD,CAAC;IAC1E,KAAK,EAAE,CAAC;SACL,MAAM,EAAE;SACR,QAAQ,EAAE;SACV,QAAQ,CAAC,6DAA6D,CAAC;IAC1E,MAAM,EAAE,CAAC;SACN,IAAI,CAAC,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;SACvB,QAAQ,EAAE;SACV,QAAQ,CAAC,qHAAqH,CAAC;IAClI,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,wBAAwB,CAAC;IAClE,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE;CACpD,EACD,KAAK,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,WAAW,EAAE,EAAE,EAAE;IACjE,IAAI,CAAC,SAAS;QAAE,OAAO,eAAe,CAAC,6BAA6B,CAAC,CAAC;IACtE,MAAM,cAAc,GAAG,MAAM,IAAI,aAAa,EAAE,CAAC;IACjD,IAAI,CAAC,cAAc,EAAE,CAAC;QACpB,OAAO;YACL,OAAO,EAAE;gBACP;oBACE,IAAI,EAAE,MAAe;oBACrB,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC;iBACzD;aACF;SACF,CAAC;IACJ,CAAC;IACD,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,yBAAyB,CAAC;YAC7C,SAAS;YACT,MAAM,EAAE,cAAc;YACtB,KAAK,EAAE;gBACL,MAAM,EAAE,MAAqD;gBAC7D,KAAK;gBACL,MAAM,EAAE,MAAsC;gBAC9C,QAAQ;aACT;YACD,WAAW;SACZ,CAAC,CAAC;QACH,OAAO;YACL,OAAO,EAAE;gBACP,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE;aACxD;SACF,CAAC;IACJ,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,qEAAqE;QACrE,uCAAuC;QACvC,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,gCAAgC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CACrF,CAAC;QACF,OAAO;YACL,OAAO,EAAE;gBACP;oBACE,IAAI,EAAE,MAAe;oBACrB,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC;iBACzD;aACF;SACF,CAAC;IACJ,CAAC;AACH,CAAC,CACF,CAAC;AAEF,MAAM,CAAC,IAAI,CACT,uBAAuB,EACvB,sSAAsS,EACtS;IACE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC7B,MAAM,EAAE,OAAO,CAAC,QAAQ,CAAC,2CAA2C,CAAC;IACrE,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IAC/B,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IAC7B,MAAM,EAAE,CAAC;SACN,MAAM,EAAE;SACR,GAAG,CAAC,CAAC,CAAC;SACN,QAAQ,CAAC,gKAAgK,CAAC;IAC7K,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,oCAAoC,CAAC;IAC3E,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,2CAA2C,CAAC;CACnF,EACD,KAAK,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,EAAE;IAC3E,IAAI,CAAC,SAAS;QAAE,OAAO,eAAe,CAAC,uBAAuB,CAAC,CAAC;IAChE,MAAM,cAAc,GAAG,MAAM,IAAI,aAAa,EAAE,CAAC;IACjD,IAAI,CAAC,cAAc,EAAE,CAAC;QACpB,OAAO;YACL,OAAO,EAAE;gBACP;oBACE,IAAI,EAAE,MAAe;oBACrB,IAAI,EAAE,yEAAyE;iBAChF;aACF;YACD,OAAO,EAAE,IAAI;SACd,CAAC;IACJ,CAAC;IACD,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,mBAAmB,CAAC;YACvC,SAAS;YACT,MAAM,EAAE,cAAc;YACtB,MAAM,EAAE,MAAqD;YAC7D,YAAY;YACZ,UAAU;YACV,MAAM;YACN,OAAO,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE;SAC1B,CAAC,CAAC;QACH,OAAO;YACL,OAAO,EAAE;gBACP;oBACE,IAAI,EAAE,MAAe;oBACrB,IAAI,EAAE,iCAAiC,MAAM,CAAC,MAAM,WAAW,MAAM,YAAY,MAAM,CAAC,MAAM,gBAAgB,MAAM,CAAC,UAAU,EAAE;iBAClI;aACF;SACF,CAAC;IACJ,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO;YACL,OAAO,EAAE;gBACP;oBACE,IAAI,EAAE,MAAe;oBACrB,IAAI,EAAE,iCAAiC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE;iBAC1F;aACF;YACD,OAAO,EAAE,IAAI;SACd,CAAC;IACJ,CAAC;AACH,CAAC,CACF,CAAC;AAEF,MAAM,CAAC,IAAI,CACT,2BAA2B,EAC3B,qaAAqa,EACra;IACE,gBAAgB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,qDAAqD,CAAC;IACnG,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,8DAA8D,CAAC;IACzG,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,+DAA+D,CAAC;CACxG,EACD,KAAK,EAAE,EAAE,gBAAgB,EAAE,SAAS,EAAE,MAAM,EAAE,EAAE,EAAE;IAChD,IAAI,CAAC,SAAS;QAAE,OAAO,eAAe,CAAC,2BAA2B,CAAC,CAAC;IACpE,MAAM,cAAc,GAAG,MAAM,IAAI,aAAa,EAAE,CAAC;IACjD,IAAI,CAAC,cAAc,EAAE,CAAC;QACpB,OAAO;YACL,OAAO,EAAE;gBACP;oBACE,IAAI,EAAE,MAAe;oBACrB,IAAI,EAAE,6EAA6E;iBACpF;aACF;YACD,OAAO,EAAE,IAAI;SACd,CAAC;IACJ,CAAC;IACD,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,sBAAsB,CAAC;YAC1C,gBAAgB;YAChB,SAAS;YACT,MAAM,EAAE,cAAc;YACtB,SAAS;SACV,CAAC,CAAC;QACH,OAAO;YACL,OAAO,EAAE;gBACP;oBACE,IAAI,EAAE,MAAe;oBACrB,IAAI,EAAE,4CAA4C,MAAM,CAAC,aAAa,iBAAiB,MAAM,CAAC,YAAY,cAAc,MAAM,CAAC,SAAS,IAAI,SAAS,EAAE;iBACxJ;aACF;SACF,CAAC;IACJ,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO;YACL,OAAO,EAAE;gBACP;oBACE,IAAI,EAAE,MAAe;oBACrB,IAAI,EAAE,qCAAqC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE;iBAC9F;aACF;YACD,OAAO,EAAE,IAAI;SACd,CAAC;IACJ,CAAC;AACH,CAAC,CACF,CAAC;AAEF,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;AAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;AAEhC,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,KAAK,IAAI,EAAE;IAC/B,MAAM,WAAW,EAAE,CAAC;IACpB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC;AAEH,0DAA0D;AAC1D,OAAO,EAAE,gBAAgB,EAAE,CAAC"}
@@ -1,11 +1,13 @@
1
1
  /**
2
- * Shared corpus-filter clause for the voice-mirror tools.
2
+ * Shared corpus-filter clauses and format helpers for the voice-mirror tools.
3
3
  *
4
- * Imported by `voice-distil-profile` (count + sample walks) and
5
- * `voice-retrieve-conditioning` (exemplar walk). The single load-bearing
6
- * filter — when the corpus rules change, this is the only place to edit.
4
+ * Imported by `voice-distil-profile` (count + sample walks),
5
+ * `voice-retrieve-conditioning` (exemplar walk), `voice-tag-content` (tag
6
+ * writes), and `voice-ingest-session-text` (SessionEnd ingest). The single
7
+ * load-bearing filter — when the corpus rules change, this is the only place
8
+ * to edit.
7
9
  *
8
- * Two predicates:
10
+ * Two predicates in VOICE_CORPUS_WHERE:
9
11
  *
10
12
  * 1. `authorshipMode IN ['human-only', 'human-led-agent-assisted']`.
11
13
  * `human-only` is the operator's own writing verbatim;
@@ -25,7 +27,7 @@
25
27
  * Chat captures voice in a way email rarely does — this is the
26
28
  * single highest-leverage corpus addition for voice fidelity.
27
29
  *
28
- * The clause expects `$accountId` to be bound in the calling cypher
30
+ * The clause expects `$accountId` to be bound in the calling Cypher
29
31
  * parameters. It does not bind any other parameters.
30
32
  */
31
33
  export declare const VOICE_CORPUS_WHERE = "n.accountId = $accountId\n AND n.authorshipMode IN ['human-only', 'human-led-agent-assisted']\n AND (\n any(lbl IN labels(n) WHERE lbl IN ['KnowledgeDocument', 'Message', 'SocialPost'])\n OR ('Section' IN labels(n) AND EXISTS {\n MATCH (parent:KnowledgeDocument)-[:HAS_SECTION]->(n)\n WHERE parent.conversationIdentity IS NOT NULL\n })\n )";
@@ -39,4 +41,43 @@ export declare const VOICE_CORPUS_WHERE = "n.accountId = $accountId\n AND n.aut
39
41
  * `:KnowledgeDocument {source:'email'}` and are already covered.
40
42
  */
41
43
  export declare const TAGGABLE_PRIMARY_LABELS: readonly ["KnowledgeDocument", "Message", "SocialPost"];
44
+ /**
45
+ * Closed enum of writing-format values. One `:VoiceProfile` exists per
46
+ * `(accountId, userId, format)`. Adding a new value is a separate task.
47
+ *
48
+ * `marketing-copy` has no auto-derivation path — operator-tagged only.
49
+ */
50
+ export declare const FORMAT_VALUES: readonly ["text", "email", "social-post", "article", "marketing-copy", "note"];
51
+ export type VoiceFormat = (typeof FORMAT_VALUES)[number];
52
+ /**
53
+ * Returns VOICE_CORPUS_WHERE with an additional `n.format = $format`
54
+ * predicate appended. Requires `$format` to be bound alongside `$accountId`
55
+ * in the calling Cypher parameters.
56
+ *
57
+ * Format-discovery queries (which enumerate distinct formats from the
58
+ * corpus) use the base `VOICE_CORPUS_WHERE` directly; per-format corpus
59
+ * walks use this function.
60
+ */
61
+ export declare function voiceCorpusWhereWithFormat(format: VoiceFormat): string;
62
+ /**
63
+ * Derives the default writing format for a corpus node from its labels
64
+ * and properties. Used by ingest writers and `voice-tag-content` when the
65
+ * operator does not specify a format explicitly.
66
+ *
67
+ * Derivation rules (first match wins):
68
+ *
69
+ * | Node shape | format |
70
+ * |-------------------------------------------------------------|---------------|
71
+ * | :Message | 'text' |
72
+ * | :SocialPost | 'social-post' |
73
+ * | :KnowledgeDocument {source:'email'} | 'email' |
74
+ * | :ConversationArchive {source:'email'} | 'email' |
75
+ * | :KnowledgeDocument (non-email), body.length > 1500 | 'article' |
76
+ * | :KnowledgeDocument (non-email), body.length ≤ 1500 | 'note' |
77
+ * | :Section (conversation-document chunk) | 'text' |
78
+ * | fallback | 'text' |
79
+ *
80
+ * `marketing-copy` has no auto-derivation path.
81
+ */
82
+ export declare function deriveFormat(labels: string[], source?: string | null, body?: string | null): VoiceFormat;
42
83
  //# sourceMappingURL=voice-corpus.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"voice-corpus.d.ts","sourceRoot":"","sources":["../../src/lib/voice-corpus.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,eAAO,MAAM,kBAAkB,8WAQ3B,CAAC;AAEL;;;;;;;;GAQG;AACH,eAAO,MAAM,uBAAuB,yDAI1B,CAAC"}
1
+ {"version":3,"file":"voice-corpus.d.ts","sourceRoot":"","sources":["../../src/lib/voice-corpus.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,eAAO,MAAM,kBAAkB,8WAQ3B,CAAC;AAEL;;;;;;;;GAQG;AACH,eAAO,MAAM,uBAAuB,yDAI1B,CAAC;AAEX;;;;;GAKG;AACH,eAAO,MAAM,aAAa,gFAOhB,CAAC;AAEX,MAAM,MAAM,WAAW,GAAG,CAAC,OAAO,aAAa,CAAC,CAAC,MAAM,CAAC,CAAC;AAEzD;;;;;;;;GAQG;AACH,wBAAgB,0BAA0B,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,CAEtE;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,YAAY,CAC1B,MAAM,EAAE,MAAM,EAAE,EAChB,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,EACtB,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,GACnB,WAAW,CAcb"}
@@ -1,11 +1,13 @@
1
1
  /**
2
- * Shared corpus-filter clause for the voice-mirror tools.
2
+ * Shared corpus-filter clauses and format helpers for the voice-mirror tools.
3
3
  *
4
- * Imported by `voice-distil-profile` (count + sample walks) and
5
- * `voice-retrieve-conditioning` (exemplar walk). The single load-bearing
6
- * filter — when the corpus rules change, this is the only place to edit.
4
+ * Imported by `voice-distil-profile` (count + sample walks),
5
+ * `voice-retrieve-conditioning` (exemplar walk), `voice-tag-content` (tag
6
+ * writes), and `voice-ingest-session-text` (SessionEnd ingest). The single
7
+ * load-bearing filter — when the corpus rules change, this is the only place
8
+ * to edit.
7
9
  *
8
- * Two predicates:
10
+ * Two predicates in VOICE_CORPUS_WHERE:
9
11
  *
10
12
  * 1. `authorshipMode IN ['human-only', 'human-led-agent-assisted']`.
11
13
  * `human-only` is the operator's own writing verbatim;
@@ -25,7 +27,7 @@
25
27
  * Chat captures voice in a way email rarely does — this is the
26
28
  * single highest-leverage corpus addition for voice fidelity.
27
29
  *
28
- * The clause expects `$accountId` to be bound in the calling cypher
30
+ * The clause expects `$accountId` to be bound in the calling Cypher
29
31
  * parameters. It does not bind any other parameters.
30
32
  */
31
33
  export const VOICE_CORPUS_WHERE = `n.accountId = $accountId
@@ -51,4 +53,65 @@ export const TAGGABLE_PRIMARY_LABELS = [
51
53
  "Message",
52
54
  "SocialPost",
53
55
  ];
56
+ /**
57
+ * Closed enum of writing-format values. One `:VoiceProfile` exists per
58
+ * `(accountId, userId, format)`. Adding a new value is a separate task.
59
+ *
60
+ * `marketing-copy` has no auto-derivation path — operator-tagged only.
61
+ */
62
+ export const FORMAT_VALUES = [
63
+ "text",
64
+ "email",
65
+ "social-post",
66
+ "article",
67
+ "marketing-copy",
68
+ "note",
69
+ ];
70
+ /**
71
+ * Returns VOICE_CORPUS_WHERE with an additional `n.format = $format`
72
+ * predicate appended. Requires `$format` to be bound alongside `$accountId`
73
+ * in the calling Cypher parameters.
74
+ *
75
+ * Format-discovery queries (which enumerate distinct formats from the
76
+ * corpus) use the base `VOICE_CORPUS_WHERE` directly; per-format corpus
77
+ * walks use this function.
78
+ */
79
+ export function voiceCorpusWhereWithFormat(format) {
80
+ return `${VOICE_CORPUS_WHERE}\n AND n.format = $format`;
81
+ }
82
+ /**
83
+ * Derives the default writing format for a corpus node from its labels
84
+ * and properties. Used by ingest writers and `voice-tag-content` when the
85
+ * operator does not specify a format explicitly.
86
+ *
87
+ * Derivation rules (first match wins):
88
+ *
89
+ * | Node shape | format |
90
+ * |-------------------------------------------------------------|---------------|
91
+ * | :Message | 'text' |
92
+ * | :SocialPost | 'social-post' |
93
+ * | :KnowledgeDocument {source:'email'} | 'email' |
94
+ * | :ConversationArchive {source:'email'} | 'email' |
95
+ * | :KnowledgeDocument (non-email), body.length > 1500 | 'article' |
96
+ * | :KnowledgeDocument (non-email), body.length ≤ 1500 | 'note' |
97
+ * | :Section (conversation-document chunk) | 'text' |
98
+ * | fallback | 'text' |
99
+ *
100
+ * `marketing-copy` has no auto-derivation path.
101
+ */
102
+ export function deriveFormat(labels, source, body) {
103
+ if (labels.includes("Message"))
104
+ return "text";
105
+ if (labels.includes("SocialPost"))
106
+ return "social-post";
107
+ if ((labels.includes("KnowledgeDocument") || labels.includes("ConversationArchive")) &&
108
+ source === "email") {
109
+ return "email";
110
+ }
111
+ if (labels.includes("KnowledgeDocument")) {
112
+ return (body?.length ?? 0) > 1500 ? "article" : "note";
113
+ }
114
+ // :Section (conversation-document chunk) and any other label → text.
115
+ return "text";
116
+ }
54
117
  //# sourceMappingURL=voice-corpus.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"voice-corpus.js","sourceRoot":"","sources":["../../src/lib/voice-corpus.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG;;;;;;;;IAQ9B,CAAC;AAEL;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAG;IACrC,mBAAmB;IACnB,SAAS;IACT,YAAY;CACJ,CAAC"}
1
+ {"version":3,"file":"voice-corpus.js","sourceRoot":"","sources":["../../src/lib/voice-corpus.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG;;;;;;;;IAQ9B,CAAC;AAEL;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAG;IACrC,mBAAmB;IACnB,SAAS;IACT,YAAY;CACJ,CAAC;AAEX;;;;;GAKG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG;IAC3B,MAAM;IACN,OAAO;IACP,aAAa;IACb,SAAS;IACT,gBAAgB;IAChB,MAAM;CACE,CAAC;AAIX;;;;;;;;GAQG;AACH,MAAM,UAAU,0BAA0B,CAAC,MAAmB;IAC5D,OAAO,GAAG,kBAAkB,4BAA4B,CAAC;AAC3D,CAAC;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,UAAU,YAAY,CAC1B,MAAgB,EAChB,MAAsB,EACtB,IAAoB;IAEpB,IAAI,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAC;QAAE,OAAO,MAAM,CAAC;IAC9C,IAAI,MAAM,CAAC,QAAQ,CAAC,YAAY,CAAC;QAAE,OAAO,aAAa,CAAC;IACxD,IACE,CAAC,MAAM,CAAC,QAAQ,CAAC,mBAAmB,CAAC,IAAI,MAAM,CAAC,QAAQ,CAAC,qBAAqB,CAAC,CAAC;QAChF,MAAM,KAAK,OAAO,EAClB,CAAC;QACD,OAAO,OAAO,CAAC;IACjB,CAAC;IACD,IAAI,MAAM,CAAC,QAAQ,CAAC,mBAAmB,CAAC,EAAE,CAAC;QACzC,OAAO,CAAC,IAAI,EAAE,MAAM,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC;IACzD,CAAC;IACD,qEAAqE;IACrE,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -1,7 +1,13 @@
1
+ import { type VoiceFormat } from "../lib/voice-corpus.js";
1
2
  export interface VoiceDistilProfileParams {
2
3
  accountId: string;
3
4
  userId: string;
4
5
  force?: boolean;
6
+ /**
7
+ * Writing format to distil. When omitted, enumerates distinct format
8
+ * values in the corpus and distils each that fires the cadence guard.
9
+ */
10
+ format?: VoiceFormat;
5
11
  /**
6
12
  * Operation mode (Task 424):
7
13
  * - `'sample'` (default) — read the corpus + feedback intents and return
@@ -25,12 +31,12 @@ export interface VoiceDistilProfileResult {
25
31
  generatedAt: string | null;
26
32
  feedbackEntries: number;
27
33
  skipped: boolean;
28
- skipReason?: "below-threshold" | "recent" | "empty-corpus" | "missing-style-card";
34
+ skipReason?: "below-threshold" | "recent" | "empty-corpus" | "missing-style-card" | "no-format-tagged-content";
29
35
  errorReason?: string;
30
36
  /** Present when `mode='sample'`: corpus exemplars for the agent to read. */
31
37
  exemplars?: VoiceCorpusExemplar[];
32
38
  /** Present when `mode='sample'`: operator-edit intents to fold into the style card. */
33
39
  feedbackIntents?: string[];
34
40
  }
35
- export declare function voiceDistilProfile(params: VoiceDistilProfileParams): Promise<VoiceDistilProfileResult>;
41
+ export declare function voiceDistilProfile(params: VoiceDistilProfileParams): Promise<VoiceDistilProfileResult | VoiceDistilProfileResult[]>;
36
42
  //# sourceMappingURL=voice-distil-profile.d.ts.map