@stelis/agent-q-core 0.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/README.md +144 -0
  2. package/dist/adapter-internal.d.ts +5 -0
  3. package/dist/adapter-internal.js +6 -0
  4. package/dist/adapter-internal.js.map +1 -0
  5. package/dist/config.d.ts +74 -0
  6. package/dist/config.js +489 -0
  7. package/dist/config.js.map +1 -0
  8. package/dist/core.d.ts +320 -0
  9. package/dist/core.js +840 -0
  10. package/dist/core.js.map +1 -0
  11. package/dist/device.d.ts +55 -0
  12. package/dist/device.js +23 -0
  13. package/dist/device.js.map +1 -0
  14. package/dist/errors.d.ts +6 -0
  15. package/dist/errors.js +20 -0
  16. package/dist/errors.js.map +1 -0
  17. package/dist/host-output-schema.d.ts +2437 -0
  18. package/dist/host-output-schema.js +655 -0
  19. package/dist/host-output-schema.js.map +1 -0
  20. package/dist/protocol-error.d.ts +4 -0
  21. package/dist/protocol-error.js +9 -0
  22. package/dist/protocol-error.js.map +1 -0
  23. package/dist/protocol-management-primitives.d.ts +27 -0
  24. package/dist/protocol-management-primitives.js +51 -0
  25. package/dist/protocol-management-primitives.js.map +1 -0
  26. package/dist/protocol-primitives.d.ts +53 -0
  27. package/dist/protocol-primitives.js +331 -0
  28. package/dist/protocol-primitives.js.map +1 -0
  29. package/dist/protocol.d.ts +207 -0
  30. package/dist/protocol.js +897 -0
  31. package/dist/protocol.js.map +1 -0
  32. package/dist/provider-protocol.d.ts +262 -0
  33. package/dist/provider-protocol.js +637 -0
  34. package/dist/provider-protocol.js.map +1 -0
  35. package/dist/public-error.d.ts +9 -0
  36. package/dist/public-error.js +79 -0
  37. package/dist/public-error.js.map +1 -0
  38. package/dist/safe-text.d.ts +31 -0
  39. package/dist/safe-text.js +143 -0
  40. package/dist/safe-text.js.map +1 -0
  41. package/dist/transport-invariants.d.ts +18 -0
  42. package/dist/transport-invariants.js +24 -0
  43. package/dist/transport-invariants.js.map +1 -0
  44. package/dist/usb.d.ts +76 -0
  45. package/dist/usb.js +454 -0
  46. package/dist/usb.js.map +1 -0
  47. package/package.json +58 -0
package/README.md ADDED
@@ -0,0 +1,144 @@
1
+ # Agent-Q Core
2
+
3
+ `@stelis/agent-q-core` is the shared Agent-Q core package.
4
+
5
+ It provides transport, protocol builders and parsers, runtime session mirroring,
6
+ local device selection/config storage, public error mapping, and Firmware result
7
+ parsing. The `agent-q` local server, Sui provider, and Sui CLI signer use this
8
+ package instead of reimplementing the device/protocol boundary.
9
+
10
+ The core package is not a signing authority and is not a policy authority.
11
+ It does not store signing keys, does not make signing decisions, and does not
12
+ apply policy. Agent-Q Firmware owns keys, policy evaluation, sensitive approval,
13
+ and active policy commits.
14
+
15
+ ## Quick Start
16
+
17
+ Use this package directly when a Node process needs to discover an Agent-Q
18
+ device, open a session, read accounts, and request signatures.
19
+
20
+ ```ts
21
+ import { createDefaultAgentQDeviceClient } from "@stelis/agent-q-core/device";
22
+
23
+ const client = createDefaultAgentQDeviceClient();
24
+
25
+ await client.scanDevices();
26
+ await client.connectDevice({});
27
+
28
+ const accounts = await client.getAccounts({});
29
+
30
+ const result = await client.signTransaction({
31
+ chain: "sui",
32
+ method: "sign_transaction",
33
+ network: "testnet",
34
+ txBytes,
35
+ });
36
+
37
+ await client.disconnectDevice({});
38
+ ```
39
+
40
+ The core request succeeds only when Firmware accepts the state, session,
41
+ route, parameters, policy or device-confirmation gate, and signing operation.
42
+
43
+ ## Common Flow
44
+
45
+ ```text
46
+ scanDevices
47
+ -> identifyDevices?
48
+ -> selectDevice?
49
+ -> connectDevice
50
+ -> getCapabilities
51
+ -> getAccounts
52
+ -> signTransaction or signPersonalMessage
53
+ -> disconnectDevice
54
+ ```
55
+
56
+ Use `getCapabilities` before signing. It reports the device's current signing
57
+ mode and supported signing methods for display and request selection. The
58
+ client cannot choose the device signing mode.
59
+
60
+ ## Entrypoints
61
+
62
+ - `@stelis/agent-q-core` exposes the full `AgentQCore`,
63
+ `createDefaultAgentQCore`, and low-level transport classes used by the
64
+ `agent-q` local server.
65
+ - `@stelis/agent-q-core/device` exposes the limited
66
+ `createDefaultAgentQDeviceClient` facade for provider/app code that should not
67
+ see policy proposal or server management methods.
68
+ - `@stelis/agent-q-core/protocol` exposes the shared protocol builders,
69
+ parsers, constants, and response types.
70
+ - `@stelis/agent-q-core/provider-protocol` exposes the browser-safe provider
71
+ protocol projection used by official dapp-facing adapters. It includes
72
+ provider request builders, an exact provider request serializer, provider
73
+ response parsers, bounded response-line handling, USB identifiers, and fixed
74
+ internal deadline constants; it does not expose Admin, policy read/update,
75
+ approval-history, or full-protocol request serialization.
76
+ - `@stelis/agent-q-core/adapter-internal` exposes support APIs for official
77
+ Agent-Q adapters, including bounded output schemas, public error mapping, safe
78
+ text validation, and the local host device registry. It is not the
79
+ dapp-facing provider API.
80
+
81
+ ## Boundaries
82
+
83
+ - A connection session opens a communication channel between the host process and
84
+ Firmware. It is not signing approval.
85
+ - Session ids are held in host process memory only and are not returned to callers.
86
+ - Labels and purpose names are local host process metadata. They are not Firmware
87
+ policy and are not authorization facts.
88
+ - Policy update proposals are available only through the full core. They are
89
+ not part of the limited device API facade.
90
+ This is API surface separation, not a security barrier against code that
91
+ deliberately imports the full core. Firmware remains responsible for
92
+ validating and approving sensitive writes.
93
+ - Current StackChan CoreS3 capabilities report Sui account identity and no
94
+ delegated signing methods in `chains[].methods`. Signing availability is
95
+ advertised through top-level `signing.authorization` and `signing.methods`,
96
+ and the device API facade exposes `signTransaction` and
97
+ `signPersonalMessage`. The core parser accepts Firmware-authored
98
+ `sign_result` values for transaction policy/user outcomes and user-mode
99
+ personal-message outcomes. It accepts `messageBytes` only for signed
100
+ personal-message results and rejects raw transaction bytes in results, decoded
101
+ internals, session ids, request ids, and secret-like fields.
102
+ - External inputs do not accept caller-controlled timing fields. The host process
103
+ uses fixed internal transport budgets. Firmware-owned device-local approval
104
+ windows remain 30 seconds; the host process waits with a non-configurable transport
105
+ margin so a valid terminal device result can still be received at the end of
106
+ that window.
107
+ - Shared signing calls classify bounded `(type, chain, method)` routes before
108
+ resolving state/session. Sui is currently the only executable chain.
109
+ Method-parameter validation remains after a runtime session exists. Common
110
+ Core validation owns transport bounds and canonical base64 syntax, not the
111
+ current Sui Firmware adapter's decoded-payload capacities.
112
+
113
+ ## Development
114
+
115
+ From the repository root:
116
+
117
+ ```sh
118
+ npm --workspace @stelis/agent-q-core run build
119
+ npm --workspace @stelis/agent-q-core test
120
+ ```
121
+
122
+ Direct USB/Firmware hardware smoke tests live in this package and are opt-in.
123
+ They are skipped unless their `AGENTQ_HW_CLIENT_*` environment gates are set:
124
+
125
+ ```sh
126
+ npm --workspace @stelis/agent-q-core run build
127
+
128
+ AGENTQ_HW_CLIENT_SIGN_TRANSACTION_USER=1 \
129
+ AGENTQ_HW_CLIENT_SIGN_TRANSACTION_USER_SCENARIO=positive \
130
+ AGENTQ_HW_CLIENT_SIGN_TRANSACTION_USER_TX_BYTES=<base64> \
131
+ node --test packages/core/test/hardware-sign-api-smoke.test.mjs
132
+
133
+ AGENTQ_HW_CLIENT_SIGN_TRANSACTION_POLICY=1 \
134
+ AGENTQ_HW_CLIENT_SIGN_TRANSACTION_POLICY_SCENARIO=rejected \
135
+ node --test packages/core/test/hardware-sign-api-smoke.test.mjs
136
+
137
+ AGENTQ_HW_CLIENT_POLICY_UPDATE=1 \
138
+ node --test packages/core/test/hardware-sign-api-smoke.test.mjs
139
+ ```
140
+
141
+ Adapter packages keep their tests focused on adapter projection and public API
142
+ boundaries. Hardware smoke evidence must still record target hardware, commit,
143
+ build/flash command, manual steps, observed result, and unchecked paths before
144
+ implementation status is raised.
@@ -0,0 +1,5 @@
1
+ export { ConfigStore } from "./config.js";
2
+ export { AgentQError, toAgentQError } from "./errors.js";
3
+ export * from "./host-output-schema.js";
4
+ export { PUBLIC_ERROR_MESSAGES, normalizeErrorCode, toPublicError } from "./public-error.js";
5
+ export * from "./safe-text.js";
@@ -0,0 +1,6 @@
1
+ export { ConfigStore } from "./config.js";
2
+ export { AgentQError, toAgentQError } from "./errors.js";
3
+ export * from "./host-output-schema.js";
4
+ export { PUBLIC_ERROR_MESSAGES, normalizeErrorCode, toPublicError } from "./public-error.js";
5
+ export * from "./safe-text.js";
6
+ //# sourceMappingURL=adapter-internal.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adapter-internal.js","sourceRoot":"","sources":["../src/adapter-internal.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACzD,cAAc,yBAAyB,CAAC;AACxC,OAAO,EAAE,qBAAqB,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAC7F,cAAc,gBAAgB,CAAC"}
@@ -0,0 +1,74 @@
1
+ import { type DeviceStatusSnapshot } from "./protocol.js";
2
+ import { MAX_LABEL_LENGTH, PURPOSE_PATTERN, RESERVED_PURPOSES, isValidLabel, isValidPurpose } from "./safe-text.js";
3
+ export declare const CONFIG_SCHEMA_VERSION = 0;
4
+ export { MAX_LABEL_LENGTH, PURPOSE_PATTERN, RESERVED_PURPOSES, isValidLabel, isValidPurpose };
5
+ export interface DeviceRecord {
6
+ deviceId: string;
7
+ transport: "usb";
8
+ lastPortHint: string;
9
+ lastSeenAt: string;
10
+ label: string | null;
11
+ lastStatus: DeviceStatusSnapshot;
12
+ }
13
+ export interface AgentQConfig {
14
+ schemaVersion: typeof CONFIG_SCHEMA_VERSION;
15
+ activeDeviceId: string | null;
16
+ activeDeviceIdsByPurpose: Record<string, string>;
17
+ devices: DeviceRecord[];
18
+ }
19
+ export interface DeviceListing {
20
+ deviceId: string;
21
+ transport: "usb";
22
+ lastPortHint: string;
23
+ lastSeenAt: string;
24
+ label: string | null;
25
+ lastStatus: DeviceStatusSnapshot;
26
+ assignedPurposes: string[];
27
+ isDefaultActive: boolean;
28
+ }
29
+ export interface ConfigPathOptions {
30
+ env?: NodeJS.ProcessEnv;
31
+ homeDir?: string;
32
+ }
33
+ export interface RememberUsbStatusOptions {
34
+ observedAt?: Date;
35
+ setActive?: boolean;
36
+ }
37
+ export interface SetDeviceMetadataInput {
38
+ deviceId: string;
39
+ label?: string | null;
40
+ }
41
+ export interface ConfigValidationError {
42
+ code: string;
43
+ message: string;
44
+ }
45
+ export declare class ConfigError extends Error {
46
+ readonly code: string;
47
+ constructor(code: string, message: string);
48
+ }
49
+ export declare function defaultAgentQConfig(): AgentQConfig;
50
+ export declare function getConfigPath(options?: ConfigPathOptions): string;
51
+ export declare class ConfigStore {
52
+ readonly path: string;
53
+ constructor(path?: string);
54
+ private lastWarnedRaw;
55
+ load(): Promise<AgentQConfig>;
56
+ private writeConfig;
57
+ private maybeWarnNormalized;
58
+ listDevices(): Promise<DeviceListing[]>;
59
+ rememberUsbStatus(status: DeviceStatusSnapshot, portPath: string, options?: RememberUsbStatusOptions): Promise<AgentQConfig>;
60
+ setDeviceMetadata(input: SetDeviceMetadataInput): Promise<DeviceRecord>;
61
+ setActiveDevice(deviceId: string, purpose?: string): Promise<DeviceRecord>;
62
+ getActiveDevice(purpose?: string): Promise<DeviceRecord | undefined>;
63
+ }
64
+ /**
65
+ * Drop routing selections that point at devices not present in `devices`.
66
+ * Writes always validate references, so dangling entries only arise from a
67
+ * hand-edited config. Pruning keeps `list_devices` and purpose routing
68
+ * self-consistent instead of failing later with `device_not_found`.
69
+ *
70
+ * Stable exported shape. Internally this is the report-free view of the
71
+ * pipeline's reference-pruning stage ({@link pruneReferences}); load and write
72
+ * thread a NormalizationReport through that stage instead.
73
+ */
74
+ export declare function normalizeReferences(config: AgentQConfig): AgentQConfig;