loop-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 (62) hide show
  1. package/README.md +591 -0
  2. package/dist/agent.d.ts +31 -0
  3. package/dist/agent.d.ts.map +1 -0
  4. package/dist/agent.js +48 -0
  5. package/dist/agent.js.map +1 -0
  6. package/dist/checkpoint.d.ts +16 -0
  7. package/dist/checkpoint.d.ts.map +1 -0
  8. package/dist/checkpoint.js +20 -0
  9. package/dist/checkpoint.js.map +1 -0
  10. package/dist/claude-cli.d.ts +35 -0
  11. package/dist/claude-cli.d.ts.map +1 -0
  12. package/dist/claude-cli.js +135 -0
  13. package/dist/claude-cli.js.map +1 -0
  14. package/dist/context.d.ts +53 -0
  15. package/dist/context.d.ts.map +1 -0
  16. package/dist/context.js +95 -0
  17. package/dist/context.js.map +1 -0
  18. package/dist/events.d.ts +111 -0
  19. package/dist/events.d.ts.map +1 -0
  20. package/dist/events.js +53 -0
  21. package/dist/events.js.map +1 -0
  22. package/dist/flow.d.ts +36 -0
  23. package/dist/flow.d.ts.map +1 -0
  24. package/dist/flow.js +62 -0
  25. package/dist/flow.js.map +1 -0
  26. package/dist/index.d.ts +26 -0
  27. package/dist/index.d.ts.map +1 -0
  28. package/dist/index.js +14 -0
  29. package/dist/index.js.map +1 -0
  30. package/dist/logger.d.ts +37 -0
  31. package/dist/logger.d.ts.map +1 -0
  32. package/dist/logger.js +64 -0
  33. package/dist/logger.js.map +1 -0
  34. package/dist/loop.d.ts +199 -0
  35. package/dist/loop.d.ts.map +1 -0
  36. package/dist/loop.js +403 -0
  37. package/dist/loop.js.map +1 -0
  38. package/dist/loopfile.d.ts +82 -0
  39. package/dist/loopfile.d.ts.map +1 -0
  40. package/dist/loopfile.js +235 -0
  41. package/dist/loopfile.js.map +1 -0
  42. package/dist/mcp/server.d.ts +26 -0
  43. package/dist/mcp/server.d.ts.map +1 -0
  44. package/dist/mcp/server.js +160 -0
  45. package/dist/mcp/server.js.map +1 -0
  46. package/dist/notify.d.ts +43 -0
  47. package/dist/notify.d.ts.map +1 -0
  48. package/dist/notify.js +68 -0
  49. package/dist/notify.js.map +1 -0
  50. package/dist/plugins/retry.d.ts +41 -0
  51. package/dist/plugins/retry.d.ts.map +1 -0
  52. package/dist/plugins/retry.js +53 -0
  53. package/dist/plugins/retry.js.map +1 -0
  54. package/dist/providers/playwright.d.ts +38 -0
  55. package/dist/providers/playwright.d.ts.map +1 -0
  56. package/dist/providers/playwright.js +155 -0
  57. package/dist/providers/playwright.js.map +1 -0
  58. package/dist/session.d.ts +43 -0
  59. package/dist/session.d.ts.map +1 -0
  60. package/dist/session.js +26 -0
  61. package/dist/session.js.map +1 -0
  62. package/package.json +78 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"flow.js","sourceRoot":"","sources":["../src/flow.ts"],"names":[],"mappings":"AASA;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,KAAK,UAAU,IAAI,CACxB,GAAY,EACZ,KAAa,EACb,EAAsC,EACtC,EAAE,eAAe,GAAG,KAAK,KAAkB,EAAE;IAE7C,MAAM,KAAK,GAAG,WAAW,CAAC,KAAK,CAAC,CAAA;IAEhC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,IAAI,MAAM,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAA;QACzE,MAAM,QAAQ,GAAG,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QAE/B,IAAI,CAAC;YACH,MAAM,EAAE,CAAC,QAAQ,CAAC,CAAA;QACpB,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,CAAC,eAAe;gBAAE,MAAM,GAAG,CAAA;YAC/B,MAAM,GAAG,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;YAC5D,GAAG,CAAC,GAAG,CAAC,UAAU,KAAK,cAAc,GAAG,EAAE,CAAC,CAAA;QAC7C,CAAC;IACH,CAAC;AACH,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,CAAC,KAAK,UAAU,GAAG,CACvB,GAAY,EACZ,IAAU,EACV,OAAgC,EAAE;IAElC,MAAM,QAAQ,GAAG,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IAC/B,OAAO,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAA;AAC/B,CAAC;AAUD,SAAS,WAAW,CAAC,KAAa;IAChC,MAAM,KAAK,GAAe,EAAE,CAAA;IAC5B,KAAK,MAAM,KAAK,IAAI,KAAK,EAAE,CAAC;QAC1B,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;YAC9B,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAA;QAC7B,CAAC;aAAM,IAAI,KAAK,CAAC,QAAQ,EAAE,MAAM,EAAE,CAAC;YAClC,KAAK,MAAM,OAAO,IAAI,KAAK,CAAC,QAAQ,EAAE,CAAC;gBACrC,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,OAAO,EAAE,CAAC,CAAA;YAC3C,CAAC;QACH,CAAC;aAAM,CAAC;YACN,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC,CAAA;QAClC,CAAC;IACH,CAAC;IACD,OAAO,KAAK,CAAA;AACd,CAAC"}
@@ -0,0 +1,26 @@
1
+ export { Loop, run } from './loop.js';
2
+ export type { Plugin, StepOptions, RunOptions, RunLog, RunHandle, HandleStatus, StepFn, StepResult } from './loop.js';
3
+ export { RetryPlugin } from './plugins/retry.js';
4
+ export type { RetryPluginOptions } from './plugins/retry.js';
5
+ export { Session } from './session.js';
6
+ export type { ClickOptions, ScrollOptions } from './session.js';
7
+ export { Context } from './context.js';
8
+ export type { ContextOptions } from './context.js';
9
+ export { Logger } from './logger.js';
10
+ export type { RunStatus, StepStatus, RunDoc, StepRecord } from './logger.js';
11
+ export { each, sub } from './flow.js';
12
+ export type { Item, EachOptions } from './flow.js';
13
+ export { agent } from './agent.js';
14
+ export type { AgentOptions, AgentResult } from './agent.js';
15
+ export { claudeCli } from './claude-cli.js';
16
+ export type { ClaudeCliOptions, ClaudeCliResult } from './claude-cli.js';
17
+ export { checkpointExists, deleteCheckpoint } from './checkpoint.js';
18
+ export type { Checkpoint } from './checkpoint.js';
19
+ export { loadLoop, loadLoopFile, parseLoopFile, runFile, runFileBackground } from './loopfile.js';
20
+ export type { LoopFileMeta, LoopFileStep, LoopFileSchema, ActionRegistry } from './loopfile.js';
21
+ export { Emitter } from './events.js';
22
+ export type { LoopEvents, LoopStartEvent, LoopCompleteEvent, StepStartEvent, StepCompleteEvent, StepErrorEvent, StepSkipEvent, StepRetryEvent, CheckpointSavedEvent, } from './events.js';
23
+ export { PlaywrightSession } from './providers/playwright.js';
24
+ export { notify, notifyOn } from './notify.js';
25
+ export type { NotifyOptions, NotifyOnOptions } from './notify.js';
26
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,MAAM,WAAW,CAAA;AACrC,YAAY,EAAE,MAAM,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,WAAW,CAAA;AAErH,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AAChD,YAAY,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAA;AAE5D,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AACtC,YAAY,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,cAAc,CAAA;AAE/D,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AACtC,YAAY,EAAE,cAAc,EAAE,MAAM,cAAc,CAAA;AAElD,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AACpC,YAAY,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AAE5E,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,MAAM,WAAW,CAAA;AACrC,YAAY,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,WAAW,CAAA;AAElD,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAA;AAClC,YAAY,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AAE3D,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAC3C,YAAY,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AAExE,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAA;AACpE,YAAY,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;AAEjD,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,aAAa,EAAE,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAA;AACjG,YAAY,EAAE,YAAY,EAAE,YAAY,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,eAAe,CAAA;AAE/F,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAA;AACrC,YAAY,EACV,UAAU,EACV,cAAc,EACd,iBAAiB,EACjB,cAAc,EACd,iBAAiB,EACjB,cAAc,EACd,aAAa,EACb,cAAc,EACd,oBAAoB,GACrB,MAAM,aAAa,CAAA;AAEpB,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAA;AAE7D,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA;AAC9C,YAAY,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA"}
package/dist/index.js ADDED
@@ -0,0 +1,14 @@
1
+ export { Loop, run } from './loop.js';
2
+ export { RetryPlugin } from './plugins/retry.js';
3
+ export { Session } from './session.js';
4
+ export { Context } from './context.js';
5
+ export { Logger } from './logger.js';
6
+ export { each, sub } from './flow.js';
7
+ export { agent } from './agent.js';
8
+ export { claudeCli } from './claude-cli.js';
9
+ export { checkpointExists, deleteCheckpoint } from './checkpoint.js';
10
+ export { loadLoop, loadLoopFile, parseLoopFile, runFile, runFileBackground } from './loopfile.js';
11
+ export { Emitter } from './events.js';
12
+ export { PlaywrightSession } from './providers/playwright.js';
13
+ export { notify, notifyOn } from './notify.js';
14
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,MAAM,WAAW,CAAA;AAGrC,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AAGhD,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AAGtC,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AAGtC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AAGpC,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,MAAM,WAAW,CAAA;AAGrC,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAA;AAGlC,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAG3C,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAA;AAGpE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,aAAa,EAAE,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAA;AAGjG,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAA;AAarC,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAA;AAE7D,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA"}
@@ -0,0 +1,37 @@
1
+ export type StepStatus = 'ok' | 'error' | 'running';
2
+ export type RunStatus = 'completed' | 'failed' | 'running' | 'cancelled';
3
+ export interface StepRecord {
4
+ name: string;
5
+ status: StepStatus;
6
+ result?: unknown;
7
+ error?: string;
8
+ startedAt: string;
9
+ finishedAt?: string;
10
+ }
11
+ export interface RunDoc {
12
+ loop: string;
13
+ session: string;
14
+ startedAt: string;
15
+ finishedAt: string;
16
+ status: RunStatus;
17
+ steps: StepRecord[];
18
+ }
19
+ export declare class Logger {
20
+ readonly logFile: string | null;
21
+ private readonly loopName;
22
+ private readonly sessionId;
23
+ private readonly startedAt;
24
+ private readonly steps;
25
+ private currentStep;
26
+ constructor(logDir: string | null, loopName: string, sessionId: string);
27
+ write(_: {
28
+ msg: string;
29
+ data?: unknown;
30
+ }): void;
31
+ stepStart(name: string): void;
32
+ stepDone(result?: unknown): void;
33
+ stepError(err: Error): void;
34
+ finish(status: RunStatus): void;
35
+ private flush;
36
+ }
37
+ //# sourceMappingURL=logger.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAGA,MAAM,MAAM,UAAU,GAAG,IAAI,GAAG,OAAO,GAAG,SAAS,CAAA;AACnD,MAAM,MAAM,SAAS,GAAG,WAAW,GAAG,QAAQ,GAAG,SAAS,GAAG,WAAW,CAAA;AAExE,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE,UAAU,CAAA;IAClB,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,SAAS,EAAE,MAAM,CAAA;IACjB,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB;AAED,MAAM,WAAW,MAAM;IACrB,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,MAAM,CAAA;IACf,SAAS,EAAE,MAAM,CAAA;IACjB,UAAU,EAAE,MAAM,CAAA;IAClB,MAAM,EAAE,SAAS,CAAA;IACjB,KAAK,EAAE,UAAU,EAAE,CAAA;CACpB;AAED,qBAAa,MAAM;IACjB,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;IAC/B,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAQ;IACjC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAQ;IAClC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAQ;IAClC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAmB;IACzC,OAAO,CAAC,WAAW,CAA0B;gBAEjC,MAAM,EAAE,MAAM,GAAG,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM;IAatE,KAAK,CAAC,CAAC,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,IAAI;IAI/C,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAK7B,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,GAAG,IAAI;IAQhC,SAAS,CAAC,GAAG,EAAE,KAAK,GAAG,IAAI;IAQ3B,MAAM,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI;IAI/B,OAAO,CAAC,KAAK;CAYd"}
package/dist/logger.js ADDED
@@ -0,0 +1,64 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ export class Logger {
4
+ logFile;
5
+ loopName;
6
+ sessionId;
7
+ startedAt;
8
+ steps = [];
9
+ currentStep = null;
10
+ constructor(logDir, loopName, sessionId) {
11
+ this.loopName = loopName;
12
+ this.sessionId = sessionId;
13
+ this.startedAt = new Date().toISOString();
14
+ this.logFile = null;
15
+ if (logDir) {
16
+ fs.mkdirSync(logDir, { recursive: true });
17
+ const ts = this.startedAt.replace(/[:.]/g, '-').replace('T', '_').slice(0, 19);
18
+ this.logFile = path.join(logDir, `${ts}_${loopName}.json`);
19
+ }
20
+ }
21
+ write(_) {
22
+ // No-op: stdout output is handled by ctx.log(); structured data is captured in step records
23
+ }
24
+ stepStart(name) {
25
+ this.currentStep = { name, status: 'running', startedAt: new Date().toISOString() };
26
+ this.steps.push(this.currentStep);
27
+ }
28
+ stepDone(result) {
29
+ if (!this.currentStep)
30
+ return;
31
+ this.currentStep.status = 'ok';
32
+ this.currentStep.result = result ?? null;
33
+ this.currentStep.finishedAt = new Date().toISOString();
34
+ this.flush('running');
35
+ }
36
+ stepError(err) {
37
+ if (!this.currentStep)
38
+ return;
39
+ this.currentStep.status = 'error';
40
+ this.currentStep.error = err.message;
41
+ this.currentStep.finishedAt = new Date().toISOString();
42
+ this.flush('failed');
43
+ }
44
+ finish(status) {
45
+ this.flush(status);
46
+ }
47
+ flush(status) {
48
+ if (!this.logFile)
49
+ return;
50
+ const doc = {
51
+ loop: this.loopName,
52
+ session: this.sessionId,
53
+ startedAt: this.startedAt,
54
+ finishedAt: new Date().toISOString(),
55
+ status,
56
+ steps: this.steps,
57
+ };
58
+ try {
59
+ fs.writeFileSync(this.logFile, JSON.stringify(doc, null, 2));
60
+ }
61
+ catch { }
62
+ }
63
+ }
64
+ //# sourceMappingURL=logger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.js","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"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"}
package/dist/loop.d.ts ADDED
@@ -0,0 +1,199 @@
1
+ import { Context } from './context.js';
2
+ import { type RunStatus } from './logger.js';
3
+ import type { Session } from './session.js';
4
+ import { type LoopEvents } from './events.js';
5
+ export type StepFn = (ctx: Context) => Promise<unknown>;
6
+ export interface StepOptions {
7
+ /**
8
+ * Run this function if the step fails (after all retries are exhausted).
9
+ * If the fallback succeeds, the loop continues rather than aborting.
10
+ *
11
+ * @example
12
+ * loop.step('fetch-live', fetchLive, {
13
+ * onError: async (err, ctx) => {
14
+ * ctx.set('data', FALLBACK_DATA)
15
+ * }
16
+ * })
17
+ */
18
+ onError?: (err: Error, ctx: Context) => Promise<unknown>;
19
+ /**
20
+ * Skip this step on failure and continue the loop instead of aborting.
21
+ * The step is recorded as 'skipped' in the run log.
22
+ *
23
+ * @example
24
+ * loop.step('post-metrics', postMetrics, { skipOnError: true })
25
+ */
26
+ skipOnError?: boolean;
27
+ /**
28
+ * Retry the step this many additional times before giving up.
29
+ * Combined with retryDelay / retryBackoff for pacing.
30
+ *
31
+ * @example
32
+ * loop.step('call-api', callApi, { retries: 3, retryDelay: 500, retryBackoff: 'exponential' })
33
+ */
34
+ retries?: number;
35
+ /** Milliseconds to wait before the first retry. Default: 0. */
36
+ retryDelay?: number;
37
+ /**
38
+ * How to scale the delay across retry attempts.
39
+ * - 'flat' — same delay every time
40
+ * - 'linear' — delay * attempt (1x, 2x, 3x …)
41
+ * - 'exponential' — delay * 2^attempt (1x, 2x, 4x …)
42
+ *
43
+ * Default: 'flat'
44
+ */
45
+ retryBackoff?: 'flat' | 'linear' | 'exponential';
46
+ }
47
+ export interface Plugin {
48
+ name: string;
49
+ hooks?: {
50
+ /**
51
+ * Called when a step throws. Return true to signal that the error was
52
+ * handled and the step should be retried once.
53
+ */
54
+ onStepError?: (err: Error, step: {
55
+ name: string;
56
+ index: number;
57
+ }, ctx: Context) => Promise<boolean | void>;
58
+ };
59
+ }
60
+ export type HandleStatus = 'running' | 'completed' | 'failed' | 'cancelled' | 'paused';
61
+ /**
62
+ * A handle to a loop running in the background via loop.runBackground().
63
+ *
64
+ * @example
65
+ * const handle = loop.runBackground({ session })
66
+ *
67
+ * handle.status // 'running'
68
+ * await handle.wait() // resolves when done
69
+ * handle.cancel() // stop — state discarded
70
+ * handle.pause() // stop — state saved for resume
71
+ * handle.resume() // returns a new handle for the continued run
72
+ */
73
+ export interface RunHandle {
74
+ readonly id: string;
75
+ readonly status: HandleStatus;
76
+ /** Resolves with the RunLog on completion/cancellation. Rejects on unrecovered step failure. */
77
+ wait(): Promise<RunLog>;
78
+ /** Stop after the current step finishes. State is discarded — cannot be resumed. */
79
+ cancel(): void;
80
+ /** Stop after the current step finishes. State is saved — resume with handle.resume(). */
81
+ pause(): void;
82
+ /**
83
+ * Resume a paused loop from the last completed step.
84
+ * Returns a new RunHandle for the continued run.
85
+ * Throws if the handle is not in 'paused' state.
86
+ */
87
+ resume(): RunHandle;
88
+ }
89
+ export interface RunOptions {
90
+ session: Session;
91
+ vars?: Record<string, unknown>;
92
+ logDir?: string | null;
93
+ startAt?: number | null;
94
+ stopAt?: number | null;
95
+ /** AbortSignal to cancel the loop between steps. Use loop.runBackground() for a managed handle. */
96
+ signal?: AbortSignal | null;
97
+ checkpointFile?: string | null;
98
+ resumeFrom?: string | null;
99
+ keepCheckpointOnSuccess?: boolean;
100
+ /**
101
+ * Called when the loop fails — after all step-level retries, fallbacks, and
102
+ * plugin hooks are exhausted. Use for cleanup, alerting, or partial saves.
103
+ *
104
+ * Errors thrown inside onError are swallowed so they don't mask the original failure.
105
+ *
106
+ * @example
107
+ * loop.run({
108
+ * session,
109
+ * onError: async (err, ctx, failedStep) => {
110
+ * await slack.send(`Loop failed at "${failedStep}": ${err.message}`)
111
+ * await ctx.get('partialResults')?.save()
112
+ * }
113
+ * })
114
+ */
115
+ onError?: (err: Error, ctx: Context, failedStep: string) => Promise<void>;
116
+ }
117
+ export interface StepResult {
118
+ name: string;
119
+ status: 'ok' | 'error' | 'skipped' | 'recovered';
120
+ error?: string;
121
+ }
122
+ export interface RunLog {
123
+ loop: string;
124
+ session: string;
125
+ startedAt: string;
126
+ finishedAt: string;
127
+ status: RunStatus;
128
+ resumedFrom?: string;
129
+ steps: StepResult[];
130
+ }
131
+ type KnownListener<K extends keyof LoopEvents> = (data: LoopEvents[K]) => void | Promise<void>;
132
+ type AnyListener = (data: unknown) => void | Promise<void>;
133
+ export declare class Loop {
134
+ readonly name: string;
135
+ private readonly _steps;
136
+ private readonly _plugins;
137
+ private readonly _emitter;
138
+ constructor(name: string);
139
+ step(name: string, fn: StepFn, opts?: StepOptions): this;
140
+ /**
141
+ * Add a parallel step — all named functions run concurrently.
142
+ * The step only completes when every sub-step resolves.
143
+ * Each sub-step's return value is stored in ctx under its name.
144
+ *
145
+ * @example
146
+ * loop.parallel('gather', {
147
+ * 'fetch-prices': async (ctx) => { ctx.set('fetch-prices', await getPrice()) },
148
+ * 'fetch-reviews': async (ctx) => { ctx.set('fetch-reviews', await getReviews()) },
149
+ * })
150
+ *
151
+ * loop.step('summarize', async (ctx) => {
152
+ * const prices = ctx.get('fetch-prices')
153
+ * const reviews = ctx.get('fetch-reviews')
154
+ * })
155
+ */
156
+ parallel(name: string, fns: Record<string, StepFn>, opts?: StepOptions): this;
157
+ /**
158
+ * Run multiple loops concurrently and return all results.
159
+ *
160
+ * @example
161
+ * const logs = await Loop.runAll([
162
+ * { loop: researchLoop, session: sessionA },
163
+ * { loop: reportLoop, session: sessionB },
164
+ * ])
165
+ */
166
+ static runAll(jobs: Array<{
167
+ loop: Loop;
168
+ } & RunOptions>): Promise<RunLog[]>;
169
+ use(plugin: Plugin): this;
170
+ on<K extends keyof LoopEvents>(event: K, listener: KnownListener<K>): this;
171
+ on(event: string, listener: AnyListener): this;
172
+ off<K extends keyof LoopEvents>(event: K, listener: KnownListener<K>): this;
173
+ off(event: string, listener: AnyListener): this;
174
+ /** Run steps against an existing Context — used by sub() and each(). */
175
+ runWith(ctx: Context): Promise<void>;
176
+ /** Full run: create a fresh Context, execute all steps, return a run log. */
177
+ run({ session, vars, logDir, startAt, stopAt, checkpointFile, resumeFrom, keepCheckpointOnSuccess, onError, signal, }: RunOptions): Promise<RunLog>;
178
+ /**
179
+ * Start the loop in the background and return a RunHandle immediately.
180
+ * Auto-generates a checkpoint file so pause/resume works without any configuration.
181
+ *
182
+ * @example
183
+ * const handle = loop.runBackground({ session })
184
+ *
185
+ * // Pause after the current step, resume later
186
+ * handle.pause()
187
+ * const handle2 = handle.resume()
188
+ * await handle2.wait()
189
+ *
190
+ * // Parallel loops
191
+ * const [log1, log2] = await Promise.all([h1.wait(), h2.wait()])
192
+ */
193
+ runBackground(opts: RunOptions): RunHandle;
194
+ private _runErrorHooks;
195
+ }
196
+ /** Functional API — define and run a loop in one call. */
197
+ export declare function run(name: string, session: Session, fn: StepFn, opts?: Omit<RunOptions, 'session'>): Promise<RunLog>;
198
+ export {};
199
+ //# sourceMappingURL=loop.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loop.d.ts","sourceRoot":"","sources":["../src/loop.ts"],"names":[],"mappings":"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"}