@nyxa/automation 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 (48) hide show
  1. package/README.md +559 -0
  2. package/dist/cancellation.d.ts +1 -0
  3. package/dist/cancellation.js +5 -0
  4. package/dist/claude-code.d.ts +19 -0
  5. package/dist/claude-code.js +182 -0
  6. package/dist/cli.d.ts +2 -0
  7. package/dist/cli.js +487 -0
  8. package/dist/codex-output.d.ts +6 -0
  9. package/dist/codex-output.js +167 -0
  10. package/dist/codex.d.ts +17 -0
  11. package/dist/codex.js +228 -0
  12. package/dist/doctor.d.ts +17 -0
  13. package/dist/doctor.js +138 -0
  14. package/dist/errors.d.ts +30 -0
  15. package/dist/errors.js +51 -0
  16. package/dist/events.d.ts +55 -0
  17. package/dist/events.js +51 -0
  18. package/dist/filesystem.d.ts +2 -0
  19. package/dist/filesystem.js +13 -0
  20. package/dist/harness-process.d.ts +39 -0
  21. package/dist/harness-process.js +359 -0
  22. package/dist/harness-prompt.d.ts +2 -0
  23. package/dist/harness-prompt.js +14 -0
  24. package/dist/harness.d.ts +44 -0
  25. package/dist/harness.js +68 -0
  26. package/dist/index.d.ts +10 -0
  27. package/dist/index.js +9 -0
  28. package/dist/init.d.ts +1 -0
  29. package/dist/init.js +305 -0
  30. package/dist/json.d.ts +4 -0
  31. package/dist/json.js +1 -0
  32. package/dist/kimi-code.d.ts +16 -0
  33. package/dist/kimi-code.js +299 -0
  34. package/dist/opencode.d.ts +15 -0
  35. package/dist/opencode.js +164 -0
  36. package/dist/run-coordination.d.ts +10 -0
  37. package/dist/run-coordination.js +96 -0
  38. package/dist/run-journal.d.ts +14 -0
  39. package/dist/run-journal.js +129 -0
  40. package/dist/schema.d.ts +167 -0
  41. package/dist/schema.js +516 -0
  42. package/dist/standard-input.d.ts +1 -0
  43. package/dist/standard-input.js +7 -0
  44. package/dist/type-utils.d.ts +1 -0
  45. package/dist/type-utils.js +1 -0
  46. package/dist/workflow.d.ts +160 -0
  47. package/dist/workflow.js +530 -0
  48. package/package.json +51 -0
@@ -0,0 +1,530 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import { realpath, stat } from "node:fs/promises";
3
+ import path from "node:path";
4
+ import { throwIfAborted } from "./cancellation.js";
5
+ import { AutomationEventDispatcher, } from "./events.js";
6
+ import { AutomationError, automationErrorDetails, contextualizeAutomationError, } from "./errors.js";
7
+ import { isWithinDirectory } from "./filesystem.js";
8
+ import { harnessName, runHarness, } from "./harness.js";
9
+ import { acquireWorkspaceAccess, RunConcurrencyLimiter, } from "./run-coordination.js";
10
+ import { RunJournal } from "./run-journal.js";
11
+ const workflowDefinitionBrand = Symbol.for("@nyxa/automation/workflow-definition");
12
+ const workflowRunner = Symbol.for("@nyxa/automation/workflow-runner");
13
+ const workflowInputSchema = Symbol.for("@nyxa/automation/workflow-input-schema");
14
+ const workflowOutputSchema = Symbol.for("@nyxa/automation/workflow-output-schema");
15
+ const workflowHarness = Symbol.for("@nyxa/automation/workflow-harness");
16
+ export function defineWorkflow(options) {
17
+ const inputSchema = options.input;
18
+ const outputSchema = options.output;
19
+ const harness = options.harness;
20
+ return Object.freeze({
21
+ [workflowDefinitionBrand]: true,
22
+ [workflowInputSchema]: inputSchema,
23
+ [workflowOutputSchema]: outputSchema,
24
+ [workflowHarness]: harness,
25
+ [workflowRunner]: options.run,
26
+ });
27
+ }
28
+ export function isWorkflowDefinition(value) {
29
+ if (typeof value !== "object" || value === null) {
30
+ return false;
31
+ }
32
+ const candidate = value;
33
+ return (candidate[workflowDefinitionBrand] === true &&
34
+ typeof candidate[workflowRunner] === "function");
35
+ }
36
+ export function executeWorkflow(definition, options) {
37
+ return executeWorkflowWithControls(definition, options);
38
+ }
39
+ export async function executeWorkflowWithControls(definition, options, forceSignal) {
40
+ const cancellation = createExecutionCancellation(options?.signal);
41
+ try {
42
+ return await executeWorkflowExecution(definition, options, cancellation.signal, cancellation.abort, forceSignal);
43
+ }
44
+ finally {
45
+ cancellation.dispose();
46
+ }
47
+ }
48
+ async function executeWorkflowExecution(definition, options, executionSignal, abortExecution, forceSignal) {
49
+ const hasInput = options !== undefined && Object.hasOwn(options, "input");
50
+ const inputSchema = definition[workflowInputSchema];
51
+ const workflowId = randomUUID();
52
+ const workspaceRoot = path.resolve(options?.workspaceRoot ?? process.cwd());
53
+ const journalMode = runJournalMode(options?.record);
54
+ const journal = journalMode === false
55
+ ? undefined
56
+ : await RunJournal.create(workflowId, journalMode, workspaceRoot);
57
+ const events = new AutomationEventDispatcher(options?.onEvent, journal === undefined
58
+ ? undefined
59
+ : (event, content) => journal.append(event, content), abortExecution);
60
+ const concurrency = new RunConcurrencyLimiter(options?.concurrency);
61
+ let input;
62
+ try {
63
+ if (inputSchema === undefined) {
64
+ if (hasInput) {
65
+ throw new AutomationError("WORKFLOW_INPUT_UNEXPECTED", "This Workflow Definition does not declare a Workflow Input contract.");
66
+ }
67
+ input = undefined;
68
+ }
69
+ else {
70
+ if (!hasInput) {
71
+ throw new AutomationError("WORKFLOW_INPUT_INVALID", "A Workflow Input is required by this Workflow Definition.");
72
+ }
73
+ const parsedInput = inputSchema.safeParse(options?.input);
74
+ if (!parsedInput.success) {
75
+ throw new AutomationError("WORKFLOW_INPUT_INVALID", "The Workflow Input does not satisfy its contract.", { cause: parsedInput.error });
76
+ }
77
+ input = parsedInput.data;
78
+ }
79
+ }
80
+ catch (cause) {
81
+ const error = contextualizeAutomationError(cause, "WORKFLOW_EXECUTION_FAILED", "The Workflow execution failed unexpectedly.", { workflowId });
82
+ await journal?.append({
83
+ error: automationErrorDetails(error),
84
+ sequence: 0,
85
+ timestamp: new Date().toISOString(),
86
+ type: "workflow.failed",
87
+ workflowId,
88
+ }, hasInput ? { input: options?.input } : undefined);
89
+ throw error;
90
+ }
91
+ await events.emit({ type: "workflow.started", workflowId }, hasInput ? { input: options?.input } : undefined);
92
+ const activeRuns = new Set();
93
+ const context = Object.freeze({
94
+ input,
95
+ signal: executionSignal,
96
+ run(prompt, runOptions) {
97
+ return executeContextRun(prompt, runOptions);
98
+ },
99
+ session(sessionOptions = {}) {
100
+ const harness = sessionOptions?.harness ?? definition[workflowHarness];
101
+ const cwd = sessionOptions?.cwd;
102
+ const sessionEnvironment = sessionOptions.env === undefined
103
+ ? undefined
104
+ : Object.freeze({ ...sessionOptions.env });
105
+ const state = {
106
+ busy: false,
107
+ nativeSessionId: undefined,
108
+ sessionId: randomUUID(),
109
+ sessionName: sessionOptions?.name,
110
+ state: "new",
111
+ };
112
+ return Object.freeze({
113
+ run(prompt, runOptions) {
114
+ if (state.busy) {
115
+ return Promise.reject(new AutomationError("SESSION_BUSY", "A Session cannot run concurrently on the same handle.", {
116
+ harness: harnessName(harness),
117
+ sessionId: state.sessionId,
118
+ workflowId,
119
+ }));
120
+ }
121
+ if (state.state === "unavailable") {
122
+ return Promise.reject(new AutomationError("SESSION_UNAVAILABLE", "The Session can no longer prove conversation continuity.", {
123
+ harness: harnessName(harness),
124
+ sessionId: state.sessionId,
125
+ workflowId,
126
+ }));
127
+ }
128
+ state.busy = true;
129
+ const { cwd: _ignoredCwd, harness: _ignoredHarness, ...sessionRunOptions } = runOptions;
130
+ const environment = mergeEnvironmentOverrides(sessionEnvironment, sessionRunOptions.env);
131
+ return executeContextRun(prompt, {
132
+ ...sessionRunOptions,
133
+ ...(cwd === undefined ? {} : { cwd }),
134
+ ...(environment === undefined ? {} : { env: environment }),
135
+ ...(harness === undefined ? {} : { harness }),
136
+ }, state).finally(() => {
137
+ state.busy = false;
138
+ });
139
+ },
140
+ });
141
+ },
142
+ });
143
+ function executeContextRun(prompt, runOptions, explicitSession) {
144
+ const harness = runOptions?.harness ?? definition[workflowHarness];
145
+ const runId = randomUUID();
146
+ const sessionId = explicitSession?.sessionId ?? randomUUID();
147
+ const runName = runOptions?.name;
148
+ const selectedHarnessName = harnessName(harness);
149
+ const correlation = {
150
+ harness: selectedHarnessName,
151
+ runId,
152
+ runName,
153
+ sessionId,
154
+ sessionName: explicitSession?.sessionName,
155
+ workflowId,
156
+ };
157
+ const execution = performRun();
158
+ activeRuns.add(execution);
159
+ void execution.then(() => activeRuns.delete(execution), () => activeRuns.delete(execution));
160
+ return execution;
161
+ async function performRun() {
162
+ let started = false;
163
+ let continuityProven = false;
164
+ let timeout;
165
+ const runAbort = new AbortController();
166
+ const cancelRun = () => runAbort.abort(executionSignal.reason);
167
+ executionSignal.addEventListener("abort", cancelRun, { once: true });
168
+ if (executionSignal.aborted) {
169
+ cancelRun();
170
+ }
171
+ try {
172
+ throwIfAborted(runAbort.signal);
173
+ if (!isAccessPolicy(runOptions?.access)) {
174
+ throw new AutomationError("RUN_POLICY_INVALID", "A Run requires an explicit Access Policy.");
175
+ }
176
+ const approval = runOptions.approval ?? "deny";
177
+ if (!isApprovalPolicy(approval)) {
178
+ throw new AutomationError("RUN_POLICY_INVALID", "A Run Approval Policy must be either deny or auto.");
179
+ }
180
+ if (!isRunTimeout(runOptions.timeout)) {
181
+ throw new AutomationError("RUN_POLICY_INVALID", "A Run timeout must be a positive finite duration or false.");
182
+ }
183
+ if (runOptions.timeout !== false) {
184
+ timeout = setTimeout(() => runAbort.abort(new AutomationError("RUN_TIMED_OUT", "The Run exceeded its timeout.")), runOptions.timeout ?? 30 * 60 * 1_000);
185
+ timeout.unref();
186
+ }
187
+ const directories = await resolveRunWorkingDirectory(workspaceRoot, runOptions.cwd);
188
+ const environment = createRunEnvironment(runOptions.env);
189
+ const releaseWorkspace = acquireWorkspaceAccess(directories.workspaceRoot, runOptions.access);
190
+ try {
191
+ const releaseConcurrency = await concurrency.acquire(runAbort.signal);
192
+ try {
193
+ throwIfAborted(runAbort.signal);
194
+ const request = {
195
+ access: runOptions.access,
196
+ approval,
197
+ emitNativeEvent: (event) => events.emit({
198
+ ...correlation,
199
+ type: "run.native",
200
+ harness: selectedHarnessName,
201
+ native: { portable: false, event },
202
+ }),
203
+ environment,
204
+ ...(explicitSession?.nativeSessionId === undefined
205
+ ? {}
206
+ : { nativeSessionId: explicitSession.nativeSessionId }),
207
+ prompt,
208
+ runId,
209
+ signal: runAbort.signal,
210
+ ...(forceSignal === undefined ? {} : { forceSignal }),
211
+ ...(explicitSession === undefined
212
+ ? {}
213
+ : {
214
+ sessionReady(nativeSessionId) {
215
+ explicitSession.nativeSessionId = nativeSessionId;
216
+ explicitSession.state = "ready";
217
+ continuityProven = true;
218
+ },
219
+ }),
220
+ async start() {
221
+ await events.emit({ ...correlation, type: "run.started" }, { environment, prompt });
222
+ started = true;
223
+ },
224
+ workingDirectory: directories.workingDirectory,
225
+ };
226
+ const result = runOptions?.output === undefined
227
+ ? await runHarness(harness, request)
228
+ : await runHarness(harness, {
229
+ ...request,
230
+ output: runOptions.output,
231
+ });
232
+ await events.emit({
233
+ ...correlation,
234
+ type: "run.completed",
235
+ harness: selectedHarnessName,
236
+ }, { result });
237
+ return result;
238
+ }
239
+ finally {
240
+ releaseConcurrency();
241
+ }
242
+ }
243
+ finally {
244
+ releaseWorkspace();
245
+ }
246
+ }
247
+ catch (cause) {
248
+ const error = contextualizeAutomationError(cause, "HARNESS_PROCESS_FAILED", "The Run failed unexpectedly.", {
249
+ harness: selectedHarnessName,
250
+ runId,
251
+ sessionId,
252
+ workflowId,
253
+ });
254
+ if (explicitSession !== undefined &&
255
+ (isRunInterruption(error) || (started && !continuityProven))) {
256
+ explicitSession.state = "unavailable";
257
+ }
258
+ if (!events.failed && started) {
259
+ await events.emit({
260
+ ...correlation,
261
+ type: "run.failed",
262
+ error: automationErrorDetails(error),
263
+ harness: error.harness,
264
+ });
265
+ }
266
+ throw error;
267
+ }
268
+ finally {
269
+ if (timeout !== undefined) {
270
+ clearTimeout(timeout);
271
+ }
272
+ executionSignal.removeEventListener("abort", cancelRun);
273
+ }
274
+ }
275
+ }
276
+ try {
277
+ throwIfAborted(executionSignal);
278
+ const workflowExecution = Promise.resolve(definition[workflowRunner](context));
279
+ const result = await awaitWorkflowOrCancellation(workflowExecution, executionSignal, activeRuns);
280
+ throwIfAborted(executionSignal);
281
+ const outputSchema = definition[workflowOutputSchema];
282
+ if (outputSchema !== undefined) {
283
+ const parsedOutput = outputSchema.safeParse(result);
284
+ if (!parsedOutput.success) {
285
+ throw new AutomationError("WORKFLOW_OUTPUT_INVALID", "The Workflow Result does not satisfy its contract.", { cause: parsedOutput.error });
286
+ }
287
+ assertJsonSerializable(parsedOutput.data);
288
+ await events.emit({
289
+ type: "workflow.completed",
290
+ result: parsedOutput.data,
291
+ workflowId,
292
+ });
293
+ return parsedOutput.data;
294
+ }
295
+ assertJsonSerializable(result);
296
+ await events.emit({ type: "workflow.completed", result, workflowId });
297
+ return result;
298
+ }
299
+ catch (cause) {
300
+ const error = contextualizeAutomationError(cause, "WORKFLOW_EXECUTION_FAILED", "The Workflow execution failed unexpectedly.", { workflowId });
301
+ if (!events.failed) {
302
+ await events.emit({
303
+ type: "workflow.failed",
304
+ error: automationErrorDetails(error),
305
+ workflowId,
306
+ });
307
+ }
308
+ throw error;
309
+ }
310
+ }
311
+ function createExecutionCancellation(externalSignal) {
312
+ const controller = new AbortController();
313
+ if (externalSignal === undefined) {
314
+ return {
315
+ abort: (reason) => controller.abort(reason),
316
+ dispose() { },
317
+ signal: controller.signal,
318
+ };
319
+ }
320
+ if (!(externalSignal instanceof AbortSignal)) {
321
+ throw new TypeError("Workflow signal must be an AbortSignal.");
322
+ }
323
+ const cancel = () => controller.abort(new AutomationError("RUN_CANCELLED", "The Workflow was cancelled."));
324
+ externalSignal.addEventListener("abort", cancel, { once: true });
325
+ if (externalSignal.aborted) {
326
+ cancel();
327
+ }
328
+ return {
329
+ abort: (reason) => controller.abort(reason),
330
+ dispose: () => externalSignal.removeEventListener("abort", cancel),
331
+ signal: controller.signal,
332
+ };
333
+ }
334
+ function runJournalMode(value) {
335
+ if (value === undefined) {
336
+ return "metadata";
337
+ }
338
+ if (value === false || value === "full" || value === "metadata") {
339
+ return value;
340
+ }
341
+ throw new TypeError("Workflow record mode must be metadata, full, or false.");
342
+ }
343
+ function awaitWorkflowOrCancellation(workflowExecution, signal, activeRuns) {
344
+ return new Promise((resolve, reject) => {
345
+ let terminal = false;
346
+ const cancel = () => {
347
+ if (terminal) {
348
+ return;
349
+ }
350
+ terminal = true;
351
+ signal.removeEventListener("abort", cancel);
352
+ void Promise.allSettled([...activeRuns]).then(() => reject(signal.reason));
353
+ };
354
+ signal.addEventListener("abort", cancel, { once: true });
355
+ if (signal.aborted) {
356
+ cancel();
357
+ }
358
+ void workflowExecution.then((result) => {
359
+ if (terminal) {
360
+ return;
361
+ }
362
+ terminal = true;
363
+ signal.removeEventListener("abort", cancel);
364
+ resolve(result);
365
+ }, (cause) => {
366
+ if (terminal) {
367
+ return;
368
+ }
369
+ terminal = true;
370
+ signal.removeEventListener("abort", cancel);
371
+ reject(cause);
372
+ });
373
+ });
374
+ }
375
+ function isAccessPolicy(value) {
376
+ return value === "read" || value === "write-workspace" || value === "full";
377
+ }
378
+ function isApprovalPolicy(value) {
379
+ return value === "deny" || value === "auto";
380
+ }
381
+ function isRunTimeout(value) {
382
+ return (value === undefined ||
383
+ value === false ||
384
+ (typeof value === "number" && Number.isFinite(value) && value > 0));
385
+ }
386
+ function isRunInterruption(error) {
387
+ return error.code === "RUN_CANCELLED" || error.code === "RUN_TIMED_OUT";
388
+ }
389
+ async function resolveRunWorkingDirectory(workspaceRoot, cwd) {
390
+ if (cwd !== undefined && typeof cwd !== "string") {
391
+ throw new AutomationError("RUN_CWD_INVALID", "A Run cwd must be a path relative to the Workspace root.");
392
+ }
393
+ if (typeof cwd === "string" && path.isAbsolute(cwd)) {
394
+ throw new AutomationError("RUN_CWD_INVALID", "A Run cwd must be relative to the Workspace root.");
395
+ }
396
+ const candidate = path.resolve(workspaceRoot, cwd ?? ".");
397
+ if (!isWithinDirectory(workspaceRoot, candidate)) {
398
+ throw new AutomationError("RUN_CWD_INVALID", "A Run cwd must stay within the Workspace root.");
399
+ }
400
+ let canonicalWorkspace;
401
+ let canonicalCandidate;
402
+ try {
403
+ [canonicalWorkspace, canonicalCandidate] = await Promise.all([
404
+ realpath(workspaceRoot),
405
+ realpath(candidate),
406
+ ]);
407
+ }
408
+ catch (cause) {
409
+ throw new AutomationError("RUN_CWD_INVALID", "A Run cwd must resolve to an existing directory in the Workspace.", { cause });
410
+ }
411
+ if (!isWithinDirectory(canonicalWorkspace, canonicalCandidate)) {
412
+ throw new AutomationError("RUN_CWD_INVALID", "A Run cwd must not resolve outside the Workspace root.");
413
+ }
414
+ try {
415
+ if (!(await stat(canonicalCandidate)).isDirectory()) {
416
+ throw new TypeError("The Run cwd is not a directory.");
417
+ }
418
+ }
419
+ catch (cause) {
420
+ throw new AutomationError("RUN_CWD_INVALID", "A Run cwd must resolve to an existing directory in the Workspace.", { cause });
421
+ }
422
+ return {
423
+ workspaceRoot: canonicalWorkspace,
424
+ workingDirectory: canonicalCandidate,
425
+ };
426
+ }
427
+ function createRunEnvironment(overrides) {
428
+ const environment = { ...process.env };
429
+ if (overrides === undefined) {
430
+ return environment;
431
+ }
432
+ if (typeof overrides !== "object" || overrides === null) {
433
+ throw new AutomationError("RUN_POLICY_INVALID", "Run environment overrides must be an object.");
434
+ }
435
+ for (const [name, value] of Object.entries(overrides)) {
436
+ if (value === undefined) {
437
+ delete environment[name];
438
+ }
439
+ else if (typeof value === "string") {
440
+ environment[name] = value;
441
+ }
442
+ else {
443
+ throw new AutomationError("RUN_POLICY_INVALID", "Run environment values must be strings or undefined.");
444
+ }
445
+ }
446
+ return environment;
447
+ }
448
+ function mergeEnvironmentOverrides(sessionEnvironment, runEnvironment) {
449
+ if (sessionEnvironment === undefined) {
450
+ return runEnvironment;
451
+ }
452
+ if (runEnvironment === undefined) {
453
+ return sessionEnvironment;
454
+ }
455
+ return Object.freeze({ ...sessionEnvironment, ...runEnvironment });
456
+ }
457
+ function assertJsonSerializable(result) {
458
+ if (result === undefined) {
459
+ return;
460
+ }
461
+ try {
462
+ assertJsonValue(result, new Set());
463
+ }
464
+ catch (cause) {
465
+ throw new AutomationError("WORKFLOW_OUTPUT_INVALID", "The Workflow Result must be JSON-serializable.", { cause });
466
+ }
467
+ }
468
+ function assertJsonValue(value, ancestors) {
469
+ if (value === null ||
470
+ typeof value === "boolean" ||
471
+ typeof value === "string") {
472
+ return;
473
+ }
474
+ if (typeof value === "number") {
475
+ if (!Number.isFinite(value)) {
476
+ throw new TypeError("JSON numbers must be finite.");
477
+ }
478
+ return;
479
+ }
480
+ if (typeof value !== "object") {
481
+ throw new TypeError(`Unsupported JSON value: ${typeof value}.`);
482
+ }
483
+ if (ancestors.has(value)) {
484
+ throw new TypeError("Circular references are not JSON-serializable.");
485
+ }
486
+ ancestors.add(value);
487
+ try {
488
+ if (Array.isArray(value)) {
489
+ assertJsonArray(value, ancestors);
490
+ return;
491
+ }
492
+ const prototype = Object.getPrototypeOf(value);
493
+ if (prototype !== Object.prototype && prototype !== null) {
494
+ throw new TypeError("JSON objects must have a plain object prototype.");
495
+ }
496
+ for (const key of Reflect.ownKeys(value)) {
497
+ if (typeof key === "symbol") {
498
+ throw new TypeError("JSON objects cannot contain symbol keys.");
499
+ }
500
+ const descriptor = Object.getOwnPropertyDescriptor(value, key);
501
+ if (descriptor?.enumerable !== true) {
502
+ throw new TypeError("JSON object properties must be enumerable.");
503
+ }
504
+ assertJsonValue(Reflect.get(value, key), ancestors);
505
+ }
506
+ }
507
+ finally {
508
+ ancestors.delete(value);
509
+ }
510
+ }
511
+ function assertJsonArray(value, ancestors) {
512
+ for (const key of Reflect.ownKeys(value)) {
513
+ if (key === "length") {
514
+ continue;
515
+ }
516
+ if (typeof key === "symbol" ||
517
+ !Number.isInteger(Number(key)) ||
518
+ String(Number(key)) !== key ||
519
+ Number(key) < 0 ||
520
+ Number(key) >= value.length) {
521
+ throw new TypeError("JSON arrays cannot contain extra properties.");
522
+ }
523
+ }
524
+ for (let index = 0; index < value.length; index += 1) {
525
+ if (!Object.hasOwn(value, index)) {
526
+ throw new TypeError("Sparse arrays are not JSON-serializable.");
527
+ }
528
+ assertJsonValue(value[index], ancestors);
529
+ }
530
+ }
package/package.json ADDED
@@ -0,0 +1,51 @@
1
+ {
2
+ "name": "@nyxa/automation",
3
+ "version": "0.1.0",
4
+ "description": "Execute trusted TypeScript Workflows with local Harness CLIs.",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "https://github.com/Nyxa07/automation.git"
8
+ },
9
+ "homepage": "https://github.com/Nyxa07/automation#readme",
10
+ "bugs": {
11
+ "url": "https://github.com/Nyxa07/automation/issues"
12
+ },
13
+ "type": "module",
14
+ "engines": {
15
+ "node": ">=22"
16
+ },
17
+ "exports": {
18
+ ".": {
19
+ "types": "./dist/index.d.ts",
20
+ "import": "./dist/index.js"
21
+ }
22
+ },
23
+ "bin": {
24
+ "automation": "./dist/cli.js"
25
+ },
26
+ "files": [
27
+ "dist/**/*.d.ts",
28
+ "dist/**/*.js",
29
+ "README.md"
30
+ ],
31
+ "publishConfig": {
32
+ "access": "public",
33
+ "registry": "https://registry.npmjs.org/"
34
+ },
35
+ "scripts": {
36
+ "build": "tsc -p tsconfig.build.json",
37
+ "prepack": "npm run build",
38
+ "typecheck": "tsc -p tsconfig.json --noEmit",
39
+ "test": "npm run build && node --test tests/**/*.test.js && npm run test:types",
40
+ "test:integration": "npm run build && node --test tests/integration/*.test.js",
41
+ "test:types": "npm run build && tsc -p tests/types/tsconfig.json"
42
+ },
43
+ "dependencies": {
44
+ "@agentclientprotocol/sdk": "^0.23.0",
45
+ "tsx": "^4.23.1"
46
+ },
47
+ "devDependencies": {
48
+ "@types/node": "^22.20.1",
49
+ "typescript": "^7.0.2"
50
+ }
51
+ }