@potential-agents/cli 0.0.0-stage → 0.1.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.
- package/LICENSE +21 -0
- package/README.md +83 -2
- package/dist/adapters/outbound/filesystem/bundle-filesystem-repository.d.ts +20 -0
- package/dist/adapters/outbound/filesystem/bundle-filesystem-repository.js +181 -0
- package/dist/adapters/outbound/filesystem/bundle-filesystem-repository.js.map +1 -0
- package/dist/adapters/outbound/filesystem/yaml-lock-repository.d.ts +7 -0
- package/dist/adapters/outbound/filesystem/yaml-lock-repository.js +64 -0
- package/dist/adapters/outbound/filesystem/yaml-lock-repository.js.map +1 -0
- package/dist/adapters/outbound/http/http-potential-agents-api.d.ts +36 -0
- package/dist/adapters/outbound/http/http-potential-agents-api.js +150 -0
- package/dist/adapters/outbound/http/http-potential-agents-api.js.map +1 -0
- package/dist/adapters/outbound/runtime/sha256-idempotency-key-generator.d.ts +5 -0
- package/dist/adapters/outbound/runtime/sha256-idempotency-key-generator.js +8 -0
- package/dist/adapters/outbound/runtime/sha256-idempotency-key-generator.js.map +1 -0
- package/dist/application/apply-bundle.d.ts +22 -0
- package/dist/application/apply-bundle.js +78 -0
- package/dist/application/apply-bundle.js.map +1 -0
- package/dist/application/plan-bundle.d.ts +18 -0
- package/dist/application/plan-bundle.js +22 -0
- package/dist/application/plan-bundle.js.map +1 -0
- package/dist/application/ports/bundle-repository.d.ts +6 -0
- package/dist/application/ports/bundle-repository.js +2 -0
- package/dist/application/ports/bundle-repository.js.map +1 -0
- package/dist/application/ports/idempotency-key-generator.d.ts +4 -0
- package/dist/application/ports/idempotency-key-generator.js +2 -0
- package/dist/application/ports/idempotency-key-generator.js.map +1 -0
- package/dist/application/ports/lock-repository.d.ts +6 -0
- package/dist/application/ports/lock-repository.js +2 -0
- package/dist/application/ports/lock-repository.js.map +1 -0
- package/dist/application/ports/potential-agents-api.d.ts +35 -0
- package/dist/application/ports/potential-agents-api.js +2 -0
- package/dist/application/ports/potential-agents-api.js.map +1 -0
- package/dist/application/run-agent.d.ts +14 -0
- package/dist/application/run-agent.js +20 -0
- package/dist/application/run-agent.js.map +1 -0
- package/dist/application/validate-bundle.d.ts +8 -0
- package/dist/application/validate-bundle.js +11 -0
- package/dist/application/validate-bundle.js.map +1 -0
- package/dist/cli.d.ts +4 -0
- package/dist/cli.js +120 -0
- package/dist/cli.js.map +1 -0
- package/dist/composition-root.d.ts +29 -0
- package/dist/composition-root.js +35 -0
- package/dist/composition-root.js.map +1 -0
- package/dist/domain/agent-definition.d.ts +40 -0
- package/dist/domain/agent-definition.js +94 -0
- package/dist/domain/agent-definition.js.map +1 -0
- package/dist/domain/bundle.d.ts +16 -0
- package/dist/domain/bundle.js +29 -0
- package/dist/domain/bundle.js.map +1 -0
- package/dist/domain/errors.d.ts +10 -0
- package/dist/domain/errors.js +16 -0
- package/dist/domain/errors.js.map +1 -0
- package/dist/domain/lock.d.ts +18 -0
- package/dist/domain/lock.js +2 -0
- package/dist/domain/lock.js.map +1 -0
- package/package.json +45 -4
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Potential Agents contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,84 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Potential Agents CLI
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
`p-agents` turns a reviewed `potential.md` into a managed Potential Agent revision. The bundle
|
|
4
|
+
contains only logical agent intent; runtime profile IDs, cloud infrastructure, secrets, images,
|
|
5
|
+
and IAM never enter the repository.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
After publication to npm:
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npm install -g @potential-agents/cli
|
|
13
|
+
p-agents validate
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
CI should pin the version it executes:
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
npx --yes @potential-agents/cli@0.1.0 validate
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Bundle
|
|
23
|
+
|
|
24
|
+
```md
|
|
25
|
+
---
|
|
26
|
+
apiVersion: potentialagents/v1alpha1
|
|
27
|
+
id: research-agent
|
|
28
|
+
name: Research Agent
|
|
29
|
+
engine: claude
|
|
30
|
+
model: claude-sonnet-4-6
|
|
31
|
+
tools: [Read, Glob, Grep]
|
|
32
|
+
browser: false
|
|
33
|
+
skills: []
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
Use evidence and identify uncertainty.
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Run `p-agents validate` without credentials. Connected commands require configuration outside
|
|
40
|
+
the bundle:
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
export POTENTIAL_AGENTS_API_URL=https://api.example.com
|
|
44
|
+
export POTENTIAL_AGENTS_ORGANIZATION=org_example
|
|
45
|
+
export POTENTIAL_AGENTS_TOKEN=short_lived_token
|
|
46
|
+
|
|
47
|
+
p-agents plan
|
|
48
|
+
p-agents apply
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
`apply` writes `potential.lock`. Commit that generated identity with the reviewed source bundle.
|
|
52
|
+
|
|
53
|
+
## Architecture
|
|
54
|
+
|
|
55
|
+
The implementation is intentionally hexagonal:
|
|
56
|
+
|
|
57
|
+
- `src/domain`: immutable values, invariants and deterministic hashes.
|
|
58
|
+
- `src/application`: SOLID use cases and small ports.
|
|
59
|
+
- `src/adapters`: Commander/terminal inbound adapter plus filesystem, YAML, HTTPS and runtime
|
|
60
|
+
outbound adapters.
|
|
61
|
+
- `src/composition-root.ts`: the only place concrete adapters are injected.
|
|
62
|
+
|
|
63
|
+
No application or domain code depends on Commander, Node filesystem APIs, `fetch`, environment
|
|
64
|
+
variables, or cloud SDKs.
|
|
65
|
+
|
|
66
|
+
## Development
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
npm ci
|
|
70
|
+
npm run typecheck
|
|
71
|
+
npm run build
|
|
72
|
+
npm test
|
|
73
|
+
npm pack --dry-run
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
The black-box test starts a disposable control-plane fixture and executes the compiled binary. It
|
|
77
|
+
verifies create, readiness, generated lockfile, no-op and run without a real cloud account.
|
|
78
|
+
|
|
79
|
+
## Releases
|
|
80
|
+
|
|
81
|
+
Tags in the form `v*` invoke `.github/workflows/publish.yml`. Configure npm Trusted Publishing
|
|
82
|
+
for `shinsekai-dev/potential-agents-cli` and `publish.yml`; the workflow uses GitHub OIDC and has
|
|
83
|
+
no long-lived npm publish token. The first package publication requires the npm scope to have
|
|
84
|
+
been claimed by a maintainer.
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { BundleRepository } from '../../../application/ports/bundle-repository.js';
|
|
2
|
+
import { Bundle } from '../../../domain/bundle.js';
|
|
3
|
+
/** Filesystem adapter that parses potential.md and produces deterministic skill hashes. */
|
|
4
|
+
export declare class FilesystemBundleRepository implements BundleRepository {
|
|
5
|
+
read(root: string): Promise<Bundle>;
|
|
6
|
+
initialize(root: string, overwrite: boolean): Promise<string>;
|
|
7
|
+
/** Parses YAML front matter and rejects ambiguous or malformed Markdown documents. */
|
|
8
|
+
private _parseMarkdown;
|
|
9
|
+
/** Maps a closed YAML contract to a domain definition. */
|
|
10
|
+
private _toDefinition;
|
|
11
|
+
/** Resolves one declared skill directory without allowing an escape from the bundle root. */
|
|
12
|
+
private _readSkill;
|
|
13
|
+
/** Lists UTF-8 skill support files in a stable recursive order and rejects symlinks. */
|
|
14
|
+
private _listFiles;
|
|
15
|
+
private _readUtf8;
|
|
16
|
+
private _string;
|
|
17
|
+
private _number;
|
|
18
|
+
private _boolean;
|
|
19
|
+
private _stringArray;
|
|
20
|
+
}
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
import { lstat, mkdir, readdir, readFile, stat, writeFile } from 'node:fs/promises';
|
|
3
|
+
import { basename, relative, resolve, sep } from 'node:path';
|
|
4
|
+
import { parseDocument } from 'yaml';
|
|
5
|
+
import { AgentDefinition } from '../../../domain/agent-definition.js';
|
|
6
|
+
import { Bundle } from '../../../domain/bundle.js';
|
|
7
|
+
import { PotentialAgentsError, validationError } from '../../../domain/errors.js';
|
|
8
|
+
const TEMPLATE = `---
|
|
9
|
+
apiVersion: potentialagents/v1alpha1
|
|
10
|
+
id: my-agent
|
|
11
|
+
name: My Agent
|
|
12
|
+
description: A managed Potential Agent.
|
|
13
|
+
engine: claude
|
|
14
|
+
model: claude-sonnet-4-6
|
|
15
|
+
tools: []
|
|
16
|
+
browser: false
|
|
17
|
+
skills: []
|
|
18
|
+
# limits:
|
|
19
|
+
# duration_seconds: 300
|
|
20
|
+
# max_budget_usd: 0.50
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
Describe the agent's system instructions here.
|
|
24
|
+
`;
|
|
25
|
+
/** Filesystem adapter that parses potential.md and produces deterministic skill hashes. */
|
|
26
|
+
export class FilesystemBundleRepository {
|
|
27
|
+
async read(root) {
|
|
28
|
+
const resolvedRoot = resolve(root);
|
|
29
|
+
const sourcePath = resolve(resolvedRoot, 'potential.md');
|
|
30
|
+
const source = await this._readUtf8(sourcePath, 'potential.md');
|
|
31
|
+
const { attributes, instructions } = this._parseMarkdown(source);
|
|
32
|
+
const definition = this._toDefinition(attributes, instructions);
|
|
33
|
+
const skills = await Promise.all(definition.skillPaths.map((skillPath) => this._readSkill(resolvedRoot, skillPath)));
|
|
34
|
+
const names = new Set();
|
|
35
|
+
for (const skill of skills) {
|
|
36
|
+
if (names.has(skill.name))
|
|
37
|
+
throw validationError(`Duplicate skill name "${skill.name}".`);
|
|
38
|
+
names.add(skill.name);
|
|
39
|
+
}
|
|
40
|
+
return new Bundle(resolvedRoot, definition, skills.sort((left, right) => left.path.localeCompare(right.path)));
|
|
41
|
+
}
|
|
42
|
+
async initialize(root, overwrite) {
|
|
43
|
+
const destination = resolve(root, 'potential.md');
|
|
44
|
+
await mkdir(resolve(root), { recursive: true });
|
|
45
|
+
try {
|
|
46
|
+
await stat(destination);
|
|
47
|
+
if (!overwrite)
|
|
48
|
+
throw new PotentialAgentsError('FILE_EXISTS', 'potential.md already exists; use --force to overwrite it.');
|
|
49
|
+
}
|
|
50
|
+
catch (error) {
|
|
51
|
+
if (!(error instanceof Error) || !('code' in error) || error.code !== 'ENOENT')
|
|
52
|
+
throw error;
|
|
53
|
+
}
|
|
54
|
+
await writeFile(destination, TEMPLATE, { encoding: 'utf8', flag: 'w' });
|
|
55
|
+
return destination;
|
|
56
|
+
}
|
|
57
|
+
/** Parses YAML front matter and rejects ambiguous or malformed Markdown documents. */
|
|
58
|
+
_parseMarkdown(source) {
|
|
59
|
+
const match = /^---\r?\n([\s\S]*?)\r?\n---\r?\n?([\s\S]*)$/u.exec(source);
|
|
60
|
+
if (!match)
|
|
61
|
+
throw validationError('potential.md must start with YAML front matter delimited by --- lines.');
|
|
62
|
+
const yaml = parseDocument(match[1] ?? '');
|
|
63
|
+
if (yaml.errors.length > 0)
|
|
64
|
+
throw validationError(`Invalid YAML front matter: ${yaml.errors[0]?.message ?? 'unknown error'}`);
|
|
65
|
+
const content = yaml.toJS();
|
|
66
|
+
if (content === null || Array.isArray(content) || typeof content !== 'object')
|
|
67
|
+
throw validationError('YAML front matter must be an object.');
|
|
68
|
+
return { attributes: content, instructions: match[2] ?? '' };
|
|
69
|
+
}
|
|
70
|
+
/** Maps a closed YAML contract to a domain definition. */
|
|
71
|
+
_toDefinition(attributes, instructions) {
|
|
72
|
+
const allowed = new Set(['apiVersion', 'id', 'name', 'description', 'engine', 'model', 'tools', 'browser', 'skills', 'limits']);
|
|
73
|
+
for (const key of Object.keys(attributes)) {
|
|
74
|
+
if (!allowed.has(key))
|
|
75
|
+
throw validationError(`Unknown field "${key}" in potential.md.`);
|
|
76
|
+
}
|
|
77
|
+
const limitsValue = attributes.limits;
|
|
78
|
+
if (limitsValue !== undefined && (limitsValue === null || Array.isArray(limitsValue) || typeof limitsValue !== 'object')) {
|
|
79
|
+
throw validationError('limits must be an object.');
|
|
80
|
+
}
|
|
81
|
+
const limitsRecord = (limitsValue ?? {});
|
|
82
|
+
for (const key of Object.keys(limitsRecord)) {
|
|
83
|
+
if (!['duration_seconds', 'max_budget_usd'].includes(key))
|
|
84
|
+
throw validationError(`Unknown limits field "${key}".`);
|
|
85
|
+
}
|
|
86
|
+
const tools = this._stringArray(attributes.tools, 'tools');
|
|
87
|
+
const skills = this._stringArray(attributes.skills, 'skills');
|
|
88
|
+
const limits = {
|
|
89
|
+
...(limitsRecord.duration_seconds === undefined ? {} : { durationSeconds: this._number(limitsRecord.duration_seconds, 'limits.duration_seconds') }),
|
|
90
|
+
...(limitsRecord.max_budget_usd === undefined ? {} : { maxBudgetUsd: this._number(limitsRecord.max_budget_usd, 'limits.max_budget_usd') }),
|
|
91
|
+
};
|
|
92
|
+
return AgentDefinition.create({
|
|
93
|
+
apiVersion: this._string(attributes.apiVersion, 'apiVersion'),
|
|
94
|
+
id: this._string(attributes.id, 'id'),
|
|
95
|
+
name: this._string(attributes.name, 'name'),
|
|
96
|
+
...(attributes.description === undefined ? {} : { description: this._string(attributes.description, 'description') }),
|
|
97
|
+
engine: this._string(attributes.engine, 'engine'),
|
|
98
|
+
model: this._string(attributes.model, 'model'),
|
|
99
|
+
tools,
|
|
100
|
+
browser: attributes.browser === undefined ? false : this._boolean(attributes.browser, 'browser'),
|
|
101
|
+
skillPaths: skills,
|
|
102
|
+
limits,
|
|
103
|
+
instructions,
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
/** Resolves one declared skill directory without allowing an escape from the bundle root. */
|
|
107
|
+
async _readSkill(root, declaredPath) {
|
|
108
|
+
if (!declaredPath.trim())
|
|
109
|
+
throw validationError('Skill paths must be non-blank.');
|
|
110
|
+
const absolute = resolve(root, declaredPath);
|
|
111
|
+
const relativePath = relative(root, absolute);
|
|
112
|
+
if (!relativePath || relativePath === '..' || relativePath.startsWith(`..${sep}`) || relativePath.split(sep).includes('..')) {
|
|
113
|
+
throw validationError(`Skill path "${declaredPath}" escapes the bundle root.`);
|
|
114
|
+
}
|
|
115
|
+
const directory = await lstat(absolute);
|
|
116
|
+
if (directory.isSymbolicLink())
|
|
117
|
+
throw validationError(`Skill path "${declaredPath}" may not be a symlink.`);
|
|
118
|
+
if (!directory.isDirectory())
|
|
119
|
+
throw validationError(`Skill path "${declaredPath}" must be a directory.`);
|
|
120
|
+
await stat(resolve(absolute, 'SKILL.md'));
|
|
121
|
+
const files = await this._listFiles(absolute, root);
|
|
122
|
+
const hash = createHash('sha256');
|
|
123
|
+
for (const file of files) {
|
|
124
|
+
hash.update(relative(root, file).replaceAll('\\', '/'));
|
|
125
|
+
hash.update('\0');
|
|
126
|
+
hash.update(await readFile(file));
|
|
127
|
+
hash.update('\0');
|
|
128
|
+
}
|
|
129
|
+
return { path: `./${relativePath.replaceAll('\\', '/')}`, name: basename(absolute), sha256: `sha256:${hash.digest('hex')}`, sourceDirectory: absolute };
|
|
130
|
+
}
|
|
131
|
+
/** Lists UTF-8 skill support files in a stable recursive order and rejects symlinks. */
|
|
132
|
+
async _listFiles(directory, root) {
|
|
133
|
+
const entries = await readdir(directory, { withFileTypes: true });
|
|
134
|
+
const files = [];
|
|
135
|
+
for (const entry of entries.sort((left, right) => left.name.localeCompare(right.name))) {
|
|
136
|
+
const absolute = resolve(directory, entry.name);
|
|
137
|
+
if (entry.isSymbolicLink())
|
|
138
|
+
throw validationError(`Skills may not contain symlinks: ${relative(root, absolute)}.`);
|
|
139
|
+
if (entry.isDirectory())
|
|
140
|
+
files.push(...await this._listFiles(absolute, root));
|
|
141
|
+
else if (entry.isFile())
|
|
142
|
+
files.push(absolute);
|
|
143
|
+
else
|
|
144
|
+
throw validationError(`Unsupported skill entry: ${relative(root, absolute)}.`);
|
|
145
|
+
}
|
|
146
|
+
return files;
|
|
147
|
+
}
|
|
148
|
+
async _readUtf8(path, label) {
|
|
149
|
+
try {
|
|
150
|
+
return await readFile(path, 'utf8');
|
|
151
|
+
}
|
|
152
|
+
catch (error) {
|
|
153
|
+
if (error instanceof Error && 'code' in error && error.code === 'ENOENT')
|
|
154
|
+
throw validationError(`${label} is required.`);
|
|
155
|
+
throw error;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
_string(value, field) {
|
|
159
|
+
if (typeof value !== 'string')
|
|
160
|
+
throw validationError(`${field} must be a string.`);
|
|
161
|
+
return value;
|
|
162
|
+
}
|
|
163
|
+
_number(value, field) {
|
|
164
|
+
if (typeof value !== 'number')
|
|
165
|
+
throw validationError(`${field} must be a number.`);
|
|
166
|
+
return value;
|
|
167
|
+
}
|
|
168
|
+
_boolean(value, field) {
|
|
169
|
+
if (typeof value !== 'boolean')
|
|
170
|
+
throw validationError(`${field} must be a boolean.`);
|
|
171
|
+
return value;
|
|
172
|
+
}
|
|
173
|
+
_stringArray(value, field) {
|
|
174
|
+
if (value === undefined)
|
|
175
|
+
return [];
|
|
176
|
+
if (!Array.isArray(value) || value.some((item) => typeof item !== 'string'))
|
|
177
|
+
throw validationError(`${field} must be a list of strings.`);
|
|
178
|
+
return [...value];
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
//# sourceMappingURL=bundle-filesystem-repository.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bundle-filesystem-repository.js","sourceRoot":"","sources":["../../../../src/adapters/outbound/filesystem/bundle-filesystem-repository.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { LockRepository } from '../../../application/ports/lock-repository.js';
|
|
2
|
+
import type { PotentialLock } from '../../../domain/lock.js';
|
|
3
|
+
/** Reads and atomically writes the generated potential.lock document. */
|
|
4
|
+
export declare class YamlLockRepository implements LockRepository {
|
|
5
|
+
read(root: string): Promise<PotentialLock | undefined>;
|
|
6
|
+
write(root: string, lock: PotentialLock): Promise<void>;
|
|
7
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { randomUUID } from 'node:crypto';
|
|
2
|
+
import { readFile, rename, writeFile } from 'node:fs/promises';
|
|
3
|
+
import { resolve } from 'node:path';
|
|
4
|
+
import { parse, stringify } from 'yaml';
|
|
5
|
+
import { PotentialAgentsError } from '../../../domain/errors.js';
|
|
6
|
+
/** Reads and atomically writes the generated potential.lock document. */
|
|
7
|
+
export class YamlLockRepository {
|
|
8
|
+
async read(root) {
|
|
9
|
+
const path = resolve(root, 'potential.lock');
|
|
10
|
+
try {
|
|
11
|
+
const parsed = parse(await readFile(path, 'utf8'));
|
|
12
|
+
const agent = parsed.agent;
|
|
13
|
+
if (parsed.format !== 'potentialagents/lock/v1' || !agent || typeof agent.remote_id !== 'string' || typeof agent.local_id !== 'string' || typeof agent.active_revision !== 'string' || typeof agent.deployment_id !== 'string' || typeof agent.definition_sha256 !== 'string' || typeof agent.status !== 'string') {
|
|
14
|
+
throw new PotentialAgentsError('LOCK_ERROR', 'potential.lock has an unsupported or incomplete format.');
|
|
15
|
+
}
|
|
16
|
+
const skills = Object.fromEntries(Object.entries(parsed.skills ?? {}).map(([pathKey, value]) => {
|
|
17
|
+
if (typeof value.path !== 'string' || typeof value.skill_id !== 'string' || typeof value.revision !== 'string' || typeof value.sha256 !== 'string') {
|
|
18
|
+
throw new PotentialAgentsError('LOCK_ERROR', `potential.lock skill ${pathKey} is incomplete.`);
|
|
19
|
+
}
|
|
20
|
+
return [pathKey, { path: value.path, skillId: value.skill_id, revision: value.revision, sha256: value.sha256 }];
|
|
21
|
+
}));
|
|
22
|
+
return {
|
|
23
|
+
format: 'potentialagents/lock/v1',
|
|
24
|
+
agent: {
|
|
25
|
+
localId: agent.local_id,
|
|
26
|
+
remoteId: agent.remote_id,
|
|
27
|
+
activeRevision: agent.active_revision,
|
|
28
|
+
deploymentId: agent.deployment_id,
|
|
29
|
+
definitionSha256: agent.definition_sha256,
|
|
30
|
+
status: agent.status,
|
|
31
|
+
},
|
|
32
|
+
skills,
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
catch (error) {
|
|
36
|
+
if (error instanceof Error && 'code' in error && error.code === 'ENOENT')
|
|
37
|
+
return undefined;
|
|
38
|
+
throw error;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
async write(root, lock) {
|
|
42
|
+
const destination = resolve(root, 'potential.lock');
|
|
43
|
+
const temporary = resolve(root, `.potential.lock.${randomUUID()}.tmp`);
|
|
44
|
+
await writeFile(temporary, stringify({
|
|
45
|
+
format: lock.format,
|
|
46
|
+
agent: {
|
|
47
|
+
local_id: lock.agent.localId,
|
|
48
|
+
remote_id: lock.agent.remoteId,
|
|
49
|
+
active_revision: lock.agent.activeRevision,
|
|
50
|
+
deployment_id: lock.agent.deploymentId,
|
|
51
|
+
definition_sha256: lock.agent.definitionSha256,
|
|
52
|
+
status: lock.agent.status,
|
|
53
|
+
},
|
|
54
|
+
skills: Object.fromEntries(Object.entries(lock.skills).map(([path, skill]) => [path, {
|
|
55
|
+
path: skill.path,
|
|
56
|
+
skill_id: skill.skillId,
|
|
57
|
+
revision: skill.revision,
|
|
58
|
+
sha256: skill.sha256,
|
|
59
|
+
}])),
|
|
60
|
+
}), 'utf8');
|
|
61
|
+
await rename(temporary, destination);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
//# sourceMappingURL=yaml-lock-repository.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"yaml-lock-repository.js","sourceRoot":"","sources":["../../../../src/adapters/outbound/filesystem/yaml-lock-repository.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { PotentialAgentsApi, ApiSkillRevision, ApplyAccepted, PlanResult, RemoteAgent } from '../../../application/ports/potential-agents-api.js';
|
|
2
|
+
import type { Bundle, SkillSource } from '../../../domain/bundle.js';
|
|
3
|
+
interface HttpApiOptions {
|
|
4
|
+
readonly baseUrl: string;
|
|
5
|
+
readonly accessToken?: string;
|
|
6
|
+
}
|
|
7
|
+
/** HTTPS adapter for the public Potential Agents control-plane contract. */
|
|
8
|
+
export declare class HttpPotentialAgentsApi implements PotentialAgentsApi {
|
|
9
|
+
private readonly options;
|
|
10
|
+
private readonly baseUrl;
|
|
11
|
+
constructor(options: HttpApiOptions);
|
|
12
|
+
plan(organizationId: string, bundle: Bundle, remoteId?: string): Promise<PlanResult>;
|
|
13
|
+
uploadSkill(organizationId: string, skill: SkillSource): Promise<ApiSkillRevision>;
|
|
14
|
+
createAgent(organizationId: string, bundle: Bundle, skills: readonly ApiSkillRevision[], idempotencyKey: string): Promise<ApplyAccepted>;
|
|
15
|
+
createRevision(organizationId: string, remoteId: string, bundle: Bundle, skills: readonly ApiSkillRevision[], idempotencyKey: string): Promise<ApplyAccepted>;
|
|
16
|
+
getAgent(organizationId: string, remoteId: string): Promise<RemoteAgent>;
|
|
17
|
+
createSession(organizationId: string, remoteId: string): Promise<{
|
|
18
|
+
readonly sessionId: string;
|
|
19
|
+
}>;
|
|
20
|
+
createRun(sessionId: string, message: string, idempotencyKey: string): Promise<{
|
|
21
|
+
readonly runId: string;
|
|
22
|
+
readonly status: string;
|
|
23
|
+
}>;
|
|
24
|
+
archiveAgent(organizationId: string, remoteId: string): Promise<void>;
|
|
25
|
+
/** Constructs only public logical runtime intent; profile IDs cannot enter this adapter. */
|
|
26
|
+
private _intent;
|
|
27
|
+
/** Loads a small, explicit UTF-8 skill directory for the public immutable-skill API. */
|
|
28
|
+
private _skillContent;
|
|
29
|
+
/** Sends one authenticated JSON request and converts server failures to safe typed errors. */
|
|
30
|
+
private _json;
|
|
31
|
+
private _parseJson;
|
|
32
|
+
private _errorMessage;
|
|
33
|
+
private _string;
|
|
34
|
+
private _remoteAgent;
|
|
35
|
+
}
|
|
36
|
+
export {};
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import { lstat, readdir, readFile } from 'node:fs/promises';
|
|
2
|
+
import { relative, resolve } from 'node:path';
|
|
3
|
+
import { PotentialAgentsError } from '../../../domain/errors.js';
|
|
4
|
+
/** HTTPS adapter for the public Potential Agents control-plane contract. */
|
|
5
|
+
export class HttpPotentialAgentsApi {
|
|
6
|
+
options;
|
|
7
|
+
baseUrl;
|
|
8
|
+
constructor(options) {
|
|
9
|
+
this.options = options;
|
|
10
|
+
this.baseUrl = options.baseUrl.replace(/\/$/u, '');
|
|
11
|
+
}
|
|
12
|
+
async plan(organizationId, bundle, remoteId) {
|
|
13
|
+
return this._json('POST', '/v1/managed-agents:plan', {
|
|
14
|
+
organization_id: organizationId,
|
|
15
|
+
remote_id: remoteId,
|
|
16
|
+
definition_sha256: bundle.definitionSha256,
|
|
17
|
+
intent: this._intent(bundle, []),
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
async uploadSkill(organizationId, skill) {
|
|
21
|
+
const content = await this._skillContent(skill.sourceDirectory);
|
|
22
|
+
const response = await this._json('POST', '/v1/skills:publish', {
|
|
23
|
+
organization_id: organizationId,
|
|
24
|
+
name: skill.name,
|
|
25
|
+
sha256: skill.sha256,
|
|
26
|
+
files: content,
|
|
27
|
+
});
|
|
28
|
+
return {
|
|
29
|
+
skillId: this._string(response.skill_id, 'skill_id'),
|
|
30
|
+
revision: this._string(response.revision, 'revision'),
|
|
31
|
+
sha256: this._string(response.sha256, 'sha256'),
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
async createAgent(organizationId, bundle, skills, idempotencyKey) {
|
|
35
|
+
const response = await this._json('POST', '/v1/managed-agents', {
|
|
36
|
+
organization_id: organizationId,
|
|
37
|
+
definition_sha256: bundle.definitionSha256,
|
|
38
|
+
...this._intent(bundle, skills),
|
|
39
|
+
}, { 'Idempotency-Key': idempotencyKey });
|
|
40
|
+
return this._remoteAgent(response);
|
|
41
|
+
}
|
|
42
|
+
async createRevision(organizationId, remoteId, bundle, skills, idempotencyKey) {
|
|
43
|
+
const response = await this._json('POST', `/v1/managed-agents/${encodeURIComponent(remoteId)}/revisions`, {
|
|
44
|
+
definition_sha256: bundle.definitionSha256,
|
|
45
|
+
...this._intent(bundle, skills),
|
|
46
|
+
}, { 'Idempotency-Key': idempotencyKey, 'X-Potential-Organization': organizationId });
|
|
47
|
+
return this._remoteAgent(response);
|
|
48
|
+
}
|
|
49
|
+
async getAgent(organizationId, remoteId) {
|
|
50
|
+
const response = await this._json('GET', `/v1/managed-agents/${encodeURIComponent(remoteId)}`, undefined, { 'X-Potential-Organization': organizationId });
|
|
51
|
+
return this._remoteAgent(response);
|
|
52
|
+
}
|
|
53
|
+
async createSession(organizationId, remoteId) {
|
|
54
|
+
const response = await this._json('POST', `/v1/managed-agents/${encodeURIComponent(remoteId)}/sessions`, { organization_id: organizationId });
|
|
55
|
+
return { sessionId: this._string(response.session_id, 'session_id') };
|
|
56
|
+
}
|
|
57
|
+
async createRun(sessionId, message, idempotencyKey) {
|
|
58
|
+
const response = await this._json('POST', `/v1/sessions/${encodeURIComponent(sessionId)}/runs`, { input: { message, data: null }, metadata: {} }, { 'Idempotency-Key': idempotencyKey });
|
|
59
|
+
return { runId: this._string(response.run_id, 'run_id'), status: this._string(response.status, 'status') };
|
|
60
|
+
}
|
|
61
|
+
async archiveAgent(organizationId, remoteId) {
|
|
62
|
+
await this._json('DELETE', `/v1/managed-agents/${encodeURIComponent(remoteId)}`, undefined, { 'X-Potential-Organization': organizationId });
|
|
63
|
+
}
|
|
64
|
+
/** Constructs only public logical runtime intent; profile IDs cannot enter this adapter. */
|
|
65
|
+
_intent(bundle, skills) {
|
|
66
|
+
return {
|
|
67
|
+
agent: { name: bundle.definition.name, ...(bundle.definition.description ? { description: bundle.definition.description } : {}) },
|
|
68
|
+
runtime: { engine: bundle.definition.engine, model: bundle.definition.model },
|
|
69
|
+
behavior: {
|
|
70
|
+
instructions: bundle.definition.instructions,
|
|
71
|
+
input_schema: { type: 'object', additionalProperties: true },
|
|
72
|
+
output_schema: { type: 'object', additionalProperties: true },
|
|
73
|
+
skills: skills.map((skill) => ({ skill_id: skill.skillId, revision: skill.revision, sha256: skill.sha256 })),
|
|
74
|
+
},
|
|
75
|
+
execution: {
|
|
76
|
+
tools: bundle.definition.tools,
|
|
77
|
+
browser: bundle.definition.browser,
|
|
78
|
+
limits: {
|
|
79
|
+
...(bundle.definition.limits.durationSeconds === undefined ? {} : { duration_seconds: bundle.definition.limits.durationSeconds }),
|
|
80
|
+
...(bundle.definition.limits.maxBudgetUsd === undefined ? {} : { max_budget_usd: bundle.definition.limits.maxBudgetUsd }),
|
|
81
|
+
},
|
|
82
|
+
},
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
/** Loads a small, explicit UTF-8 skill directory for the public immutable-skill API. */
|
|
86
|
+
async _skillContent(directory, root = directory) {
|
|
87
|
+
const entries = await readdir(directory, { withFileTypes: true });
|
|
88
|
+
const files = [];
|
|
89
|
+
for (const entry of entries.sort((left, right) => left.name.localeCompare(right.name))) {
|
|
90
|
+
const path = resolve(directory, entry.name);
|
|
91
|
+
const info = await lstat(path);
|
|
92
|
+
if (info.isSymbolicLink())
|
|
93
|
+
throw new PotentialAgentsError('VALIDATION_ERROR', `Skills may not contain symlinks: ${relative(root, path)}.`);
|
|
94
|
+
if (info.isDirectory())
|
|
95
|
+
files.push(...await this._skillContent(path, root));
|
|
96
|
+
else if (info.isFile())
|
|
97
|
+
files.push({ path: relative(root, path).replaceAll('\\', '/'), content: await readFile(path, 'utf8') });
|
|
98
|
+
}
|
|
99
|
+
return files;
|
|
100
|
+
}
|
|
101
|
+
/** Sends one authenticated JSON request and converts server failures to safe typed errors. */
|
|
102
|
+
async _json(method, path, body, headers = {}) {
|
|
103
|
+
const response = await fetch(`${this.baseUrl}${path}`, {
|
|
104
|
+
method,
|
|
105
|
+
headers: {
|
|
106
|
+
Accept: 'application/json',
|
|
107
|
+
...(body === undefined ? {} : { 'Content-Type': 'application/json' }),
|
|
108
|
+
...(this.options.accessToken ? { Authorization: `Bearer ${this.options.accessToken}` } : {}),
|
|
109
|
+
...headers,
|
|
110
|
+
},
|
|
111
|
+
...(body === undefined ? {} : { body: JSON.stringify(body) }),
|
|
112
|
+
});
|
|
113
|
+
const text = await response.text();
|
|
114
|
+
const parsed = text ? this._parseJson(text) : undefined;
|
|
115
|
+
if (!response.ok) {
|
|
116
|
+
const message = parsed !== null && typeof parsed === 'object' && 'error' in parsed
|
|
117
|
+
? `Potential Agents API returned ${response.status}: ${this._errorMessage(parsed.error)}`
|
|
118
|
+
: `Potential Agents API returned ${response.status}.`;
|
|
119
|
+
throw new PotentialAgentsError('API_ERROR', message);
|
|
120
|
+
}
|
|
121
|
+
return parsed;
|
|
122
|
+
}
|
|
123
|
+
_parseJson(text) {
|
|
124
|
+
try {
|
|
125
|
+
return JSON.parse(text);
|
|
126
|
+
}
|
|
127
|
+
catch {
|
|
128
|
+
throw new PotentialAgentsError('API_PROTOCOL_ERROR', 'Potential Agents API returned invalid JSON.');
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
_errorMessage(error) {
|
|
132
|
+
if (error !== null && typeof error === 'object' && 'message' in error && typeof error.message === 'string')
|
|
133
|
+
return error.message;
|
|
134
|
+
return 'request failed';
|
|
135
|
+
}
|
|
136
|
+
_string(value, field) {
|
|
137
|
+
if (typeof value !== 'string' || !value)
|
|
138
|
+
throw new PotentialAgentsError('API_PROTOCOL_ERROR', `Potential Agents API response lacks ${field}.`);
|
|
139
|
+
return value;
|
|
140
|
+
}
|
|
141
|
+
_remoteAgent(response) {
|
|
142
|
+
return {
|
|
143
|
+
agentId: this._string(response.agent_id, 'agent_id'),
|
|
144
|
+
activeRevision: this._string(response.active_revision, 'active_revision'),
|
|
145
|
+
deploymentId: this._string(response.deployment_id, 'deployment_id'),
|
|
146
|
+
status: this._string(response.status, 'status'),
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
//# sourceMappingURL=http-potential-agents-api.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http-potential-agents-api.js","sourceRoot":"","sources":["../../../../src/adapters/outbound/http/http-potential-agents-api.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { IdempotencyKeyGenerator } from '../../../application/ports/idempotency-key-generator.js';
|
|
2
|
+
/** Derives retry-safe idempotency keys from scoped immutable definitions. */
|
|
3
|
+
export declare class Sha256IdempotencyKeyGenerator implements IdempotencyKeyGenerator {
|
|
4
|
+
generate(organizationId: string, definitionSha256: string, operation: 'create' | 'revision' | 'run'): string;
|
|
5
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
/** Derives retry-safe idempotency keys from scoped immutable definitions. */
|
|
3
|
+
export class Sha256IdempotencyKeyGenerator {
|
|
4
|
+
generate(organizationId, definitionSha256, operation) {
|
|
5
|
+
return createHash('sha256').update(`${operation}\0${organizationId}\0${definitionSha256}`).digest('hex');
|
|
6
|
+
}
|
|
7
|
+
}
|
|
8
|
+
//# sourceMappingURL=sha256-idempotency-key-generator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sha256-idempotency-key-generator.js","sourceRoot":"","sources":["../../../../src/adapters/outbound/runtime/sha256-idempotency-key-generator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAGzC,6EAA6E;AAC7E,MAAM,OAAO,6BAA6B;IACjC,QAAQ,CAAC,cAAsB,EAAE,gBAAwB,EAAE,SAAwC;QACxG,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,GAAG,SAAS,KAAK,cAAc,KAAK,gBAAgB,EAAE,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IAC3G,CAAC;CACF"}
|