@unicity-astrid/sdk 0.1.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 (124) hide show
  1. package/README.md +120 -0
  2. package/dist/approval.d.ts +23 -0
  3. package/dist/approval.d.ts.map +1 -0
  4. package/dist/approval.js +29 -0
  5. package/dist/approval.js.map +1 -0
  6. package/dist/capabilities.d.ts +14 -0
  7. package/dist/capabilities.d.ts.map +1 -0
  8. package/dist/capabilities.js +19 -0
  9. package/dist/capabilities.js.map +1 -0
  10. package/dist/capsule.d.ts +39 -0
  11. package/dist/capsule.d.ts.map +1 -0
  12. package/dist/capsule.js +67 -0
  13. package/dist/capsule.js.map +1 -0
  14. package/dist/contracts.d.ts +1104 -0
  15. package/dist/contracts.d.ts.map +1 -0
  16. package/dist/contracts.js +4 -0
  17. package/dist/contracts.js.map +1 -0
  18. package/dist/elicit.d.ts +30 -0
  19. package/dist/elicit.d.ts.map +1 -0
  20. package/dist/elicit.js +103 -0
  21. package/dist/elicit.js.map +1 -0
  22. package/dist/env.d.ts +19 -0
  23. package/dist/env.d.ts.map +1 -0
  24. package/dist/env.js +27 -0
  25. package/dist/env.js.map +1 -0
  26. package/dist/errors.d.ts +46 -0
  27. package/dist/errors.d.ts.map +1 -0
  28. package/dist/errors.js +108 -0
  29. package/dist/errors.js.map +1 -0
  30. package/dist/fs.d.ts +135 -0
  31. package/dist/fs.d.ts.map +1 -0
  32. package/dist/fs.js +257 -0
  33. package/dist/fs.js.map +1 -0
  34. package/dist/http.d.ts +90 -0
  35. package/dist/http.d.ts.map +1 -0
  36. package/dist/http.js +276 -0
  37. package/dist/http.js.map +1 -0
  38. package/dist/identity.d.ts +46 -0
  39. package/dist/identity.d.ts.map +1 -0
  40. package/dist/identity.js +69 -0
  41. package/dist/identity.js.map +1 -0
  42. package/dist/index.d.ts +30 -0
  43. package/dist/index.d.ts.map +1 -0
  44. package/dist/index.js +27 -0
  45. package/dist/index.js.map +1 -0
  46. package/dist/interceptors.d.ts +21 -0
  47. package/dist/interceptors.d.ts.map +1 -0
  48. package/dist/interceptors.js +22 -0
  49. package/dist/interceptors.js.map +1 -0
  50. package/dist/ipc.d.ts +143 -0
  51. package/dist/ipc.d.ts.map +1 -0
  52. package/dist/ipc.js +261 -0
  53. package/dist/ipc.js.map +1 -0
  54. package/dist/kv.d.ts +45 -0
  55. package/dist/kv.d.ts.map +1 -0
  56. package/dist/kv.js +91 -0
  57. package/dist/kv.js.map +1 -0
  58. package/dist/log.d.ts +17 -0
  59. package/dist/log.d.ts.map +1 -0
  60. package/dist/log.js +40 -0
  61. package/dist/log.js.map +1 -0
  62. package/dist/net.d.ts +154 -0
  63. package/dist/net.d.ts.map +1 -0
  64. package/dist/net.js +421 -0
  65. package/dist/net.js.map +1 -0
  66. package/dist/process.d.ts +77 -0
  67. package/dist/process.d.ts.map +1 -0
  68. package/dist/process.js +128 -0
  69. package/dist/process.js.map +1 -0
  70. package/dist/runtime/bridge.d.ts +34 -0
  71. package/dist/runtime/bridge.d.ts.map +1 -0
  72. package/dist/runtime/bridge.js +326 -0
  73. package/dist/runtime/bridge.js.map +1 -0
  74. package/dist/runtime/index.d.ts +3 -0
  75. package/dist/runtime/index.d.ts.map +1 -0
  76. package/dist/runtime/index.js +3 -0
  77. package/dist/runtime/index.js.map +1 -0
  78. package/dist/runtime/registry.d.ts +58 -0
  79. package/dist/runtime/registry.d.ts.map +1 -0
  80. package/dist/runtime/registry.js +129 -0
  81. package/dist/runtime/registry.js.map +1 -0
  82. package/dist/runtime.d.ts +36 -0
  83. package/dist/runtime.d.ts.map +1 -0
  84. package/dist/runtime.js +50 -0
  85. package/dist/runtime.js.map +1 -0
  86. package/dist/time.d.ts +29 -0
  87. package/dist/time.d.ts.map +1 -0
  88. package/dist/time.js +43 -0
  89. package/dist/time.js.map +1 -0
  90. package/dist/tool.d.ts +48 -0
  91. package/dist/tool.d.ts.map +1 -0
  92. package/dist/tool.js +86 -0
  93. package/dist/tool.js.map +1 -0
  94. package/dist/uplink.d.ts +27 -0
  95. package/dist/uplink.d.ts.map +1 -0
  96. package/dist/uplink.js +36 -0
  97. package/dist/uplink.js.map +1 -0
  98. package/package.json +38 -0
  99. package/src/approval.ts +38 -0
  100. package/src/capabilities.ts +22 -0
  101. package/src/capsule.ts +90 -0
  102. package/src/contracts.ts +1189 -0
  103. package/src/elicit.ts +136 -0
  104. package/src/env.ts +31 -0
  105. package/src/errors.ts +122 -0
  106. package/src/fs.ts +357 -0
  107. package/src/http.ts +345 -0
  108. package/src/identity.ts +101 -0
  109. package/src/index.ts +83 -0
  110. package/src/interceptors.ts +25 -0
  111. package/src/ipc.ts +354 -0
  112. package/src/kv.ts +123 -0
  113. package/src/log.ts +43 -0
  114. package/src/net.ts +545 -0
  115. package/src/process.ts +205 -0
  116. package/src/runtime/bridge.ts +374 -0
  117. package/src/runtime/index.ts +11 -0
  118. package/src/runtime/registry.ts +178 -0
  119. package/src/runtime.ts +70 -0
  120. package/src/time.ts +48 -0
  121. package/src/tool.ts +125 -0
  122. package/src/uplink.ts +49 -0
  123. package/src/wit-imports.d.ts +689 -0
  124. package/wit-contracts/astrid-contracts.wit +1266 -0
@@ -0,0 +1,50 @@
1
+ /**
2
+ * OS runtime introspection + signaling. Mirrors `astrid_sdk::runtime`.
3
+ *
4
+ * Also surfaces {@link randomBytes} (cryptographically secure host entropy
5
+ * via `sys::random-bytes`) for capsules that need an audit-traced CSPRNG —
6
+ * `globalThis.crypto.getRandomValues` works inside StarlingMonkey but
7
+ * bypasses the host audit trail.
8
+ */
9
+ import { getCaller as hostGetCaller, signalReady as hostSignalReady, randomBytes as hostRandomBytes, } from "astrid:sys/host@1.0.0";
10
+ import { SysError, callHost } from "./errors.js";
11
+ import { get as getEnv, CONFIG_SOCKET_PATH } from "./env.js";
12
+ /**
13
+ * Signal that the capsule's run loop is ready. Call after setting up IPC
14
+ * subscriptions inside `@run`; the kernel waits for this before loading
15
+ * dependent capsules.
16
+ */
17
+ export function signalReady() {
18
+ callHost("runtime.signalReady", () => hostSignalReady());
19
+ }
20
+ /** Caller context for the current invocation. */
21
+ export function caller() {
22
+ const ctx = callHost("runtime.caller", () => hostGetCaller());
23
+ return {
24
+ sourceId: ctx.sourceId,
25
+ principal: ctx.principal,
26
+ timestamp: ctx.timestamp,
27
+ };
28
+ }
29
+ /**
30
+ * Fill `length` bytes with cryptographically secure random data from the
31
+ * host's OS-level CSPRNG. Capped at 4096 bytes per call.
32
+ */
33
+ export function randomBytes(length) {
34
+ return callHost(`runtime.randomBytes(${length})`, () => hostRandomBytes(BigInt(length)));
35
+ }
36
+ /**
37
+ * Kernel's Unix domain socket path, injected via the well-known
38
+ * `ASTRID_SOCKET_PATH` config key.
39
+ */
40
+ export function socketPath() {
41
+ const path = getEnv(CONFIG_SOCKET_PATH);
42
+ if (path === "") {
43
+ throw SysError.api("ASTRID_SOCKET_PATH config key is empty");
44
+ }
45
+ if (path.indexOf("\0") >= 0) {
46
+ throw SysError.api("ASTRID_SOCKET_PATH contains null byte");
47
+ }
48
+ return path;
49
+ }
50
+ //# sourceMappingURL=runtime.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runtime.js","sourceRoot":"","sources":["../src/runtime.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EACL,SAAS,IAAI,aAAa,EAC1B,WAAW,IAAI,eAAe,EAC9B,WAAW,IAAI,eAAe,GAC/B,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,EAAE,GAAG,IAAI,MAAM,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAC;AAY7D;;;;GAIG;AACH,MAAM,UAAU,WAAW;IACzB,QAAQ,CAAC,qBAAqB,EAAE,GAAG,EAAE,CAAC,eAAe,EAAE,CAAC,CAAC;AAC3D,CAAC;AAED,iDAAiD;AACjD,MAAM,UAAU,MAAM;IACpB,MAAM,GAAG,GAAG,QAAQ,CAAC,gBAAgB,EAAE,GAAG,EAAE,CAAC,aAAa,EAAE,CAAC,CAAC;IAC9D,OAAO;QACL,QAAQ,EAAE,GAAG,CAAC,QAAQ;QACtB,SAAS,EAAE,GAAG,CAAC,SAAS;QACxB,SAAS,EAAE,GAAG,CAAC,SAAS;KACzB,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,WAAW,CAAC,MAAc;IACxC,OAAO,QAAQ,CAAC,uBAAuB,MAAM,GAAG,EAAE,GAAG,EAAE,CACrD,eAAe,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAChC,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,UAAU;IACxB,MAAM,IAAI,GAAG,MAAM,CAAC,kBAAkB,CAAC,CAAC;IACxC,IAAI,IAAI,KAAK,EAAE,EAAE,CAAC;QAChB,MAAM,QAAQ,CAAC,GAAG,CAAC,wCAAwC,CAAC,CAAC;IAC/D,CAAC;IACD,IAAI,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QAC5B,MAAM,QAAQ,CAAC,GAAG,CAAC,uCAAuC,CAAC,CAAC;IAC9D,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC"}
package/dist/time.d.ts ADDED
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Wall-clock and monotonic time — mirrors `astrid_sdk::time`.
3
+ *
4
+ * The WASM guest has no direct access to the system clock; all time comes
5
+ * through the `sys` host package. {@link now} / {@link nowMs} return wall
6
+ * clock (subject to NTP adjustments); {@link monotonicNs} returns a host
7
+ * monotonic reading suitable for measuring elapsed time within a single
8
+ * capsule lifetime.
9
+ */
10
+ /** Current wall-clock time as a JS `Date`. */
11
+ export declare function now(): Date;
12
+ /** Current wall-clock time as a bigint of milliseconds since UNIX epoch. */
13
+ export declare function nowMs(): bigint;
14
+ /**
15
+ * Current monotonic clock reading in nanoseconds. Suitable for measuring
16
+ * elapsed time; the absolute value is meaningless across processes or capsule
17
+ * reloads — only differences are.
18
+ */
19
+ export declare function monotonicNs(): bigint;
20
+ /**
21
+ * Block the calling task for the given duration in milliseconds.
22
+ *
23
+ * Capped at 60_000 ms (60 s) per call by the host. Throws `cancelled` if
24
+ * the capsule unloads mid-sleep.
25
+ */
26
+ export declare function sleepMs(ms: number): void;
27
+ /** Block for `ns` nanoseconds. See {@link sleepMs} for the practical wrapper. */
28
+ export declare function sleepNs(ns: bigint): void;
29
+ //# sourceMappingURL=time.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"time.d.ts","sourceRoot":"","sources":["../src/time.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAKH,8CAA8C;AAC9C,wBAAgB,GAAG,IAAI,IAAI,CAG1B;AAED,4EAA4E;AAC5E,wBAAgB,KAAK,IAAI,MAAM,CAE9B;AAED;;;;GAIG;AACH,wBAAgB,WAAW,IAAI,MAAM,CAEpC;AAED;;;;;GAKG;AACH,wBAAgB,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAGxC;AAED,iFAAiF;AACjF,wBAAgB,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAExC"}
package/dist/time.js ADDED
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Wall-clock and monotonic time — mirrors `astrid_sdk::time`.
3
+ *
4
+ * The WASM guest has no direct access to the system clock; all time comes
5
+ * through the `sys` host package. {@link now} / {@link nowMs} return wall
6
+ * clock (subject to NTP adjustments); {@link monotonicNs} returns a host
7
+ * monotonic reading suitable for measuring elapsed time within a single
8
+ * capsule lifetime.
9
+ */
10
+ import { clockMs, clockMonotonicNs, sleepNs as hostSleepNs } from "astrid:sys/host@1.0.0";
11
+ import { callHost } from "./errors.js";
12
+ /** Current wall-clock time as a JS `Date`. */
13
+ export function now() {
14
+ const ms = callHost("time.now", () => clockMs());
15
+ return new Date(Number(ms));
16
+ }
17
+ /** Current wall-clock time as a bigint of milliseconds since UNIX epoch. */
18
+ export function nowMs() {
19
+ return callHost("time.nowMs", () => clockMs());
20
+ }
21
+ /**
22
+ * Current monotonic clock reading in nanoseconds. Suitable for measuring
23
+ * elapsed time; the absolute value is meaningless across processes or capsule
24
+ * reloads — only differences are.
25
+ */
26
+ export function monotonicNs() {
27
+ return callHost("time.monotonicNs", () => clockMonotonicNs());
28
+ }
29
+ /**
30
+ * Block the calling task for the given duration in milliseconds.
31
+ *
32
+ * Capped at 60_000 ms (60 s) per call by the host. Throws `cancelled` if
33
+ * the capsule unloads mid-sleep.
34
+ */
35
+ export function sleepMs(ms) {
36
+ const ns = BigInt(Math.max(0, Math.floor(ms))) * 1000000n;
37
+ callHost(`time.sleepMs(${ms})`, () => hostSleepNs(ns));
38
+ }
39
+ /** Block for `ns` nanoseconds. See {@link sleepMs} for the practical wrapper. */
40
+ export function sleepNs(ns) {
41
+ callHost(`time.sleepNs(${ns})`, () => hostSleepNs(ns));
42
+ }
43
+ //# sourceMappingURL=time.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"time.js","sourceRoot":"","sources":["../src/time.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,OAAO,EAAE,gBAAgB,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAC1F,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAEvC,8CAA8C;AAC9C,MAAM,UAAU,GAAG;IACjB,MAAM,EAAE,GAAG,QAAQ,CAAC,UAAU,EAAE,GAAG,EAAE,CAAC,OAAO,EAAE,CAAC,CAAC;IACjD,OAAO,IAAI,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC;AAC9B,CAAC;AAED,4EAA4E;AAC5E,MAAM,UAAU,KAAK;IACnB,OAAO,QAAQ,CAAC,YAAY,EAAE,GAAG,EAAE,CAAC,OAAO,EAAE,CAAC,CAAC;AACjD,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,WAAW;IACzB,OAAO,QAAQ,CAAC,kBAAkB,EAAE,GAAG,EAAE,CAAC,gBAAgB,EAAE,CAAC,CAAC;AAChE,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,OAAO,CAAC,EAAU;IAChC,MAAM,EAAE,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,QAAU,CAAC;IAC5D,QAAQ,CAAC,gBAAgB,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC,CAAC;AACzD,CAAC;AAED,iFAAiF;AACjF,MAAM,UAAU,OAAO,CAAC,EAAU;IAChC,QAAQ,CAAC,gBAAgB,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC,CAAC;AACzD,CAAC"}
package/dist/tool.d.ts ADDED
@@ -0,0 +1,48 @@
1
+ /**
2
+ * `@tool`, `@interceptor`, `@command` method decorators — mirror
3
+ * `#[astrid::tool]`, `#[astrid::interceptor]`, `#[astrid::command]` from the
4
+ * Rust SDK.
5
+ *
6
+ * Unlike Rust, JS has no `&mut self` signal at decoration time, so
7
+ * mutability is opt-in via the options bag. Without `mutable: true`, the
8
+ * bridge will not load or save `__state` around the call.
9
+ */
10
+ export interface ToolOptions {
11
+ /** If true, the bridge auto-loads + auto-persists capsule state via KV `__state`. */
12
+ mutable?: boolean;
13
+ /** Human-readable tool description. If omitted, build-time codegen extracts from TSDoc. */
14
+ description?: string;
15
+ /** Pre-computed JSON Schema. If omitted, build-time codegen derives from TS types. */
16
+ inputSchema?: Record<string, unknown>;
17
+ }
18
+ export interface InterceptorOptions {
19
+ /** Mirror @tool: opt-in state load/save for handlers that mutate `this`. */
20
+ mutable?: boolean;
21
+ }
22
+ export interface CommandOptions {
23
+ mutable?: boolean;
24
+ }
25
+ /**
26
+ * Declares a method as an Astrid tool. The decorator records the tool in
27
+ * the registry; the bridge dispatches `tool_execute_<name>` hook actions
28
+ * to it.
29
+ */
30
+ export declare function tool(name: string, options?: ToolOptions): <This extends object, Args, Result>(_value: (this: This, args: Args) => Result | Promise<Result>, context: ClassMethodDecoratorContext<This, (this: This, args: Args) => Result | Promise<Result>>) => void;
31
+ /**
32
+ * Declares a method as an interceptor on a specific IPC topic. The bridge
33
+ * routes hook-trigger actions named exactly `<topic>` to this method.
34
+ *
35
+ * Topic patterns follow IPC subscription rules (exact match or
36
+ * trailing-suffix wildcard). The kernel pre-registers the subscription
37
+ * when the capsule has both `@run` and `@interceptor` — for purely
38
+ * hook-driven (non-runnable) capsules the kernel dispatches directly.
39
+ */
40
+ export declare function interceptor(topic: string, options?: InterceptorOptions): <This extends object, Payload, Result>(_value: (this: This, payload: Payload) => Result | Promise<Result>, context: ClassMethodDecoratorContext<This, (this: This, payload: Payload) => Result | Promise<Result>>) => void;
41
+ /**
42
+ * Declares a method as an RPC-style command. Commands and interceptors
43
+ * share the same dispatch table on the kernel side — the only difference
44
+ * is intent (commands are invoked directly by name, interceptors fire on
45
+ * topic matches).
46
+ */
47
+ export declare function command(name: string, options?: CommandOptions): <This extends object, Payload, Result>(_value: (this: This, payload: Payload) => Result | Promise<Result>, context: ClassMethodDecoratorContext<This, (this: This, payload: Payload) => Result | Promise<Result>>) => void;
48
+ //# sourceMappingURL=tool.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tool.d.ts","sourceRoot":"","sources":["../src/tool.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AASH,MAAM,WAAW,WAAW;IAC1B,qFAAqF;IACrF,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,2FAA2F;IAC3F,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,sFAAsF;IACtF,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACvC;AAED,MAAM,WAAW,kBAAkB;IACjC,4EAA4E;IAC5E,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,cAAc;IAC7B,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED;;;;GAIG;AACH,wBAAgB,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,WAAgB,IAGzC,IAAI,SAAS,MAAM,EAAE,IAAI,EAAE,MAAM,EAChD,QAAQ,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,KAAK,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,EAC5D,SAAS,2BAA2B,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,KAAK,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,KAC/F,IAAI,CAeR;AAED;;;;;;;;GAQG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,GAAE,kBAAuB,IAGxD,IAAI,SAAS,MAAM,EAAE,OAAO,EAAE,MAAM,EACnD,QAAQ,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,KAAK,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,EAClE,SAAS,2BAA2B,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,KAAK,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,KACrG,IAAI,CAaR;AAED;;;;;GAKG;AACH,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,cAAmB,IAG/C,IAAI,SAAS,MAAM,EAAE,OAAO,EAAE,MAAM,EACnD,QAAQ,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,KAAK,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,EAClE,SAAS,2BAA2B,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,KAAK,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,KACrG,IAAI,CAaR"}
package/dist/tool.js ADDED
@@ -0,0 +1,86 @@
1
+ /**
2
+ * `@tool`, `@interceptor`, `@command` method decorators — mirror
3
+ * `#[astrid::tool]`, `#[astrid::interceptor]`, `#[astrid::command]` from the
4
+ * Rust SDK.
5
+ *
6
+ * Unlike Rust, JS has no `&mut self` signal at decoration time, so
7
+ * mutability is opt-in via the options bag. Without `mutable: true`, the
8
+ * bridge will not load or save `__state` around the call.
9
+ */
10
+ import { recordTool, recordInterceptor, recordCommand, } from "./runtime/registry.js";
11
+ /**
12
+ * Declares a method as an Astrid tool. The decorator records the tool in
13
+ * the registry; the bridge dispatches `tool_execute_<name>` hook actions
14
+ * to it.
15
+ */
16
+ export function tool(name, options = {}) {
17
+ requireName("tool", name);
18
+ return function (_value, context) {
19
+ if (context.private || context.static) {
20
+ throw new Error(`@tool("${name}") must be applied to a public instance method.`);
21
+ }
22
+ context.addInitializer(function () {
23
+ const ctor = this.constructor;
24
+ recordTool(ctor, {
25
+ name,
26
+ methodName: String(context.name),
27
+ mutable: options.mutable === true,
28
+ description: options.description,
29
+ inputSchema: options.inputSchema,
30
+ });
31
+ });
32
+ };
33
+ }
34
+ /**
35
+ * Declares a method as an interceptor on a specific IPC topic. The bridge
36
+ * routes hook-trigger actions named exactly `<topic>` to this method.
37
+ *
38
+ * Topic patterns follow IPC subscription rules (exact match or
39
+ * trailing-suffix wildcard). The kernel pre-registers the subscription
40
+ * when the capsule has both `@run` and `@interceptor` — for purely
41
+ * hook-driven (non-runnable) capsules the kernel dispatches directly.
42
+ */
43
+ export function interceptor(topic, options = {}) {
44
+ requireName("interceptor", topic);
45
+ return function (_value, context) {
46
+ if (context.private || context.static) {
47
+ throw new Error(`@interceptor("${topic}") must be applied to a public instance method.`);
48
+ }
49
+ context.addInitializer(function () {
50
+ const ctor = this.constructor;
51
+ recordInterceptor(ctor, {
52
+ topic,
53
+ methodName: String(context.name),
54
+ mutable: options.mutable === true,
55
+ });
56
+ });
57
+ };
58
+ }
59
+ /**
60
+ * Declares a method as an RPC-style command. Commands and interceptors
61
+ * share the same dispatch table on the kernel side — the only difference
62
+ * is intent (commands are invoked directly by name, interceptors fire on
63
+ * topic matches).
64
+ */
65
+ export function command(name, options = {}) {
66
+ requireName("command", name);
67
+ return function (_value, context) {
68
+ if (context.private || context.static) {
69
+ throw new Error(`@command("${name}") must be applied to a public instance method.`);
70
+ }
71
+ context.addInitializer(function () {
72
+ const ctor = this.constructor;
73
+ recordCommand(ctor, {
74
+ name,
75
+ methodName: String(context.name),
76
+ mutable: options.mutable === true,
77
+ });
78
+ });
79
+ };
80
+ }
81
+ function requireName(kind, name) {
82
+ if (typeof name !== "string" || name.length === 0) {
83
+ throw new Error(`@${kind} requires a non-empty name (got ${JSON.stringify(name)})`);
84
+ }
85
+ }
86
+ //# sourceMappingURL=tool.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tool.js","sourceRoot":"","sources":["../src/tool.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAEL,UAAU,EACV,iBAAiB,EACjB,aAAa,GACd,MAAM,uBAAuB,CAAC;AAoB/B;;;;GAIG;AACH,MAAM,UAAU,IAAI,CAAC,IAAY,EAAE,UAAuB,EAAE;IAC1D,WAAW,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IAE1B,OAAO,UACL,MAA4D,EAC5D,OAAgG;QAEhG,IAAI,OAAO,CAAC,OAAO,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;YACtC,MAAM,IAAI,KAAK,CAAC,UAAU,IAAI,iDAAiD,CAAC,CAAC;QACnF,CAAC;QACD,OAAO,CAAC,cAAc,CAAC;YACrB,MAAM,IAAI,GAAI,IAAe,CAAC,WAAiC,CAAC;YAChE,UAAU,CAAC,IAAI,EAAE;gBACf,IAAI;gBACJ,UAAU,EAAE,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC;gBAChC,OAAO,EAAE,OAAO,CAAC,OAAO,KAAK,IAAI;gBACjC,WAAW,EAAE,OAAO,CAAC,WAAW;gBAChC,WAAW,EAAE,OAAO,CAAC,WAAW;aACjC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;IACL,CAAC,CAAC;AACJ,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,WAAW,CAAC,KAAa,EAAE,UAA8B,EAAE;IACzE,WAAW,CAAC,aAAa,EAAE,KAAK,CAAC,CAAC;IAElC,OAAO,UACL,MAAkE,EAClE,OAAsG;QAEtG,IAAI,OAAO,CAAC,OAAO,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;YACtC,MAAM,IAAI,KAAK,CAAC,iBAAiB,KAAK,iDAAiD,CAAC,CAAC;QAC3F,CAAC;QACD,OAAO,CAAC,cAAc,CAAC;YACrB,MAAM,IAAI,GAAI,IAAe,CAAC,WAAiC,CAAC;YAChE,iBAAiB,CAAC,IAAI,EAAE;gBACtB,KAAK;gBACL,UAAU,EAAE,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC;gBAChC,OAAO,EAAE,OAAO,CAAC,OAAO,KAAK,IAAI;aAClC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;IACL,CAAC,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,OAAO,CAAC,IAAY,EAAE,UAA0B,EAAE;IAChE,WAAW,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;IAE7B,OAAO,UACL,MAAkE,EAClE,OAAsG;QAEtG,IAAI,OAAO,CAAC,OAAO,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;YACtC,MAAM,IAAI,KAAK,CAAC,aAAa,IAAI,iDAAiD,CAAC,CAAC;QACtF,CAAC;QACD,OAAO,CAAC,cAAc,CAAC;YACrB,MAAM,IAAI,GAAI,IAAe,CAAC,WAAiC,CAAC;YAChE,aAAa,CAAC,IAAI,EAAE;gBAClB,IAAI;gBACJ,UAAU,EAAE,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC;gBAChC,OAAO,EAAE,OAAO,CAAC,OAAO,KAAK,IAAI;aAClC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;IACL,CAAC,CAAC;AACJ,CAAC;AAED,SAAS,WAAW,CAAC,IAAY,EAAE,IAAY;IAC7C,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAClD,MAAM,IAAI,KAAK,CAAC,IAAI,IAAI,mCAAmC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACtF,CAAC;AACH,CAAC"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Direct frontend messaging. Mirrors `astrid_sdk::uplink`.
3
+ *
4
+ * Capsules register uplinks (named endpoints) for platforms they bridge —
5
+ * Discord, Slack, Telegram, CLI proxy — and then forward inbound user
6
+ * messages to the kernel's processing pipeline.
7
+ */
8
+ import { type UplinkProfile } from "astrid:uplink/host@1.0.0";
9
+ export type { UplinkProfile } from "astrid:uplink/host@1.0.0";
10
+ export declare class UplinkId {
11
+ readonly value: string;
12
+ constructor(value: string);
13
+ toString(): string;
14
+ }
15
+ /**
16
+ * Register an uplink. `profile` is one of `"chat"` / `"interactive"` /
17
+ * `"notify"` / `"bridge"`. Returns the assigned uplink UUID wrapped in
18
+ * {@link UplinkId}.
19
+ */
20
+ export declare function register(name: string, platform: string, profile: UplinkProfile): UplinkId;
21
+ /**
22
+ * Forward an inbound message through a registered uplink. Returns `true` if
23
+ * sent, `false` if intentionally dropped (e.g. no active session for the
24
+ * principal).
25
+ */
26
+ export declare function send(uplink: UplinkId, platformUserId: string, content: string): boolean;
27
+ //# sourceMappingURL=uplink.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"uplink.d.ts","sourceRoot":"","sources":["../src/uplink.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAGL,KAAK,aAAa,EACnB,MAAM,0BAA0B,CAAC;AAGlC,YAAY,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAE9D,qBAAa,QAAQ;IACnB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;gBACX,KAAK,EAAE,MAAM;IAGzB,QAAQ,IAAI,MAAM;CAGnB;AAED;;;;GAIG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,aAAa,GAAG,QAAQ,CAKzF;AAED;;;;GAIG;AACH,wBAAgB,IAAI,CAAC,MAAM,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAIvF"}
package/dist/uplink.js ADDED
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Direct frontend messaging. Mirrors `astrid_sdk::uplink`.
3
+ *
4
+ * Capsules register uplinks (named endpoints) for platforms they bridge —
5
+ * Discord, Slack, Telegram, CLI proxy — and then forward inbound user
6
+ * messages to the kernel's processing pipeline.
7
+ */
8
+ import { uplinkRegister, uplinkSend, } from "astrid:uplink/host@1.0.0";
9
+ import { callHost } from "./errors.js";
10
+ export class UplinkId {
11
+ value;
12
+ constructor(value) {
13
+ this.value = value;
14
+ }
15
+ toString() {
16
+ return this.value;
17
+ }
18
+ }
19
+ /**
20
+ * Register an uplink. `profile` is one of `"chat"` / `"interactive"` /
21
+ * `"notify"` / `"bridge"`. Returns the assigned uplink UUID wrapped in
22
+ * {@link UplinkId}.
23
+ */
24
+ export function register(name, platform, profile) {
25
+ const id = callHost(`uplink.register(${JSON.stringify(name)})`, () => uplinkRegister(name, platform, profile));
26
+ return new UplinkId(id);
27
+ }
28
+ /**
29
+ * Forward an inbound message through a registered uplink. Returns `true` if
30
+ * sent, `false` if intentionally dropped (e.g. no active session for the
31
+ * principal).
32
+ */
33
+ export function send(uplink, platformUserId, content) {
34
+ return callHost(`uplink.send(${uplink.value})`, () => uplinkSend(uplink.value, platformUserId, content));
35
+ }
36
+ //# sourceMappingURL=uplink.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"uplink.js","sourceRoot":"","sources":["../src/uplink.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EACL,cAAc,EACd,UAAU,GAEX,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAIvC,MAAM,OAAO,QAAQ;IACV,KAAK,CAAS;IACvB,YAAY,KAAa;QACvB,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;IACrB,CAAC;IACD,QAAQ;QACN,OAAO,IAAI,CAAC,KAAK,CAAC;IACpB,CAAC;CACF;AAED;;;;GAIG;AACH,MAAM,UAAU,QAAQ,CAAC,IAAY,EAAE,QAAgB,EAAE,OAAsB;IAC7E,MAAM,EAAE,GAAG,QAAQ,CAAC,mBAAmB,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,CACnE,cAAc,CAAC,IAAI,EAAE,QAAQ,EAAE,OAAO,CAAC,CACxC,CAAC;IACF,OAAO,IAAI,QAAQ,CAAC,EAAE,CAAC,CAAC;AAC1B,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,IAAI,CAAC,MAAgB,EAAE,cAAsB,EAAE,OAAe;IAC5E,OAAO,QAAQ,CAAC,eAAe,MAAM,CAAC,KAAK,GAAG,EAAE,GAAG,EAAE,CACnD,UAAU,CAAC,MAAM,CAAC,KAAK,EAAE,cAAc,EAAE,OAAO,CAAC,CAClD,CAAC;AACJ,CAAC"}
package/package.json ADDED
@@ -0,0 +1,38 @@
1
+ {
2
+ "name": "@unicity-astrid/sdk",
3
+ "version": "0.1.0",
4
+ "description": "System SDK for building user-space capsules for Astrid OS in JavaScript and TypeScript.",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js"
12
+ },
13
+ "./runtime": {
14
+ "types": "./dist/runtime/index.d.ts",
15
+ "import": "./dist/runtime/index.js"
16
+ },
17
+ "./contracts": {
18
+ "types": "./dist/contracts.d.ts",
19
+ "import": "./dist/contracts.js"
20
+ }
21
+ },
22
+ "files": [
23
+ "dist",
24
+ "src",
25
+ "wit-contracts"
26
+ ],
27
+ "scripts": {
28
+ "prebuild": "node scripts/generate-contracts.mjs",
29
+ "build": "tsc -b",
30
+ "clean": "rm -rf dist src/contracts.ts"
31
+ },
32
+ "devDependencies": {
33
+ "@unicity-astrid/build": "*"
34
+ },
35
+ "engines": {
36
+ "node": ">=20"
37
+ }
38
+ }
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Human-in-the-loop approval. Mirrors `astrid_sdk::approval`.
3
+ *
4
+ * The capsule declares the action and target resource. The kernel classifies
5
+ * risk, checks any pre-approved allowances, and either auto-approves or
6
+ * prompts the frontend user. The capsule sees the specific decision class
7
+ * (one-shot / session / always / allowance-hit / denied), not just
8
+ * approved/denied — UI can communicate WHY (e.g. "stored as always-approve")
9
+ * for transparency.
10
+ */
11
+
12
+ import {
13
+ requestApproval as hostRequestApproval,
14
+ type ApprovalDecision,
15
+ } from "astrid:approval/host@1.0.0";
16
+ import { callHost } from "./errors.js";
17
+
18
+ export type { ApprovalDecision } from "astrid:approval/host@1.0.0";
19
+
20
+ /**
21
+ * Request approval for a sensitive action. Returns `true` if approved (any
22
+ * approval variant), `false` if denied. Blocks until the user responds or
23
+ * the request times out (60s).
24
+ *
25
+ * For the specific decision class, use {@link requestDecision}.
26
+ */
27
+ export function request(action: string, resource: string): boolean {
28
+ const decision = requestDecision(action, resource);
29
+ return decision !== "denied";
30
+ }
31
+
32
+ /** Request approval and return the specific decision class. */
33
+ export function requestDecision(action: string, resource: string): ApprovalDecision {
34
+ const resp = callHost(`approval.request(${JSON.stringify(action)})`, () =>
35
+ hostRequestApproval({ action, targetResource: resource }),
36
+ );
37
+ return resp.decision;
38
+ }
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Cross-capsule capability queries. Mirrors `astrid_sdk::capabilities`.
3
+ *
4
+ * Allows a capsule to check whether another capsule (identified by its IPC
5
+ * session UUID) has a specific manifest capability. Used by the prompt
6
+ * builder to enforce `allow_prompt_injection` gating, for example.
7
+ *
8
+ * Fail-closed: returns `false` for unknown UUIDs, unknown capabilities, or
9
+ * registry-unavailable conditions (the host returns `registry-unavailable`,
10
+ * which `callHost` raises as a SysError — capsule code that wants to swallow
11
+ * registry outages should wrap the call).
12
+ */
13
+
14
+ import { checkCapsuleCapability } from "astrid:sys/host@1.0.0";
15
+ import { callHost } from "./errors.js";
16
+
17
+ export function check(sourceUuid: string, capability: string): boolean {
18
+ const resp = callHost(`capabilities.check(${JSON.stringify(capability)})`, () =>
19
+ checkCapsuleCapability({ sourceUuid, capability }),
20
+ );
21
+ return resp.allowed;
22
+ }
package/src/capsule.ts ADDED
@@ -0,0 +1,90 @@
1
+ /**
2
+ * Capsule + lifecycle decorators. Mirrors `#[capsule]` / `#[astrid::install]`
3
+ * / `#[astrid::upgrade]` from the Rust SDK.
4
+ *
5
+ * TypeScript standard decorators (TC39 Stage 3 / TS 5.0+). Class-method
6
+ * decorators are the most stable subset of the spec; we deliberately use
7
+ * only that subset to minimize churn risk.
8
+ */
9
+
10
+ import {
11
+ type CapsuleConstructor,
12
+ registerCapsule,
13
+ recordInstall,
14
+ recordUpgrade,
15
+ recordRun,
16
+ adoptPending,
17
+ } from "./runtime/registry.js";
18
+
19
+ /**
20
+ * Class decorator marking the entry-point of the capsule. The decorated
21
+ * class must have a no-arg constructor (state defaults via field initializers).
22
+ *
23
+ * Exactly one `@capsule` class per compiled WASM module.
24
+ */
25
+ export function capsule<T extends CapsuleConstructor>(
26
+ target: T,
27
+ _context: ClassDecoratorContext<T>,
28
+ ): T {
29
+ registerCapsule(target);
30
+ adoptPending(target);
31
+ return target;
32
+ }
33
+
34
+ /**
35
+ * Method decorator marking the first-time install lifecycle hook. The
36
+ * method receives no arguments and may be async. It runs once before any
37
+ * tool dispatch.
38
+ */
39
+ export function install<This extends object>(
40
+ _value: (this: This) => unknown,
41
+ context: ClassMethodDecoratorContext<This, (this: This) => unknown>,
42
+ ): void {
43
+ if (context.private || context.static) {
44
+ throw new Error("@install must be applied to a public instance method.");
45
+ }
46
+ context.addInitializer(function () {
47
+ const ctor = (this as object).constructor as CapsuleConstructor;
48
+ recordInstall(ctor, String(context.name));
49
+ });
50
+ }
51
+
52
+ /**
53
+ * Method decorator marking the upgrade lifecycle hook. The method receives
54
+ * the previous version string and may be async.
55
+ */
56
+ export function upgrade<This extends object>(
57
+ _value: (this: This, prevVersion: string) => unknown,
58
+ context: ClassMethodDecoratorContext<This, (this: This, prevVersion: string) => unknown>,
59
+ ): void {
60
+ if (context.private || context.static) {
61
+ throw new Error("@upgrade must be applied to a public instance method.");
62
+ }
63
+ context.addInitializer(function () {
64
+ const ctor = (this as object).constructor as CapsuleConstructor;
65
+ recordUpgrade(ctor, String(context.name));
66
+ });
67
+ }
68
+
69
+ /**
70
+ * Method decorator marking the long-running background loop. The method
71
+ * receives no arguments, may be async, and is expected NEVER to return
72
+ * (it is the capsule's daemon loop). Mirror of `#[astrid::run]`.
73
+ *
74
+ * Capsules that declare `@run` are "runnable" capsules: the kernel
75
+ * spawns them as background tasks and the WIT `run` export blocks until
76
+ * the loop exits. Capsules without `@run` are hook-driven and the `run`
77
+ * export is a no-op.
78
+ */
79
+ export function run<This extends object>(
80
+ _value: (this: This) => unknown,
81
+ context: ClassMethodDecoratorContext<This, (this: This) => unknown>,
82
+ ): void {
83
+ if (context.private || context.static) {
84
+ throw new Error("@run must be applied to a public instance method.");
85
+ }
86
+ context.addInitializer(function () {
87
+ const ctor = (this as object).constructor as CapsuleConstructor;
88
+ recordRun(ctor, String(context.name));
89
+ });
90
+ }