@dotit/core 1.0.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/LICENSE +21 -0
- package/README.md +229 -0
- package/dist/aliases.d.ts +1 -0
- package/dist/aliases.js +8 -0
- package/dist/ask.d.ts +7 -0
- package/dist/ask.js +55 -0
- package/dist/browser.d.ts +12 -0
- package/dist/browser.js +32 -0
- package/dist/diff.d.ts +17 -0
- package/dist/diff.js +179 -0
- package/dist/document-css.d.ts +1 -0
- package/dist/document-css.js +290 -0
- package/dist/executor.d.ts +40 -0
- package/dist/executor.js +501 -0
- package/dist/history.d.ts +10 -0
- package/dist/history.js +297 -0
- package/dist/html-to-it.d.ts +1 -0
- package/dist/html-to-it.js +288 -0
- package/dist/index-builder.d.ts +62 -0
- package/dist/index-builder.js +228 -0
- package/dist/index.d.ts +39 -0
- package/dist/index.js +94 -0
- package/dist/language-registry.d.ts +39 -0
- package/dist/language-registry.js +530 -0
- package/dist/markdown.d.ts +1 -0
- package/dist/markdown.js +123 -0
- package/dist/merge.d.ts +6 -0
- package/dist/merge.js +255 -0
- package/dist/parser.d.ts +29 -0
- package/dist/parser.js +1562 -0
- package/dist/query.d.ts +32 -0
- package/dist/query.js +293 -0
- package/dist/renderer.d.ts +16 -0
- package/dist/renderer.js +1286 -0
- package/dist/schema.d.ts +47 -0
- package/dist/schema.js +574 -0
- package/dist/source.d.ts +3 -0
- package/dist/source.js +223 -0
- package/dist/theme.d.ts +49 -0
- package/dist/theme.js +113 -0
- package/dist/themes/corporate.json +86 -0
- package/dist/themes/dark.json +64 -0
- package/dist/themes/editorial.json +54 -0
- package/dist/themes/legal.json +57 -0
- package/dist/themes/minimal.json +50 -0
- package/dist/themes/print.json +54 -0
- package/dist/themes/technical.json +59 -0
- package/dist/themes/warm.json +53 -0
- package/dist/trust.d.ts +66 -0
- package/dist/trust.js +200 -0
- package/dist/types.d.ts +234 -0
- package/dist/types.js +19 -0
- package/dist/utils.d.ts +2 -0
- package/dist/utils.js +13 -0
- package/dist/validate.d.ts +13 -0
- package/dist/validate.js +711 -0
- package/dist/workflow.d.ts +18 -0
- package/dist/workflow.js +160 -0
- package/package.json +51 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 IntentText Team
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
# @dotit/core
|
|
2
|
+
|
|
3
|
+
Parser, HTML renderer, and document generation engine for **IntentText** (`.it`) — a structured interchange format for AI agents and humans.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @dotit/core
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Quick Start
|
|
12
|
+
|
|
13
|
+
```typescript
|
|
14
|
+
import { parseIntentText, renderHTML } from "@dotit/core";
|
|
15
|
+
|
|
16
|
+
const doc = parseIntentText(`
|
|
17
|
+
title: Sprint Planning — Week 12
|
|
18
|
+
summary: Tasks and decisions for the week.
|
|
19
|
+
|
|
20
|
+
section: Action Items
|
|
21
|
+
task: Write migration script | owner: Sarah | due: Wednesday
|
|
22
|
+
task: Update CI pipeline | owner: Dev Team | due: Friday
|
|
23
|
+
done: Security audit complete
|
|
24
|
+
|
|
25
|
+
section: Notes
|
|
26
|
+
note: Next demo on Friday 3pm.
|
|
27
|
+
info: New staging environment is live.
|
|
28
|
+
`);
|
|
29
|
+
|
|
30
|
+
console.log(doc.version); // "1.4"
|
|
31
|
+
console.log(doc.blocks.length); // 8
|
|
32
|
+
|
|
33
|
+
const html = renderHTML(doc); // Styled HTML output
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
> Pure TypeScript — no native or WASM dependency. Runs unchanged in Node and the
|
|
37
|
+
> browser. (The earlier Rust/WASM engine was removed in v4; the TS parser is the
|
|
38
|
+
> single canonical implementation. See [SPEC.md](./SPEC.md).)
|
|
39
|
+
|
|
40
|
+
## API
|
|
41
|
+
|
|
42
|
+
### Parsing
|
|
43
|
+
|
|
44
|
+
```typescript
|
|
45
|
+
import { parseIntentText } from "@dotit/core";
|
|
46
|
+
|
|
47
|
+
const doc = parseIntentText(source);
|
|
48
|
+
// Returns: IntentDocument { version, metadata, blocks, diagnostics }
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### Rendering
|
|
52
|
+
|
|
53
|
+
```typescript
|
|
54
|
+
import { renderHTML, renderPrint } from "@dotit/core";
|
|
55
|
+
|
|
56
|
+
// Inline HTML fragment (for embedding in a page)
|
|
57
|
+
const html = renderHTML(doc);
|
|
58
|
+
|
|
59
|
+
// Full print-optimized HTML document with embedded CSS
|
|
60
|
+
// Reads font: and page: blocks for dynamic typography and layout
|
|
61
|
+
const printHtml = renderPrint(doc);
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### Template Merge
|
|
65
|
+
|
|
66
|
+
Resolve `{{variable}}` placeholders in a parsed document using a JSON data object.
|
|
67
|
+
|
|
68
|
+
```typescript
|
|
69
|
+
import { mergeData, parseAndMerge } from "@dotit/core";
|
|
70
|
+
|
|
71
|
+
const data = {
|
|
72
|
+
company: { name: "Acme Corp" },
|
|
73
|
+
invoice_number: "INV-2026-001",
|
|
74
|
+
total: "17,325 QAR",
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
// Merge after parsing
|
|
78
|
+
const merged = mergeData(doc, data);
|
|
79
|
+
|
|
80
|
+
// Parse + merge in one step
|
|
81
|
+
const result = parseAndMerge(templateString, data);
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
- Dot notation: `{{company.name}}` → `data.company.name`
|
|
85
|
+
- Array indices: `{{items.0.description}}` → `data.items[0].description`
|
|
86
|
+
- System variables: `{{date}}`, `{{year}}` resolved automatically
|
|
87
|
+
- Runtime variables: `{{page}}`, `{{pages}}` become CSS page counters in `renderPrint`
|
|
88
|
+
- Missing fields: `parseAndMerge(src, data, { missing: "blank" })` renders an
|
|
89
|
+
unresolved `{{field}}` empty — use for finished documents so an invoice never
|
|
90
|
+
prints a literal `{{customer.phone}}` (default `"keep"` aids template authoring)
|
|
91
|
+
|
|
92
|
+
### Server-side PDFs
|
|
93
|
+
|
|
94
|
+
For real PDF bytes on a server (email attachments, archiving, batch runs) use the
|
|
95
|
+
opt-in companion **[`@dotit/pdf`](https://www.npmjs.com/package/@dotit/pdf)** —
|
|
96
|
+
`issuePDF(template, data, { signer })` runs merge → **seal** (tamper-evident SHA-256) →
|
|
97
|
+
PDF in one call. Core itself stays zero-dependency.
|
|
98
|
+
|
|
99
|
+
### Querying
|
|
100
|
+
|
|
101
|
+
```typescript
|
|
102
|
+
import { queryBlocks } from "@dotit/core";
|
|
103
|
+
|
|
104
|
+
const result = queryBlocks(doc, "type:task owner:Ahmed sort:due:asc limit:5");
|
|
105
|
+
console.log(result.blocks); // Filtered & sorted blocks
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### Trust — sign, seal, verify
|
|
109
|
+
|
|
110
|
+
`.it` documents are tamper-evident. `sealDocument` records a signer and freezes the
|
|
111
|
+
content with a SHA-256 hash; `verifyDocument` recomputes it and reports integrity.
|
|
112
|
+
|
|
113
|
+
```typescript
|
|
114
|
+
import { sealDocument, verifyDocument } from "@dotit/core";
|
|
115
|
+
|
|
116
|
+
const sealed = sealDocument(source, { signer: "Sarah Chen", role: "Legal" });
|
|
117
|
+
const result = verifyDocument(sealed.source);
|
|
118
|
+
console.log(result.intact); // true — false if a single character changed
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
The hashing rules are open and documented in [SPEC.md](./SPEC.md), so anyone with the
|
|
122
|
+
library can verify independently.
|
|
123
|
+
|
|
124
|
+
### Converters
|
|
125
|
+
|
|
126
|
+
```typescript
|
|
127
|
+
import { convertMarkdownToIntentText } from "@dotit/core";
|
|
128
|
+
|
|
129
|
+
const itSource = convertMarkdownToIntentText(markdownString);
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
## Syntax Overview
|
|
133
|
+
|
|
134
|
+
### Structure & Content
|
|
135
|
+
|
|
136
|
+
```
|
|
137
|
+
title: My Document
|
|
138
|
+
section: Chapter One
|
|
139
|
+
sub: Details
|
|
140
|
+
note: A standalone fact.
|
|
141
|
+
task: Do something | owner: Ahmed | due: Friday
|
|
142
|
+
done: Already finished | time: Monday
|
|
143
|
+
quote: Be concise. | by: Strunk
|
|
144
|
+
info: Informational callout.
|
|
145
|
+
---
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### Agentic Workflows (v2.0+)
|
|
149
|
+
|
|
150
|
+
```
|
|
151
|
+
agent: deploy-agent | model: claude-sonnet-4
|
|
152
|
+
step: Run tests | tool: ci.test | timeout: 300000
|
|
153
|
+
decision: Pass? | if: tests == "pass" | then: step-2 | else: step-3
|
|
154
|
+
gate: Approve deploy | approver: ops-lead | timeout: 24h
|
|
155
|
+
handoff: Transfer | from: deploy-agent | to: monitor-agent
|
|
156
|
+
emit: Complete | phase: deploy | level: success
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
### Document Generation (v2.5)
|
|
160
|
+
|
|
161
|
+
```
|
|
162
|
+
font: | family: Palatino Linotype | size: 12pt | leading: 1.8
|
|
163
|
+
page: | size: A5 | margins: 25mm | footer: Page {{page}} of {{pages}}
|
|
164
|
+
|
|
165
|
+
title: *Chapter One*
|
|
166
|
+
dedication: To the builders who write before they code.
|
|
167
|
+
byline: Ahmed Al-Rashid | role: Author
|
|
168
|
+
epigraph: The tools we build shape the thoughts we can think. | source: Kenneth Iverson
|
|
169
|
+
toc: | depth: 2 | title: Contents
|
|
170
|
+
|
|
171
|
+
section: Introduction
|
|
172
|
+
caption: Figure 1 — The parsing pipeline
|
|
173
|
+
footnote: 1 | See chapter 3 for details.
|
|
174
|
+
break:
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
### Inline Formatting
|
|
178
|
+
|
|
179
|
+
| Style | Syntax |
|
|
180
|
+
| ------------- | ------------ |
|
|
181
|
+
| Bold | `*text*` |
|
|
182
|
+
| Italic | `_text_` |
|
|
183
|
+
| Strikethrough | `~text~` |
|
|
184
|
+
| Code | `` `code` `` |
|
|
185
|
+
| Highlight | `^text^` |
|
|
186
|
+
| Inline note | `[[text]]` |
|
|
187
|
+
| Footnote ref | `{1}` |
|
|
188
|
+
| Styled span | `[text]{ color: #c00; weight: bold }` — style part of a line |
|
|
189
|
+
|
|
190
|
+
### Styling (three layers)
|
|
191
|
+
|
|
192
|
+
1. **Theme** — `renderHTML(doc, { theme: "corporate" })` (8 built-in document classes)
|
|
193
|
+
2. **`style:` rules (v4.3)** — house styling per block type, declared once:
|
|
194
|
+
`style: section | color: #0a7 | weight: 600`
|
|
195
|
+
(targets: title, summary, section, sub, text, quote, callout/info, table,
|
|
196
|
+
table-header, metric, contact, divider; same constrained style keys — never
|
|
197
|
+
arbitrary CSS, content stays queryable)
|
|
198
|
+
3. **Per-line props / inline spans** — exceptions: `text: hi | color: red`,
|
|
199
|
+
`[word]{ size: 1.2em }` (most-specific wins)
|
|
200
|
+
|
|
201
|
+
## CLI
|
|
202
|
+
|
|
203
|
+
```bash
|
|
204
|
+
node cli.js document.it # Parse to JSON
|
|
205
|
+
node cli.js document.it --html # Render HTML
|
|
206
|
+
node cli.js template.it --data data.json --html # Merge + render
|
|
207
|
+
node cli.js template.it --data data.json --print # Print-optimized HTML
|
|
208
|
+
node cli.js template.it --data data.json --pdf out.pdf # PDF via Puppeteer
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
## Test Suite
|
|
212
|
+
|
|
213
|
+
869 tests covering parser, renderer, query engine, converters, agentic blocks,
|
|
214
|
+
document generation, trust/seal, and round-trip serialization.
|
|
215
|
+
|
|
216
|
+
```bash
|
|
217
|
+
pnpm test
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
## Links
|
|
221
|
+
|
|
222
|
+
- [Full Specification](https://itdocs.vercel.app/docs/reference)
|
|
223
|
+
- [Usage Guide](https://itdocs.vercel.app/docs/guide)
|
|
224
|
+
- [Changelog](https://github.com/intenttext/IntentText/blob/main/CHANGELOG.md)
|
|
225
|
+
- [Example Templates](https://github.com/intenttext/IntentText/tree/main/examples/templates)
|
|
226
|
+
|
|
227
|
+
## License
|
|
228
|
+
|
|
229
|
+
MIT
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const ALIASES: Record<string, string>;
|
package/dist/aliases.js
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ALIASES = void 0;
|
|
4
|
+
const language_registry_1 = require("./language-registry");
|
|
5
|
+
exports.ALIASES = {
|
|
6
|
+
...language_registry_1.ALIAS_MAP,
|
|
7
|
+
...language_registry_1.EXTENSION_LEGACY_ALIASES,
|
|
8
|
+
};
|
package/dist/ask.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { ComposedResult } from "./index-builder";
|
|
2
|
+
export interface AskOptions {
|
|
3
|
+
maxTokens?: number;
|
|
4
|
+
format?: "text" | "json";
|
|
5
|
+
}
|
|
6
|
+
export declare function serializeContext(results: ComposedResult[]): string;
|
|
7
|
+
export declare function askDocuments(results: ComposedResult[], question: string, options?: AskOptions): Promise<string>;
|
package/dist/ask.js
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.serializeContext = serializeContext;
|
|
4
|
+
exports.askDocuments = askDocuments;
|
|
5
|
+
function serializeContext(results) {
|
|
6
|
+
const lines = [];
|
|
7
|
+
let currentFile = "";
|
|
8
|
+
for (const r of results) {
|
|
9
|
+
if (r.file !== currentFile) {
|
|
10
|
+
currentFile = r.file;
|
|
11
|
+
lines.push(`\n--- ${r.file} ---`);
|
|
12
|
+
}
|
|
13
|
+
const props = Object.entries(r.block.properties)
|
|
14
|
+
.map(([k, v]) => `${k}: ${v}`)
|
|
15
|
+
.join(" | ");
|
|
16
|
+
const section = r.block.section ? ` [${r.block.section}]` : "";
|
|
17
|
+
lines.push(`[${r.block.type}]${section} ${r.block.content}${props ? " | " + props : ""}`);
|
|
18
|
+
}
|
|
19
|
+
return lines.join("\n");
|
|
20
|
+
}
|
|
21
|
+
async function askDocuments(results, question, options = {}) {
|
|
22
|
+
const apiKey = process.env.ANTHROPIC_API_KEY;
|
|
23
|
+
if (!apiKey) {
|
|
24
|
+
return "Error: ANTHROPIC_API_KEY environment variable is not set.\nSet it with: export ANTHROPIC_API_KEY=your-key-here";
|
|
25
|
+
}
|
|
26
|
+
const context = serializeContext(results);
|
|
27
|
+
const maxTokens = options.maxTokens ?? 1024;
|
|
28
|
+
const formatHint = options.format === "json"
|
|
29
|
+
? "\nReturn your answer as valid JSON when possible."
|
|
30
|
+
: "";
|
|
31
|
+
const systemPrompt = `You are a helpful assistant that answers questions about IntentText (.it) documents. You will be given a structured representation of document blocks from one or more .it files. Answer the user's question based only on the provided document data. Be concise and factual.${formatHint}`;
|
|
32
|
+
const userMessage = `Here are the document contents:\n${context}\n\nQuestion: ${question}`;
|
|
33
|
+
const body = JSON.stringify({
|
|
34
|
+
model: "claude-sonnet-4-20250514",
|
|
35
|
+
max_tokens: maxTokens,
|
|
36
|
+
system: systemPrompt,
|
|
37
|
+
messages: [{ role: "user", content: userMessage }],
|
|
38
|
+
});
|
|
39
|
+
const response = await fetch("https://api.anthropic.com/v1/messages", {
|
|
40
|
+
method: "POST",
|
|
41
|
+
headers: {
|
|
42
|
+
"Content-Type": "application/json",
|
|
43
|
+
"x-api-key": apiKey,
|
|
44
|
+
"anthropic-version": "2023-06-01",
|
|
45
|
+
},
|
|
46
|
+
body,
|
|
47
|
+
});
|
|
48
|
+
if (!response.ok) {
|
|
49
|
+
const errorText = await response.text();
|
|
50
|
+
return `Error: Anthropic API returned ${response.status}: ${errorText}`;
|
|
51
|
+
}
|
|
52
|
+
const data = (await response.json());
|
|
53
|
+
const textBlocks = data.content.filter((c) => c.type === "text");
|
|
54
|
+
return textBlocks.map((b) => b.text).join("\n");
|
|
55
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export { parseIntentText, parseIntentTextSafe } from "./parser";
|
|
2
|
+
export { renderHTML, renderPrint } from "./renderer";
|
|
3
|
+
export { mergeData, parseAndMerge } from "./merge";
|
|
4
|
+
export { convertMarkdownToIntentText } from "./markdown";
|
|
5
|
+
export { queryBlocks, parseQuery, formatQueryResult, queryDocument, } from "./query";
|
|
6
|
+
export { validateDocument, createSchema, formatValidationResult, PREDEFINED_SCHEMAS, } from "./schema";
|
|
7
|
+
export { documentToSource } from "./source";
|
|
8
|
+
export { validateDocumentSemantic } from "./validate";
|
|
9
|
+
export { diffDocuments } from "./diff";
|
|
10
|
+
export { extractWorkflow } from "./workflow";
|
|
11
|
+
export type { WorkflowStep, WorkflowGraph } from "./workflow";
|
|
12
|
+
export type { IntentDocument, IntentBlock, BlockType, InlineNode, ParseOptions, Diagnostic, AgenticStatus, IntentDocumentMetadata, } from "./types";
|
package/dist/browser.js
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.extractWorkflow = exports.diffDocuments = exports.validateDocumentSemantic = exports.documentToSource = exports.PREDEFINED_SCHEMAS = exports.formatValidationResult = exports.createSchema = exports.validateDocument = exports.queryDocument = exports.formatQueryResult = exports.parseQuery = exports.queryBlocks = exports.convertMarkdownToIntentText = exports.parseAndMerge = exports.mergeData = exports.renderPrint = exports.renderHTML = exports.parseIntentTextSafe = exports.parseIntentText = void 0;
|
|
4
|
+
var parser_1 = require("./parser");
|
|
5
|
+
Object.defineProperty(exports, "parseIntentText", { enumerable: true, get: function () { return parser_1.parseIntentText; } });
|
|
6
|
+
Object.defineProperty(exports, "parseIntentTextSafe", { enumerable: true, get: function () { return parser_1.parseIntentTextSafe; } });
|
|
7
|
+
var renderer_1 = require("./renderer");
|
|
8
|
+
Object.defineProperty(exports, "renderHTML", { enumerable: true, get: function () { return renderer_1.renderHTML; } });
|
|
9
|
+
Object.defineProperty(exports, "renderPrint", { enumerable: true, get: function () { return renderer_1.renderPrint; } });
|
|
10
|
+
var merge_1 = require("./merge");
|
|
11
|
+
Object.defineProperty(exports, "mergeData", { enumerable: true, get: function () { return merge_1.mergeData; } });
|
|
12
|
+
Object.defineProperty(exports, "parseAndMerge", { enumerable: true, get: function () { return merge_1.parseAndMerge; } });
|
|
13
|
+
var markdown_1 = require("./markdown");
|
|
14
|
+
Object.defineProperty(exports, "convertMarkdownToIntentText", { enumerable: true, get: function () { return markdown_1.convertMarkdownToIntentText; } });
|
|
15
|
+
var query_1 = require("./query");
|
|
16
|
+
Object.defineProperty(exports, "queryBlocks", { enumerable: true, get: function () { return query_1.queryBlocks; } });
|
|
17
|
+
Object.defineProperty(exports, "parseQuery", { enumerable: true, get: function () { return query_1.parseQuery; } });
|
|
18
|
+
Object.defineProperty(exports, "formatQueryResult", { enumerable: true, get: function () { return query_1.formatQueryResult; } });
|
|
19
|
+
Object.defineProperty(exports, "queryDocument", { enumerable: true, get: function () { return query_1.queryDocument; } });
|
|
20
|
+
var schema_1 = require("./schema");
|
|
21
|
+
Object.defineProperty(exports, "validateDocument", { enumerable: true, get: function () { return schema_1.validateDocument; } });
|
|
22
|
+
Object.defineProperty(exports, "createSchema", { enumerable: true, get: function () { return schema_1.createSchema; } });
|
|
23
|
+
Object.defineProperty(exports, "formatValidationResult", { enumerable: true, get: function () { return schema_1.formatValidationResult; } });
|
|
24
|
+
Object.defineProperty(exports, "PREDEFINED_SCHEMAS", { enumerable: true, get: function () { return schema_1.PREDEFINED_SCHEMAS; } });
|
|
25
|
+
var source_1 = require("./source");
|
|
26
|
+
Object.defineProperty(exports, "documentToSource", { enumerable: true, get: function () { return source_1.documentToSource; } });
|
|
27
|
+
var validate_1 = require("./validate");
|
|
28
|
+
Object.defineProperty(exports, "validateDocumentSemantic", { enumerable: true, get: function () { return validate_1.validateDocumentSemantic; } });
|
|
29
|
+
var diff_1 = require("./diff");
|
|
30
|
+
Object.defineProperty(exports, "diffDocuments", { enumerable: true, get: function () { return diff_1.diffDocuments; } });
|
|
31
|
+
var workflow_1 = require("./workflow");
|
|
32
|
+
Object.defineProperty(exports, "extractWorkflow", { enumerable: true, get: function () { return workflow_1.extractWorkflow; } });
|
package/dist/diff.d.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { IntentDocument, IntentBlock } from "./types";
|
|
2
|
+
export interface BlockModification {
|
|
3
|
+
blockId: string;
|
|
4
|
+
before: IntentBlock;
|
|
5
|
+
after: IntentBlock;
|
|
6
|
+
contentChanged: boolean;
|
|
7
|
+
propertiesChanged: string[];
|
|
8
|
+
typeChanged: boolean;
|
|
9
|
+
}
|
|
10
|
+
export interface DocumentDiff {
|
|
11
|
+
added: IntentBlock[];
|
|
12
|
+
removed: IntentBlock[];
|
|
13
|
+
modified: BlockModification[];
|
|
14
|
+
unchanged: IntentBlock[];
|
|
15
|
+
summary: string;
|
|
16
|
+
}
|
|
17
|
+
export declare function diffDocuments(before: IntentDocument, after: IntentDocument): DocumentDiff;
|
package/dist/diff.js
ADDED
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.diffDocuments = diffDocuments;
|
|
4
|
+
const utils_1 = require("./utils");
|
|
5
|
+
function diffDocuments(before, after) {
|
|
6
|
+
const beforeBlocks = before?.blocks ? (0, utils_1.flattenBlocks)(before.blocks) : [];
|
|
7
|
+
const afterBlocks = after?.blocks ? (0, utils_1.flattenBlocks)(after.blocks) : [];
|
|
8
|
+
const added = [];
|
|
9
|
+
const removed = [];
|
|
10
|
+
const modified = [];
|
|
11
|
+
const unchanged = [];
|
|
12
|
+
const matchedBefore = new Set();
|
|
13
|
+
const matchedAfter = new Set();
|
|
14
|
+
for (let i = 0; i < beforeBlocks.length; i++) {
|
|
15
|
+
if (matchedBefore.has(i))
|
|
16
|
+
continue;
|
|
17
|
+
for (let j = 0; j < afterBlocks.length; j++) {
|
|
18
|
+
if (matchedAfter.has(j))
|
|
19
|
+
continue;
|
|
20
|
+
if (beforeBlocks[i].type === afterBlocks[j].type &&
|
|
21
|
+
beforeBlocks[i].content === afterBlocks[j].content) {
|
|
22
|
+
const propChanges = diffProperties(beforeBlocks[i], afterBlocks[j]);
|
|
23
|
+
if (propChanges.length === 0) {
|
|
24
|
+
unchanged.push(beforeBlocks[i]);
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
modified.push({
|
|
28
|
+
blockId: beforeBlocks[i].id,
|
|
29
|
+
before: beforeBlocks[i],
|
|
30
|
+
after: afterBlocks[j],
|
|
31
|
+
contentChanged: false,
|
|
32
|
+
propertiesChanged: propChanges,
|
|
33
|
+
typeChanged: false,
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
matchedBefore.add(i);
|
|
37
|
+
matchedAfter.add(j);
|
|
38
|
+
break;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
for (let i = 0; i < beforeBlocks.length; i++) {
|
|
43
|
+
if (matchedBefore.has(i))
|
|
44
|
+
continue;
|
|
45
|
+
let bestJ = -1;
|
|
46
|
+
let bestSim = 0;
|
|
47
|
+
for (let j = 0; j < afterBlocks.length; j++) {
|
|
48
|
+
if (matchedAfter.has(j))
|
|
49
|
+
continue;
|
|
50
|
+
if (beforeBlocks[i].type !== afterBlocks[j].type)
|
|
51
|
+
continue;
|
|
52
|
+
const sim = similarity(beforeBlocks[i].content, afterBlocks[j].content);
|
|
53
|
+
if (sim > 0.8 && sim > bestSim) {
|
|
54
|
+
bestSim = sim;
|
|
55
|
+
bestJ = j;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
if (bestJ >= 0) {
|
|
59
|
+
const propChanges = diffProperties(beforeBlocks[i], afterBlocks[bestJ]);
|
|
60
|
+
modified.push({
|
|
61
|
+
blockId: beforeBlocks[i].id,
|
|
62
|
+
before: beforeBlocks[i],
|
|
63
|
+
after: afterBlocks[bestJ],
|
|
64
|
+
contentChanged: beforeBlocks[i].content !== afterBlocks[bestJ].content,
|
|
65
|
+
propertiesChanged: propChanges,
|
|
66
|
+
typeChanged: false,
|
|
67
|
+
});
|
|
68
|
+
matchedBefore.add(i);
|
|
69
|
+
matchedAfter.add(bestJ);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
for (let i = 0; i < beforeBlocks.length; i++) {
|
|
73
|
+
if (matchedBefore.has(i))
|
|
74
|
+
continue;
|
|
75
|
+
let bestJ = -1;
|
|
76
|
+
let bestSim = 0;
|
|
77
|
+
for (let j = 0; j < afterBlocks.length; j++) {
|
|
78
|
+
if (matchedAfter.has(j))
|
|
79
|
+
continue;
|
|
80
|
+
const sim = similarity(beforeBlocks[i].content, afterBlocks[j].content);
|
|
81
|
+
if (sim > 0.8 && sim > bestSim) {
|
|
82
|
+
bestSim = sim;
|
|
83
|
+
bestJ = j;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
if (bestJ >= 0) {
|
|
87
|
+
const propChanges = diffProperties(beforeBlocks[i], afterBlocks[bestJ]);
|
|
88
|
+
modified.push({
|
|
89
|
+
blockId: beforeBlocks[i].id,
|
|
90
|
+
before: beforeBlocks[i],
|
|
91
|
+
after: afterBlocks[bestJ],
|
|
92
|
+
contentChanged: beforeBlocks[i].content !== afterBlocks[bestJ].content,
|
|
93
|
+
propertiesChanged: propChanges,
|
|
94
|
+
typeChanged: beforeBlocks[i].type !== afterBlocks[bestJ].type,
|
|
95
|
+
});
|
|
96
|
+
matchedBefore.add(i);
|
|
97
|
+
matchedAfter.add(bestJ);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
for (let i = 0; i < beforeBlocks.length; i++) {
|
|
101
|
+
if (!matchedBefore.has(i))
|
|
102
|
+
removed.push(beforeBlocks[i]);
|
|
103
|
+
}
|
|
104
|
+
for (let j = 0; j < afterBlocks.length; j++) {
|
|
105
|
+
if (!matchedAfter.has(j))
|
|
106
|
+
added.push(afterBlocks[j]);
|
|
107
|
+
}
|
|
108
|
+
const parts = [];
|
|
109
|
+
if (added.length > 0)
|
|
110
|
+
parts.push(`${added.length} added`);
|
|
111
|
+
if (removed.length > 0)
|
|
112
|
+
parts.push(`${removed.length} removed`);
|
|
113
|
+
if (modified.length > 0)
|
|
114
|
+
parts.push(`${modified.length} modified`);
|
|
115
|
+
if (unchanged.length > 0)
|
|
116
|
+
parts.push(`${unchanged.length} unchanged`);
|
|
117
|
+
const summary = parts.join(", ") || "no changes";
|
|
118
|
+
return { added, removed, modified, unchanged, summary };
|
|
119
|
+
}
|
|
120
|
+
function diffProperties(a, b) {
|
|
121
|
+
const propsA = a.properties || {};
|
|
122
|
+
const propsB = b.properties || {};
|
|
123
|
+
const allKeys = new Set([...Object.keys(propsA), ...Object.keys(propsB)]);
|
|
124
|
+
const changed = [];
|
|
125
|
+
for (const key of allKeys) {
|
|
126
|
+
if (String(propsA[key] ?? "") !== String(propsB[key] ?? "")) {
|
|
127
|
+
changed.push(key);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
return changed;
|
|
131
|
+
}
|
|
132
|
+
function similarity(a, b) {
|
|
133
|
+
if (a === b)
|
|
134
|
+
return 1;
|
|
135
|
+
if (a.length === 0 && b.length === 0)
|
|
136
|
+
return 1;
|
|
137
|
+
if (a.length === 0 || b.length === 0)
|
|
138
|
+
return 0;
|
|
139
|
+
const maxLen = Math.max(a.length, b.length);
|
|
140
|
+
if (maxLen > 1000) {
|
|
141
|
+
return quickSimilarity(a, b);
|
|
142
|
+
}
|
|
143
|
+
const dist = levenshtein(a, b);
|
|
144
|
+
return 1 - dist / maxLen;
|
|
145
|
+
}
|
|
146
|
+
function levenshtein(a, b) {
|
|
147
|
+
const m = a.length;
|
|
148
|
+
const n = b.length;
|
|
149
|
+
let prev = new Array(n + 1);
|
|
150
|
+
let curr = new Array(n + 1);
|
|
151
|
+
for (let j = 0; j <= n; j++)
|
|
152
|
+
prev[j] = j;
|
|
153
|
+
for (let i = 1; i <= m; i++) {
|
|
154
|
+
curr[0] = i;
|
|
155
|
+
for (let j = 1; j <= n; j++) {
|
|
156
|
+
const cost = a[i - 1] === b[j - 1] ? 0 : 1;
|
|
157
|
+
curr[j] = Math.min(prev[j] + 1, curr[j - 1] + 1, prev[j - 1] + cost);
|
|
158
|
+
}
|
|
159
|
+
[prev, curr] = [curr, prev];
|
|
160
|
+
}
|
|
161
|
+
return prev[n];
|
|
162
|
+
}
|
|
163
|
+
function quickSimilarity(a, b) {
|
|
164
|
+
const triA = new Set();
|
|
165
|
+
const triB = new Set();
|
|
166
|
+
for (let i = 0; i <= a.length - 3; i++)
|
|
167
|
+
triA.add(a.slice(i, i + 3));
|
|
168
|
+
for (let i = 0; i <= b.length - 3; i++)
|
|
169
|
+
triB.add(b.slice(i, i + 3));
|
|
170
|
+
let shared = 0;
|
|
171
|
+
for (const t of triA) {
|
|
172
|
+
if (triB.has(t))
|
|
173
|
+
shared++;
|
|
174
|
+
}
|
|
175
|
+
const total = triA.size + triB.size;
|
|
176
|
+
if (total === 0)
|
|
177
|
+
return 1;
|
|
178
|
+
return (2 * shared) / total;
|
|
179
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const DOCUMENT_CSS = "\n/* \u2500\u2500 Base \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.intent-document{font-family:Georgia,'Times New Roman',serif;line-height:1.7;color:#111;max-width:680px;margin:0 auto;padding:32px 24px;}\n/* \u2500\u2500 Typography \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.intent-title{font-size:1.75rem;line-height:1.2;margin:0 0 12px;font-weight:700;letter-spacing:-0.01em;}\n.intent-summary{margin:8px 0 20px;padding:8px 0 8px 14px;border-left:2px solid #999;color:#333;font-style:italic;font-size:0.95rem;}\n.intent-section{margin:24px 0 8px;font-size:1.1rem;line-height:1.3;font-weight:600;padding-bottom:4px;border-bottom:1px solid #ccc;}\n.intent-sub{margin:16px 0 6px;font-size:1rem;line-height:1.3;font-weight:600;}\n.intent-note{margin:6px 0;color:#222;}\n.intent-prose{margin:0 0 1em;color:#222;font-size:1rem;line-height:1.8;max-width:65ch;text-wrap:pretty;}\n.intent-align-center{text-align:center;}\n.intent-align-right{text-align:right;}\n.intent-align-justify{text-align:justify;}\n/* \u2500\u2500 Divider \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.intent-divider{margin:18px 0;text-align:center;}\n.intent-divider-line{border:none;border-top:1px solid #ccc;margin:0;}\n.intent-divider-label{display:inline-block;padding:0 10px;background:#fff;color:#888;font-size:0.78rem;position:relative;top:-9px;}\n/* \u2500\u2500 Tasks \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.intent-task{display:flex;align-items:flex-start;gap:8px;padding:7px 10px;border:1px solid #ddd;margin:5px 0;}\n.intent-task-checkbox{margin-top:3px;flex-shrink:0;}\n.intent-task-text{flex:1;}\n.intent-task-meta{display:flex;gap:6px;color:#888;font-size:0.78rem;white-space:nowrap;}\n.intent-task-owner::before{content:'@ ';opacity:0.6;}\n.intent-task-due::before{content:'due ';}\n.intent-task-time::before{content:'at ';}\n.intent-task-text-done{text-decoration:line-through;color:#999;}\n/* \u2500\u2500 Ask \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.intent-ask{display:flex;gap:10px;margin:10px 0;padding:6px 0 6px 12px;border-left:2px solid #999;align-items:baseline;}\n.intent-ask-label{font-size:0.68rem;font-weight:700;text-transform:uppercase;letter-spacing:0.08em;color:#555;flex-shrink:0;line-height:1.65;}\n.intent-ask-content{flex:1;color:#333;font-style:italic;}\n/* \u2500\u2500 Quote \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.intent-quote{margin:14px 0;padding:2px 0 2px 16px;border-left:2px solid #999;font-style:italic;color:#333;}\n.intent-quote p{margin:0;line-height:1.7;}\n.intent-quote-cite{display:block;margin-top:5px;font-style:normal;color:#888;font-size:0.82rem;}\n/* \u2500\u2500 Code \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.intent-code{margin:10px 0;padding:10px 12px;background:#f5f5f5;border:1px solid #ddd;overflow-x:auto;}\n.intent-code code{font-family:'SFMono-Regular',Consolas,'Liberation Mono',Menlo,monospace;font-size:0.85rem;color:#111;}\n/* \u2500\u2500 Table \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.intent-table{width:100%;border-collapse:collapse;margin:12px 0;font-size:0.9em;}\n.intent-table th,.intent-table-th{padding:6px 10px;text-align:left;font-weight:600;font-size:0.78rem;text-transform:uppercase;letter-spacing:0.04em;border-bottom:2px solid #333;}\n.intent-table td,.intent-table-td{padding:6px 10px;text-align:left;border-bottom:1px solid #ddd;vertical-align:top;}\n.intent-row:last-child .intent-table-td,.intent-row:last-child td{border-bottom:none;}\n/* \u2500\u2500 Image \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.intent-image{margin:12px 0;}\n.intent-image-img{max-width:100%;height:auto;border:1px solid #ddd;}\n.intent-image-caption{margin-top:4px;color:#555;font-size:0.82rem;text-align:center;font-style:italic;}\n/* \u2500\u2500 Links / Refs \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.intent-link{margin:4px 0;}\n.intent-link a{color:#111;text-decoration:underline;}\n.intent-ref{margin:4px 0;}\n.intent-ref a{color:#111;text-decoration:underline;font-style:italic;}\n.intent-unknown{margin:6px 0;padding:6px 10px;border:1px dashed #ccc;color:#888;}\n/* \u2500\u2500 Embed \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.intent-embed{margin:14px 0;}\n.intent-embed iframe,.intent-embed video,.intent-embed audio{display:block;width:100%;border:1px solid #ddd;}\n/* \u2500\u2500 Callouts \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.intent-callout{display:flex;gap:10px;margin:10px 0;padding:6px 0 6px 12px;border-left:2px solid #888;align-items:baseline;}\n.intent-callout-label{font-size:0.68rem;font-weight:700;text-transform:uppercase;letter-spacing:0.08em;flex-shrink:0;white-space:nowrap;line-height:1.65;color:#444;}\n.intent-callout-content{flex:1;color:#222;}\n.intent-info{border-color:#888;}\n.intent-info .intent-callout-label{color:#444;}\n.intent-warning{border-color:#888;}\n.intent-warning .intent-callout-label{color:#444;}\n.intent-tip{border-color:#888;}\n.intent-tip .intent-callout-label{color:#444;}\n.intent-success{border-color:#888;}\n.intent-success .intent-callout-label{color:#444;}\n/* \u2500\u2500 Inline formatting \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.intent-inline-link{color:#111;text-decoration:underline;}\n.intent-inline-highlight{background:#eee;padding:0 .15em;}\n.intent-inline-note{display:inline-block;padding:0 .3em;border:1px solid #ddd;color:#333;font-size:.92em;}\n.intent-inline-quote{color:#333;font-style:italic;}\n.intent-inline-date{font-weight:600;font-family:'SFMono-Regular',Consolas,monospace;}\n.intent-inline-mention{font-weight:600;}\n.intent-inline-tag{font-weight:600;}\n/* \u2500\u2500 Lists \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\nul,ol{margin:6px 0 6px 20px;padding:0;}\nli{margin:3px 0;color:#222;}\n/* \u2500\u2500 v2 Agentic Workflow Blocks \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.intent-step{display:flex;align-items:center;gap:8px;padding:7px 10px;border:1px solid #ddd;margin:5px 0;}\n.intent-step-icon{font-size:0.85rem;flex-shrink:0;}\n.intent-step-content{flex:1;font-weight:500;}\n.intent-step-meta{display:flex;gap:5px;align-items:center;flex-wrap:wrap;}\n.intent-step-id{font-size:0.72rem;color:#888;font-family:monospace;}\n.intent-step-depends{font-size:0.75rem;color:#555;font-style:italic;}\n.intent-badge{font-size:0.7rem;padding:1px 6px;border:1px solid #bbb;font-weight:600;text-transform:uppercase;letter-spacing:0.04em;}\n.intent-badge-tool{border-color:#999;}\n.intent-status-pending{color:#666;}\n.intent-status-running{color:#333;animation:intent-pulse 1.5s ease-in-out infinite;}\n.intent-status-blocked{color:#666;}\n.intent-status-failed{color:#333;text-decoration:line-through;}\n.intent-status-done{color:#333;}\n.intent-status-skipped,.intent-status-cancelled{color:#999;text-decoration:line-through;}\n@keyframes intent-pulse{0%,100%{opacity:1;}50%{opacity:0.4;}}\n.intent-decision{display:flex;gap:10px;margin:8px 0;padding:8px 12px;border:1px solid #bbb;}\n.intent-decision-diamond{width:16px;height:16px;border:2px solid #333;transform:rotate(45deg);flex-shrink:0;margin-top:4px;}\n.intent-decision-body{flex:1;}\n.intent-decision-label{font-weight:600;margin-bottom:3px;}\n.intent-decision-condition{font-size:0.85rem;color:#444;font-family:monospace;margin-bottom:3px;}\n.intent-decision-branches{display:flex;gap:14px;font-size:0.82rem;}\n.intent-decision-then{color:#333;}\n.intent-decision-else{color:#333;}\n.intent-trigger{display:flex;align-items:center;gap:8px;padding:7px 10px;border:1px solid #ddd;margin:5px 0;}\n.intent-trigger-icon{font-size:1rem;}\n.intent-trigger-content{flex:1;font-weight:500;}\n.intent-badge-event{border-color:#999;}\n.intent-loop{display:flex;align-items:center;gap:8px;padding:7px 10px;border:1px solid #ddd;margin:5px 0;}\n.intent-loop-icon{font-size:1rem;}\n.intent-loop-content{flex:1;font-weight:500;}\n.intent-loop-over,.intent-loop-do{font-size:0.8rem;color:#555;font-family:monospace;}\n.intent-checkpoint{display:flex;align-items:center;gap:8px;margin:16px 0;color:#555;font-size:0.85rem;font-weight:600;text-transform:uppercase;letter-spacing:0.06em;}\n.intent-checkpoint-flag{font-size:1rem;}\n.intent-checkpoint-label{flex-shrink:0;}\n.intent-checkpoint-line{flex:1;border:none;border-top:1px dashed #bbb;margin:0;}\n.intent-audit{margin:4px 0;padding:4px 8px;font-family:'SFMono-Regular',Consolas,monospace;font-size:0.8rem;color:#555;border-left:2px solid #bbb;}\n.intent-audit-prefix{color:#888;font-weight:600;}\n.intent-error-block{border-color:#999;}\n.intent-error-block .intent-callout-label{color:#333;}\n.intent-error-fallback{font-size:0.8rem;color:#555;font-style:italic;margin-left:6px;}\n.intent-error-notify{font-size:0.8rem;color:#555;margin-left:6px;}\n.intent-context-table{width:auto;border-collapse:collapse;margin:6px 0;font-size:0.85rem;}\n.intent-context-key{padding:3px 10px 3px 8px;font-weight:600;color:#333;font-family:monospace;border-bottom:1px solid #ddd;}\n.intent-context-val{padding:3px 12px 3px 6px;color:#333;font-family:monospace;border-bottom:1px solid #ddd;}\n.intent-context{margin:4px 0;font-size:0.85rem;color:#333;}\n.intent-progress{display:flex;align-items:center;gap:8px;margin:6px 0;}\n.intent-progress-label{font-size:0.85rem;color:#222;flex-shrink:0;}\n.intent-progress-bar{flex:1;height:6px;background:#ddd;overflow:hidden;}\n.intent-progress-fill{height:100%;background:#555;}\n.intent-progress-pct{font-size:0.78rem;color:#555;font-weight:600;min-width:36px;text-align:right;}\n.intent-file-ref{display:flex;align-items:center;gap:6px;margin:4px 0;padding:4px 8px;border:1px dashed #ccc;font-size:0.82rem;color:#555;font-family:monospace;}\n.intent-file-ref-icon{font-size:0.9rem;}\n/* \u2500\u2500 v2.1 Agentic Workflow Blocks \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.intent-emit-block{display:flex;align-items:center;gap:8px;padding:7px 10px;border:1px solid #bbb;margin:5px 0;}\n.intent-emit-icon{font-size:1rem;}\n.intent-emit-content{flex:1;font-weight:500;}\n.intent-emit-meta{display:flex;gap:5px;align-items:center;}\n.intent-emit-phase{font-size:0.78rem;color:#555;font-weight:600;}\n.intent-badge-level{border-color:#999;}\n.intent-result{display:flex;align-items:flex-start;gap:8px;padding:7px 10px;border:1px solid #bbb;margin:5px 0;flex-wrap:wrap;}\n.intent-result-success{border-color:#999;}\n.intent-result-error,.intent-result-failure{border-color:#999;}\n.intent-result-icon{font-size:1rem;flex-shrink:0;}\n.intent-result-content{flex:1;font-weight:500;}\n.intent-badge-code{border-color:#999;font-family:monospace;}\n.intent-result-data{width:100%;margin-top:3px;padding:4px 8px;font-size:0.82rem;overflow-x:auto;border-top:1px solid #ddd;}\n.intent-result-data code{font-family:'SFMono-Regular',Consolas,monospace;font-size:0.82rem;color:#333;}\n.intent-handoff{display:flex;align-items:center;gap:8px;padding:7px 10px;border:1px solid #bbb;margin:5px 0;}\n.intent-handoff-icon{font-size:1rem;}\n.intent-handoff-content{flex:1;font-weight:500;}\n.intent-handoff-arrow{display:flex;align-items:center;gap:5px;font-size:0.82rem;color:#444;font-weight:600;}\n.intent-handoff-agent{padding:1px 5px;border:1px solid #bbb;font-family:monospace;font-size:0.78rem;}\n.intent-wait{display:flex;align-items:center;gap:8px;padding:7px 10px;border:1px solid #ddd;margin:5px 0;border-left:2px solid #999;}\n.intent-wait-icon{font-size:1rem;animation:intent-pulse 2s ease-in-out infinite;}\n.intent-wait-content{flex:1;font-weight:500;color:#333;}\n.intent-wait-meta{display:flex;gap:5px;align-items:center;}\n.intent-badge-timeout{border-color:#999;font-family:monospace;}\n.intent-wait-fallback{font-size:0.8rem;color:#555;font-style:italic;}\n.intent-parallel{display:flex;align-items:center;gap:8px;padding:7px 10px;border:1px solid #bbb;margin:5px 0;}\n.intent-parallel-icon{font-size:1rem;}\n.intent-parallel-content{flex:1;font-weight:500;}\n.intent-parallel-steps{display:flex;gap:4px;flex-wrap:wrap;}\n.intent-badge-parallel-step{border-color:#999;font-family:monospace;font-size:0.72rem;padding:1px 5px;}\n.intent-badge-join{border-color:#999;font-size:0.72rem;padding:1px 5px;}\n.intent-retry{display:flex;align-items:center;gap:8px;padding:7px 10px;border:1px solid #bbb;margin:5px 0;}\n.intent-retry-icon{font-size:1rem;}\n.intent-retry-content{flex:1;font-weight:500;}\n.intent-retry-meta{display:flex;gap:5px;align-items:center;}\n.intent-badge-retry-max{border-color:#999;font-size:0.72rem;}\n.intent-badge-retry-delay{border-color:#999;font-size:0.72rem;font-family:monospace;}\n.intent-badge-retry-backoff{border-color:#999;font-size:0.72rem;font-style:italic;}\n/* \u2500\u2500 v2.2 Agentic Workflow Blocks \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.intent-gate{display:flex;gap:10px;margin:8px 0;padding:10px 12px;border:2px solid #888;}\n.intent-gate-icon{font-size:1.2rem;flex-shrink:0;margin-top:2px;}\n.intent-gate-body{flex:1;}\n.intent-gate-label{font-weight:600;margin-bottom:3px;}\n.intent-gate-meta{display:flex;gap:5px;align-items:center;flex-wrap:wrap;}\n.intent-badge-approver{border-color:#999;font-family:monospace;}\n.intent-gate-fallback{font-size:0.8rem;color:#555;font-style:italic;}\n.intent-call{display:flex;align-items:center;gap:8px;padding:7px 10px;border:1px dashed #999;margin:5px 0;}\n.intent-call-icon{font-size:1rem;}\n.intent-call-content{flex:1;font-weight:500;font-family:monospace;font-size:0.9rem;}\n.intent-call-meta{display:flex;gap:6px;align-items:center;}\n.intent-call-input{font-size:0.78rem;color:#555;font-family:monospace;}\n.intent-call-output{font-size:0.78rem;color:#555;font-family:monospace;}\n/* \u2500\u2500 v2.5 Document Generation Blocks \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.it-page-break{page-break-after:always;break-after:page;height:0;}\n.it-byline{margin:0 0 16px;font-size:0.9em;color:#333;}\n.it-byline-author{display:block;font-weight:bold;}\n.it-byline-meta{display:block;font-size:0.85em;color:#666;margin-top:2px;}\n.it-epigraph{font-style:italic;text-align:center;margin:20px 3em;border:none;padding:0;}\n.it-epigraph p{margin:0;}\n.it-epigraph .it-epigraph-by{display:block;text-align:right;font-size:0.9em;margin-top:4px;font-style:normal;color:#666;}\n.it-caption{font-size:0.85em;font-style:italic;text-align:center;color:#444;margin-top:3px;margin-bottom:10px;}\n.it-dedication{font-style:italic;text-align:center;margin:3em auto;}\n.it-toc{margin:20px 0;}\n.it-toc-title{font-size:1.1rem;font-weight:600;margin-bottom:8px;border:none;}\n.it-toc ol{list-style:none;padding:0;margin:0;}\n.it-toc li{margin:3px 0;}\n.it-toc li a{color:#111;text-decoration:none;border-bottom:1px dotted #bbb;}\n.it-toc li a:hover{border-bottom-style:solid;}\n.it-toc .it-toc-sub{padding-left:20px;font-size:0.92em;}\n.it-footnotes{border-top:1px solid #ccc;margin-top:24px;padding-top:8px;font-size:0.85em;color:#444;}\n.it-footnotes ol{padding-left:1.5em;margin:0;}\n.it-footnotes li{margin:3px 0;}\nsup.it-fn-ref{font-size:0.7em;vertical-align:super;}\nsup.it-fn-ref a{color:#111;text-decoration:none;border-bottom:1px solid #999;}\n/* \u2500\u2500 v2.8 Document Trust \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.it-approval{display:flex;gap:10px;margin:10px 0;padding:10px 14px;border:1px solid #4caf50;background:#f8fdf8;}\n.it-approval__icon{font-size:1.2rem;color:#4caf50;flex-shrink:0;}\n.it-approval__body{display:flex;flex-direction:column;gap:2px;}\n.it-approval__label{font-size:0.72rem;font-weight:700;text-transform:uppercase;letter-spacing:0.08em;color:#4caf50;}\n.it-approval__who{font-size:0.9rem;color:#222;}\n.it-approval__date{font-size:0.8rem;color:#666;}\n.it-signature{display:flex;flex-wrap:wrap;gap:8px;align-items:center;margin:10px 0;padding:10px 14px;border:1px solid #daa520;background:#fffdf5;}\n.it-signature--valid{border-color:#4caf50;background:#f8fdf8;}\n.it-signature--invalid{border-color:#c62828;background:#fdf5f5;}\n.it-signature__name{font-weight:600;font-size:0.95rem;color:#111;}\n.it-signature__role{font-size:0.85rem;color:#555;}\n.it-signature__date{font-size:0.8rem;color:#666;}\n.it-signature__status{font-size:0.8rem;font-weight:600;margin-left:auto;}\n.it-sealed-banner{display:flex;gap:10px;align-items:center;margin:16px 0;padding:12px 16px;border:2px solid #c62828;background:#fdf5f5;font-weight:600;}\n.it-sealed-banner__icon{font-size:1.3rem;}\n.it-sealed-banner__text{font-size:1rem;color:#c62828;text-transform:uppercase;letter-spacing:0.04em;}\n.it-sealed-banner__date{font-size:0.8rem;color:#666;margin-left:auto;}\n.it-sealed-banner__hash{font-size:0.72rem;color:#888;font-family:monospace;}\n/* \u2500\u2500 v2.11 Keyword Expansion \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.it-ref-card{display:flex;align-items:center;gap:8px;padding:7px 10px;border:1px solid #ddd;margin:5px 0;}\n.it-ref-icon{font-size:1rem;flex-shrink:0;}\n.it-ref-link{color:#111;text-decoration:underline;font-weight:500;}\n.it-ref-name{font-weight:500;}\n.it-ref-rel{font-size:0.7rem;padding:1px 6px;border:1px solid #bbb;font-weight:600;text-transform:uppercase;letter-spacing:0.04em;}\n.it-def{margin:6px 0;padding:4px 0;}\n.it-def-term{font-weight:700;font-size:0.95rem;color:#111;}\n.it-def-abbr{font-weight:400;color:#555;}\n.it-def-meaning{margin:2px 0 0 0;color:#333;font-size:0.92rem;padding-left:1em;}\n.it-metric{display:inline-block;padding:10px 14px;border:1px solid #ddd;margin:5px;min-width:140px;vertical-align:top;}\n.it-metric-name{font-size:0.78rem;font-weight:600;text-transform:uppercase;letter-spacing:0.04em;color:#555;}\n.it-metric-value{font-size:1.6rem;font-weight:700;line-height:1.2;color:#111;}\n.it-metric-unit{font-size:0.85rem;font-weight:400;color:#666;margin-left:2px;}\n.it-metric-target{font-size:0.78rem;color:#888;}\n.it-metric-trend{font-size:1rem;font-weight:700;margin-top:2px;}\n.it-metric-period{font-size:0.72rem;color:#888;}\n.it-metric-green{border-color:#4caf50;}\n.it-metric-green .it-metric-value{color:#2e7d32;}\n.it-metric-red{border-color:#c62828;}\n.it-metric-red .it-metric-value{color:#c62828;}\n.it-metric-neutral{border-color:#ddd;}\n/* Document total/line rows (invoice, receipt, statement) \u2014 matches the editor's\n itMetric node so editor-designed templates print identically. */\n.it-metric-row{display:flex;align-items:baseline;justify-content:space-between;gap:16px;padding:5px 0;border-bottom:1px solid var(--it-color-border,#e5e7eb);}\n.it-metric-row__label{color:var(--it-color-muted,#555);}\n.it-metric-row__value{font-variant-numeric:tabular-nums;font-weight:600;color:var(--it-color-text,#111);white-space:nowrap;}\n.it-metric-row--total{border-bottom:none;border-top:2px solid var(--it-color-text,#333);margin-top:2px;padding-top:8px;font-size:1.05em;}\n.it-metric-row--total .it-metric-row__label{color:var(--it-color-text,#111);font-weight:600;}\n.it-amendment{margin:10px 0;padding:10px 14px;border:2px solid #e65100;background:#fff8e1;}\n.it-amendment-header{display:flex;align-items:center;gap:8px;margin-bottom:6px;}\n.it-amendment-icon{font-size:1rem;}\n.it-amendment-ref{font-size:0.72rem;font-weight:700;padding:1px 6px;border:1px solid #e65100;color:#e65100;text-transform:uppercase;letter-spacing:0.04em;}\n.it-amendment-title{font-weight:600;color:#111;}\n.it-amendment-section{font-size:0.85rem;color:#555;font-style:italic;}\n.it-amendment-was{font-size:0.85rem;color:#c62828;text-decoration:line-through;}\n.it-amendment-now{font-size:0.85rem;color:#2e7d32;font-weight:500;}\n.it-amendment-meta{display:flex;gap:8px;margin-top:4px;font-size:0.8rem;color:#666;}\n.it-figure{margin:14px 0;}\n.it-figure img{display:block;margin:0 auto;border:1px solid #ddd;}\n.it-figure-caption{font-size:0.85em;font-style:italic;text-align:center;color:#444;margin-top:6px;}\n.it-signline{margin:20px 0;padding:0;}\n.it-signline-label{font-size:0.72rem;color:#888;text-transform:uppercase;letter-spacing:0.06em;margin-bottom:4px;}\n.it-signline-rule{border-bottom:1px solid #111;margin-bottom:4px;}\n.it-signline-name{font-size:0.9rem;font-weight:500;color:#111;}\n.it-signline-role{font-size:0.82rem;color:#555;}\n.it-signline-date{font-size:0.82rem;color:#555;margin-top:4px;}\n.it-contact{padding:8px 12px;border:1px solid #ddd;margin:5px 0;}\n.it-contact-name{font-weight:600;font-size:0.95rem;color:#111;}\n.it-contact-role{font-size:0.82rem;color:#555;}\n.it-contact-org{font-size:0.82rem;color:#555;}\n.it-contact-email a,.it-contact-phone a,.it-contact-url a{color:#111;text-decoration:underline;font-size:0.85rem;}\n.it-deadline{padding:8px 12px;border-left:3px solid #4caf50;margin:5px 0;}\n.it-deadline-name{font-weight:600;color:#111;}\n.it-deadline-date{font-size:0.9rem;font-weight:600;color:#111;}\n.it-deadline-consequence{font-size:0.85rem;color:#555;font-style:italic;}\n.it-deadline-owner{font-size:0.82rem;color:#555;}\n.it-deadline-authority{font-size:0.82rem;color:#555;}\n.it-deadline-green{border-color:#4caf50;}\n.it-deadline-amber{border-color:#f57c00;}\n.it-deadline-red{border-color:#c62828;}\n";
|