@open-agent-toolkit/cli 0.3.36 → 0.3.38
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/assets/bundle-metadata.json +1 -1
- package/assets/docs/provider-sync/pilot-with-a-team.md +6 -6
- package/assets/docs/provider-sync/providers.md +1 -0
- package/assets/docs/reference/cli-reference.md +3 -3
- package/assets/docs/reference/project-artifacts.md +12 -3
- package/assets/docs/reference/what-oat-writes.md +14 -11
- package/assets/docs/skills/repo-improve.md +23 -19
- package/assets/docs/workflows/advanced/workflow-gates.md +7 -1
- package/assets/docs/workflows/projects/closeout/closeout-skills.md +3 -1
- package/assets/docs/workflows/projects/lifecycle.md +3 -1
- package/assets/public-package-versions.json +4 -4
- package/assets/skills/oat-project-brief/SKILL.md +1 -1
- package/assets/skills/oat-project-brief/references/brief-contract.md +32 -9
- package/assets/skills/oat-project-implement/SKILL.md +1 -1
- package/assets/skills/oat-project-implement/references/completion-and-closeout.md +14 -4
- package/assets/skills/oat-project-pr-progress/SKILL.md +23 -12
- package/assets/skills/oat-repo-knowledge-index/SKILL.md +226 -131
- package/dist/commands/project/closeout-check/index.d.ts.map +1 -1
- package/dist/commands/project/closeout-check/index.js +4 -8
- package/dist/commands/project/delivery/check.d.ts.map +1 -1
- package/dist/commands/project/delivery/check.js +32 -14
- package/dist/commands/project/delivery/evidence.d.ts +39 -0
- package/dist/commands/project/delivery/evidence.d.ts.map +1 -1
- package/dist/commands/project/delivery/evidence.js +163 -17
- package/dist/commands/project/delivery/refresh.d.ts.map +1 -1
- package/dist/commands/project/delivery/refresh.js +13 -16
- package/dist/commands/project/journal-check/index.d.ts +2 -0
- package/dist/commands/project/journal-check/index.d.ts.map +1 -1
- package/dist/commands/project/journal-check/index.js +78 -1
- package/dist/commands/project/journal-check/types.d.ts +1 -1
- package/dist/commands/project/journal-check/types.d.ts.map +1 -1
- package/dist/providers/codex/codec/config-merge.d.ts +5 -1
- package/dist/providers/codex/codec/config-merge.d.ts.map +1 -1
- package/dist/providers/codex/codec/config-merge.js +111 -62
- package/dist/providers/codex/codec/config-toml-edit.d.ts +8 -0
- package/dist/providers/codex/codec/config-toml-edit.d.ts.map +1 -0
- package/dist/providers/codex/codec/config-toml-edit.js +718 -0
- package/package.json +3 -3
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config-merge.d.ts","sourceRoot":"","sources":["../../../../src/providers/codex/codec/config-merge.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"config-merge.d.ts","sourceRoot":"","sources":["../../../../src/providers/codex/codec/config-merge.ts"],"names":[],"mappings":"AASA,MAAM,WAAW,sBAAsB;IACrC,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,oBAAoB;IACnC,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,YAAY,EAAE,sBAAsB,EAAE,CAAC;IACvC,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC7B,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,8BAA8B;IAC7C,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,IAAI,EAAE,sBAAsB,CAAC;IAC7B,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC7B,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,sBAAsB;IACrC,aAAa,EAAE,MAAM,CAAC;IACtB,OAAO,EAAE,OAAO,CAAC;IACjB,YAAY,EAAE,MAAM,EAAE,CAAC;CACxB;AAqFD,4EAA4E;AAC5E,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,GAAG,IAAI,CAIvE;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,EAC/B,eAAe,EACf,YAAY,EACZ,iBAAsB,EACtB,iBAAiB,GAClB,EAAE,oBAAoB,GAAG,sBAAsB,CAkH/C;AAED,6EAA6E;AAC7E,wBAAgB,uBAAuB,CAAC,EACtC,eAAe,EACf,IAAI,EACJ,iBAAsB,EACtB,iBAAiB,GAClB,EAAE,8BAA8B,GAAG,sBAAsB,CAOzD"}
|
|
@@ -1,44 +1,6 @@
|
|
|
1
1
|
import { CliError } from '../../../errors/index.js';
|
|
2
2
|
import TOML from '@iarna/toml';
|
|
3
|
-
import {
|
|
4
|
-
function isEscapedBasicStringDelimiter(line, index) {
|
|
5
|
-
let backslashCount = 0;
|
|
6
|
-
for (let cursor = index - 1; cursor >= 0 && line[cursor] === '\\'; cursor--) {
|
|
7
|
-
backslashCount += 1;
|
|
8
|
-
}
|
|
9
|
-
return backslashCount % 2 === 1;
|
|
10
|
-
}
|
|
11
|
-
function scanMultilineStringDelimiter(line, initialDelimiter) {
|
|
12
|
-
let delimiter = initialDelimiter;
|
|
13
|
-
for (let index = 0; index < line.length - 2; index++) {
|
|
14
|
-
if (delimiter === null) {
|
|
15
|
-
const candidate = line.slice(index, index + 3);
|
|
16
|
-
if ((candidate === '"""' && !isEscapedBasicStringDelimiter(line, index)) ||
|
|
17
|
-
candidate === "'''") {
|
|
18
|
-
delimiter = candidate;
|
|
19
|
-
index += 2;
|
|
20
|
-
}
|
|
21
|
-
continue;
|
|
22
|
-
}
|
|
23
|
-
if (line.startsWith(delimiter, index) &&
|
|
24
|
-
(delimiter === "'''" || !isEscapedBasicStringDelimiter(line, index))) {
|
|
25
|
-
delimiter = null;
|
|
26
|
-
index += 2;
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
return delimiter;
|
|
30
|
-
}
|
|
31
|
-
function normalizeCodexConfigIndentation(content) {
|
|
32
|
-
let multilineDelimiter = null;
|
|
33
|
-
return content
|
|
34
|
-
.split('\n')
|
|
35
|
-
.map((line) => {
|
|
36
|
-
const normalizedLine = multilineDelimiter === null ? line.trimStart() : line;
|
|
37
|
-
multilineDelimiter = scanMultilineStringDelimiter(normalizedLine, multilineDelimiter);
|
|
38
|
-
return normalizedLine;
|
|
39
|
-
})
|
|
40
|
-
.join('\n');
|
|
41
|
-
}
|
|
3
|
+
import { removeTomlTable, renderTomlString, setTomlValue, } from './config-toml-edit.js';
|
|
42
4
|
function parseConfig(content) {
|
|
43
5
|
if (!content || content.trim() === '') {
|
|
44
6
|
return {};
|
|
@@ -57,39 +19,85 @@ function parseConfig(content) {
|
|
|
57
19
|
throw new CliError(`Failed to parse .codex/config.toml: ${error instanceof Error ? error.message : 'unknown parse error'}`);
|
|
58
20
|
}
|
|
59
21
|
}
|
|
22
|
+
function isTable(value) {
|
|
23
|
+
return (!!value &&
|
|
24
|
+
typeof value === 'object' &&
|
|
25
|
+
!Array.isArray(value) &&
|
|
26
|
+
!(value instanceof Date));
|
|
27
|
+
}
|
|
60
28
|
function getObject(value) {
|
|
61
|
-
|
|
29
|
+
return isTable(value) ? { ...value } : {};
|
|
30
|
+
}
|
|
31
|
+
function requireTableOrAbsent(value, label) {
|
|
32
|
+
if (value === undefined) {
|
|
62
33
|
return {};
|
|
63
34
|
}
|
|
64
|
-
|
|
35
|
+
if (!isTable(value)) {
|
|
36
|
+
throw new CliError(`Refusing to rewrite .codex/config.toml: ${label} must be a table. Fix it by hand and rerun sync.`);
|
|
37
|
+
}
|
|
38
|
+
return value;
|
|
39
|
+
}
|
|
40
|
+
function requireNotTable(value, label) {
|
|
41
|
+
if (isTable(value)) {
|
|
42
|
+
throw new CliError(`Refusing to rewrite .codex/config.toml: ${label} must not be a table. Fix it by hand and rerun sync.`);
|
|
43
|
+
}
|
|
65
44
|
}
|
|
66
45
|
function getFiniteNumber(value) {
|
|
67
46
|
return typeof value === 'number' && Number.isFinite(value) ? value : null;
|
|
68
47
|
}
|
|
48
|
+
function canonicalTomlValue(value) {
|
|
49
|
+
if (value instanceof Date) {
|
|
50
|
+
return { $date: value.toISOString() };
|
|
51
|
+
}
|
|
52
|
+
if (Array.isArray(value)) {
|
|
53
|
+
return value.map(canonicalTomlValue);
|
|
54
|
+
}
|
|
55
|
+
if (typeof value === 'bigint') {
|
|
56
|
+
return { $bigint: value.toString() };
|
|
57
|
+
}
|
|
58
|
+
if (typeof value === 'number' && !Number.isFinite(value)) {
|
|
59
|
+
return { $number: String(value) };
|
|
60
|
+
}
|
|
61
|
+
if (isTable(value)) {
|
|
62
|
+
return Object.fromEntries(Object.keys(value)
|
|
63
|
+
.sort()
|
|
64
|
+
.map((key) => [key, canonicalTomlValue(value[key])]));
|
|
65
|
+
}
|
|
66
|
+
return value;
|
|
67
|
+
}
|
|
69
68
|
/** Reads a valid numeric agents.max_depth value from Codex TOML content. */
|
|
70
69
|
export function readCodexMaxDepth(content) {
|
|
71
70
|
const parsed = parseConfig(content);
|
|
72
71
|
const agents = getObject(parsed.agents);
|
|
73
72
|
return getFiniteNumber(agents.max_depth);
|
|
74
73
|
}
|
|
75
|
-
/**
|
|
74
|
+
/**
|
|
75
|
+
* Merges managed Codex roles and required shared agent configuration in place:
|
|
76
|
+
* other tools keep ownership markers in this file's comments, so unmanaged
|
|
77
|
+
* content must survive byte for byte.
|
|
78
|
+
*/
|
|
76
79
|
export function mergeCodexConfig({ existingContent, desiredRoles, staleManagedRoles = [], inheritedMaxDepth, }) {
|
|
77
80
|
const parsed = parseConfig(existingContent);
|
|
78
|
-
const features =
|
|
79
|
-
const agents =
|
|
80
|
-
const
|
|
81
|
-
const
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
81
|
+
const features = requireTableOrAbsent(parsed.features, 'features');
|
|
82
|
+
const agents = requireTableOrAbsent(parsed.agents, 'agents');
|
|
83
|
+
const roles = new Map(desiredRoles.map((role) => [role.roleName, role]));
|
|
84
|
+
const stale = new Set(staleManagedRoles);
|
|
85
|
+
requireNotTable(features.multi_agent, 'features.multi_agent');
|
|
86
|
+
if (!stale.has('max_depth')) {
|
|
87
|
+
requireNotTable(agents.max_depth, 'agents.max_depth');
|
|
88
|
+
}
|
|
89
|
+
for (const roleName of roles.keys()) {
|
|
90
|
+
if (stale.has(roleName)) {
|
|
91
|
+
continue;
|
|
92
|
+
}
|
|
93
|
+
const role = requireTableOrAbsent(agents[roleName], `agents.${roleName}`);
|
|
94
|
+
requireNotTable(role.description, `agents.${roleName}.description`);
|
|
95
|
+
requireNotTable(role.config_file, `agents.${roleName}.config_file`);
|
|
96
|
+
}
|
|
97
|
+
const maxDepth = Math.max(2, getFiniteNumber(agents.max_depth) ?? 2, getFiniteNumber(inheritedMaxDepth) ?? 2);
|
|
98
|
+
const expectedAgents = { ...agents, max_depth: maxDepth };
|
|
99
|
+
for (const role of roles.values()) {
|
|
100
|
+
expectedAgents[role.roleName] = {
|
|
93
101
|
...getObject(agents[role.roleName]),
|
|
94
102
|
description: role.description,
|
|
95
103
|
config_file: role.configFile,
|
|
@@ -97,16 +105,57 @@ export function mergeCodexConfig({ existingContent, desiredRoles, staleManagedRo
|
|
|
97
105
|
}
|
|
98
106
|
const removedRoles = [];
|
|
99
107
|
for (const staleRole of staleManagedRoles) {
|
|
100
|
-
if (staleRole
|
|
101
|
-
delete
|
|
108
|
+
if (Object.hasOwn(expectedAgents, staleRole)) {
|
|
109
|
+
delete expectedAgents[staleRole];
|
|
102
110
|
removedRoles.push(staleRole);
|
|
103
111
|
}
|
|
104
112
|
}
|
|
105
|
-
const
|
|
106
|
-
const
|
|
113
|
+
const removed = new Set(removedRoles);
|
|
114
|
+
const original = existingContent !== null && existingContent.trim() !== ''
|
|
115
|
+
? existingContent
|
|
116
|
+
: '';
|
|
117
|
+
let mergedContent = original;
|
|
118
|
+
if (features.multi_agent !== true) {
|
|
119
|
+
mergedContent = setTomlValue(mergedContent, ['features', 'multi_agent'], 'true');
|
|
120
|
+
}
|
|
121
|
+
if (agents.max_depth !== maxDepth && !removed.has('max_depth')) {
|
|
122
|
+
mergedContent = setTomlValue(mergedContent, ['agents', 'max_depth'], String(maxDepth));
|
|
123
|
+
}
|
|
124
|
+
for (const staleRole of removedRoles) {
|
|
125
|
+
mergedContent = removeTomlTable(mergedContent, ['agents', staleRole]);
|
|
126
|
+
}
|
|
127
|
+
for (const role of roles.values()) {
|
|
128
|
+
if (removed.has(role.roleName)) {
|
|
129
|
+
continue;
|
|
130
|
+
}
|
|
131
|
+
const current = getObject(agents[role.roleName]);
|
|
132
|
+
if (current.description !== role.description) {
|
|
133
|
+
mergedContent = setTomlValue(mergedContent, ['agents', role.roleName, 'description'], renderTomlString(role.description));
|
|
134
|
+
}
|
|
135
|
+
if (current.config_file !== role.configFile) {
|
|
136
|
+
mergedContent = setTomlValue(mergedContent, ['agents', role.roleName, 'config_file'], renderTomlString(role.configFile));
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
const expected = {
|
|
140
|
+
...parsed,
|
|
141
|
+
features: { ...features, multi_agent: true },
|
|
142
|
+
agents: expectedAgents,
|
|
143
|
+
};
|
|
144
|
+
let actual;
|
|
145
|
+
try {
|
|
146
|
+
actual = parseConfig(mergedContent);
|
|
147
|
+
}
|
|
148
|
+
catch {
|
|
149
|
+
actual = null;
|
|
150
|
+
}
|
|
151
|
+
if (actual === null ||
|
|
152
|
+
JSON.stringify(canonicalTomlValue(actual)) !==
|
|
153
|
+
JSON.stringify(canonicalTomlValue(expected))) {
|
|
154
|
+
throw new CliError('Refusing to write .codex/config.toml: the in-place edit did not produce the expected managed configuration. Edit the file by hand and rerun sync.');
|
|
155
|
+
}
|
|
107
156
|
return {
|
|
108
157
|
mergedContent,
|
|
109
|
-
changed,
|
|
158
|
+
changed: mergedContent !== (existingContent ?? ''),
|
|
110
159
|
removedRoles,
|
|
111
160
|
};
|
|
112
161
|
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
type KeyPath = readonly string[];
|
|
2
|
+
/** Renders a TOML basic string; JSON escaping is not TOML-safe for all input. */
|
|
3
|
+
export declare function renderTomlString(value: string): string;
|
|
4
|
+
/** `renderedValue` must already be a valid TOML value literal. */
|
|
5
|
+
export declare function setTomlValue(text: string, path: KeyPath, renderedValue: string): string;
|
|
6
|
+
export declare function removeTomlTable(text: string, path: KeyPath): string;
|
|
7
|
+
export {};
|
|
8
|
+
//# sourceMappingURL=config-toml-edit.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config-toml-edit.d.ts","sourceRoot":"","sources":["../../../../src/providers/codex/codec/config-toml-edit.ts"],"names":[],"mappings":"AAOA,KAAK,OAAO,GAAG,SAAS,MAAM,EAAE,CAAC;AAofjC,iFAAiF;AACjF,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAyBtD;AAqTD,kEAAkE;AAClE,wBAAgB,YAAY,CAC1B,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,OAAO,EACb,aAAa,EAAE,MAAM,GACpB,MAAM,CAsFR;AA8BD,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,MAAM,CA4BnE"}
|