cc-codeconductor 0.2.10 → 0.3.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/README.md +5 -4
- package/dist/index.js +1636 -1078
- package/package.json +1 -1
- package/presets/agy/AGENTS.md +46 -2
- package/presets/claude/CLAUDE.md +62 -2
- package/presets/claude/skills/android/SKILL.md +119 -0
- package/presets/claude/skills/laravel-specialist/SKILL.md +264 -0
- package/presets/claude/skills/laravel-specialist/references/eloquent.md +351 -0
- package/presets/claude/skills/laravel-specialist/references/livewire.md +512 -0
- package/presets/claude/skills/laravel-specialist/references/queues.md +423 -0
- package/presets/claude/skills/laravel-specialist/references/routing.md +362 -0
- package/presets/claude/skills/laravel-specialist/references/testing.md +522 -0
- package/presets/claude/skills/php-pro/SKILL.md +208 -0
- package/presets/claude/skills/php-pro/references/async-patterns.md +412 -0
- package/presets/claude/skills/php-pro/references/laravel-patterns.md +377 -0
- package/presets/claude/skills/php-pro/references/modern-php-features.md +323 -0
- package/presets/claude/skills/php-pro/references/symfony-patterns.md +466 -0
- package/presets/claude/skills/php-pro/references/testing-quality.md +466 -0
- package/presets/codex/AGENTS.md +47 -2
- package/presets/codex/skills/android/SKILL.md +119 -0
- package/presets/codex/skills/laravel-specialist/SKILL.md +264 -0
- package/presets/codex/skills/laravel-specialist/references/eloquent.md +351 -0
- package/presets/codex/skills/laravel-specialist/references/livewire.md +512 -0
- package/presets/codex/skills/laravel-specialist/references/queues.md +423 -0
- package/presets/codex/skills/laravel-specialist/references/routing.md +362 -0
- package/presets/codex/skills/laravel-specialist/references/testing.md +522 -0
- package/presets/codex/skills/php-pro/SKILL.md +208 -0
- package/presets/codex/skills/php-pro/references/async-patterns.md +412 -0
- package/presets/codex/skills/php-pro/references/laravel-patterns.md +377 -0
- package/presets/codex/skills/php-pro/references/modern-php-features.md +323 -0
- package/presets/codex/skills/php-pro/references/symfony-patterns.md +466 -0
- package/presets/codex/skills/php-pro/references/testing-quality.md +466 -0
- package/presets/opencode/agents/implementer.md +2 -2
- package/presets/opencode/agents/orchestrator.md +132 -5
- package/presets/opencode/agents/reviewer.md +33 -0
- package/presets/opencode/prompts/v0.3.0/architect.md +221 -0
- package/presets/opencode/prompts/v0.3.0/docs.md +189 -0
- package/presets/opencode/prompts/v0.3.0/implementer.md +162 -0
- package/presets/opencode/prompts/v0.3.0/orchestrator.md +360 -0
- package/presets/opencode/prompts/v0.3.0/repo-explorer.md +110 -0
- package/presets/opencode/prompts/v0.3.0/reviewer.md +225 -0
- package/presets/opencode/prompts/v0.3.0/task-coach.md +155 -0
- package/presets/opencode/prompts/v0.3.0/tester.md +251 -0
- package/presets/opencode/skills/android/SKILL.md +119 -0
- package/presets/opencode/skills/laravel-specialist/SKILL.md +264 -0
- package/presets/opencode/skills/laravel-specialist/references/eloquent.md +351 -0
- package/presets/opencode/skills/laravel-specialist/references/livewire.md +512 -0
- package/presets/opencode/skills/laravel-specialist/references/queues.md +423 -0
- package/presets/opencode/skills/laravel-specialist/references/routing.md +362 -0
- package/presets/opencode/skills/laravel-specialist/references/testing.md +522 -0
- package/presets/opencode/skills/php-pro/SKILL.md +208 -0
- package/presets/opencode/skills/php-pro/references/async-patterns.md +412 -0
- package/presets/opencode/skills/php-pro/references/laravel-patterns.md +377 -0
- package/presets/opencode/skills/php-pro/references/modern-php-features.md +323 -0
- package/presets/opencode/skills/php-pro/references/symfony-patterns.md +466 -0
- package/presets/opencode/skills/php-pro/references/testing-quality.md +466 -0
- package/src/presets/manifests/agy.yml +3 -2
- package/src/presets/manifests/claude.yml +3 -2
- package/src/presets/manifests/codex.yml +3 -2
- package/src/presets/manifests/cursor.yml +3 -2
- package/src/presets/manifests/gemini.yml +3 -2
- package/src/presets/manifests/opencode.yml +3 -2
- package/src/presets/models/opencode.yml +6 -6
package/dist/index.js
CHANGED
|
@@ -77,24 +77,24 @@ var require_identity = __commonJS((exports) => {
|
|
|
77
77
|
var SCALAR = Symbol.for("yaml.scalar");
|
|
78
78
|
var SEQ = Symbol.for("yaml.seq");
|
|
79
79
|
var NODE_TYPE = Symbol.for("yaml.node.type");
|
|
80
|
-
var isAlias = (
|
|
81
|
-
var isDocument = (
|
|
82
|
-
var isMap = (
|
|
83
|
-
var isPair = (
|
|
84
|
-
var isScalar = (
|
|
85
|
-
var isSeq = (
|
|
86
|
-
function isCollection(
|
|
87
|
-
if (
|
|
88
|
-
switch (
|
|
80
|
+
var isAlias = (node2) => !!node2 && typeof node2 === "object" && node2[NODE_TYPE] === ALIAS;
|
|
81
|
+
var isDocument = (node2) => !!node2 && typeof node2 === "object" && node2[NODE_TYPE] === DOC;
|
|
82
|
+
var isMap = (node2) => !!node2 && typeof node2 === "object" && node2[NODE_TYPE] === MAP;
|
|
83
|
+
var isPair = (node2) => !!node2 && typeof node2 === "object" && node2[NODE_TYPE] === PAIR;
|
|
84
|
+
var isScalar = (node2) => !!node2 && typeof node2 === "object" && node2[NODE_TYPE] === SCALAR;
|
|
85
|
+
var isSeq = (node2) => !!node2 && typeof node2 === "object" && node2[NODE_TYPE] === SEQ;
|
|
86
|
+
function isCollection(node2) {
|
|
87
|
+
if (node2 && typeof node2 === "object")
|
|
88
|
+
switch (node2[NODE_TYPE]) {
|
|
89
89
|
case MAP:
|
|
90
90
|
case SEQ:
|
|
91
91
|
return true;
|
|
92
92
|
}
|
|
93
93
|
return false;
|
|
94
94
|
}
|
|
95
|
-
function isNode(
|
|
96
|
-
if (
|
|
97
|
-
switch (
|
|
95
|
+
function isNode(node2) {
|
|
96
|
+
if (node2 && typeof node2 === "object")
|
|
97
|
+
switch (node2[NODE_TYPE]) {
|
|
98
98
|
case ALIAS:
|
|
99
99
|
case MAP:
|
|
100
100
|
case SCALAR:
|
|
@@ -103,7 +103,7 @@ var require_identity = __commonJS((exports) => {
|
|
|
103
103
|
}
|
|
104
104
|
return false;
|
|
105
105
|
}
|
|
106
|
-
var hasAnchor = (
|
|
106
|
+
var hasAnchor = (node2) => (isScalar(node2) || isCollection(node2)) && !!node2.anchor;
|
|
107
107
|
exports.ALIAS = ALIAS;
|
|
108
108
|
exports.DOC = DOC;
|
|
109
109
|
exports.MAP = MAP;
|
|
@@ -128,98 +128,98 @@ var require_visit = __commonJS((exports) => {
|
|
|
128
128
|
var BREAK = Symbol("break visit");
|
|
129
129
|
var SKIP = Symbol("skip children");
|
|
130
130
|
var REMOVE = Symbol("remove node");
|
|
131
|
-
function visit(
|
|
131
|
+
function visit(node2, visitor) {
|
|
132
132
|
const visitor_ = initVisitor(visitor);
|
|
133
|
-
if (identity.isDocument(
|
|
134
|
-
const cd = visit_(null,
|
|
133
|
+
if (identity.isDocument(node2)) {
|
|
134
|
+
const cd = visit_(null, node2.contents, visitor_, Object.freeze([node2]));
|
|
135
135
|
if (cd === REMOVE)
|
|
136
|
-
|
|
136
|
+
node2.contents = null;
|
|
137
137
|
} else
|
|
138
|
-
visit_(null,
|
|
138
|
+
visit_(null, node2, visitor_, Object.freeze([]));
|
|
139
139
|
}
|
|
140
140
|
visit.BREAK = BREAK;
|
|
141
141
|
visit.SKIP = SKIP;
|
|
142
142
|
visit.REMOVE = REMOVE;
|
|
143
|
-
function visit_(key,
|
|
144
|
-
const ctrl = callVisitor(key,
|
|
143
|
+
function visit_(key, node2, visitor, path) {
|
|
144
|
+
const ctrl = callVisitor(key, node2, visitor, path);
|
|
145
145
|
if (identity.isNode(ctrl) || identity.isPair(ctrl)) {
|
|
146
146
|
replaceNode(key, path, ctrl);
|
|
147
147
|
return visit_(key, ctrl, visitor, path);
|
|
148
148
|
}
|
|
149
149
|
if (typeof ctrl !== "symbol") {
|
|
150
|
-
if (identity.isCollection(
|
|
151
|
-
path = Object.freeze(path.concat(
|
|
152
|
-
for (let i = 0;i <
|
|
153
|
-
const ci = visit_(i,
|
|
150
|
+
if (identity.isCollection(node2)) {
|
|
151
|
+
path = Object.freeze(path.concat(node2));
|
|
152
|
+
for (let i = 0;i < node2.items.length; ++i) {
|
|
153
|
+
const ci = visit_(i, node2.items[i], visitor, path);
|
|
154
154
|
if (typeof ci === "number")
|
|
155
155
|
i = ci - 1;
|
|
156
156
|
else if (ci === BREAK)
|
|
157
157
|
return BREAK;
|
|
158
158
|
else if (ci === REMOVE) {
|
|
159
|
-
|
|
159
|
+
node2.items.splice(i, 1);
|
|
160
160
|
i -= 1;
|
|
161
161
|
}
|
|
162
162
|
}
|
|
163
|
-
} else if (identity.isPair(
|
|
164
|
-
path = Object.freeze(path.concat(
|
|
165
|
-
const ck = visit_("key",
|
|
163
|
+
} else if (identity.isPair(node2)) {
|
|
164
|
+
path = Object.freeze(path.concat(node2));
|
|
165
|
+
const ck = visit_("key", node2.key, visitor, path);
|
|
166
166
|
if (ck === BREAK)
|
|
167
167
|
return BREAK;
|
|
168
168
|
else if (ck === REMOVE)
|
|
169
|
-
|
|
170
|
-
const cv = visit_("value",
|
|
169
|
+
node2.key = null;
|
|
170
|
+
const cv = visit_("value", node2.value, visitor, path);
|
|
171
171
|
if (cv === BREAK)
|
|
172
172
|
return BREAK;
|
|
173
173
|
else if (cv === REMOVE)
|
|
174
|
-
|
|
174
|
+
node2.value = null;
|
|
175
175
|
}
|
|
176
176
|
}
|
|
177
177
|
return ctrl;
|
|
178
178
|
}
|
|
179
|
-
async function visitAsync(
|
|
179
|
+
async function visitAsync(node2, visitor) {
|
|
180
180
|
const visitor_ = initVisitor(visitor);
|
|
181
|
-
if (identity.isDocument(
|
|
182
|
-
const cd = await visitAsync_(null,
|
|
181
|
+
if (identity.isDocument(node2)) {
|
|
182
|
+
const cd = await visitAsync_(null, node2.contents, visitor_, Object.freeze([node2]));
|
|
183
183
|
if (cd === REMOVE)
|
|
184
|
-
|
|
184
|
+
node2.contents = null;
|
|
185
185
|
} else
|
|
186
|
-
await visitAsync_(null,
|
|
186
|
+
await visitAsync_(null, node2, visitor_, Object.freeze([]));
|
|
187
187
|
}
|
|
188
188
|
visitAsync.BREAK = BREAK;
|
|
189
189
|
visitAsync.SKIP = SKIP;
|
|
190
190
|
visitAsync.REMOVE = REMOVE;
|
|
191
|
-
async function visitAsync_(key,
|
|
192
|
-
const ctrl = await callVisitor(key,
|
|
191
|
+
async function visitAsync_(key, node2, visitor, path) {
|
|
192
|
+
const ctrl = await callVisitor(key, node2, visitor, path);
|
|
193
193
|
if (identity.isNode(ctrl) || identity.isPair(ctrl)) {
|
|
194
194
|
replaceNode(key, path, ctrl);
|
|
195
195
|
return visitAsync_(key, ctrl, visitor, path);
|
|
196
196
|
}
|
|
197
197
|
if (typeof ctrl !== "symbol") {
|
|
198
|
-
if (identity.isCollection(
|
|
199
|
-
path = Object.freeze(path.concat(
|
|
200
|
-
for (let i = 0;i <
|
|
201
|
-
const ci = await visitAsync_(i,
|
|
198
|
+
if (identity.isCollection(node2)) {
|
|
199
|
+
path = Object.freeze(path.concat(node2));
|
|
200
|
+
for (let i = 0;i < node2.items.length; ++i) {
|
|
201
|
+
const ci = await visitAsync_(i, node2.items[i], visitor, path);
|
|
202
202
|
if (typeof ci === "number")
|
|
203
203
|
i = ci - 1;
|
|
204
204
|
else if (ci === BREAK)
|
|
205
205
|
return BREAK;
|
|
206
206
|
else if (ci === REMOVE) {
|
|
207
|
-
|
|
207
|
+
node2.items.splice(i, 1);
|
|
208
208
|
i -= 1;
|
|
209
209
|
}
|
|
210
210
|
}
|
|
211
|
-
} else if (identity.isPair(
|
|
212
|
-
path = Object.freeze(path.concat(
|
|
213
|
-
const ck = await visitAsync_("key",
|
|
211
|
+
} else if (identity.isPair(node2)) {
|
|
212
|
+
path = Object.freeze(path.concat(node2));
|
|
213
|
+
const ck = await visitAsync_("key", node2.key, visitor, path);
|
|
214
214
|
if (ck === BREAK)
|
|
215
215
|
return BREAK;
|
|
216
216
|
else if (ck === REMOVE)
|
|
217
|
-
|
|
218
|
-
const cv = await visitAsync_("value",
|
|
217
|
+
node2.key = null;
|
|
218
|
+
const cv = await visitAsync_("value", node2.value, visitor, path);
|
|
219
219
|
if (cv === BREAK)
|
|
220
220
|
return BREAK;
|
|
221
221
|
else if (cv === REMOVE)
|
|
222
|
-
|
|
222
|
+
node2.value = null;
|
|
223
223
|
}
|
|
224
224
|
}
|
|
225
225
|
return ctrl;
|
|
@@ -242,32 +242,32 @@ var require_visit = __commonJS((exports) => {
|
|
|
242
242
|
}
|
|
243
243
|
return visitor;
|
|
244
244
|
}
|
|
245
|
-
function callVisitor(key,
|
|
245
|
+
function callVisitor(key, node2, visitor, path) {
|
|
246
246
|
if (typeof visitor === "function")
|
|
247
|
-
return visitor(key,
|
|
248
|
-
if (identity.isMap(
|
|
249
|
-
return visitor.Map?.(key,
|
|
250
|
-
if (identity.isSeq(
|
|
251
|
-
return visitor.Seq?.(key,
|
|
252
|
-
if (identity.isPair(
|
|
253
|
-
return visitor.Pair?.(key,
|
|
254
|
-
if (identity.isScalar(
|
|
255
|
-
return visitor.Scalar?.(key,
|
|
256
|
-
if (identity.isAlias(
|
|
257
|
-
return visitor.Alias?.(key,
|
|
247
|
+
return visitor(key, node2, path);
|
|
248
|
+
if (identity.isMap(node2))
|
|
249
|
+
return visitor.Map?.(key, node2, path);
|
|
250
|
+
if (identity.isSeq(node2))
|
|
251
|
+
return visitor.Seq?.(key, node2, path);
|
|
252
|
+
if (identity.isPair(node2))
|
|
253
|
+
return visitor.Pair?.(key, node2, path);
|
|
254
|
+
if (identity.isScalar(node2))
|
|
255
|
+
return visitor.Scalar?.(key, node2, path);
|
|
256
|
+
if (identity.isAlias(node2))
|
|
257
|
+
return visitor.Alias?.(key, node2, path);
|
|
258
258
|
return;
|
|
259
259
|
}
|
|
260
|
-
function replaceNode(key, path,
|
|
260
|
+
function replaceNode(key, path, node2) {
|
|
261
261
|
const parent = path[path.length - 1];
|
|
262
262
|
if (identity.isCollection(parent)) {
|
|
263
|
-
parent.items[key] =
|
|
263
|
+
parent.items[key] = node2;
|
|
264
264
|
} else if (identity.isPair(parent)) {
|
|
265
265
|
if (key === "key")
|
|
266
|
-
parent.key =
|
|
266
|
+
parent.key = node2;
|
|
267
267
|
else
|
|
268
|
-
parent.value =
|
|
268
|
+
parent.value = node2;
|
|
269
269
|
} else if (identity.isDocument(parent)) {
|
|
270
|
-
parent.contents =
|
|
270
|
+
parent.contents = node2;
|
|
271
271
|
} else {
|
|
272
272
|
const pt = identity.isAlias(parent) ? "alias" : "scalar";
|
|
273
273
|
throw new Error(`Cannot replace node with ${pt} parent`);
|
|
@@ -407,9 +407,9 @@ var require_directives = __commonJS((exports) => {
|
|
|
407
407
|
let tagNames;
|
|
408
408
|
if (doc && tagEntries.length > 0 && identity.isNode(doc.contents)) {
|
|
409
409
|
const tags = {};
|
|
410
|
-
visit.visit(doc.contents, (_key,
|
|
411
|
-
if (identity.isNode(
|
|
412
|
-
tags[
|
|
410
|
+
visit.visit(doc.contents, (_key, node2) => {
|
|
411
|
+
if (identity.isNode(node2) && node2.tag)
|
|
412
|
+
tags[node2.tag] = true;
|
|
413
413
|
});
|
|
414
414
|
tagNames = Object.keys(tags);
|
|
415
415
|
} else
|
|
@@ -444,9 +444,9 @@ var require_anchors = __commonJS((exports) => {
|
|
|
444
444
|
function anchorNames(root) {
|
|
445
445
|
const anchors = new Set;
|
|
446
446
|
visit.visit(root, {
|
|
447
|
-
Value(_key,
|
|
448
|
-
if (
|
|
449
|
-
anchors.add(
|
|
447
|
+
Value(_key, node2) {
|
|
448
|
+
if (node2.anchor)
|
|
449
|
+
anchors.add(node2.anchor);
|
|
450
450
|
}
|
|
451
451
|
});
|
|
452
452
|
return anchors;
|
|
@@ -629,20 +629,20 @@ var require_Alias = __commonJS((exports) => {
|
|
|
629
629
|
} else {
|
|
630
630
|
nodes = [];
|
|
631
631
|
visit.visit(doc, {
|
|
632
|
-
Node: (_key,
|
|
633
|
-
if (identity.isAlias(
|
|
634
|
-
nodes.push(
|
|
632
|
+
Node: (_key, node2) => {
|
|
633
|
+
if (identity.isAlias(node2) || identity.hasAnchor(node2))
|
|
634
|
+
nodes.push(node2);
|
|
635
635
|
}
|
|
636
636
|
});
|
|
637
637
|
if (ctx)
|
|
638
638
|
ctx.aliasResolveCache = nodes;
|
|
639
639
|
}
|
|
640
640
|
let found = undefined;
|
|
641
|
-
for (const
|
|
642
|
-
if (
|
|
641
|
+
for (const node2 of nodes) {
|
|
642
|
+
if (node2 === this)
|
|
643
643
|
break;
|
|
644
|
-
if (
|
|
645
|
-
found =
|
|
644
|
+
if (node2.anchor === this.source)
|
|
645
|
+
found = node2;
|
|
646
646
|
}
|
|
647
647
|
return found;
|
|
648
648
|
}
|
|
@@ -689,22 +689,22 @@ var require_Alias = __commonJS((exports) => {
|
|
|
689
689
|
return src;
|
|
690
690
|
}
|
|
691
691
|
}
|
|
692
|
-
function getAliasCount(doc,
|
|
693
|
-
if (identity.isAlias(
|
|
694
|
-
const source =
|
|
692
|
+
function getAliasCount(doc, node2, anchors2) {
|
|
693
|
+
if (identity.isAlias(node2)) {
|
|
694
|
+
const source = node2.resolve(doc);
|
|
695
695
|
const anchor = anchors2 && source && anchors2.get(source);
|
|
696
696
|
return anchor ? anchor.count * anchor.aliasCount : 0;
|
|
697
|
-
} else if (identity.isCollection(
|
|
697
|
+
} else if (identity.isCollection(node2)) {
|
|
698
698
|
let count = 0;
|
|
699
|
-
for (const item of
|
|
699
|
+
for (const item of node2.items) {
|
|
700
700
|
const c = getAliasCount(doc, item, anchors2);
|
|
701
701
|
if (c > count)
|
|
702
702
|
count = c;
|
|
703
703
|
}
|
|
704
704
|
return count;
|
|
705
|
-
} else if (identity.isPair(
|
|
706
|
-
const kc = getAliasCount(doc,
|
|
707
|
-
const vc = getAliasCount(doc,
|
|
705
|
+
} else if (identity.isPair(node2)) {
|
|
706
|
+
const kc = getAliasCount(doc, node2.key, anchors2);
|
|
707
|
+
const vc = getAliasCount(doc, node2.value, anchors2);
|
|
708
708
|
return Math.max(kc, vc);
|
|
709
709
|
}
|
|
710
710
|
return 1;
|
|
@@ -789,10 +789,10 @@ var require_createNode = __commonJS((exports) => {
|
|
|
789
789
|
value = value.toJSON();
|
|
790
790
|
}
|
|
791
791
|
if (!value || typeof value !== "object") {
|
|
792
|
-
const
|
|
792
|
+
const node3 = new Scalar.Scalar(value);
|
|
793
793
|
if (ref)
|
|
794
|
-
ref.node =
|
|
795
|
-
return
|
|
794
|
+
ref.node = node3;
|
|
795
|
+
return node3;
|
|
796
796
|
}
|
|
797
797
|
tagObj = value instanceof Map ? schema[identity.MAP] : (Symbol.iterator in Object(value)) ? schema[identity.SEQ] : schema[identity.MAP];
|
|
798
798
|
}
|
|
@@ -800,14 +800,14 @@ var require_createNode = __commonJS((exports) => {
|
|
|
800
800
|
onTagObj(tagObj);
|
|
801
801
|
delete ctx.onTagObj;
|
|
802
802
|
}
|
|
803
|
-
const
|
|
803
|
+
const node2 = tagObj?.createNode ? tagObj.createNode(ctx.schema, value, ctx) : typeof tagObj?.nodeClass?.from === "function" ? tagObj.nodeClass.from(ctx.schema, value, ctx) : new Scalar.Scalar(value);
|
|
804
804
|
if (tagName)
|
|
805
|
-
|
|
805
|
+
node2.tag = tagName;
|
|
806
806
|
else if (!tagObj.default)
|
|
807
|
-
|
|
807
|
+
node2.tag = tagObj.tag;
|
|
808
808
|
if (ref)
|
|
809
|
-
ref.node =
|
|
810
|
-
return
|
|
809
|
+
ref.node = node2;
|
|
810
|
+
return node2;
|
|
811
811
|
}
|
|
812
812
|
exports.createNode = createNode;
|
|
813
813
|
});
|
|
@@ -865,10 +865,10 @@ var require_Collection = __commonJS((exports) => {
|
|
|
865
865
|
this.add(value);
|
|
866
866
|
else {
|
|
867
867
|
const [key, ...rest] = path;
|
|
868
|
-
const
|
|
869
|
-
if (identity.isCollection(
|
|
870
|
-
|
|
871
|
-
else if (
|
|
868
|
+
const node2 = this.get(key, true);
|
|
869
|
+
if (identity.isCollection(node2))
|
|
870
|
+
node2.addIn(rest, value);
|
|
871
|
+
else if (node2 === undefined && this.schema)
|
|
872
872
|
this.set(key, collectionFromPath(this.schema, rest, value));
|
|
873
873
|
else
|
|
874
874
|
throw new Error(`Expected YAML collection at ${key}. Remaining path: ${rest}`);
|
|
@@ -878,25 +878,25 @@ var require_Collection = __commonJS((exports) => {
|
|
|
878
878
|
const [key, ...rest] = path;
|
|
879
879
|
if (rest.length === 0)
|
|
880
880
|
return this.delete(key);
|
|
881
|
-
const
|
|
882
|
-
if (identity.isCollection(
|
|
883
|
-
return
|
|
881
|
+
const node2 = this.get(key, true);
|
|
882
|
+
if (identity.isCollection(node2))
|
|
883
|
+
return node2.deleteIn(rest);
|
|
884
884
|
else
|
|
885
885
|
throw new Error(`Expected YAML collection at ${key}. Remaining path: ${rest}`);
|
|
886
886
|
}
|
|
887
887
|
getIn(path, keepScalar) {
|
|
888
888
|
const [key, ...rest] = path;
|
|
889
|
-
const
|
|
889
|
+
const node2 = this.get(key, true);
|
|
890
890
|
if (rest.length === 0)
|
|
891
|
-
return !keepScalar && identity.isScalar(
|
|
891
|
+
return !keepScalar && identity.isScalar(node2) ? node2.value : node2;
|
|
892
892
|
else
|
|
893
|
-
return identity.isCollection(
|
|
893
|
+
return identity.isCollection(node2) ? node2.getIn(rest, keepScalar) : undefined;
|
|
894
894
|
}
|
|
895
895
|
hasAllNullValues(allowScalar) {
|
|
896
|
-
return this.items.every((
|
|
897
|
-
if (!identity.isPair(
|
|
896
|
+
return this.items.every((node2) => {
|
|
897
|
+
if (!identity.isPair(node2))
|
|
898
898
|
return false;
|
|
899
|
-
const n =
|
|
899
|
+
const n = node2.value;
|
|
900
900
|
return n == null || allowScalar && identity.isScalar(n) && n.value == null && !n.commentBefore && !n.comment && !n.tag;
|
|
901
901
|
});
|
|
902
902
|
}
|
|
@@ -904,18 +904,18 @@ var require_Collection = __commonJS((exports) => {
|
|
|
904
904
|
const [key, ...rest] = path;
|
|
905
905
|
if (rest.length === 0)
|
|
906
906
|
return this.has(key);
|
|
907
|
-
const
|
|
908
|
-
return identity.isCollection(
|
|
907
|
+
const node2 = this.get(key, true);
|
|
908
|
+
return identity.isCollection(node2) ? node2.hasIn(rest) : false;
|
|
909
909
|
}
|
|
910
910
|
setIn(path, value) {
|
|
911
911
|
const [key, ...rest] = path;
|
|
912
912
|
if (rest.length === 0) {
|
|
913
913
|
this.set(key, value);
|
|
914
914
|
} else {
|
|
915
|
-
const
|
|
916
|
-
if (identity.isCollection(
|
|
917
|
-
|
|
918
|
-
else if (
|
|
915
|
+
const node2 = this.get(key, true);
|
|
916
|
+
if (identity.isCollection(node2))
|
|
917
|
+
node2.setIn(rest, value);
|
|
918
|
+
else if (node2 === undefined && this.schema)
|
|
919
919
|
this.set(key, collectionFromPath(this.schema, rest, value));
|
|
920
920
|
else
|
|
921
921
|
throw new Error(`Expected YAML collection at ${key}. Remaining path: ${rest}`);
|
|
@@ -1454,16 +1454,16 @@ var require_stringify = __commonJS((exports) => {
|
|
|
1454
1454
|
}
|
|
1455
1455
|
return tagObj;
|
|
1456
1456
|
}
|
|
1457
|
-
function stringifyProps(
|
|
1457
|
+
function stringifyProps(node2, tagObj, { anchors: anchors$1, doc }) {
|
|
1458
1458
|
if (!doc.directives)
|
|
1459
1459
|
return "";
|
|
1460
1460
|
const props = [];
|
|
1461
|
-
const anchor = (identity.isScalar(
|
|
1461
|
+
const anchor = (identity.isScalar(node2) || identity.isCollection(node2)) && node2.anchor;
|
|
1462
1462
|
if (anchor && anchors.anchorIsValid(anchor)) {
|
|
1463
1463
|
anchors$1.add(anchor);
|
|
1464
1464
|
props.push(`&${anchor}`);
|
|
1465
1465
|
}
|
|
1466
|
-
const tag =
|
|
1466
|
+
const tag = node2.tag ?? (tagObj.default ? null : tagObj.tag);
|
|
1467
1467
|
if (tag)
|
|
1468
1468
|
props.push(doc.directives.tagString(tag));
|
|
1469
1469
|
return props.join(" ");
|
|
@@ -1485,15 +1485,15 @@ var require_stringify = __commonJS((exports) => {
|
|
|
1485
1485
|
}
|
|
1486
1486
|
}
|
|
1487
1487
|
let tagObj = undefined;
|
|
1488
|
-
const
|
|
1489
|
-
tagObj ?? (tagObj = getTagObject(ctx.doc.schema.tags,
|
|
1490
|
-
const props = stringifyProps(
|
|
1488
|
+
const node2 = identity.isNode(item) ? item : ctx.doc.createNode(item, { onTagObj: (o) => tagObj = o });
|
|
1489
|
+
tagObj ?? (tagObj = getTagObject(ctx.doc.schema.tags, node2));
|
|
1490
|
+
const props = stringifyProps(node2, tagObj, ctx);
|
|
1491
1491
|
if (props.length > 0)
|
|
1492
1492
|
ctx.indentAtStart = (ctx.indentAtStart ?? 0) + props.length + 1;
|
|
1493
|
-
const str = typeof tagObj.stringify === "function" ? tagObj.stringify(
|
|
1493
|
+
const str = typeof tagObj.stringify === "function" ? tagObj.stringify(node2, ctx, onComment, onChompKeep) : identity.isScalar(node2) ? stringifyString.stringifyString(node2, ctx, onComment, onChompKeep) : node2.toString(ctx, onComment, onChompKeep);
|
|
1494
1494
|
if (!props)
|
|
1495
1495
|
return str;
|
|
1496
|
-
return identity.isScalar(
|
|
1496
|
+
return identity.isScalar(node2) || str[0] === "{" || str[0] === "[" ? `${props} ${str}` : `${props}
|
|
1497
1497
|
${ctx.indent}${str}`;
|
|
1498
1498
|
}
|
|
1499
1499
|
exports.createStringifyContext = createStringifyContext;
|
|
@@ -1754,8 +1754,8 @@ var require_addPairToJSMap = __commonJS((exports) => {
|
|
|
1754
1754
|
if (identity.isNode(key) && ctx?.doc) {
|
|
1755
1755
|
const strCtx = stringify.createStringifyContext(ctx.doc, {});
|
|
1756
1756
|
strCtx.anchors = new Set;
|
|
1757
|
-
for (const
|
|
1758
|
-
strCtx.anchors.add(
|
|
1757
|
+
for (const node2 of ctx.anchors.keys())
|
|
1758
|
+
strCtx.anchors.add(node2.anchor);
|
|
1759
1759
|
strCtx.inFlow = true;
|
|
1760
1760
|
strCtx.inStringifyKey = true;
|
|
1761
1761
|
const strKey = key.toString(strCtx);
|
|
@@ -2051,8 +2051,8 @@ var require_YAMLMap = __commonJS((exports) => {
|
|
|
2051
2051
|
}
|
|
2052
2052
|
get(key, keepScalar) {
|
|
2053
2053
|
const it = findPair(this.items, key);
|
|
2054
|
-
const
|
|
2055
|
-
return (!keepScalar && identity.isScalar(
|
|
2054
|
+
const node2 = it?.value;
|
|
2055
|
+
return (!keepScalar && identity.isScalar(node2) ? node2.value : node2) ?? undefined;
|
|
2056
2056
|
}
|
|
2057
2057
|
has(key) {
|
|
2058
2058
|
return !!findPair(this.items, key);
|
|
@@ -2316,9 +2316,9 @@ var require_float = __commonJS((exports) => {
|
|
|
2316
2316
|
format: "EXP",
|
|
2317
2317
|
test: /^[-+]?(?:\.[0-9]+|[0-9]+(?:\.[0-9]*)?)[eE][-+]?[0-9]+$/,
|
|
2318
2318
|
resolve: (str) => parseFloat(str),
|
|
2319
|
-
stringify(
|
|
2320
|
-
const num = Number(
|
|
2321
|
-
return isFinite(num) ? num.toExponential() : stringifyNumber.stringifyNumber(
|
|
2319
|
+
stringify(node2) {
|
|
2320
|
+
const num = Number(node2.value);
|
|
2321
|
+
return isFinite(num) ? num.toExponential() : stringifyNumber.stringifyNumber(node2);
|
|
2322
2322
|
}
|
|
2323
2323
|
};
|
|
2324
2324
|
var float = {
|
|
@@ -2327,11 +2327,11 @@ var require_float = __commonJS((exports) => {
|
|
|
2327
2327
|
tag: "tag:yaml.org,2002:float",
|
|
2328
2328
|
test: /^[-+]?(?:\.[0-9]+|[0-9]+\.[0-9]*)$/,
|
|
2329
2329
|
resolve(str) {
|
|
2330
|
-
const
|
|
2330
|
+
const node2 = new Scalar.Scalar(parseFloat(str));
|
|
2331
2331
|
const dot = str.indexOf(".");
|
|
2332
2332
|
if (dot !== -1 && str[str.length - 1] === "0")
|
|
2333
|
-
|
|
2334
|
-
return
|
|
2333
|
+
node2.minFractionDigits = str.length - dot - 1;
|
|
2334
|
+
return node2;
|
|
2335
2335
|
},
|
|
2336
2336
|
stringify: stringifyNumber.stringifyNumber
|
|
2337
2337
|
};
|
|
@@ -2345,11 +2345,11 @@ var require_int = __commonJS((exports) => {
|
|
|
2345
2345
|
var stringifyNumber = require_stringifyNumber();
|
|
2346
2346
|
var intIdentify = (value) => typeof value === "bigint" || Number.isInteger(value);
|
|
2347
2347
|
var intResolve = (str, offset, radix, { intAsBigInt }) => intAsBigInt ? BigInt(str) : parseInt(str.substring(offset), radix);
|
|
2348
|
-
function intStringify(
|
|
2349
|
-
const { value } =
|
|
2348
|
+
function intStringify(node2, radix, prefix) {
|
|
2349
|
+
const { value } = node2;
|
|
2350
2350
|
if (intIdentify(value) && value >= 0)
|
|
2351
2351
|
return prefix + value.toString(radix);
|
|
2352
|
-
return stringifyNumber.stringifyNumber(
|
|
2352
|
+
return stringifyNumber.stringifyNumber(node2);
|
|
2353
2353
|
}
|
|
2354
2354
|
var intOct = {
|
|
2355
2355
|
identify: (value) => intIdentify(value) && value >= 0,
|
|
@@ -2358,7 +2358,7 @@ var require_int = __commonJS((exports) => {
|
|
|
2358
2358
|
format: "OCT",
|
|
2359
2359
|
test: /^0o[0-7]+$/,
|
|
2360
2360
|
resolve: (str, _onError, opt) => intResolve(str, 2, 8, opt),
|
|
2361
|
-
stringify: (
|
|
2361
|
+
stringify: (node2) => intStringify(node2, 8, "0o")
|
|
2362
2362
|
};
|
|
2363
2363
|
var int = {
|
|
2364
2364
|
identify: intIdentify,
|
|
@@ -2375,7 +2375,7 @@ var require_int = __commonJS((exports) => {
|
|
|
2375
2375
|
format: "HEX",
|
|
2376
2376
|
test: /^0x[0-9a-fA-F]+$/,
|
|
2377
2377
|
resolve: (str, _onError, opt) => intResolve(str, 2, 16, opt),
|
|
2378
|
-
stringify: (
|
|
2378
|
+
stringify: (node2) => intStringify(node2, 16, "0x")
|
|
2379
2379
|
};
|
|
2380
2380
|
exports.int = int;
|
|
2381
2381
|
exports.intHex = intHex;
|
|
@@ -2721,9 +2721,9 @@ var require_float2 = __commonJS((exports) => {
|
|
|
2721
2721
|
format: "EXP",
|
|
2722
2722
|
test: /^[-+]?(?:[0-9][0-9_]*)?(?:\.[0-9_]*)?[eE][-+]?[0-9]+$/,
|
|
2723
2723
|
resolve: (str) => parseFloat(str.replace(/_/g, "")),
|
|
2724
|
-
stringify(
|
|
2725
|
-
const num = Number(
|
|
2726
|
-
return isFinite(num) ? num.toExponential() : stringifyNumber.stringifyNumber(
|
|
2724
|
+
stringify(node2) {
|
|
2725
|
+
const num = Number(node2.value);
|
|
2726
|
+
return isFinite(num) ? num.toExponential() : stringifyNumber.stringifyNumber(node2);
|
|
2727
2727
|
}
|
|
2728
2728
|
};
|
|
2729
2729
|
var float = {
|
|
@@ -2732,14 +2732,14 @@ var require_float2 = __commonJS((exports) => {
|
|
|
2732
2732
|
tag: "tag:yaml.org,2002:float",
|
|
2733
2733
|
test: /^[-+]?(?:[0-9][0-9_]*)?\.[0-9_]*$/,
|
|
2734
2734
|
resolve(str) {
|
|
2735
|
-
const
|
|
2735
|
+
const node2 = new Scalar.Scalar(parseFloat(str.replace(/_/g, "")));
|
|
2736
2736
|
const dot = str.indexOf(".");
|
|
2737
2737
|
if (dot !== -1) {
|
|
2738
2738
|
const f = str.substring(dot + 1).replace(/_/g, "");
|
|
2739
2739
|
if (f[f.length - 1] === "0")
|
|
2740
|
-
|
|
2740
|
+
node2.minFractionDigits = f.length;
|
|
2741
2741
|
}
|
|
2742
|
-
return
|
|
2742
|
+
return node2;
|
|
2743
2743
|
},
|
|
2744
2744
|
stringify: stringifyNumber.stringifyNumber
|
|
2745
2745
|
};
|
|
@@ -2775,13 +2775,13 @@ var require_int2 = __commonJS((exports) => {
|
|
|
2775
2775
|
const n = parseInt(str, radix);
|
|
2776
2776
|
return sign === "-" ? -1 * n : n;
|
|
2777
2777
|
}
|
|
2778
|
-
function intStringify(
|
|
2779
|
-
const { value } =
|
|
2778
|
+
function intStringify(node2, radix, prefix) {
|
|
2779
|
+
const { value } = node2;
|
|
2780
2780
|
if (intIdentify(value)) {
|
|
2781
2781
|
const str = value.toString(radix);
|
|
2782
2782
|
return value < 0 ? "-" + prefix + str.substr(1) : prefix + str;
|
|
2783
2783
|
}
|
|
2784
|
-
return stringifyNumber.stringifyNumber(
|
|
2784
|
+
return stringifyNumber.stringifyNumber(node2);
|
|
2785
2785
|
}
|
|
2786
2786
|
var intBin = {
|
|
2787
2787
|
identify: intIdentify,
|
|
@@ -2790,7 +2790,7 @@ var require_int2 = __commonJS((exports) => {
|
|
|
2790
2790
|
format: "BIN",
|
|
2791
2791
|
test: /^[-+]?0b[0-1_]+$/,
|
|
2792
2792
|
resolve: (str, _onError, opt) => intResolve(str, 2, 2, opt),
|
|
2793
|
-
stringify: (
|
|
2793
|
+
stringify: (node2) => intStringify(node2, 2, "0b")
|
|
2794
2794
|
};
|
|
2795
2795
|
var intOct = {
|
|
2796
2796
|
identify: intIdentify,
|
|
@@ -2799,7 +2799,7 @@ var require_int2 = __commonJS((exports) => {
|
|
|
2799
2799
|
format: "OCT",
|
|
2800
2800
|
test: /^[-+]?0[0-7_]+$/,
|
|
2801
2801
|
resolve: (str, _onError, opt) => intResolve(str, 1, 8, opt),
|
|
2802
|
-
stringify: (
|
|
2802
|
+
stringify: (node2) => intStringify(node2, 8, "0")
|
|
2803
2803
|
};
|
|
2804
2804
|
var int = {
|
|
2805
2805
|
identify: intIdentify,
|
|
@@ -2816,7 +2816,7 @@ var require_int2 = __commonJS((exports) => {
|
|
|
2816
2816
|
format: "HEX",
|
|
2817
2817
|
test: /^[-+]?0x[0-9a-fA-F_]+$/,
|
|
2818
2818
|
resolve: (str, _onError, opt) => intResolve(str, 2, 16, opt),
|
|
2819
|
-
stringify: (
|
|
2819
|
+
stringify: (node2) => intStringify(node2, 16, "0x")
|
|
2820
2820
|
};
|
|
2821
2821
|
exports.int = int;
|
|
2822
2822
|
exports.intBin = intBin;
|
|
@@ -2917,13 +2917,13 @@ var require_timestamp = __commonJS((exports) => {
|
|
|
2917
2917
|
const res = parts.replace(/_/g, "").split(":").reduce((res2, p) => res2 * num(60) + num(p), num(0));
|
|
2918
2918
|
return sign === "-" ? num(-1) * res : res;
|
|
2919
2919
|
}
|
|
2920
|
-
function stringifySexagesimal(
|
|
2921
|
-
let { value } =
|
|
2920
|
+
function stringifySexagesimal(node2) {
|
|
2921
|
+
let { value } = node2;
|
|
2922
2922
|
let num = (n) => n;
|
|
2923
2923
|
if (typeof value === "bigint")
|
|
2924
2924
|
num = (n) => BigInt(n);
|
|
2925
2925
|
else if (isNaN(value) || !isFinite(value))
|
|
2926
|
-
return stringifyNumber.stringifyNumber(
|
|
2926
|
+
return stringifyNumber.stringifyNumber(node2);
|
|
2927
2927
|
let sign = "";
|
|
2928
2928
|
if (value < 0) {
|
|
2929
2929
|
sign = "-";
|
|
@@ -3305,12 +3305,12 @@ var require_Document = __commonJS((exports) => {
|
|
|
3305
3305
|
if (assertCollection(this.contents))
|
|
3306
3306
|
this.contents.addIn(path, value);
|
|
3307
3307
|
}
|
|
3308
|
-
createAlias(
|
|
3309
|
-
if (!
|
|
3308
|
+
createAlias(node2, name) {
|
|
3309
|
+
if (!node2.anchor) {
|
|
3310
3310
|
const prev = anchors.anchorNames(this);
|
|
3311
|
-
|
|
3311
|
+
node2.anchor = !name || prev.has(name) ? anchors.findNewAnchor(name || "a", prev) : name;
|
|
3312
3312
|
}
|
|
3313
|
-
return new Alias.Alias(
|
|
3313
|
+
return new Alias.Alias(node2.anchor);
|
|
3314
3314
|
}
|
|
3315
3315
|
createNode(value, replacer, options) {
|
|
3316
3316
|
let _replacer = undefined;
|
|
@@ -3338,11 +3338,11 @@ var require_Document = __commonJS((exports) => {
|
|
|
3338
3338
|
schema: this.schema,
|
|
3339
3339
|
sourceObjects
|
|
3340
3340
|
};
|
|
3341
|
-
const
|
|
3342
|
-
if (flow && identity.isCollection(
|
|
3343
|
-
|
|
3341
|
+
const node2 = createNode.createNode(value, tag, ctx);
|
|
3342
|
+
if (flow && identity.isCollection(node2))
|
|
3343
|
+
node2.flow = true;
|
|
3344
3344
|
setAnchors();
|
|
3345
|
-
return
|
|
3345
|
+
return node2;
|
|
3346
3346
|
}
|
|
3347
3347
|
createPair(key, value, options = {}) {
|
|
3348
3348
|
const k = this.createNode(key, null, options);
|
|
@@ -3872,11 +3872,11 @@ var require_resolve_block_seq = __commonJS((exports) => {
|
|
|
3872
3872
|
continue;
|
|
3873
3873
|
}
|
|
3874
3874
|
}
|
|
3875
|
-
const
|
|
3875
|
+
const node2 = value ? composeNode(ctx, value, props, onError) : composeEmptyNode(ctx, props.end, start, null, props, onError);
|
|
3876
3876
|
if (ctx.schema.compat)
|
|
3877
3877
|
utilFlowIndentCheck.flowIndentCheck(bs.indent, value, onError);
|
|
3878
|
-
offset =
|
|
3879
|
-
seq.items.push(
|
|
3878
|
+
offset = node2.range[2];
|
|
3879
|
+
seq.items.push(node2);
|
|
3880
3880
|
}
|
|
3881
3881
|
seq.range = [bs.offset, offset, commentEnd ?? offset];
|
|
3882
3882
|
return seq;
|
|
@@ -4167,12 +4167,12 @@ var require_compose_collection = __commonJS((exports) => {
|
|
|
4167
4167
|
}
|
|
4168
4168
|
const coll = resolveCollection(CN, ctx, token, onError, tagName, tag);
|
|
4169
4169
|
const res = tag.resolve?.(coll, (msg) => onError(tagToken, "TAG_RESOLVE_FAILED", msg), ctx.options) ?? coll;
|
|
4170
|
-
const
|
|
4171
|
-
|
|
4172
|
-
|
|
4170
|
+
const node2 = identity.isNode(res) ? res : new Scalar.Scalar(res);
|
|
4171
|
+
node2.range = coll.range;
|
|
4172
|
+
node2.tag = tagName;
|
|
4173
4173
|
if (tag?.format)
|
|
4174
|
-
|
|
4175
|
-
return
|
|
4174
|
+
node2.format = tag.format;
|
|
4175
|
+
return node2;
|
|
4176
4176
|
}
|
|
4177
4177
|
exports.composeCollection = composeCollection;
|
|
4178
4178
|
});
|
|
@@ -4704,11 +4704,11 @@ var require_compose_node = __commonJS((exports) => {
|
|
|
4704
4704
|
function composeNode(ctx, token, props, onError) {
|
|
4705
4705
|
const atKey = ctx.atKey;
|
|
4706
4706
|
const { spaceBefore, comment, anchor, tag } = props;
|
|
4707
|
-
let
|
|
4707
|
+
let node2;
|
|
4708
4708
|
let isSrcToken = true;
|
|
4709
4709
|
switch (token.type) {
|
|
4710
4710
|
case "alias":
|
|
4711
|
-
|
|
4711
|
+
node2 = composeAlias(ctx, token, onError);
|
|
4712
4712
|
if (anchor || tag)
|
|
4713
4713
|
onError(token, "ALIAS_PROPS", "An alias node must not specify any properties");
|
|
4714
4714
|
break;
|
|
@@ -4716,17 +4716,17 @@ var require_compose_node = __commonJS((exports) => {
|
|
|
4716
4716
|
case "single-quoted-scalar":
|
|
4717
4717
|
case "double-quoted-scalar":
|
|
4718
4718
|
case "block-scalar":
|
|
4719
|
-
|
|
4719
|
+
node2 = composeScalar.composeScalar(ctx, token, tag, onError);
|
|
4720
4720
|
if (anchor)
|
|
4721
|
-
|
|
4721
|
+
node2.anchor = anchor.source.substring(1);
|
|
4722
4722
|
break;
|
|
4723
4723
|
case "block-map":
|
|
4724
4724
|
case "block-seq":
|
|
4725
4725
|
case "flow-collection":
|
|
4726
4726
|
try {
|
|
4727
|
-
|
|
4727
|
+
node2 = composeCollection.composeCollection(CN, ctx, token, props, onError);
|
|
4728
4728
|
if (anchor)
|
|
4729
|
-
|
|
4729
|
+
node2.anchor = anchor.source.substring(1);
|
|
4730
4730
|
} catch (error) {
|
|
4731
4731
|
const message = error instanceof Error ? error.message : String(error);
|
|
4732
4732
|
onError(token, "RESOURCE_EXHAUSTION", message);
|
|
@@ -4738,24 +4738,24 @@ var require_compose_node = __commonJS((exports) => {
|
|
|
4738
4738
|
isSrcToken = false;
|
|
4739
4739
|
}
|
|
4740
4740
|
}
|
|
4741
|
-
|
|
4742
|
-
if (anchor &&
|
|
4741
|
+
node2 ?? (node2 = composeEmptyNode(ctx, token.offset, undefined, null, props, onError));
|
|
4742
|
+
if (anchor && node2.anchor === "")
|
|
4743
4743
|
onError(anchor, "BAD_ALIAS", "Anchor cannot be an empty string");
|
|
4744
|
-
if (atKey && ctx.options.stringKeys && (!identity.isScalar(
|
|
4744
|
+
if (atKey && ctx.options.stringKeys && (!identity.isScalar(node2) || typeof node2.value !== "string" || node2.tag && node2.tag !== "tag:yaml.org,2002:str")) {
|
|
4745
4745
|
const msg = "With stringKeys, all keys must be strings";
|
|
4746
4746
|
onError(tag ?? token, "NON_STRING_KEY", msg);
|
|
4747
4747
|
}
|
|
4748
4748
|
if (spaceBefore)
|
|
4749
|
-
|
|
4749
|
+
node2.spaceBefore = true;
|
|
4750
4750
|
if (comment) {
|
|
4751
4751
|
if (token.type === "scalar" && token.source === "")
|
|
4752
|
-
|
|
4752
|
+
node2.comment = comment;
|
|
4753
4753
|
else
|
|
4754
|
-
|
|
4754
|
+
node2.commentBefore = comment;
|
|
4755
4755
|
}
|
|
4756
4756
|
if (ctx.options.keepSourceTokens && isSrcToken)
|
|
4757
|
-
|
|
4758
|
-
return
|
|
4757
|
+
node2.srcToken = token;
|
|
4758
|
+
return node2;
|
|
4759
4759
|
}
|
|
4760
4760
|
function composeEmptyNode(ctx, offset, before, pos, { spaceBefore, comment, anchor, tag, end }, onError) {
|
|
4761
4761
|
const token = {
|
|
@@ -4764,19 +4764,19 @@ var require_compose_node = __commonJS((exports) => {
|
|
|
4764
4764
|
indent: -1,
|
|
4765
4765
|
source: ""
|
|
4766
4766
|
};
|
|
4767
|
-
const
|
|
4767
|
+
const node2 = composeScalar.composeScalar(ctx, token, tag, onError);
|
|
4768
4768
|
if (anchor) {
|
|
4769
|
-
|
|
4770
|
-
if (
|
|
4769
|
+
node2.anchor = anchor.source.substring(1);
|
|
4770
|
+
if (node2.anchor === "")
|
|
4771
4771
|
onError(anchor, "BAD_ALIAS", "Anchor cannot be an empty string");
|
|
4772
4772
|
}
|
|
4773
4773
|
if (spaceBefore)
|
|
4774
|
-
|
|
4774
|
+
node2.spaceBefore = true;
|
|
4775
4775
|
if (comment) {
|
|
4776
|
-
|
|
4777
|
-
|
|
4776
|
+
node2.comment = comment;
|
|
4777
|
+
node2.range[2] = end;
|
|
4778
4778
|
}
|
|
4779
|
-
return
|
|
4779
|
+
return node2;
|
|
4780
4780
|
}
|
|
4781
4781
|
function composeAlias({ options }, { offset, source, end }, onError) {
|
|
4782
4782
|
const alias = new Alias.Alias(source.substring(1));
|
|
@@ -7044,7 +7044,7 @@ function getExitCode(error) {
|
|
|
7044
7044
|
// package.json
|
|
7045
7045
|
var package_default = {
|
|
7046
7046
|
name: "cc-codeconductor",
|
|
7047
|
-
version: "0.
|
|
7047
|
+
version: "0.3.1",
|
|
7048
7048
|
description: "A multi-agent orchestration framework for AI-assisted software engineering workflows.",
|
|
7049
7049
|
keywords: [
|
|
7050
7050
|
"ai",
|
|
@@ -7098,6 +7098,230 @@ var package_default = {
|
|
|
7098
7098
|
}
|
|
7099
7099
|
};
|
|
7100
7100
|
|
|
7101
|
+
// src/core/detection/detectors/node.ts
|
|
7102
|
+
async function detectNode(rootDir) {
|
|
7103
|
+
const { fileExists: fileExists2 } = await Promise.resolve().then(() => (init_safety(), exports_safety));
|
|
7104
|
+
const signals = [];
|
|
7105
|
+
if (await fileExists2(rootDir, "package.json")) {
|
|
7106
|
+
signals.push("package.json");
|
|
7107
|
+
}
|
|
7108
|
+
if (await fileExists2(rootDir, "node_modules")) {
|
|
7109
|
+
signals.push("node_modules/");
|
|
7110
|
+
}
|
|
7111
|
+
return signals;
|
|
7112
|
+
}
|
|
7113
|
+
async function detectBun(rootDir) {
|
|
7114
|
+
const { fileExists: fileExists2 } = await Promise.resolve().then(() => (init_safety(), exports_safety));
|
|
7115
|
+
const signals = [];
|
|
7116
|
+
if (await fileExists2(rootDir, "bun.lockb")) {
|
|
7117
|
+
signals.push("bun.lockb");
|
|
7118
|
+
}
|
|
7119
|
+
if (await fileExists2(rootDir, "bun.lock")) {
|
|
7120
|
+
signals.push("bun.lock");
|
|
7121
|
+
}
|
|
7122
|
+
return signals;
|
|
7123
|
+
}
|
|
7124
|
+
// src/core/detection/detectors/backend.ts
|
|
7125
|
+
async function detectSpring(rootDir) {
|
|
7126
|
+
const { fileExists: fileExists2 } = await Promise.resolve().then(() => (init_safety(), exports_safety));
|
|
7127
|
+
const signals = [];
|
|
7128
|
+
if (await fileExists2(rootDir, "build.gradle") || await fileExists2(rootDir, "build.gradle.kts")) {
|
|
7129
|
+
signals.push("build.gradle");
|
|
7130
|
+
}
|
|
7131
|
+
if (await fileExists2(rootDir, "pom.xml")) {
|
|
7132
|
+
signals.push("pom.xml");
|
|
7133
|
+
}
|
|
7134
|
+
return signals;
|
|
7135
|
+
}
|
|
7136
|
+
async function detectDjango(rootDir) {
|
|
7137
|
+
const { fileExists: fileExists2 } = await Promise.resolve().then(() => (init_safety(), exports_safety));
|
|
7138
|
+
const signals = [];
|
|
7139
|
+
if (await fileExists2(rootDir, "manage.py")) {
|
|
7140
|
+
signals.push("manage.py");
|
|
7141
|
+
}
|
|
7142
|
+
if (await fileExists2(rootDir, "requirements.txt")) {
|
|
7143
|
+
signals.push("requirements.txt");
|
|
7144
|
+
}
|
|
7145
|
+
return signals;
|
|
7146
|
+
}
|
|
7147
|
+
async function detectFastApi(rootDir) {
|
|
7148
|
+
const { fileExists: fileExists2 } = await Promise.resolve().then(() => (init_safety(), exports_safety));
|
|
7149
|
+
const { join } = await import("node:path");
|
|
7150
|
+
const { readFile } = await import("node:fs/promises");
|
|
7151
|
+
const signals = [];
|
|
7152
|
+
if (await fileExists2(rootDir, "requirements.txt")) {
|
|
7153
|
+
try {
|
|
7154
|
+
const content = await readFile(join(rootDir, "requirements.txt"), "utf-8");
|
|
7155
|
+
if (content.includes("fastapi")) {
|
|
7156
|
+
signals.push("fastapi-requirements");
|
|
7157
|
+
}
|
|
7158
|
+
} catch {}
|
|
7159
|
+
}
|
|
7160
|
+
if (await fileExists2(rootDir, "pyproject.toml")) {
|
|
7161
|
+
try {
|
|
7162
|
+
const content = await readFile(join(rootDir, "pyproject.toml"), "utf-8");
|
|
7163
|
+
if (content.includes("fastapi")) {
|
|
7164
|
+
signals.push("fastapi-pyproject");
|
|
7165
|
+
}
|
|
7166
|
+
} catch {}
|
|
7167
|
+
}
|
|
7168
|
+
for (const filename of ["main.py", "app.py", "app/main.py", "app/app.py"]) {
|
|
7169
|
+
if (await fileExists2(rootDir, filename)) {
|
|
7170
|
+
try {
|
|
7171
|
+
const content = await readFile(join(rootDir, filename), "utf-8");
|
|
7172
|
+
if (content.includes("FastAPI") && content.includes("fastapi")) {
|
|
7173
|
+
signals.push(`${filename}-fastapi`);
|
|
7174
|
+
}
|
|
7175
|
+
} catch {}
|
|
7176
|
+
}
|
|
7177
|
+
}
|
|
7178
|
+
return signals;
|
|
7179
|
+
}
|
|
7180
|
+
async function detectPhp(rootDir) {
|
|
7181
|
+
const { fileExists: fileExists2 } = await Promise.resolve().then(() => (init_safety(), exports_safety));
|
|
7182
|
+
const signals = [];
|
|
7183
|
+
if (await fileExists2(rootDir, "composer.json")) {
|
|
7184
|
+
signals.push("composer.json");
|
|
7185
|
+
}
|
|
7186
|
+
if (await fileExists2(rootDir, "artisan")) {
|
|
7187
|
+
signals.push("artisan");
|
|
7188
|
+
}
|
|
7189
|
+
try {
|
|
7190
|
+
const { readdir } = await import("node:fs/promises");
|
|
7191
|
+
const entries = await readdir(rootDir, { withFileTypes: true });
|
|
7192
|
+
const hasPhpFiles = entries.some((entry) => entry.isFile() && entry.name.endsWith(".php"));
|
|
7193
|
+
if (hasPhpFiles) {
|
|
7194
|
+
signals.push("*.php");
|
|
7195
|
+
}
|
|
7196
|
+
} catch {}
|
|
7197
|
+
return signals;
|
|
7198
|
+
}
|
|
7199
|
+
async function detectGenericBackend(rootDir) {
|
|
7200
|
+
const { fileExists: fileExists2 } = await Promise.resolve().then(() => (init_safety(), exports_safety));
|
|
7201
|
+
const { readdir } = await import("node:fs/promises");
|
|
7202
|
+
const signals = [];
|
|
7203
|
+
if (await fileExists2(rootDir, "go.mod")) {
|
|
7204
|
+
signals.push("go.mod");
|
|
7205
|
+
}
|
|
7206
|
+
if (await fileExists2(rootDir, "Cargo.toml")) {
|
|
7207
|
+
signals.push("Cargo.toml");
|
|
7208
|
+
}
|
|
7209
|
+
if (await fileExists2(rootDir, "Gemfile")) {
|
|
7210
|
+
signals.push("Gemfile");
|
|
7211
|
+
}
|
|
7212
|
+
try {
|
|
7213
|
+
const entries = await readdir(rootDir, { withFileTypes: true });
|
|
7214
|
+
const hasCsProj = entries.some((entry) => entry.isFile() && entry.name.endsWith(".csproj"));
|
|
7215
|
+
if (hasCsProj) {
|
|
7216
|
+
signals.push("*.csproj");
|
|
7217
|
+
}
|
|
7218
|
+
} catch {}
|
|
7219
|
+
return signals;
|
|
7220
|
+
}
|
|
7221
|
+
// src/core/detection/detectors/frontend.ts
|
|
7222
|
+
async function detectAstro(rootDir) {
|
|
7223
|
+
const { fileExists: fileExists2 } = await Promise.resolve().then(() => (init_safety(), exports_safety));
|
|
7224
|
+
const signals = [];
|
|
7225
|
+
if (await fileExists2(rootDir, "astro.config.mjs") || await fileExists2(rootDir, "astro.config.ts")) {
|
|
7226
|
+
signals.push("astro.config");
|
|
7227
|
+
}
|
|
7228
|
+
return signals;
|
|
7229
|
+
}
|
|
7230
|
+
async function detectNext(rootDir) {
|
|
7231
|
+
const { fileExists: fileExists2 } = await Promise.resolve().then(() => (init_safety(), exports_safety));
|
|
7232
|
+
const { join } = await import("node:path");
|
|
7233
|
+
const { readFile } = await import("node:fs/promises");
|
|
7234
|
+
const signals = [];
|
|
7235
|
+
if (await fileExists2(rootDir, "next.config.js") || await fileExists2(rootDir, "next.config.mjs") || await fileExists2(rootDir, "next.config.ts")) {
|
|
7236
|
+
signals.push("next.config");
|
|
7237
|
+
}
|
|
7238
|
+
if (await fileExists2(rootDir, "package.json")) {
|
|
7239
|
+
try {
|
|
7240
|
+
const content = await readFile(join(rootDir, "package.json"), "utf-8");
|
|
7241
|
+
const pkg = JSON.parse(content);
|
|
7242
|
+
if (pkg.dependencies?.next || pkg.devDependencies?.next) {
|
|
7243
|
+
signals.push("package.json-next");
|
|
7244
|
+
}
|
|
7245
|
+
} catch {}
|
|
7246
|
+
}
|
|
7247
|
+
return signals;
|
|
7248
|
+
}
|
|
7249
|
+
async function detectGenericFrontend(rootDir) {
|
|
7250
|
+
const { fileExists: fileExists2 } = await Promise.resolve().then(() => (init_safety(), exports_safety));
|
|
7251
|
+
const { join } = await import("node:path");
|
|
7252
|
+
const { readFile } = await import("node:fs/promises");
|
|
7253
|
+
const signals = [];
|
|
7254
|
+
if (await fileExists2(rootDir, "index.html")) {
|
|
7255
|
+
signals.push("index.html");
|
|
7256
|
+
}
|
|
7257
|
+
if (await fileExists2(rootDir, "vite.config.js") || await fileExists2(rootDir, "vite.config.ts")) {
|
|
7258
|
+
signals.push("vite.config");
|
|
7259
|
+
}
|
|
7260
|
+
if (await fileExists2(rootDir, "webpack.config.js")) {
|
|
7261
|
+
signals.push("webpack.config.js");
|
|
7262
|
+
}
|
|
7263
|
+
if (await fileExists2(rootDir, "package.json")) {
|
|
7264
|
+
try {
|
|
7265
|
+
const content = await readFile(join(rootDir, "package.json"), "utf-8");
|
|
7266
|
+
const pkg = JSON.parse(content);
|
|
7267
|
+
const frontendDeps = ["react", "vue", "svelte", "solid-js", "angular", "@angular/core"];
|
|
7268
|
+
const hasFrontendDep = frontendDeps.some((dep) => pkg.dependencies?.[dep] || pkg.devDependencies?.[dep]);
|
|
7269
|
+
if (hasFrontendDep) {
|
|
7270
|
+
signals.push("package.json-frontend");
|
|
7271
|
+
}
|
|
7272
|
+
} catch {}
|
|
7273
|
+
}
|
|
7274
|
+
return signals;
|
|
7275
|
+
}
|
|
7276
|
+
// src/core/detection/detectors/monorepo.ts
|
|
7277
|
+
async function detectMonorepo(rootDir) {
|
|
7278
|
+
const { fileExists: fileExists2 } = await Promise.resolve().then(() => (init_safety(), exports_safety));
|
|
7279
|
+
const { join } = await import("node:path");
|
|
7280
|
+
const { readFile } = await import("node:fs/promises");
|
|
7281
|
+
const signals = [];
|
|
7282
|
+
if (await fileExists2(rootDir, "pnpm-workspace.yaml")) {
|
|
7283
|
+
signals.push("pnpm-workspace.yaml");
|
|
7284
|
+
}
|
|
7285
|
+
if (await fileExists2(rootDir, "lerna.json")) {
|
|
7286
|
+
signals.push("lerna.json");
|
|
7287
|
+
}
|
|
7288
|
+
if (await fileExists2(rootDir, "go.work")) {
|
|
7289
|
+
signals.push("go.work");
|
|
7290
|
+
}
|
|
7291
|
+
if (await fileExists2(rootDir, "package.json")) {
|
|
7292
|
+
try {
|
|
7293
|
+
const content = await readFile(join(rootDir, "package.json"), "utf-8");
|
|
7294
|
+
const pkg = JSON.parse(content);
|
|
7295
|
+
if (pkg.workspaces) {
|
|
7296
|
+
signals.push("package.json-workspaces");
|
|
7297
|
+
}
|
|
7298
|
+
} catch {}
|
|
7299
|
+
}
|
|
7300
|
+
if (await fileExists2(rootDir, "Cargo.toml")) {
|
|
7301
|
+
try {
|
|
7302
|
+
const content = await readFile(join(rootDir, "Cargo.toml"), "utf-8");
|
|
7303
|
+
if (content.includes("[workspace]")) {
|
|
7304
|
+
signals.push("Cargo.toml-workspace");
|
|
7305
|
+
}
|
|
7306
|
+
} catch {}
|
|
7307
|
+
}
|
|
7308
|
+
return signals;
|
|
7309
|
+
}
|
|
7310
|
+
// src/core/detection/detectors/android.ts
|
|
7311
|
+
async function detectAndroid(rootDir) {
|
|
7312
|
+
const { fileExists: fileExists2 } = await Promise.resolve().then(() => (init_safety(), exports_safety));
|
|
7313
|
+
const signals = [];
|
|
7314
|
+
if (await fileExists2(rootDir, "AndroidManifest.xml") || await fileExists2(rootDir, "app/src/main/AndroidManifest.xml")) {
|
|
7315
|
+
signals.push("AndroidManifest.xml");
|
|
7316
|
+
}
|
|
7317
|
+
if (await fileExists2(rootDir, "settings.gradle") || await fileExists2(rootDir, "settings.gradle.kts")) {
|
|
7318
|
+
signals.push("settings.gradle");
|
|
7319
|
+
}
|
|
7320
|
+
if (await fileExists2(rootDir, "gradlew")) {
|
|
7321
|
+
signals.push("gradlew");
|
|
7322
|
+
}
|
|
7323
|
+
return signals;
|
|
7324
|
+
}
|
|
7101
7325
|
// src/core/detection/project-detector.ts
|
|
7102
7326
|
async function detectProject(rootDir) {
|
|
7103
7327
|
const signals = [];
|
|
@@ -7138,12 +7362,68 @@ async function detectProject(rootDir) {
|
|
|
7138
7362
|
languages.push("php");
|
|
7139
7363
|
runtimes.push("php");
|
|
7140
7364
|
packageManagers.push("composer");
|
|
7365
|
+
if (phpSignals.includes("artisan")) {
|
|
7366
|
+
frameworks.push("laravel");
|
|
7367
|
+
}
|
|
7141
7368
|
}
|
|
7142
7369
|
const astroSignals = await detectAstro(rootDir);
|
|
7143
7370
|
if (astroSignals.length > 0) {
|
|
7144
7371
|
signals.push(...astroSignals);
|
|
7145
7372
|
frameworks.push("astro");
|
|
7146
7373
|
}
|
|
7374
|
+
const nextSignals = await detectNext(rootDir);
|
|
7375
|
+
if (nextSignals.length > 0) {
|
|
7376
|
+
signals.push(...nextSignals);
|
|
7377
|
+
languages.push("javascript", "typescript");
|
|
7378
|
+
runtimes.push("node");
|
|
7379
|
+
frameworks.push("nextjs");
|
|
7380
|
+
}
|
|
7381
|
+
const fastapiSignals = await detectFastApi(rootDir);
|
|
7382
|
+
if (fastapiSignals.length > 0) {
|
|
7383
|
+
signals.push(...fastapiSignals);
|
|
7384
|
+
languages.push("python");
|
|
7385
|
+
runtimes.push("python");
|
|
7386
|
+
frameworks.push("fastapi");
|
|
7387
|
+
}
|
|
7388
|
+
const monorepoSignals = await detectMonorepo(rootDir);
|
|
7389
|
+
if (monorepoSignals.length > 0) {
|
|
7390
|
+
signals.push(...monorepoSignals);
|
|
7391
|
+
}
|
|
7392
|
+
const androidSignals = await detectAndroid(rootDir);
|
|
7393
|
+
if (androidSignals.includes("AndroidManifest.xml")) {
|
|
7394
|
+
signals.push(...androidSignals);
|
|
7395
|
+
languages.push("kotlin", "java");
|
|
7396
|
+
runtimes.push("android");
|
|
7397
|
+
frameworks.push("android");
|
|
7398
|
+
}
|
|
7399
|
+
const genericBackendSignals = await detectGenericBackend(rootDir);
|
|
7400
|
+
if (genericBackendSignals.length > 0 && !frameworks.includes("django") && !frameworks.includes("fastapi") && !frameworks.includes("spring")) {
|
|
7401
|
+
signals.push(...genericBackendSignals);
|
|
7402
|
+
frameworks.push("backend");
|
|
7403
|
+
if (genericBackendSignals.includes("go.mod")) {
|
|
7404
|
+
languages.push("go");
|
|
7405
|
+
runtimes.push("go");
|
|
7406
|
+
}
|
|
7407
|
+
if (genericBackendSignals.includes("Cargo.toml")) {
|
|
7408
|
+
languages.push("rust");
|
|
7409
|
+
runtimes.push("rust");
|
|
7410
|
+
}
|
|
7411
|
+
if (genericBackendSignals.includes("Gemfile")) {
|
|
7412
|
+
languages.push("ruby");
|
|
7413
|
+
runtimes.push("ruby");
|
|
7414
|
+
}
|
|
7415
|
+
if (genericBackendSignals.includes("*.csproj")) {
|
|
7416
|
+
languages.push("csharp");
|
|
7417
|
+
runtimes.push("dotnet");
|
|
7418
|
+
}
|
|
7419
|
+
}
|
|
7420
|
+
const genericFrontendSignals = await detectGenericFrontend(rootDir);
|
|
7421
|
+
if (genericFrontendSignals.length > 0 && !frameworks.includes("astro") && !frameworks.includes("nextjs")) {
|
|
7422
|
+
signals.push(...genericFrontendSignals);
|
|
7423
|
+
frameworks.push("frontend");
|
|
7424
|
+
languages.push("javascript", "typescript");
|
|
7425
|
+
runtimes.push("node");
|
|
7426
|
+
}
|
|
7147
7427
|
const uniqueSignals = [...new Set(signals)];
|
|
7148
7428
|
return {
|
|
7149
7429
|
rootDir,
|
|
@@ -7173,74 +7453,6 @@ function calculateConfidence(profile) {
|
|
|
7173
7453
|
}
|
|
7174
7454
|
return "low";
|
|
7175
7455
|
}
|
|
7176
|
-
async function detectNode(rootDir) {
|
|
7177
|
-
const { fileExists: fileExists2 } = await Promise.resolve().then(() => (init_safety(), exports_safety));
|
|
7178
|
-
const signals = [];
|
|
7179
|
-
if (await fileExists2(rootDir, "package.json")) {
|
|
7180
|
-
signals.push("package.json");
|
|
7181
|
-
}
|
|
7182
|
-
if (await fileExists2(rootDir, "node_modules")) {
|
|
7183
|
-
signals.push("node_modules/");
|
|
7184
|
-
}
|
|
7185
|
-
return signals;
|
|
7186
|
-
}
|
|
7187
|
-
async function detectBun(rootDir) {
|
|
7188
|
-
const { fileExists: fileExists2 } = await Promise.resolve().then(() => (init_safety(), exports_safety));
|
|
7189
|
-
const signals = [];
|
|
7190
|
-
if (await fileExists2(rootDir, "bun.lockb")) {
|
|
7191
|
-
signals.push("bun.lockb");
|
|
7192
|
-
}
|
|
7193
|
-
if (await fileExists2(rootDir, "bun.lock")) {
|
|
7194
|
-
signals.push("bun.lock");
|
|
7195
|
-
}
|
|
7196
|
-
return signals;
|
|
7197
|
-
}
|
|
7198
|
-
async function detectSpring(rootDir) {
|
|
7199
|
-
const { fileExists: fileExists2 } = await Promise.resolve().then(() => (init_safety(), exports_safety));
|
|
7200
|
-
const signals = [];
|
|
7201
|
-
if (await fileExists2(rootDir, "build.gradle") || await fileExists2(rootDir, "build.gradle.kts")) {
|
|
7202
|
-
signals.push("build.gradle");
|
|
7203
|
-
}
|
|
7204
|
-
if (await fileExists2(rootDir, "pom.xml")) {
|
|
7205
|
-
signals.push("pom.xml");
|
|
7206
|
-
}
|
|
7207
|
-
return signals;
|
|
7208
|
-
}
|
|
7209
|
-
async function detectDjango(rootDir) {
|
|
7210
|
-
const { fileExists: fileExists2 } = await Promise.resolve().then(() => (init_safety(), exports_safety));
|
|
7211
|
-
const signals = [];
|
|
7212
|
-
if (await fileExists2(rootDir, "manage.py")) {
|
|
7213
|
-
signals.push("manage.py");
|
|
7214
|
-
}
|
|
7215
|
-
if (await fileExists2(rootDir, "requirements.txt")) {
|
|
7216
|
-
signals.push("requirements.txt");
|
|
7217
|
-
}
|
|
7218
|
-
return signals;
|
|
7219
|
-
}
|
|
7220
|
-
async function detectAstro(rootDir) {
|
|
7221
|
-
const { fileExists: fileExists2 } = await Promise.resolve().then(() => (init_safety(), exports_safety));
|
|
7222
|
-
const signals = [];
|
|
7223
|
-
if (await fileExists2(rootDir, "astro.config.mjs") || await fileExists2(rootDir, "astro.config.ts")) {
|
|
7224
|
-
signals.push("astro.config");
|
|
7225
|
-
}
|
|
7226
|
-
return signals;
|
|
7227
|
-
}
|
|
7228
|
-
async function detectPhp(rootDir) {
|
|
7229
|
-
const { fileExists: fileExists2 } = await Promise.resolve().then(() => (init_safety(), exports_safety));
|
|
7230
|
-
const signals = [];
|
|
7231
|
-
if (await fileExists2(rootDir, "composer.json")) {
|
|
7232
|
-
signals.push("composer.json");
|
|
7233
|
-
}
|
|
7234
|
-
try {
|
|
7235
|
-
const { readdir } = await import("node:fs/promises");
|
|
7236
|
-
const entries = await readdir(rootDir, { withFileTypes: true });
|
|
7237
|
-
const hasPhpFiles = entries.some((entry) => entry.isFile() && entry.name.endsWith(".php"));
|
|
7238
|
-
if (hasPhpFiles) {
|
|
7239
|
-
signals.push("*.php");
|
|
7240
|
-
}
|
|
7241
|
-
} catch {}
|
|
7242
|
-
return signals;
|
|
7243
|
-
}
|
|
7244
7456
|
|
|
7245
7457
|
// src/commands/detect.command.ts
|
|
7246
7458
|
async function detectCommand(options) {
|
|
@@ -7299,7 +7511,8 @@ function getRecommendedPresets(profile) {
|
|
|
7299
7511
|
}
|
|
7300
7512
|
|
|
7301
7513
|
// src/commands/doctor.command.ts
|
|
7302
|
-
import { join } from "node:path";
|
|
7514
|
+
import { join as join4 } from "node:path";
|
|
7515
|
+
import { homedir as homedir3 } from "node:os";
|
|
7303
7516
|
|
|
7304
7517
|
// src/core/config/config-loader.ts
|
|
7305
7518
|
import { readFile } from "node:fs/promises";
|
|
@@ -11509,39 +11722,658 @@ async function loadTargetSecurityCompatibility() {
|
|
|
11509
11722
|
});
|
|
11510
11723
|
}
|
|
11511
11724
|
|
|
11512
|
-
// src/
|
|
11513
|
-
|
|
11514
|
-
|
|
11515
|
-
|
|
11516
|
-
|
|
11517
|
-
|
|
11518
|
-
|
|
11519
|
-
|
|
11520
|
-
|
|
11521
|
-
|
|
11522
|
-
|
|
11523
|
-
|
|
11524
|
-
|
|
11525
|
-
|
|
11526
|
-
|
|
11527
|
-
|
|
11528
|
-
|
|
11529
|
-
|
|
11530
|
-
|
|
11531
|
-
|
|
11532
|
-
|
|
11533
|
-
|
|
11534
|
-
|
|
11535
|
-
|
|
11536
|
-
|
|
11537
|
-
|
|
11538
|
-
|
|
11539
|
-
|
|
11540
|
-
|
|
11541
|
-
|
|
11542
|
-
|
|
11543
|
-
|
|
11544
|
-
|
|
11725
|
+
// src/core/presets/update-checker.ts
|
|
11726
|
+
import { stat as stat2, readFile as readFile5 } from "node:fs/promises";
|
|
11727
|
+
import { resolve as resolve4, join as join3 } from "node:path";
|
|
11728
|
+
import { homedir as homedir2 } from "node:os";
|
|
11729
|
+
|
|
11730
|
+
// src/core/presets/manifest-loader.ts
|
|
11731
|
+
import { readFile as readFile3 } from "node:fs/promises";
|
|
11732
|
+
import { join } from "node:path";
|
|
11733
|
+
var MANIFESTS_DIR = join(SRC_PRESETS_DIR, "manifests");
|
|
11734
|
+
var MODELS_DIR = join(SRC_PRESETS_DIR, "models");
|
|
11735
|
+
var PRESETS_DIR = ROOT_PRESETS_DIR;
|
|
11736
|
+
async function loadManifest(target) {
|
|
11737
|
+
const manifestPath = join(MANIFESTS_DIR, `${target}.yml`);
|
|
11738
|
+
const content = await readFile3(manifestPath, "utf-8");
|
|
11739
|
+
const data = $parse(content);
|
|
11740
|
+
return InstallManifestSchema.parse(data);
|
|
11741
|
+
}
|
|
11742
|
+
async function loadModelConfig(target) {
|
|
11743
|
+
const modelPath = join(MODELS_DIR, `${target}.yml`);
|
|
11744
|
+
const content = await readFile3(modelPath, "utf-8");
|
|
11745
|
+
const data = $parse(content);
|
|
11746
|
+
return ModelConfigSchema.parse(data);
|
|
11747
|
+
}
|
|
11748
|
+
|
|
11749
|
+
// src/core/presets/file-copier.ts
|
|
11750
|
+
import { mkdir, readdir, readFile as readFile4, stat, writeFile } from "node:fs/promises";
|
|
11751
|
+
import { homedir } from "node:os";
|
|
11752
|
+
import { dirname as dirname2, join as join2, relative, resolve as resolve3 } from "node:path";
|
|
11753
|
+
|
|
11754
|
+
// src/core/i18n/language-instructions.ts
|
|
11755
|
+
var SUPPORTED_LOCALES = ["en", "es"];
|
|
11756
|
+
var LANGUAGE_INSTRUCTIONS = {
|
|
11757
|
+
en: 'Prose/docs/code comments: be terse and direct. Prefer concrete nouns over abstract ones. Omit filler phrases ("note that", "please", "as mentioned"). One idea per sentence.',
|
|
11758
|
+
es: "Spanish prose/docs/reports/Markdown: preserve natural Spanish orthography, including accents, `ñ`, `¿`, `¡`, and normal Unicode. The ASCII-only editing preference does not apply to these artifacts."
|
|
11759
|
+
};
|
|
11760
|
+
var COMMIT_STYLE = {
|
|
11761
|
+
en: `---
|
|
11762
|
+
trigger: always_on
|
|
11763
|
+
description: Rules for generating commit messages using Conventional Commits format
|
|
11764
|
+
---
|
|
11765
|
+
|
|
11766
|
+
## Git Commit Messages
|
|
11767
|
+
|
|
11768
|
+
### Format
|
|
11769
|
+
|
|
11770
|
+
\`\`\`
|
|
11771
|
+
<type>(<scope>): <short description>
|
|
11772
|
+
|
|
11773
|
+
- <detail 1>
|
|
11774
|
+
- <detail 2>
|
|
11775
|
+
\`\`\`
|
|
11776
|
+
|
|
11777
|
+
### Valid Types
|
|
11778
|
+
|
|
11779
|
+
\`feat\` \`fix\` \`docs\` \`style\` \`refactor\` \`test\` \`chore\` \`perf\` \`ci\` \`build\`
|
|
11780
|
+
\`revert\`
|
|
11781
|
+
|
|
11782
|
+
### Rules
|
|
11783
|
+
|
|
11784
|
+
- Language: **neutral English** always
|
|
11785
|
+
- Header: maximum 69 characters, no trailing period
|
|
11786
|
+
- Body: concise bullet points, one idea per line
|
|
11787
|
+
- Footer: only for breaking changes or issues
|
|
11788
|
+
- No gerunds ("adding", "fixing")
|
|
11789
|
+
- Use infinitive or imperative ("add", "fix", "update")`,
|
|
11790
|
+
es: `---
|
|
11791
|
+
trigger: always_on
|
|
11792
|
+
description: Reglas para generar mensajes de commit con formato Conventional Commits
|
|
11793
|
+
---
|
|
11794
|
+
|
|
11795
|
+
## Git Commit Messages
|
|
11796
|
+
|
|
11797
|
+
### Formato
|
|
11798
|
+
|
|
11799
|
+
\`\`\`
|
|
11800
|
+
<tipo>(<scope>): <descripcion corta>
|
|
11801
|
+
|
|
11802
|
+
- <detalle 1>
|
|
11803
|
+
- <detalle 2>
|
|
11804
|
+
\`\`\`
|
|
11805
|
+
|
|
11806
|
+
### Tipos validos
|
|
11807
|
+
|
|
11808
|
+
\`feat\` \`fix\` \`docs\` \`style\` \`refactor\` \`test\` \`chore\` \`perf\` \`ci\` \`build\`
|
|
11809
|
+
\`revert\`
|
|
11810
|
+
|
|
11811
|
+
### Reglas
|
|
11812
|
+
|
|
11813
|
+
- Idioma: **inglés neutro** siempre
|
|
11814
|
+
- Encabezado: maximo 69 caracteres, sin punto final
|
|
11815
|
+
- Cuerpo: viñetas concisas, una idea por linea
|
|
11816
|
+
- Footer: solo para breaking changes o issues
|
|
11817
|
+
- Sin gerundios ("agregando", "corrigiendo")
|
|
11818
|
+
- Usar infinitivo o imperativo ("agregar", "corregir", "actualizar")`
|
|
11819
|
+
};
|
|
11820
|
+
var COMMIT_WORKFLOW = {
|
|
11821
|
+
en: `---
|
|
11822
|
+
name: commit
|
|
11823
|
+
description: Generates a commit in English following Conventional Commits based on staged changes
|
|
11824
|
+
---
|
|
11825
|
+
|
|
11826
|
+
// turbo-all
|
|
11827
|
+
|
|
11828
|
+
## Steps
|
|
11829
|
+
|
|
11830
|
+
1. View staged changes: \`git diff --cached --stat\`
|
|
11831
|
+
2. If nothing is staged, suggest \`git add .\` or specific files
|
|
11832
|
+
3. Get full diff: \`git diff --cached\`
|
|
11833
|
+
4. Check recent style: \`git log -n 3 --oneline\`
|
|
11834
|
+
5. Generate message following \`.agents/rules/commit-style.md\`
|
|
11835
|
+
6. Show proposal and confirm with the user
|
|
11836
|
+
7. Execute: \`git commit -m "<message>"\`
|
|
11837
|
+
8. Confirm success: \`git status\``,
|
|
11838
|
+
es: `---
|
|
11839
|
+
name: commit
|
|
11840
|
+
description: Genera un commit en inglés siguiendo Conventional Commits basado en los cambios staged
|
|
11841
|
+
---
|
|
11842
|
+
|
|
11843
|
+
// turbo-all
|
|
11844
|
+
|
|
11845
|
+
## Pasos
|
|
11846
|
+
|
|
11847
|
+
1. Ver cambios staged: \`git diff --cached --stat\`
|
|
11848
|
+
2. Si no hay nada staged, sugiere \`git add .\` o archivos específicos
|
|
11849
|
+
3. Obtener diff completo: \`git diff --cached\`
|
|
11850
|
+
4. Ver estilo reciente: \`git log -n 3 --oneline\`
|
|
11851
|
+
5. Generar mensaje siguiendo \`.agents/rules/commit-style.md\`
|
|
11852
|
+
6. Mostrar propuesta y confirmar con el usuario
|
|
11853
|
+
7. Ejecutar: \`git commit -m "<mensaje>"\`
|
|
11854
|
+
8. Confirmar éxito: \`git status\``
|
|
11855
|
+
};
|
|
11856
|
+
function getLanguageInstruction(locale) {
|
|
11857
|
+
const key = SUPPORTED_LOCALES.includes(locale) ? locale : "en";
|
|
11858
|
+
return `- ${LANGUAGE_INSTRUCTIONS[key]}`;
|
|
11859
|
+
}
|
|
11860
|
+
var LOCALE_PLACEHOLDER = "{{LANGUAGE_INSTRUCTIONS}}";
|
|
11861
|
+
|
|
11862
|
+
// src/core/filesystem/safe-merger.ts
|
|
11863
|
+
var MANAGED_BEGIN_MARKER = "<!-- CODECONDUCTOR:BEGIN managed -->";
|
|
11864
|
+
var MANAGED_END_MARKER = "<!-- CODECONDUCTOR:END managed -->";
|
|
11865
|
+
function mergeManagedBlock(existing, incoming) {
|
|
11866
|
+
validateMarkers(incoming, "incoming content");
|
|
11867
|
+
if (!existing) {
|
|
11868
|
+
return { content: incoming, action: "written" };
|
|
11869
|
+
}
|
|
11870
|
+
validateMarkers(existing, "existing content");
|
|
11871
|
+
const existingBlock = getManagedBlockRange(existing);
|
|
11872
|
+
const incomingBlock = getManagedBlockRange(incoming);
|
|
11873
|
+
return {
|
|
11874
|
+
content: existing.slice(0, existingBlock.start) + incoming.slice(incomingBlock.start, incomingBlock.end) + existing.slice(existingBlock.end),
|
|
11875
|
+
action: "merged"
|
|
11876
|
+
};
|
|
11877
|
+
}
|
|
11878
|
+
function validateMarkers(content, label) {
|
|
11879
|
+
const beginCount = countOccurrences(content, MANAGED_BEGIN_MARKER);
|
|
11880
|
+
const endCount = countOccurrences(content, MANAGED_END_MARKER);
|
|
11881
|
+
if (beginCount !== 1 || endCount !== 1) {
|
|
11882
|
+
throw new Error(`${label} must contain exactly one managed begin marker and one managed end marker`);
|
|
11883
|
+
}
|
|
11884
|
+
if (content.indexOf(MANAGED_BEGIN_MARKER) > content.indexOf(MANAGED_END_MARKER)) {
|
|
11885
|
+
throw new Error(`${label} has managed markers in the wrong order`);
|
|
11886
|
+
}
|
|
11887
|
+
}
|
|
11888
|
+
function getManagedBlockRange(content) {
|
|
11889
|
+
const start = content.indexOf(MANAGED_BEGIN_MARKER);
|
|
11890
|
+
const end = content.indexOf(MANAGED_END_MARKER) + MANAGED_END_MARKER.length;
|
|
11891
|
+
return { start, end };
|
|
11892
|
+
}
|
|
11893
|
+
function countOccurrences(content, needle) {
|
|
11894
|
+
return content.split(needle).length - 1;
|
|
11895
|
+
}
|
|
11896
|
+
|
|
11897
|
+
// src/core/presets/file-copier.ts
|
|
11898
|
+
async function listFilesRecursive(dir, base = dir) {
|
|
11899
|
+
const entries = await readdir(dir, { withFileTypes: true });
|
|
11900
|
+
const files = [];
|
|
11901
|
+
for (const entry of entries) {
|
|
11902
|
+
const full = join2(dir, entry.name);
|
|
11903
|
+
if (entry.isDirectory()) {
|
|
11904
|
+
files.push(...await listFilesRecursive(full, base));
|
|
11905
|
+
} else {
|
|
11906
|
+
files.push(relative(base, full));
|
|
11907
|
+
}
|
|
11908
|
+
}
|
|
11909
|
+
return files;
|
|
11910
|
+
}
|
|
11911
|
+
async function resolveEntryFiles(entry, presetsDir, baseDir) {
|
|
11912
|
+
const srcAbsolute = resolve3(presetsDir, entry.src);
|
|
11913
|
+
try {
|
|
11914
|
+
const s = await stat(srcAbsolute);
|
|
11915
|
+
if (s.isDirectory()) {
|
|
11916
|
+
const files = await listFilesRecursive(srcAbsolute);
|
|
11917
|
+
return files.map((f) => ({
|
|
11918
|
+
src: join2(srcAbsolute, f),
|
|
11919
|
+
dest: resolve3(baseDir, entry.dest, f)
|
|
11920
|
+
}));
|
|
11921
|
+
}
|
|
11922
|
+
return [{ src: srcAbsolute, dest: resolve3(baseDir, entry.dest) }];
|
|
11923
|
+
} catch {
|
|
11924
|
+
return [];
|
|
11925
|
+
}
|
|
11926
|
+
}
|
|
11927
|
+
function mergeDeep(target, source) {
|
|
11928
|
+
const result = { ...target };
|
|
11929
|
+
for (const key of Object.keys(source)) {
|
|
11930
|
+
const srcVal = source[key];
|
|
11931
|
+
const tgtVal = target[key];
|
|
11932
|
+
if (Array.isArray(srcVal) && Array.isArray(tgtVal)) {
|
|
11933
|
+
result[key] = [...new Set([...tgtVal, ...srcVal])];
|
|
11934
|
+
} else if (srcVal && typeof srcVal === "object" && !Array.isArray(srcVal) && tgtVal && typeof tgtVal === "object" && !Array.isArray(tgtVal)) {
|
|
11935
|
+
result[key] = mergeDeep(tgtVal, srcVal);
|
|
11936
|
+
} else {
|
|
11937
|
+
result[key] = srcVal;
|
|
11938
|
+
}
|
|
11939
|
+
}
|
|
11940
|
+
return result;
|
|
11941
|
+
}
|
|
11942
|
+
function extractAgentRole(filePath) {
|
|
11943
|
+
const parts = filePath.replace(/\\/g, "/").split("/");
|
|
11944
|
+
const basename = parts[parts.length - 1];
|
|
11945
|
+
const name = basename.replace(/\.md$/, "");
|
|
11946
|
+
const knownRoles = [
|
|
11947
|
+
"architect",
|
|
11948
|
+
"implementer",
|
|
11949
|
+
"tester",
|
|
11950
|
+
"orchestrator",
|
|
11951
|
+
"reviewer",
|
|
11952
|
+
"docs",
|
|
11953
|
+
"task-coach",
|
|
11954
|
+
"repo-explorer"
|
|
11955
|
+
];
|
|
11956
|
+
return knownRoles.includes(name) ? name : null;
|
|
11957
|
+
}
|
|
11958
|
+
function renderTemplate(content, modelConfig, filePath, locale = "en") {
|
|
11959
|
+
const cleanLocale = locale === "es" || locale === "en" ? locale : "en";
|
|
11960
|
+
const templatedContent = content.replace(/\{\{COMMIT_STYLE\}\}/g, COMMIT_STYLE[cleanLocale]).replace(/\{\{COMMIT_WORKFLOW\}\}/g, COMMIT_WORKFLOW[cleanLocale]);
|
|
11961
|
+
const agentRole = extractAgentRole(filePath);
|
|
11962
|
+
if (agentRole && modelConfig.agents[agentRole]) {
|
|
11963
|
+
const agentModels = modelConfig.agents[agentRole];
|
|
11964
|
+
const targetModel = agentModels[modelConfig.target];
|
|
11965
|
+
let result2 = templatedContent.replace(/\{\{MODEL\}\}/g, targetModel ?? "").replace(/\{\{MODEL_CLAUDE\}\}/g, agentModels.claude ?? "").replace(/\{\{MODEL_OPENCODE\}\}/g, agentModels.opencode ?? "").replace(/\{\{MODEL_CODEX\}\}/g, agentModels.codex ?? "").replace(/\{\{MODEL_GEMINI\}\}/g, agentModels.gemini ?? "").replace(/\{\{MODEL_CURSOR\}\}/g, agentModels.cursor ?? "").replace(new RegExp(LOCALE_PLACEHOLDER.replace(/[{}]/g, "\\$&"), "g"), getLanguageInstruction(locale));
|
|
11966
|
+
if (modelConfig.tools || modelConfig.permissions) {
|
|
11967
|
+
result2 = substituteToolNames(result2, modelConfig);
|
|
11968
|
+
}
|
|
11969
|
+
return result2;
|
|
11970
|
+
}
|
|
11971
|
+
const knownRoles = [
|
|
11972
|
+
"orchestrator",
|
|
11973
|
+
"task-coach",
|
|
11974
|
+
"architect",
|
|
11975
|
+
"implementer",
|
|
11976
|
+
"tester",
|
|
11977
|
+
"reviewer",
|
|
11978
|
+
"docs",
|
|
11979
|
+
"repo-explorer"
|
|
11980
|
+
];
|
|
11981
|
+
let result = templatedContent;
|
|
11982
|
+
for (const role of knownRoles) {
|
|
11983
|
+
if (!modelConfig.agents[role])
|
|
11984
|
+
continue;
|
|
11985
|
+
const agentModels = modelConfig.agents[role];
|
|
11986
|
+
const sectionRegex = new RegExp(`(### ${role}[\\s\\S]*?)(?=### |## |$)`, "gi");
|
|
11987
|
+
const sectionMatch = result.match(sectionRegex);
|
|
11988
|
+
if (sectionMatch) {
|
|
11989
|
+
for (const section of sectionMatch) {
|
|
11990
|
+
const renderedSection = section.replace(/\{\{MODEL_CLAUDE\}\}/g, agentModels.claude ?? "").replace(/\{\{MODEL_OPENCODE\}\}/g, agentModels.opencode ?? "").replace(/\{\{MODEL_CODEX\}\}/g, agentModels.codex ?? "").replace(/\{\{MODEL_GEMINI\}\}/g, agentModels.gemini ?? "").replace(/\{\{MODEL_CURSOR\}\}/g, agentModels.cursor ?? "");
|
|
11991
|
+
result = result.replace(section, renderedSection);
|
|
11992
|
+
}
|
|
11993
|
+
}
|
|
11994
|
+
}
|
|
11995
|
+
result = result.replace(new RegExp(LOCALE_PLACEHOLDER.replace(/[{}]/g, "\\$&"), "g"), getLanguageInstruction(locale));
|
|
11996
|
+
if (modelConfig.tools || modelConfig.permissions) {
|
|
11997
|
+
result = substituteToolNames(result, modelConfig);
|
|
11998
|
+
}
|
|
11999
|
+
return result;
|
|
12000
|
+
}
|
|
12001
|
+
function substituteToolNames(content, modelConfig) {
|
|
12002
|
+
if (!modelConfig.tools && !modelConfig.permissions)
|
|
12003
|
+
return content;
|
|
12004
|
+
const target = modelConfig.target;
|
|
12005
|
+
const fmMatch = content.match(/^---\r?\n([\s\S]*?)\r?\n---/);
|
|
12006
|
+
if (!fmMatch)
|
|
12007
|
+
return content;
|
|
12008
|
+
const frontmatter = fmMatch[1];
|
|
12009
|
+
if (target === "opencode" && modelConfig.permissions) {
|
|
12010
|
+
const updatedFrontmatter2 = frontmatter.replace(/^tools:\s*(.+)\r?\n?/m, "");
|
|
12011
|
+
return content.replace(fmMatch[0], `---
|
|
12012
|
+
${updatedFrontmatter2}
|
|
12013
|
+
---`);
|
|
12014
|
+
}
|
|
12015
|
+
if (!modelConfig.tools)
|
|
12016
|
+
return content;
|
|
12017
|
+
const updatedFrontmatter = frontmatter.replace(/^tools:\s*(.+)$/m, (_match, toolsLine) => {
|
|
12018
|
+
const baseNames = toolsLine.split(",").map((t) => t.trim());
|
|
12019
|
+
const mappedNames = baseNames.map((baseName) => {
|
|
12020
|
+
const toolMapping = modelConfig.tools?.[baseName];
|
|
12021
|
+
if (toolMapping && toolMapping[target]) {
|
|
12022
|
+
return toolMapping[target];
|
|
12023
|
+
}
|
|
12024
|
+
return baseName;
|
|
12025
|
+
});
|
|
12026
|
+
return `tools: ${mappedNames.join(", ")}`;
|
|
12027
|
+
});
|
|
12028
|
+
return content.replace(fmMatch[0], `---
|
|
12029
|
+
${updatedFrontmatter}
|
|
12030
|
+
---`);
|
|
12031
|
+
}
|
|
12032
|
+
async function applySingleFile(srcPath, destPath, strategy, force, dryRun, isTemplate, modelConfig, locale) {
|
|
12033
|
+
if (strategy === "skip") {
|
|
12034
|
+
return { src: srcPath, dest: destPath, action: "skipped", dryRun };
|
|
12035
|
+
}
|
|
12036
|
+
let content;
|
|
12037
|
+
try {
|
|
12038
|
+
content = await readFile4(srcPath, "utf-8");
|
|
12039
|
+
} catch (e) {
|
|
12040
|
+
return { src: srcPath, dest: destPath, action: "error", error: `Cannot read source: ${e}` };
|
|
12041
|
+
}
|
|
12042
|
+
const incomingContent = isTemplate && modelConfig ? renderTemplate(content, modelConfig, srcPath, locale) : content;
|
|
12043
|
+
let finalContent = incomingContent;
|
|
12044
|
+
let action = "written";
|
|
12045
|
+
if (strategy === "append") {
|
|
12046
|
+
let existing = "";
|
|
12047
|
+
try {
|
|
12048
|
+
existing = await readFile4(destPath, "utf-8");
|
|
12049
|
+
} catch {}
|
|
12050
|
+
if (existing) {
|
|
12051
|
+
finalContent = existing + `
|
|
12052
|
+
|
|
12053
|
+
---
|
|
12054
|
+
|
|
12055
|
+
` + incomingContent;
|
|
12056
|
+
}
|
|
12057
|
+
action = "appended";
|
|
12058
|
+
} else if (strategy === "merge-json") {
|
|
12059
|
+
let existing = {};
|
|
12060
|
+
try {
|
|
12061
|
+
existing = JSON.parse(await readFile4(destPath, "utf-8"));
|
|
12062
|
+
} catch {}
|
|
12063
|
+
try {
|
|
12064
|
+
const incoming = JSON.parse(incomingContent);
|
|
12065
|
+
finalContent = JSON.stringify(mergeDeep(existing, incoming), null, 2);
|
|
12066
|
+
} catch (e) {
|
|
12067
|
+
return { src: srcPath, dest: destPath, action: "error", error: `JSON merge failed: ${e}` };
|
|
12068
|
+
}
|
|
12069
|
+
action = "merged";
|
|
12070
|
+
} else if (strategy === "merge-managed") {
|
|
12071
|
+
let existing = null;
|
|
12072
|
+
try {
|
|
12073
|
+
existing = await readFile4(destPath, "utf-8");
|
|
12074
|
+
} catch {}
|
|
12075
|
+
try {
|
|
12076
|
+
const merged = mergeManagedBlock(existing, incomingContent);
|
|
12077
|
+
finalContent = merged.content;
|
|
12078
|
+
action = merged.action;
|
|
12079
|
+
} catch (e) {
|
|
12080
|
+
return { src: srcPath, dest: destPath, action: "error", error: `Managed merge failed: ${e}` };
|
|
12081
|
+
}
|
|
12082
|
+
}
|
|
12083
|
+
if (dryRun) {
|
|
12084
|
+
return { src: srcPath, dest: destPath, action, dryRun: true };
|
|
12085
|
+
}
|
|
12086
|
+
try {
|
|
12087
|
+
await mkdir(dirname2(destPath), { recursive: true });
|
|
12088
|
+
await writeFile(destPath, finalContent, "utf-8");
|
|
12089
|
+
return { src: srcPath, dest: destPath, action };
|
|
12090
|
+
} catch (e) {
|
|
12091
|
+
return { src: srcPath, dest: destPath, action: "error", error: String(e) };
|
|
12092
|
+
}
|
|
12093
|
+
}
|
|
12094
|
+
async function copyFromManifest(manifest, presetsDir, baseDir, isGlobal, dryRun, force, modelConfig = null, locale = "en") {
|
|
12095
|
+
const results = [];
|
|
12096
|
+
for (const entry of manifest.entries) {
|
|
12097
|
+
const strategy = isGlobal && entry.globalStrategy ? entry.globalStrategy : entry.strategy;
|
|
12098
|
+
let resolvedBaseDir = baseDir;
|
|
12099
|
+
let resolvedEntry = entry;
|
|
12100
|
+
if (manifest.target === "agy" && isGlobal) {
|
|
12101
|
+
resolvedBaseDir = join2(homedir(), ".gemini", "config");
|
|
12102
|
+
resolvedEntry = {
|
|
12103
|
+
...entry,
|
|
12104
|
+
dest: entry.dest.replace(/^\.agents\/?/, "")
|
|
12105
|
+
};
|
|
12106
|
+
}
|
|
12107
|
+
const files = await resolveEntryFiles(resolvedEntry, presetsDir, resolvedBaseDir);
|
|
12108
|
+
const isTemplate = entry.template === true;
|
|
12109
|
+
for (const { src, dest } of files) {
|
|
12110
|
+
results.push(await applySingleFile(src, dest, strategy, force, dryRun, isTemplate, modelConfig, locale));
|
|
12111
|
+
}
|
|
12112
|
+
}
|
|
12113
|
+
return results;
|
|
12114
|
+
}
|
|
12115
|
+
|
|
12116
|
+
// src/core/presets/update-checker.ts
|
|
12117
|
+
function getTargetInstallationPath(target, basePath, isGlobal) {
|
|
12118
|
+
if (target === "agy") {
|
|
12119
|
+
return isGlobal ? resolve4(basePath, ".gemini", "config") : resolve4(basePath, ".agents");
|
|
12120
|
+
}
|
|
12121
|
+
return resolve4(basePath, `.${target}`);
|
|
12122
|
+
}
|
|
12123
|
+
async function isTargetInstalled(target, basePath, isGlobal) {
|
|
12124
|
+
const path = getTargetInstallationPath(target, basePath, isGlobal);
|
|
12125
|
+
try {
|
|
12126
|
+
const s = await stat2(path);
|
|
12127
|
+
return s.isDirectory();
|
|
12128
|
+
} catch {
|
|
12129
|
+
return false;
|
|
12130
|
+
}
|
|
12131
|
+
}
|
|
12132
|
+
async function validateAgentFileSizes(basePath, isGlobal) {
|
|
12133
|
+
const filesToCheck = [];
|
|
12134
|
+
filesToCheck.push(resolve4(basePath, ".claude", "CLAUDE.md"));
|
|
12135
|
+
filesToCheck.push(resolve4(basePath, ".codex", "AGENTS.md"));
|
|
12136
|
+
if (isGlobal) {
|
|
12137
|
+
filesToCheck.push(resolve4(basePath, ".gemini", "config", "AGENTS.md"));
|
|
12138
|
+
} else {
|
|
12139
|
+
filesToCheck.push(resolve4(basePath, ".agents", "AGENTS.md"));
|
|
12140
|
+
}
|
|
12141
|
+
const largeFiles = [];
|
|
12142
|
+
for (const filePath of filesToCheck) {
|
|
12143
|
+
try {
|
|
12144
|
+
const s = await stat2(filePath);
|
|
12145
|
+
if (s.isFile() && s.size > 40 * 1024) {
|
|
12146
|
+
largeFiles.push({ path: filePath, size: s.size });
|
|
12147
|
+
}
|
|
12148
|
+
} catch {}
|
|
12149
|
+
}
|
|
12150
|
+
return largeFiles;
|
|
12151
|
+
}
|
|
12152
|
+
async function fileContentDiffers(pathA, pathB) {
|
|
12153
|
+
try {
|
|
12154
|
+
const contentA = await readFile5(pathA, "utf-8");
|
|
12155
|
+
const contentB = await readFile5(pathB, "utf-8");
|
|
12156
|
+
return contentA.trim() !== contentB.trim();
|
|
12157
|
+
} catch {
|
|
12158
|
+
try {
|
|
12159
|
+
await stat2(pathB);
|
|
12160
|
+
return true;
|
|
12161
|
+
} catch {
|
|
12162
|
+
return false;
|
|
12163
|
+
}
|
|
12164
|
+
}
|
|
12165
|
+
}
|
|
12166
|
+
async function loadSkillsLock(basePath) {
|
|
12167
|
+
const paths = [
|
|
12168
|
+
resolve4(basePath, ".codeconductor", "skills-lock.json"),
|
|
12169
|
+
resolve4(basePath, ".agents", "skills-lock.json")
|
|
12170
|
+
];
|
|
12171
|
+
for (const p of paths) {
|
|
12172
|
+
try {
|
|
12173
|
+
const content = await readFile5(p, "utf-8");
|
|
12174
|
+
return JSON.parse(content);
|
|
12175
|
+
} catch {}
|
|
12176
|
+
}
|
|
12177
|
+
return null;
|
|
12178
|
+
}
|
|
12179
|
+
async function getLatestSkillVersion(skillId) {
|
|
12180
|
+
const targets = [
|
|
12181
|
+
"opencode",
|
|
12182
|
+
"agy",
|
|
12183
|
+
"claude",
|
|
12184
|
+
"codex",
|
|
12185
|
+
"gemini",
|
|
12186
|
+
"cursor"
|
|
12187
|
+
];
|
|
12188
|
+
for (const target of targets) {
|
|
12189
|
+
const skillPath = resolve4(ROOT_PRESETS_DIR, target, "skills", skillId, "SKILL.md");
|
|
12190
|
+
try {
|
|
12191
|
+
const content = await readFile5(skillPath, "utf-8");
|
|
12192
|
+
const fmMatch = content.match(/^---\r?\n([\s\S]*?)\r?\n---/);
|
|
12193
|
+
if (fmMatch) {
|
|
12194
|
+
const parsed = $parse(fmMatch[1]);
|
|
12195
|
+
if (parsed && parsed.id === skillId && parsed.version) {
|
|
12196
|
+
return String(parsed.version);
|
|
12197
|
+
}
|
|
12198
|
+
}
|
|
12199
|
+
} catch {}
|
|
12200
|
+
}
|
|
12201
|
+
return null;
|
|
12202
|
+
}
|
|
12203
|
+
async function checkUpdates(basePath, isGlobal) {
|
|
12204
|
+
const localCouncil = resolve4(basePath, ".codeconductor", "presets", "council.yml");
|
|
12205
|
+
const bundledCouncil = resolve4(SRC_PRESETS_DIR, "council", "council.yml");
|
|
12206
|
+
const councilHasUpdate = await fileContentDiffers(localCouncil, bundledCouncil);
|
|
12207
|
+
const localPolicy = resolve4(basePath, ".codeconductor", "presets", "policy.yml");
|
|
12208
|
+
const policyHasUpdate = await fileContentDiffers(localPolicy, POLICY_PATH);
|
|
12209
|
+
const targetsToCheck = [
|
|
12210
|
+
"opencode",
|
|
12211
|
+
"claude",
|
|
12212
|
+
"codex",
|
|
12213
|
+
"gemini",
|
|
12214
|
+
"cursor",
|
|
12215
|
+
"agy"
|
|
12216
|
+
];
|
|
12217
|
+
const targetResults = [];
|
|
12218
|
+
let locale = "en";
|
|
12219
|
+
try {
|
|
12220
|
+
const configResult = await loadConfig(basePath);
|
|
12221
|
+
if (configResult.success) {
|
|
12222
|
+
locale = configResult.data.defaults.locale ?? "en";
|
|
12223
|
+
}
|
|
12224
|
+
} catch {}
|
|
12225
|
+
for (const target of targetsToCheck) {
|
|
12226
|
+
const isInstalled = await isTargetInstalled(target, basePath, isGlobal);
|
|
12227
|
+
if (!isInstalled) {
|
|
12228
|
+
continue;
|
|
12229
|
+
}
|
|
12230
|
+
let manifest;
|
|
12231
|
+
let modelConfig;
|
|
12232
|
+
try {
|
|
12233
|
+
manifest = await loadManifest(target);
|
|
12234
|
+
modelConfig = await loadModelConfig(target);
|
|
12235
|
+
} catch {
|
|
12236
|
+
continue;
|
|
12237
|
+
}
|
|
12238
|
+
const changedFiles = [];
|
|
12239
|
+
for (const entry of manifest.entries) {
|
|
12240
|
+
const strategy = isGlobal && entry.globalStrategy ? entry.globalStrategy : entry.strategy;
|
|
12241
|
+
if (strategy === "skip")
|
|
12242
|
+
continue;
|
|
12243
|
+
let resolvedEntry = entry;
|
|
12244
|
+
let targetBaseDir = basePath;
|
|
12245
|
+
if (target === "agy" && isGlobal) {
|
|
12246
|
+
targetBaseDir = join3(homedir2(), ".gemini", "config");
|
|
12247
|
+
resolvedEntry = {
|
|
12248
|
+
...entry,
|
|
12249
|
+
dest: entry.dest.replace(/^\.agents\/?/, "")
|
|
12250
|
+
};
|
|
12251
|
+
}
|
|
12252
|
+
const files = await resolveEntryFiles(resolvedEntry, PRESETS_DIR, targetBaseDir);
|
|
12253
|
+
const isTemplate = entry.template === true;
|
|
12254
|
+
for (const { src, dest } of files) {
|
|
12255
|
+
let expectedContent;
|
|
12256
|
+
try {
|
|
12257
|
+
const srcContent = await readFile5(src, "utf-8");
|
|
12258
|
+
expectedContent = isTemplate && modelConfig ? renderTemplate(srcContent, modelConfig, src, locale) : srcContent;
|
|
12259
|
+
} catch {
|
|
12260
|
+
continue;
|
|
12261
|
+
}
|
|
12262
|
+
let destContent;
|
|
12263
|
+
try {
|
|
12264
|
+
destContent = await readFile5(dest, "utf-8");
|
|
12265
|
+
} catch {
|
|
12266
|
+
changedFiles.push(dest);
|
|
12267
|
+
continue;
|
|
12268
|
+
}
|
|
12269
|
+
let fileHasUpdate = false;
|
|
12270
|
+
if (strategy === "overwrite") {
|
|
12271
|
+
if (destContent.trim() !== expectedContent.trim()) {
|
|
12272
|
+
fileHasUpdate = true;
|
|
12273
|
+
}
|
|
12274
|
+
} else if (strategy === "append") {
|
|
12275
|
+
if (!destContent.includes(expectedContent)) {
|
|
12276
|
+
fileHasUpdate = true;
|
|
12277
|
+
}
|
|
12278
|
+
} else if (strategy === "merge-json") {
|
|
12279
|
+
try {
|
|
12280
|
+
const destJson = JSON.parse(destContent);
|
|
12281
|
+
const expectedJson = JSON.parse(expectedContent);
|
|
12282
|
+
const merged = mergeDeep(destJson, expectedJson);
|
|
12283
|
+
if (JSON.stringify(merged) !== JSON.stringify(destJson)) {
|
|
12284
|
+
fileHasUpdate = true;
|
|
12285
|
+
}
|
|
12286
|
+
} catch {
|
|
12287
|
+
fileHasUpdate = true;
|
|
12288
|
+
}
|
|
12289
|
+
} else if (strategy === "merge-managed") {
|
|
12290
|
+
try {
|
|
12291
|
+
const merged = mergeManagedBlock(destContent, expectedContent);
|
|
12292
|
+
if (merged.content.trim() !== destContent.trim()) {
|
|
12293
|
+
fileHasUpdate = true;
|
|
12294
|
+
}
|
|
12295
|
+
} catch {
|
|
12296
|
+
fileHasUpdate = true;
|
|
12297
|
+
}
|
|
12298
|
+
}
|
|
12299
|
+
if (fileHasUpdate) {
|
|
12300
|
+
changedFiles.push(dest);
|
|
12301
|
+
}
|
|
12302
|
+
}
|
|
12303
|
+
}
|
|
12304
|
+
targetResults.push({
|
|
12305
|
+
target,
|
|
12306
|
+
hasUpdate: changedFiles.length > 0,
|
|
12307
|
+
files: changedFiles
|
|
12308
|
+
});
|
|
12309
|
+
}
|
|
12310
|
+
const skillResults = [];
|
|
12311
|
+
const skillsLock = await loadSkillsLock(basePath);
|
|
12312
|
+
if (skillsLock) {
|
|
12313
|
+
for (const [skillId, currentVersion] of Object.entries(skillsLock)) {
|
|
12314
|
+
const latestVersion = await getLatestSkillVersion(skillId);
|
|
12315
|
+
if (latestVersion && latestVersion !== currentVersion) {
|
|
12316
|
+
skillResults.push({
|
|
12317
|
+
id: skillId,
|
|
12318
|
+
currentVersion,
|
|
12319
|
+
latestVersion,
|
|
12320
|
+
hasUpdate: true
|
|
12321
|
+
});
|
|
12322
|
+
} else {
|
|
12323
|
+
skillResults.push({
|
|
12324
|
+
id: skillId,
|
|
12325
|
+
currentVersion,
|
|
12326
|
+
latestVersion: latestVersion || currentVersion,
|
|
12327
|
+
hasUpdate: false
|
|
12328
|
+
});
|
|
12329
|
+
}
|
|
12330
|
+
}
|
|
12331
|
+
}
|
|
12332
|
+
const hasPresetUpdates = councilHasUpdate || policyHasUpdate;
|
|
12333
|
+
const hasTargetUpdates = targetResults.some((t) => t.hasUpdate);
|
|
12334
|
+
const hasSkillUpdates = skillResults.some((s) => s.hasUpdate);
|
|
12335
|
+
return {
|
|
12336
|
+
hasUpdates: hasPresetUpdates || hasTargetUpdates || hasSkillUpdates,
|
|
12337
|
+
council: councilHasUpdate,
|
|
12338
|
+
policy: policyHasUpdate,
|
|
12339
|
+
targets: targetResults,
|
|
12340
|
+
skills: skillResults
|
|
12341
|
+
};
|
|
12342
|
+
}
|
|
12343
|
+
|
|
12344
|
+
// src/commands/doctor.command.ts
|
|
12345
|
+
async function doctorCommand(options) {
|
|
12346
|
+
const { projectRoot, output } = options;
|
|
12347
|
+
const checks = [];
|
|
12348
|
+
try {
|
|
12349
|
+
const hasConfig = await configExists(projectRoot);
|
|
12350
|
+
if (hasConfig) {
|
|
12351
|
+
checks.push({
|
|
12352
|
+
name: "config-exists",
|
|
12353
|
+
status: "pass",
|
|
12354
|
+
message: ".codeconductor/config.yml exists"
|
|
12355
|
+
});
|
|
12356
|
+
} else {
|
|
12357
|
+
checks.push({
|
|
12358
|
+
name: "config-exists",
|
|
12359
|
+
status: "fail",
|
|
12360
|
+
message: ".codeconductor/config.yml not found. Run `codeconductor init` first."
|
|
12361
|
+
});
|
|
12362
|
+
return {
|
|
12363
|
+
code: 4,
|
|
12364
|
+
data: {
|
|
12365
|
+
success: false,
|
|
12366
|
+
command: "doctor",
|
|
12367
|
+
checks
|
|
12368
|
+
}
|
|
12369
|
+
};
|
|
12370
|
+
}
|
|
12371
|
+
const configResult = await loadConfig(projectRoot);
|
|
12372
|
+
if (configResult.success) {
|
|
12373
|
+
checks.push({
|
|
12374
|
+
name: "config-valid",
|
|
12375
|
+
status: "pass",
|
|
12376
|
+
message: "Config is valid"
|
|
11545
12377
|
});
|
|
11546
12378
|
} else {
|
|
11547
12379
|
checks.push({
|
|
@@ -11562,7 +12394,7 @@ async function doctorCommand(options) {
|
|
|
11562
12394
|
for (const dir of runnerDirs) {
|
|
11563
12395
|
try {
|
|
11564
12396
|
const { access: access2 } = await import("node:fs/promises");
|
|
11565
|
-
await access2(
|
|
12397
|
+
await access2(join4(projectRoot, dir));
|
|
11566
12398
|
checks.push({
|
|
11567
12399
|
name: `dir-${dir}`,
|
|
11568
12400
|
status: "pass",
|
|
@@ -11584,6 +12416,66 @@ async function doctorCommand(options) {
|
|
|
11584
12416
|
message: `Council preset enabled (v${config.presets.council.version})`
|
|
11585
12417
|
});
|
|
11586
12418
|
}
|
|
12419
|
+
const localUpdates = await checkUpdates(projectRoot, false);
|
|
12420
|
+
const globalUpdates = await checkUpdates(homedir3(), true);
|
|
12421
|
+
const updateDetails = [];
|
|
12422
|
+
if (localUpdates.hasUpdates) {
|
|
12423
|
+
if (localUpdates.council)
|
|
12424
|
+
updateDetails.push("local council preset");
|
|
12425
|
+
if (localUpdates.policy)
|
|
12426
|
+
updateDetails.push("local policy");
|
|
12427
|
+
const updatedLocalTargets = localUpdates.targets.filter((t) => t.hasUpdate).map((t) => t.target);
|
|
12428
|
+
if (updatedLocalTargets.length > 0) {
|
|
12429
|
+
updateDetails.push(`local targets (${updatedLocalTargets.join(", ")})`);
|
|
12430
|
+
}
|
|
12431
|
+
const updatedLocalSkills = localUpdates.skills.filter((s) => s.hasUpdate).map((s) => s.id);
|
|
12432
|
+
if (updatedLocalSkills.length > 0) {
|
|
12433
|
+
updateDetails.push(`local skills (${updatedLocalSkills.join(", ")})`);
|
|
12434
|
+
}
|
|
12435
|
+
}
|
|
12436
|
+
if (globalUpdates.hasUpdates) {
|
|
12437
|
+
if (globalUpdates.council)
|
|
12438
|
+
updateDetails.push("global council preset");
|
|
12439
|
+
if (globalUpdates.policy)
|
|
12440
|
+
updateDetails.push("global policy");
|
|
12441
|
+
const updatedGlobalTargets = globalUpdates.targets.filter((t) => t.hasUpdate).map((t) => t.target);
|
|
12442
|
+
if (updatedGlobalTargets.length > 0) {
|
|
12443
|
+
updateDetails.push(`global targets (${updatedGlobalTargets.join(", ")})`);
|
|
12444
|
+
}
|
|
12445
|
+
const updatedGlobalSkills = globalUpdates.skills.filter((s) => s.hasUpdate).map((s) => s.id);
|
|
12446
|
+
if (updatedGlobalSkills.length > 0) {
|
|
12447
|
+
updateDetails.push(`global skills (${updatedGlobalSkills.join(", ")})`);
|
|
12448
|
+
}
|
|
12449
|
+
}
|
|
12450
|
+
if (updateDetails.length > 0) {
|
|
12451
|
+
checks.push({
|
|
12452
|
+
name: "updates-available",
|
|
12453
|
+
status: "warn",
|
|
12454
|
+
message: `Updates available for: ${updateDetails.join(", ")}`
|
|
12455
|
+
});
|
|
12456
|
+
} else {
|
|
12457
|
+
checks.push({
|
|
12458
|
+
name: "updates-available",
|
|
12459
|
+
status: "pass",
|
|
12460
|
+
message: "All presets, targets, and skills are up to date"
|
|
12461
|
+
});
|
|
12462
|
+
}
|
|
12463
|
+
const largeFilesLocal = await validateAgentFileSizes(projectRoot, false);
|
|
12464
|
+
const largeFilesGlobal = await validateAgentFileSizes(homedir3(), true);
|
|
12465
|
+
const allLargeFiles = [...largeFilesLocal, ...largeFilesGlobal];
|
|
12466
|
+
if (allLargeFiles.length > 0) {
|
|
12467
|
+
checks.push({
|
|
12468
|
+
name: "agent-file-sizes",
|
|
12469
|
+
status: "warn",
|
|
12470
|
+
message: `The following files exceed 40KB: ${allLargeFiles.map((f) => f.path).join(", ")}`
|
|
12471
|
+
});
|
|
12472
|
+
} else {
|
|
12473
|
+
checks.push({
|
|
12474
|
+
name: "agent-file-sizes",
|
|
12475
|
+
status: "pass",
|
|
12476
|
+
message: "All agent files (AGENTS.md/CLAUDE.md) are under 40KB"
|
|
12477
|
+
});
|
|
12478
|
+
}
|
|
11587
12479
|
const securityCompatibility = await loadTargetSecurityCompatibility();
|
|
11588
12480
|
for (const compatibility of securityCompatibility) {
|
|
11589
12481
|
checks.push({
|
|
@@ -11625,13 +12517,13 @@ async function doctorCommand(options) {
|
|
|
11625
12517
|
}
|
|
11626
12518
|
|
|
11627
12519
|
// src/commands/init.command.ts
|
|
11628
|
-
import { access as access3, mkdir as
|
|
11629
|
-
import { homedir } from "node:os";
|
|
11630
|
-
import { basename, resolve as
|
|
12520
|
+
import { access as access3, mkdir as mkdir3, readFile as readFile6, writeFile as writeFile3 } from "node:fs/promises";
|
|
12521
|
+
import { homedir as homedir4 } from "node:os";
|
|
12522
|
+
import { basename, resolve as resolve6 } from "node:path";
|
|
11631
12523
|
|
|
11632
12524
|
// src/core/config/config-writer.ts
|
|
11633
|
-
import { access as access2, mkdir, writeFile } from "node:fs/promises";
|
|
11634
|
-
import { resolve as
|
|
12525
|
+
import { access as access2, mkdir as mkdir2, writeFile as writeFile2 } from "node:fs/promises";
|
|
12526
|
+
import { resolve as resolve5 } from "node:path";
|
|
11635
12527
|
|
|
11636
12528
|
// src/core/config/codeconductor-config.ts
|
|
11637
12529
|
var DEFAULT_CONFIG = {
|
|
@@ -11661,9 +12553,9 @@ var CONFIG_DIR = ".codeconductor";
|
|
|
11661
12553
|
var CONFIG_FILE2 = "config.yml";
|
|
11662
12554
|
async function writeConfig(projectRoot, config = {}, force = false) {
|
|
11663
12555
|
try {
|
|
11664
|
-
const configDir =
|
|
11665
|
-
await
|
|
11666
|
-
const configPath =
|
|
12556
|
+
const configDir = resolve5(projectRoot, CONFIG_DIR);
|
|
12557
|
+
await mkdir2(configDir, { recursive: true });
|
|
12558
|
+
const configPath = resolve5(configDir, CONFIG_FILE2);
|
|
11667
12559
|
if (!force) {
|
|
11668
12560
|
try {
|
|
11669
12561
|
await access2(configPath);
|
|
@@ -11691,7 +12583,7 @@ async function writeConfig(projectRoot, config = {}, force = false) {
|
|
|
11691
12583
|
}
|
|
11692
12584
|
};
|
|
11693
12585
|
const yamlContent = $stringify(mergedConfig);
|
|
11694
|
-
await
|
|
12586
|
+
await writeFile2(configPath, yamlContent, "utf-8");
|
|
11695
12587
|
return ok(undefined);
|
|
11696
12588
|
} catch (error) {
|
|
11697
12589
|
return err(new ValidationError("Failed to write config", error));
|
|
@@ -11699,10 +12591,17 @@ async function writeConfig(projectRoot, config = {}, force = false) {
|
|
|
11699
12591
|
}
|
|
11700
12592
|
|
|
11701
12593
|
// src/core/presets/preset-resolver.ts
|
|
11702
|
-
var CURRENT_PRESET_VERSION = "v0.
|
|
12594
|
+
var CURRENT_PRESET_VERSION = "v0.3.0";
|
|
11703
12595
|
function resolvePreset(target, profile) {
|
|
11704
12596
|
const stack = resolveStack(profile);
|
|
11705
|
-
const
|
|
12597
|
+
const isMonorepo = profile.signals.some((s) => [
|
|
12598
|
+
"pnpm-workspace.yaml",
|
|
12599
|
+
"lerna.json",
|
|
12600
|
+
"go.work",
|
|
12601
|
+
"package.json-workspaces",
|
|
12602
|
+
"Cargo.toml-workspace"
|
|
12603
|
+
].includes(s));
|
|
12604
|
+
const architecture = isMonorepo ? "monorepo" : profile.signals.length > 0 ? "single-project" : "unknown";
|
|
11706
12605
|
const warnings = [];
|
|
11707
12606
|
if (profile.confidence === "low") {
|
|
11708
12607
|
warnings.push("Detection confidence is low; review the selected preset before applying it.");
|
|
@@ -11732,6 +12631,20 @@ function resolveStack(profile) {
|
|
|
11732
12631
|
return "django";
|
|
11733
12632
|
if (profile.frameworks.includes("astro"))
|
|
11734
12633
|
return "astro";
|
|
12634
|
+
if (profile.frameworks.includes("nextjs"))
|
|
12635
|
+
return "nextjs";
|
|
12636
|
+
if (profile.frameworks.includes("fastapi"))
|
|
12637
|
+
return "fastapi";
|
|
12638
|
+
if (profile.frameworks.includes("backend"))
|
|
12639
|
+
return "backend";
|
|
12640
|
+
if (profile.frameworks.includes("frontend"))
|
|
12641
|
+
return "frontend";
|
|
12642
|
+
if (profile.frameworks.includes("android"))
|
|
12643
|
+
return "android";
|
|
12644
|
+
if (profile.frameworks.includes("laravel"))
|
|
12645
|
+
return "laravel";
|
|
12646
|
+
if (profile.runtimes.includes("php"))
|
|
12647
|
+
return "php";
|
|
11735
12648
|
if (profile.runtimes.includes("bun"))
|
|
11736
12649
|
return "bun";
|
|
11737
12650
|
if (profile.runtimes.includes("node"))
|
|
@@ -11741,24 +12654,24 @@ function resolveStack(profile) {
|
|
|
11741
12654
|
function resolveAssets(target) {
|
|
11742
12655
|
switch (target) {
|
|
11743
12656
|
case "opencode":
|
|
11744
|
-
return ["opencode.jsonc", "agents", "commands", "prompts/v0.
|
|
12657
|
+
return ["opencode.jsonc", "agents", "commands", "prompts/v0.3.0", "skills"];
|
|
11745
12658
|
case "claude":
|
|
11746
|
-
return ["CLAUDE.md", "settings.json", "commands", "skills", "agents", "prompts/v0.
|
|
12659
|
+
return ["CLAUDE.md", "settings.json", "commands", "skills", "agents", "prompts/v0.3.0"];
|
|
11747
12660
|
case "codex":
|
|
11748
|
-
return ["AGENTS.md", "skills", "prompts/v0.
|
|
12661
|
+
return ["AGENTS.md", "skills", "prompts/v0.3.0"];
|
|
11749
12662
|
case "gemini":
|
|
11750
|
-
return ["agents", "prompts/v0.
|
|
12663
|
+
return ["agents", "prompts/v0.3.0"];
|
|
11751
12664
|
case "cursor":
|
|
11752
|
-
return ["agents", "prompts/v0.
|
|
12665
|
+
return ["agents", "prompts/v0.3.0"];
|
|
11753
12666
|
case "agy":
|
|
11754
|
-
return ["AGENTS.md", "rules", "workflows", "skills", "prompts/v0.
|
|
12667
|
+
return ["AGENTS.md", "rules", "workflows", "skills", "prompts/v0.3.0"];
|
|
11755
12668
|
}
|
|
11756
12669
|
}
|
|
11757
12670
|
|
|
11758
12671
|
// src/commands/init.command.ts
|
|
11759
12672
|
async function initCommand(options) {
|
|
11760
12673
|
const { projectRoot, dryRun, force, global: isGlobal, output, locale } = options;
|
|
11761
|
-
const baseDir = isGlobal ?
|
|
12674
|
+
const baseDir = isGlobal ? homedir4() : projectRoot;
|
|
11762
12675
|
try {
|
|
11763
12676
|
let profile = null;
|
|
11764
12677
|
if (!isGlobal) {
|
|
@@ -11865,7 +12778,7 @@ async function initCommand(options) {
|
|
|
11865
12778
|
}
|
|
11866
12779
|
async function resolvePresetsToCopy() {
|
|
11867
12780
|
const sources = [];
|
|
11868
|
-
const bundledCouncil =
|
|
12781
|
+
const bundledCouncil = resolve6(SRC_PRESETS_DIR, "council", "council.yml");
|
|
11869
12782
|
if (await fileExists2(bundledCouncil)) {
|
|
11870
12783
|
sources.push({ name: "council.yml", sourcePath: bundledCouncil });
|
|
11871
12784
|
}
|
|
@@ -11876,17 +12789,17 @@ async function resolvePresetsToCopy() {
|
|
|
11876
12789
|
return sources;
|
|
11877
12790
|
}
|
|
11878
12791
|
async function copyPresets(baseDir, presets, force) {
|
|
11879
|
-
const presetsDir =
|
|
11880
|
-
await
|
|
12792
|
+
const presetsDir = resolve6(baseDir, ".codeconductor", "presets");
|
|
12793
|
+
await mkdir3(presetsDir, { recursive: true });
|
|
11881
12794
|
const copied = [];
|
|
11882
12795
|
for (const preset of presets) {
|
|
11883
|
-
const destPath =
|
|
12796
|
+
const destPath = resolve6(presetsDir, preset.name);
|
|
11884
12797
|
if (!force && await fileExists2(destPath)) {
|
|
11885
12798
|
continue;
|
|
11886
12799
|
}
|
|
11887
12800
|
try {
|
|
11888
|
-
const content = await
|
|
11889
|
-
await
|
|
12801
|
+
const content = await readFile6(preset.sourcePath, "utf-8");
|
|
12802
|
+
await writeFile3(destPath, content, "utf-8");
|
|
11890
12803
|
copied.push(`.codeconductor/presets/${preset.name}`);
|
|
11891
12804
|
} catch (err2) {
|
|
11892
12805
|
const code = err2.code;
|
|
@@ -11908,8 +12821,8 @@ async function fileExists2(path) {
|
|
|
11908
12821
|
}
|
|
11909
12822
|
|
|
11910
12823
|
// src/commands/install.command.ts
|
|
11911
|
-
import { homedir as
|
|
11912
|
-
import { resolve as
|
|
12824
|
+
import { homedir as homedir5 } from "node:os";
|
|
12825
|
+
import { resolve as resolve8 } from "node:path";
|
|
11913
12826
|
|
|
11914
12827
|
// src/domain/council/council-agent.ts
|
|
11915
12828
|
function getResponsibilities(agentId) {
|
|
@@ -11967,281 +12880,63 @@ function generateAgentContent(agent) {
|
|
|
11967
12880
|
## Role
|
|
11968
12881
|
${agent.role}
|
|
11969
12882
|
|
|
11970
|
-
## Context
|
|
11971
|
-
${agent.context === "repo-readonly" ? "Can read repository but cannot modify files" : "Only receives prompts, no direct repository access"}
|
|
11972
|
-
|
|
11973
|
-
## Model Hint
|
|
11974
|
-
${agent.modelHint}
|
|
11975
|
-
|
|
11976
|
-
## Focus Areas
|
|
11977
|
-
${agent.focus.map((f) => `- ${f}`).join(`
|
|
11978
|
-
`)}
|
|
11979
|
-
|
|
11980
|
-
## Responsibilities
|
|
11981
|
-
${getResponsibilities(agent.id)}
|
|
11982
|
-
`;
|
|
11983
|
-
}
|
|
11984
|
-
|
|
11985
|
-
// src/adapters/claude/claude-council-generator.ts
|
|
11986
|
-
function generateClaudeFiles(spec) {
|
|
11987
|
-
const files = [];
|
|
11988
|
-
files.push({
|
|
11989
|
-
path: ".claude/skills/council/SKILL.md",
|
|
11990
|
-
content: generateCouncilSkill(spec),
|
|
11991
|
-
overwrite: false
|
|
11992
|
-
});
|
|
11993
|
-
for (const agent of spec.agents) {
|
|
11994
|
-
files.push({
|
|
11995
|
-
path: `.claude/agents/council-${agent.id}.md`,
|
|
11996
|
-
content: generateAgentContent(agent),
|
|
11997
|
-
overwrite: false
|
|
11998
|
-
});
|
|
11999
|
-
}
|
|
12000
|
-
return files;
|
|
12001
|
-
}
|
|
12002
|
-
function generateCouncilSkill(spec) {
|
|
12003
|
-
return `# Council Skill
|
|
12004
|
-
|
|
12005
|
-
## Description
|
|
12006
|
-
${spec.description}
|
|
12007
|
-
|
|
12008
|
-
## Version
|
|
12009
|
-
${spec.version}
|
|
12010
|
-
|
|
12011
|
-
## Agents
|
|
12012
|
-
${spec.agents.map((a) => `- **${a.role}** (${a.id}): ${a.focus.join(", ")}`).join(`
|
|
12013
|
-
`)}
|
|
12014
|
-
|
|
12015
|
-
## Usage
|
|
12016
|
-
Use the council agents to get multi-perspective analysis on code changes, architecture decisions, and security reviews.
|
|
12017
|
-
|
|
12018
|
-
## Context
|
|
12019
|
-
${spec.outputContract}
|
|
12020
|
-
`;
|
|
12021
|
-
}
|
|
12022
|
-
|
|
12023
|
-
// src/adapters/claude/claude-installer.ts
|
|
12024
|
-
class ClaudeInstaller {
|
|
12025
|
-
name = "claude";
|
|
12026
|
-
target = "claude";
|
|
12027
|
-
spec = null;
|
|
12028
|
-
setSpec(spec) {
|
|
12029
|
-
this.spec = spec;
|
|
12030
|
-
}
|
|
12031
|
-
async generate() {
|
|
12032
|
-
if (!this.spec) {
|
|
12033
|
-
throw new Error("Council spec not set");
|
|
12034
|
-
}
|
|
12035
|
-
return generateClaudeFiles(this.spec);
|
|
12036
|
-
}
|
|
12037
|
-
async isAvailable() {
|
|
12038
|
-
return true;
|
|
12039
|
-
}
|
|
12040
|
-
}
|
|
12041
|
-
function createClaudeInstaller(spec) {
|
|
12042
|
-
const installer = new ClaudeInstaller;
|
|
12043
|
-
installer.setSpec(spec);
|
|
12044
|
-
return installer;
|
|
12045
|
-
}
|
|
12046
|
-
|
|
12047
|
-
// src/adapters/codex/codex-council-generator.ts
|
|
12048
|
-
function generateCodexFiles(spec) {
|
|
12049
|
-
const files = [];
|
|
12050
|
-
files.push({
|
|
12051
|
-
path: ".codex/config.toml",
|
|
12052
|
-
content: generateCodexConfig(spec),
|
|
12053
|
-
overwrite: false
|
|
12054
|
-
});
|
|
12055
|
-
for (const agent of spec.agents) {
|
|
12056
|
-
files.push({
|
|
12057
|
-
path: `.codex/agents/council_${agent.id}.toml`,
|
|
12058
|
-
content: generateCodexAgent(agent),
|
|
12059
|
-
overwrite: true
|
|
12060
|
-
});
|
|
12061
|
-
}
|
|
12062
|
-
files.push({
|
|
12063
|
-
path: ".codex/skills/council/SKILL.md",
|
|
12064
|
-
content: generateCodexSkill(spec),
|
|
12065
|
-
overwrite: true
|
|
12066
|
-
});
|
|
12067
|
-
return files;
|
|
12068
|
-
}
|
|
12069
|
-
function generateCodexConfig(spec) {
|
|
12070
|
-
const agentTables = spec.agents.map((agent) => {
|
|
12071
|
-
const focusAreas = agent.focus.join(", ");
|
|
12072
|
-
return `
|
|
12073
|
-
[agents.${agent.id}]
|
|
12074
|
-
description = "${agent.role} council agent. Focus: ${focusAreas}. Context: ${agent.context}. Model hint: ${agent.modelHint}."
|
|
12075
|
-
nickname_candidates = ["${agent.role}", "Council ${agent.role}"]`;
|
|
12076
|
-
}).join(`
|
|
12077
|
-
`);
|
|
12078
|
-
return `# Codex Council Configuration
|
|
12079
|
-
|
|
12080
|
-
[project]
|
|
12081
|
-
name = "council"
|
|
12082
|
-
version = "${spec.version}"
|
|
12083
|
-
${agentTables}
|
|
12084
|
-
`;
|
|
12085
|
-
}
|
|
12086
|
-
function generateCodexAgent(agent) {
|
|
12087
|
-
const focusAreas = agent.focus.join(", ");
|
|
12088
|
-
return `name = "${agent.role}"
|
|
12089
|
-
description = "${agent.role} council agent. Focus: ${focusAreas}. Context: ${agent.context}. Model hint: ${agent.modelHint}."
|
|
12090
|
-
nickname_candidates = ["${agent.role}", "Council ${agent.role}"]
|
|
12091
|
-
developer_instructions = "You are the ${agent.role} council agent. Your focus areas are: ${focusAreas}. Context: ${agent.context}. Apply ${agent.modelHint} reasoning to your analysis."
|
|
12092
|
-
`;
|
|
12093
|
-
}
|
|
12094
|
-
function generateCodexSkill(spec) {
|
|
12095
|
-
return `---
|
|
12096
|
-
name: council
|
|
12097
|
-
description: ${spec.description}
|
|
12098
|
-
version: ${spec.version}
|
|
12099
|
-
---
|
|
12100
|
-
|
|
12101
|
-
## Agents
|
|
12102
|
-
${spec.agents.map((a) => `- **${a.role}** (${a.id}): ${a.focus.join(", ")}`).join(`
|
|
12103
|
-
`)}
|
|
12104
|
-
|
|
12105
|
-
## Usage
|
|
12106
|
-
Use the council agents to get multi-perspective analysis on code changes, architecture decisions, and security reviews.
|
|
12107
|
-
`;
|
|
12108
|
-
}
|
|
12109
|
-
|
|
12110
|
-
// src/adapters/codex/codex-installer.ts
|
|
12111
|
-
class CodexInstaller {
|
|
12112
|
-
name = "codex";
|
|
12113
|
-
target = "codex";
|
|
12114
|
-
spec = null;
|
|
12115
|
-
setSpec(spec) {
|
|
12116
|
-
this.spec = spec;
|
|
12117
|
-
}
|
|
12118
|
-
async generate() {
|
|
12119
|
-
if (!this.spec) {
|
|
12120
|
-
throw new Error("Council spec not set");
|
|
12121
|
-
}
|
|
12122
|
-
return generateCodexFiles(this.spec);
|
|
12123
|
-
}
|
|
12124
|
-
async isAvailable() {
|
|
12125
|
-
return true;
|
|
12126
|
-
}
|
|
12127
|
-
}
|
|
12128
|
-
function createCodexInstaller(spec) {
|
|
12129
|
-
const installer = new CodexInstaller;
|
|
12130
|
-
installer.setSpec(spec);
|
|
12131
|
-
return installer;
|
|
12132
|
-
}
|
|
12133
|
-
|
|
12134
|
-
// src/adapters/opencode/opencode-council-generator.ts
|
|
12135
|
-
function generateOpenCodeFiles(spec) {
|
|
12136
|
-
const files = [];
|
|
12137
|
-
files.push({
|
|
12138
|
-
path: ".opencode/commands/cc-council.md",
|
|
12139
|
-
content: generateCouncilCommand(spec),
|
|
12140
|
-
overwrite: false
|
|
12141
|
-
});
|
|
12142
|
-
files.push({
|
|
12143
|
-
path: ".opencode/agents/council-lead.md",
|
|
12144
|
-
content: generateCouncilLead(spec),
|
|
12145
|
-
overwrite: false
|
|
12146
|
-
});
|
|
12147
|
-
for (const agent of spec.agents) {
|
|
12148
|
-
files.push({
|
|
12149
|
-
path: `.opencode/agents/council-${agent.id}.md`,
|
|
12150
|
-
content: generateOpenCodeAgentContent(agent),
|
|
12151
|
-
overwrite: false
|
|
12152
|
-
});
|
|
12153
|
-
}
|
|
12154
|
-
return files;
|
|
12155
|
-
}
|
|
12156
|
-
function generateCouncilCommand(spec) {
|
|
12157
|
-
return `---
|
|
12158
|
-
description: ${yamlString(spec.description)}
|
|
12159
|
-
agent: council-lead
|
|
12160
|
-
subtask: true
|
|
12161
|
-
---
|
|
12162
|
-
|
|
12163
|
-
Run the CodeConductor council for multi-perspective analysis.
|
|
12164
|
-
|
|
12165
|
-
## Version
|
|
12166
|
-
${spec.version}
|
|
12167
|
-
|
|
12168
|
-
## Agents
|
|
12169
|
-
${spec.agents.map((a) => `- ${a.role} (${a.id})`).join(`
|
|
12170
|
-
`)}
|
|
12171
|
-
|
|
12172
|
-
## Instructions
|
|
12173
|
-
Coordinate with the council agents and synthesize their perspectives into the configured output contract.
|
|
12174
|
-
`;
|
|
12175
|
-
}
|
|
12176
|
-
function generateCouncilLead(spec) {
|
|
12177
|
-
return `---
|
|
12178
|
-
description: ${yamlString(`${spec.description} Council lead. Coordinates council members and synthesizes recommendations.`)}
|
|
12179
|
-
mode: subagent
|
|
12180
|
-
permission:
|
|
12181
|
-
read: allow
|
|
12182
|
-
edit: deny
|
|
12183
|
-
bash: deny
|
|
12184
|
-
glob: allow
|
|
12185
|
-
grep: allow
|
|
12186
|
-
webfetch: deny
|
|
12187
|
-
websearch: deny
|
|
12188
|
-
---
|
|
12189
|
-
|
|
12190
|
-
# Council Lead Agent
|
|
12191
|
-
|
|
12192
|
-
## Role
|
|
12193
|
-
Coordinates the council and synthesizes perspectives
|
|
12883
|
+
## Context
|
|
12884
|
+
${agent.context === "repo-readonly" ? "Can read repository but cannot modify files" : "Only receives prompts, no direct repository access"}
|
|
12194
12885
|
|
|
12195
|
-
##
|
|
12196
|
-
${
|
|
12886
|
+
## Model Hint
|
|
12887
|
+
${agent.modelHint}
|
|
12197
12888
|
|
|
12198
|
-
##
|
|
12199
|
-
${
|
|
12889
|
+
## Focus Areas
|
|
12890
|
+
${agent.focus.map((f) => `- ${f}`).join(`
|
|
12200
12891
|
`)}
|
|
12201
12892
|
|
|
12202
12893
|
## Responsibilities
|
|
12203
|
-
|
|
12204
|
-
- Synthesize different perspectives
|
|
12205
|
-
- Identify consensus and disagreements
|
|
12206
|
-
- Provide final recommendation
|
|
12894
|
+
${getResponsibilities(agent.id)}
|
|
12207
12895
|
`;
|
|
12208
12896
|
}
|
|
12209
|
-
function generateOpenCodeAgentContent(agent) {
|
|
12210
|
-
return `---
|
|
12211
|
-
description: ${yamlString(`${agent.role} council agent. Focus: ${agent.focus.join(", ")}. Context: ${agent.context}. Model hint: ${agent.modelHint}.`)}
|
|
12212
|
-
mode: subagent
|
|
12213
|
-
permission:
|
|
12214
|
-
${generatePermissionBlock(agent.context)}
|
|
12215
|
-
---
|
|
12216
12897
|
|
|
12217
|
-
|
|
12218
|
-
|
|
12219
|
-
|
|
12220
|
-
|
|
12221
|
-
|
|
12222
|
-
|
|
12223
|
-
|
|
12224
|
-
|
|
12225
|
-
|
|
12226
|
-
|
|
12227
|
-
|
|
12898
|
+
// src/adapters/claude/claude-council-generator.ts
|
|
12899
|
+
function generateClaudeFiles(spec) {
|
|
12900
|
+
const files = [];
|
|
12901
|
+
files.push({
|
|
12902
|
+
path: ".claude/skills/council/SKILL.md",
|
|
12903
|
+
content: generateCouncilSkill(spec),
|
|
12904
|
+
overwrite: false
|
|
12905
|
+
});
|
|
12906
|
+
for (const agent of spec.agents) {
|
|
12907
|
+
files.push({
|
|
12908
|
+
path: `.claude/agents/council-${agent.id}.md`,
|
|
12909
|
+
content: generateAgentContent(agent),
|
|
12910
|
+
overwrite: false
|
|
12911
|
+
});
|
|
12228
12912
|
}
|
|
12229
|
-
return
|
|
12230
|
-
edit: deny
|
|
12231
|
-
bash: deny
|
|
12232
|
-
glob: deny
|
|
12233
|
-
grep: deny
|
|
12234
|
-
webfetch: deny
|
|
12235
|
-
websearch: deny`;
|
|
12913
|
+
return files;
|
|
12236
12914
|
}
|
|
12237
|
-
function
|
|
12238
|
-
return
|
|
12915
|
+
function generateCouncilSkill(spec) {
|
|
12916
|
+
return `# Council Skill
|
|
12917
|
+
|
|
12918
|
+
## Description
|
|
12919
|
+
${spec.description}
|
|
12920
|
+
|
|
12921
|
+
## Version
|
|
12922
|
+
${spec.version}
|
|
12923
|
+
|
|
12924
|
+
## Agents
|
|
12925
|
+
${spec.agents.map((a) => `- **${a.role}** (${a.id}): ${a.focus.join(", ")}`).join(`
|
|
12926
|
+
`)}
|
|
12927
|
+
|
|
12928
|
+
## Usage
|
|
12929
|
+
Use the council agents to get multi-perspective analysis on code changes, architecture decisions, and security reviews.
|
|
12930
|
+
|
|
12931
|
+
## Context
|
|
12932
|
+
${spec.outputContract}
|
|
12933
|
+
`;
|
|
12239
12934
|
}
|
|
12240
12935
|
|
|
12241
|
-
// src/adapters/
|
|
12242
|
-
class
|
|
12243
|
-
name = "
|
|
12244
|
-
target = "
|
|
12936
|
+
// src/adapters/claude/claude-installer.ts
|
|
12937
|
+
class ClaudeInstaller {
|
|
12938
|
+
name = "claude";
|
|
12939
|
+
target = "claude";
|
|
12245
12940
|
spec = null;
|
|
12246
12941
|
setSpec(spec) {
|
|
12247
12942
|
this.spec = spec;
|
|
@@ -12250,467 +12945,299 @@ class OpenCodeInstaller {
|
|
|
12250
12945
|
if (!this.spec) {
|
|
12251
12946
|
throw new Error("Council spec not set");
|
|
12252
12947
|
}
|
|
12253
|
-
return
|
|
12948
|
+
return generateClaudeFiles(this.spec);
|
|
12254
12949
|
}
|
|
12255
12950
|
async isAvailable() {
|
|
12256
12951
|
return true;
|
|
12257
12952
|
}
|
|
12258
12953
|
}
|
|
12259
|
-
function
|
|
12260
|
-
const installer = new
|
|
12954
|
+
function createClaudeInstaller(spec) {
|
|
12955
|
+
const installer = new ClaudeInstaller;
|
|
12261
12956
|
installer.setSpec(spec);
|
|
12262
12957
|
return installer;
|
|
12263
12958
|
}
|
|
12264
12959
|
|
|
12265
|
-
// src/
|
|
12266
|
-
|
|
12267
|
-
|
|
12268
|
-
|
|
12269
|
-
|
|
12270
|
-
|
|
12271
|
-
|
|
12272
|
-
|
|
12273
|
-
|
|
12274
|
-
|
|
12275
|
-
|
|
12276
|
-
|
|
12277
|
-
|
|
12278
|
-
|
|
12279
|
-
}
|
|
12280
|
-
if (options.dryRun) {
|
|
12281
|
-
results.push({
|
|
12282
|
-
path: file.path,
|
|
12283
|
-
success: true
|
|
12284
|
-
});
|
|
12285
|
-
continue;
|
|
12286
|
-
}
|
|
12287
|
-
if (!options.force) {
|
|
12288
|
-
try {
|
|
12289
|
-
await access4(file.path);
|
|
12290
|
-
results.push({
|
|
12291
|
-
path: file.path,
|
|
12292
|
-
success: false,
|
|
12293
|
-
error: "File exists, use --force to overwrite"
|
|
12294
|
-
});
|
|
12295
|
-
continue;
|
|
12296
|
-
} catch {}
|
|
12297
|
-
}
|
|
12298
|
-
try {
|
|
12299
|
-
const dir = dirname2(file.path);
|
|
12300
|
-
await mkdir3(dir, { recursive: true });
|
|
12301
|
-
await writeFile3(file.path, file.content, "utf-8");
|
|
12302
|
-
results.push({
|
|
12303
|
-
path: file.path,
|
|
12304
|
-
success: true
|
|
12305
|
-
});
|
|
12306
|
-
} catch (error) {
|
|
12307
|
-
results.push({
|
|
12308
|
-
path: file.path,
|
|
12309
|
-
success: false,
|
|
12310
|
-
error: String(error)
|
|
12311
|
-
});
|
|
12312
|
-
}
|
|
12960
|
+
// src/adapters/codex/codex-council-generator.ts
|
|
12961
|
+
function generateCodexFiles(spec) {
|
|
12962
|
+
const files = [];
|
|
12963
|
+
files.push({
|
|
12964
|
+
path: ".codex/config.toml",
|
|
12965
|
+
content: generateCodexConfig(spec),
|
|
12966
|
+
overwrite: false
|
|
12967
|
+
});
|
|
12968
|
+
for (const agent of spec.agents) {
|
|
12969
|
+
files.push({
|
|
12970
|
+
path: `.codex/agents/council_${agent.id}.toml`,
|
|
12971
|
+
content: generateCodexAgent(agent),
|
|
12972
|
+
overwrite: true
|
|
12973
|
+
});
|
|
12313
12974
|
}
|
|
12314
|
-
|
|
12975
|
+
files.push({
|
|
12976
|
+
path: ".codex/skills/council/SKILL.md",
|
|
12977
|
+
content: generateCodexSkill(spec),
|
|
12978
|
+
overwrite: true
|
|
12979
|
+
});
|
|
12980
|
+
return files;
|
|
12315
12981
|
}
|
|
12982
|
+
function generateCodexConfig(spec) {
|
|
12983
|
+
const agentTables = spec.agents.map((agent) => {
|
|
12984
|
+
const focusAreas = agent.focus.join(", ");
|
|
12985
|
+
return `
|
|
12986
|
+
[agents.${agent.id}]
|
|
12987
|
+
description = "${agent.role} council agent. Focus: ${focusAreas}. Context: ${agent.context}. Model hint: ${agent.modelHint}."
|
|
12988
|
+
nickname_candidates = ["${agent.role}", "Council ${agent.role}"]`;
|
|
12989
|
+
}).join(`
|
|
12990
|
+
`);
|
|
12991
|
+
return `# Codex Council Configuration
|
|
12316
12992
|
|
|
12317
|
-
|
|
12318
|
-
|
|
12319
|
-
|
|
12320
|
-
|
|
12321
|
-
|
|
12322
|
-
|
|
12323
|
-
|
|
12324
|
-
|
|
12325
|
-
|
|
12326
|
-
|
|
12327
|
-
}
|
|
12328
|
-
|
|
12329
|
-
|
|
12330
|
-
|
|
12331
|
-
|
|
12332
|
-
|
|
12333
|
-
|
|
12334
|
-
|
|
12335
|
-
|
|
12336
|
-
|
|
12337
|
-
|
|
12338
|
-
\`\`\`
|
|
12339
|
-
<type>(<scope>): <short description>
|
|
12340
|
-
|
|
12341
|
-
- <detail 1>
|
|
12342
|
-
- <detail 2>
|
|
12343
|
-
\`\`\`
|
|
12344
|
-
|
|
12345
|
-
### Valid Types
|
|
12346
|
-
|
|
12347
|
-
\`feat\` \`fix\` \`docs\` \`style\` \`refactor\` \`test\` \`chore\` \`perf\` \`ci\` \`build\`
|
|
12348
|
-
\`revert\`
|
|
12349
|
-
|
|
12350
|
-
### Rules
|
|
12351
|
-
|
|
12352
|
-
- Language: **neutral English** always
|
|
12353
|
-
- Header: maximum 69 characters, no trailing period
|
|
12354
|
-
- Body: concise bullet points, one idea per line
|
|
12355
|
-
- Footer: only for breaking changes or issues
|
|
12356
|
-
- No gerunds ("adding", "fixing")
|
|
12357
|
-
- Use infinitive or imperative ("add", "fix", "update")`,
|
|
12358
|
-
es: `---
|
|
12359
|
-
trigger: always_on
|
|
12360
|
-
description: Reglas para generar mensajes de commit con formato Conventional Commits
|
|
12361
|
-
---
|
|
12362
|
-
|
|
12363
|
-
## Git Commit Messages
|
|
12364
|
-
|
|
12365
|
-
### Formato
|
|
12366
|
-
|
|
12367
|
-
\`\`\`
|
|
12368
|
-
<tipo>(<scope>): <descripcion corta>
|
|
12369
|
-
|
|
12370
|
-
- <detalle 1>
|
|
12371
|
-
- <detalle 2>
|
|
12372
|
-
\`\`\`
|
|
12373
|
-
|
|
12374
|
-
### Tipos validos
|
|
12375
|
-
|
|
12376
|
-
\`feat\` \`fix\` \`docs\` \`style\` \`refactor\` \`test\` \`chore\` \`perf\` \`ci\` \`build\`
|
|
12377
|
-
\`revert\`
|
|
12378
|
-
|
|
12379
|
-
### Reglas
|
|
12380
|
-
|
|
12381
|
-
- Idioma: **inglés neutro** siempre
|
|
12382
|
-
- Encabezado: maximo 69 caracteres, sin punto final
|
|
12383
|
-
- Cuerpo: viñetas concisas, una idea por linea
|
|
12384
|
-
- Footer: solo para breaking changes o issues
|
|
12385
|
-
- Sin gerundios ("agregando", "corrigiendo")
|
|
12386
|
-
- Usar infinitivo o imperativo ("agregar", "corregir", "actualizar")`
|
|
12387
|
-
};
|
|
12388
|
-
var COMMIT_WORKFLOW = {
|
|
12389
|
-
en: `---
|
|
12390
|
-
name: commit
|
|
12391
|
-
description: Generates a commit in English following Conventional Commits based on staged changes
|
|
12392
|
-
---
|
|
12393
|
-
|
|
12394
|
-
// turbo-all
|
|
12395
|
-
|
|
12396
|
-
## Steps
|
|
12397
|
-
|
|
12398
|
-
1. View staged changes: \`git diff --cached --stat\`
|
|
12399
|
-
2. If nothing is staged, suggest \`git add .\` or specific files
|
|
12400
|
-
3. Get full diff: \`git diff --cached\`
|
|
12401
|
-
4. Check recent style: \`git log -n 3 --oneline\`
|
|
12402
|
-
5. Generate message following \`.agents/rules/commit-style.md\`
|
|
12403
|
-
6. Show proposal and confirm with the user
|
|
12404
|
-
7. Execute: \`git commit -m "<message>"\`
|
|
12405
|
-
8. Confirm success: \`git status\``,
|
|
12406
|
-
es: `---
|
|
12407
|
-
name: commit
|
|
12408
|
-
description: Genera un commit en inglés siguiendo Conventional Commits basado en los cambios staged
|
|
12409
|
-
---
|
|
12410
|
-
|
|
12411
|
-
// turbo-all
|
|
12993
|
+
[project]
|
|
12994
|
+
name = "council"
|
|
12995
|
+
version = "${spec.version}"
|
|
12996
|
+
${agentTables}
|
|
12997
|
+
`;
|
|
12998
|
+
}
|
|
12999
|
+
function generateCodexAgent(agent) {
|
|
13000
|
+
const focusAreas = agent.focus.join(", ");
|
|
13001
|
+
return `name = "${agent.role}"
|
|
13002
|
+
description = "${agent.role} council agent. Focus: ${focusAreas}. Context: ${agent.context}. Model hint: ${agent.modelHint}."
|
|
13003
|
+
nickname_candidates = ["${agent.role}", "Council ${agent.role}"]
|
|
13004
|
+
developer_instructions = "You are the ${agent.role} council agent. Your focus areas are: ${focusAreas}. Context: ${agent.context}. Apply ${agent.modelHint} reasoning to your analysis."
|
|
13005
|
+
`;
|
|
13006
|
+
}
|
|
13007
|
+
function generateCodexSkill(spec) {
|
|
13008
|
+
return `---
|
|
13009
|
+
name: council
|
|
13010
|
+
description: ${spec.description}
|
|
13011
|
+
version: ${spec.version}
|
|
13012
|
+
---
|
|
12412
13013
|
|
|
12413
|
-
##
|
|
13014
|
+
## Agents
|
|
13015
|
+
${spec.agents.map((a) => `- **${a.role}** (${a.id}): ${a.focus.join(", ")}`).join(`
|
|
13016
|
+
`)}
|
|
12414
13017
|
|
|
12415
|
-
|
|
12416
|
-
|
|
12417
|
-
|
|
12418
|
-
4. Ver estilo reciente: \`git log -n 3 --oneline\`
|
|
12419
|
-
5. Generar mensaje siguiendo \`.agents/rules/commit-style.md\`
|
|
12420
|
-
6. Mostrar propuesta y confirmar con el usuario
|
|
12421
|
-
7. Ejecutar: \`git commit -m "<mensaje>"\`
|
|
12422
|
-
8. Confirmar éxito: \`git status\``
|
|
12423
|
-
};
|
|
12424
|
-
function getLanguageInstruction(locale) {
|
|
12425
|
-
const key = SUPPORTED_LOCALES.includes(locale) ? locale : "en";
|
|
12426
|
-
return `- ${LANGUAGE_INSTRUCTIONS[key]}`;
|
|
13018
|
+
## Usage
|
|
13019
|
+
Use the council agents to get multi-perspective analysis on code changes, architecture decisions, and security reviews.
|
|
13020
|
+
`;
|
|
12427
13021
|
}
|
|
12428
|
-
var LOCALE_PLACEHOLDER = "{{LANGUAGE_INSTRUCTIONS}}";
|
|
12429
13022
|
|
|
12430
|
-
// src/
|
|
12431
|
-
|
|
12432
|
-
|
|
12433
|
-
|
|
12434
|
-
|
|
12435
|
-
|
|
12436
|
-
|
|
13023
|
+
// src/adapters/codex/codex-installer.ts
|
|
13024
|
+
class CodexInstaller {
|
|
13025
|
+
name = "codex";
|
|
13026
|
+
target = "codex";
|
|
13027
|
+
spec = null;
|
|
13028
|
+
setSpec(spec) {
|
|
13029
|
+
this.spec = spec;
|
|
12437
13030
|
}
|
|
12438
|
-
|
|
12439
|
-
|
|
12440
|
-
|
|
12441
|
-
|
|
12442
|
-
|
|
12443
|
-
action: "merged"
|
|
12444
|
-
};
|
|
12445
|
-
}
|
|
12446
|
-
function validateMarkers(content, label) {
|
|
12447
|
-
const beginCount = countOccurrences(content, MANAGED_BEGIN_MARKER);
|
|
12448
|
-
const endCount = countOccurrences(content, MANAGED_END_MARKER);
|
|
12449
|
-
if (beginCount !== 1 || endCount !== 1) {
|
|
12450
|
-
throw new Error(`${label} must contain exactly one managed begin marker and one managed end marker`);
|
|
13031
|
+
async generate() {
|
|
13032
|
+
if (!this.spec) {
|
|
13033
|
+
throw new Error("Council spec not set");
|
|
13034
|
+
}
|
|
13035
|
+
return generateCodexFiles(this.spec);
|
|
12451
13036
|
}
|
|
12452
|
-
|
|
12453
|
-
|
|
13037
|
+
async isAvailable() {
|
|
13038
|
+
return true;
|
|
12454
13039
|
}
|
|
12455
13040
|
}
|
|
12456
|
-
function
|
|
12457
|
-
const
|
|
12458
|
-
|
|
12459
|
-
return
|
|
12460
|
-
}
|
|
12461
|
-
function countOccurrences(content, needle) {
|
|
12462
|
-
return content.split(needle).length - 1;
|
|
13041
|
+
function createCodexInstaller(spec) {
|
|
13042
|
+
const installer = new CodexInstaller;
|
|
13043
|
+
installer.setSpec(spec);
|
|
13044
|
+
return installer;
|
|
12463
13045
|
}
|
|
12464
13046
|
|
|
12465
|
-
// src/
|
|
12466
|
-
|
|
12467
|
-
const entries = await readdir(dir, { withFileTypes: true });
|
|
13047
|
+
// src/adapters/opencode/opencode-council-generator.ts
|
|
13048
|
+
function generateOpenCodeFiles(spec) {
|
|
12468
13049
|
const files = [];
|
|
12469
|
-
|
|
12470
|
-
|
|
12471
|
-
|
|
12472
|
-
|
|
12473
|
-
|
|
12474
|
-
|
|
12475
|
-
|
|
13050
|
+
files.push({
|
|
13051
|
+
path: ".opencode/commands/cc-council.md",
|
|
13052
|
+
content: generateCouncilCommand(spec),
|
|
13053
|
+
overwrite: false
|
|
13054
|
+
});
|
|
13055
|
+
files.push({
|
|
13056
|
+
path: ".opencode/agents/council-lead.md",
|
|
13057
|
+
content: generateCouncilLead(spec),
|
|
13058
|
+
overwrite: false
|
|
13059
|
+
});
|
|
13060
|
+
for (const agent of spec.agents) {
|
|
13061
|
+
files.push({
|
|
13062
|
+
path: `.opencode/agents/council-${agent.id}.md`,
|
|
13063
|
+
content: generateOpenCodeAgentContent(agent),
|
|
13064
|
+
overwrite: false
|
|
13065
|
+
});
|
|
12476
13066
|
}
|
|
12477
13067
|
return files;
|
|
12478
13068
|
}
|
|
12479
|
-
|
|
12480
|
-
|
|
12481
|
-
|
|
12482
|
-
|
|
12483
|
-
|
|
12484
|
-
|
|
12485
|
-
|
|
12486
|
-
|
|
12487
|
-
|
|
12488
|
-
|
|
12489
|
-
|
|
12490
|
-
|
|
12491
|
-
|
|
12492
|
-
|
|
12493
|
-
|
|
12494
|
-
|
|
12495
|
-
|
|
12496
|
-
|
|
12497
|
-
|
|
12498
|
-
const srcVal = source[key];
|
|
12499
|
-
const tgtVal = target[key];
|
|
12500
|
-
if (Array.isArray(srcVal) && Array.isArray(tgtVal)) {
|
|
12501
|
-
result[key] = [...new Set([...tgtVal, ...srcVal])];
|
|
12502
|
-
} else if (srcVal && typeof srcVal === "object" && !Array.isArray(srcVal) && tgtVal && typeof tgtVal === "object" && !Array.isArray(tgtVal)) {
|
|
12503
|
-
result[key] = mergeDeep(tgtVal, srcVal);
|
|
12504
|
-
} else {
|
|
12505
|
-
result[key] = srcVal;
|
|
12506
|
-
}
|
|
12507
|
-
}
|
|
12508
|
-
return result;
|
|
13069
|
+
function generateCouncilCommand(spec) {
|
|
13070
|
+
return `---
|
|
13071
|
+
description: ${yamlString(spec.description)}
|
|
13072
|
+
agent: council-lead
|
|
13073
|
+
subtask: true
|
|
13074
|
+
---
|
|
13075
|
+
|
|
13076
|
+
Run the CodeConductor council for multi-perspective analysis.
|
|
13077
|
+
|
|
13078
|
+
## Version
|
|
13079
|
+
${spec.version}
|
|
13080
|
+
|
|
13081
|
+
## Agents
|
|
13082
|
+
${spec.agents.map((a) => `- ${a.role} (${a.id})`).join(`
|
|
13083
|
+
`)}
|
|
13084
|
+
|
|
13085
|
+
## Instructions
|
|
13086
|
+
Coordinate with the council agents and synthesize their perspectives into the configured output contract.
|
|
13087
|
+
`;
|
|
12509
13088
|
}
|
|
12510
|
-
function
|
|
12511
|
-
|
|
12512
|
-
|
|
12513
|
-
|
|
12514
|
-
|
|
12515
|
-
|
|
12516
|
-
|
|
12517
|
-
|
|
12518
|
-
|
|
12519
|
-
|
|
12520
|
-
|
|
12521
|
-
|
|
12522
|
-
|
|
12523
|
-
|
|
12524
|
-
|
|
13089
|
+
function generateCouncilLead(spec) {
|
|
13090
|
+
return `---
|
|
13091
|
+
description: ${yamlString(`${spec.description} Council lead. Coordinates council members and synthesizes recommendations.`)}
|
|
13092
|
+
mode: subagent
|
|
13093
|
+
permission:
|
|
13094
|
+
read: allow
|
|
13095
|
+
edit: deny
|
|
13096
|
+
bash: deny
|
|
13097
|
+
glob: allow
|
|
13098
|
+
grep: allow
|
|
13099
|
+
webfetch: deny
|
|
13100
|
+
websearch: deny
|
|
13101
|
+
---
|
|
13102
|
+
|
|
13103
|
+
# Council Lead Agent
|
|
13104
|
+
|
|
13105
|
+
## Role
|
|
13106
|
+
Coordinates the council and synthesizes perspectives
|
|
13107
|
+
|
|
13108
|
+
## Version
|
|
13109
|
+
${spec.version}
|
|
13110
|
+
|
|
13111
|
+
## Council Members
|
|
13112
|
+
${spec.agents.map((a) => `- ${a.role}: ${a.focus.join(", ")}`).join(`
|
|
13113
|
+
`)}
|
|
13114
|
+
|
|
13115
|
+
## Responsibilities
|
|
13116
|
+
- Coordinate agent responses
|
|
13117
|
+
- Synthesize different perspectives
|
|
13118
|
+
- Identify consensus and disagreements
|
|
13119
|
+
- Provide final recommendation
|
|
13120
|
+
`;
|
|
12525
13121
|
}
|
|
12526
|
-
function
|
|
12527
|
-
|
|
12528
|
-
|
|
12529
|
-
|
|
12530
|
-
|
|
12531
|
-
|
|
12532
|
-
|
|
12533
|
-
|
|
12534
|
-
|
|
12535
|
-
result2 = substituteToolNames(result2, modelConfig);
|
|
12536
|
-
}
|
|
12537
|
-
return result2;
|
|
12538
|
-
}
|
|
12539
|
-
const knownRoles = [
|
|
12540
|
-
"orchestrator",
|
|
12541
|
-
"task-coach",
|
|
12542
|
-
"architect",
|
|
12543
|
-
"implementer",
|
|
12544
|
-
"tester",
|
|
12545
|
-
"reviewer",
|
|
12546
|
-
"docs",
|
|
12547
|
-
"repo-explorer"
|
|
12548
|
-
];
|
|
12549
|
-
let result = templatedContent;
|
|
12550
|
-
for (const role of knownRoles) {
|
|
12551
|
-
if (!modelConfig.agents[role])
|
|
12552
|
-
continue;
|
|
12553
|
-
const agentModels = modelConfig.agents[role];
|
|
12554
|
-
const sectionRegex = new RegExp(`(### ${role}[\\s\\S]*?)(?=### |## |$)`, "gi");
|
|
12555
|
-
const sectionMatch = result.match(sectionRegex);
|
|
12556
|
-
if (sectionMatch) {
|
|
12557
|
-
for (const section of sectionMatch) {
|
|
12558
|
-
const renderedSection = section.replace(/\{\{MODEL_CLAUDE\}\}/g, agentModels.claude ?? "").replace(/\{\{MODEL_OPENCODE\}\}/g, agentModels.opencode ?? "").replace(/\{\{MODEL_CODEX\}\}/g, agentModels.codex ?? "").replace(/\{\{MODEL_GEMINI\}\}/g, agentModels.gemini ?? "").replace(/\{\{MODEL_CURSOR\}\}/g, agentModels.cursor ?? "");
|
|
12559
|
-
result = result.replace(section, renderedSection);
|
|
12560
|
-
}
|
|
12561
|
-
}
|
|
12562
|
-
}
|
|
12563
|
-
result = result.replace(new RegExp(LOCALE_PLACEHOLDER.replace(/[{}]/g, "\\$&"), "g"), getLanguageInstruction(locale));
|
|
12564
|
-
if (modelConfig.tools || modelConfig.permissions) {
|
|
12565
|
-
result = substituteToolNames(result, modelConfig);
|
|
12566
|
-
}
|
|
12567
|
-
return result;
|
|
13122
|
+
function generateOpenCodeAgentContent(agent) {
|
|
13123
|
+
return `---
|
|
13124
|
+
description: ${yamlString(`${agent.role} council agent. Focus: ${agent.focus.join(", ")}. Context: ${agent.context}. Model hint: ${agent.modelHint}.`)}
|
|
13125
|
+
mode: subagent
|
|
13126
|
+
permission:
|
|
13127
|
+
${generatePermissionBlock(agent.context)}
|
|
13128
|
+
---
|
|
13129
|
+
|
|
13130
|
+
${generateAgentContent(agent)}`;
|
|
12568
13131
|
}
|
|
12569
|
-
function
|
|
12570
|
-
if (
|
|
12571
|
-
return
|
|
12572
|
-
|
|
12573
|
-
|
|
12574
|
-
|
|
12575
|
-
|
|
12576
|
-
|
|
12577
|
-
|
|
12578
|
-
const updatedFrontmatter2 = frontmatter.replace(/^tools:\s*(.+)\r?\n?/m, "");
|
|
12579
|
-
return content.replace(fmMatch[0], `---
|
|
12580
|
-
${updatedFrontmatter2}
|
|
12581
|
-
---`);
|
|
13132
|
+
function generatePermissionBlock(context) {
|
|
13133
|
+
if (context === "repo-readonly") {
|
|
13134
|
+
return ` read: allow
|
|
13135
|
+
edit: deny
|
|
13136
|
+
bash: deny
|
|
13137
|
+
glob: allow
|
|
13138
|
+
grep: allow
|
|
13139
|
+
webfetch: deny
|
|
13140
|
+
websearch: deny`;
|
|
12582
13141
|
}
|
|
12583
|
-
|
|
12584
|
-
|
|
12585
|
-
|
|
12586
|
-
|
|
12587
|
-
|
|
12588
|
-
|
|
12589
|
-
|
|
12590
|
-
|
|
12591
|
-
|
|
12592
|
-
|
|
12593
|
-
});
|
|
12594
|
-
return `tools: ${mappedNames.join(", ")}`;
|
|
12595
|
-
});
|
|
12596
|
-
return content.replace(fmMatch[0], `---
|
|
12597
|
-
${updatedFrontmatter}
|
|
12598
|
-
---`);
|
|
13142
|
+
return ` read: deny
|
|
13143
|
+
edit: deny
|
|
13144
|
+
bash: deny
|
|
13145
|
+
glob: deny
|
|
13146
|
+
grep: deny
|
|
13147
|
+
webfetch: deny
|
|
13148
|
+
websearch: deny`;
|
|
13149
|
+
}
|
|
13150
|
+
function yamlString(value) {
|
|
13151
|
+
return JSON.stringify(value);
|
|
12599
13152
|
}
|
|
12600
|
-
async function applySingleFile(srcPath, destPath, strategy, force, dryRun, isTemplate, modelConfig, locale) {
|
|
12601
|
-
if (strategy === "skip") {
|
|
12602
|
-
return { src: srcPath, dest: destPath, action: "skipped", dryRun };
|
|
12603
|
-
}
|
|
12604
|
-
let content;
|
|
12605
|
-
try {
|
|
12606
|
-
content = await readFile4(srcPath, "utf-8");
|
|
12607
|
-
} catch (e) {
|
|
12608
|
-
return { src: srcPath, dest: destPath, action: "error", error: `Cannot read source: ${e}` };
|
|
12609
|
-
}
|
|
12610
|
-
const incomingContent = isTemplate && modelConfig ? renderTemplate(content, modelConfig, srcPath, locale) : content;
|
|
12611
|
-
let finalContent = incomingContent;
|
|
12612
|
-
let action = "written";
|
|
12613
|
-
if (strategy === "append") {
|
|
12614
|
-
let existing = "";
|
|
12615
|
-
try {
|
|
12616
|
-
existing = await readFile4(destPath, "utf-8");
|
|
12617
|
-
} catch {}
|
|
12618
|
-
if (existing) {
|
|
12619
|
-
finalContent = existing + `
|
|
12620
|
-
|
|
12621
|
-
---
|
|
12622
13153
|
|
|
12623
|
-
|
|
12624
|
-
|
|
12625
|
-
|
|
12626
|
-
|
|
12627
|
-
|
|
12628
|
-
|
|
12629
|
-
|
|
12630
|
-
} catch {}
|
|
12631
|
-
try {
|
|
12632
|
-
const incoming = JSON.parse(incomingContent);
|
|
12633
|
-
finalContent = JSON.stringify(mergeDeep(existing, incoming), null, 2);
|
|
12634
|
-
} catch (e) {
|
|
12635
|
-
return { src: srcPath, dest: destPath, action: "error", error: `JSON merge failed: ${e}` };
|
|
12636
|
-
}
|
|
12637
|
-
action = "merged";
|
|
12638
|
-
} else if (strategy === "merge-managed") {
|
|
12639
|
-
let existing = null;
|
|
12640
|
-
try {
|
|
12641
|
-
existing = await readFile4(destPath, "utf-8");
|
|
12642
|
-
} catch {}
|
|
12643
|
-
try {
|
|
12644
|
-
const merged = mergeManagedBlock(existing, incomingContent);
|
|
12645
|
-
finalContent = merged.content;
|
|
12646
|
-
action = merged.action;
|
|
12647
|
-
} catch (e) {
|
|
12648
|
-
return { src: srcPath, dest: destPath, action: "error", error: `Managed merge failed: ${e}` };
|
|
12649
|
-
}
|
|
13154
|
+
// src/adapters/opencode/opencode-installer.ts
|
|
13155
|
+
class OpenCodeInstaller {
|
|
13156
|
+
name = "opencode";
|
|
13157
|
+
target = "opencode";
|
|
13158
|
+
spec = null;
|
|
13159
|
+
setSpec(spec) {
|
|
13160
|
+
this.spec = spec;
|
|
12650
13161
|
}
|
|
12651
|
-
|
|
12652
|
-
|
|
13162
|
+
async generate() {
|
|
13163
|
+
if (!this.spec) {
|
|
13164
|
+
throw new Error("Council spec not set");
|
|
13165
|
+
}
|
|
13166
|
+
return generateOpenCodeFiles(this.spec);
|
|
12653
13167
|
}
|
|
12654
|
-
|
|
12655
|
-
|
|
12656
|
-
await writeFile4(destPath, finalContent, "utf-8");
|
|
12657
|
-
return { src: srcPath, dest: destPath, action };
|
|
12658
|
-
} catch (e) {
|
|
12659
|
-
return { src: srcPath, dest: destPath, action: "error", error: String(e) };
|
|
13168
|
+
async isAvailable() {
|
|
13169
|
+
return true;
|
|
12660
13170
|
}
|
|
12661
13171
|
}
|
|
12662
|
-
|
|
13172
|
+
function createOpenCodeInstaller(spec) {
|
|
13173
|
+
const installer = new OpenCodeInstaller;
|
|
13174
|
+
installer.setSpec(spec);
|
|
13175
|
+
return installer;
|
|
13176
|
+
}
|
|
13177
|
+
|
|
13178
|
+
// src/core/filesystem/file-writer.ts
|
|
13179
|
+
import { access as access4, mkdir as mkdir4, writeFile as writeFile4 } from "node:fs/promises";
|
|
13180
|
+
import { dirname as dirname3 } from "node:path";
|
|
13181
|
+
init_safety();
|
|
13182
|
+
async function writeGeneratedFiles(files, options) {
|
|
12663
13183
|
const results = [];
|
|
12664
|
-
for (const
|
|
12665
|
-
|
|
12666
|
-
|
|
12667
|
-
|
|
12668
|
-
|
|
12669
|
-
|
|
12670
|
-
|
|
12671
|
-
|
|
12672
|
-
dest: entry.dest.replace(/^\.agents\/?/, "")
|
|
12673
|
-
};
|
|
13184
|
+
for (const file of files) {
|
|
13185
|
+
if (!validateWritePath(file.path)) {
|
|
13186
|
+
results.push({
|
|
13187
|
+
path: file.path,
|
|
13188
|
+
success: false,
|
|
13189
|
+
error: "Protected path"
|
|
13190
|
+
});
|
|
13191
|
+
continue;
|
|
12674
13192
|
}
|
|
12675
|
-
|
|
12676
|
-
|
|
12677
|
-
|
|
12678
|
-
|
|
13193
|
+
if (options.dryRun) {
|
|
13194
|
+
results.push({
|
|
13195
|
+
path: file.path,
|
|
13196
|
+
success: true
|
|
13197
|
+
});
|
|
13198
|
+
continue;
|
|
13199
|
+
}
|
|
13200
|
+
if (!options.force) {
|
|
13201
|
+
try {
|
|
13202
|
+
await access4(file.path);
|
|
13203
|
+
results.push({
|
|
13204
|
+
path: file.path,
|
|
13205
|
+
success: false,
|
|
13206
|
+
error: "File exists, use --force to overwrite"
|
|
13207
|
+
});
|
|
13208
|
+
continue;
|
|
13209
|
+
} catch {}
|
|
13210
|
+
}
|
|
13211
|
+
try {
|
|
13212
|
+
const dir = dirname3(file.path);
|
|
13213
|
+
await mkdir4(dir, { recursive: true });
|
|
13214
|
+
await writeFile4(file.path, file.content, "utf-8");
|
|
13215
|
+
results.push({
|
|
13216
|
+
path: file.path,
|
|
13217
|
+
success: true
|
|
13218
|
+
});
|
|
13219
|
+
} catch (error) {
|
|
13220
|
+
results.push({
|
|
13221
|
+
path: file.path,
|
|
13222
|
+
success: false,
|
|
13223
|
+
error: String(error)
|
|
13224
|
+
});
|
|
12679
13225
|
}
|
|
12680
13226
|
}
|
|
12681
13227
|
return results;
|
|
12682
13228
|
}
|
|
12683
13229
|
|
|
12684
|
-
// src/core/presets/manifest-loader.ts
|
|
12685
|
-
import { readFile as readFile5 } from "node:fs/promises";
|
|
12686
|
-
import { join as join3 } from "node:path";
|
|
12687
|
-
var MANIFESTS_DIR = join3(SRC_PRESETS_DIR, "manifests");
|
|
12688
|
-
var MODELS_DIR = join3(SRC_PRESETS_DIR, "models");
|
|
12689
|
-
var PRESETS_DIR = ROOT_PRESETS_DIR;
|
|
12690
|
-
async function loadManifest(target) {
|
|
12691
|
-
const manifestPath = join3(MANIFESTS_DIR, `${target}.yml`);
|
|
12692
|
-
const content = await readFile5(manifestPath, "utf-8");
|
|
12693
|
-
const data = $parse(content);
|
|
12694
|
-
return InstallManifestSchema.parse(data);
|
|
12695
|
-
}
|
|
12696
|
-
async function loadModelConfig(target) {
|
|
12697
|
-
const modelPath = join3(MODELS_DIR, `${target}.yml`);
|
|
12698
|
-
const content = await readFile5(modelPath, "utf-8");
|
|
12699
|
-
const data = $parse(content);
|
|
12700
|
-
return ModelConfigSchema.parse(data);
|
|
12701
|
-
}
|
|
12702
|
-
|
|
12703
13230
|
// src/core/presets/preset-loader.ts
|
|
12704
|
-
import { readFile as
|
|
12705
|
-
import { resolve as
|
|
13231
|
+
import { readFile as readFile7 } from "node:fs/promises";
|
|
13232
|
+
import { resolve as resolve7 } from "node:path";
|
|
12706
13233
|
async function loadPreset(name, projectRoot = process.cwd()) {
|
|
12707
13234
|
const candidates = [
|
|
12708
|
-
|
|
12709
|
-
|
|
13235
|
+
resolve7(projectRoot, ".codeconductor", "presets", `${name}.yml`),
|
|
13236
|
+
resolve7(SRC_PRESETS_DIR, name, `${name}.yml`)
|
|
12710
13237
|
];
|
|
12711
13238
|
for (const presetPath of candidates) {
|
|
12712
13239
|
try {
|
|
12713
|
-
const content = await
|
|
13240
|
+
const content = await readFile7(presetPath, "utf-8");
|
|
12714
13241
|
const data = $parse(content);
|
|
12715
13242
|
if (!data)
|
|
12716
13243
|
continue;
|
|
@@ -12754,7 +13281,7 @@ function getIndividualTargets(target) {
|
|
|
12754
13281
|
// src/commands/install.command.ts
|
|
12755
13282
|
async function installCommand(options) {
|
|
12756
13283
|
const { target, dryRun, force, global: isGlobal, output, projectRoot } = options;
|
|
12757
|
-
const baseDir = isGlobal ?
|
|
13284
|
+
const baseDir = isGlobal ? homedir5() : projectRoot;
|
|
12758
13285
|
try {
|
|
12759
13286
|
const runnerTarget = parseRunnerTarget(target);
|
|
12760
13287
|
const targets = getIndividualTargets(runnerTarget);
|
|
@@ -12790,7 +13317,7 @@ async function installCommand(options) {
|
|
|
12790
13317
|
const generatedFiles = await installer.generate();
|
|
12791
13318
|
const resolvedFiles = generatedFiles.map((f) => ({
|
|
12792
13319
|
...f,
|
|
12793
|
-
path:
|
|
13320
|
+
path: resolve8(baseDir, f.path)
|
|
12794
13321
|
}));
|
|
12795
13322
|
const results = await writeGeneratedFiles(resolvedFiles, writeOptions);
|
|
12796
13323
|
for (const result of results) {
|
|
@@ -12849,7 +13376,7 @@ async function installCommand(options) {
|
|
|
12849
13376
|
}
|
|
12850
13377
|
async function installPresetCommand(options) {
|
|
12851
13378
|
const { target, dryRun, force, global: isGlobal, projectRoot } = options;
|
|
12852
|
-
const baseDir = isGlobal ?
|
|
13379
|
+
const baseDir = isGlobal ? homedir5() : projectRoot;
|
|
12853
13380
|
try {
|
|
12854
13381
|
const runnerTarget = parseRunnerTarget(target);
|
|
12855
13382
|
const targets = getIndividualTargets(runnerTarget);
|
|
@@ -12899,8 +13426,8 @@ async function installPresetCommand(options) {
|
|
|
12899
13426
|
}
|
|
12900
13427
|
|
|
12901
13428
|
// src/commands/install-lsp.command.ts
|
|
12902
|
-
import { homedir as
|
|
12903
|
-
import { resolve as
|
|
13429
|
+
import { homedir as homedir7 } from "node:os";
|
|
13430
|
+
import { resolve as resolve9 } from "node:path";
|
|
12904
13431
|
|
|
12905
13432
|
// src/core/lsp/lsp-config-utils.ts
|
|
12906
13433
|
function getLanguageServerConfig(lspIds) {
|
|
@@ -13144,15 +13671,15 @@ function createOpenCodeLspGenerator() {
|
|
|
13144
13671
|
// src/core/lsp/lsp-installer.ts
|
|
13145
13672
|
import { execFile } from "node:child_process";
|
|
13146
13673
|
import { access as access5, mkdir as mkdir5 } from "node:fs/promises";
|
|
13147
|
-
import { homedir as
|
|
13148
|
-
import { join as
|
|
13674
|
+
import { homedir as homedir6 } from "node:os";
|
|
13675
|
+
import { join as join5 } from "node:path";
|
|
13149
13676
|
import { promisify } from "node:util";
|
|
13150
13677
|
var execFileAsync = promisify(execFile);
|
|
13151
13678
|
|
|
13152
13679
|
class LspInstaller {
|
|
13153
13680
|
lspBinDir;
|
|
13154
13681
|
constructor() {
|
|
13155
|
-
this.lspBinDir =
|
|
13682
|
+
this.lspBinDir = join5(homedir6(), ".codeconductor", "lsp", "bin");
|
|
13156
13683
|
}
|
|
13157
13684
|
async checkInstalled(def) {
|
|
13158
13685
|
try {
|
|
@@ -13279,7 +13806,7 @@ class LspInstaller {
|
|
|
13279
13806
|
throw new Error(`No binary available for platform: ${platformKey}`);
|
|
13280
13807
|
}
|
|
13281
13808
|
await mkdir5(this.lspBinDir, { recursive: true });
|
|
13282
|
-
const destPath =
|
|
13809
|
+
const destPath = join5(this.lspBinDir, def.binaryName);
|
|
13283
13810
|
try {
|
|
13284
13811
|
await access5(destPath);
|
|
13285
13812
|
return;
|
|
@@ -13386,7 +13913,7 @@ function resolveLsps(languages) {
|
|
|
13386
13913
|
// src/commands/install-lsp.command.ts
|
|
13387
13914
|
async function installLspCommand(options) {
|
|
13388
13915
|
const { target, lang, dryRun, force, global: isGlobal, output, projectRoot } = options;
|
|
13389
|
-
const baseDir = isGlobal ?
|
|
13916
|
+
const baseDir = isGlobal ? homedir7() : projectRoot;
|
|
13390
13917
|
try {
|
|
13391
13918
|
const runnerTarget = parseRunnerTarget(target);
|
|
13392
13919
|
const targets = getIndividualTargets(runnerTarget);
|
|
@@ -13432,7 +13959,7 @@ async function installLspCommand(options) {
|
|
|
13432
13959
|
const generatedFiles = generator.generate(installReport.results);
|
|
13433
13960
|
const resolvedFiles = generatedFiles.map((f) => ({
|
|
13434
13961
|
...f,
|
|
13435
|
-
path:
|
|
13962
|
+
path: resolve9(baseDir, f.path)
|
|
13436
13963
|
}));
|
|
13437
13964
|
const results = await writeGeneratedFiles(resolvedFiles, writeOptions);
|
|
13438
13965
|
for (const result of results) {
|
|
@@ -13526,7 +14053,7 @@ function getLspConfigGenerator(target) {
|
|
|
13526
14053
|
|
|
13527
14054
|
// src/commands/seo-audit.command.ts
|
|
13528
14055
|
import { writeFile as writeFile5, mkdir as mkdir6 } from "node:fs/promises";
|
|
13529
|
-
import { dirname as dirname4, resolve as
|
|
14056
|
+
import { dirname as dirname4, resolve as resolve10 } from "node:path";
|
|
13530
14057
|
|
|
13531
14058
|
// src/infrastructure/http/safe-fetch.ts
|
|
13532
14059
|
import { lookup } from "node:dns/promises";
|
|
@@ -13613,7 +14140,7 @@ async function safeFetch(urlString, options = {}) {
|
|
|
13613
14140
|
}
|
|
13614
14141
|
}
|
|
13615
14142
|
async function delay(ms) {
|
|
13616
|
-
return new Promise((
|
|
14143
|
+
return new Promise((resolve10) => setTimeout(resolve10, ms));
|
|
13617
14144
|
}
|
|
13618
14145
|
|
|
13619
14146
|
// src/infrastructure/parsers/sitemap-parser.ts
|
|
@@ -14817,12 +15344,12 @@ async function seoAuditCommand(options) {
|
|
|
14817
15344
|
formattedOutput = formatCli(report);
|
|
14818
15345
|
}
|
|
14819
15346
|
if (output) {
|
|
14820
|
-
const outputPath =
|
|
15347
|
+
const outputPath = resolve10(options.projectRoot, output);
|
|
14821
15348
|
await mkdir6(dirname4(outputPath), { recursive: true });
|
|
14822
15349
|
await writeFile5(outputPath, formattedOutput, "utf-8");
|
|
14823
15350
|
} else if (format === "markdown") {
|
|
14824
15351
|
const timestamp = new Date().toISOString().replace(/[:.]/g, "-").slice(0, 19);
|
|
14825
|
-
const defaultPath =
|
|
15352
|
+
const defaultPath = resolve10(options.projectRoot, "seo-reports", `audit-report-${timestamp}.md`);
|
|
14826
15353
|
await mkdir6(dirname4(defaultPath), { recursive: true });
|
|
14827
15354
|
await writeFile5(defaultPath, formattedOutput, "utf-8");
|
|
14828
15355
|
process.stderr.write(`Report saved to: ${defaultPath}
|
|
@@ -14836,7 +15363,7 @@ async function seoAuditCommand(options) {
|
|
|
14836
15363
|
command: "seo audit",
|
|
14837
15364
|
report,
|
|
14838
15365
|
output: formattedOutput,
|
|
14839
|
-
outputFile: output ?
|
|
15366
|
+
outputFile: output ? resolve10(options.projectRoot, output) : format === "markdown" ? resolve10(options.projectRoot, "seo-reports") : undefined
|
|
14840
15367
|
}
|
|
14841
15368
|
};
|
|
14842
15369
|
} catch (error) {
|
|
@@ -14853,7 +15380,7 @@ async function seoAuditCommand(options) {
|
|
|
14853
15380
|
|
|
14854
15381
|
// src/commands/seo-llms.command.ts
|
|
14855
15382
|
import { writeFile as writeFile6, mkdir as mkdir7 } from "node:fs/promises";
|
|
14856
|
-
import { dirname as dirname5, resolve as
|
|
15383
|
+
import { dirname as dirname5, resolve as resolve11 } from "node:path";
|
|
14857
15384
|
|
|
14858
15385
|
// src/domain/seo/llms-generator.ts
|
|
14859
15386
|
function extractTitle2(html) {
|
|
@@ -14996,7 +15523,7 @@ async function seoLlmsCommand(options) {
|
|
|
14996
15523
|
}
|
|
14997
15524
|
}) : await generateLlmsTxtFromUrl(url);
|
|
14998
15525
|
process.stderr.write("\r" + " ".repeat(80) + "\r");
|
|
14999
|
-
const outputPath = output ?
|
|
15526
|
+
const outputPath = output ? resolve11(options.projectRoot, output) : resolve11(options.projectRoot, "llms.txt");
|
|
15000
15527
|
await mkdir7(dirname5(outputPath), { recursive: true });
|
|
15001
15528
|
await writeFile6(outputPath, result.content, "utf-8");
|
|
15002
15529
|
process.stderr.write(`Generated: ${outputPath} (${result.entries.length} entries)
|
|
@@ -15024,10 +15551,14 @@ async function seoLlmsCommand(options) {
|
|
|
15024
15551
|
}
|
|
15025
15552
|
|
|
15026
15553
|
// src/commands/update.command.ts
|
|
15554
|
+
import { homedir as homedir8 } from "node:os";
|
|
15555
|
+
import { resolve as resolve12, dirname as dirname6 } from "node:path";
|
|
15556
|
+
import { mkdir as mkdir8, readFile as readFile8, writeFile as writeFile7, stat as stat3 } from "node:fs/promises";
|
|
15027
15557
|
async function updateCommand(options) {
|
|
15028
|
-
const { dryRun, force, output, projectRoot } = options;
|
|
15558
|
+
const { dryRun, force, global: isGlobal, output, projectRoot } = options;
|
|
15559
|
+
const basePath = isGlobal ? homedir8() : projectRoot;
|
|
15029
15560
|
try {
|
|
15030
|
-
const configResult = await loadConfig(
|
|
15561
|
+
const configResult = await loadConfig(basePath);
|
|
15031
15562
|
if (!configResult.success) {
|
|
15032
15563
|
return {
|
|
15033
15564
|
code: 1,
|
|
@@ -15039,42 +15570,40 @@ async function updateCommand(options) {
|
|
|
15039
15570
|
};
|
|
15040
15571
|
}
|
|
15041
15572
|
const config = configResult.data;
|
|
15042
|
-
|
|
15043
|
-
|
|
15044
|
-
|
|
15045
|
-
|
|
15046
|
-
|
|
15047
|
-
|
|
15048
|
-
errors: ["Council preset is not enabled"]
|
|
15049
|
-
}
|
|
15050
|
-
};
|
|
15051
|
-
}
|
|
15052
|
-
const presetResult = await loadCouncilPreset(projectRoot);
|
|
15053
|
-
if (!presetResult.success) {
|
|
15054
|
-
return {
|
|
15055
|
-
code: 1,
|
|
15056
|
-
data: {
|
|
15057
|
-
success: false,
|
|
15058
|
-
command: "update",
|
|
15059
|
-
errors: ["Failed to load preset"]
|
|
15060
|
-
}
|
|
15061
|
-
};
|
|
15573
|
+
const updateResults = await checkUpdates(basePath, isGlobal);
|
|
15574
|
+
const largeFiles = await validateAgentFileSizes(basePath, isGlobal);
|
|
15575
|
+
if (largeFiles.length > 0) {
|
|
15576
|
+
largeFiles.forEach((file) => {
|
|
15577
|
+
console.warn(`[WARNING] File exceeds 40KB: ${file.path} (${(file.size / 1024).toFixed(1)} KB)`);
|
|
15578
|
+
});
|
|
15062
15579
|
}
|
|
15063
|
-
|
|
15064
|
-
const currentVersion = config.presets.council.version;
|
|
15065
|
-
const newVersion = spec.version;
|
|
15066
|
-
if (currentVersion === newVersion) {
|
|
15580
|
+
if (!updateResults.hasUpdates) {
|
|
15067
15581
|
return {
|
|
15068
15582
|
code: 0,
|
|
15069
15583
|
data: {
|
|
15070
15584
|
success: true,
|
|
15071
15585
|
command: "update",
|
|
15072
15586
|
message: "Already up to date",
|
|
15073
|
-
|
|
15074
|
-
|
|
15587
|
+
wouldUpdate: [],
|
|
15588
|
+
updated: []
|
|
15075
15589
|
}
|
|
15076
15590
|
};
|
|
15077
15591
|
}
|
|
15592
|
+
const wouldUpdate = [];
|
|
15593
|
+
if (updateResults.council)
|
|
15594
|
+
wouldUpdate.push("council preset");
|
|
15595
|
+
if (updateResults.policy)
|
|
15596
|
+
wouldUpdate.push("policy file");
|
|
15597
|
+
for (const t of updateResults.targets) {
|
|
15598
|
+
if (t.hasUpdate) {
|
|
15599
|
+
wouldUpdate.push(`${t.target} target files`);
|
|
15600
|
+
}
|
|
15601
|
+
}
|
|
15602
|
+
for (const s of updateResults.skills) {
|
|
15603
|
+
if (s.hasUpdate) {
|
|
15604
|
+
wouldUpdate.push(`skill ${s.id} to v${s.latestVersion}`);
|
|
15605
|
+
}
|
|
15606
|
+
}
|
|
15078
15607
|
if (dryRun) {
|
|
15079
15608
|
return {
|
|
15080
15609
|
code: 0,
|
|
@@ -15082,48 +15611,77 @@ async function updateCommand(options) {
|
|
|
15082
15611
|
success: true,
|
|
15083
15612
|
command: "update",
|
|
15084
15613
|
message: "Dry run - would update",
|
|
15085
|
-
|
|
15086
|
-
|
|
15087
|
-
wouldUpdate: ["council preset files"]
|
|
15614
|
+
wouldUpdate,
|
|
15615
|
+
updated: []
|
|
15088
15616
|
}
|
|
15089
15617
|
};
|
|
15090
15618
|
}
|
|
15091
|
-
const
|
|
15092
|
-
|
|
15093
|
-
|
|
15094
|
-
|
|
15095
|
-
|
|
15096
|
-
|
|
15097
|
-
|
|
15098
|
-
|
|
15099
|
-
|
|
15100
|
-
|
|
15101
|
-
|
|
15102
|
-
|
|
15103
|
-
|
|
15104
|
-
|
|
15105
|
-
|
|
15106
|
-
|
|
15107
|
-
|
|
15108
|
-
|
|
15109
|
-
|
|
15110
|
-
|
|
15619
|
+
const updated = [];
|
|
15620
|
+
if (updateResults.council) {
|
|
15621
|
+
const localCouncil = resolve12(basePath, ".codeconductor", "presets", "council.yml");
|
|
15622
|
+
const bundledCouncil = resolve12(SRC_PRESETS_DIR, "council", "council.yml");
|
|
15623
|
+
try {
|
|
15624
|
+
const content = await readFile8(bundledCouncil, "utf-8");
|
|
15625
|
+
await mkdir8(dirname6(localCouncil), { recursive: true });
|
|
15626
|
+
await writeFile7(localCouncil, content, "utf-8");
|
|
15627
|
+
updated.push(localCouncil);
|
|
15628
|
+
} catch (e) {
|
|
15629
|
+
throw new Error(`Failed to update council.yml: ${e}`);
|
|
15630
|
+
}
|
|
15631
|
+
}
|
|
15632
|
+
if (updateResults.policy) {
|
|
15633
|
+
const localPolicy = resolve12(basePath, ".codeconductor", "presets", "policy.yml");
|
|
15634
|
+
try {
|
|
15635
|
+
const content = await readFile8(POLICY_PATH, "utf-8");
|
|
15636
|
+
await mkdir8(dirname6(localPolicy), { recursive: true });
|
|
15637
|
+
await writeFile7(localPolicy, content, "utf-8");
|
|
15638
|
+
updated.push(localPolicy);
|
|
15639
|
+
} catch (e) {
|
|
15640
|
+
throw new Error(`Failed to update policy.yml: ${e}`);
|
|
15641
|
+
}
|
|
15642
|
+
}
|
|
15643
|
+
const locale = config?.defaults?.locale ?? "en";
|
|
15644
|
+
for (const t of updateResults.targets) {
|
|
15645
|
+
if (t.hasUpdate) {
|
|
15646
|
+
const targetName = t.target;
|
|
15647
|
+
const manifest = await loadManifest(targetName);
|
|
15648
|
+
const modelConfig = await loadModelConfig(targetName);
|
|
15649
|
+
const results = await copyFromManifest(manifest, PRESETS_DIR, basePath, isGlobal, false, force, modelConfig, locale);
|
|
15650
|
+
for (const r of results) {
|
|
15651
|
+
if (r.action !== "skipped" && r.action !== "error") {
|
|
15652
|
+
updated.push(r.dest);
|
|
15653
|
+
} else if (r.action === "error") {
|
|
15654
|
+
throw new Error(`Failed to copy target file: ${r.error}`);
|
|
15111
15655
|
}
|
|
15112
|
-
}
|
|
15656
|
+
}
|
|
15657
|
+
}
|
|
15113
15658
|
}
|
|
15114
|
-
|
|
15115
|
-
|
|
15116
|
-
|
|
15117
|
-
|
|
15118
|
-
|
|
15119
|
-
|
|
15120
|
-
|
|
15121
|
-
|
|
15122
|
-
|
|
15123
|
-
|
|
15124
|
-
|
|
15659
|
+
if (updateResults.skills.some((s) => s.hasUpdate)) {
|
|
15660
|
+
const newSkillsLock = {};
|
|
15661
|
+
const currentLock = await loadSkillsLock(basePath) || {};
|
|
15662
|
+
for (const [id, ver] of Object.entries(currentLock)) {
|
|
15663
|
+
newSkillsLock[id] = ver;
|
|
15664
|
+
}
|
|
15665
|
+
for (const s of updateResults.skills) {
|
|
15666
|
+
newSkillsLock[s.id] = s.latestVersion;
|
|
15667
|
+
}
|
|
15668
|
+
let lockDest = resolve12(basePath, ".codeconductor", "skills-lock.json");
|
|
15669
|
+
try {
|
|
15670
|
+
const statAgents = await stat3(resolve12(basePath, ".agents"));
|
|
15671
|
+
if (statAgents.isDirectory()) {
|
|
15672
|
+
const statCodeConductor = await stat3(resolve12(basePath, ".codeconductor")).catch(() => null);
|
|
15673
|
+
if (!statCodeConductor) {
|
|
15674
|
+
lockDest = resolve12(basePath, ".agents", "skills-lock.json");
|
|
15675
|
+
}
|
|
15125
15676
|
}
|
|
15126
|
-
}
|
|
15677
|
+
} catch {}
|
|
15678
|
+
try {
|
|
15679
|
+
await mkdir8(dirname6(lockDest), { recursive: true });
|
|
15680
|
+
await writeFile7(lockDest, JSON.stringify(newSkillsLock, null, 2), "utf-8");
|
|
15681
|
+
updated.push(lockDest);
|
|
15682
|
+
} catch (e) {
|
|
15683
|
+
throw new Error(`Failed to write skills-lock.json: ${e}`);
|
|
15684
|
+
}
|
|
15127
15685
|
}
|
|
15128
15686
|
return {
|
|
15129
15687
|
code: 0,
|
|
@@ -15131,8 +15689,7 @@ async function updateCommand(options) {
|
|
|
15131
15689
|
success: true,
|
|
15132
15690
|
command: "update",
|
|
15133
15691
|
message: "Updated successfully",
|
|
15134
|
-
|
|
15135
|
-
newVersion,
|
|
15692
|
+
wouldUpdate: [],
|
|
15136
15693
|
updated
|
|
15137
15694
|
}
|
|
15138
15695
|
};
|
|
@@ -15337,6 +15894,7 @@ async function routeCommand(args, projectRoot) {
|
|
|
15337
15894
|
projectRoot,
|
|
15338
15895
|
dryRun: flags.dryRun,
|
|
15339
15896
|
force: flags.force,
|
|
15897
|
+
global: options.global === true || options.global === "true",
|
|
15340
15898
|
output: flags.output
|
|
15341
15899
|
});
|
|
15342
15900
|
case "seo": {
|