@orderful/droid 0.53.0 → 0.55.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.
Files changed (28) hide show
  1. package/.claude-plugin/plugin.json +4 -0
  2. package/CHANGELOG.md +16 -0
  3. package/README.md +21 -1
  4. package/dist/tools/propose-plan/skills/propose-plan/SKILL.md +6 -1
  5. package/dist/tools/test-blueprints/.claude-plugin/plugin.json +22 -0
  6. package/dist/tools/test-blueprints/TOOL.yaml +22 -0
  7. package/dist/tools/test-blueprints/commands/test-blueprints.md +27 -0
  8. package/dist/tools/test-blueprints/skills/test-blueprints/SKILL.md +160 -0
  9. package/dist/tools/test-blueprints/skills/test-blueprints/references/codebase-paths.md +79 -0
  10. package/dist/tools/test-blueprints/skills/test-blueprints/scripts/validate.d.ts +28 -0
  11. package/dist/tools/test-blueprints/skills/test-blueprints/scripts/validate.d.ts.map +1 -0
  12. package/dist/tools/test-blueprints/skills/test-blueprints/scripts/validate.ts +250 -0
  13. package/dist/tools/webform/.claude-plugin/plugin.json +22 -0
  14. package/dist/tools/webform/TOOL.yaml +26 -0
  15. package/dist/tools/webform/commands/webform.md +17 -0
  16. package/dist/tools/webform/skills/webform/SKILL.md +354 -0
  17. package/package.json +1 -1
  18. package/src/tools/propose-plan/skills/propose-plan/SKILL.md +6 -1
  19. package/src/tools/test-blueprints/.claude-plugin/plugin.json +22 -0
  20. package/src/tools/test-blueprints/TOOL.yaml +22 -0
  21. package/src/tools/test-blueprints/commands/test-blueprints.md +27 -0
  22. package/src/tools/test-blueprints/skills/test-blueprints/SKILL.md +160 -0
  23. package/src/tools/test-blueprints/skills/test-blueprints/references/codebase-paths.md +79 -0
  24. package/src/tools/test-blueprints/skills/test-blueprints/scripts/validate.ts +250 -0
  25. package/src/tools/webform/.claude-plugin/plugin.json +22 -0
  26. package/src/tools/webform/TOOL.yaml +26 -0
  27. package/src/tools/webform/commands/webform.md +17 -0
  28. package/src/tools/webform/skills/webform/SKILL.md +354 -0
@@ -0,0 +1,250 @@
1
+ #!/usr/bin/env bun
2
+ /**
3
+ * test-blueprints validate
4
+ *
5
+ * Validate blueprint .json.hbs templates against their Zod schema.
6
+ * Generates a temporary validation script in the workspace and runs it
7
+ * via ts-node so that tsconfig paths resolve correctly.
8
+ *
9
+ * Usage:
10
+ * droid exec test-blueprints validate \
11
+ * --workspace /path/to/orderful-workspace \
12
+ * --schema-import "simplifiedSchemas/schemaFile" \
13
+ * --schema-name "Simplified943Schema" \
14
+ * --blueprints-dir "apps/platform-api/src/modules/testTransformation/data/testBlueprints/943s"
15
+ *
16
+ * Output (JSON):
17
+ * {
18
+ * "success": true,
19
+ * "results": [
20
+ * { "file": "943_standard.json.hbs", "status": "pass" },
21
+ * { "file": "943_templated.json.hbs", "status": "skip", "reason": "contains Handlebars expressions" },
22
+ * { "file": "943_bad.json.hbs", "status": "fail", "errors": [{ "path": "header.type", "message": "Invalid enum value" }] }
23
+ * ],
24
+ * "summary": { "pass": 8, "fail": 1, "skip": 2, "total": 11 }
25
+ * }
26
+ */
27
+
28
+ import { execSync } from 'child_process';
29
+ import { existsSync, writeFileSync, unlinkSync, readdirSync, readFileSync } from 'fs';
30
+ import { join } from 'path';
31
+ import { tmpdir } from 'os';
32
+
33
+ interface ValidationError {
34
+ path: string;
35
+ message: string;
36
+ }
37
+
38
+ interface FileResult {
39
+ file: string;
40
+ status: 'pass' | 'fail' | 'skip';
41
+ reason?: string;
42
+ errors?: ValidationError[];
43
+ }
44
+
45
+ interface ValidateResult {
46
+ success: boolean;
47
+ results?: FileResult[];
48
+ summary?: { pass: number; fail: number; skip: number; total: number };
49
+ error?: string;
50
+ }
51
+
52
+ interface ParsedArgs {
53
+ workspace?: string;
54
+ schemaImport?: string;
55
+ schemaName?: string;
56
+ blueprintsDir?: string;
57
+ }
58
+
59
+ function parseArgs(args: string[]): ParsedArgs {
60
+ const result: ParsedArgs = {};
61
+
62
+ for (let i = 0; i < args.length; i++) {
63
+ const arg = args[i];
64
+ if (arg === '--workspace' && args[i + 1]) {
65
+ result.workspace = args[++i];
66
+ } else if (arg === '--schema-import' && args[i + 1]) {
67
+ result.schemaImport = args[++i];
68
+ } else if (arg === '--schema-name' && args[i + 1]) {
69
+ result.schemaName = args[++i];
70
+ } else if (arg === '--blueprints-dir' && args[i + 1]) {
71
+ result.blueprintsDir = args[++i];
72
+ }
73
+ }
74
+
75
+ return result;
76
+ }
77
+
78
+ function expandPath(p: string): string {
79
+ if (p.startsWith('~/')) {
80
+ return p.replace('~', process.env.HOME || '');
81
+ }
82
+ if (p.startsWith('$HOME/')) {
83
+ return p.replace('$HOME', process.env.HOME || '');
84
+ }
85
+ return p;
86
+ }
87
+
88
+ function validate(parsed: ParsedArgs): ValidateResult {
89
+ if (!parsed.workspace) {
90
+ return { success: false, error: 'Missing --workspace' };
91
+ }
92
+ if (!parsed.schemaImport) {
93
+ return { success: false, error: 'Missing --schema-import' };
94
+ }
95
+ if (!parsed.schemaName) {
96
+ return { success: false, error: 'Missing --schema-name' };
97
+ }
98
+ if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(parsed.schemaName)) {
99
+ return { success: false, error: 'Invalid --schema-name: must be a valid identifier' };
100
+ }
101
+ if (/['"\n\r]/.test(parsed.schemaImport)) {
102
+ return { success: false, error: 'Invalid --schema-import: must not contain quotes or newlines' };
103
+ }
104
+ if (!parsed.blueprintsDir) {
105
+ return { success: false, error: 'Missing --blueprints-dir' };
106
+ }
107
+
108
+ const workspace = expandPath(parsed.workspace);
109
+ if (!existsSync(workspace)) {
110
+ return { success: false, error: `Workspace not found: ${workspace}` };
111
+ }
112
+
113
+ const blueprintsDir = parsed.blueprintsDir.startsWith('/')
114
+ ? parsed.blueprintsDir
115
+ : join(workspace, parsed.blueprintsDir);
116
+
117
+ if (!existsSync(blueprintsDir)) {
118
+ return { success: false, error: `Blueprints directory not found: ${blueprintsDir}` };
119
+ }
120
+
121
+ // Find .json.hbs files
122
+ const files = readdirSync(blueprintsDir).filter(f => f.endsWith('.json.hbs'));
123
+ if (files.length === 0) {
124
+ return { success: false, error: `No .json.hbs files found in ${blueprintsDir}` };
125
+ }
126
+
127
+ // Pre-check for Handlebars templates (skip these from Zod validation)
128
+ const results: FileResult[] = [];
129
+ const filesToValidate: string[] = [];
130
+
131
+ for (const file of files) {
132
+ const content = readFileSync(join(blueprintsDir, file), 'utf-8');
133
+ if (content.includes('{{')) {
134
+ results.push({ file, status: 'skip', reason: 'contains Handlebars expressions' });
135
+ } else {
136
+ // Check JSON parsability before sending to ts-node
137
+ try {
138
+ JSON.parse(content);
139
+ filesToValidate.push(file);
140
+ } catch (e) {
141
+ const err = e as Error;
142
+ results.push({ file, status: 'fail', errors: [{ path: '(root)', message: `Invalid JSON: ${err.message}` }] });
143
+ }
144
+ }
145
+ }
146
+
147
+ // If all files are skipped or failed JSON parse, return early
148
+ if (filesToValidate.length === 0) {
149
+ const summary = {
150
+ pass: 0,
151
+ fail: results.filter(r => r.status === 'fail').length,
152
+ skip: results.filter(r => r.status === 'skip').length,
153
+ total: results.length,
154
+ };
155
+ return { success: summary.fail === 0, results, summary };
156
+ }
157
+
158
+ // Generate validation script
159
+ const validationScript = `
160
+ import { ${parsed.schemaName} } from '${parsed.schemaImport}';
161
+ import * as fs from 'fs';
162
+ import * as path from 'path';
163
+
164
+ const dir = ${JSON.stringify(blueprintsDir)};
165
+ const filesToValidate: string[] = ${JSON.stringify(filesToValidate)};
166
+ const results: Array<{ file: string; status: string; errors?: Array<{ path: string; message: string }> }> = [];
167
+
168
+ for (const file of filesToValidate) {
169
+ const content = fs.readFileSync(path.join(dir, file), 'utf-8');
170
+ const parsed = JSON.parse(content);
171
+ const result = ${parsed.schemaName}.safeParse(parsed);
172
+
173
+ if (result.success) {
174
+ results.push({ file, status: 'pass' });
175
+ } else {
176
+ results.push({
177
+ file,
178
+ status: 'fail',
179
+ errors: result.error.issues.map((issue: { path: (string | number)[]; message: string }) => ({
180
+ path: issue.path.join('.'),
181
+ message: issue.message,
182
+ })),
183
+ });
184
+ }
185
+ }
186
+
187
+ console.log(JSON.stringify(results));
188
+ `.trim();
189
+
190
+ const scriptPath = join(tmpdir(), `_validate-${Date.now()}.ts`);
191
+
192
+ try {
193
+ writeFileSync(scriptPath, validationScript, 'utf-8');
194
+
195
+ const output = execSync(
196
+ `npx ts-node -r tsconfig-paths/register --project apps/platform-api/tsconfig.json ${JSON.stringify(scriptPath)}`,
197
+ {
198
+ cwd: workspace,
199
+ encoding: 'utf-8',
200
+ stdio: ['pipe', 'pipe', 'pipe'],
201
+ timeout: 60_000,
202
+ }
203
+ );
204
+
205
+ let zodResults: Array<{ file: string; status: string; errors?: ValidationError[] }>;
206
+ try {
207
+ zodResults = JSON.parse(output.trim());
208
+ } catch {
209
+ return { success: false, error: `Failed to parse validation output: ${output}` };
210
+ }
211
+
212
+ for (const r of zodResults) {
213
+ results.push({
214
+ file: r.file,
215
+ status: r.status as 'pass' | 'fail',
216
+ errors: r.errors,
217
+ });
218
+ }
219
+ } catch (err: unknown) {
220
+ const error = err as { stderr?: string; message?: string };
221
+ return {
222
+ success: false,
223
+ error: `Validation script failed: ${error.stderr || error.message}`,
224
+ };
225
+ } finally {
226
+ try { unlinkSync(scriptPath); } catch { /* ignore cleanup errors */ }
227
+ }
228
+
229
+ // Sort results to match original file order
230
+ results.sort((a, b) => files.indexOf(a.file) - files.indexOf(b.file));
231
+
232
+ const summary = {
233
+ pass: results.filter(r => r.status === 'pass').length,
234
+ fail: results.filter(r => r.status === 'fail').length,
235
+ skip: results.filter(r => r.status === 'skip').length,
236
+ total: results.length,
237
+ };
238
+
239
+ return { success: summary.fail === 0, results, summary };
240
+ }
241
+
242
+ // Main
243
+ const args = process.argv.slice(2);
244
+ const parsed = parseArgs(args);
245
+ const result = validate(parsed);
246
+ console.log(JSON.stringify(result, null, 2));
247
+
248
+ if (!result.success) {
249
+ process.exit(1);
250
+ }
@@ -0,0 +1,22 @@
1
+ {
2
+ "name": "droid-webform",
3
+ "version": "0.1.0",
4
+ "description": "Generate PrintView webform templates for EDI transaction types. Reads Orderful JSON schemas and sample transactions, proposes a visual layout, then generates template code with reusable subsection items.",
5
+ "author": {
6
+ "name": "Orderful",
7
+ "url": "https://github.com/orderful"
8
+ },
9
+ "repository": "https://github.com/orderful/droid",
10
+ "license": "MIT",
11
+ "keywords": [
12
+ "droid",
13
+ "ai",
14
+ "webform"
15
+ ],
16
+ "skills": [
17
+ "./skills/webform/SKILL.md"
18
+ ],
19
+ "commands": [
20
+ "./commands/webform.md"
21
+ ]
22
+ }
@@ -0,0 +1,26 @@
1
+ name: webform
2
+ description: "Generate PrintView webform templates for EDI transaction types. Reads Orderful JSON schemas and sample transactions, proposes a visual layout, then generates template code with reusable subsection items."
3
+ version: 0.1.0
4
+ status: beta
5
+ audience:
6
+ - engineering
7
+ - product
8
+
9
+ includes:
10
+ skills:
11
+ - name: webform
12
+ required: true
13
+ commands:
14
+ - name: webform
15
+ is_alias: false
16
+ agents: []
17
+
18
+ dependencies: []
19
+
20
+ config_schema:
21
+ schema_repo:
22
+ type: string
23
+ description: "Path to orderful-workspace repo (contains Orderful JSON schemas)"
24
+ ui_repo:
25
+ type: string
26
+ description: "Path to o2-app-ui repo (contains PrintView templates and subsection items)"
@@ -0,0 +1,17 @@
1
+ ---
2
+ name: webform
3
+ description: "Generate PrintView webform templates for EDI transaction types"
4
+ argument-hint: "{transaction-type} [sample-transaction-path-or-inline-json]"
5
+ ---
6
+
7
+ # /webform
8
+
9
+ **User invoked:** `/webform $ARGUMENTS`
10
+
11
+ **Your task:** Invoke the **webform skill** with these arguments.
12
+
13
+ ## Examples
14
+
15
+ - `/webform 850 ~/Downloads/sample-850.json` → Generate 850 template from sample
16
+ - `/webform 812 ~/Downloads/812.edi` → Generate 812 template from EDI file
17
+ - `/webform 997` → Start 997 template (will ask for sample transaction)
@@ -0,0 +1,354 @@
1
+ ---
2
+ name: webform
3
+ description: "Generate PrintView webform templates for EDI transaction types. Reads Orderful JSON schemas and sample transactions, proposes a visual layout, then generates template code with reusable subsection items. User prompts like '/webform 850 sample.json', 'create a webform for 810'."
4
+ argument-hint: "{transaction-type} [sample-transaction-path-or-inline-json]"
5
+ globs: []
6
+ alwaysApply: false
7
+ allowed-tools: [Read, Write, Edit, Glob, Grep, Bash, Agent]
8
+ ---
9
+
10
+ # Webform Skill
11
+
12
+ Generate PrintView webform templates for Orderful EDI transaction types.
13
+
14
+ ## When to Use
15
+
16
+ - Creating a new webform/PrintView template for a transaction type
17
+ - User says "webform", "print view", "create a template for {type}"
18
+
19
+ ## When NOT to Use
20
+
21
+ - Modifying existing templates (just edit directly)
22
+ - Working on forms-mapper shapes/node mappers (different system)
23
+
24
+ ## Configuration
25
+
26
+ **IMPORTANT:** Run `droid config --get tools.webform` first and parse the JSON output. If paths are not configured, **ask the user** for them.
27
+
28
+ | Setting | Default | Description |
29
+ |---------|---------|-------------|
30
+ | `schema_repo` | (none) | Path to orderful-workspace repo (contains Orderful JSON schemas) |
31
+ | `ui_repo` | (none) | Path to o2-app-ui repo (contains PrintView templates) |
32
+ | `override` | (none) | User-defined behaviour overrides |
33
+
34
+ **If not configured:** Ask the user:
35
+ > "I need two repo paths to generate webform templates:
36
+ > 1. **orderful-workspace** — where are the Orderful JSON schemas? (e.g., `~/Projects/orderful-workspace`)
37
+ > 2. **o2-app-ui** — where are the PrintView templates? (e.g., `~/Projects/o2-app-ui`)"
38
+
39
+ Then set their choices:
40
+ ```bash
41
+ droid config --set tools.webform.schema_repo="{user's choice}"
42
+ droid config --set tools.webform.ui_repo="{user's choice}"
43
+ ```
44
+
45
+ ### Derived Paths
46
+
47
+ Once configured, derive all paths from the config:
48
+
49
+ - **Schema location:** `{schema_repo}/libs/schemas/src/lib/data/transactionSchemas/orderful/{type}.schema.json`
50
+ - **Template location:** `{ui_repo}/src/pages/Transaction/PrintView/templates/`
51
+ - **Subsection items:** `{ui_repo}/src/pages/Transaction/PrintView/templates/subsectionItems/`
52
+ - **Helpers:** `{ui_repo}/src/pages/Transaction/PrintView/templates/helpers.ts`
53
+ - **Types:** `{ui_repo}/src/pages/Transaction/PrintView/types/index.ts`
54
+ - **Tests:** `{ui_repo}/src/pages/Transaction/PrintView/templates/tests/templates.spec.ts`
55
+ - **Allowed types:** `{ui_repo}/src/pages/Transaction/CreateTransaction/index.tsx`
56
+ - **Print view routing:** `{ui_repo}/src/shared/helpers/printViewHelpers/getPrintViewComponentAndCsv.ts`
57
+
58
+ **Overrides:** This skill supports user-defined overrides. See `/droid` skill § Skill Overrides for how to create, register, and use overrides.
59
+
60
+ ## Invocation
61
+
62
+ ```
63
+ /webform {transaction-type} {sample-transaction}
64
+ ```
65
+
66
+ - `transaction-type`: e.g., `850`, `810`, `997`
67
+ - `sample-transaction`: file path to a JSON file, or inline JSON pasted by the user. If not provided, ask for it.
68
+
69
+ ## Workflow
70
+
71
+ Follow these steps in order. Do NOT skip the visual layout step.
72
+
73
+ ### Step 1: Load Inputs
74
+
75
+ 1. **Read config** — run `droid config --get tools.webform` and parse the JSON. If not configured, ask the user.
76
+
77
+ 2. **Read the Orderful JSON schema** for the transaction type:
78
+ ```
79
+ {schema_repo}/libs/schemas/src/lib/data/transactionSchemas/orderful/{type}.schema.json
80
+ ```
81
+ This gives you field names (camelCase), titles, descriptions, and nesting structure. Pay attention to:
82
+ - `schemaType`: `element`, `segment`, `segmentArray`, `loop`, `loopArray`
83
+ - `title`: human-readable name like "BEG03 - Purchase Order Number"
84
+ - `segmentIdentifier`: X12 segment ID like "BEG", "N1", "PO1"
85
+
86
+ 3. **Parse the sample transaction** (file or inline JSON). This determines which segments/loops are actually used and should appear in the template. **Only model what's in the sample — not every possible field in the schema.**
87
+
88
+ ### Step 2: Inventory Existing Subsection Items
89
+
90
+ Scan the existing subsection items directory:
91
+ ```
92
+ {ui_repo}/src/pages/Transaction/PrintView/templates/subsectionItems/
93
+ ```
94
+
95
+ Build a map of what already exists. Read the `index.ts` barrel file and glob for all `.ts` files. For each item, note:
96
+ - The segment/loop it handles (e.g., `BEG`, `N1_loop`, `DTM`)
97
+ - Whether it exports a block, table, or both variants
98
+ - The `parentPath` it expects
99
+
100
+ **CRITICAL: X12 is composed of shared building blocks. The same segment (N1, DTM, REF, etc.) appears across many transaction types. ALWAYS reuse existing subsection items. NEVER duplicate.**
101
+
102
+ **NAMING: Subsection items must NOT include transaction type suffixes (e.g., `CDD_loop`, not `CDD_loop_812`).** Subsection items represent reusable X12 building blocks, not transaction-specific components. Some existing items like `PO1_loop_850` have this antipattern — do not follow that convention. Name items after the segment/loop they represent (e.g., `BCD`, `SHD`, `CDD_loop`).
103
+
104
+ ### Step 3: Map Sample to Subsection Items
105
+
106
+ Walk the sample transaction's `transactionSets` structure. For each segment or loop present:
107
+
108
+ 1. **Check if a subsection item already exists** → mark as EXISTING
109
+ 2. **Check if it exists but needs additional fields** for this transaction type → mark as EXTEND
110
+ 3. **No subsection item exists** → mark as NEW
111
+
112
+ Use the schema to determine:
113
+ - Field labels (from `title`, strip the element ID prefix like "BEG03 - ")
114
+ - Field types (`ElementType`: Alphanumeric, Numeric, Date, Time, etc. — infer from `X12DataElementType` or schema `type`)
115
+ - Whether a field value comes from a qualifier code (use `QualifiedValueFieldMapItem` or `QualifiedLabelFieldMapItem`)
116
+ - Whether data is a single record (→ block) or repeating array (→ table)
117
+
118
+ ### Step 4: Propose Visual Layout
119
+
120
+ Present an ASCII/markdown layout to the user showing the proposed template structure. This is the most important step — **wait for user approval before generating any code.**
121
+
122
+ Format:
123
+
124
+ ```
125
+ # Proposed Webform: {type} - {title}
126
+
127
+ ## Section 1: {Section Title}
128
+
129
+ [{SEGMENT}] {Description} (block) ← EXISTING
130
+ • {Field Label} • {Field Label} • {Field Label}
131
+ • {Field Label} • {Field Label}
132
+
133
+ [{SEGMENT}] {Description} (table) ← NEW
134
+ | {Column 1} | {Column 2} | {Column 3} |
135
+
136
+ ## Section 2: {Section Title}
137
+
138
+ [{LOOP}] {Description} (block, 2-col) ← EXISTING
139
+ • {Field Label} • {Field Label}
140
+ ...
141
+
142
+ ## Section N: Totals
143
+
144
+ [footer] ← EXISTING (footer_CTT_loop)
145
+ Left: {fields} Right: {fields}
146
+ ```
147
+
148
+ For each subsection item, clearly indicate:
149
+ - `EXISTING` — will import and reuse as-is
150
+ - `EXTEND` — exists but needs fields added (list which fields)
151
+ - `NEW` — will create a new reusable subsection item
152
+
153
+ **Grouping guidance** (based on existing templates):
154
+ - Header/general info segments go in the first section (BEG/BAK/BIG + CUR, PER, CSH, REF, N9)
155
+ - Allowances/charges (SAC_loop) get their own section if present
156
+ - Additional info segments together (ITD, FOB, DTM, PID, TD5, etc.)
157
+ - Party identification (N1_loop) gets its own section, typically as `block--two-col`
158
+ - Line items loop gets its own section with `countPath`
159
+ - Totals/footer in the last section
160
+
161
+ ### Step 5: Iterate on Feedback
162
+
163
+ The user may request changes:
164
+ - Regroup sections
165
+ - Add/remove fields
166
+ - Change block ↔ table rendering
167
+ - Adjust column layout for tables
168
+
169
+ Iterate until the user confirms the layout.
170
+
171
+ ### Step 6: Generate Code
172
+
173
+ Once approved, generate the template and any new subsection items.
174
+
175
+ #### Template File
176
+
177
+ Create `{ui_repo}/src/pages/Transaction/PrintView/templates/{type}.template.ts`
178
+
179
+ Follow the exact patterns from existing templates. Example structure:
180
+
181
+ ```typescript
182
+ import { PrintViewTemplate } from './types';
183
+ import {
184
+ BEG,
185
+ CUR,
186
+ // ... other imports from subsectionItems
187
+ } from './subsectionItems';
188
+
189
+ export const template: PrintViewTemplate = [
190
+ {
191
+ sectionTitle: 'Section Title',
192
+ subsections: [
193
+ [BEG],
194
+ [CUR],
195
+ ],
196
+ },
197
+ // ... more sections
198
+ ];
199
+ ```
200
+
201
+ Key patterns:
202
+ - Each section is a `PrintViewPredefinedSection` with `sectionTitle` and `subsections`
203
+ - `subsections` is an array of arrays — each inner array is a group of subsection items rendered together
204
+ - Line item sections use `countPath` pointing to the loop array path (e.g., `'PO1_loop'`)
205
+ - Party sections typically use `block--two-col` layout via the subsection item's `subsectionType`
206
+
207
+ #### New Subsection Items
208
+
209
+ For each NEW item, create a file in `subsectionItems/`:
210
+ ```
211
+ {ui_repo}/src/pages/Transaction/PrintView/templates/subsectionItems/{Name}.ts
212
+ ```
213
+
214
+ Follow existing patterns exactly. Key rules:
215
+ - Import types from `'../types'`
216
+ - Use `ElementType` enum for field value types
217
+ - For blocks: set `subsectionType: 'block'` or `'block--two-col'`
218
+ - For tables: set `subsectionType: 'table'`
219
+ - For footers: set `subsectionType: 'footer'` with `leftFieldMap` and `rightFieldMap`
220
+ - `parentPath` should use the Orderful JSON path (e.g., `'beginningSegmentForPurchaseOrder'`)
221
+ - Field `valuePath` is relative to the parentPath
222
+ - For qualifier fields, use `valueQualifierPath` or `labelQualifierPath`
223
+ - Export the item as a named const
224
+
225
+ #### Extended Subsection Items
226
+
227
+ For EXTEND items, propose the specific `Edit` changes to add new fields to the existing file. Show the user what will change before applying.
228
+
229
+ #### Register in helpers.ts
230
+
231
+ Add the new template to the `loadPrintViewTemplate` switch/map in:
232
+ ```
233
+ {ui_repo}/src/pages/Transaction/PrintView/templates/helpers.ts
234
+ ```
235
+
236
+ #### Update barrel exports
237
+
238
+ Add any new subsection items to:
239
+ ```
240
+ {ui_repo}/src/pages/Transaction/PrintView/templates/subsectionItems/index.ts
241
+ ```
242
+
243
+ #### Add TransactionType enum value
244
+
245
+ If this transaction type isn't already in the `TransactionType` enum, add it to:
246
+ ```
247
+ {ui_repo}/src/pages/Transaction/PrintView/types/index.ts
248
+ ```
249
+
250
+ Follow the naming convention: `SCREAMING_SNAKE_CASE = '{type}_{SCREAMING_SNAKE_NAME}'` (e.g., `CREDIT_DEBIT_ADJUSTMENT = '812_CREDIT_DEBIT_ADJUSTMENT'`).
251
+
252
+ #### Add to ALLOWED_TRANSACTION_TYPES
253
+
254
+ If this is a new transaction type, add it to the `ALLOWED_TRANSACTION_TYPES` array in:
255
+ ```
256
+ {ui_repo}/src/pages/Transaction/CreateTransaction/index.tsx
257
+ ```
258
+
259
+ #### Wire up PrintView component
260
+
261
+ Update the print view routing in:
262
+ ```
263
+ {ui_repo}/src/shared/helpers/printViewHelpers/getPrintViewComponentAndCsv.ts
264
+ ```
265
+
266
+ If there's an existing legacy component for this transaction type, replace it with `PrintView`. If there's no existing case, add one:
267
+ ```typescript
268
+ case '{type_enum_value}':
269
+ printViewComponent = PrintView;
270
+ break;
271
+ ```
272
+
273
+ #### Add to test coverage
274
+
275
+ Add the transaction type to `testedTransactionSets` in:
276
+ ```
277
+ {ui_repo}/src/pages/Transaction/PrintView/templates/tests/templates.spec.ts
278
+ ```
279
+
280
+ This test validates that all paths in the template exist in the schema. The template **must** pass this test — if paths don't resolve, the field names in subsection items are wrong.
281
+
282
+ ### Step 7: Summary
283
+
284
+ After generating, provide a summary:
285
+ - Files created (with paths)
286
+ - Files modified (with description of changes)
287
+ - Existing subsection items reused
288
+ - Any items that were extended
289
+
290
+ ## Type Reference
291
+
292
+ Quick reference for the template type system (defined in `templates/types.ts`):
293
+
294
+ ### Subsection Item Types
295
+
296
+ | Type | Use When | Key Fields |
297
+ |------|----------|------------|
298
+ | Block (static header) | Single record, fixed title | `subsectionType`, `header`, `parentPath`, `fieldMap` |
299
+ | Block (dynamic header) | Single record, title from data | `subsectionType`, `headerQualifierPath`, `parentPath`, `fieldMap` |
300
+ | Table (static header) | Repeating records, fixed title | `subsectionType`, `header`, `parentPath`, `columns` |
301
+ | Table (dynamic header) | Repeating records, title from data | `subsectionType`, `headerQualifierPath`, `parentPath`, `columns` |
302
+ | Footer | Totals/summary | `subsectionType: 'footer'`, `parentPath`, `leftFieldMap`, `rightFieldMap` |
303
+ | Hierarchy | HL loops (856 only) | `subsectionType: 'hierarchy'`, complex nesting |
304
+
305
+ ### FieldMapItem Types
306
+
307
+ | Type | Use When | Key Fields |
308
+ |------|----------|------------|
309
+ | DirectFieldMapItem | Simple label + value | `label`, `valuePath`, `valueType` |
310
+ | QualifiedLabelFieldMapItem | Label comes from a code qualifier | `labelQualifierPath`, `valuePath`, `valueType` |
311
+ | QualifiedValueFieldMapItem | The qualifier code IS the display value | `label`, `valueQualifierPath` |
312
+
313
+ ### Table Column Types
314
+
315
+ | Type | Use When | Key Fields |
316
+ |------|----------|------------|
317
+ | TableStaticValueColumn | Simple column | `header`, `valuePath`, `valueType` |
318
+ | TableQualifiedValueColumn | Column value from qualifier | `header`, `valueQualifierPath` |
319
+ | TableFieldMapColumn | Multiple fields in one column | `header`, `fieldMap` |
320
+ | NestedTableColumn | Blocks nested inside column | `header`, `subsections` |
321
+
322
+ ### ValueFormat
323
+
324
+ Use `valueFormat` on DirectFieldMapItem when needed:
325
+ - `'currency'` — e.g., $123.45
326
+ - `'signedCurrency'` — with +/- sign
327
+ - `'percent'` — e.g., 15%
328
+ - `'decimalPercent'` — e.g., 0.15
329
+
330
+ ### ElementType
331
+
332
+ Common values: `Alphanumeric`, `Numeric`, `Date`, `Time`, `ID`
333
+
334
+ ## Existing Subsection Items
335
+
336
+ **Do NOT hardcode this list — always scan the subsectionItems directory at runtime.** This list is for reference only and may be outdated.
337
+
338
+ ### High Reuse (4+ templates)
339
+ N1_loop, DTM (table + block), REF (table + block), SAC_loop, SAC_loop_block, FOB (table + block), TD5 (table + block), PID (table + block)
340
+
341
+ ### Medium Reuse (2-3 templates)
342
+ CUR, PER, CSH, ITD, MEA (table + block), TD1, NTE, MAN, LIN, AMT, CAD, PKG, QTY, TXI
343
+
344
+ ### Transaction-Specific Headers
345
+ BEG (850), BAK (855), BIG (810), BIA (846), BSN (856), G82 (875/880), BCD (812)
346
+
347
+ ### Line Item Loops
348
+ PO1_loop_850, PO1_loop_855, IT1_loop_810, CDD_loop, G68_loop, G83_loop, HL_loop + HL_loop_items
349
+
350
+ ### Footers
351
+ footer_CTT, footer_CTT_loop, footer_TDS_CTT, footer_G76, footer_G84
352
+
353
+ ### Other
354
+ ISS_loop, LIN_loop, R4, V1, SDQ, SCH, LDT, PRF, PO4, SN1, IT3, TD3, TD4_block, MTX, YNQ, N9 (block + loop + table), SHD, G01-G86 (grocery segments), constants
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@orderful/droid",
3
- "version": "0.53.0",
3
+ "version": "0.55.0",
4
4
  "description": "AI workflow toolkit for sharing skills, commands, and agents across the team",
5
5
  "type": "module",
6
6
  "bin": {