@granular-software/sdk 0.2.1 → 0.3.2

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.
@@ -1,4 +1,4 @@
1
- import { T as ToolWithHandler } from '../types-DiMEb3SE.mjs';
1
+ import { T as ToolWithHandler } from '../types-CnX4jXYQ.mjs';
2
2
 
3
3
  /**
4
4
  * Anthropic tool_use block from message response
@@ -1,4 +1,4 @@
1
- import { T as ToolWithHandler } from '../types-DiMEb3SE.js';
1
+ import { T as ToolWithHandler } from '../types-CnX4jXYQ.js';
2
2
 
3
3
  /**
4
4
  * Anthropic tool_use block from message response
@@ -1,5 +1,5 @@
1
1
  import { StructuredTool } from '@langchain/core/tools';
2
- import { T as ToolWithHandler } from '../types-DiMEb3SE.mjs';
2
+ import { T as ToolWithHandler } from '../types-CnX4jXYQ.mjs';
3
3
 
4
4
  /**
5
5
  * Helper to convert LangChain tools to Granular tools.
@@ -1,5 +1,5 @@
1
1
  import { StructuredTool } from '@langchain/core/tools';
2
- import { T as ToolWithHandler } from '../types-DiMEb3SE.js';
2
+ import { T as ToolWithHandler } from '../types-CnX4jXYQ.js';
3
3
 
4
4
  /**
5
5
  * Helper to convert LangChain tools to Granular tools.
@@ -1,5 +1,5 @@
1
1
  import { z } from 'zod';
2
- import { T as ToolWithHandler } from '../types-DiMEb3SE.mjs';
2
+ import { T as ToolWithHandler } from '../types-CnX4jXYQ.mjs';
3
3
 
4
4
  /**
5
5
  * Mastra tool definition interface
@@ -1,5 +1,5 @@
1
1
  import { z } from 'zod';
2
- import { T as ToolWithHandler } from '../types-DiMEb3SE.js';
2
+ import { T as ToolWithHandler } from '../types-CnX4jXYQ.js';
3
3
 
4
4
  /**
5
5
  * Mastra tool definition interface
@@ -1,4 +1,4 @@
1
- import { T as ToolWithHandler } from '../types-DiMEb3SE.mjs';
1
+ import { T as ToolWithHandler } from '../types-CnX4jXYQ.mjs';
2
2
 
3
3
  /**
4
4
  * OpenAI tool call from chat completion response
@@ -1,4 +1,4 @@
1
- import { T as ToolWithHandler } from '../types-DiMEb3SE.js';
1
+ import { T as ToolWithHandler } from '../types-CnX4jXYQ.js';
2
2
 
3
3
  /**
4
4
  * OpenAI tool call from chat completion response
package/dist/cli/index.js CHANGED
@@ -7249,24 +7249,16 @@ function logEffect(name: string, className: string | null, id: string | null, pa
7249
7249
  }
7250
7250
 
7251
7251
  async function main() {
7252
- const apiKey = process.env.GRANULAR_API_KEY;
7253
- if (!apiKey) {
7254
- console.error('[Effects] GRANULAR_API_KEY is required (set in .env.local or environment).');
7252
+ const auth = process.env.GRANULAR_TOKEN ?? process.env.GRANULAR_API_KEY;
7253
+ if (!auth) {
7254
+ console.error('[Effects] Set GRANULAR_API_KEY or GRANULAR_TOKEN (e.g. from simulator "Copy CLI env").');
7255
7255
  process.exit(1);
7256
7256
  }
7257
7257
 
7258
- let WebSocketCtor: any;
7259
- try {
7260
- WebSocketCtor = (await import('ws')).default;
7261
- } catch {
7262
- log('Optional: install "ws" for Node.js WebSocket support. Using global WebSocket.');
7263
- }
7264
-
7265
7258
  log('Initializing client...');
7266
7259
  const granular = new Granular({
7267
- apiKey,
7268
- apiUrl: API_URL,
7269
- ...(WebSocketCtor && { WebSocketCtor }),
7260
+ ...(auth.startsWith('eyJ') ? { token: auth } : { apiKey: auth }),
7261
+ apiUrl: process.env.GRANULAR_API_URL ?? API_URL,
7270
7262
  });
7271
7263
 
7272
7264
  const userId = 'effects_user';
@@ -7335,7 +7327,7 @@ function confirm(question, defaultYes = true) {
7335
7327
  return answer.toLowerCase().startsWith("y");
7336
7328
  });
7337
7329
  }
7338
- async function initCommand(projectName) {
7330
+ async function initCommand(projectName, options) {
7339
7331
  printHeader();
7340
7332
  if (manifestExists()) {
7341
7333
  warn("A granular.json already exists in this directory.");
@@ -7396,7 +7388,7 @@ async function initCommand(projectName) {
7396
7388
  ensureGitignore();
7397
7389
  success("Updated .gitignore");
7398
7390
  console.log();
7399
- const shouldBuild = await confirm("Trigger initial build?", true);
7391
+ const shouldBuild = options?.skipBuild ? false : await confirm("Trigger initial build?", true);
7400
7392
  if (shouldBuild) {
7401
7393
  const building = spinner("Uploading manifest...");
7402
7394
  try {
@@ -8049,7 +8041,7 @@ ${manifest.description}`);
8049
8041
  lines.push(`import { Granular } from '@granular-software/sdk';`);
8050
8042
  lines.push(`
8051
8043
  const granular = new Granular({`);
8052
- lines.push(` apiKey: process.env.GRANULAR_API_KEY!,`);
8044
+ lines.push(` ...(process.env.GRANULAR_TOKEN ? { token: process.env.GRANULAR_TOKEN } : { apiKey: process.env.GRANULAR_API_KEY! }),`);
8053
8045
  lines.push(`});`);
8054
8046
  lines.push(`
8055
8047
  // 1. Record the user (creates or updates identity)`);
@@ -8217,9 +8209,9 @@ async function simulateCommand(sandboxIdArg) {
8217
8209
  var VERSION = "0.2.0";
8218
8210
  var program2 = new Command();
8219
8211
  program2.name("granular").description("Build and deploy AI sandboxes from code").version(VERSION, "-v, --version");
8220
- program2.command("init [project-name]").description("Initialize a new Granular project").action(async (projectName) => {
8212
+ program2.command("init [project-name]").description("Initialize a new Granular project").option("--skip-build", "Skip the initial build step").action(async (projectName, opts) => {
8221
8213
  try {
8222
- await initCommand(projectName);
8214
+ await initCommand(projectName, { skipBuild: opts.skipBuild });
8223
8215
  } catch (err) {
8224
8216
  error(err.message);
8225
8217
  process.exit(1);
package/dist/index.d.mts CHANGED
@@ -1,6 +1,6 @@
1
1
  import * as Automerge from '@automerge/automerge';
2
- import { W as WSClientOptions, T as ToolWithHandler, P as PublishToolsResult, J as Job, a as ToolHandler, I as InstanceToolHandler, b as ToolInfo, c as ToolsChangedEvent, D as DomainState, G as GranularOptions, R as RecordUserOptions, U as User, C as ConnectOptions, E as EnvironmentData, d as GraphQLResult, e as DefineRelationshipOptions, f as RelationshipInfo, M as ModelRef, g as ManifestContent, h as RecordObjectOptions, i as RecordObjectResult, S as SandboxListResponse, j as Sandbox, k as CreateSandboxData, l as DeleteResponse, m as PermissionProfile, n as CreatePermissionProfileData, o as CreateEnvironmentData, p as Subject, A as AssignmentListResponse } from './types-DiMEb3SE.mjs';
3
- export { a1 as APIError, t as Assignment, y as Build, z as BuildListResponse, B as BuildPolicy, x as BuildStatus, u as EnvironmentListResponse, F as JobStatus, H as JobSubmitResult, v as Manifest, $ as ManifestImport, w as ManifestListResponse, _ as ManifestOperation, Y as ManifestPropertySpec, Z as ManifestRelationshipDef, a0 as ManifestVolume, s as PermissionProfileListResponse, r as PermissionRules, K as Prompt, L as RPCRequest, Q as RPCRequestFromServer, N as RPCResponse, O as SyncMessage, V as ToolInvokeParams, X as ToolResultParams, q as ToolSchema } from './types-DiMEb3SE.mjs';
2
+ import { W as WSClientOptions, T as ToolWithHandler, P as PublishToolsResult, J as Job, a as ToolHandler, I as InstanceToolHandler, b as ToolInfo, c as ToolsChangedEvent, D as DomainState, G as GranularOptions, R as RecordUserOptions, U as User, C as ConnectOptions, E as EnvironmentData, d as GraphQLResult, e as DefineRelationshipOptions, f as RelationshipInfo, M as ModelRef, g as ManifestContent, h as RecordObjectOptions, i as RecordObjectResult, S as SandboxListResponse, j as Sandbox, k as CreateSandboxData, l as DeleteResponse, m as PermissionProfile, n as CreatePermissionProfileData, o as CreateEnvironmentData, p as Subject, A as AssignmentListResponse } from './types-CnX4jXYQ.mjs';
3
+ export { a2 as APIError, u as Assignment, z as Build, F as BuildListResponse, B as BuildPolicy, y as BuildStatus, v as EnvironmentListResponse, r as GranularAuth, H as JobStatus, K as JobSubmitResult, w as Manifest, a0 as ManifestImport, x as ManifestListResponse, $ as ManifestOperation, Z as ManifestPropertySpec, _ as ManifestRelationshipDef, a1 as ManifestVolume, t as PermissionProfileListResponse, s as PermissionRules, L as Prompt, N as RPCRequest, V as RPCRequestFromServer, O as RPCResponse, Q as SyncMessage, X as ToolInvokeParams, Y as ToolResultParams, q as ToolSchema } from './types-CnX4jXYQ.mjs';
4
4
  import { Doc } from '@automerge/automerge/slim';
5
5
 
6
6
  declare class WSClient {
@@ -107,6 +107,10 @@ declare class Session {
107
107
  ok: boolean;
108
108
  environmentId?: string;
109
109
  docId?: string;
110
+ graphContainerStatus?: {
111
+ lastKeepAliveAt: number;
112
+ status: 'warming' | 'hot' | 'unknown';
113
+ };
110
114
  }>;
111
115
  /**
112
116
  * Publish tools to the sandbox and register handlers for reverse-RPC.
@@ -245,21 +249,19 @@ declare class Session {
245
249
  */
246
250
  getDomain(): Promise<DomainState>;
247
251
  /**
248
- * Get auto-generated TypeScript class declarations for the current domain.
249
- *
250
- * Returns typed declarations including:
251
- * - Classes with readonly properties (from manifest)
252
- * - `static find(query: { id: string })` for each class
253
- * - Instance methods with typed input/output (from `publishTools` with `className`)
254
- * - Static methods (from `publishTools` with `className` + `static: true`)
255
- * - Relationship accessors (`get_books()`, `get_author()`, etc.)
256
- * - Global tool functions (from `publishTools` without `className`)
257
- *
258
- * Pass this documentation to LLMs so they can write correct typed code
259
- * that imports from `./sandbox-tools`.
260
- *
261
- * Falls back to generating markdown docs from the domain summary if
262
- * the synthesis server is unavailable.
252
+ * Fetch a domain package part from the backend (no fallback).
253
+ */
254
+ private fetchDomainPart;
255
+ /**
256
+ * Get TypeScript class declarations for the current domain (for LLM/code gen).
257
+ */
258
+ getDomainTypes(): Promise<string>;
259
+ /**
260
+ * Get Markdown documentation for the current domain (human-readable).
261
+ */
262
+ getDomainDocs(): Promise<string>;
263
+ /**
264
+ * Get domain documentation for LLMs. Returns types (preferred) or fallback.
263
265
  */
264
266
  getDomainDocumentation(): Promise<string>;
265
267
  /**
@@ -281,7 +283,7 @@ declare class Session {
281
283
  off(event: string, handler: (data: unknown) => void): void;
282
284
  private setupToolInvokeHandler;
283
285
  private setupEventHandlers;
284
- private emit;
286
+ protected emit(event: string, data: unknown): void;
285
287
  /**
286
288
  * Check for changes in the tool catalog and emit 'tools:changed' if needed
287
289
  */
@@ -320,6 +322,39 @@ declare class Environment extends Session {
320
322
  get permissionProfileId(): string;
321
323
  /** The GraphQL API endpoint URL */
322
324
  get apiEndpoint(): string;
325
+ /** The last known graph container status, updated by checkReadiness() or on heartbeat */
326
+ graphContainerStatus: {
327
+ lastKeepAliveAt: number;
328
+ status: 'warming' | 'hot' | 'unknown';
329
+ } | null;
330
+ /**
331
+ * Check if the graph container is ready and warm.
332
+ *
333
+ * Sends a lightweight heartbeat RPC to the Session DO which internally
334
+ * pings the FalkorDB container. The response includes `graphContainerStatus`,
335
+ * which is stored locally and emitted as a `readiness` event.
336
+ *
337
+ * Use this method to proactively warm the graph container before any
338
+ * GraphQL query that requires it, or to poll the container's state in
339
+ * the background.
340
+ *
341
+ * @returns The current graph container status object
342
+ *
343
+ * @example
344
+ * ```typescript
345
+ * const status = await env.checkReadiness();
346
+ * console.log(status.status); // 'hot' | 'warming' | 'unknown'
347
+ *
348
+ * // Or listen for live updates
349
+ * env.on('readiness', (status) => {
350
+ * console.log('Graph is now:', status.status);
351
+ * });
352
+ * ```
353
+ */
354
+ checkReadiness(): Promise<{
355
+ lastKeepAliveAt: number;
356
+ status: 'warming' | 'hot' | 'unknown';
357
+ }>;
323
358
  /**
324
359
  * Convert a class name + real-world ID into a unique graph path.
325
360
  *
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import * as Automerge from '@automerge/automerge';
2
- import { W as WSClientOptions, T as ToolWithHandler, P as PublishToolsResult, J as Job, a as ToolHandler, I as InstanceToolHandler, b as ToolInfo, c as ToolsChangedEvent, D as DomainState, G as GranularOptions, R as RecordUserOptions, U as User, C as ConnectOptions, E as EnvironmentData, d as GraphQLResult, e as DefineRelationshipOptions, f as RelationshipInfo, M as ModelRef, g as ManifestContent, h as RecordObjectOptions, i as RecordObjectResult, S as SandboxListResponse, j as Sandbox, k as CreateSandboxData, l as DeleteResponse, m as PermissionProfile, n as CreatePermissionProfileData, o as CreateEnvironmentData, p as Subject, A as AssignmentListResponse } from './types-DiMEb3SE.js';
3
- export { a1 as APIError, t as Assignment, y as Build, z as BuildListResponse, B as BuildPolicy, x as BuildStatus, u as EnvironmentListResponse, F as JobStatus, H as JobSubmitResult, v as Manifest, $ as ManifestImport, w as ManifestListResponse, _ as ManifestOperation, Y as ManifestPropertySpec, Z as ManifestRelationshipDef, a0 as ManifestVolume, s as PermissionProfileListResponse, r as PermissionRules, K as Prompt, L as RPCRequest, Q as RPCRequestFromServer, N as RPCResponse, O as SyncMessage, V as ToolInvokeParams, X as ToolResultParams, q as ToolSchema } from './types-DiMEb3SE.js';
2
+ import { W as WSClientOptions, T as ToolWithHandler, P as PublishToolsResult, J as Job, a as ToolHandler, I as InstanceToolHandler, b as ToolInfo, c as ToolsChangedEvent, D as DomainState, G as GranularOptions, R as RecordUserOptions, U as User, C as ConnectOptions, E as EnvironmentData, d as GraphQLResult, e as DefineRelationshipOptions, f as RelationshipInfo, M as ModelRef, g as ManifestContent, h as RecordObjectOptions, i as RecordObjectResult, S as SandboxListResponse, j as Sandbox, k as CreateSandboxData, l as DeleteResponse, m as PermissionProfile, n as CreatePermissionProfileData, o as CreateEnvironmentData, p as Subject, A as AssignmentListResponse } from './types-CnX4jXYQ.js';
3
+ export { a2 as APIError, u as Assignment, z as Build, F as BuildListResponse, B as BuildPolicy, y as BuildStatus, v as EnvironmentListResponse, r as GranularAuth, H as JobStatus, K as JobSubmitResult, w as Manifest, a0 as ManifestImport, x as ManifestListResponse, $ as ManifestOperation, Z as ManifestPropertySpec, _ as ManifestRelationshipDef, a1 as ManifestVolume, t as PermissionProfileListResponse, s as PermissionRules, L as Prompt, N as RPCRequest, V as RPCRequestFromServer, O as RPCResponse, Q as SyncMessage, X as ToolInvokeParams, Y as ToolResultParams, q as ToolSchema } from './types-CnX4jXYQ.js';
4
4
  import { Doc } from '@automerge/automerge/slim';
5
5
 
6
6
  declare class WSClient {
@@ -107,6 +107,10 @@ declare class Session {
107
107
  ok: boolean;
108
108
  environmentId?: string;
109
109
  docId?: string;
110
+ graphContainerStatus?: {
111
+ lastKeepAliveAt: number;
112
+ status: 'warming' | 'hot' | 'unknown';
113
+ };
110
114
  }>;
111
115
  /**
112
116
  * Publish tools to the sandbox and register handlers for reverse-RPC.
@@ -245,21 +249,19 @@ declare class Session {
245
249
  */
246
250
  getDomain(): Promise<DomainState>;
247
251
  /**
248
- * Get auto-generated TypeScript class declarations for the current domain.
249
- *
250
- * Returns typed declarations including:
251
- * - Classes with readonly properties (from manifest)
252
- * - `static find(query: { id: string })` for each class
253
- * - Instance methods with typed input/output (from `publishTools` with `className`)
254
- * - Static methods (from `publishTools` with `className` + `static: true`)
255
- * - Relationship accessors (`get_books()`, `get_author()`, etc.)
256
- * - Global tool functions (from `publishTools` without `className`)
257
- *
258
- * Pass this documentation to LLMs so they can write correct typed code
259
- * that imports from `./sandbox-tools`.
260
- *
261
- * Falls back to generating markdown docs from the domain summary if
262
- * the synthesis server is unavailable.
252
+ * Fetch a domain package part from the backend (no fallback).
253
+ */
254
+ private fetchDomainPart;
255
+ /**
256
+ * Get TypeScript class declarations for the current domain (for LLM/code gen).
257
+ */
258
+ getDomainTypes(): Promise<string>;
259
+ /**
260
+ * Get Markdown documentation for the current domain (human-readable).
261
+ */
262
+ getDomainDocs(): Promise<string>;
263
+ /**
264
+ * Get domain documentation for LLMs. Returns types (preferred) or fallback.
263
265
  */
264
266
  getDomainDocumentation(): Promise<string>;
265
267
  /**
@@ -281,7 +283,7 @@ declare class Session {
281
283
  off(event: string, handler: (data: unknown) => void): void;
282
284
  private setupToolInvokeHandler;
283
285
  private setupEventHandlers;
284
- private emit;
286
+ protected emit(event: string, data: unknown): void;
285
287
  /**
286
288
  * Check for changes in the tool catalog and emit 'tools:changed' if needed
287
289
  */
@@ -320,6 +322,39 @@ declare class Environment extends Session {
320
322
  get permissionProfileId(): string;
321
323
  /** The GraphQL API endpoint URL */
322
324
  get apiEndpoint(): string;
325
+ /** The last known graph container status, updated by checkReadiness() or on heartbeat */
326
+ graphContainerStatus: {
327
+ lastKeepAliveAt: number;
328
+ status: 'warming' | 'hot' | 'unknown';
329
+ } | null;
330
+ /**
331
+ * Check if the graph container is ready and warm.
332
+ *
333
+ * Sends a lightweight heartbeat RPC to the Session DO which internally
334
+ * pings the FalkorDB container. The response includes `graphContainerStatus`,
335
+ * which is stored locally and emitted as a `readiness` event.
336
+ *
337
+ * Use this method to proactively warm the graph container before any
338
+ * GraphQL query that requires it, or to poll the container's state in
339
+ * the background.
340
+ *
341
+ * @returns The current graph container status object
342
+ *
343
+ * @example
344
+ * ```typescript
345
+ * const status = await env.checkReadiness();
346
+ * console.log(status.status); // 'hot' | 'warming' | 'unknown'
347
+ *
348
+ * // Or listen for live updates
349
+ * env.on('readiness', (status) => {
350
+ * console.log('Graph is now:', status.status);
351
+ * });
352
+ * ```
353
+ */
354
+ checkReadiness(): Promise<{
355
+ lastKeepAliveAt: number;
356
+ status: 'warming' | 'hot' | 'unknown';
357
+ }>;
323
358
  /**
324
359
  * Convert a class name + real-world ID into a unique graph path.
325
360
  *