@sapiom/agent-core 0.6.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.
- package/CHANGELOG.md +246 -0
- package/LICENSE +21 -0
- package/dist/cjs/__tests__/execution-detail.wire.fixture.json +101 -0
- package/dist/cjs/__tests__/execution-projection.preseam.fixture.json +37 -0
- package/dist/cjs/__tests__/execution-projection.with-cost.fixture.json +60 -0
- package/dist/cjs/bundle.d.ts +5 -0
- package/dist/cjs/bundle.js +134 -0
- package/dist/cjs/check.d.ts +10 -0
- package/dist/cjs/check.js +154 -0
- package/dist/cjs/client.d.ts +21 -0
- package/dist/cjs/client.js +108 -0
- package/dist/cjs/clone.d.ts +17 -0
- package/dist/cjs/clone.js +71 -0
- package/dist/cjs/config.d.ts +16 -0
- package/dist/cjs/config.js +40 -0
- package/dist/cjs/decode.d.ts +4 -0
- package/dist/cjs/decode.js +172 -0
- package/dist/cjs/deploy.d.ts +12 -0
- package/dist/cjs/deploy.js +67 -0
- package/dist/cjs/errors.d.ts +15 -0
- package/dist/cjs/errors.js +23 -0
- package/dist/cjs/git.d.ts +12 -0
- package/dist/cjs/git.js +76 -0
- package/dist/cjs/index.d.ts +41 -0
- package/dist/cjs/index.js +72 -0
- package/dist/cjs/inspect.d.ts +40 -0
- package/dist/cjs/inspect.js +99 -0
- package/dist/cjs/link.d.ts +15 -0
- package/dist/cjs/link.js +19 -0
- package/dist/cjs/local/dispatcher.d.ts +37 -0
- package/dist/cjs/local/dispatcher.js +149 -0
- package/dist/cjs/local/load.d.ts +6 -0
- package/dist/cjs/local/load.js +102 -0
- package/dist/cjs/local/run-local.d.ts +32 -0
- package/dist/cjs/local/run-local.js +95 -0
- package/dist/cjs/local/stubs.d.ts +8 -0
- package/dist/cjs/local/stubs.js +35 -0
- package/dist/cjs/run.d.ts +11 -0
- package/dist/cjs/run.js +29 -0
- package/dist/cjs/scaffold.d.ts +24 -0
- package/dist/cjs/scaffold.js +190 -0
- package/dist/cjs/schedule.d.ts +67 -0
- package/dist/cjs/schedule.js +33 -0
- package/dist/cjs/signal.d.ts +12 -0
- package/dist/cjs/signal.js +24 -0
- package/dist/cjs/types.d.ts +99 -0
- package/dist/cjs/types.js +11 -0
- package/dist/cjs/watch.d.ts +10 -0
- package/dist/cjs/watch.js +101 -0
- package/dist/esm/__tests__/execution-detail.wire.fixture.json +101 -0
- package/dist/esm/__tests__/execution-projection.preseam.fixture.json +37 -0
- package/dist/esm/__tests__/execution-projection.with-cost.fixture.json +60 -0
- package/dist/esm/bundle.d.ts +5 -0
- package/dist/esm/bundle.js +95 -0
- package/dist/esm/check.d.ts +10 -0
- package/dist/esm/check.js +115 -0
- package/dist/esm/client.d.ts +21 -0
- package/dist/esm/client.js +103 -0
- package/dist/esm/clone.d.ts +17 -0
- package/dist/esm/clone.js +65 -0
- package/dist/esm/config.d.ts +16 -0
- package/dist/esm/config.js +31 -0
- package/dist/esm/decode.d.ts +4 -0
- package/dist/esm/decode.js +167 -0
- package/dist/esm/deploy.d.ts +12 -0
- package/dist/esm/deploy.js +61 -0
- package/dist/esm/errors.d.ts +15 -0
- package/dist/esm/errors.js +19 -0
- package/dist/esm/git.d.ts +12 -0
- package/dist/esm/git.js +69 -0
- package/dist/esm/index.d.ts +41 -0
- package/dist/esm/index.js +21 -0
- package/dist/esm/inspect.d.ts +40 -0
- package/dist/esm/inspect.js +92 -0
- package/dist/esm/link.d.ts +15 -0
- package/dist/esm/link.js +16 -0
- package/dist/esm/local/dispatcher.d.ts +37 -0
- package/dist/esm/local/dispatcher.js +145 -0
- package/dist/esm/local/load.d.ts +6 -0
- package/dist/esm/local/load.js +63 -0
- package/dist/esm/local/run-local.d.ts +32 -0
- package/dist/esm/local/run-local.js +87 -0
- package/dist/esm/local/stubs.d.ts +8 -0
- package/dist/esm/local/stubs.js +31 -0
- package/dist/esm/package.json +1 -0
- package/dist/esm/run.d.ts +11 -0
- package/dist/esm/run.js +25 -0
- package/dist/esm/scaffold.d.ts +24 -0
- package/dist/esm/scaffold.js +179 -0
- package/dist/esm/schedule.d.ts +67 -0
- package/dist/esm/schedule.js +26 -0
- package/dist/esm/signal.d.ts +12 -0
- package/dist/esm/signal.js +20 -0
- package/dist/esm/types.d.ts +99 -0
- package/dist/esm/types.js +8 -0
- package/dist/esm/watch.d.ts +10 -0
- package/dist/esm/watch.js +96 -0
- package/dist/tsconfig.cjs.tsbuildinfo +1 -0
- package/dist/tsconfig.esm.tsbuildinfo +1 -0
- package/package.json +73 -0
- package/templates/coding-pause/AGENTS.md +48 -0
- package/templates/coding-pause/CLAUDE.md +7 -0
- package/templates/coding-pause/README.md +53 -0
- package/templates/coding-pause/_gitignore +3 -0
- package/templates/coding-pause/index.ts +109 -0
- package/templates/coding-pause/package.json +21 -0
- package/templates/coding-pause/tsconfig.json +12 -0
- package/templates/default/AGENTS.md +48 -0
- package/templates/default/CLAUDE.md +7 -0
- package/templates/default/README.md +30 -0
- package/templates/default/_gitignore +3 -0
- package/templates/default/index.ts +26 -0
- package/templates/default/package.json +21 -0
- package/templates/default/tsconfig.json +12 -0
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
+
};
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.check = check;
|
|
40
|
+
const node_child_process_1 = require("node:child_process");
|
|
41
|
+
const node_crypto_1 = require("node:crypto");
|
|
42
|
+
const node_fs_1 = require("node:fs");
|
|
43
|
+
const node_os_1 = require("node:os");
|
|
44
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
45
|
+
const agent_1 = require("@sapiom/agent");
|
|
46
|
+
const esbuild = __importStar(require("esbuild"));
|
|
47
|
+
const errors_js_1 = require("./errors.js");
|
|
48
|
+
function runTypecheck(sourceDir) {
|
|
49
|
+
const tscBin = node_path_1.default.join(sourceDir, 'node_modules', '.bin', 'tsc');
|
|
50
|
+
if (!(0, node_fs_1.existsSync)(tscBin)) {
|
|
51
|
+
return 'typecheck skipped — TypeScript is not installed (run npm install first)';
|
|
52
|
+
}
|
|
53
|
+
try {
|
|
54
|
+
(0, node_child_process_1.execFileSync)(tscBin, ['--noEmit'], { cwd: sourceDir, stdio: ['ignore', 'pipe', 'pipe'] });
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
catch (err) {
|
|
58
|
+
const e = err;
|
|
59
|
+
const output = (e.stdout?.toString() ?? '').trim() || (e.stderr?.toString() ?? '').trim();
|
|
60
|
+
throw new errors_js_1.AgentOperationError({
|
|
61
|
+
code: 'TYPECHECK_FAILED',
|
|
62
|
+
message: 'The agent has type errors.',
|
|
63
|
+
hint: output || 'Run `tsc --noEmit` for details.',
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
const LOCAL_SDK_VERSION = '0.0.0-local';
|
|
68
|
+
async function check(opts) {
|
|
69
|
+
const { sourceDir } = opts;
|
|
70
|
+
const entryFile = node_path_1.default.join(sourceDir, 'index.ts');
|
|
71
|
+
if (!(0, node_fs_1.existsSync)(entryFile)) {
|
|
72
|
+
throw new errors_js_1.AgentOperationError({
|
|
73
|
+
code: 'NO_ENTRY',
|
|
74
|
+
message: `No index.ts found in ${sourceDir}.`,
|
|
75
|
+
hint: 'Run this from an agent project, or pass its directory.',
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
const warnings = [];
|
|
79
|
+
const typecheckSkip = runTypecheck(sourceDir);
|
|
80
|
+
if (typecheckSkip)
|
|
81
|
+
warnings.push(typecheckSkip);
|
|
82
|
+
const tmp = (0, node_fs_1.mkdtempSync)(node_path_1.default.join((0, node_os_1.tmpdir)(), 'sapiom-check-'));
|
|
83
|
+
const bundlePath = node_path_1.default.join(tmp, 'definition.mjs');
|
|
84
|
+
try {
|
|
85
|
+
try {
|
|
86
|
+
await esbuild.build({
|
|
87
|
+
entryPoints: [entryFile],
|
|
88
|
+
outfile: bundlePath,
|
|
89
|
+
bundle: true,
|
|
90
|
+
platform: 'node',
|
|
91
|
+
target: 'node20',
|
|
92
|
+
format: 'esm',
|
|
93
|
+
logLevel: 'silent',
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
catch (err) {
|
|
97
|
+
throw new errors_js_1.AgentOperationError({
|
|
98
|
+
code: 'BUNDLE_FAILED',
|
|
99
|
+
message: 'Failed to bundle the agent.',
|
|
100
|
+
hint: err instanceof Error ? err.message : String(err),
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
const mod = await Promise.resolve(`${`file://${bundlePath}?t=${Date.now()}`}`).then(s => __importStar(require(s)));
|
|
104
|
+
const defs = [];
|
|
105
|
+
for (const value of Object.values(mod)) {
|
|
106
|
+
if ((0, agent_1.isAgentDefinition)(value) && !defs.includes(value))
|
|
107
|
+
defs.push(value);
|
|
108
|
+
}
|
|
109
|
+
if (defs.length === 0) {
|
|
110
|
+
throw new errors_js_1.AgentOperationError({
|
|
111
|
+
code: 'NO_DEFINITION',
|
|
112
|
+
message: 'No agent was exported from index.ts.',
|
|
113
|
+
hint: 'Export the result of defineAgent({ … }).',
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
if (defs.length > 1) {
|
|
117
|
+
throw new errors_js_1.AgentOperationError({
|
|
118
|
+
code: 'MULTIPLE_DEFINITIONS',
|
|
119
|
+
message: 'index.ts exports more than one agent.',
|
|
120
|
+
hint: 'Export exactly one defineAgent({ … }) result.',
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
const def = defs[0];
|
|
124
|
+
const sha256 = (0, node_crypto_1.createHash)('sha256').update((0, node_fs_1.readFileSync)(bundlePath)).digest('hex');
|
|
125
|
+
let manifest;
|
|
126
|
+
try {
|
|
127
|
+
manifest = agent_1.agentManifestSchema.parse((0, agent_1.buildManifest)(def, { sdkVersion: LOCAL_SDK_VERSION, artifact: { sha256, entryFile: 'definition.mjs' } }));
|
|
128
|
+
}
|
|
129
|
+
catch (err) {
|
|
130
|
+
throw new errors_js_1.AgentOperationError({
|
|
131
|
+
code: 'MANIFEST_INVALID',
|
|
132
|
+
message: 'The agent produced an invalid manifest.',
|
|
133
|
+
hint: err instanceof Error ? err.message : String(err),
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
try {
|
|
137
|
+
warnings.push(...(0, agent_1.assertValidGraph)(manifest));
|
|
138
|
+
}
|
|
139
|
+
catch (err) {
|
|
140
|
+
throw new errors_js_1.AgentOperationError({
|
|
141
|
+
code: 'GRAPH_INVALID',
|
|
142
|
+
message: 'The agent graph is invalid.',
|
|
143
|
+
hint: err instanceof Error ? err.message : String(err),
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
const steps = manifest.steps;
|
|
147
|
+
const stepCount = Array.isArray(steps) ? steps.length : Object.keys(steps ?? {}).length;
|
|
148
|
+
const name = manifest.name ?? 'agent';
|
|
149
|
+
return { name, stepCount, warnings, manifest };
|
|
150
|
+
}
|
|
151
|
+
finally {
|
|
152
|
+
(0, node_fs_1.rmSync)(tmp, { recursive: true, force: true });
|
|
153
|
+
}
|
|
154
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export declare const DEFAULT_WORKFLOWS_HOST = "https://api.sapiom.ai";
|
|
2
|
+
export interface ClientOptions {
|
|
3
|
+
host?: string;
|
|
4
|
+
apiKey: string;
|
|
5
|
+
}
|
|
6
|
+
export interface GatewayErrorBody {
|
|
7
|
+
message?: string | string[];
|
|
8
|
+
}
|
|
9
|
+
export declare class GatewayClient {
|
|
10
|
+
private readonly base;
|
|
11
|
+
private readonly apiKey;
|
|
12
|
+
constructor(opts: ClientOptions);
|
|
13
|
+
request<T = unknown>(method: string, path: string, body?: unknown): Promise<T>;
|
|
14
|
+
get<T = unknown>(path: string): Promise<T>;
|
|
15
|
+
post<T = unknown>(path: string, body?: unknown): Promise<T>;
|
|
16
|
+
openStream(path: string, opts?: {
|
|
17
|
+
signal?: AbortSignal;
|
|
18
|
+
lastEventId?: string;
|
|
19
|
+
}): Promise<Response>;
|
|
20
|
+
}
|
|
21
|
+
export declare function createClient(opts: ClientOptions): GatewayClient;
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.GatewayClient = exports.DEFAULT_WORKFLOWS_HOST = void 0;
|
|
4
|
+
exports.createClient = createClient;
|
|
5
|
+
const errors_js_1 = require("./errors.js");
|
|
6
|
+
exports.DEFAULT_WORKFLOWS_HOST = 'https://api.sapiom.ai';
|
|
7
|
+
class GatewayClient {
|
|
8
|
+
constructor(opts) {
|
|
9
|
+
const host = (opts.host ?? exports.DEFAULT_WORKFLOWS_HOST).replace(/\/$/, '');
|
|
10
|
+
this.base = `${host}/v1/workflows`;
|
|
11
|
+
this.apiKey = opts.apiKey;
|
|
12
|
+
}
|
|
13
|
+
async request(method, path, body) {
|
|
14
|
+
let res;
|
|
15
|
+
try {
|
|
16
|
+
res = await fetch(`${this.base}${path}`, {
|
|
17
|
+
method,
|
|
18
|
+
headers: { 'x-api-key': this.apiKey, 'content-type': 'application/json' },
|
|
19
|
+
body: body === undefined ? undefined : JSON.stringify(body),
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
catch (err) {
|
|
23
|
+
throw new errors_js_1.AgentOperationError({
|
|
24
|
+
code: 'NETWORK',
|
|
25
|
+
message: `Could not reach ${this.base}.`,
|
|
26
|
+
hint: err instanceof Error ? err.message : String(err),
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
const text = await res.text();
|
|
30
|
+
const data = text ? safeParse(text) : undefined;
|
|
31
|
+
if (!res.ok) {
|
|
32
|
+
throw new errors_js_1.AgentOperationError({
|
|
33
|
+
code: `HTTP_${res.status}`,
|
|
34
|
+
message: messageFrom(data) ?? `Request failed (${res.status} ${res.statusText}).`,
|
|
35
|
+
hint: res.status === 401 || res.status === 403
|
|
36
|
+
? 'Check your API key (`sapiom login` or SAPIOM_API_KEY) and that it has access to this agent.'
|
|
37
|
+
: undefined,
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
return data;
|
|
41
|
+
}
|
|
42
|
+
get(path) {
|
|
43
|
+
return this.request('GET', path);
|
|
44
|
+
}
|
|
45
|
+
post(path, body) {
|
|
46
|
+
return this.request('POST', path, body);
|
|
47
|
+
}
|
|
48
|
+
async openStream(path, opts = {}) {
|
|
49
|
+
const headers = {
|
|
50
|
+
'x-api-key': this.apiKey,
|
|
51
|
+
accept: 'text/event-stream',
|
|
52
|
+
};
|
|
53
|
+
if (opts.lastEventId) {
|
|
54
|
+
headers['last-event-id'] = opts.lastEventId;
|
|
55
|
+
}
|
|
56
|
+
let res;
|
|
57
|
+
try {
|
|
58
|
+
res = await fetch(`${this.base}${path}`, { method: 'GET', headers, signal: opts.signal });
|
|
59
|
+
}
|
|
60
|
+
catch (err) {
|
|
61
|
+
throw new errors_js_1.AgentOperationError({
|
|
62
|
+
code: 'NETWORK',
|
|
63
|
+
message: `Could not reach ${this.base}.`,
|
|
64
|
+
hint: err instanceof Error ? err.message : String(err),
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
if (!res.ok) {
|
|
68
|
+
const text = await res.text().catch(() => '');
|
|
69
|
+
const data = text ? safeParse(text) : undefined;
|
|
70
|
+
throw new errors_js_1.AgentOperationError({
|
|
71
|
+
code: `HTTP_${res.status}`,
|
|
72
|
+
message: messageFrom(data) ?? `Stream request failed (${res.status} ${res.statusText}).`,
|
|
73
|
+
hint: res.status === 401 || res.status === 403
|
|
74
|
+
? 'Check your API key (`sapiom login` or SAPIOM_API_KEY) and that it has access to this agent.'
|
|
75
|
+
: undefined,
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
if (!res.body) {
|
|
79
|
+
throw new errors_js_1.AgentOperationError({
|
|
80
|
+
code: 'NETWORK',
|
|
81
|
+
message: `Stream at ${this.base}${path} returned no body.`,
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
return res;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
exports.GatewayClient = GatewayClient;
|
|
88
|
+
function createClient(opts) {
|
|
89
|
+
return new GatewayClient(opts);
|
|
90
|
+
}
|
|
91
|
+
function safeParse(text) {
|
|
92
|
+
try {
|
|
93
|
+
return JSON.parse(text);
|
|
94
|
+
}
|
|
95
|
+
catch {
|
|
96
|
+
return text;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
function messageFrom(data) {
|
|
100
|
+
if (data && typeof data === 'object' && 'message' in data) {
|
|
101
|
+
const m = data.message;
|
|
102
|
+
if (Array.isArray(m))
|
|
103
|
+
return m.join('; ');
|
|
104
|
+
if (typeof m === 'string')
|
|
105
|
+
return m;
|
|
106
|
+
}
|
|
107
|
+
return undefined;
|
|
108
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { GatewayClient } from './client.js';
|
|
2
|
+
import { type CloneRepoOptions } from './git.js';
|
|
3
|
+
export interface CloneOptions {
|
|
4
|
+
templateId?: string;
|
|
5
|
+
forkId?: string;
|
|
6
|
+
targetDir: string;
|
|
7
|
+
cloneRepo?: (opts: CloneRepoOptions) => void;
|
|
8
|
+
}
|
|
9
|
+
export interface CloneResult {
|
|
10
|
+
forkId: string;
|
|
11
|
+
templateId?: string;
|
|
12
|
+
repoFullName: string;
|
|
13
|
+
defaultBranch: string;
|
|
14
|
+
targetDir: string;
|
|
15
|
+
tokenExpiresAt: string;
|
|
16
|
+
}
|
|
17
|
+
export declare function clone(opts: CloneOptions, client: GatewayClient): Promise<CloneResult>;
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.clone = clone;
|
|
7
|
+
const node_fs_1 = require("node:fs");
|
|
8
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
9
|
+
const config_js_1 = require("./config.js");
|
|
10
|
+
const errors_js_1 = require("./errors.js");
|
|
11
|
+
const git_js_1 = require("./git.js");
|
|
12
|
+
async function clone(opts, client) {
|
|
13
|
+
const { templateId, forkId, targetDir } = opts;
|
|
14
|
+
const runClone = opts.cloneRepo ?? git_js_1.cloneRepo;
|
|
15
|
+
if (!templateId && !forkId) {
|
|
16
|
+
throw new errors_js_1.AgentOperationError({
|
|
17
|
+
code: 'BAD_INPUT',
|
|
18
|
+
message: 'Provide a templateId (to fork then clone) or a forkId (to clone an existing fork).',
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
if (templateId && forkId) {
|
|
22
|
+
throw new errors_js_1.AgentOperationError({
|
|
23
|
+
code: 'BAD_INPUT',
|
|
24
|
+
message: 'Provide only one of templateId or forkId, not both.',
|
|
25
|
+
hint: 'Use templateId to start from a gallery template, or forkId to re-clone an existing fork.',
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
if ((0, node_fs_1.existsSync)(targetDir) && (0, node_fs_1.readdirSync)(targetDir).length > 0) {
|
|
29
|
+
throw new errors_js_1.AgentOperationError({
|
|
30
|
+
code: 'DIR_NOT_EMPTY',
|
|
31
|
+
message: `Target directory '${targetDir}' already exists and is not empty.`,
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
let resolvedForkId = forkId ?? '';
|
|
35
|
+
let resolvedTemplateId = templateId;
|
|
36
|
+
if (templateId) {
|
|
37
|
+
const fork = await client.post(`/templates/${encodeURIComponent(templateId)}/fork`, {});
|
|
38
|
+
resolvedForkId = fork.id;
|
|
39
|
+
resolvedTemplateId = fork.templateId;
|
|
40
|
+
}
|
|
41
|
+
const token = await client.post(`/forks/${encodeURIComponent(resolvedForkId)}/clone-token`, {});
|
|
42
|
+
if (!token.cloneUrl.startsWith('https://')) {
|
|
43
|
+
throw new errors_js_1.AgentOperationError({
|
|
44
|
+
code: 'BAD_CLONE_URL',
|
|
45
|
+
message: 'The clone token endpoint returned an unexpected clone URL.',
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
const parent = node_path_1.default.dirname(node_path_1.default.resolve(targetDir));
|
|
49
|
+
(0, node_fs_1.mkdirSync)(parent, { recursive: true });
|
|
50
|
+
runClone({
|
|
51
|
+
cloneUrl: token.cloneUrl,
|
|
52
|
+
targetDir,
|
|
53
|
+
branch: token.defaultBranch,
|
|
54
|
+
repoFullName: token.repoFullName,
|
|
55
|
+
cwd: parent,
|
|
56
|
+
});
|
|
57
|
+
(0, config_js_1.writeConfig)(targetDir, {
|
|
58
|
+
repoFullName: token.repoFullName,
|
|
59
|
+
defaultBranch: token.defaultBranch,
|
|
60
|
+
forkId: resolvedForkId,
|
|
61
|
+
...(resolvedTemplateId ? { templateId: resolvedTemplateId } : {}),
|
|
62
|
+
});
|
|
63
|
+
return {
|
|
64
|
+
forkId: resolvedForkId,
|
|
65
|
+
...(resolvedTemplateId ? { templateId: resolvedTemplateId } : {}),
|
|
66
|
+
repoFullName: token.repoFullName,
|
|
67
|
+
defaultBranch: token.defaultBranch,
|
|
68
|
+
targetDir,
|
|
69
|
+
tokenExpiresAt: token.expiresAt,
|
|
70
|
+
};
|
|
71
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export declare const CONFIG_FILE = "sapiom.json";
|
|
2
|
+
export interface SapiomConfig {
|
|
3
|
+
definitionId?: string;
|
|
4
|
+
name?: string;
|
|
5
|
+
host?: string;
|
|
6
|
+
templateId?: string;
|
|
7
|
+
forkId?: string;
|
|
8
|
+
repoFullName?: string;
|
|
9
|
+
defaultBranch?: string;
|
|
10
|
+
}
|
|
11
|
+
export declare function readConfig(dir: string): SapiomConfig | null;
|
|
12
|
+
export type LinkedSapiomConfig = SapiomConfig & {
|
|
13
|
+
definitionId: string;
|
|
14
|
+
};
|
|
15
|
+
export declare function requireConfig(dir: string): LinkedSapiomConfig;
|
|
16
|
+
export declare function writeConfig(dir: string, cfg: SapiomConfig): void;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.CONFIG_FILE = void 0;
|
|
7
|
+
exports.readConfig = readConfig;
|
|
8
|
+
exports.requireConfig = requireConfig;
|
|
9
|
+
exports.writeConfig = writeConfig;
|
|
10
|
+
const node_fs_1 = require("node:fs");
|
|
11
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
12
|
+
const errors_js_1 = require("./errors.js");
|
|
13
|
+
exports.CONFIG_FILE = 'sapiom.json';
|
|
14
|
+
function readConfig(dir) {
|
|
15
|
+
const file = node_path_1.default.join(dir, exports.CONFIG_FILE);
|
|
16
|
+
if (!(0, node_fs_1.existsSync)(file))
|
|
17
|
+
return null;
|
|
18
|
+
try {
|
|
19
|
+
return JSON.parse((0, node_fs_1.readFileSync)(file, 'utf8'));
|
|
20
|
+
}
|
|
21
|
+
catch {
|
|
22
|
+
throw new errors_js_1.AgentOperationError({ code: 'BAD_CONFIG', message: `${exports.CONFIG_FILE} is not valid JSON.` });
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
function requireConfig(dir) {
|
|
26
|
+
const cfg = readConfig(dir);
|
|
27
|
+
if (!cfg?.definitionId) {
|
|
28
|
+
throw new errors_js_1.AgentOperationError({
|
|
29
|
+
code: 'NOT_LINKED',
|
|
30
|
+
message: 'This project is not linked to a Sapiom agent.',
|
|
31
|
+
hint: 'Run: sapiom agents link <name>',
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
return cfg;
|
|
35
|
+
}
|
|
36
|
+
function writeConfig(dir, cfg) {
|
|
37
|
+
const existing = readConfig(dir) ?? {};
|
|
38
|
+
const merged = { ...existing, ...cfg };
|
|
39
|
+
(0, node_fs_1.writeFileSync)(node_path_1.default.join(dir, exports.CONFIG_FILE), JSON.stringify(merged, null, 2) + '\n');
|
|
40
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { CostNode, ExecutionProjection, ExecutionRef } from "./types.js";
|
|
2
|
+
export declare function decodeCostNode(raw: unknown): CostNode | null;
|
|
3
|
+
export declare function decodeExecutionRef(raw: unknown): ExecutionRef;
|
|
4
|
+
export declare function decodeExecutionProjection(raw: unknown): ExecutionProjection;
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.decodeCostNode = decodeCostNode;
|
|
4
|
+
exports.decodeExecutionRef = decodeExecutionRef;
|
|
5
|
+
exports.decodeExecutionProjection = decodeExecutionProjection;
|
|
6
|
+
function isRecord(v) {
|
|
7
|
+
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
8
|
+
}
|
|
9
|
+
function rec(v) {
|
|
10
|
+
return isRecord(v) ? v : {};
|
|
11
|
+
}
|
|
12
|
+
function str(fallback, ...candidates) {
|
|
13
|
+
for (const c of candidates)
|
|
14
|
+
if (typeof c === "string")
|
|
15
|
+
return c;
|
|
16
|
+
return fallback;
|
|
17
|
+
}
|
|
18
|
+
function strOrNull(...candidates) {
|
|
19
|
+
for (const c of candidates)
|
|
20
|
+
if (typeof c === "string")
|
|
21
|
+
return c;
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
function numOr(fallback, v) {
|
|
25
|
+
return typeof v === "number" && Number.isFinite(v) ? v : fallback;
|
|
26
|
+
}
|
|
27
|
+
function recordOrNull(v) {
|
|
28
|
+
return isRecord(v) ? v : null;
|
|
29
|
+
}
|
|
30
|
+
const SETTLE_STATES = ["pending", "settling", "final"];
|
|
31
|
+
function settleState(v) {
|
|
32
|
+
return typeof v === "string" && SETTLE_STATES.includes(v)
|
|
33
|
+
? v
|
|
34
|
+
: "final";
|
|
35
|
+
}
|
|
36
|
+
function decodeCostNode(raw) {
|
|
37
|
+
if (!isRecord(raw))
|
|
38
|
+
return null;
|
|
39
|
+
return {
|
|
40
|
+
authorizedUsd: str("0", raw.authorizedUsd),
|
|
41
|
+
capturedUsd: str("0", raw.capturedUsd),
|
|
42
|
+
settleState: settleState(raw.settleState),
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
function decodeStepErrorFrame(raw) {
|
|
46
|
+
const r = rec(raw);
|
|
47
|
+
const frame = {};
|
|
48
|
+
if (typeof r.function === "string")
|
|
49
|
+
frame.function = r.function;
|
|
50
|
+
if (typeof r.file === "string")
|
|
51
|
+
frame.file = r.file;
|
|
52
|
+
if (typeof r.line === "number")
|
|
53
|
+
frame.line = r.line;
|
|
54
|
+
if (typeof r.column === "number")
|
|
55
|
+
frame.column = r.column;
|
|
56
|
+
return frame;
|
|
57
|
+
}
|
|
58
|
+
function decodeStepErrorTrace(raw) {
|
|
59
|
+
if (typeof raw === "string") {
|
|
60
|
+
return { frames: [], sourceMapped: false, raw };
|
|
61
|
+
}
|
|
62
|
+
if (!isRecord(raw))
|
|
63
|
+
return null;
|
|
64
|
+
const trace = {
|
|
65
|
+
frames: Array.isArray(raw.frames) ? raw.frames.map(decodeStepErrorFrame) : [],
|
|
66
|
+
sourceMapped: raw.sourceMapped === true,
|
|
67
|
+
};
|
|
68
|
+
if (typeof raw.raw === "string")
|
|
69
|
+
trace.raw = raw.raw;
|
|
70
|
+
return trace;
|
|
71
|
+
}
|
|
72
|
+
function decodeStepError(raw) {
|
|
73
|
+
if (!isRecord(raw))
|
|
74
|
+
return null;
|
|
75
|
+
const message = strOrNull(raw.message);
|
|
76
|
+
if (message === null)
|
|
77
|
+
return null;
|
|
78
|
+
return {
|
|
79
|
+
message,
|
|
80
|
+
trace: decodeStepErrorTrace(raw.trace ?? raw.stack ?? null),
|
|
81
|
+
traceUnavailableReason: strOrNull(raw.traceUnavailableReason),
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
function decodeStepEvent(raw) {
|
|
85
|
+
const r = rec(raw);
|
|
86
|
+
return {
|
|
87
|
+
sourceId: str("", r.sourceId),
|
|
88
|
+
sequence: numOr(0, r.sequence),
|
|
89
|
+
kind: str("", r.kind),
|
|
90
|
+
payload: recordOrNull(r.payload) ?? {},
|
|
91
|
+
eventTs: strOrNull(r.eventTs),
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
function decodeDispatchRef(raw) {
|
|
95
|
+
if (!isRecord(raw))
|
|
96
|
+
return null;
|
|
97
|
+
return {
|
|
98
|
+
childExecutionId: str("", raw.childExecutionId, raw.targetId, raw.executionId),
|
|
99
|
+
targetType: str("", raw.targetType),
|
|
100
|
+
correlationId: str("", raw.correlationId),
|
|
101
|
+
status: str("", raw.status),
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
function decodeExecutionRef(raw) {
|
|
105
|
+
const r = rec(raw);
|
|
106
|
+
const executionId = str("", r.executionId, r.id);
|
|
107
|
+
return {
|
|
108
|
+
executionId,
|
|
109
|
+
traceRoot: str(executionId, r.traceRoot, r.rootExecutionId),
|
|
110
|
+
name: str("", r.name),
|
|
111
|
+
status: str("", r.status),
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
function decodeStep(raw) {
|
|
115
|
+
const r = rec(raw);
|
|
116
|
+
return {
|
|
117
|
+
stepName: str("", r.stepName),
|
|
118
|
+
stepOrder: numOr(0, r.stepOrder),
|
|
119
|
+
attempt: numOr(0, r.attempt),
|
|
120
|
+
status: str("", r.status),
|
|
121
|
+
spanId: strOrNull(r.spanId),
|
|
122
|
+
startedAt: strOrNull(r.startedAt),
|
|
123
|
+
finishedAt: strOrNull(r.finishedAt),
|
|
124
|
+
input: r.input ?? null,
|
|
125
|
+
output: r.output ?? null,
|
|
126
|
+
sharedStateAfter: recordOrNull(r.sharedStateAfter),
|
|
127
|
+
nextDirective: r.nextDirective ?? null,
|
|
128
|
+
cost: decodeCostNode(r.cost),
|
|
129
|
+
logs: r.logs ?? null,
|
|
130
|
+
events: Array.isArray(r.events) ? r.events.map(decodeStepEvent) : [],
|
|
131
|
+
error: decodeStepError(r.error),
|
|
132
|
+
dispatch: decodeDispatchRef(r.dispatch),
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
function decodeExecutionProjection(raw) {
|
|
136
|
+
const r = rec(raw);
|
|
137
|
+
const id = str("", r.id, r.executionId);
|
|
138
|
+
const traceRoot = str(id, r.traceRoot, r.rootExecutionId);
|
|
139
|
+
const traceParent = strOrNull(r.traceParent, r.parentExecutionId);
|
|
140
|
+
return {
|
|
141
|
+
id,
|
|
142
|
+
name: str("", r.name),
|
|
143
|
+
organizationId: strOrNull(r.organizationId),
|
|
144
|
+
tenantId: strOrNull(r.tenantId),
|
|
145
|
+
status: str("", r.status),
|
|
146
|
+
currentStep: strOrNull(r.currentStep),
|
|
147
|
+
currentStepAttempt: numOr(0, r.currentStepAttempt),
|
|
148
|
+
version: numOr(0, r.version),
|
|
149
|
+
definitionId: strOrNull(r.definitionId),
|
|
150
|
+
buildRunId: strOrNull(r.buildRunId),
|
|
151
|
+
idempotencyKey: strOrNull(r.idempotencyKey),
|
|
152
|
+
pausedSignalName: strOrNull(r.pausedSignalName),
|
|
153
|
+
pausedSignalCorrelationId: strOrNull(r.pausedSignalCorrelationId),
|
|
154
|
+
pausedUntil: strOrNull(r.pausedUntil),
|
|
155
|
+
startedAt: str("", r.startedAt),
|
|
156
|
+
finishedAt: strOrNull(r.finishedAt),
|
|
157
|
+
input: r.input ?? null,
|
|
158
|
+
sharedState: recordOrNull(r.sharedState) ?? {},
|
|
159
|
+
output: r.output ?? null,
|
|
160
|
+
error: r.error ?? null,
|
|
161
|
+
pausedStepInputSchema: recordOrNull(r.pausedStepInputSchema),
|
|
162
|
+
pausedStepInputExample: r.pausedStepInputExample ?? null,
|
|
163
|
+
traceRoot,
|
|
164
|
+
rootExecutionId: str(traceRoot, r.rootExecutionId, r.traceRoot),
|
|
165
|
+
traceParent,
|
|
166
|
+
parentExecutionId: strOrNull(r.parentExecutionId, r.traceParent),
|
|
167
|
+
traceId: strOrNull(r.traceId),
|
|
168
|
+
children: Array.isArray(r.children) ? r.children.map(decodeExecutionRef) : [],
|
|
169
|
+
cost: decodeCostNode(r.cost),
|
|
170
|
+
steps: Array.isArray(r.steps) ? r.steps.map(decodeStep) : [],
|
|
171
|
+
};
|
|
172
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { GatewayClient } from './client.js';
|
|
2
|
+
export interface DeployOptions {
|
|
3
|
+
projectDir: string;
|
|
4
|
+
definitionId: string;
|
|
5
|
+
branch?: string;
|
|
6
|
+
}
|
|
7
|
+
export interface DeployResult {
|
|
8
|
+
definitionId: string;
|
|
9
|
+
buildRunId: string;
|
|
10
|
+
status: string;
|
|
11
|
+
}
|
|
12
|
+
export declare function deploy(opts: DeployOptions, client: GatewayClient): Promise<DeployResult>;
|