noxctl 0.9.0 → 0.10.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 (199) hide show
  1. package/README.md +59 -1
  2. package/dist/api-coverage.d.ts +48 -0
  3. package/dist/api-coverage.d.ts.map +1 -0
  4. package/dist/api-coverage.js +175 -0
  5. package/dist/api-coverage.js.map +1 -0
  6. package/dist/cli-validators.d.ts +3 -0
  7. package/dist/cli-validators.d.ts.map +1 -0
  8. package/dist/cli-validators.js +10 -0
  9. package/dist/cli-validators.js.map +1 -0
  10. package/dist/cli.d.ts.map +1 -1
  11. package/dist/cli.js +1015 -13
  12. package/dist/cli.js.map +1 -1
  13. package/dist/fortnox-client.d.ts.map +1 -1
  14. package/dist/fortnox-client.js +1 -0
  15. package/dist/fortnox-client.js.map +1 -1
  16. package/dist/index.d.ts.map +1 -1
  17. package/dist/index.js +8 -0
  18. package/dist/index.js.map +1 -1
  19. package/dist/operations/absencetransactions.d.ts +3 -1
  20. package/dist/operations/absencetransactions.d.ts.map +1 -1
  21. package/dist/operations/absencetransactions.js +11 -1
  22. package/dist/operations/absencetransactions.js.map +1 -1
  23. package/dist/operations/accounts.d.ts +5 -1
  24. package/dist/operations/accounts.d.ts.map +1 -1
  25. package/dist/operations/accounts.js +24 -2
  26. package/dist/operations/accounts.js.map +1 -1
  27. package/dist/operations/accruals.d.ts +65 -0
  28. package/dist/operations/accruals.d.ts.map +1 -0
  29. package/dist/operations/accruals.js +81 -0
  30. package/dist/operations/accruals.js.map +1 -0
  31. package/dist/operations/articles.d.ts +2 -1
  32. package/dist/operations/articles.d.ts.map +1 -1
  33. package/dist/operations/articles.js +7 -2
  34. package/dist/operations/articles.js.map +1 -1
  35. package/dist/operations/attendancetransactions.d.ts +3 -1
  36. package/dist/operations/attendancetransactions.d.ts.map +1 -1
  37. package/dist/operations/attendancetransactions.js +11 -1
  38. package/dist/operations/attendancetransactions.js.map +1 -1
  39. package/dist/operations/customers.d.ts +2 -1
  40. package/dist/operations/customers.d.ts.map +1 -1
  41. package/dist/operations/customers.js +7 -2
  42. package/dist/operations/customers.js.map +1 -1
  43. package/dist/operations/files.d.ts +85 -0
  44. package/dist/operations/files.d.ts.map +1 -0
  45. package/dist/operations/files.js +88 -0
  46. package/dist/operations/files.js.map +1 -0
  47. package/dist/operations/financial-years.d.ts +2 -1
  48. package/dist/operations/financial-years.d.ts.map +1 -1
  49. package/dist/operations/financial-years.js +9 -2
  50. package/dist/operations/financial-years.js.map +1 -1
  51. package/dist/operations/general-ledger.d.ts +24 -0
  52. package/dist/operations/general-ledger.d.ts.map +1 -0
  53. package/dist/operations/general-ledger.js +66 -0
  54. package/dist/operations/general-ledger.js.map +1 -0
  55. package/dist/operations/index.d.ts +376 -0
  56. package/dist/operations/index.d.ts.map +1 -1
  57. package/dist/operations/index.js +8 -0
  58. package/dist/operations/index.js.map +1 -1
  59. package/dist/operations/invoice-payments.d.ts +2 -1
  60. package/dist/operations/invoice-payments.d.ts.map +1 -1
  61. package/dist/operations/invoice-payments.js +6 -1
  62. package/dist/operations/invoice-payments.js.map +1 -1
  63. package/dist/operations/invoices.d.ts +12 -1
  64. package/dist/operations/invoices.d.ts.map +1 -1
  65. package/dist/operations/invoices.js +51 -6
  66. package/dist/operations/invoices.js.map +1 -1
  67. package/dist/operations/offers.d.ts +5 -1
  68. package/dist/operations/offers.d.ts.map +1 -1
  69. package/dist/operations/offers.js +19 -1
  70. package/dist/operations/offers.js.map +1 -1
  71. package/dist/operations/orders.d.ts +5 -1
  72. package/dist/operations/orders.d.ts.map +1 -1
  73. package/dist/operations/orders.js +26 -2
  74. package/dist/operations/orders.js.map +1 -1
  75. package/dist/operations/pricelists.d.ts +4 -2
  76. package/dist/operations/pricelists.d.ts.map +1 -1
  77. package/dist/operations/pricelists.js +23 -9
  78. package/dist/operations/pricelists.js.map +1 -1
  79. package/dist/operations/projects.d.ts +2 -1
  80. package/dist/operations/projects.d.ts.map +1 -1
  81. package/dist/operations/projects.js +5 -2
  82. package/dist/operations/projects.js.map +1 -1
  83. package/dist/operations/reference-data.d.ts +243 -0
  84. package/dist/operations/reference-data.d.ts.map +1 -0
  85. package/dist/operations/reference-data.js +113 -0
  86. package/dist/operations/reference-data.js.map +1 -0
  87. package/dist/operations/salarytransactions.d.ts +2 -1
  88. package/dist/operations/salarytransactions.d.ts.map +1 -1
  89. package/dist/operations/salarytransactions.js +6 -1
  90. package/dist/operations/salarytransactions.js.map +1 -1
  91. package/dist/operations/supplier-invoice-payments.d.ts +3 -1
  92. package/dist/operations/supplier-invoice-payments.d.ts.map +1 -1
  93. package/dist/operations/supplier-invoice-payments.js +11 -1
  94. package/dist/operations/supplier-invoice-payments.js.map +1 -1
  95. package/dist/operations/supplier-invoices.d.ts +21 -1
  96. package/dist/operations/supplier-invoices.d.ts.map +1 -1
  97. package/dist/operations/supplier-invoices.js +68 -1
  98. package/dist/operations/supplier-invoices.js.map +1 -1
  99. package/dist/operations/taxreductions.d.ts +3 -1
  100. package/dist/operations/taxreductions.d.ts.map +1 -1
  101. package/dist/operations/taxreductions.js +18 -2
  102. package/dist/operations/taxreductions.js.map +1 -1
  103. package/dist/operations/vouchers.d.ts +3 -1
  104. package/dist/operations/vouchers.d.ts.map +1 -1
  105. package/dist/operations/vouchers.js +12 -1
  106. package/dist/operations/vouchers.js.map +1 -1
  107. package/dist/safe-file-output.d.ts +4 -0
  108. package/dist/safe-file-output.d.ts.map +1 -0
  109. package/dist/safe-file-output.js +48 -0
  110. package/dist/safe-file-output.js.map +1 -0
  111. package/dist/schema-audit-mappings.d.ts +6 -5
  112. package/dist/schema-audit-mappings.d.ts.map +1 -1
  113. package/dist/schema-audit-mappings.js +159 -10
  114. package/dist/schema-audit-mappings.js.map +1 -1
  115. package/dist/schema-audit.d.ts +30 -1
  116. package/dist/schema-audit.d.ts.map +1 -1
  117. package/dist/schema-audit.js +288 -14
  118. package/dist/schema-audit.js.map +1 -1
  119. package/dist/sie.d.ts +51 -0
  120. package/dist/sie.d.ts.map +1 -0
  121. package/dist/sie.js +355 -0
  122. package/dist/sie.js.map +1 -0
  123. package/dist/tools/absencetransactions.d.ts.map +1 -1
  124. package/dist/tools/absencetransactions.js +30 -3
  125. package/dist/tools/absencetransactions.js.map +1 -1
  126. package/dist/tools/accruals.d.ts +18 -0
  127. package/dist/tools/accruals.d.ts.map +1 -0
  128. package/dist/tools/accruals.js +169 -0
  129. package/dist/tools/accruals.js.map +1 -0
  130. package/dist/tools/articles.d.ts.map +1 -1
  131. package/dist/tools/articles.js +17 -2
  132. package/dist/tools/articles.js.map +1 -1
  133. package/dist/tools/attendancetransactions.d.ts.map +1 -1
  134. package/dist/tools/attendancetransactions.js +30 -3
  135. package/dist/tools/attendancetransactions.js.map +1 -1
  136. package/dist/tools/bookkeeping.d.ts.map +1 -1
  137. package/dist/tools/bookkeeping.js +93 -52
  138. package/dist/tools/bookkeeping.js.map +1 -1
  139. package/dist/tools/contracts.js +1 -1
  140. package/dist/tools/contracts.js.map +1 -1
  141. package/dist/tools/customers.d.ts.map +1 -1
  142. package/dist/tools/customers.js +111 -20
  143. package/dist/tools/customers.js.map +1 -1
  144. package/dist/tools/files.d.ts +4 -0
  145. package/dist/tools/files.d.ts.map +1 -0
  146. package/dist/tools/files.js +120 -0
  147. package/dist/tools/files.js.map +1 -0
  148. package/dist/tools/financial-years.d.ts.map +1 -1
  149. package/dist/tools/financial-years.js +18 -2
  150. package/dist/tools/financial-years.js.map +1 -1
  151. package/dist/tools/general-ledger.d.ts +4 -0
  152. package/dist/tools/general-ledger.d.ts.map +1 -0
  153. package/dist/tools/general-ledger.js +61 -0
  154. package/dist/tools/general-ledger.js.map +1 -0
  155. package/dist/tools/invoice-payments.d.ts.map +1 -1
  156. package/dist/tools/invoice-payments.js +34 -1
  157. package/dist/tools/invoice-payments.js.map +1 -1
  158. package/dist/tools/invoices.d.ts.map +1 -1
  159. package/dist/tools/invoices.js +145 -55
  160. package/dist/tools/invoices.js.map +1 -1
  161. package/dist/tools/offers.d.ts.map +1 -1
  162. package/dist/tools/offers.js +68 -1
  163. package/dist/tools/offers.js.map +1 -1
  164. package/dist/tools/orders.d.ts.map +1 -1
  165. package/dist/tools/orders.js +68 -1
  166. package/dist/tools/orders.js.map +1 -1
  167. package/dist/tools/pricelists.d.ts.map +1 -1
  168. package/dist/tools/pricelists.js +35 -3
  169. package/dist/tools/pricelists.js.map +1 -1
  170. package/dist/tools/projects.d.ts.map +1 -1
  171. package/dist/tools/projects.js +14 -2
  172. package/dist/tools/projects.js.map +1 -1
  173. package/dist/tools/recurrings.js +1 -1
  174. package/dist/tools/recurrings.js.map +1 -1
  175. package/dist/tools/reference-data.d.ts +17 -0
  176. package/dist/tools/reference-data.d.ts.map +1 -0
  177. package/dist/tools/reference-data.js +124 -0
  178. package/dist/tools/reference-data.js.map +1 -0
  179. package/dist/tools/salarytransactions.d.ts.map +1 -1
  180. package/dist/tools/salarytransactions.js +27 -1
  181. package/dist/tools/salarytransactions.js.map +1 -1
  182. package/dist/tools/supplier-invoice-payments.d.ts.map +1 -1
  183. package/dist/tools/supplier-invoice-payments.js +34 -1
  184. package/dist/tools/supplier-invoice-payments.js.map +1 -1
  185. package/dist/tools/supplier-invoices.d.ts.map +1 -1
  186. package/dist/tools/supplier-invoices.js +147 -5
  187. package/dist/tools/supplier-invoices.js.map +1 -1
  188. package/dist/tools/taxreductions.d.ts.map +1 -1
  189. package/dist/tools/taxreductions.js +33 -2
  190. package/dist/tools/taxreductions.js.map +1 -1
  191. package/dist/version.d.ts +1 -1
  192. package/dist/version.d.ts.map +1 -1
  193. package/dist/version.js +1 -1
  194. package/dist/version.js.map +1 -1
  195. package/dist/views.d.ts +3 -0
  196. package/dist/views.d.ts.map +1 -1
  197. package/dist/views.js +29 -1
  198. package/dist/views.js.map +1 -1
  199. package/package.json +8 -5
package/README.md CHANGED
@@ -31,6 +31,20 @@ no shared credential and no backend operated by this project.
31
31
  Secret Service, or a DPAPI-protected Windows store.
32
32
  - **Multiple companies:** named profiles keep Fortnox tenants separate.
33
33
 
34
+ ### API coverage boundary
35
+
36
+ noxctl tracks the complete published Fortnox operation inventory in an opaque,
37
+ privacy-safe implementation manifest. Every family is classified as complete,
38
+ partial, excluded, or blocked, and implemented families are verified against actual
39
+ operation exports, discovered MCP tools, and CLI commands.
40
+
41
+ The open-source core deliberately excludes separate product domains such as warehouse
42
+ management, partner onboarding/KYC, integration-marketplace administration, and the
43
+ standalone time-reporting API. Shared reference/configuration resources are read-first:
44
+ their reads are supported, while writes are explicitly excluded from the v1 core.
45
+ Remote URL attachment connections are also excluded because they introduce a separate
46
+ remote-fetch trust boundary. These are product-boundary decisions, not hidden gaps.
47
+
34
48
  ## Quick start
35
49
 
36
50
  You need Node.js 22.12+, a Fortnox account with API access, and your own Fortnox
@@ -165,6 +179,8 @@ Token management is automatic after setup — no environment variables needed go
165
179
 
166
180
  ### 3. Register as MCP server (optional — for Claude Desktop/Web)
167
181
 
182
+ Running `noxctl` without arguments prints help and exits. Use `noxctl serve` to start the MCP server.
183
+
168
184
  If you use Claude Desktop or claude.ai, register the MCP server so those environments can access Fortnox. Claude Code can use the CLI directly, so this step is optional there.
169
185
 
170
186
  ```bash
@@ -377,6 +393,8 @@ Every operation is available both as a CLI command and as an MCP tool. The CLI i
377
393
  | `noxctl supplier-invoices get <givenNumber>` | `fortnox_get_supplier_invoice` | Get a single supplier invoice |
378
394
  | `noxctl supplier-invoices create --supplier <n> --input <file>` | `fortnox_create_supplier_invoice` | Create a supplier invoice (mutation) |
379
395
  | `noxctl supplier-invoices bookkeep <givenNumber>` | `fortnox_bookkeep_supplier_invoice` | Bookkeep a supplier invoice (mutation) |
396
+ | `noxctl supplier-invoices attachments <givenNumber>` | `fortnox_list_supplier_invoice_attachments` | List files (e.g. the scanned/received invoice) attached to a supplier invoice — works for unbooked/authorizepending invoices too, read-only, default scopes only |
397
+ | `noxctl supplier-invoices file <fileId> [-f <path>]` | `fortnox_get_supplier_invoice_file` | Download a file attached to a supplier invoice (get `fileId` from `supplier-invoices attachments`) — read-only, default scopes only |
380
398
 
381
399
  ### Supplier invoice payments (utbetalningar)
382
400
 
@@ -422,6 +440,7 @@ Every operation is available both as a CLI command and as an MCP tool. The CLI i
422
440
  | `noxctl vouchers attach <series> <number> <file...> [--year]` | `fortnox_attach_voucher_files` | Upload receipt/underlag files and link them to a voucher (mutation; needs the Fortnox archive scope) |
423
441
  | `noxctl vouchers attachments <series> <number> [--year]` | `fortnox_list_voucher_attachments` | List files (receipts/underlag) already attached to a voucher — read-only, default scopes only |
424
442
  | `noxctl vouchers file <fileId> [-f <path>]` | `fortnox_get_voucher_file` | Download a file attached to a voucher (get `fileId` from `vouchers attachments`) — read-only, default scopes only |
443
+ | `noxctl general-ledger list --from <date> --to <date> [--year] [--account] [--series]` / alias `ledger list` | `fortnox_general_ledger` | Bookkeeping transactions with amounts for a date range, one row per posting — reads Fortnox's SIE export instead of walking vouchers one by one, so it stays fast for a full year. Read-only, default scopes only |
425
444
  | `noxctl accounts list [--search <term>]` | `fortnox_list_accounts` | View chart of accounts, search by name or number |
426
445
 
427
446
  ### Financial reports
@@ -496,6 +515,44 @@ Every operation is available both as a CLI command and as an MCP tool. The CLI i
496
515
  | `noxctl financial-years get <id>` | `fortnox_get_financialyear` | Get a single financial year |
497
516
  | `noxctl financial-years locked-period` | `fortnox_get_lockedperiod` | Show through which date bookkeeping is locked |
498
517
 
518
+ ### Reference and setup data (read-only)
519
+
520
+ The following command groups expose `list` and, where Fortnox provides it, `get` in
521
+ both CLI and MCP: `currencies`, `units`, `modes-of-payments`,
522
+ `terms-of-deliveries`, `terms-of-payments`, `ways-of-delivery`, `voucher-series`,
523
+ `predefined-voucher-series`, `account-charts`, `predefined-accounts`, and
524
+ `customer-references`.
525
+
526
+ ```bash
527
+ noxctl currencies list
528
+ noxctl terms-of-payments get 30
529
+ noxctl account-charts list
530
+ ```
531
+
532
+ ### Accruals (periodiseringar)
533
+
534
+ | CLI group | MCP tool prefix | Operations |
535
+ |---|---|---|
536
+ | `noxctl invoice-accruals` | `fortnox_*_invoice_accrual` | list, get, create, update, delete |
537
+ | `noxctl supplier-invoice-accruals` | `fortnox_*_supplier_invoice_accrual` | list, get, create, update, delete |
538
+ | `noxctl contract-accruals` | `fortnox_*_contract_accrual` | list, get, create, update, delete |
539
+
540
+ Every mutation supports confirmation and dry-run preview. Nested accrual rows are
541
+ strict and validated before any request is sent.
542
+
543
+ ### Archive, inbox, and cross-document attachments
544
+
545
+ | CLI group | MCP surface | Purpose |
546
+ |---|---|---|
547
+ | `noxctl archive` | `fortnox_*_archive*` | List/download, multipart upload, delete path/entry |
548
+ | `noxctl inbox` | `fortnox_*_inbox*` | List, multipart upload, safe download, delete |
549
+ | `noxctl attachments` | `fortnox_*_document_attachment*` | Attach/list/count/validate/update/detach for invoices, offers, orders, and contracts |
550
+
551
+ Voucher and supplier-invoice file connections additionally expose get/connect/detach
552
+ commands under their existing CLI groups. Binary downloads default to a private
553
+ temporary directory, use mode `0600`, refuse symlink targets and accidental overwrite,
554
+ and only replace an existing regular file when `--overwrite` is explicit.
555
+
499
556
  ### Payroll (Lön)
500
557
 
501
558
  > **Requires the `salary` scope**, which is **opt-in**. Enable the **Lön** permission on your Fortnox app, then run `noxctl init --with-salary` (or set `FORTNOX_WITH_SALARY=1` in non-interactive setups). Without it, these endpoints return `403 Forbidden`. See [Setup](#1-create-a-fortnox-app).
@@ -671,7 +728,8 @@ npm run test:watch # watch mode
671
728
  npm run lint # ESLint with typescript-eslint
672
729
  npm run format # format
673
730
  npm run check:api # refresh the git-ignored OpenAPI cache and detect API drift
674
- npm run audit:schemas # compare selected MCP write schemas with the local cache
731
+ npm run audit:schemas # inventory and recursively audit every mutating MCP input
732
+ npm run audit:api-coverage # verify the full operation inventory and implementation evidence
675
733
  ```
676
734
 
677
735
  ## Architecture
@@ -0,0 +1,48 @@
1
+ export type ApiCoverageClassification = 'complete' | 'partial' | 'excluded' | 'blocked';
2
+ export interface ApiCoverageMapping {
3
+ id: string;
4
+ classification: ApiCoverageClassification;
5
+ publicOperationCount: number;
6
+ implementedOperationIdentities: readonly string[];
7
+ missingOperationIdentities: readonly string[];
8
+ excludedOperationIdentities?: readonly string[];
9
+ evidence?: {
10
+ operationExports: readonly string[];
11
+ mcpTools: readonly string[];
12
+ cliCommands: readonly (readonly string[])[];
13
+ };
14
+ rationale?: string;
15
+ }
16
+ export interface ApiCoverageResult extends ApiCoverageMapping {
17
+ implementedOperationIdentities: string[];
18
+ missingOperationIdentities: string[];
19
+ excludedOperationIdentities: string[];
20
+ implementedCount: number;
21
+ missingCount: number;
22
+ excludedCount: number;
23
+ stateHash: string;
24
+ }
25
+ export interface ApiCoverageBaselineRecord {
26
+ id: string;
27
+ classification: ApiCoverageClassification;
28
+ publicOperationCount: number;
29
+ implementedCount: number;
30
+ missingCount: number;
31
+ excludedCount: number;
32
+ stateHash: string;
33
+ rationale?: string;
34
+ }
35
+ export interface ApiCoverageBaseline {
36
+ formatVersion: 1;
37
+ records: ApiCoverageBaselineRecord[];
38
+ }
39
+ export interface ApiCoverageComparison {
40
+ matches: boolean;
41
+ changedMappingIds: string[];
42
+ }
43
+ export declare function calculateApiCoverage(mappings: readonly ApiCoverageMapping[]): ApiCoverageResult[];
44
+ export declare function toApiCoverageBaseline(results: readonly ApiCoverageResult[]): ApiCoverageBaseline;
45
+ export declare function compareApiCoverageBaselines(expected: ApiCoverageBaseline, current: ApiCoverageBaseline): ApiCoverageComparison;
46
+ export declare function formatApiCoverageSummary(results: readonly ApiCoverageResult[], comparison?: ApiCoverageComparison): string;
47
+ export declare function formatApiCoverageDetails(results: readonly ApiCoverageResult[]): string;
48
+ //# sourceMappingURL=api-coverage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api-coverage.d.ts","sourceRoot":"","sources":["../src/api-coverage.ts"],"names":[],"mappings":"AAIA,MAAM,MAAM,yBAAyB,GAAG,UAAU,GAAG,SAAS,GAAG,UAAU,GAAG,SAAS,CAAC;AAExF,MAAM,WAAW,kBAAkB;IACjC,EAAE,EAAE,MAAM,CAAC;IACX,cAAc,EAAE,yBAAyB,CAAC;IAC1C,oBAAoB,EAAE,MAAM,CAAC;IAC7B,8BAA8B,EAAE,SAAS,MAAM,EAAE,CAAC;IAClD,0BAA0B,EAAE,SAAS,MAAM,EAAE,CAAC;IAC9C,2BAA2B,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAChD,QAAQ,CAAC,EAAE;QACT,gBAAgB,EAAE,SAAS,MAAM,EAAE,CAAC;QACpC,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAC;QAC5B,WAAW,EAAE,SAAS,CAAC,SAAS,MAAM,EAAE,CAAC,EAAE,CAAC;KAC7C,CAAC;IACF,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,iBAAkB,SAAQ,kBAAkB;IAC3D,8BAA8B,EAAE,MAAM,EAAE,CAAC;IACzC,0BAA0B,EAAE,MAAM,EAAE,CAAC;IACrC,2BAA2B,EAAE,MAAM,EAAE,CAAC;IACtC,gBAAgB,EAAE,MAAM,CAAC;IACzB,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,yBAAyB;IACxC,EAAE,EAAE,MAAM,CAAC;IACX,cAAc,EAAE,yBAAyB,CAAC;IAC1C,oBAAoB,EAAE,MAAM,CAAC;IAC7B,gBAAgB,EAAE,MAAM,CAAC;IACzB,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,mBAAmB;IAClC,aAAa,EAAE,CAAC,CAAC;IACjB,OAAO,EAAE,yBAAyB,EAAE,CAAC;CACtC;AAED,MAAM,WAAW,qBAAqB;IACpC,OAAO,EAAE,OAAO,CAAC;IACjB,iBAAiB,EAAE,MAAM,EAAE,CAAC;CAC7B;AA4GD,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,SAAS,kBAAkB,EAAE,GAAG,iBAAiB,EAAE,CAuBjG;AAED,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,SAAS,iBAAiB,EAAE,GAAG,mBAAmB,CA2BhG;AAED,wBAAgB,2BAA2B,CACzC,QAAQ,EAAE,mBAAmB,EAC7B,OAAO,EAAE,mBAAmB,GAC3B,qBAAqB,CAWvB;AAED,wBAAgB,wBAAwB,CACtC,OAAO,EAAE,SAAS,iBAAiB,EAAE,EACrC,UAAU,CAAC,EAAE,qBAAqB,GACjC,MAAM,CA6BR;AAED,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,SAAS,iBAAiB,EAAE,GAAG,MAAM,CAYtF"}
@@ -0,0 +1,175 @@
1
+ import { createHash } from 'node:crypto';
2
+ const HASH_DOMAIN = 'noxctl-api-coverage/v1';
3
+ const compareText = (left, right) => left.localeCompare(right, 'en');
4
+ function assertUnique(values, label, id) {
5
+ if (new Set(values).size !== values.length) {
6
+ throw new Error(`Duplicate ${label} identities for mapping ${id}`);
7
+ }
8
+ }
9
+ function validateMapping(mapping) {
10
+ if (!['complete', 'partial', 'excluded', 'blocked'].includes(mapping.classification)) {
11
+ throw new Error(`Invalid classification for mapping ${mapping.id}`);
12
+ }
13
+ if (!Number.isInteger(mapping.publicOperationCount) || mapping.publicOperationCount < 0) {
14
+ throw new Error(`Invalid publicOperationCount for mapping ${mapping.id}`);
15
+ }
16
+ assertUnique(mapping.implementedOperationIdentities, 'implemented', mapping.id);
17
+ assertUnique(mapping.missingOperationIdentities, 'missing', mapping.id);
18
+ assertUnique(mapping.excludedOperationIdentities ?? [], 'excluded', mapping.id);
19
+ if (mapping.evidence) {
20
+ assertUnique(mapping.evidence.operationExports, 'operation-export evidence', mapping.id);
21
+ assertUnique(mapping.evidence.mcpTools, 'MCP-tool evidence', mapping.id);
22
+ assertUnique(mapping.evidence.cliCommands.map((command) => JSON.stringify(command)), 'CLI-command evidence', mapping.id);
23
+ }
24
+ const implemented = new Set(mapping.implementedOperationIdentities);
25
+ if (mapping.missingOperationIdentities.some((identity) => implemented.has(identity))) {
26
+ throw new Error(`Operation appears as both implemented and missing for mapping ${mapping.id}`);
27
+ }
28
+ const missing = new Set(mapping.missingOperationIdentities);
29
+ const excluded = mapping.excludedOperationIdentities ?? [];
30
+ if (excluded.some((identity) => implemented.has(identity) || missing.has(identity))) {
31
+ throw new Error(`Operation has more than one coverage state for mapping ${mapping.id}`);
32
+ }
33
+ const accountedCount = mapping.implementedOperationIdentities.length +
34
+ mapping.missingOperationIdentities.length +
35
+ excluded.length;
36
+ if (accountedCount !== mapping.publicOperationCount) {
37
+ throw new Error(`Mapping ${mapping.id} accounts for ${accountedCount} of ${mapping.publicOperationCount} public operations`);
38
+ }
39
+ if (mapping.classification === 'complete' && mapping.missingOperationIdentities.length > 0) {
40
+ throw new Error(`Complete mapping ${mapping.id} has missing operations`);
41
+ }
42
+ if (mapping.classification === 'partial' && mapping.missingOperationIdentities.length === 0) {
43
+ throw new Error(`Partial mapping ${mapping.id} must have a missing operation`);
44
+ }
45
+ if (mapping.implementedOperationIdentities.length > 0 &&
46
+ (!mapping.evidence?.operationExports.length ||
47
+ !mapping.evidence.mcpTools.length ||
48
+ !mapping.evidence.cliCommands.length)) {
49
+ throw new Error(`Implemented mapping ${mapping.id} requires export, MCP, and CLI evidence`);
50
+ }
51
+ if ((mapping.classification === 'excluded' ||
52
+ mapping.classification === 'blocked' ||
53
+ excluded.length > 0) &&
54
+ !mapping.rationale?.trim()) {
55
+ throw new Error(`${mapping.classification} mapping ${mapping.id} requires a rationale`);
56
+ }
57
+ if ((mapping.classification === 'excluded' || mapping.classification === 'blocked') &&
58
+ (mapping.implementedOperationIdentities.length > 0 ||
59
+ (mapping.evidence &&
60
+ (mapping.evidence.operationExports.length > 0 ||
61
+ mapping.evidence.mcpTools.length > 0 ||
62
+ mapping.evidence.cliCommands.length > 0)))) {
63
+ throw new Error(`${mapping.classification} mapping ${mapping.id} cannot have implemented operations or exposure evidence`);
64
+ }
65
+ }
66
+ function calculateStateHash(mapping) {
67
+ const canonical = JSON.stringify({
68
+ domain: HASH_DOMAIN,
69
+ id: mapping.id,
70
+ classification: mapping.classification,
71
+ publicOperationCount: mapping.publicOperationCount,
72
+ implemented: [...mapping.implementedOperationIdentities].sort(compareText),
73
+ missing: [...mapping.missingOperationIdentities].sort(compareText),
74
+ excluded: [...(mapping.excludedOperationIdentities ?? [])].sort(compareText),
75
+ evidence: mapping.evidence
76
+ ? {
77
+ operationExports: [...mapping.evidence.operationExports].sort(compareText),
78
+ mcpTools: [...mapping.evidence.mcpTools].sort(compareText),
79
+ cliCommands: mapping.evidence.cliCommands
80
+ .map((command) => [...command])
81
+ .sort((left, right) => compareText(JSON.stringify(left), JSON.stringify(right))),
82
+ }
83
+ : undefined,
84
+ rationale: mapping.rationale,
85
+ });
86
+ return createHash('sha256').update(canonical).digest('hex');
87
+ }
88
+ export function calculateApiCoverage(mappings) {
89
+ const ids = new Set();
90
+ return mappings
91
+ .map((mapping) => {
92
+ if (ids.has(mapping.id))
93
+ throw new Error(`Duplicate API coverage mapping id: ${mapping.id}`);
94
+ ids.add(mapping.id);
95
+ validateMapping(mapping);
96
+ return {
97
+ ...mapping,
98
+ implementedOperationIdentities: [...mapping.implementedOperationIdentities].sort(compareText),
99
+ missingOperationIdentities: [...mapping.missingOperationIdentities].sort(compareText),
100
+ excludedOperationIdentities: [...(mapping.excludedOperationIdentities ?? [])].sort(compareText),
101
+ implementedCount: mapping.implementedOperationIdentities.length,
102
+ missingCount: mapping.missingOperationIdentities.length,
103
+ excludedCount: mapping.excludedOperationIdentities?.length ?? 0,
104
+ stateHash: calculateStateHash(mapping),
105
+ };
106
+ })
107
+ .sort((left, right) => compareText(left.id, right.id));
108
+ }
109
+ export function toApiCoverageBaseline(results) {
110
+ return {
111
+ formatVersion: 1,
112
+ records: [...results]
113
+ .sort((left, right) => compareText(left.id, right.id))
114
+ .map(({ id, classification, publicOperationCount, implementedCount, missingCount, excludedCount, stateHash, rationale, }) => ({
115
+ id,
116
+ classification,
117
+ publicOperationCount,
118
+ implementedCount,
119
+ missingCount,
120
+ excludedCount,
121
+ stateHash,
122
+ ...(rationale ? { rationale } : {}),
123
+ })),
124
+ };
125
+ }
126
+ export function compareApiCoverageBaselines(expected, current) {
127
+ const expectedRecords = new Map(expected.records.map((record) => [record.id, record]));
128
+ const currentRecords = new Map(current.records.map((record) => [record.id, record]));
129
+ const ids = new Set([...expectedRecords.keys(), ...currentRecords.keys()]);
130
+ const changedMappingIds = [...ids]
131
+ .filter((id) => JSON.stringify(expectedRecords.get(id)) !== JSON.stringify(currentRecords.get(id)))
132
+ .sort(compareText);
133
+ if (expected.formatVersion !== current.formatVersion)
134
+ changedMappingIds.unshift('$format');
135
+ return { matches: changedMappingIds.length === 0, changedMappingIds };
136
+ }
137
+ export function formatApiCoverageSummary(results, comparison) {
138
+ const status = comparison ? (comparison.matches ? 'ok' : 'drift') : 'generated';
139
+ const totals = results.reduce((value, result) => ({
140
+ ...value,
141
+ [result.classification]: value[result.classification] + 1,
142
+ public: value.public + result.publicOperationCount,
143
+ implemented: value.implemented + result.implementedCount,
144
+ excludedOperations: value.excludedOperations + result.excludedCount,
145
+ missing: value.missing + result.missingCount,
146
+ }), {
147
+ complete: 0,
148
+ partial: 0,
149
+ excluded: 0,
150
+ blocked: 0,
151
+ public: 0,
152
+ implemented: 0,
153
+ excludedOperations: 0,
154
+ missing: 0,
155
+ });
156
+ const lines = [
157
+ `API coverage: ${status} families=${results.length} complete=${totals.complete} partial=${totals.partial} excluded=${totals.excluded} blocked=${totals.blocked} public=${totals.public} implemented=${totals.implemented} excluded-operations=${totals.excludedOperations} missing=${totals.missing}`,
158
+ ];
159
+ if (comparison && !comparison.matches) {
160
+ lines.push(`Changed mappings: ${comparison.changedMappingIds.join(', ')}`);
161
+ }
162
+ return `${lines.join('\n')}\n`;
163
+ }
164
+ export function formatApiCoverageDetails(results) {
165
+ const lines = [];
166
+ for (const result of results) {
167
+ lines.push(`${result.id}:`);
168
+ const identities = [...result.missingOperationIdentities].sort(compareText);
169
+ lines.push(...(identities.length
170
+ ? identities.map((identity) => ` - ${JSON.stringify(identity)}`)
171
+ : [' (none)']));
172
+ }
173
+ return `${lines.join('\n')}\n`;
174
+ }
175
+ //# sourceMappingURL=api-coverage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api-coverage.js","sourceRoot":"","sources":["../src/api-coverage.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ /** Commander passes the previous option value as its second parser argument. */
2
+ export declare function parsePositiveInteger(value: string): number;
3
+ //# sourceMappingURL=cli-validators.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli-validators.d.ts","sourceRoot":"","sources":["../src/cli-validators.ts"],"names":[],"mappings":"AAEA,gFAAgF;AAChF,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAM1D"}
@@ -0,0 +1,10 @@
1
+ import { InvalidArgumentError } from 'commander';
2
+ /** Commander passes the previous option value as its second parser argument. */
3
+ export function parsePositiveInteger(value) {
4
+ const parsed = Number(value);
5
+ if (!/^\d+$/.test(value) || !Number.isSafeInteger(parsed) || parsed <= 0) {
6
+ throw new InvalidArgumentError('Expected a positive safe integer.');
7
+ }
8
+ return parsed;
9
+ }
10
+ //# sourceMappingURL=cli-validators.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli-validators.js","sourceRoot":"","sources":["../src/cli-validators.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAC;AAEjD,gFAAgF;AAChF,MAAM,UAAU,oBAAoB,CAAC,KAAa;IAChD,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;IAC7B,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,MAAM,IAAI,CAAC,EAAE,CAAC;QACzE,MAAM,IAAI,oBAAoB,CAAC,mCAAmC,CAAC,CAAC;IACtE,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC"}
package/dist/cli.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAcA,OAAO,EAOL,KAAK,eAAe,EACrB,MAAM,eAAe,CAAC;AA0IvB,wBAAgB,sBAAsB,IAAI,eAAe,CAExD"}
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAeA,OAAO,EAOL,KAAK,eAAe,EACrB,MAAM,eAAe,CAAC;AA+IvB,wBAAgB,sBAAsB,IAAI,eAAe,CAExD"}