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.
- package/README.md +59 -1
- package/dist/api-coverage.d.ts +48 -0
- package/dist/api-coverage.d.ts.map +1 -0
- package/dist/api-coverage.js +175 -0
- package/dist/api-coverage.js.map +1 -0
- package/dist/cli-validators.d.ts +3 -0
- package/dist/cli-validators.d.ts.map +1 -0
- package/dist/cli-validators.js +10 -0
- package/dist/cli-validators.js.map +1 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +1015 -13
- package/dist/cli.js.map +1 -1
- package/dist/fortnox-client.d.ts.map +1 -1
- package/dist/fortnox-client.js +1 -0
- package/dist/fortnox-client.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -1
- package/dist/operations/absencetransactions.d.ts +3 -1
- package/dist/operations/absencetransactions.d.ts.map +1 -1
- package/dist/operations/absencetransactions.js +11 -1
- package/dist/operations/absencetransactions.js.map +1 -1
- package/dist/operations/accounts.d.ts +5 -1
- package/dist/operations/accounts.d.ts.map +1 -1
- package/dist/operations/accounts.js +24 -2
- package/dist/operations/accounts.js.map +1 -1
- package/dist/operations/accruals.d.ts +65 -0
- package/dist/operations/accruals.d.ts.map +1 -0
- package/dist/operations/accruals.js +81 -0
- package/dist/operations/accruals.js.map +1 -0
- package/dist/operations/articles.d.ts +2 -1
- package/dist/operations/articles.d.ts.map +1 -1
- package/dist/operations/articles.js +7 -2
- package/dist/operations/articles.js.map +1 -1
- package/dist/operations/attendancetransactions.d.ts +3 -1
- package/dist/operations/attendancetransactions.d.ts.map +1 -1
- package/dist/operations/attendancetransactions.js +11 -1
- package/dist/operations/attendancetransactions.js.map +1 -1
- package/dist/operations/customers.d.ts +2 -1
- package/dist/operations/customers.d.ts.map +1 -1
- package/dist/operations/customers.js +7 -2
- package/dist/operations/customers.js.map +1 -1
- package/dist/operations/files.d.ts +85 -0
- package/dist/operations/files.d.ts.map +1 -0
- package/dist/operations/files.js +88 -0
- package/dist/operations/files.js.map +1 -0
- package/dist/operations/financial-years.d.ts +2 -1
- package/dist/operations/financial-years.d.ts.map +1 -1
- package/dist/operations/financial-years.js +9 -2
- package/dist/operations/financial-years.js.map +1 -1
- package/dist/operations/general-ledger.d.ts +24 -0
- package/dist/operations/general-ledger.d.ts.map +1 -0
- package/dist/operations/general-ledger.js +66 -0
- package/dist/operations/general-ledger.js.map +1 -0
- package/dist/operations/index.d.ts +376 -0
- package/dist/operations/index.d.ts.map +1 -1
- package/dist/operations/index.js +8 -0
- package/dist/operations/index.js.map +1 -1
- package/dist/operations/invoice-payments.d.ts +2 -1
- package/dist/operations/invoice-payments.d.ts.map +1 -1
- package/dist/operations/invoice-payments.js +6 -1
- package/dist/operations/invoice-payments.js.map +1 -1
- package/dist/operations/invoices.d.ts +12 -1
- package/dist/operations/invoices.d.ts.map +1 -1
- package/dist/operations/invoices.js +51 -6
- package/dist/operations/invoices.js.map +1 -1
- package/dist/operations/offers.d.ts +5 -1
- package/dist/operations/offers.d.ts.map +1 -1
- package/dist/operations/offers.js +19 -1
- package/dist/operations/offers.js.map +1 -1
- package/dist/operations/orders.d.ts +5 -1
- package/dist/operations/orders.d.ts.map +1 -1
- package/dist/operations/orders.js +26 -2
- package/dist/operations/orders.js.map +1 -1
- package/dist/operations/pricelists.d.ts +4 -2
- package/dist/operations/pricelists.d.ts.map +1 -1
- package/dist/operations/pricelists.js +23 -9
- package/dist/operations/pricelists.js.map +1 -1
- package/dist/operations/projects.d.ts +2 -1
- package/dist/operations/projects.d.ts.map +1 -1
- package/dist/operations/projects.js +5 -2
- package/dist/operations/projects.js.map +1 -1
- package/dist/operations/reference-data.d.ts +243 -0
- package/dist/operations/reference-data.d.ts.map +1 -0
- package/dist/operations/reference-data.js +113 -0
- package/dist/operations/reference-data.js.map +1 -0
- package/dist/operations/salarytransactions.d.ts +2 -1
- package/dist/operations/salarytransactions.d.ts.map +1 -1
- package/dist/operations/salarytransactions.js +6 -1
- package/dist/operations/salarytransactions.js.map +1 -1
- package/dist/operations/supplier-invoice-payments.d.ts +3 -1
- package/dist/operations/supplier-invoice-payments.d.ts.map +1 -1
- package/dist/operations/supplier-invoice-payments.js +11 -1
- package/dist/operations/supplier-invoice-payments.js.map +1 -1
- package/dist/operations/supplier-invoices.d.ts +21 -1
- package/dist/operations/supplier-invoices.d.ts.map +1 -1
- package/dist/operations/supplier-invoices.js +68 -1
- package/dist/operations/supplier-invoices.js.map +1 -1
- package/dist/operations/taxreductions.d.ts +3 -1
- package/dist/operations/taxreductions.d.ts.map +1 -1
- package/dist/operations/taxreductions.js +18 -2
- package/dist/operations/taxreductions.js.map +1 -1
- package/dist/operations/vouchers.d.ts +3 -1
- package/dist/operations/vouchers.d.ts.map +1 -1
- package/dist/operations/vouchers.js +12 -1
- package/dist/operations/vouchers.js.map +1 -1
- package/dist/safe-file-output.d.ts +4 -0
- package/dist/safe-file-output.d.ts.map +1 -0
- package/dist/safe-file-output.js +48 -0
- package/dist/safe-file-output.js.map +1 -0
- package/dist/schema-audit-mappings.d.ts +6 -5
- package/dist/schema-audit-mappings.d.ts.map +1 -1
- package/dist/schema-audit-mappings.js +159 -10
- package/dist/schema-audit-mappings.js.map +1 -1
- package/dist/schema-audit.d.ts +30 -1
- package/dist/schema-audit.d.ts.map +1 -1
- package/dist/schema-audit.js +288 -14
- package/dist/schema-audit.js.map +1 -1
- package/dist/sie.d.ts +51 -0
- package/dist/sie.d.ts.map +1 -0
- package/dist/sie.js +355 -0
- package/dist/sie.js.map +1 -0
- package/dist/tools/absencetransactions.d.ts.map +1 -1
- package/dist/tools/absencetransactions.js +30 -3
- package/dist/tools/absencetransactions.js.map +1 -1
- package/dist/tools/accruals.d.ts +18 -0
- package/dist/tools/accruals.d.ts.map +1 -0
- package/dist/tools/accruals.js +169 -0
- package/dist/tools/accruals.js.map +1 -0
- package/dist/tools/articles.d.ts.map +1 -1
- package/dist/tools/articles.js +17 -2
- package/dist/tools/articles.js.map +1 -1
- package/dist/tools/attendancetransactions.d.ts.map +1 -1
- package/dist/tools/attendancetransactions.js +30 -3
- package/dist/tools/attendancetransactions.js.map +1 -1
- package/dist/tools/bookkeeping.d.ts.map +1 -1
- package/dist/tools/bookkeeping.js +93 -52
- package/dist/tools/bookkeeping.js.map +1 -1
- package/dist/tools/contracts.js +1 -1
- package/dist/tools/contracts.js.map +1 -1
- package/dist/tools/customers.d.ts.map +1 -1
- package/dist/tools/customers.js +111 -20
- package/dist/tools/customers.js.map +1 -1
- package/dist/tools/files.d.ts +4 -0
- package/dist/tools/files.d.ts.map +1 -0
- package/dist/tools/files.js +120 -0
- package/dist/tools/files.js.map +1 -0
- package/dist/tools/financial-years.d.ts.map +1 -1
- package/dist/tools/financial-years.js +18 -2
- package/dist/tools/financial-years.js.map +1 -1
- package/dist/tools/general-ledger.d.ts +4 -0
- package/dist/tools/general-ledger.d.ts.map +1 -0
- package/dist/tools/general-ledger.js +61 -0
- package/dist/tools/general-ledger.js.map +1 -0
- package/dist/tools/invoice-payments.d.ts.map +1 -1
- package/dist/tools/invoice-payments.js +34 -1
- package/dist/tools/invoice-payments.js.map +1 -1
- package/dist/tools/invoices.d.ts.map +1 -1
- package/dist/tools/invoices.js +145 -55
- package/dist/tools/invoices.js.map +1 -1
- package/dist/tools/offers.d.ts.map +1 -1
- package/dist/tools/offers.js +68 -1
- package/dist/tools/offers.js.map +1 -1
- package/dist/tools/orders.d.ts.map +1 -1
- package/dist/tools/orders.js +68 -1
- package/dist/tools/orders.js.map +1 -1
- package/dist/tools/pricelists.d.ts.map +1 -1
- package/dist/tools/pricelists.js +35 -3
- package/dist/tools/pricelists.js.map +1 -1
- package/dist/tools/projects.d.ts.map +1 -1
- package/dist/tools/projects.js +14 -2
- package/dist/tools/projects.js.map +1 -1
- package/dist/tools/recurrings.js +1 -1
- package/dist/tools/recurrings.js.map +1 -1
- package/dist/tools/reference-data.d.ts +17 -0
- package/dist/tools/reference-data.d.ts.map +1 -0
- package/dist/tools/reference-data.js +124 -0
- package/dist/tools/reference-data.js.map +1 -0
- package/dist/tools/salarytransactions.d.ts.map +1 -1
- package/dist/tools/salarytransactions.js +27 -1
- package/dist/tools/salarytransactions.js.map +1 -1
- package/dist/tools/supplier-invoice-payments.d.ts.map +1 -1
- package/dist/tools/supplier-invoice-payments.js +34 -1
- package/dist/tools/supplier-invoice-payments.js.map +1 -1
- package/dist/tools/supplier-invoices.d.ts.map +1 -1
- package/dist/tools/supplier-invoices.js +147 -5
- package/dist/tools/supplier-invoices.js.map +1 -1
- package/dist/tools/taxreductions.d.ts.map +1 -1
- package/dist/tools/taxreductions.js +33 -2
- package/dist/tools/taxreductions.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.d.ts.map +1 -1
- package/dist/version.js +1 -1
- package/dist/version.js.map +1 -1
- package/dist/views.d.ts +3 -0
- package/dist/views.d.ts.map +1 -1
- package/dist/views.js +29 -1
- package/dist/views.js.map +1 -1
- 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 #
|
|
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 @@
|
|
|
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":";
|
|
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"}
|