@corenel/cli 0.1.1 → 0.2.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/dist/cli.js +606 -72
- package/package.json +2 -1
package/dist/cli.js
CHANGED
|
@@ -1500,7 +1500,7 @@ var require_stringify = __commonJS({
|
|
|
1500
1500
|
props.push(doc.directives.tagString(tag));
|
|
1501
1501
|
return props.join(" ");
|
|
1502
1502
|
}
|
|
1503
|
-
function
|
|
1503
|
+
function stringify3(item, ctx, onComment, onChompKeep) {
|
|
1504
1504
|
if (identity.isPair(item))
|
|
1505
1505
|
return item.toString(ctx, onComment, onChompKeep);
|
|
1506
1506
|
if (identity.isAlias(item)) {
|
|
@@ -1529,7 +1529,7 @@ var require_stringify = __commonJS({
|
|
|
1529
1529
|
${ctx.indent}${str5}`;
|
|
1530
1530
|
}
|
|
1531
1531
|
exports.createStringifyContext = createStringifyContext;
|
|
1532
|
-
exports.stringify =
|
|
1532
|
+
exports.stringify = stringify3;
|
|
1533
1533
|
}
|
|
1534
1534
|
});
|
|
1535
1535
|
|
|
@@ -1539,7 +1539,7 @@ var require_stringifyPair = __commonJS({
|
|
|
1539
1539
|
"use strict";
|
|
1540
1540
|
var identity = require_identity();
|
|
1541
1541
|
var Scalar = require_Scalar();
|
|
1542
|
-
var
|
|
1542
|
+
var stringify3 = require_stringify();
|
|
1543
1543
|
var stringifyComment = require_stringifyComment();
|
|
1544
1544
|
function stringifyPair({ key, value }, ctx, onComment, onChompKeep) {
|
|
1545
1545
|
const { allNullValues, doc, indent, indentStep, options: { commentString, indentSeq, simpleKeys } } = ctx;
|
|
@@ -1561,7 +1561,7 @@ var require_stringifyPair = __commonJS({
|
|
|
1561
1561
|
});
|
|
1562
1562
|
let keyCommentDone = false;
|
|
1563
1563
|
let chompKeep = false;
|
|
1564
|
-
let str5 =
|
|
1564
|
+
let str5 = stringify3.stringify(key, ctx, () => keyCommentDone = true, () => chompKeep = true);
|
|
1565
1565
|
if (!explicitKey && !ctx.inFlow && str5.length > 1024) {
|
|
1566
1566
|
if (simpleKeys)
|
|
1567
1567
|
throw new Error("With simple keys, single line scalar must not span more than 1024 characters");
|
|
@@ -1613,7 +1613,7 @@ ${indent}:`;
|
|
|
1613
1613
|
ctx.indent = ctx.indent.substring(2);
|
|
1614
1614
|
}
|
|
1615
1615
|
let valueCommentDone = false;
|
|
1616
|
-
const valueStr =
|
|
1616
|
+
const valueStr = stringify3.stringify(value, ctx, () => valueCommentDone = true, () => chompKeep = true);
|
|
1617
1617
|
let ws = " ";
|
|
1618
1618
|
if (keyComment || vsb || vcb) {
|
|
1619
1619
|
ws = vsb ? "\n" : "";
|
|
@@ -1754,7 +1754,7 @@ var require_addPairToJSMap = __commonJS({
|
|
|
1754
1754
|
"use strict";
|
|
1755
1755
|
var log = require_log();
|
|
1756
1756
|
var merge = require_merge();
|
|
1757
|
-
var
|
|
1757
|
+
var stringify3 = require_stringify();
|
|
1758
1758
|
var identity = require_identity();
|
|
1759
1759
|
var toJS = require_toJS();
|
|
1760
1760
|
function addPairToJSMap(ctx, map, { key, value }) {
|
|
@@ -1790,7 +1790,7 @@ var require_addPairToJSMap = __commonJS({
|
|
|
1790
1790
|
if (typeof jsKey !== "object")
|
|
1791
1791
|
return String(jsKey);
|
|
1792
1792
|
if (identity.isNode(key) && ctx?.doc) {
|
|
1793
|
-
const strCtx =
|
|
1793
|
+
const strCtx = stringify3.createStringifyContext(ctx.doc, {});
|
|
1794
1794
|
strCtx.anchors = /* @__PURE__ */ new Set();
|
|
1795
1795
|
for (const node of ctx.anchors.keys())
|
|
1796
1796
|
strCtx.anchors.add(node.anchor);
|
|
@@ -1857,12 +1857,12 @@ var require_stringifyCollection = __commonJS({
|
|
|
1857
1857
|
"../../node_modules/.pnpm/yaml@2.9.0/node_modules/yaml/dist/stringify/stringifyCollection.js"(exports) {
|
|
1858
1858
|
"use strict";
|
|
1859
1859
|
var identity = require_identity();
|
|
1860
|
-
var
|
|
1860
|
+
var stringify3 = require_stringify();
|
|
1861
1861
|
var stringifyComment = require_stringifyComment();
|
|
1862
1862
|
function stringifyCollection(collection, ctx, options) {
|
|
1863
1863
|
const flow = ctx.inFlow ?? collection.flow;
|
|
1864
|
-
const
|
|
1865
|
-
return
|
|
1864
|
+
const stringify4 = flow ? stringifyFlowCollection : stringifyBlockCollection;
|
|
1865
|
+
return stringify4(collection, ctx, options);
|
|
1866
1866
|
}
|
|
1867
1867
|
function stringifyBlockCollection({ comment, items }, ctx, { blockItemPrefix, flowChars, itemIndent, onChompKeep, onComment }) {
|
|
1868
1868
|
const { indent, options: { commentString } } = ctx;
|
|
@@ -1887,7 +1887,7 @@ var require_stringifyCollection = __commonJS({
|
|
|
1887
1887
|
}
|
|
1888
1888
|
}
|
|
1889
1889
|
chompKeep = false;
|
|
1890
|
-
let str6 =
|
|
1890
|
+
let str6 = stringify3.stringify(item, itemCtx, () => comment2 = null, () => chompKeep = true);
|
|
1891
1891
|
if (comment2)
|
|
1892
1892
|
str6 += stringifyComment.lineComment(str6, itemIndent, commentString(comment2));
|
|
1893
1893
|
if (chompKeep && comment2)
|
|
@@ -1954,7 +1954,7 @@ ${indent}${line}` : "\n";
|
|
|
1954
1954
|
}
|
|
1955
1955
|
if (comment)
|
|
1956
1956
|
reqNewline = true;
|
|
1957
|
-
let str5 =
|
|
1957
|
+
let str5 = stringify3.stringify(item, itemCtx, () => comment = null);
|
|
1958
1958
|
reqNewline || (reqNewline = lines.length > linesAtValue || str5.includes("\n"));
|
|
1959
1959
|
if (i < items.length - 1) {
|
|
1960
1960
|
str5 += ",";
|
|
@@ -3315,7 +3315,7 @@ var require_stringifyDocument = __commonJS({
|
|
|
3315
3315
|
"../../node_modules/.pnpm/yaml@2.9.0/node_modules/yaml/dist/stringify/stringifyDocument.js"(exports) {
|
|
3316
3316
|
"use strict";
|
|
3317
3317
|
var identity = require_identity();
|
|
3318
|
-
var
|
|
3318
|
+
var stringify3 = require_stringify();
|
|
3319
3319
|
var stringifyComment = require_stringifyComment();
|
|
3320
3320
|
function stringifyDocument(doc, options) {
|
|
3321
3321
|
const lines = [];
|
|
@@ -3330,7 +3330,7 @@ var require_stringifyDocument = __commonJS({
|
|
|
3330
3330
|
}
|
|
3331
3331
|
if (hasDirectives)
|
|
3332
3332
|
lines.push("---");
|
|
3333
|
-
const ctx =
|
|
3333
|
+
const ctx = stringify3.createStringifyContext(doc, options);
|
|
3334
3334
|
const { commentString } = ctx.options;
|
|
3335
3335
|
if (doc.commentBefore) {
|
|
3336
3336
|
if (lines.length !== 1)
|
|
@@ -3352,7 +3352,7 @@ var require_stringifyDocument = __commonJS({
|
|
|
3352
3352
|
contentComment = doc.contents.comment;
|
|
3353
3353
|
}
|
|
3354
3354
|
const onChompKeep = contentComment ? void 0 : () => chompKeep = true;
|
|
3355
|
-
let body =
|
|
3355
|
+
let body = stringify3.stringify(doc.contents, ctx, () => contentComment = null, onChompKeep);
|
|
3356
3356
|
if (contentComment)
|
|
3357
3357
|
body += stringifyComment.lineComment(body, "", commentString(contentComment));
|
|
3358
3358
|
if ((body[0] === "|" || body[0] === ">") && lines[lines.length - 1] === "---") {
|
|
@@ -3360,7 +3360,7 @@ var require_stringifyDocument = __commonJS({
|
|
|
3360
3360
|
} else
|
|
3361
3361
|
lines.push(body);
|
|
3362
3362
|
} else {
|
|
3363
|
-
lines.push(
|
|
3363
|
+
lines.push(stringify3.stringify(doc.contents, ctx));
|
|
3364
3364
|
}
|
|
3365
3365
|
if (doc.directives?.docEnd) {
|
|
3366
3366
|
if (doc.comment) {
|
|
@@ -5490,7 +5490,7 @@ var require_cst_scalar = __commonJS({
|
|
|
5490
5490
|
var require_cst_stringify = __commonJS({
|
|
5491
5491
|
"../../node_modules/.pnpm/yaml@2.9.0/node_modules/yaml/dist/parse/cst-stringify.js"(exports) {
|
|
5492
5492
|
"use strict";
|
|
5493
|
-
var
|
|
5493
|
+
var stringify3 = (cst) => "type" in cst ? stringifyToken(cst) : stringifyItem(cst);
|
|
5494
5494
|
function stringifyToken(token) {
|
|
5495
5495
|
switch (token.type) {
|
|
5496
5496
|
case "block-scalar": {
|
|
@@ -5543,7 +5543,7 @@ var require_cst_stringify = __commonJS({
|
|
|
5543
5543
|
res += stringifyToken(value);
|
|
5544
5544
|
return res;
|
|
5545
5545
|
}
|
|
5546
|
-
exports.stringify =
|
|
5546
|
+
exports.stringify = stringify3;
|
|
5547
5547
|
}
|
|
5548
5548
|
});
|
|
5549
5549
|
|
|
@@ -7245,7 +7245,7 @@ var require_public_api = __commonJS({
|
|
|
7245
7245
|
}
|
|
7246
7246
|
return doc;
|
|
7247
7247
|
}
|
|
7248
|
-
function
|
|
7248
|
+
function parse3(src, reviver, options) {
|
|
7249
7249
|
let _reviver = void 0;
|
|
7250
7250
|
if (typeof reviver === "function") {
|
|
7251
7251
|
_reviver = reviver;
|
|
@@ -7264,7 +7264,7 @@ var require_public_api = __commonJS({
|
|
|
7264
7264
|
}
|
|
7265
7265
|
return doc.toJS(Object.assign({ reviver: _reviver }, options));
|
|
7266
7266
|
}
|
|
7267
|
-
function
|
|
7267
|
+
function stringify3(value, replacer, options) {
|
|
7268
7268
|
let _replacer = null;
|
|
7269
7269
|
if (typeof replacer === "function" || Array.isArray(replacer)) {
|
|
7270
7270
|
_replacer = replacer;
|
|
@@ -7286,10 +7286,10 @@ var require_public_api = __commonJS({
|
|
|
7286
7286
|
return value.toString(options);
|
|
7287
7287
|
return new Document.Document(value, _replacer, options).toString(options);
|
|
7288
7288
|
}
|
|
7289
|
-
exports.parse =
|
|
7289
|
+
exports.parse = parse3;
|
|
7290
7290
|
exports.parseAllDocuments = parseAllDocuments;
|
|
7291
7291
|
exports.parseDocument = parseDocument;
|
|
7292
|
-
exports.stringify =
|
|
7292
|
+
exports.stringify = stringify3;
|
|
7293
7293
|
}
|
|
7294
7294
|
});
|
|
7295
7295
|
|
|
@@ -7812,7 +7812,7 @@ var require_parse = __commonJS({
|
|
|
7812
7812
|
"../../node_modules/.pnpm/semver@7.8.5/node_modules/semver/functions/parse.js"(exports, module) {
|
|
7813
7813
|
"use strict";
|
|
7814
7814
|
var SemVer = require_semver();
|
|
7815
|
-
var
|
|
7815
|
+
var parse3 = (version, options, throwErrors = false) => {
|
|
7816
7816
|
if (version instanceof SemVer) {
|
|
7817
7817
|
return version;
|
|
7818
7818
|
}
|
|
@@ -7825,7 +7825,7 @@ var require_parse = __commonJS({
|
|
|
7825
7825
|
throw er;
|
|
7826
7826
|
}
|
|
7827
7827
|
};
|
|
7828
|
-
module.exports =
|
|
7828
|
+
module.exports = parse3;
|
|
7829
7829
|
}
|
|
7830
7830
|
});
|
|
7831
7831
|
|
|
@@ -7833,9 +7833,9 @@ var require_parse = __commonJS({
|
|
|
7833
7833
|
var require_valid = __commonJS({
|
|
7834
7834
|
"../../node_modules/.pnpm/semver@7.8.5/node_modules/semver/functions/valid.js"(exports, module) {
|
|
7835
7835
|
"use strict";
|
|
7836
|
-
var
|
|
7836
|
+
var parse3 = require_parse();
|
|
7837
7837
|
var valid = (version, options) => {
|
|
7838
|
-
const v =
|
|
7838
|
+
const v = parse3(version, options);
|
|
7839
7839
|
return v ? v.version : null;
|
|
7840
7840
|
};
|
|
7841
7841
|
module.exports = valid;
|
|
@@ -7846,9 +7846,9 @@ var require_valid = __commonJS({
|
|
|
7846
7846
|
var require_clean = __commonJS({
|
|
7847
7847
|
"../../node_modules/.pnpm/semver@7.8.5/node_modules/semver/functions/clean.js"(exports, module) {
|
|
7848
7848
|
"use strict";
|
|
7849
|
-
var
|
|
7849
|
+
var parse3 = require_parse();
|
|
7850
7850
|
var clean = (version, options) => {
|
|
7851
|
-
const s =
|
|
7851
|
+
const s = parse3(version.trim().replace(/^[=v]+/, ""), options);
|
|
7852
7852
|
return s ? s.version : null;
|
|
7853
7853
|
};
|
|
7854
7854
|
module.exports = clean;
|
|
@@ -7883,10 +7883,10 @@ var require_inc = __commonJS({
|
|
|
7883
7883
|
var require_diff = __commonJS({
|
|
7884
7884
|
"../../node_modules/.pnpm/semver@7.8.5/node_modules/semver/functions/diff.js"(exports, module) {
|
|
7885
7885
|
"use strict";
|
|
7886
|
-
var
|
|
7886
|
+
var parse3 = require_parse();
|
|
7887
7887
|
var diff = (version1, version2) => {
|
|
7888
|
-
const v1 =
|
|
7889
|
-
const v2 =
|
|
7888
|
+
const v1 = parse3(version1, null, true);
|
|
7889
|
+
const v2 = parse3(version2, null, true);
|
|
7890
7890
|
const comparison = v1.compare(v2);
|
|
7891
7891
|
if (comparison === 0) {
|
|
7892
7892
|
return null;
|
|
@@ -7957,9 +7957,9 @@ var require_patch = __commonJS({
|
|
|
7957
7957
|
var require_prerelease = __commonJS({
|
|
7958
7958
|
"../../node_modules/.pnpm/semver@7.8.5/node_modules/semver/functions/prerelease.js"(exports, module) {
|
|
7959
7959
|
"use strict";
|
|
7960
|
-
var
|
|
7960
|
+
var parse3 = require_parse();
|
|
7961
7961
|
var prerelease = (version, options) => {
|
|
7962
|
-
const parsed =
|
|
7962
|
+
const parsed = parse3(version, options);
|
|
7963
7963
|
return parsed && parsed.prerelease.length ? parsed.prerelease : null;
|
|
7964
7964
|
};
|
|
7965
7965
|
module.exports = prerelease;
|
|
@@ -8145,7 +8145,7 @@ var require_coerce = __commonJS({
|
|
|
8145
8145
|
"../../node_modules/.pnpm/semver@7.8.5/node_modules/semver/functions/coerce.js"(exports, module) {
|
|
8146
8146
|
"use strict";
|
|
8147
8147
|
var SemVer = require_semver();
|
|
8148
|
-
var
|
|
8148
|
+
var parse3 = require_parse();
|
|
8149
8149
|
var { safeRe: re, t } = require_re();
|
|
8150
8150
|
var coerce = (version, options) => {
|
|
8151
8151
|
if (version instanceof SemVer) {
|
|
@@ -8180,7 +8180,7 @@ var require_coerce = __commonJS({
|
|
|
8180
8180
|
const patch = match[4] || "0";
|
|
8181
8181
|
const prerelease = options.includePrerelease && match[5] ? `-${match[5]}` : "";
|
|
8182
8182
|
const build = options.includePrerelease && match[6] ? `+${match[6]}` : "";
|
|
8183
|
-
return
|
|
8183
|
+
return parse3(`${major}.${minor}.${patch}${prerelease}${build}`, options);
|
|
8184
8184
|
};
|
|
8185
8185
|
module.exports = coerce;
|
|
8186
8186
|
}
|
|
@@ -8190,7 +8190,7 @@ var require_coerce = __commonJS({
|
|
|
8190
8190
|
var require_truncate = __commonJS({
|
|
8191
8191
|
"../../node_modules/.pnpm/semver@7.8.5/node_modules/semver/functions/truncate.js"(exports, module) {
|
|
8192
8192
|
"use strict";
|
|
8193
|
-
var
|
|
8193
|
+
var parse3 = require_parse();
|
|
8194
8194
|
var constants = require_constants();
|
|
8195
8195
|
var SemVer = require_semver();
|
|
8196
8196
|
var truncate = (version, truncation, options) => {
|
|
@@ -8202,7 +8202,7 @@ var require_truncate = __commonJS({
|
|
|
8202
8202
|
};
|
|
8203
8203
|
var cloneInputVersion = (version, options) => {
|
|
8204
8204
|
const versionStringToParse = version instanceof SemVer ? version.version : version;
|
|
8205
|
-
return
|
|
8205
|
+
return parse3(versionStringToParse, options);
|
|
8206
8206
|
};
|
|
8207
8207
|
var doTruncation = (version, truncation) => {
|
|
8208
8208
|
if (isPrerelease(truncation)) {
|
|
@@ -9244,7 +9244,7 @@ var require_semver2 = __commonJS({
|
|
|
9244
9244
|
var constants = require_constants();
|
|
9245
9245
|
var SemVer = require_semver();
|
|
9246
9246
|
var identifiers = require_identifiers();
|
|
9247
|
-
var
|
|
9247
|
+
var parse3 = require_parse();
|
|
9248
9248
|
var valid = require_valid();
|
|
9249
9249
|
var clean = require_clean();
|
|
9250
9250
|
var inc = require_inc();
|
|
@@ -9283,7 +9283,7 @@ var require_semver2 = __commonJS({
|
|
|
9283
9283
|
var simplifyRange = require_simplify();
|
|
9284
9284
|
var subset = require_subset();
|
|
9285
9285
|
module.exports = {
|
|
9286
|
-
parse:
|
|
9286
|
+
parse: parse3,
|
|
9287
9287
|
valid,
|
|
9288
9288
|
clean,
|
|
9289
9289
|
inc,
|
|
@@ -11670,7 +11670,7 @@ var require_parser2 = __commonJS({
|
|
|
11670
11670
|
}
|
|
11671
11671
|
return buf;
|
|
11672
11672
|
};
|
|
11673
|
-
_proto.parse = function
|
|
11673
|
+
_proto.parse = function parse3() {
|
|
11674
11674
|
return new nodes.NodeList(0, 0, this.parseNodes());
|
|
11675
11675
|
};
|
|
11676
11676
|
_proto.parseAsRoot = function parseAsRoot() {
|
|
@@ -11679,7 +11679,7 @@ var require_parser2 = __commonJS({
|
|
|
11679
11679
|
return Parser2;
|
|
11680
11680
|
}(Obj);
|
|
11681
11681
|
module.exports = {
|
|
11682
|
-
parse: function
|
|
11682
|
+
parse: function parse3(src, extensions, opts) {
|
|
11683
11683
|
var p = new Parser(lexer.lex(src, opts));
|
|
11684
11684
|
if (extensions !== void 0) {
|
|
11685
11685
|
p.extensions = extensions;
|
|
@@ -15074,10 +15074,21 @@ async function streamCompletion(client, params, signal, onText) {
|
|
|
15074
15074
|
messages: params.messages,
|
|
15075
15075
|
tools: params.tools,
|
|
15076
15076
|
tool_choice: params.tool_choice,
|
|
15077
|
+
// Undefined is dropped by the SDK's JSON serialization, so an unset cap
|
|
15078
|
+
// leaves output unbounded (unchanged behavior).
|
|
15079
|
+
max_completion_tokens: params.max_completion_tokens,
|
|
15080
|
+
// Undefined is dropped by the SDK, so an unset temperature leaves the
|
|
15081
|
+
// provider default in place (unchanged behavior).
|
|
15082
|
+
temperature: params.temperature,
|
|
15077
15083
|
stream: true,
|
|
15078
15084
|
stream_options: { include_usage: true }
|
|
15079
15085
|
},
|
|
15080
|
-
|
|
15086
|
+
// The agent loop (loop.ts) is the SOLE retry authority — it owns the bounded
|
|
15087
|
+
// backoff retry for transient failures. Disable the OpenAI SDK's own retries
|
|
15088
|
+
// (default 2) so they don't MULTIPLY with the loop's: a gateway timeout was
|
|
15089
|
+
// being retried SDK(1+2) x loop(1+3) = ~12 times, turning one 300s timeout
|
|
15090
|
+
// into ~12 minutes of dead attempts.
|
|
15091
|
+
{ signal, maxRetries: 0 }
|
|
15081
15092
|
);
|
|
15082
15093
|
} catch (e) {
|
|
15083
15094
|
const err = e;
|
|
@@ -15119,7 +15130,7 @@ async function streamCompletion(client, params, signal, onText) {
|
|
|
15119
15130
|
alog("stream:end", { chunks: chunkN, contentLen: content.length, toolCalls: toolCalls.length, finishReason, usage });
|
|
15120
15131
|
return { content, toolCalls, usage, finishReason };
|
|
15121
15132
|
}
|
|
15122
|
-
function createChatClient(auth) {
|
|
15133
|
+
function createChatClient(auth, opts = {}) {
|
|
15123
15134
|
return new OpenAI({
|
|
15124
15135
|
baseURL: gatewayBaseURL(),
|
|
15125
15136
|
// Real key lives server-side; this placeholder is replaced per-request by the
|
|
@@ -15132,6 +15143,7 @@ function createChatClient(auth) {
|
|
|
15132
15143
|
const token = await auth.getToken().catch(() => null);
|
|
15133
15144
|
if (token) headers.set("Authorization", `Bearer ${token}`);
|
|
15134
15145
|
else headers.delete("Authorization");
|
|
15146
|
+
if (opts.origin) headers.set("X-Prompd-Origin", opts.origin);
|
|
15135
15147
|
alog("gateway:fetch", { url: String(url), hasToken: !!token });
|
|
15136
15148
|
try {
|
|
15137
15149
|
const res = await fetch(url, { ...init, headers });
|
|
@@ -15163,6 +15175,7 @@ function statusOf(message) {
|
|
|
15163
15175
|
}
|
|
15164
15176
|
function classifyStreamError(message, status) {
|
|
15165
15177
|
if (/\baborted\b|AbortError/i.test(message)) return "fatal";
|
|
15178
|
+
if (/\b(timed out|request timeout|gateway timeout|deadline exceeded)\b/i.test(message)) return "fatal";
|
|
15166
15179
|
const code = status ?? statusOf(message);
|
|
15167
15180
|
if (code != null) {
|
|
15168
15181
|
if (FATAL_STATUS.has(code)) return "fatal";
|
|
@@ -15370,7 +15383,25 @@ var BUILTIN_NAMESPACES = {
|
|
|
15370
15383
|
ask_user: "agent",
|
|
15371
15384
|
spawn_agent: "agent",
|
|
15372
15385
|
spawn_agents: "agent",
|
|
15373
|
-
todo_write: "agent"
|
|
15386
|
+
todo_write: "agent",
|
|
15387
|
+
// Named here as a backstop; the sidecar's own decls also carry `namespace`,
|
|
15388
|
+
// and an explicit field always wins (resolveNamespace). Both say the same
|
|
15389
|
+
// thing so a sidecar that predates this still lands in the right namespace.
|
|
15390
|
+
sidecar_fs_read_file: "sidecar",
|
|
15391
|
+
sidecar_fs_write_file: "sidecar",
|
|
15392
|
+
sidecar_fs_read_bytes: "sidecar",
|
|
15393
|
+
sidecar_fs_list_dir: "sidecar",
|
|
15394
|
+
sidecar_fs_delete: "sidecar",
|
|
15395
|
+
sidecar_shell_exec: "sidecar",
|
|
15396
|
+
// Host-side orchestration tools. They are not in allTools() - they reach the
|
|
15397
|
+
// agent as remote decls (workerFactory) - but they are still governed by the
|
|
15398
|
+
// policy, so they need a canonical address like everything else.
|
|
15399
|
+
create_strategy: "agent",
|
|
15400
|
+
edit_strategy: "agent",
|
|
15401
|
+
view_strategy: "agent",
|
|
15402
|
+
run_strategy: "agent",
|
|
15403
|
+
list_strategies: "agent",
|
|
15404
|
+
list_saved_strategies: "agent"
|
|
15374
15405
|
};
|
|
15375
15406
|
function resolveNamespace(tool) {
|
|
15376
15407
|
if (tool.namespace) return tool.namespace;
|
|
@@ -15390,6 +15421,14 @@ function toolAddress(tool) {
|
|
|
15390
15421
|
const m = new RegExp(`^${ns}__?`).exec(leaf);
|
|
15391
15422
|
if (m) leaf = leaf.slice(m[0].length);
|
|
15392
15423
|
}
|
|
15424
|
+
if (ns === "sidecar") {
|
|
15425
|
+
for (const p of ["sidecar_fs_", "sidecar_"]) {
|
|
15426
|
+
if (leaf.startsWith(p)) {
|
|
15427
|
+
leaf = leaf.slice(p.length);
|
|
15428
|
+
break;
|
|
15429
|
+
}
|
|
15430
|
+
}
|
|
15431
|
+
}
|
|
15393
15432
|
return `${ns}:${leaf}`;
|
|
15394
15433
|
}
|
|
15395
15434
|
|
|
@@ -15408,6 +15447,16 @@ function formatOffloadRef(ref) {
|
|
|
15408
15447
|
${ref.preview}${ref.bytes > ref.preview.length ? "\n\u2026(truncated)" : ""}` : head;
|
|
15409
15448
|
}
|
|
15410
15449
|
|
|
15450
|
+
// ../harness/prompts/toolsMarker.ts
|
|
15451
|
+
var TOOLS_MARKER = "\uE000PROMPD_TOOLS\uE000";
|
|
15452
|
+
function formatToolLines(tools) {
|
|
15453
|
+
return tools.map((t) => `- \`${t.name}\`: ${t.description}`).join("\n");
|
|
15454
|
+
}
|
|
15455
|
+
function fillToolsMarker(system, tools) {
|
|
15456
|
+
if (!system.includes(TOOLS_MARKER)) return system;
|
|
15457
|
+
return system.replaceAll(TOOLS_MARKER, tools.length ? formatToolLines(tools) : "(no tools available this run)");
|
|
15458
|
+
}
|
|
15459
|
+
|
|
15411
15460
|
// ../harness/core/loop.ts
|
|
15412
15461
|
async function runAgent(args) {
|
|
15413
15462
|
const { client, system, tools, toolCtx } = args;
|
|
@@ -15423,8 +15472,9 @@ async function runAgent(args) {
|
|
|
15423
15472
|
const recovery = resolveRecovery(args.recovery);
|
|
15424
15473
|
const toolFails = new ToolFailureTracker();
|
|
15425
15474
|
const messages = [...args.messages];
|
|
15426
|
-
|
|
15427
|
-
|
|
15475
|
+
const filledSystem = system ? fillToolsMarker(system, tools) : system;
|
|
15476
|
+
if (filledSystem && !messages.some((m) => m.role === "system")) {
|
|
15477
|
+
messages.unshift({ role: "system", content: filledSystem });
|
|
15428
15478
|
}
|
|
15429
15479
|
const toolDefs = tools.map((t) => ({
|
|
15430
15480
|
type: "function",
|
|
@@ -15462,7 +15512,9 @@ async function runAgent(args) {
|
|
|
15462
15512
|
model,
|
|
15463
15513
|
messages,
|
|
15464
15514
|
tools: toolDefs.length ? toolDefs : void 0,
|
|
15465
|
-
tool_choice: toolDefs.length ? "auto" : void 0
|
|
15515
|
+
tool_choice: toolDefs.length ? "auto" : void 0,
|
|
15516
|
+
max_completion_tokens: args.maxCompletionTokens,
|
|
15517
|
+
temperature: args.temperature
|
|
15466
15518
|
},
|
|
15467
15519
|
signal,
|
|
15468
15520
|
(delta) => emit({ type: "assistant-delta", delta })
|
|
@@ -15910,6 +15962,18 @@ var todoWriteTool = {
|
|
|
15910
15962
|
name: "todo_write",
|
|
15911
15963
|
noOffload: true,
|
|
15912
15964
|
// the task list is what the user wants to see — keep it inline
|
|
15965
|
+
/* DECLARED, not left to the policy's default. It is a write in name only: it
|
|
15966
|
+
* touches no file, no network and no state outside the run's own task panel,
|
|
15967
|
+
* so there is nothing for a person to approve. Without this it inherited
|
|
15968
|
+
* `policy.defaultPermission` — `ask` under any careful policy — and an agent
|
|
15969
|
+
* doing multi-step work stopped to request approval every time it ticked off a
|
|
15970
|
+
* step, which trains people to approve without reading.
|
|
15971
|
+
*
|
|
15972
|
+
* `permission` sits BELOW an explicit `policy.permissions` entry in the
|
|
15973
|
+
* precedence chain (permission-service.ts), so anyone who genuinely wants to
|
|
15974
|
+
* gate it still can; it only replaces the blanket default. And it is not
|
|
15975
|
+
* `mutates`, so a policy's mutating backstop correctly does not catch it. */
|
|
15976
|
+
permission: "allow",
|
|
15913
15977
|
description: 'Maintain a visible task list for a multi-step job. Pass the COMPLETE list each time (a rewrite). Keep exactly one task "in_progress" while you work it; mark tasks "completed" as you finish; use "blocked" + blockedBy for tasks waiting on others; nest a subtask one level with parentId. Reuse a short stable id per task across updates so its progress and activity persist. Call it when you start a multi-step task and after each meaningful step.',
|
|
15914
15978
|
parameters: {
|
|
15915
15979
|
type: "object",
|
|
@@ -16103,17 +16167,29 @@ async function prmdCompileError(content, ctx) {
|
|
|
16103
16167
|
}
|
|
16104
16168
|
var proposeEditTool = {
|
|
16105
16169
|
name: "propose_edit",
|
|
16106
|
-
description: "Propose a replacement for the
|
|
16170
|
+
description: "Propose a replacement for the CURRENTLY OPEN editor file. It takes no path and can only ever replace that one file, so never use it to create a new file or to edit a different one \u2014 use create_file or write_file for those. The user reviews a diff and applies or rejects it \u2014 this does NOT write the file directly. Provide the COMPLETE new file content (not a patch) plus a short explanation. Use the editor file shown in the system context as the basis. This call WAITS for the review and returns the outcome: applied, partially applied (with the rejected changes), or rejected \u2014 rely on that outcome, not on the proposal, for any follow-up work.",
|
|
16107
16171
|
parameters: {
|
|
16108
16172
|
type: "object",
|
|
16109
16173
|
properties: {
|
|
16110
16174
|
explanation: { type: "string", description: "One line describing the change." },
|
|
16111
|
-
new_content: { type: "string", description: "The full proposed file content." }
|
|
16175
|
+
new_content: { type: "string", description: "The full proposed file content." },
|
|
16176
|
+
path: { type: "string", description: "The file being replaced. Must be the file currently open in the editor." }
|
|
16112
16177
|
},
|
|
16113
|
-
required: ["explanation", "new_content"]
|
|
16178
|
+
required: ["explanation", "new_content", "path"]
|
|
16114
16179
|
},
|
|
16115
16180
|
async run(args, ctx) {
|
|
16116
16181
|
const explanation = str4(args, "explanation") || "Proposed an edit";
|
|
16182
|
+
if (!ctx.editorFile) {
|
|
16183
|
+
return "Cannot propose an edit: no file is open in the editor, and propose_edit only replaces the open file. To create a new file use create_file, and to overwrite an existing one use write_file \u2014 both take an explicit path.";
|
|
16184
|
+
}
|
|
16185
|
+
const target = str4(args, "path");
|
|
16186
|
+
if (!target) {
|
|
16187
|
+
return `Cannot propose an edit: propose_edit needs a path, and it must be the open file (${ctx.editorFile}). To create a new file use create_file, or to overwrite a different one use write_file.`;
|
|
16188
|
+
}
|
|
16189
|
+
const norm = (p) => p.trim().replace(/\\/g, "/").replace(/^\.\//, "");
|
|
16190
|
+
if (norm(target) !== norm(ctx.editorFile)) {
|
|
16191
|
+
return `Cannot propose an edit: the open file is ${ctx.editorFile}, but this proposal targets ${target}. propose_edit can only replace the open file. Use create_file for a new file, or write_file to overwrite a different one.`;
|
|
16192
|
+
}
|
|
16117
16193
|
if (!ctx.reviewEdit || !ctx.callId) {
|
|
16118
16194
|
return `Proposed an edit: ${explanation}. Awaiting the user's review (apply/reject).`;
|
|
16119
16195
|
}
|
|
@@ -16147,21 +16223,23 @@ Respect the rejection \u2014 do not re-propose those changes unless the user ask
|
|
|
16147
16223
|
var saveMemoryTool = {
|
|
16148
16224
|
name: "save_memory",
|
|
16149
16225
|
mutates: true,
|
|
16150
|
-
description:
|
|
16226
|
+
description: 'Persist a durable note to memory for later recall (facts, user preferences, decisions). Choose scope: "workspace" for facts specific to the current project, "global" for facts about the user or their preferences that apply everywhere.',
|
|
16151
16227
|
parameters: {
|
|
16152
16228
|
type: "object",
|
|
16153
16229
|
properties: {
|
|
16154
16230
|
text: { type: "string", description: "The note to remember." },
|
|
16231
|
+
scope: { type: "string", enum: ["workspace", "global"], description: "Where to store it: workspace (this project) or global (everywhere)." },
|
|
16155
16232
|
tags: { type: "array", items: { type: "string" }, description: "Optional tags." }
|
|
16156
16233
|
},
|
|
16157
|
-
required: ["text"]
|
|
16234
|
+
required: ["text", "scope"]
|
|
16158
16235
|
},
|
|
16159
16236
|
// Permission is gated centrally by the loop's policy/permission layer (this
|
|
16160
16237
|
// tool is `mutates`), so no confirm call here.
|
|
16161
16238
|
async run(args, ctx) {
|
|
16162
16239
|
const text = str4(args, "text");
|
|
16163
16240
|
const tags = Array.isArray(args.tags) ? args.tags.map(String) : [];
|
|
16164
|
-
const
|
|
16241
|
+
const scope = args.scope === "global" ? "global" : "workspace";
|
|
16242
|
+
const item = await ctx.memory.save(text, tags, scope);
|
|
16165
16243
|
return `Saved memory ${item.id}.`;
|
|
16166
16244
|
}
|
|
16167
16245
|
};
|
|
@@ -16208,6 +16286,19 @@ var recallResultTool = {
|
|
|
16208
16286
|
name: "recall_result",
|
|
16209
16287
|
noOffload: true,
|
|
16210
16288
|
// recalling a large result must never re-offload itself
|
|
16289
|
+
/* DECLARED, like todo_write's and ask_user's. This one grants no new access at
|
|
16290
|
+
* all: it reads back a tool result THIS SESSION ALREADY PRODUCED, which means
|
|
16291
|
+
* the original call already passed the policy check that produced it. The
|
|
16292
|
+
* store is session-scoped (`<root>/<sessionId>/blobs/<id>.json`) and the id
|
|
16293
|
+
* shape is validated, so it cannot reach another session's data or escape the
|
|
16294
|
+
* directory.
|
|
16295
|
+
*
|
|
16296
|
+
* The deciding argument is that offloading is a CONTEXT-MANAGEMENT detail,
|
|
16297
|
+
* triggered by size. Gating recall means the same information costs an
|
|
16298
|
+
* approval prompt depending on how large it happened to be - a performance
|
|
16299
|
+
* heuristic leaking into governance, and an approval the user cannot act on
|
|
16300
|
+
* meaningfully because they already approved the thing that produced it. */
|
|
16301
|
+
permission: "allow",
|
|
16211
16302
|
description: 'Fetch the full content of a tool result that was offloaded to save context. You saw an "[offloaded tool result \u2026 recall_result({ id })]" reference \u2014 pass that id.',
|
|
16212
16303
|
parameters: {
|
|
16213
16304
|
type: "object",
|
|
@@ -16223,6 +16314,21 @@ var recallResultTool = {
|
|
|
16223
16314
|
var askUserTool = {
|
|
16224
16315
|
name: "ask_user",
|
|
16225
16316
|
noOffload: true,
|
|
16317
|
+
/* DECLARED, like todo_write's. Gating this behind an approval prompt is asking
|
|
16318
|
+
* the user for permission to ask the user a question — two dialogs for one
|
|
16319
|
+
* decision, the first of which carries no information.
|
|
16320
|
+
*
|
|
16321
|
+
* It changes nothing outside the run: no file, no network, no state. Its whole
|
|
16322
|
+
* effect is to put a question in front of a person who is already there.
|
|
16323
|
+
*
|
|
16324
|
+
* Nothing depended on its previous `ask` tier. The case that looks like it
|
|
16325
|
+
* might — an unattended run parking forever on a question nobody will answer —
|
|
16326
|
+
* is handled by EXCLUSION rather than by permission: CREW_EXCLUDED_TOOLS drops
|
|
16327
|
+
* ask_user from every crew agent (see @corenel/crew's capabilities.ts), and the
|
|
16328
|
+
* daemon's executor honours the same set. On a surface where it IS offered,
|
|
16329
|
+
* someone is by definition attending. And with no `ask` handler wired, `run`
|
|
16330
|
+
* already returns "unavailable in this environment" rather than hanging. */
|
|
16331
|
+
permission: "allow",
|
|
16226
16332
|
description: "Ask the user one or more questions when you need a decision you cannot make from context \u2014 to choose between approaches, get a missing requirement, or confirm direction. Prefer this over guessing. Give each question a short `header` (a chip label), the `question` text, and 2\u20134 distinct `options` (each with a label and an optional one-line description of the trade-off). Set `multiSelect: true` when more than one option may apply. The user can also type a custom answer. Returns the chosen answers per question.",
|
|
16227
16333
|
parameters: {
|
|
16228
16334
|
type: "object",
|
|
@@ -16349,6 +16455,24 @@ Error: ${String(e?.message || e)}`;
|
|
|
16349
16455
|
return results.join("\n\n");
|
|
16350
16456
|
}
|
|
16351
16457
|
};
|
|
16458
|
+
var listToolsTool = {
|
|
16459
|
+
name: "list_tools",
|
|
16460
|
+
noOffload: true,
|
|
16461
|
+
description: "List the tools available to you this run \u2014 their names, one-line descriptions, and top-level parameters. Use this to discover what you can call (including any MCP or connected-host tools) before deciding how to act.",
|
|
16462
|
+
parameters: { type: "object", properties: {} },
|
|
16463
|
+
async run(_args, ctx) {
|
|
16464
|
+
if (!ctx.listTools) return "Tool discovery is not available here.";
|
|
16465
|
+
const tools = ctx.listTools();
|
|
16466
|
+
if (!tools.length) return "No tools are available this run.";
|
|
16467
|
+
const lines = tools.map((t) => {
|
|
16468
|
+
const props = t.parameters && typeof t.parameters === "object" ? Object.keys(t.parameters.properties ?? {}) : [];
|
|
16469
|
+
const params = props.length ? ` \u2014 params: ${props.join(", ")}` : "";
|
|
16470
|
+
return `- \`${t.name}\`: ${t.description}${params}`;
|
|
16471
|
+
});
|
|
16472
|
+
return `Available tools this run (${tools.length}):
|
|
16473
|
+
${lines.join("\n")}`;
|
|
16474
|
+
}
|
|
16475
|
+
};
|
|
16352
16476
|
var compilePrompdTool = {
|
|
16353
16477
|
name: "compile_prompd",
|
|
16354
16478
|
noOffload: true,
|
|
@@ -16383,6 +16507,7 @@ var defaultTools = [
|
|
|
16383
16507
|
askUserTool,
|
|
16384
16508
|
spawnAgentTool,
|
|
16385
16509
|
spawnAgentsTool,
|
|
16510
|
+
listToolsTool,
|
|
16386
16511
|
proposeEditTool,
|
|
16387
16512
|
saveMemoryTool,
|
|
16388
16513
|
recallMemoryTool,
|
|
@@ -16414,7 +16539,7 @@ function configWorkspace() {
|
|
|
16414
16539
|
|
|
16415
16540
|
// ../harness/prompts/library/defaults.generated.ts
|
|
16416
16541
|
var RAW_DEFAULTS = {
|
|
16417
|
-
"
|
|
16542
|
+
"systems/help-system.md": '---\nid: help-system\nname: Help assistant\nversion: 1.0.0\ndescription: System prompt for the isolated in-app help chat. Compiled with the site index injected.\nparameters:\n - name: app_index\n type: string\n description: The compiled site index describing the app\'s structure.\n default: ""\n - name: recent_summary\n type: string\n description: A summary of the earlier conversation when a new session was started.\n default: ""\n---\nYou are the **Prompd Help** assistant \u2014 a friendly in-app guide embedded in the Prompd web editor. Your only job is to help the user understand and navigate THIS app. You are not a general chatbot and you do not write or edit their prompts (the editor\'s Assistant does that).\n\nHow to help:\n- Answer from the SITE INDEX below. Tell the user exactly where a thing is and how to get to it ("Settings \u2192 Appearance", "the Build button in the Editor panel header", "the layout presets in the top bar").\n- When pointing at a route, link it in markdown so it\'s clickable: `[Editor](/editor)`, `[Workflows](/workflows)`. For buttons/panels that aren\'t routes, name their location precisely instead of inventing a link.\n- You can DO things, not just describe them. For any action in the "Actions you can trigger" list, write a link as `[label](prompd:<id>)` (e.g. `[create a new file](prompd:new-file)`, `[switch to Chat layout](prompd:layout-chat)`). Clicking it performs the action in the app. Offer an action link whenever the user wants to *do* the thing.\n- For multi-step tasks, follow the matching "How-to flow": give the numbered steps, and turn each step that has an action into a `prompd:<id>` link so the user can jump straight there. Lead with the action link, then the remaining steps.\n- Only use action ids and route paths that appear in the index \u2014 never invent a `prompd:` id.\n- Be concise and concrete. Lead with the answer. Use short steps or a tight list when there are multiple actions.\n- If something isn\'t in the index, say you\'re not sure rather than inventing UI that may not exist.\n- Keep a warm, plain tone. No filler, no preamble.\n\n{% if recent_summary %}\nEarlier in this conversation (summarized, because a new session was started):\n{{ recent_summary }}\n{% endif %}\n\n--- SITE INDEX ---\n{{ app_index }}\n',
|
|
16418
16543
|
"tools/guidance.md": '<!--\nTool Guidance \u2014 use this to steer tool usage, e.g. "Prefer searching the registry\nfor relevant packages over guessing which tools to use." Anything outside this\ncomment is added to the system prompt; the comment itself is stripped.\n-->\n',
|
|
16419
16544
|
"editor/inline-assist.prmd": `---
|
|
16420
16545
|
id: inline-assist
|
|
@@ -16496,7 +16621,64 @@ Add a constraint :: Add a constraint or rule to the prompt instructions (what to
|
|
|
16496
16621
|
"personas/senior-architect.md": "---\nid: senior-architect\nname: Senior architect\ndescription: Shapes systems and tradeoffs.\n---\nYou are a senior software architect. You shape systems before code is written and keep them coherent as they grow.\n- Understand before designing. Map the existing architecture, data flow, and constraints; reuse and extend established patterns before introducing new ones.\n- Design for the real requirement, not an imagined one. Prefer the simplest structure that meets today's need with a clear seam for tomorrow's. Avoid speculative abstraction (YAGNI).\n- Make boundaries explicit. Define interfaces, contracts, and ownership; keep coupling low and cohesion high; isolate the decisions most likely to change behind stable seams.\n- Name the tradeoffs. For any consequential choice, lay out the options, what each costs, and why you'd pick one. Surface assumptions and risks plainly.\n- Sequence the work into safe, shippable steps with reversible checkpoints; call out what must land first.\n- Stay grounded in the actual codebase and conventions. When uncertain, say so and propose how to de-risk it.\n",
|
|
16497
16622
|
"personas/senior-dev.md": "---\nid: senior-dev\nname: Senior engineer\ndescription: Senior software engineer.\n---\nYou are a senior software engineer. Bring that craft to every change:\n- Fit the codebase. Study neighboring code and follow its conventions before writing. Don't assume a library is available \u2014 confirm it's already used in the project before depending on it.\n- Write the minimum that solves the task. No speculative abstractions, options, or features for hypothetical futures; three similar lines beat a premature abstraction. No half-finished or stubbed implementations.\n- Don't add error handling, validation, or fallbacks for cases that can't happen. Trust internal guarantees; validate only at real boundaries (user input, external systems). No backwards-compat shims unless asked.\n- Comments are for the non-obvious WHY \u2014 a constraint, an invariant, a workaround. Don't narrate what the code already says; default to none.\n- Verify your work before calling a change done. If you couldn't verify something, say so plainly.\n- Be security-minded: no injection, no leaked secrets, least privilege.\n",
|
|
16498
16623
|
"personas/terse.md": "---\nid: terse\nname: Terse\ndescription: Extremely concise.\n---\nBe extremely concise. One sentence per update. No preamble. No summary unless asked.\n",
|
|
16499
|
-
"
|
|
16624
|
+
"memory/MEMORY.md": "# Memory index\n\nSaved notes appear here, one line each. The agent adds them with save_memory and\nreads them with recall_memory. This is the global (~/.prompd) memory; a project's\nown notes live in ./.prompd/memory.\n",
|
|
16625
|
+
"systems/system-base.md": `---
|
|
16626
|
+
id: system-base
|
|
16627
|
+
name: Operational system prompt
|
|
16628
|
+
version: 1.0.0
|
|
16629
|
+
description: The agent's system prompt \u2014 persona, mode, tool definitions and editor context composed by @prompd/core.
|
|
16630
|
+
parameters:
|
|
16631
|
+
- name: persona
|
|
16632
|
+
type: string
|
|
16633
|
+
description: The selected persona's voice/role text, placed first.
|
|
16634
|
+
default: ""
|
|
16635
|
+
- name: mode
|
|
16636
|
+
type: string
|
|
16637
|
+
description: Active mode id (auto / edit / plan / brainstorm).
|
|
16638
|
+
default: "auto"
|
|
16639
|
+
- name: mode_hint
|
|
16640
|
+
type: string
|
|
16641
|
+
description: Steering text for the active mode.
|
|
16642
|
+
default: ""
|
|
16643
|
+
- name: tools
|
|
16644
|
+
type: string
|
|
16645
|
+
description: Definitions of the tools available this run.
|
|
16646
|
+
default: ""
|
|
16647
|
+
- name: tool_guidance
|
|
16648
|
+
type: string
|
|
16649
|
+
description: Optional extra guidance on tool usage.
|
|
16650
|
+
default: ""
|
|
16651
|
+
- name: file_context
|
|
16652
|
+
type: string
|
|
16653
|
+
description: The editor file / selection / compiled-output context block.
|
|
16654
|
+
default: ""
|
|
16655
|
+
- name: app
|
|
16656
|
+
type: string
|
|
16657
|
+
description: Product name of the host application, used for the agent's own identity.
|
|
16658
|
+
default: "Prompd"
|
|
16659
|
+
---
|
|
16660
|
+
{% if persona %}{{ persona }}
|
|
16661
|
+
|
|
16662
|
+
{% endif %}You are the {{ app }} assistant embedded in the in-browser .prmd editor. You help the user author, compile, and improve .prmd/.md prompts (YAML frontmatter + Nunjucks body with typed parameters). When the user asks about the .prmd format itself \u2014 frontmatter fields, parameter types (including enums), date defaults, inheritance, or templating \u2014 the canonical reference is \`languages/prmd.md\` in the {{ app }} config workspace; consult it rather than guessing (it is already included in context whenever a .prmd/.md file is open).
|
|
16663
|
+
|
|
16664
|
+
To change the file open in the editor, call propose_edit with the COMPLETE new file content \u2014 the user reviews a diff and applies it. To read or change other files in the workspace, use the file tools (writes ask the user for permission first). Use compile_prompd to preview rendered output and search_packages to find registry packages. For any multi-step job, maintain a visible task list with todo_write: lay out the steps, keep one task in_progress, and mark each completed as you go. Prefer calling a tool over guessing, and be concise.
|
|
16665
|
+
|
|
16666
|
+
## Tools available this run
|
|
16667
|
+
{{ tools }}
|
|
16668
|
+
{% if tool_guidance %}
|
|
16669
|
+
|
|
16670
|
+
{{ tool_guidance }}
|
|
16671
|
+
{% endif %}
|
|
16672
|
+
{% if mode_hint %}
|
|
16673
|
+
|
|
16674
|
+
## Mode
|
|
16675
|
+
{{ mode_hint }}
|
|
16676
|
+
{% endif %}
|
|
16677
|
+
{% if file_context %}
|
|
16678
|
+
|
|
16679
|
+
{{ file_context }}
|
|
16680
|
+
{% endif %}
|
|
16681
|
+
`,
|
|
16500
16682
|
"systems/system-pdflow.md": '---\nid: system-pdflow\nname: Workflow file system prompt\nversion: 1.0.0\ndescription: Adds .pdflow format knowledge (node taxonomy, edges, parameters) on top of the base system prompt.\ninherits: system-base.md\n---\n\n## Active file format \u2014 Prompd workflow (.pdflow)\n\nThe open file is a **Prompd workflow**: JSON with `{ version, metadata, parameters[], nodes[], edges[] }`. The web editor renders it as a linear chain \u2014 a fixed Start, ordered middle nodes, a fixed End \u2014 connected one edge each.\n\nEach node is `{ id, type, position, data }`. Node types and their key `data`:\n\n- `trigger` \u2014 Start (entry point). Exactly one.\n- `prompt` \u2014 runs a `.prmd`/`.md` prompt. `data.sourceType` is `\'file\'` (`data.source` = a WORKSPACE-RELATIVE path) or `\'raw\'` (`data.rawPrompt`). Optional `data.model` / `data.providerNodeId`.\n- `user-input` \u2014 pauses to collect input. `data.prompt`, `data.inputType` (`text` / `textarea` / `choice` / `confirm` / `number`).\n- `guardrail` \u2014 validates/gates. `data.systemPrompt`, `data.passExpression` or `data.scoreThreshold`.\n- `agent` \u2014 composite (input guardrail \u2192 prompt \u2192 output guardrail). `data.systemPrompt`, `data.userPrompt`, `data.maxIterations`; internal guardrails in `data.inputGuardrail` / `data.outputGuardrail` (each `{ enabled, preset|systemPrompt, passExpression|scoreThreshold }`).\n- `transformer` \u2014 JSON\u2192JSON map. `data.mode: \'template\'` with `data.template` (`{{ input }}` substitution).\n- `callback` / `checkpoint` \u2014 debug/observation point (logs node I/O).\n- `output` \u2014 End (workflow result). Exactly one.\n- `provider` \u2014 one off-chain node holding the canvas-wide provider/model; nodes reference it via `data.providerNodeId`.\n\nEdges thread each node\'s output to the next; the runner exposes `{{ input }}` / `{{ previous_output }}` to downstream nodes.\n\n### Example (minimal chain)\n\n```\n{\n "version": "1.0",\n "metadata": { "name": "summarize" },\n "parameters": [],\n "nodes": [\n { "id": "start", "type": "trigger", "position": { "x": 0, "y": 0 }, "data": {} },\n { "id": "p1", "type": "prompt", "position": { "x": 0, "y": 120 }, "data": { "sourceType": "file", "source": "prompts/summarize.prmd" } },\n { "id": "end", "type": "output", "position": { "x": 0, "y": 240 }, "data": {} }\n ],\n "edges": [\n { "id": "e1", "source": "start", "target": "p1" },\n { "id": "e2", "source": "p1", "target": "end" }\n ]\n}\n```\n\nTo edit the workflow, modify this JSON with the file tools (paths are workspace-relative). Keep exactly one `trigger` and one `output`.\n',
|
|
16501
16683
|
"systems/system-prmd-md.md": '---\nid: system-prmd-md\nname: Prompt file system prompt (.prmd / .md)\nversion: 1.0.0\ninherits: ./system-base.md\nparameters:\n - name: persona\n type: string\n description: The selected persona\'s voice/role text, placed first.\n default: ""\n - name: mode\n type: string\n description: Active mode id (auto / edit / plan / brainstorm).\n default: "auto"\n - name: mode_hint\n type: string\n description: Steering text for the active mode.\n default: ""\n - name: tools\n type: string\n description: Definitions of the tools available this run.\n default: ""\n - name: tool_guidance\n type: string\n description: Optional extra guidance on tool usage.\n default: ""\n - name: file_context\n type: string\n description: The editor file / selection / compiled-output context block.\n default: ""\n---\n\n{% include "../languages/prmd.md" %}\n\nWhen you edit this file, call `propose_edit` with the COMPLETE new file content. Keep the frontmatter valid YAML and only reference declared parameters in the body.\n',
|
|
16502
16684
|
"templates/index.json": '[\n {\n "_comment": "EXAMPLE of a data-driven New File type. Copy this entry, remove \\"disabled\\", give it a unique \\"id\\", and create the seed file at \\"template\\" (in this templates/ folder). Tokens __ID__ / __NAME__ are substituted on create. Icon is a ui-kit name (e.g. IcFileCode, IcUser, IcFlow) or \\"svg:<markup>\\". See docs/file-types.md.",\n "disabled": true,\n "id": "example-agent-prompt",\n "label": "Agent prompt",\n "description": "A .prmd tuned for tool-using agents.",\n "ext": "prmd",\n "category": "Prompd",\n "icon": "IcUser",\n "defaultName": "agent",\n "template": "templates/new-agent-prmd.prmd",\n "accent": true\n }\n]\n',
|
|
@@ -16562,9 +16744,9 @@ Add your specific criteria here.
|
|
|
16562
16744
|
|
|
16563
16745
|
Respond with PASS or FAIL followed by a one-sentence reason.
|
|
16564
16746
|
`,
|
|
16565
|
-
"strategies/debate.md": "---\nid: debate\nname: Debate\ndescription: Several independent attempts at the whole goal, judged and merged. Highest token use; best quality for open-ended or high-stakes goals.\ntier: 4\nknobs:\n attempts: 3\n parallelism: parallel\n---\nDo not split the goal. Instead, have it attempted WHOLE multiple times: create one\nsubagent per attempt (3 attempts), each with a single work item that tackles the\nentire goal from a distinct perspective (for example pragmatic, contrarian,\nfirst-principles). Name each subagent for its perspective. Write the synthesis as\na JUDGE: compare the attempts in {{ joined }}, weigh their strengths, and merge\nthe best elements into one final answer, noting significant disagreements.\n",
|
|
16566
|
-
"strategies/fanout.md": "---\nid: fanout\nname: Fan-out\ndescription: Wide parallel decomposition across specialist subagents. Higher token use; broad coverage, fastest wall-clock.\ntier: 3\ndefault: true\nknobs:\n parallelism: parallel\n---\nDecompose the goal into INDEPENDENT workstreams that can run in parallel \u2014 one\nspecialist subagent per theme, each with focused work items. Maximize coverage:\ndistinct angles, no overlapping work. Use dependsOn only where a work item truly\nneeds another item's output.\n",
|
|
16567
|
-
"strategies/lean.md": `---
|
|
16747
|
+
"strategies/types/debate.md": "---\nid: debate\nname: Debate\ndescription: Several independent attempts at the whole goal, judged and merged. Highest token use; best quality for open-ended or high-stakes goals.\ntier: 4\nknobs:\n attempts: 3\n parallelism: parallel\n---\nDo not split the goal. Instead, have it attempted WHOLE multiple times: create one\nsubagent per attempt (3 attempts), each with a single work item that tackles the\nentire goal from a distinct perspective (for example pragmatic, contrarian,\nfirst-principles). Name each subagent for its perspective. Write the synthesis as\na JUDGE: compare the attempts in {{ joined }}, weigh their strengths, and merge\nthe best elements into one final answer, noting significant disagreements.\n",
|
|
16748
|
+
"strategies/types/fanout.md": "---\nid: fanout\nname: Fan-out\ndescription: Wide parallel decomposition across specialist subagents. Higher token use; broad coverage, fastest wall-clock.\ntier: 3\ndefault: true\nknobs:\n parallelism: parallel\n---\nDecompose the goal into INDEPENDENT workstreams that can run in parallel \u2014 one\nspecialist subagent per theme, each with focused work items. Maximize coverage:\ndistinct angles, no overlapping work. Use dependsOn only where a work item truly\nneeds another item's output.\n",
|
|
16749
|
+
"strategies/types/lean.md": `---
|
|
16568
16750
|
id: lean
|
|
16569
16751
|
name: Lean
|
|
16570
16752
|
description: One subagent, a few sequential steps. Lowest token use \u2014 best for focused, well-defined goals.
|
|
@@ -16582,7 +16764,7 @@ reserve a stronger model only for a work item that is genuinely hard.
|
|
|
16582
16764
|
If a single work item covers the goal, set "synthesis" to exactly "{{ joined }}"
|
|
16583
16765
|
so the runner returns that output directly without a synthesis call.
|
|
16584
16766
|
`,
|
|
16585
|
-
"strategies/pipeline.md": "---\nid: pipeline\nname: Pipeline\ndescription: Staged chain \u2014 each stage's output feeds the next. Moderate token use; best for transform-and-refine goals.\ntier: 2\nknobs:\n parallelism: staged\n---\nDecompose the goal into sequential STAGES (one subagent per stage), each\ntransforming or refining what the previous stage produced \u2014 for example\nresearch, then draft, then refine, then package. Keep it to 2-4 stages. Within a\nstage, work items may run in parallel, but a stage must only need what earlier\nstages produced. Write each stage's work prompts to state what they consume from\nthe previous stage and what they hand to the next.\n",
|
|
16767
|
+
"strategies/types/pipeline.md": "---\nid: pipeline\nname: Pipeline\ndescription: Staged chain \u2014 each stage's output feeds the next. Moderate token use; best for transform-and-refine goals.\ntier: 2\nknobs:\n parallelism: staged\n---\nDecompose the goal into sequential STAGES (one subagent per stage), each\ntransforming or refining what the previous stage produced \u2014 for example\nresearch, then draft, then refine, then package. Keep it to 2-4 stages. Within a\nstage, work items may run in parallel, but a stage must only need what earlier\nstages produced. Write each stage's work prompts to state what they consume from\nthe previous stage and what they hand to the next.\n",
|
|
16586
16768
|
"skills/strategy-planning/SKILL.prmd": `---
|
|
16587
16769
|
id: strategy-planning
|
|
16588
16770
|
name: strategy-planning
|
|
@@ -16631,7 +16813,19 @@ the goal's stakes and vagueness:
|
|
|
16631
16813
|
or context gaps with edit_strategy. Then tell the user what you gathered, what
|
|
16632
16814
|
you decided, and where the spec/plan files live \u2014 the canvas graph plus those
|
|
16633
16815
|
two files ARE the deliverable.
|
|
16634
|
-
|
|
16816
|
+
`,
|
|
16817
|
+
"roles/document-writer/PERSONA.md": "Clear, plain-spoken technical writer. Values accuracy and brevity over flourish.\n",
|
|
16818
|
+
"roles/document-writer/POLICY.yaml": "version: 1\nname: role:document-writer\ndefaultPermission: ask\nmutatingDefault: ask\npermissions:\n read_file: allow\n list_files: allow\n search_files: allow\n stat_file: allow\n write_file: ask\n create_file: ask\n",
|
|
16819
|
+
"roles/document-writer/ROLE.md": "---\nlabel: Document Writer\njobTitle: Document Writer\ndescription: Drafts and edits clear documentation from the codebase and context.\nsuggestedSkills: []\n---\nWrite clearly and concisely for the intended reader. Ground every claim in the source. Prefer short sentences and concrete examples.\n",
|
|
16820
|
+
"roles/research-analyst/PERSONA.md": "Rigorous analyst. Sources claims, flags uncertainty, distinguishes fact from inference.\n",
|
|
16821
|
+
"roles/research-analyst/POLICY.yaml": "version: 1\nname: role:research-analyst\ndefaultPermission: ask\nmutatingDefault: deny\npermissions:\n read_file: allow\n list_files: allow\n search_files: allow\n stat_file: allow\n web_search: allow\n recall_memory: allow\n",
|
|
16822
|
+
"roles/research-analyst/ROLE.md": "---\nlabel: Research Analyst\njobTitle: Research Analyst\ndescription: Gathers and synthesizes information; does not modify the workspace.\nsuggestedSkills: []\n---\nGather from the web and the workspace, then synthesize a sourced, structured answer. Separate findings from assumptions. Do not modify files.\n",
|
|
16823
|
+
"roles/senior-software-engineer/PERSONA.md": "Pragmatic senior engineer. Precise, terse, correctness-first. Prefers the smallest change that fully solves the problem.\n",
|
|
16824
|
+
"roles/senior-software-engineer/POLICY.yaml": "version: 1\nname: role:senior-software-engineer\ndefaultPermission: ask\nmutatingDefault: ask\npermissions:\n read_file: allow\n list_files: allow\n search_files: allow\n stat_file: allow\n compile_prompd: allow\n write_file: ask\n create_file: ask\n rename_file: ask\n",
|
|
16825
|
+
"roles/senior-software-engineer/ROLE.md": "---\nlabel: Senior Software Engineer\njobTitle: Senior Software Engineer\ndescription: Implements features and fixes with tests; reads before writing.\nsuggestedSkills: []\n---\nImplement changes test-first. Read the surrounding code and match its conventions. Keep changes minimal and focused; explain non-obvious decisions.\n",
|
|
16826
|
+
"roles/senior-test-engineer/PERSONA.md": "Meticulous, adversarial about correctness. Thinks in failure modes and boundary conditions.\n",
|
|
16827
|
+
"roles/senior-test-engineer/POLICY.yaml": "version: 1\nname: role:senior-test-engineer\ndefaultPermission: ask\nmutatingDefault: deny\npermissions:\n read_file: allow\n list_files: allow\n search_files: allow\n stat_file: allow\n compile_prompd: allow\n",
|
|
16828
|
+
"roles/senior-test-engineer/ROLE.md": "---\nlabel: Senior Test Engineer\njobTitle: Senior Test Engineer\ndescription: Writes and runs tests; hunts edge cases; does not modify source.\nsuggestedSkills: []\n---\nFocus on coverage and edge cases. Write tests that fail before a fix and pass after. Do not modify production source; report gaps you find.\n"
|
|
16635
16829
|
};
|
|
16636
16830
|
|
|
16637
16831
|
// ../harness/prompts/library/index.ts
|
|
@@ -16884,8 +17078,7 @@ async function compileConfigTemplate(path, params) {
|
|
|
16884
17078
|
}
|
|
16885
17079
|
}
|
|
16886
17080
|
function formatTools(tools) {
|
|
16887
|
-
|
|
16888
|
-
return tools.map((t) => `- \`${t.name}\`: ${t.description}`).join("\n");
|
|
17081
|
+
return tools && tools.length ? formatToolLines(tools) : "";
|
|
16889
17082
|
}
|
|
16890
17083
|
async function composeAgentSystem(args) {
|
|
16891
17084
|
const mode = args.mode || "auto";
|
|
@@ -16902,21 +17095,41 @@ async function composeAgentSystem(args) {
|
|
|
16902
17095
|
]);
|
|
16903
17096
|
const tool_guidance = toolGuidanceRaw.replace(/<!--[\s\S]*?-->/g, "").trim();
|
|
16904
17097
|
const skillsBlock = await enabledSkillInstructions().catch(() => "");
|
|
17098
|
+
const memoryIdx = args.memoryIndex ? await args.memoryIndex().catch(() => "") : "";
|
|
17099
|
+
const memoryBlock = memoryIdx.trim() ? `## Memory
|
|
17100
|
+
Notes you've saved. Call recall_memory to read one in full; save_memory to add one.
|
|
17101
|
+
|
|
17102
|
+
${memoryIdx.trim()}` : "";
|
|
16905
17103
|
return compileConfigTemplate(systemPath, {
|
|
17104
|
+
// Who the agent says it IS. Injected rather than written into the prompt,
|
|
17105
|
+
// because the same shipped default is seeded into every host's config
|
|
17106
|
+
// workspace and each one carries a different product name.
|
|
17107
|
+
app: promptHost().appName?.() || "Prompd",
|
|
16906
17108
|
persona: persona.trim(),
|
|
16907
17109
|
mode,
|
|
16908
17110
|
mode_hint,
|
|
16909
17111
|
tool_guidance,
|
|
16910
|
-
tools: formatTools(args.tools),
|
|
16911
|
-
file_context: [(args.contextText || "").trim(), skillsBlock].filter(Boolean).join("\n\n"),
|
|
17112
|
+
tools: args.toolsText ?? formatTools(args.tools),
|
|
17113
|
+
file_context: [(args.contextText || "").trim(), memoryBlock, skillsBlock].filter(Boolean).join("\n\n"),
|
|
16912
17114
|
...args.params || {}
|
|
16913
17115
|
});
|
|
16914
17116
|
}
|
|
16915
17117
|
|
|
16916
17118
|
// ../tools-node/fileService.ts
|
|
16917
17119
|
import { promises as fs } from "node:fs";
|
|
16918
|
-
import { join, resolve, relative, dirname, sep, basename } from "node:path";
|
|
17120
|
+
import { join, resolve, relative, dirname, sep, basename, isAbsolute } from "node:path";
|
|
16919
17121
|
var SKIP = /* @__PURE__ */ new Set(["node_modules", ".git", "dist", "build", ".next", ".cache", ".turbo"]);
|
|
17122
|
+
function escapesRoot(rel, platformSep = sep) {
|
|
17123
|
+
if (rel === "") return false;
|
|
17124
|
+
if (rel === ".." || rel.startsWith(".." + platformSep)) return true;
|
|
17125
|
+
if (rel.split(platformSep)[0] === "..") return true;
|
|
17126
|
+
if (isAbsolute(rel)) return true;
|
|
17127
|
+
if (platformSep === "\\") {
|
|
17128
|
+
if (/^[a-zA-Z]:/.test(rel)) return true;
|
|
17129
|
+
if (rel.startsWith("\\\\")) return true;
|
|
17130
|
+
}
|
|
17131
|
+
return false;
|
|
17132
|
+
}
|
|
16920
17133
|
var NodeFileService = class {
|
|
16921
17134
|
kind = "directory";
|
|
16922
17135
|
label;
|
|
@@ -16930,8 +17143,7 @@ var NodeFileService = class {
|
|
|
16930
17143
|
}
|
|
16931
17144
|
/** True if `a` is lexically within the root (the root itself counts). */
|
|
16932
17145
|
within(a) {
|
|
16933
|
-
|
|
16934
|
-
return rel === "" || rel !== ".." && !rel.startsWith(".." + sep) && rel.split(sep)[0] !== "..";
|
|
17146
|
+
return !escapesRoot(relative(this.root, a));
|
|
16935
17147
|
}
|
|
16936
17148
|
/** Absolute path for a folder-relative one, rejecting anything that escapes root
|
|
16937
17149
|
* LEXICALLY (../, absolute). Symlink escapes are caught by assertReal/realAbs. */
|
|
@@ -16950,7 +17162,7 @@ var NodeFileService = class {
|
|
|
16950
17162
|
try {
|
|
16951
17163
|
const real = await fs.realpath(probe);
|
|
16952
17164
|
const rel = relative(realRoot, real);
|
|
16953
|
-
if (
|
|
17165
|
+
if (escapesRoot(rel)) {
|
|
16954
17166
|
throw new Error(`path escapes the workspace root via symlink: ${a}`);
|
|
16955
17167
|
}
|
|
16956
17168
|
return;
|
|
@@ -20165,13 +20377,23 @@ async function deviceLogin(opts) {
|
|
|
20165
20377
|
const f = opts.fetchImpl ?? fetch;
|
|
20166
20378
|
const base = opts.base.replace(/\/$/, "");
|
|
20167
20379
|
const post = async (path, body) => {
|
|
20168
|
-
const
|
|
20380
|
+
const url = `${base}${path}`;
|
|
20381
|
+
const res = await f(url, {
|
|
20169
20382
|
method: "POST",
|
|
20170
20383
|
headers: { "Content-Type": "application/json" },
|
|
20171
20384
|
body: JSON.stringify(body),
|
|
20172
20385
|
signal: opts.signal
|
|
20173
20386
|
});
|
|
20174
|
-
|
|
20387
|
+
const text = await res.text();
|
|
20388
|
+
try {
|
|
20389
|
+
return JSON.parse(text);
|
|
20390
|
+
} catch {
|
|
20391
|
+
const looksLikeHtml = /^\s*</.test(text);
|
|
20392
|
+
throw new Error(
|
|
20393
|
+
`${url} answered ${res.status} with ${looksLikeHtml ? "an HTML page" : "a non-JSON body"}, not JSON.` + (res.status === 404 ? `
|
|
20394
|
+
That usually means --base is wrong. The device endpoints live under /api \u2014 try --base ${base.replace(/\/api$/, "")}/api` : "")
|
|
20395
|
+
);
|
|
20396
|
+
}
|
|
20175
20397
|
};
|
|
20176
20398
|
const dc = await post("/oauth/device/code", { client_id: "corenel-cli", scope: "agent" });
|
|
20177
20399
|
if (!dc.device_code) throw new Error("device authorization failed");
|
|
@@ -20198,11 +20420,300 @@ async function deviceLogin(opts) {
|
|
|
20198
20420
|
}
|
|
20199
20421
|
}
|
|
20200
20422
|
|
|
20423
|
+
// ../crew/frontmatter.ts
|
|
20424
|
+
var import_yaml = __toESM(require_dist(), 1);
|
|
20425
|
+
var FRONTMATTER = /^---\r?\n([\s\S]*?)\r?\n---\r?\n?([\s\S]*)$/;
|
|
20426
|
+
function parseFrontmatter2(text) {
|
|
20427
|
+
const m = text.match(FRONTMATTER);
|
|
20428
|
+
if (!m) return { meta: {}, body: text };
|
|
20429
|
+
let meta = {};
|
|
20430
|
+
try {
|
|
20431
|
+
const parsed = import_yaml.default.parse(m[1]);
|
|
20432
|
+
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
20433
|
+
meta = parsed;
|
|
20434
|
+
}
|
|
20435
|
+
} catch {
|
|
20436
|
+
meta = {};
|
|
20437
|
+
}
|
|
20438
|
+
return { meta, body: m[2] };
|
|
20439
|
+
}
|
|
20440
|
+
|
|
20441
|
+
// ../crew/policy.ts
|
|
20442
|
+
var import_yaml2 = __toESM(require_dist(), 1);
|
|
20443
|
+
var LEVELS = ["allow", "ask", "deny"];
|
|
20444
|
+
var UNATTENDED = ["deny", "park", "allow"];
|
|
20445
|
+
function asLevel(v) {
|
|
20446
|
+
return typeof v === "string" && LEVELS.includes(v) ? v : void 0;
|
|
20447
|
+
}
|
|
20448
|
+
function asStringArray(v) {
|
|
20449
|
+
if (!Array.isArray(v)) return void 0;
|
|
20450
|
+
const out = v.filter((x) => typeof x === "string");
|
|
20451
|
+
return out.length ? out : void 0;
|
|
20452
|
+
}
|
|
20453
|
+
function coercePermissions(v) {
|
|
20454
|
+
const out = {};
|
|
20455
|
+
if (v && typeof v === "object" && !Array.isArray(v)) {
|
|
20456
|
+
for (const [k, val] of Object.entries(v)) {
|
|
20457
|
+
const lvl = asLevel(val);
|
|
20458
|
+
if (lvl) out[k] = lvl;
|
|
20459
|
+
}
|
|
20460
|
+
}
|
|
20461
|
+
return out;
|
|
20462
|
+
}
|
|
20463
|
+
function parsePolicyYaml(text, agentName) {
|
|
20464
|
+
let raw = {};
|
|
20465
|
+
if (text.trim()) {
|
|
20466
|
+
try {
|
|
20467
|
+
const parsed = import_yaml2.default.parse(text);
|
|
20468
|
+
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
20469
|
+
raw = parsed;
|
|
20470
|
+
}
|
|
20471
|
+
} catch {
|
|
20472
|
+
raw = {};
|
|
20473
|
+
}
|
|
20474
|
+
}
|
|
20475
|
+
const toolsAllow = raw.tools && typeof raw.tools === "object" ? asStringArray(raw.tools.allow) : void 0;
|
|
20476
|
+
const toolsDeny = raw.tools && typeof raw.tools === "object" ? asStringArray(raw.tools.deny) : void 0;
|
|
20477
|
+
const rawUnattended = raw.unattended;
|
|
20478
|
+
const unattended = typeof rawUnattended === "string" && UNATTENDED.includes(rawUnattended) ? rawUnattended : "deny";
|
|
20479
|
+
const rawPark = raw.parkTimeoutMs;
|
|
20480
|
+
const parkTimeoutMs = typeof rawPark === "number" && Number.isFinite(rawPark) && rawPark > 0 ? rawPark : void 0;
|
|
20481
|
+
const policy = {
|
|
20482
|
+
version: 1,
|
|
20483
|
+
name: typeof raw.name === "string" ? raw.name : `crew:${agentName}`,
|
|
20484
|
+
description: typeof raw.description === "string" ? raw.description : void 0,
|
|
20485
|
+
onViolation: raw.onViolation === "warn" ? "warn" : "stop",
|
|
20486
|
+
defaultPermission: asLevel(raw.defaultPermission) ?? "ask",
|
|
20487
|
+
mutatingDefault: asLevel(raw.mutatingDefault) ?? "deny",
|
|
20488
|
+
permissions: coercePermissions(raw.permissions),
|
|
20489
|
+
maxTurns: typeof raw.maxTurns === "number" ? raw.maxTurns : void 0,
|
|
20490
|
+
maxToolCalls: typeof raw.maxToolCalls === "number" ? raw.maxToolCalls : void 0,
|
|
20491
|
+
unattended,
|
|
20492
|
+
parkTimeoutMs
|
|
20493
|
+
};
|
|
20494
|
+
if (toolsAllow || toolsDeny) {
|
|
20495
|
+
policy.tools = { ...toolsAllow ? { allow: toolsAllow } : {}, ...toolsDeny ? { deny: toolsDeny } : {} };
|
|
20496
|
+
}
|
|
20497
|
+
return policy;
|
|
20498
|
+
}
|
|
20499
|
+
|
|
20500
|
+
// ../crew/paths.ts
|
|
20501
|
+
var CREW_SEG = "crew";
|
|
20502
|
+
var NAME_RE = /^[A-Za-z0-9][A-Za-z0-9_-]*$/;
|
|
20503
|
+
function isValidAgentName(name) {
|
|
20504
|
+
return NAME_RE.test(name);
|
|
20505
|
+
}
|
|
20506
|
+
|
|
20507
|
+
// ../crew/store.ts
|
|
20508
|
+
var import_yaml3 = __toESM(require_dist(), 1);
|
|
20509
|
+
var TRIGGER_TYPES = [
|
|
20510
|
+
"manual",
|
|
20511
|
+
"file-change",
|
|
20512
|
+
"run-complete",
|
|
20513
|
+
"interval-while-open",
|
|
20514
|
+
"app-init",
|
|
20515
|
+
"workspace-init",
|
|
20516
|
+
"schedule",
|
|
20517
|
+
"continuous",
|
|
20518
|
+
"self-directed",
|
|
20519
|
+
"external-webhook"
|
|
20520
|
+
];
|
|
20521
|
+
async function readOr(files, path, fallback = "") {
|
|
20522
|
+
try {
|
|
20523
|
+
return await files.read(path);
|
|
20524
|
+
} catch {
|
|
20525
|
+
return fallback;
|
|
20526
|
+
}
|
|
20527
|
+
}
|
|
20528
|
+
function parseTriggers(meta) {
|
|
20529
|
+
const raw = meta.triggers;
|
|
20530
|
+
if (!Array.isArray(raw)) return [];
|
|
20531
|
+
const out = [];
|
|
20532
|
+
for (const item of raw) {
|
|
20533
|
+
if (item && typeof item === "object") {
|
|
20534
|
+
const t = item.type;
|
|
20535
|
+
if (typeof t === "string" && TRIGGER_TYPES.includes(t)) {
|
|
20536
|
+
const cfg = item.config;
|
|
20537
|
+
out.push({
|
|
20538
|
+
type: t,
|
|
20539
|
+
config: cfg && typeof cfg === "object" && !Array.isArray(cfg) ? cfg : void 0
|
|
20540
|
+
});
|
|
20541
|
+
}
|
|
20542
|
+
}
|
|
20543
|
+
}
|
|
20544
|
+
return out;
|
|
20545
|
+
}
|
|
20546
|
+
function parseBudget(meta) {
|
|
20547
|
+
const raw = meta.budget;
|
|
20548
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) return {};
|
|
20549
|
+
const o = raw;
|
|
20550
|
+
const out = {};
|
|
20551
|
+
for (const k of ["maxUsd", "maxTokens", "maxMs"]) {
|
|
20552
|
+
const v = o[k];
|
|
20553
|
+
if (typeof v === "number" && v > 0) out[k] = v;
|
|
20554
|
+
}
|
|
20555
|
+
return out;
|
|
20556
|
+
}
|
|
20557
|
+
function parseCanCall(meta) {
|
|
20558
|
+
const raw = meta.canCall;
|
|
20559
|
+
if (!Array.isArray(raw)) return [];
|
|
20560
|
+
return raw.filter((x) => typeof x === "string" && isValidAgentName(x));
|
|
20561
|
+
}
|
|
20562
|
+
function parseSettings(text) {
|
|
20563
|
+
try {
|
|
20564
|
+
const raw = JSON.parse(text);
|
|
20565
|
+
if (raw && typeof raw === "object" && !Array.isArray(raw)) {
|
|
20566
|
+
const o = raw;
|
|
20567
|
+
return {
|
|
20568
|
+
model: typeof o.model === "string" ? o.model : void 0,
|
|
20569
|
+
temperature: typeof o.temperature === "number" ? o.temperature : void 0
|
|
20570
|
+
};
|
|
20571
|
+
}
|
|
20572
|
+
} catch {
|
|
20573
|
+
}
|
|
20574
|
+
return {};
|
|
20575
|
+
}
|
|
20576
|
+
async function loadCrewAgentAt(files, root, name, scope = "workspace") {
|
|
20577
|
+
if (!isValidAgentName(name)) throw new Error(`invalid crew agent name: ${name}`);
|
|
20578
|
+
const dir = `${root}/${name}`;
|
|
20579
|
+
const { meta, body } = parseFrontmatter2(await readOr(files, `${dir}/AGENT.md`));
|
|
20580
|
+
return {
|
|
20581
|
+
name,
|
|
20582
|
+
jobTitle: typeof meta.jobTitle === "string" ? meta.jobTitle : "",
|
|
20583
|
+
description: typeof meta.description === "string" ? meta.description : "",
|
|
20584
|
+
scope,
|
|
20585
|
+
enabled: meta.enabled !== false,
|
|
20586
|
+
// absent/anything-but-false -> enabled
|
|
20587
|
+
triggers: parseTriggers(meta),
|
|
20588
|
+
instructions: body,
|
|
20589
|
+
soul: await readOr(files, `${dir}/SOUL.md`),
|
|
20590
|
+
persona: await readOr(files, `${dir}/PERSONA.md`),
|
|
20591
|
+
policy: parsePolicyYaml(await readOr(files, `${dir}/POLICY.yaml`), name),
|
|
20592
|
+
settings: parseSettings(await readOr(files, `${dir}/settings.json`, "{}")),
|
|
20593
|
+
budget: parseBudget(meta),
|
|
20594
|
+
canCall: parseCanCall(meta)
|
|
20595
|
+
};
|
|
20596
|
+
}
|
|
20597
|
+
async function loadCrewAgentAtIfExists(files, root, name, scope = "workspace") {
|
|
20598
|
+
if (!isValidAgentName(name)) return null;
|
|
20599
|
+
try {
|
|
20600
|
+
const st = await files.stat(`${root}/${name}/AGENT.md`);
|
|
20601
|
+
if (st?.kind !== "file") return null;
|
|
20602
|
+
return await loadCrewAgentAt(files, root, name, scope);
|
|
20603
|
+
} catch {
|
|
20604
|
+
return null;
|
|
20605
|
+
}
|
|
20606
|
+
}
|
|
20607
|
+
|
|
20608
|
+
// ../harness/guardrail/serialize.ts
|
|
20609
|
+
var import_yaml4 = __toESM(require_dist(), 1);
|
|
20610
|
+
|
|
20611
|
+
// ../crew/runtime.ts
|
|
20612
|
+
function buildSystemExtra(def) {
|
|
20613
|
+
const parts = [];
|
|
20614
|
+
if (def.jobTitle?.trim()) parts.push(`--- Role ---
|
|
20615
|
+
${def.jobTitle.trim()}`);
|
|
20616
|
+
if (def.soul.trim()) parts.push(`--- Soul ---
|
|
20617
|
+
${def.soul.trim()}`);
|
|
20618
|
+
if (def.persona.trim()) parts.push(`--- Persona ---
|
|
20619
|
+
${def.persona.trim()}`);
|
|
20620
|
+
if (def.instructions.trim()) parts.push(`--- Instructions ---
|
|
20621
|
+
${def.instructions.trim()}`);
|
|
20622
|
+
return parts.join("\n\n");
|
|
20623
|
+
}
|
|
20624
|
+
|
|
20625
|
+
// src/runAgent.ts
|
|
20626
|
+
function workspaceStateDir() {
|
|
20627
|
+
const fromEnv = process.env.CORENEL_STATE_DIR;
|
|
20628
|
+
return fromEnv && /^\.[A-Za-z0-9][A-Za-z0-9._-]*$/.test(fromEnv) ? fromEnv : stateDirName();
|
|
20629
|
+
}
|
|
20630
|
+
function eventLine(e) {
|
|
20631
|
+
try {
|
|
20632
|
+
return JSON.stringify(e);
|
|
20633
|
+
} catch {
|
|
20634
|
+
const type = e.type;
|
|
20635
|
+
return JSON.stringify({ type: typeof type === "string" ? type : "unknown", unserializable: true });
|
|
20636
|
+
}
|
|
20637
|
+
}
|
|
20638
|
+
async function runCrewAgentCli(opts) {
|
|
20639
|
+
const files = new NodeFileService(opts.cwd);
|
|
20640
|
+
const root = `${workspaceStateDir()}/${CREW_SEG}`;
|
|
20641
|
+
const def = await loadCrewAgentAtIfExists(files, root, opts.agent, "workspace");
|
|
20642
|
+
if (!def) {
|
|
20643
|
+
opts.warn(`no such agent "${opts.agent}" under ${opts.cwd}/${root}`);
|
|
20644
|
+
return 2;
|
|
20645
|
+
}
|
|
20646
|
+
if (!def.enabled) {
|
|
20647
|
+
opts.warn(`agent "${opts.agent}" is disabled; enable it before running`);
|
|
20648
|
+
return 2;
|
|
20649
|
+
}
|
|
20650
|
+
setGatewayBase(opts.base ?? process.env.CORENEL_API_BASE ?? "https://api.corenel.ai/api");
|
|
20651
|
+
const token = await nodeAuthToken().getToken();
|
|
20652
|
+
if (!token) {
|
|
20653
|
+
opts.warn("not signed in: set CORENEL_TOKEN, or run `corenel login` on this machine");
|
|
20654
|
+
return 2;
|
|
20655
|
+
}
|
|
20656
|
+
registerGuard(tokenGuard(() => token));
|
|
20657
|
+
const tools = allTools();
|
|
20658
|
+
const extra = buildSystemExtra(def);
|
|
20659
|
+
let system = extra;
|
|
20660
|
+
try {
|
|
20661
|
+
const base = await composeAgentSystem({
|
|
20662
|
+
mode: "auto",
|
|
20663
|
+
tools: tools.map((t) => ({ name: t.name, description: t.description }))
|
|
20664
|
+
});
|
|
20665
|
+
system = extra ? `${base}
|
|
20666
|
+
|
|
20667
|
+
${extra}` : base;
|
|
20668
|
+
} catch {
|
|
20669
|
+
}
|
|
20670
|
+
const realConsole = { log: console.log, info: console.info, warn: console.warn, debug: console.debug };
|
|
20671
|
+
const toStderr = (...parts) => {
|
|
20672
|
+
opts.warn(parts.map((x) => typeof x === "string" ? x : JSON.stringify(x)).join(" "));
|
|
20673
|
+
};
|
|
20674
|
+
console.log = toStderr;
|
|
20675
|
+
console.info = toStderr;
|
|
20676
|
+
console.warn = toStderr;
|
|
20677
|
+
console.debug = toStderr;
|
|
20678
|
+
const ac = new AbortController();
|
|
20679
|
+
try {
|
|
20680
|
+
const result = await runAgent({
|
|
20681
|
+
client: createChatClient({ getToken: async () => token }),
|
|
20682
|
+
model: opts.model ?? def.settings.model ?? "gpt-4o-mini",
|
|
20683
|
+
system,
|
|
20684
|
+
messages: [{ role: "user", content: opts.input }],
|
|
20685
|
+
tools,
|
|
20686
|
+
toolCtx: nodeToolCtx(ac.signal, { files }),
|
|
20687
|
+
policy: def.policy,
|
|
20688
|
+
signal: ac.signal,
|
|
20689
|
+
onEvent: (e) => opts.emit(eventLine(e))
|
|
20690
|
+
});
|
|
20691
|
+
opts.emit(eventLine({ type: "done", text: result.text }));
|
|
20692
|
+
return 0;
|
|
20693
|
+
} catch (e) {
|
|
20694
|
+
opts.warn(`run failed: ${e instanceof Error ? e.message : String(e)}`);
|
|
20695
|
+
return 1;
|
|
20696
|
+
} finally {
|
|
20697
|
+
Object.assign(console, realConsole);
|
|
20698
|
+
}
|
|
20699
|
+
}
|
|
20700
|
+
|
|
20201
20701
|
// src/cli.ts
|
|
20202
20702
|
function flag(argv, name, fallback) {
|
|
20203
20703
|
const i = argv.indexOf(`--${name}`);
|
|
20204
20704
|
return i >= 0 && argv[i + 1] ? argv[i + 1] : fallback;
|
|
20205
20705
|
}
|
|
20706
|
+
function positional(argv) {
|
|
20707
|
+
const out = [];
|
|
20708
|
+
for (let i = 0; i < argv.length; i++) {
|
|
20709
|
+
if (argv[i].startsWith("--")) {
|
|
20710
|
+
i++;
|
|
20711
|
+
continue;
|
|
20712
|
+
}
|
|
20713
|
+
out.push(argv[i]);
|
|
20714
|
+
}
|
|
20715
|
+
return out;
|
|
20716
|
+
}
|
|
20206
20717
|
function promptOf(argv) {
|
|
20207
20718
|
const parts = [];
|
|
20208
20719
|
for (let i = 0; i < argv.length; i++) {
|
|
@@ -20253,8 +20764,28 @@ async function main() {
|
|
|
20253
20764
|
case "run":
|
|
20254
20765
|
await run(rest);
|
|
20255
20766
|
break;
|
|
20767
|
+
case "run-agent": {
|
|
20768
|
+
const agent = positional(rest)[0];
|
|
20769
|
+
if (!agent) {
|
|
20770
|
+
process.stderr.write('usage: corenel run-agent <name> --input "<text>" [--model M] [--base URL]\n');
|
|
20771
|
+
process.exit(2);
|
|
20772
|
+
}
|
|
20773
|
+
const code = await runCrewAgentCli({
|
|
20774
|
+
cwd: process.cwd(),
|
|
20775
|
+
agent,
|
|
20776
|
+
input: flag(rest, "input", ""),
|
|
20777
|
+
...rest.includes("--model") ? { model: flag(rest, "model", "") } : {},
|
|
20778
|
+
...rest.includes("--base") ? { base: flag(rest, "base", "") } : {},
|
|
20779
|
+
emit: (line) => process.stdout.write(`${line}
|
|
20780
|
+
`),
|
|
20781
|
+
warn: (line) => process.stderr.write(`corenel: ${line}
|
|
20782
|
+
`)
|
|
20783
|
+
});
|
|
20784
|
+
process.exitCode = code;
|
|
20785
|
+
break;
|
|
20786
|
+
}
|
|
20256
20787
|
case "login": {
|
|
20257
|
-
const base = flag(rest, "base", process.env.CORENEL_API_BASE || "https://api.corenel.ai");
|
|
20788
|
+
const base = flag(rest, "base", process.env.CORENEL_API_BASE || "https://api.corenel.ai/api");
|
|
20258
20789
|
await deviceLogin({ base, store: writeAuthToken });
|
|
20259
20790
|
process.stdout.write(`
|
|
20260
20791
|
Logged in. Token saved to ${authTokenPath()}
|
|
@@ -20267,6 +20798,7 @@ Logged in. Token saved to ${authTokenPath()}
|
|
|
20267
20798
|
"",
|
|
20268
20799
|
" corenel login [--base URL] OAuth device flow -> ~/.corenel/token",
|
|
20269
20800
|
' corenel run "<prompt>" [--model M] [--base URL] one-shot turn (needs a login or CORENEL_TOKEN)',
|
|
20801
|
+
' corenel run-agent <name> --input "<text>" run a crew agent; events as JSON Lines on stdout',
|
|
20270
20802
|
"",
|
|
20271
20803
|
" (ask/chat + start --sidecar to follow.)",
|
|
20272
20804
|
""
|
|
@@ -20282,5 +20814,7 @@ function friendlyError(msg) {
|
|
|
20282
20814
|
main().catch((e) => {
|
|
20283
20815
|
process.stderr.write(`corenel: ${friendlyError(e instanceof Error ? e.message : String(e))}
|
|
20284
20816
|
`);
|
|
20285
|
-
process.
|
|
20817
|
+
process.exitCode = 1;
|
|
20818
|
+
const bail = setTimeout(() => process.exit(1), 2e3);
|
|
20819
|
+
bail.unref();
|
|
20286
20820
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@corenel/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Corenel CLI — runs the harness in node, in-proc, no transport. The headless proof the kernel is host-agnostic. (corenel run/ask/chat/login + start --sidecar to follow.)",
|
|
6
6
|
"bin": {
|
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
"openai": "^4.77.0"
|
|
18
18
|
},
|
|
19
19
|
"devDependencies": {
|
|
20
|
+
"@corenel/crew": "workspace:*",
|
|
20
21
|
"@corenel/harness": "workspace:*",
|
|
21
22
|
"@corenel/protocol": "workspace:*",
|
|
22
23
|
"@corenel/tools-node": "workspace:*",
|