@orderful/droid 0.52.1 → 0.54.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/.claude-plugin/plugin.json +2 -0
- package/CHANGELOG.md +20 -0
- package/README.md +21 -1
- package/dist/bin/droid.js +83 -3
- package/dist/commands/copy-skills.d.ts +15 -0
- package/dist/commands/copy-skills.d.ts.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +334 -0
- package/dist/lib/skills.d.ts +23 -0
- package/dist/lib/skills.d.ts.map +1 -1
- package/dist/tools/propose-plan/skills/propose-plan/SKILL.md +12 -4
- package/dist/tools/propose-plan/skills/propose-plan/references/output-schema.json +4 -0
- package/dist/tools/webform/.claude-plugin/plugin.json +22 -0
- package/dist/tools/webform/TOOL.yaml +26 -0
- package/dist/tools/webform/commands/webform.md +17 -0
- package/dist/tools/webform/skills/webform/SKILL.md +354 -0
- package/package.json +1 -1
- package/src/bin/droid.ts +9 -0
- package/src/commands/copy-skills.ts +66 -0
- package/src/index.ts +2 -0
- package/src/lib/skills.ts +63 -0
- package/src/tools/propose-plan/skills/propose-plan/SKILL.md +12 -4
- package/src/tools/propose-plan/skills/propose-plan/references/output-schema.json +4 -0
- package/src/tools/webform/.claude-plugin/plugin.json +22 -0
- package/src/tools/webform/TOOL.yaml +26 -0
- package/src/tools/webform/commands/webform.md +17 -0
- package/src/tools/webform/skills/webform/SKILL.md +354 -0
|
@@ -23,6 +23,10 @@ A plan has two parts:
|
|
|
23
23
|
|
|
24
24
|
The human reviewer sees your evidence first (the reasoning and impact), then reviews each action. Clear evidence builds trust; vague evidence gets rejected.
|
|
25
25
|
|
|
26
|
+
**An empty actions array is valid.** If your research shows no writes are needed — conflicts block all operations, the work is already done, or the situation requires human input before any action can be proposed — return `"actions": []` with evidence explaining why. This is a "findings only" output. The reviewer still gets your analysis.
|
|
27
|
+
|
|
28
|
+
**Partial plans are also valid.** If some items are blocked but others are clear, include actions only for the clear ones. Flag blocked items in caveats with specific reasons. Don't skip the entire plan because one item has a conflict.
|
|
29
|
+
|
|
26
30
|
## Output Format
|
|
27
31
|
|
|
28
32
|
Produce a single JSON object matching the schema in `references/output-schema.json`. The shape:
|
|
@@ -32,6 +36,7 @@ Produce a single JSON object matching the schema in `references/output-schema.js
|
|
|
32
36
|
"name": "string — short human-readable plan name (optional)",
|
|
33
37
|
"category": "string — grouping category, e.g. org-provisioning (optional)",
|
|
34
38
|
"evidence": {
|
|
39
|
+
"planSummary": "string — one-line plain-language summary, e.g. 'Provision org and billing for Acme Corp' (optional)",
|
|
35
40
|
"reasoning": "string — your analysis of what needs to happen and why",
|
|
36
41
|
"sourceSummary": "string — concise summary of what you found during research",
|
|
37
42
|
"sourceRaw": "string — JSON-stringified raw source data from research (optional)",
|
|
@@ -53,9 +58,10 @@ Produce a single JSON object matching the schema in `references/output-schema.js
|
|
|
53
58
|
|
|
54
59
|
### Evidence Fields
|
|
55
60
|
|
|
56
|
-
| Field | Purpose
|
|
57
|
-
| --------------- |
|
|
58
|
-
| `
|
|
61
|
+
| Field | Purpose | Reviewer Experience |
|
|
62
|
+
| --------------- | ------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------ |
|
|
63
|
+
| `planSummary` | Optional. One-line plain-language summary of the plan. Keep it short and specific — entity names, not jargon. | Shown in headers and card previews. Quick scan context. |
|
|
64
|
+
| `reasoning` | Your analysis — what needs to happen and why. Cite actual data from your research, not assumptions. | First thing they read. Establishes trust. |
|
|
59
65
|
| `sourceSummary` | Concise summary of what you found. Include entity names, IDs, and states. | Quick scan to verify you looked at the right things. |
|
|
60
66
|
| `sourceRaw` | Optional. JSON-stringified raw API responses or data snapshots. | Expandable detail for reviewers who want to verify. |
|
|
61
67
|
| `impactSummary` | What changes if the plan is approved. Be specific — "creates org X with ISA ID Y" not "creates an org". | The core decision point. Reviewer approves based on this. |
|
|
@@ -129,6 +135,7 @@ Say you've been asked to provision an Orderful org for a new customer. You've qu
|
|
|
129
135
|
```json
|
|
130
136
|
{
|
|
131
137
|
"evidence": {
|
|
138
|
+
"planSummary": "Provision org, billing, and welcome email for Acme Corp",
|
|
132
139
|
"reasoning": "Salesforce account Acme Corp (SF-001234) was signed on 2026-03-01 and has no Orderful OrgID. No existing Orderful org matches by name or ISA ID. The account's primary contact is jane@acme.com. ISA ID derived from Customer_ISA_ID__c field: ACME001.",
|
|
133
140
|
"sourceSummary": "Salesforce: Acme Corp (SF-001234), signed 2026-03-01, no OrgID. Orderful: no org named 'Acme Corp', no ISA ID 'ACME001' in use.",
|
|
134
141
|
"sourceRaw": "{\"salesforce_account\":{\"Id\":\"SF-001234\",\"Name\":\"Acme Corp\",\"OrgID__c\":null,\"Customer_ISA_ID__c\":\"ACME001\"},\"orderful_org_search\":{\"results\":[]}}",
|
|
@@ -166,7 +173,8 @@ These are hard rules. Violating any of them will cause the plan to be rejected o
|
|
|
166
173
|
- **Don't include read operations as actions.** Actions are for writes only — things that change state and need human approval. Reading data is research, not an action. If you need to look something up, use read tools directly during your research phase.
|
|
167
174
|
- **Don't fabricate data.** If a value wasn't in your research and you can't verify it with read tools, say so in caveats. Never guess IDs, names, emails, or configuration values. A plan with honest gaps gets sent back for more research. A plan with invented data gets approved and breaks things.
|
|
168
175
|
- **Don't produce actions for tools outside your available list.** You can only propose actions for tools you've been given. If an operation requires a tool you don't have, note it as a caveat — don't invent an action for it. The execution step will reject unknown tools.
|
|
169
|
-
- **Don't skip evidence.** A plan without evidence will be rejected. The reviewer needs to see what you found, what it means, and what will change. Evidence is not optional filler — it is how the reviewer decides whether to approve.
|
|
176
|
+
- **Don't skip evidence.** A plan without evidence will be rejected — even if the actions array is empty. The reviewer needs to see what you found, what it means, and what will change. Evidence is not optional filler — it is how the reviewer decides whether to approve.
|
|
177
|
+
- **Don't force actions when none are possible.** If conflicts or preconditions block all operations, return an empty actions array with evidence explaining why. A findings-only plan is better than a plan with actions that will fail.
|
|
170
178
|
- **Don't combine multiple operations into one action.** Each action is one tool call. "Create org and set up billing" is two actions, not one. The execution step calls each action individually — a combined action will fail.
|
|
171
179
|
- **Don't hardcode values from actions that haven't run yet.** If action 2 needs the org ID from action 1, don't guess or invent a value — use a template reference: `"orgId": "{{ actions.0.result.id }}"`. The execution step resolves these at runtime. Never put a placeholder like `"TBD"` or `"<org-id>"` in a payload.
|
|
172
180
|
- **Don't use vague descriptions.** "Create org" tells the reviewer nothing. "Create Orderful org 'Acme Corp' with ISA ID 'ACME001'" tells them exactly what will happen. The description is what the reviewer reads before deciding whether to expand the payload.
|
|
@@ -18,6 +18,10 @@
|
|
|
18
18
|
"description": "Research findings and rationale supporting the plan",
|
|
19
19
|
"required": ["reasoning", "sourceSummary", "impactSummary"],
|
|
20
20
|
"properties": {
|
|
21
|
+
"planSummary": {
|
|
22
|
+
"type": "string",
|
|
23
|
+
"description": "One-line plain-language summary of the plan"
|
|
24
|
+
},
|
|
21
25
|
"reasoning": {
|
|
22
26
|
"type": "string",
|
|
23
27
|
"description": "Analysis of what needs to happen and why"
|
|
@@ -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
package/src/bin/droid.ts
CHANGED
|
@@ -21,6 +21,7 @@ import { integrationsSetupSlackCommand, integrationsStatusCommand, slackPostComm
|
|
|
21
21
|
import { getVersion } from '../lib/version';
|
|
22
22
|
import { loadConfig, saveConfig, configExists } from '../lib/config';
|
|
23
23
|
import { syncNewPlatforms } from '../lib/platforms';
|
|
24
|
+
import { copySkillsCommand } from '../commands/copy-skills';
|
|
24
25
|
|
|
25
26
|
const version = getVersion();
|
|
26
27
|
|
|
@@ -120,6 +121,14 @@ program
|
|
|
120
121
|
.allowUnknownOption()
|
|
121
122
|
.action(execCommand);
|
|
122
123
|
|
|
124
|
+
program
|
|
125
|
+
.command('copy-skills')
|
|
126
|
+
.description('Copy bundled skills to a destination directory')
|
|
127
|
+
.requiredOption('-d, --dest <dir>', 'Destination directory')
|
|
128
|
+
.option('-m, --manifest <file>', 'JSON file with array of skill names')
|
|
129
|
+
.option('-n, --names <names...>', 'Skill names to copy')
|
|
130
|
+
.action(copySkillsCommand);
|
|
131
|
+
|
|
123
132
|
// Integrations command with subcommands
|
|
124
133
|
const integrations = program
|
|
125
134
|
.command('integrations')
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import { readFileSync } from 'fs';
|
|
3
|
+
import { copySkillsToDir } from '../lib/skills';
|
|
4
|
+
|
|
5
|
+
interface CopySkillsOptions {
|
|
6
|
+
dest: string;
|
|
7
|
+
manifest?: string;
|
|
8
|
+
names?: string[];
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Copy bundled skills to a destination directory.
|
|
13
|
+
*
|
|
14
|
+
* Usage:
|
|
15
|
+
* droid copy-skills -d dist/assets/skills -m droid-skills.json
|
|
16
|
+
* droid copy-skills -d dist/assets/skills -n propose-plan edi-schema
|
|
17
|
+
*/
|
|
18
|
+
export function copySkillsCommand(options: CopySkillsOptions): void {
|
|
19
|
+
const { dest, manifest, names } = options;
|
|
20
|
+
|
|
21
|
+
// Resolve skill names from manifest file or --names flag
|
|
22
|
+
let skillNames: string[];
|
|
23
|
+
|
|
24
|
+
if (manifest) {
|
|
25
|
+
try {
|
|
26
|
+
const content = readFileSync(manifest, 'utf-8');
|
|
27
|
+
skillNames = JSON.parse(content);
|
|
28
|
+
if (!Array.isArray(skillNames)) {
|
|
29
|
+
console.error(
|
|
30
|
+
chalk.red('Manifest must be a JSON array of skill names'),
|
|
31
|
+
);
|
|
32
|
+
process.exit(1);
|
|
33
|
+
}
|
|
34
|
+
} catch (err) {
|
|
35
|
+
console.error(chalk.red(`Failed to read manifest: ${err}`));
|
|
36
|
+
process.exit(1);
|
|
37
|
+
}
|
|
38
|
+
} else if (names?.length) {
|
|
39
|
+
skillNames = names;
|
|
40
|
+
} else {
|
|
41
|
+
console.error(
|
|
42
|
+
chalk.red('Provide either --manifest <file> or --names <names...>'),
|
|
43
|
+
);
|
|
44
|
+
process.exit(1);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (skillNames.length === 0) {
|
|
48
|
+
console.log(chalk.yellow('No skills to copy.'));
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const results = copySkillsToDir(skillNames, dest);
|
|
53
|
+
|
|
54
|
+
for (const result of results) {
|
|
55
|
+
if (result.success) {
|
|
56
|
+
console.log(chalk.green(` ✓ ${result.name} → ${result.dest}`));
|
|
57
|
+
} else {
|
|
58
|
+
console.error(chalk.red(` ✗ ${result.name}: ${result.error}`));
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const failed = results.filter((r) => !r.success);
|
|
63
|
+
if (failed.length > 0) {
|
|
64
|
+
process.exit(1);
|
|
65
|
+
}
|
|
66
|
+
}
|
package/src/index.ts
CHANGED
package/src/lib/skills.ts
CHANGED
|
@@ -213,6 +213,69 @@ export function findSkillPath(
|
|
|
213
213
|
return null;
|
|
214
214
|
}
|
|
215
215
|
|
|
216
|
+
/**
|
|
217
|
+
* Resolve the absolute path to a bundled skill directory by name.
|
|
218
|
+
* Returns null if the skill is not found.
|
|
219
|
+
*
|
|
220
|
+
* This is the stable public API for consumers who need to locate skill
|
|
221
|
+
* assets (e.g., for copying into a build output). It encapsulates droid's
|
|
222
|
+
* internal `tools/{tool}/skills/{name}/` directory structure.
|
|
223
|
+
*/
|
|
224
|
+
export function getSkillPath(skillName: string): string | null {
|
|
225
|
+
const result = findSkillPath(skillName);
|
|
226
|
+
return result?.skillDir ?? null;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* Copy bundled skills to a destination directory.
|
|
231
|
+
* Each skill is copied as `{dest}/{skillName}/` with SKILL.md, references/, etc.
|
|
232
|
+
*
|
|
233
|
+
* @param skillNames - Array of skill names to copy
|
|
234
|
+
* @param dest - Target directory (created if it doesn't exist)
|
|
235
|
+
* @returns Results per skill: success/failure with paths
|
|
236
|
+
*/
|
|
237
|
+
export function copySkillsToDir(
|
|
238
|
+
skillNames: string[],
|
|
239
|
+
dest: string,
|
|
240
|
+
): Array<{ name: string; success: boolean; dest?: string; error?: string }> {
|
|
241
|
+
if (!existsSync(dest)) {
|
|
242
|
+
mkdirSync(dest, { recursive: true });
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
const results: Array<{
|
|
246
|
+
name: string;
|
|
247
|
+
success: boolean;
|
|
248
|
+
dest?: string;
|
|
249
|
+
error?: string;
|
|
250
|
+
}> = [];
|
|
251
|
+
|
|
252
|
+
for (const name of skillNames) {
|
|
253
|
+
const skillDir = getSkillPath(name);
|
|
254
|
+
if (!skillDir) {
|
|
255
|
+
results.push({
|
|
256
|
+
name,
|
|
257
|
+
success: false,
|
|
258
|
+
error: `Skill '${name}' not found in bundled tools`,
|
|
259
|
+
});
|
|
260
|
+
continue;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
const targetDir = join(dest, name);
|
|
264
|
+
try {
|
|
265
|
+
copyDirectoryRecursive(skillDir, targetDir, () => true);
|
|
266
|
+
results.push({ name, success: true, dest: targetDir });
|
|
267
|
+
} catch (err) {
|
|
268
|
+
results.push({
|
|
269
|
+
name,
|
|
270
|
+
success: false,
|
|
271
|
+
error: `Failed to copy: ${err}`,
|
|
272
|
+
});
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
return results;
|
|
277
|
+
}
|
|
278
|
+
|
|
216
279
|
/**
|
|
217
280
|
* Get all bundled skills from all tools
|
|
218
281
|
*/
|