@arke-institute/klados-testing 0.1.3 → 0.3.1

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.
@@ -33,12 +33,19 @@ export declare function deleteEntity(id: string): Promise<void>;
33
33
  * Create a new collection
34
34
  *
35
35
  * Uses POST /collections to get proper owner permissions.
36
+ * By default, collections include standard roles with public *:view access.
36
37
  *
37
38
  * @example
38
39
  * ```typescript
40
+ * // Minimal - gets default roles
39
41
  * const collection = await createCollection({
40
42
  * label: 'Test Collection',
41
- * allowedTypes: ['document'],
43
+ * });
44
+ *
45
+ * // Agent-accessible collection
46
+ * const agentCollection = await createCollection({
47
+ * label: 'Agent Collection',
48
+ * roles: { public: ['*:view', '*:invoke'] }
42
49
  * });
43
50
  * ```
44
51
  */
@@ -1 +1 @@
1
- {"version":3,"file":"entities.d.ts","sourceRoot":"","sources":["../src/entities.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,KAAK,EACV,MAAM,EACN,UAAU,EACV,kBAAkB,EAClB,mBAAmB,EACnB,uBAAuB,EACxB,MAAM,YAAY,CAAC;AAEpB;;;;;;;;;;;GAWG;AACH,wBAAsB,YAAY,CAAC,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,MAAM,CAAC,CAWhF;AAED;;;;GAIG;AACH,wBAAsB,SAAS,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAE3D;AAED;;;;;;GAMG;AACH,wBAAsB,YAAY,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAQ5D;AAED;;;;;;;;;;;;GAYG;AACH,wBAAsB,gBAAgB,CACpC,OAAO,EAAE,uBAAuB,GAC/B,OAAO,CAAC,UAAU,CAAC,CAMrB;AAED;;;;;;;GAOG;AACH,wBAAsB,qBAAqB,CACzC,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC,kBAAkB,CAAC,CAK7B"}
1
+ {"version":3,"file":"entities.d.ts","sourceRoot":"","sources":["../src/entities.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,KAAK,EACV,MAAM,EACN,UAAU,EACV,kBAAkB,EAClB,mBAAmB,EACnB,uBAAuB,EACxB,MAAM,YAAY,CAAC;AAEpB;;;;;;;;;;;GAWG;AACH,wBAAsB,YAAY,CAAC,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,MAAM,CAAC,CAWhF;AAED;;;;GAIG;AACH,wBAAsB,SAAS,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAE3D;AAED;;;;;;GAMG;AACH,wBAAsB,YAAY,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAQ5D;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAsB,gBAAgB,CACpC,OAAO,EAAE,uBAAuB,GAC/B,OAAO,CAAC,UAAU,CAAC,CAQrB;AAED;;;;;;;GAOG;AACH,wBAAsB,qBAAqB,CACzC,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC,kBAAkB,CAAC,CAK7B"}
package/dist/entities.js CHANGED
@@ -51,12 +51,19 @@ export async function deleteEntity(id) {
51
51
  * Create a new collection
52
52
  *
53
53
  * Uses POST /collections to get proper owner permissions.
54
+ * By default, collections include standard roles with public *:view access.
54
55
  *
55
56
  * @example
56
57
  * ```typescript
58
+ * // Minimal - gets default roles
57
59
  * const collection = await createCollection({
58
60
  * label: 'Test Collection',
59
- * allowedTypes: ['document'],
61
+ * });
62
+ *
63
+ * // Agent-accessible collection
64
+ * const agentCollection = await createCollection({
65
+ * label: 'Agent Collection',
66
+ * roles: { public: ['*:view', '*:invoke'] }
60
67
  * });
61
68
  * ```
62
69
  */
@@ -65,6 +72,8 @@ export async function createCollection(options) {
65
72
  label: options.label,
66
73
  description: options.description,
67
74
  allowed_types: options.allowedTypes,
75
+ roles: options.roles,
76
+ use_roles_default: options.useRolesDefault,
68
77
  });
69
78
  }
70
79
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"entities.js","sourceRoot":"","sources":["../src/entities.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AASzC;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,OAA4B;IAC7D,MAAM,IAAI,GAA4B;QACpC,IAAI,EAAE,OAAO,CAAC,IAAI;QAClB,UAAU,EAAE,OAAO,CAAC,UAAU;KAC/B,CAAC;IAEF,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC;QACzB,IAAI,CAAC,UAAU,GAAG,OAAO,CAAC,YAAY,CAAC;IACzC,CAAC;IAED,OAAO,UAAU,CAAS,MAAM,EAAE,WAAW,EAAE,IAAI,CAAC,CAAC;AACvD,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,EAAU;IACxC,OAAO,UAAU,CAAS,KAAK,EAAE,aAAa,EAAE,EAAE,CAAC,CAAC;AACtD,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,EAAU;IAC3C,0BAA0B;IAC1B,MAAM,GAAG,GAAG,MAAM,UAAU,CAAkB,KAAK,EAAE,aAAa,EAAE,MAAM,CAAC,CAAC;IAE5E,yBAAyB;IACzB,MAAM,UAAU,CAAC,QAAQ,EAAE,aAAa,EAAE,EAAE,EAAE;QAC5C,UAAU,EAAE,GAAG,CAAC,GAAG;KACpB,CAAC,CAAC;AACL,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,OAAgC;IAEhC,OAAO,UAAU,CAAa,MAAM,EAAE,cAAc,EAAE;QACpD,KAAK,EAAE,OAAO,CAAC,KAAK;QACpB,WAAW,EAAE,OAAO,CAAC,WAAW;QAChC,aAAa,EAAE,OAAO,CAAC,YAAY;KACpC,CAAC,CAAC;AACL,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,qBAAqB,CACzC,YAAoB;IAEpB,OAAO,UAAU,CACf,KAAK,EACL,gBAAgB,YAAY,WAAW,CACxC,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"entities.js","sourceRoot":"","sources":["../src/entities.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AASzC;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,OAA4B;IAC7D,MAAM,IAAI,GAA4B;QACpC,IAAI,EAAE,OAAO,CAAC,IAAI;QAClB,UAAU,EAAE,OAAO,CAAC,UAAU;KAC/B,CAAC;IAEF,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC;QACzB,IAAI,CAAC,UAAU,GAAG,OAAO,CAAC,YAAY,CAAC;IACzC,CAAC;IAED,OAAO,UAAU,CAAS,MAAM,EAAE,WAAW,EAAE,IAAI,CAAC,CAAC;AACvD,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,EAAU;IACxC,OAAO,UAAU,CAAS,KAAK,EAAE,aAAa,EAAE,EAAE,CAAC,CAAC;AACtD,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,EAAU;IAC3C,0BAA0B;IAC1B,MAAM,GAAG,GAAG,MAAM,UAAU,CAAkB,KAAK,EAAE,aAAa,EAAE,MAAM,CAAC,CAAC;IAE5E,yBAAyB;IACzB,MAAM,UAAU,CAAC,QAAQ,EAAE,aAAa,EAAE,EAAE,EAAE;QAC5C,UAAU,EAAE,GAAG,CAAC,GAAG;KACpB,CAAC,CAAC;AACL,CAAC;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,OAAgC;IAEhC,OAAO,UAAU,CAAa,MAAM,EAAE,cAAc,EAAE;QACpD,KAAK,EAAE,OAAO,CAAC,KAAK;QACpB,WAAW,EAAE,OAAO,CAAC,WAAW;QAChC,aAAa,EAAE,OAAO,CAAC,YAAY;QACnC,KAAK,EAAE,OAAO,CAAC,KAAK;QACpB,iBAAiB,EAAE,OAAO,CAAC,eAAe;KAC3C,CAAC,CAAC;AACL,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,qBAAqB,CACzC,YAAoB;IAEpB,OAAO,UAAU,CACf,KAAK,EACL,gBAAgB,YAAY,WAAW,CACxC,CAAC;AACJ,CAAC"}
package/dist/index.d.ts CHANGED
@@ -53,8 +53,10 @@
53
53
  */
54
54
  export { configureTestClient, getConfig, resetTestClient, apiRequest, sleep, log } from './client.js';
55
55
  export { createEntity, getEntity, deleteEntity, createCollection, getCollectionEntities } from './entities.js';
56
- export { getKladosLog, getFirstLogFromCollection, waitForKladosLog, getLogMessages, getLogEntry } from './logs.js';
56
+ export { getKladosLog, getFirstLogFromCollection, waitForKladosLog, getLogMessages, getLogEntry, getLogChildren, buildWorkflowTree, waitForWorkflowTree, } from './logs.js';
57
57
  export { invokeKlados } from './invoke.js';
58
+ export { invokeRhiza, createRhiza, getWorkflowLogs, waitForWorkflowCompletion, assertWorkflowCompleted, assertWorkflowPath, } from './workflows.js';
58
59
  export { assertLogCompleted, assertLogFailed, assertLogHasMessages, assertLogMessageCount, assertLogHasHandoff, } from './assertions.js';
59
- export type { TestConfig, Entity, Collection, CollectionEntities, InvokeResult, LogMessage, KladosLogEntry, CreateEntityOptions, CreateCollectionOptions, InvokeKladosOptions, WaitForLogOptions, LogMessageCriteria, } from './types.js';
60
+ export type { TestConfig, Entity, Collection, CollectionEntities, InvokeResult, LogMessage, KladosLogEntry, CreateEntityOptions, CreateCollectionOptions, InvokeKladosOptions, WaitForLogOptions, LogMessageCriteria, LogTreeNode, WorkflowLogTree, WaitForWorkflowTreeOptions, } from './types.js';
61
+ export type { InvokeRhizaOptions, InvokeRhizaResult, WorkflowCompletionResult, CreateRhizaOptions, FlowStep, ThenSpec, } from './workflows.js';
60
62
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoDG;AAGH,OAAO,EAAE,mBAAmB,EAAE,SAAS,EAAE,eAAe,EAAE,UAAU,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,aAAa,CAAC;AAGtG,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,YAAY,EAAE,gBAAgB,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AAG/G,OAAO,EAAE,YAAY,EAAE,yBAAyB,EAAE,gBAAgB,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAGnH,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAG3C,OAAO,EACL,kBAAkB,EAClB,eAAe,EACf,oBAAoB,EACpB,qBAAqB,EACrB,mBAAmB,GACpB,MAAM,iBAAiB,CAAC;AAGzB,YAAY,EACV,UAAU,EACV,MAAM,EACN,UAAU,EACV,kBAAkB,EAClB,YAAY,EACZ,UAAU,EACV,cAAc,EACd,mBAAmB,EACnB,uBAAuB,EACvB,mBAAmB,EACnB,iBAAiB,EACjB,kBAAkB,GACnB,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoDG;AAGH,OAAO,EAAE,mBAAmB,EAAE,SAAS,EAAE,eAAe,EAAE,UAAU,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,aAAa,CAAC;AAGtG,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,YAAY,EAAE,gBAAgB,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AAG/G,OAAO,EACL,YAAY,EACZ,yBAAyB,EACzB,gBAAgB,EAChB,cAAc,EACd,WAAW,EAEX,cAAc,EACd,iBAAiB,EACjB,mBAAmB,GACpB,MAAM,WAAW,CAAC;AAGnB,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAG3C,OAAO,EACL,WAAW,EACX,WAAW,EACX,eAAe,EACf,yBAAyB,EACzB,uBAAuB,EACvB,kBAAkB,GACnB,MAAM,gBAAgB,CAAC;AAGxB,OAAO,EACL,kBAAkB,EAClB,eAAe,EACf,oBAAoB,EACpB,qBAAqB,EACrB,mBAAmB,GACpB,MAAM,iBAAiB,CAAC;AAGzB,YAAY,EACV,UAAU,EACV,MAAM,EACN,UAAU,EACV,kBAAkB,EAClB,YAAY,EACZ,UAAU,EACV,cAAc,EACd,mBAAmB,EACnB,uBAAuB,EACvB,mBAAmB,EACnB,iBAAiB,EACjB,kBAAkB,EAElB,WAAW,EACX,eAAe,EACf,0BAA0B,GAC3B,MAAM,YAAY,CAAC;AAGpB,YAAY,EACV,kBAAkB,EAClB,iBAAiB,EACjB,wBAAwB,EACxB,kBAAkB,EAClB,QAAQ,EACR,QAAQ,GACT,MAAM,gBAAgB,CAAC"}
package/dist/index.js CHANGED
@@ -56,9 +56,13 @@ export { configureTestClient, getConfig, resetTestClient, apiRequest, sleep, log
56
56
  // Entity operations
57
57
  export { createEntity, getEntity, deleteEntity, createCollection, getCollectionEntities } from './entities.js';
58
58
  // Log utilities
59
- export { getKladosLog, getFirstLogFromCollection, waitForKladosLog, getLogMessages, getLogEntry } from './logs.js';
59
+ export { getKladosLog, getFirstLogFromCollection, waitForKladosLog, getLogMessages, getLogEntry,
60
+ // Tree-based traversal
61
+ getLogChildren, buildWorkflowTree, waitForWorkflowTree, } from './logs.js';
60
62
  // Klados invocation
61
63
  export { invokeKlados } from './invoke.js';
64
+ // Workflow utilities
65
+ export { invokeRhiza, createRhiza, getWorkflowLogs, waitForWorkflowCompletion, assertWorkflowCompleted, assertWorkflowPath, } from './workflows.js';
62
66
  // Assertions
63
67
  export { assertLogCompleted, assertLogFailed, assertLogHasMessages, assertLogMessageCount, assertLogHasHandoff, } from './assertions.js';
64
68
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoDG;AAEH,gBAAgB;AAChB,OAAO,EAAE,mBAAmB,EAAE,SAAS,EAAE,eAAe,EAAE,UAAU,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,aAAa,CAAC;AAEtG,oBAAoB;AACpB,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,YAAY,EAAE,gBAAgB,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AAE/G,gBAAgB;AAChB,OAAO,EAAE,YAAY,EAAE,yBAAyB,EAAE,gBAAgB,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAEnH,oBAAoB;AACpB,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,aAAa;AACb,OAAO,EACL,kBAAkB,EAClB,eAAe,EACf,oBAAoB,EACpB,qBAAqB,EACrB,mBAAmB,GACpB,MAAM,iBAAiB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoDG;AAEH,gBAAgB;AAChB,OAAO,EAAE,mBAAmB,EAAE,SAAS,EAAE,eAAe,EAAE,UAAU,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,aAAa,CAAC;AAEtG,oBAAoB;AACpB,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,YAAY,EAAE,gBAAgB,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AAE/G,gBAAgB;AAChB,OAAO,EACL,YAAY,EACZ,yBAAyB,EACzB,gBAAgB,EAChB,cAAc,EACd,WAAW;AACX,uBAAuB;AACvB,cAAc,EACd,iBAAiB,EACjB,mBAAmB,GACpB,MAAM,WAAW,CAAC;AAEnB,oBAAoB;AACpB,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,qBAAqB;AACrB,OAAO,EACL,WAAW,EACX,WAAW,EACX,eAAe,EACf,yBAAyB,EACzB,uBAAuB,EACvB,kBAAkB,GACnB,MAAM,gBAAgB,CAAC;AAExB,aAAa;AACb,OAAO,EACL,kBAAkB,EAClB,eAAe,EACf,oBAAoB,EACpB,qBAAqB,EACrB,mBAAmB,GACpB,MAAM,iBAAiB,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"invoke.d.ts","sourceRoot":"","sources":["../src/invoke.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAEpE;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAsB,YAAY,CAChC,OAAO,EAAE,mBAAmB,GAC3B,OAAO,CAAC,YAAY,CAAC,CAwBvB"}
1
+ {"version":3,"file":"invoke.d.ts","sourceRoot":"","sources":["../src/invoke.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAEpE;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAsB,YAAY,CAChC,OAAO,EAAE,mBAAmB,GAC3B,OAAO,CAAC,YAAY,CAAC,CA2BvB"}
package/dist/invoke.js CHANGED
@@ -26,9 +26,11 @@ import { apiRequest } from './client.js';
26
26
  export async function invokeKlados(options) {
27
27
  const body = {
28
28
  target_collection: options.targetCollection,
29
- job_collection: options.jobCollection,
30
29
  confirm: options.confirm ?? true,
31
30
  };
31
+ if (options.jobCollection) {
32
+ body.job_collection = options.jobCollection;
33
+ }
32
34
  if (options.targetEntity) {
33
35
  body.target_entity = options.targetEntity;
34
36
  }
@@ -1 +1 @@
1
- {"version":3,"file":"invoke.js","sourceRoot":"","sources":["../src/invoke.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAGzC;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,OAA4B;IAE5B,MAAM,IAAI,GAA4B;QACpC,iBAAiB,EAAE,OAAO,CAAC,gBAAgB;QAC3C,cAAc,EAAE,OAAO,CAAC,aAAa;QACrC,OAAO,EAAE,OAAO,CAAC,OAAO,IAAI,IAAI;KACjC,CAAC;IAEF,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC;QACzB,IAAI,CAAC,aAAa,GAAG,OAAO,CAAC,YAAY,CAAC;IAC5C,CAAC;IAED,IAAI,OAAO,CAAC,cAAc,EAAE,CAAC;QAC3B,IAAI,CAAC,eAAe,GAAG,OAAO,CAAC,cAAc,CAAC;IAChD,CAAC;IAED,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;QAClB,IAAI,CAAC,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC;IAC7B,CAAC;IAED,OAAO,UAAU,CACf,MAAM,EACN,WAAW,OAAO,CAAC,QAAQ,SAAS,EACpC,IAAI,CACL,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"invoke.js","sourceRoot":"","sources":["../src/invoke.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAGzC;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,OAA4B;IAE5B,MAAM,IAAI,GAA4B;QACpC,iBAAiB,EAAE,OAAO,CAAC,gBAAgB;QAC3C,OAAO,EAAE,OAAO,CAAC,OAAO,IAAI,IAAI;KACjC,CAAC;IAEF,IAAI,OAAO,CAAC,aAAa,EAAE,CAAC;QAC1B,IAAI,CAAC,cAAc,GAAG,OAAO,CAAC,aAAa,CAAC;IAC9C,CAAC;IAED,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC;QACzB,IAAI,CAAC,aAAa,GAAG,OAAO,CAAC,YAAY,CAAC;IAC5C,CAAC;IAED,IAAI,OAAO,CAAC,cAAc,EAAE,CAAC;QAC3B,IAAI,CAAC,eAAe,GAAG,OAAO,CAAC,cAAc,CAAC;IAChD,CAAC;IAED,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;QAClB,IAAI,CAAC,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC;IAC7B,CAAC;IAED,OAAO,UAAU,CACf,MAAM,EACN,WAAW,OAAO,CAAC,QAAQ,SAAS,EACpC,IAAI,CACL,CAAC;AACJ,CAAC"}
package/dist/logs.d.ts CHANGED
@@ -1,7 +1,9 @@
1
1
  /**
2
2
  * Klados log utilities for testing
3
+ *
4
+ * Includes tree-based traversal for multi-step workflows and scatter/gather operations.
3
5
  */
4
- import type { KladosLogEntry, WaitForLogOptions } from './types.js';
6
+ import type { KladosLogEntry, WaitForLogOptions, WorkflowLogTree, WaitForWorkflowTreeOptions } from './types.js';
5
7
  /**
6
8
  * Get a klados log entry by ID
7
9
  *
@@ -75,9 +77,21 @@ export declare function getLogEntry(log: KladosLogEntry): {
75
77
  };
76
78
  handoffs?: Array<{
77
79
  target: string;
78
- type: "invoke" | "scatter" | "complete" | "error" | "none";
80
+ type: "invoke" | "pass" | "scatter" | "gather" | "complete" | "error" | "none";
79
81
  job_id?: string;
80
82
  error?: string;
83
+ outputs?: string[];
84
+ invocations
85
+ /**
86
+ * Result of getting log children
87
+ */
88
+ ?: Array<{
89
+ target: string;
90
+ request?: Record<string, unknown>;
91
+ }>;
92
+ delegated?: boolean;
93
+ dispatch_id?: string;
94
+ done_slots?: number;
81
95
  }>;
82
96
  error?: {
83
97
  code: string;
@@ -85,4 +99,87 @@ export declare function getLogEntry(log: KladosLogEntry): {
85
99
  retryable: boolean;
86
100
  };
87
101
  };
102
+ /**
103
+ * Result of getting log children
104
+ */
105
+ interface LogChildrenResult {
106
+ /** Array of child log entity IDs */
107
+ childIds: string[];
108
+ /** Total count of sent_to relationships (may be more than childIds if some don't exist yet) */
109
+ sentToCount: number;
110
+ }
111
+ /**
112
+ * Get children of a log by querying for outgoing sent_to relationships
113
+ *
114
+ * In the Rhiza log tree:
115
+ * - Parents have `sent_to` outgoing relationships pointing to children
116
+ * - Children have `received_from` outgoing relationships pointing to parents
117
+ * - We use `sent_to` for traversal since it's an outgoing relationship (no indexing lag)
118
+ *
119
+ * @param logEntityId - Log entity ID to find children of
120
+ * @returns Object with child IDs and total sent_to count
121
+ */
122
+ export declare function getLogChildren(logEntityId: string): Promise<LogChildrenResult>;
123
+ /**
124
+ * Build a snapshot of the workflow log tree
125
+ *
126
+ * This traverses the log tree starting from the first_log relationship
127
+ * on the job collection, following incoming received_from relationships
128
+ * to discover all logs in the workflow.
129
+ *
130
+ * @example
131
+ * ```typescript
132
+ * const tree = await buildWorkflowTree(jobCollectionId);
133
+ *
134
+ * if (tree.isComplete) {
135
+ * console.log('Workflow finished with', tree.logs.size, 'logs');
136
+ * if (tree.hasErrors) {
137
+ * console.log('Errors:', tree.errors);
138
+ * }
139
+ * }
140
+ * ```
141
+ *
142
+ * @param jobCollectionId - Job collection ID
143
+ * @returns Current state of the workflow log tree
144
+ */
145
+ export declare function buildWorkflowTree(jobCollectionId: string): Promise<WorkflowLogTree>;
146
+ /**
147
+ * Wait for a workflow to complete by polling the log tree
148
+ *
149
+ * This function properly handles:
150
+ * - Multi-step workflows (A → B → C)
151
+ * - Scatter operations (A → [B1, B2, B3])
152
+ * - Nested scatters
153
+ * - Gather operations
154
+ * - Mixed success/error branches
155
+ *
156
+ * Unlike `waitForKladosLog` which only checks the first log, this function
157
+ * traverses the entire log tree and waits for ALL branches to complete.
158
+ *
159
+ * @example
160
+ * ```typescript
161
+ * // Wait for a scatter workflow to complete
162
+ * const tree = await waitForWorkflowTree(jobCollectionId, {
163
+ * timeout: 60000,
164
+ * pollInterval: 2000,
165
+ * });
166
+ *
167
+ * if (tree.isComplete) {
168
+ * console.log('All', tree.logs.size, 'logs completed');
169
+ * if (tree.hasErrors) {
170
+ * console.log('Some branches failed:', tree.errors);
171
+ * } else {
172
+ * console.log('Workflow succeeded!');
173
+ * }
174
+ * } else {
175
+ * console.log('Workflow timed out');
176
+ * }
177
+ * ```
178
+ *
179
+ * @param jobCollectionId - Job collection ID
180
+ * @param options - Wait options
181
+ * @returns Final state of the workflow log tree
182
+ */
183
+ export declare function waitForWorkflowTree(jobCollectionId: string, options?: WaitForWorkflowTreeOptions): Promise<WorkflowLogTree>;
184
+ export {};
88
185
  //# sourceMappingURL=logs.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"logs.d.ts","sourceRoot":"","sources":["../src/logs.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,KAAK,EAAU,cAAc,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAE5E;;;;GAIG;AACH,wBAAsB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC,CAEzE;AAED;;;;;;;;GAQG;AACH,wBAAsB,yBAAyB,CAC7C,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CASxB;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAsB,gBAAgB,CACpC,eAAe,EAAE,MAAM,EACvB,OAAO,CAAC,EAAE,iBAAiB,GAC1B,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC,CA0BhC;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,cAAc,qCAEjD;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,cAAc;;;;;;;;qBAvB1B,CAAC;uBAGlB,CAAH;;iBAOU,CAAC;aAA2B,CAAC;;;;;;;;;;cAaD,CAAC;aAC1B,CAAC;;;;;;;EACd"}
1
+ {"version":3,"file":"logs.d.ts","sourceRoot":"","sources":["../src/logs.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,KAAK,EAEV,cAAc,EACd,iBAAiB,EAEjB,eAAe,EACf,0BAA0B,EAC3B,MAAM,YAAY,CAAC;AAEpB;;;;GAIG;AACH,wBAAsB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC,CAEzE;AAED;;;;;;;;GAQG;AACH,wBAAsB,yBAAyB,CAC7C,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CASxB;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAsB,gBAAgB,CACpC,eAAe,EAAE,MAAM,EACvB,OAAO,CAAC,EAAE,iBAAiB,GAC1B,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC,CA0BhC;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,cAAc,qCAEjD;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,cAAc;;;;;;;;qBAzBzC,CADG;uBAAmC,CAAC;;iBAGZ,CAAC;aAG9B,CAAC;;;;;;;;;;cAkBE,CAAC;aAAyB,CAAC;eAMxB,CAAC;;QAIX;;WAEG;QACH,CALA;;mBAAyD,CAAC;;iBAM5B,CAAC;mBAEuB,CAAC;kBAKtB,CAAC;;;;;;;EAjBjC;AAMD;;GAEG;AACH,UAAU,iBAAiB;IACzB,oCAAoC;IACpC,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,+FAA+F;IAC/F,WAAW,EAAE,MAAM,CAAC;CACrB;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,cAAc,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAiBpF;AAyMD;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAsB,iBAAiB,CACrC,eAAe,EAAE,MAAM,GACtB,OAAO,CAAC,eAAe,CAAC,CAoE1B;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,wBAAsB,mBAAmB,CACvC,eAAe,EAAE,MAAM,EACvB,OAAO,CAAC,EAAE,0BAA0B,GACnC,OAAO,CAAC,eAAe,CAAC,CAyD1B"}
package/dist/logs.js CHANGED
@@ -1,5 +1,7 @@
1
1
  /**
2
2
  * Klados log utilities for testing
3
+ *
4
+ * Includes tree-based traversal for multi-step workflows and scatter/gather operations.
3
5
  */
4
6
  import { apiRequest, sleep } from './client.js';
5
7
  /**
@@ -89,4 +91,383 @@ export function getLogMessages(log) {
89
91
  export function getLogEntry(log) {
90
92
  return log.properties.log_data.entry;
91
93
  }
94
+ /**
95
+ * Get children of a log by querying for outgoing sent_to relationships
96
+ *
97
+ * In the Rhiza log tree:
98
+ * - Parents have `sent_to` outgoing relationships pointing to children
99
+ * - Children have `received_from` outgoing relationships pointing to parents
100
+ * - We use `sent_to` for traversal since it's an outgoing relationship (no indexing lag)
101
+ *
102
+ * @param logEntityId - Log entity ID to find children of
103
+ * @returns Object with child IDs and total sent_to count
104
+ */
105
+ export async function getLogChildren(logEntityId) {
106
+ try {
107
+ const entity = await apiRequest('GET', `/entities/${logEntityId}`);
108
+ // Look for sent_to relationships pointing to children
109
+ // Note: GET /entities/{id} only returns outgoing relationships,
110
+ // so no direction check is needed.
111
+ const sentToRels = entity.relationships?.filter((r) => r.predicate === 'sent_to') ?? [];
112
+ const childIds = sentToRels.map((r) => r.peer);
113
+ return {
114
+ childIds,
115
+ sentToCount: sentToRels.length,
116
+ };
117
+ }
118
+ catch {
119
+ return { childIds: [], sentToCount: 0 };
120
+ }
121
+ }
122
+ /**
123
+ * Extract expected children count from log messages
124
+ *
125
+ * Scatter workers log numCopies in their success message metadata.
126
+ * This is the most reliable source for expected children count.
127
+ *
128
+ * @param log - Log entry to analyze
129
+ * @returns Number of expected children from messages, or null if not found
130
+ */
131
+ function extractExpectedChildrenFromMessages(log) {
132
+ const messages = log.properties.log_data.messages ?? [];
133
+ for (const msg of messages) {
134
+ // Check for numCopies in message metadata (from scatter worker)
135
+ if (msg.metadata?.numCopies !== undefined) {
136
+ return msg.metadata.numCopies;
137
+ }
138
+ }
139
+ return null;
140
+ }
141
+ /**
142
+ * Calculate expected children count from handoffs
143
+ *
144
+ * Priority:
145
+ * 1. numCopies from log messages (worker-provided, legacy support)
146
+ * 2. outputs array from handoff record (framework-provided, most reliable)
147
+ * 3. invocations array length (for local scatters without outputs field)
148
+ * 4. Handoff type analysis (pass = 1, etc.)
149
+ *
150
+ * @param log - Log entry to analyze
151
+ * @returns Number of expected children, or -1 if unknown (keep polling)
152
+ */
153
+ function getExpectedChildrenCount(log) {
154
+ // First, check log messages for numCopies (from scatter worker - legacy support)
155
+ const numCopies = extractExpectedChildrenFromMessages(log);
156
+ if (numCopies !== null) {
157
+ return numCopies;
158
+ }
159
+ // Fall back to handoff analysis
160
+ const entry = log.properties.log_data.entry;
161
+ const handoffs = entry.handoffs ?? [];
162
+ if (handoffs.length === 0) {
163
+ return 0; // No handoffs = leaf node
164
+ }
165
+ let total = 0;
166
+ for (const handoff of handoffs) {
167
+ if (handoff.type === 'invoke' || handoff.type === 'pass') {
168
+ // Invoke/pass creates 1 child
169
+ total += 1;
170
+ }
171
+ else if (handoff.type === 'scatter') {
172
+ // Scatter creates N children
173
+ // Priority: outputs array (framework-provided) > invocations > unknown
174
+ if (handoff.outputs && handoff.outputs.length > 0) {
175
+ // Use outputs array - this is the most reliable source
176
+ // Subtract done_slots since those don't create children
177
+ const doneSlots = handoff.done_slots ?? 0;
178
+ total += handoff.outputs.length - doneSlots;
179
+ }
180
+ else if (handoff.invocations && handoff.invocations.length > 0) {
181
+ // Use invocations array for local scatters (legacy)
182
+ total += handoff.invocations.length;
183
+ }
184
+ else if (handoff.delegated) {
185
+ // Delegated scatter without outputs field (shouldn't happen with new code)
186
+ // Return -1 to indicate we need to keep polling
187
+ total = -1;
188
+ break;
189
+ }
190
+ else {
191
+ // Fallback: expect at least 1 child
192
+ total += 1;
193
+ }
194
+ }
195
+ else if (handoff.type === 'gather') {
196
+ // Gather creates 1 child (the gather target)
197
+ total += 1;
198
+ }
199
+ // Other types = 0 children
200
+ }
201
+ return total;
202
+ }
203
+ /**
204
+ * Build a log tree node recursively
205
+ *
206
+ * @param logEntityId - Entity ID of the log
207
+ * @param logsMap - Map to collect all discovered logs
208
+ * @param visited - Set of visited log IDs to prevent cycles
209
+ */
210
+ async function buildTreeNode(logEntityId, logsMap, visited) {
211
+ if (visited.has(logEntityId)) {
212
+ // Prevent infinite loops on malformed data
213
+ const existingLog = logsMap.get(logEntityId);
214
+ if (existingLog) {
215
+ return {
216
+ log: existingLog,
217
+ children: [],
218
+ isLeaf: true,
219
+ isTerminal: existingLog.properties.status === 'done' ||
220
+ existingLog.properties.status === 'error',
221
+ expectedChildren: 0,
222
+ };
223
+ }
224
+ return null;
225
+ }
226
+ visited.add(logEntityId);
227
+ // Fetch the log entry
228
+ let log;
229
+ try {
230
+ log = await getKladosLog(logEntityId);
231
+ logsMap.set(logEntityId, log);
232
+ }
233
+ catch {
234
+ // Log doesn't exist yet or fetch failed
235
+ return null;
236
+ }
237
+ const isTerminal = log.properties.status === 'done' || log.properties.status === 'error';
238
+ // Find children via sent_to relationships
239
+ const { childIds } = await getLogChildren(logEntityId);
240
+ // Get expected children count (from log messages or handoff analysis)
241
+ const expectedChildren = getExpectedChildrenCount(log);
242
+ // Recursively build child nodes
243
+ const children = [];
244
+ for (const childId of childIds) {
245
+ const childNode = await buildTreeNode(childId, logsMap, visited);
246
+ if (childNode) {
247
+ children.push(childNode);
248
+ }
249
+ }
250
+ // A node is a leaf if it's terminal AND has no expected children
251
+ // OR if it has error status (errors stop the branch)
252
+ const isLeaf = log.properties.status === 'error' ||
253
+ (isTerminal && expectedChildren === 0);
254
+ return {
255
+ log,
256
+ children,
257
+ isLeaf,
258
+ isTerminal,
259
+ expectedChildren,
260
+ };
261
+ }
262
+ /**
263
+ * Collect all leaf nodes from a tree
264
+ */
265
+ function collectLeaves(node) {
266
+ if (node.children.length === 0) {
267
+ return [node];
268
+ }
269
+ return node.children.flatMap(collectLeaves);
270
+ }
271
+ /**
272
+ * Check if all expected children have been discovered in the tree
273
+ *
274
+ * Returns false if:
275
+ * - We don't know how many children to expect (expectedChildren === -1)
276
+ * - We have fewer children than expected
277
+ * - Any child hasn't discovered all its children (recursive)
278
+ */
279
+ function checkAllChildrenDiscovered(node) {
280
+ // If node is still running, children may not exist yet - assume OK for now
281
+ if (!node.isTerminal) {
282
+ return true;
283
+ }
284
+ // If we don't know expected children count, keep polling
285
+ if (node.expectedChildren < 0) {
286
+ return false;
287
+ }
288
+ // If we have fewer children than expected, not complete
289
+ if (node.children.length < node.expectedChildren) {
290
+ return false;
291
+ }
292
+ // Recursively check all children
293
+ for (const child of node.children) {
294
+ if (!checkAllChildrenDiscovered(child)) {
295
+ return false;
296
+ }
297
+ }
298
+ return true;
299
+ }
300
+ /**
301
+ * Build a snapshot of the workflow log tree
302
+ *
303
+ * This traverses the log tree starting from the first_log relationship
304
+ * on the job collection, following incoming received_from relationships
305
+ * to discover all logs in the workflow.
306
+ *
307
+ * @example
308
+ * ```typescript
309
+ * const tree = await buildWorkflowTree(jobCollectionId);
310
+ *
311
+ * if (tree.isComplete) {
312
+ * console.log('Workflow finished with', tree.logs.size, 'logs');
313
+ * if (tree.hasErrors) {
314
+ * console.log('Errors:', tree.errors);
315
+ * }
316
+ * }
317
+ * ```
318
+ *
319
+ * @param jobCollectionId - Job collection ID
320
+ * @returns Current state of the workflow log tree
321
+ */
322
+ export async function buildWorkflowTree(jobCollectionId) {
323
+ const logsMap = new Map();
324
+ const visited = new Set();
325
+ // Find root via first_log relationship
326
+ const firstLogId = await getFirstLogFromCollection(jobCollectionId);
327
+ if (!firstLogId) {
328
+ return {
329
+ root: null,
330
+ logs: logsMap,
331
+ isComplete: false,
332
+ hasErrors: false,
333
+ leaves: [],
334
+ errors: [],
335
+ allChildrenDiscovered: false,
336
+ };
337
+ }
338
+ // Build tree starting from root
339
+ const root = await buildTreeNode(firstLogId, logsMap, visited);
340
+ if (!root) {
341
+ return {
342
+ root: null,
343
+ logs: logsMap,
344
+ isComplete: false,
345
+ hasErrors: false,
346
+ leaves: [],
347
+ errors: [],
348
+ allChildrenDiscovered: false,
349
+ };
350
+ }
351
+ // Collect leaves and analyze tree
352
+ const leaves = collectLeaves(root);
353
+ const allChildrenDiscovered = checkAllChildrenDiscovered(root);
354
+ // Workflow is complete when:
355
+ // 1. All leaves are terminal (done or error)
356
+ // 2. All expected children have been discovered
357
+ const allLeavesTerminal = leaves.every((leaf) => leaf.isTerminal);
358
+ const isComplete = allLeavesTerminal && allChildrenDiscovered;
359
+ // Collect errors
360
+ const errors = [];
361
+ for (const log of logsMap.values()) {
362
+ if (log.properties.status === 'error') {
363
+ const entry = log.properties.log_data.entry;
364
+ if (entry.error) {
365
+ errors.push({
366
+ logId: log.id,
367
+ kladosId: log.properties.klados_id,
368
+ error: entry.error,
369
+ });
370
+ }
371
+ }
372
+ }
373
+ return {
374
+ root,
375
+ logs: logsMap,
376
+ isComplete,
377
+ hasErrors: errors.length > 0,
378
+ leaves,
379
+ errors,
380
+ allChildrenDiscovered,
381
+ };
382
+ }
383
+ /**
384
+ * Wait for a workflow to complete by polling the log tree
385
+ *
386
+ * This function properly handles:
387
+ * - Multi-step workflows (A → B → C)
388
+ * - Scatter operations (A → [B1, B2, B3])
389
+ * - Nested scatters
390
+ * - Gather operations
391
+ * - Mixed success/error branches
392
+ *
393
+ * Unlike `waitForKladosLog` which only checks the first log, this function
394
+ * traverses the entire log tree and waits for ALL branches to complete.
395
+ *
396
+ * @example
397
+ * ```typescript
398
+ * // Wait for a scatter workflow to complete
399
+ * const tree = await waitForWorkflowTree(jobCollectionId, {
400
+ * timeout: 60000,
401
+ * pollInterval: 2000,
402
+ * });
403
+ *
404
+ * if (tree.isComplete) {
405
+ * console.log('All', tree.logs.size, 'logs completed');
406
+ * if (tree.hasErrors) {
407
+ * console.log('Some branches failed:', tree.errors);
408
+ * } else {
409
+ * console.log('Workflow succeeded!');
410
+ * }
411
+ * } else {
412
+ * console.log('Workflow timed out');
413
+ * }
414
+ * ```
415
+ *
416
+ * @param jobCollectionId - Job collection ID
417
+ * @param options - Wait options
418
+ * @returns Final state of the workflow log tree
419
+ */
420
+ export async function waitForWorkflowTree(jobCollectionId, options) {
421
+ const timeout = options?.timeout ?? 30000;
422
+ const pollInterval = options?.pollInterval ?? 2000;
423
+ const startTime = Date.now();
424
+ let lastTree = {
425
+ root: null,
426
+ logs: new Map(),
427
+ isComplete: false,
428
+ hasErrors: false,
429
+ leaves: [],
430
+ errors: [],
431
+ allChildrenDiscovered: false,
432
+ };
433
+ // Track stability: require the same log count for 2 consecutive polls
434
+ // before declaring complete. This handles async sent_to relationship updates.
435
+ let stableCount = 0;
436
+ let lastLogCount = 0;
437
+ while (Date.now() - startTime < timeout) {
438
+ try {
439
+ const tree = await buildWorkflowTree(jobCollectionId);
440
+ lastTree = tree;
441
+ // Call optional progress callback
442
+ if (options?.onPoll) {
443
+ options.onPoll(tree, Date.now() - startTime);
444
+ }
445
+ if (tree.isComplete) {
446
+ // Check if the tree is stable (same log count as last poll)
447
+ if (tree.logs.size === lastLogCount) {
448
+ stableCount++;
449
+ // Require 2 stable polls before returning (handles async relationship updates)
450
+ if (stableCount >= 2) {
451
+ return tree;
452
+ }
453
+ }
454
+ else {
455
+ // Log count changed, reset stability counter
456
+ stableCount = 0;
457
+ }
458
+ }
459
+ else {
460
+ stableCount = 0;
461
+ }
462
+ lastLogCount = tree.logs.size;
463
+ }
464
+ catch {
465
+ // Ignore errors during polling, just retry
466
+ stableCount = 0;
467
+ }
468
+ await sleep(pollInterval);
469
+ }
470
+ // Timeout - return last known state
471
+ return lastTree;
472
+ }
92
473
  //# sourceMappingURL=logs.js.map