@promptbook/cli 0.114.0-35 → 0.114.0-39
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/agents/default/.core/adam.book +33 -0
- package/apps/agents-server/package.json +1 -1
- package/apps/agents-server/scripts/build-agents-server.js +4 -0
- package/apps/agents-server/scripts/build-e2e.js +1 -1
- package/apps/agents-server/src/app/swagger/SwaggerPageClient.tsx +35 -19
- package/apps/agents-server/src/types/swagger-ui-dist.d.ts +5 -0
- package/apps/agents-server/src/utils/agentReferenceResolver/AgentReferenceResolutionIssue.ts +1 -69
- package/apps/agents-server/src/utils/agentReferenceResolver/extractAgentReferenceTokens.ts +1 -61
- package/apps/agents-server/src/utils/explicitFromCommitment.ts +1 -130
- package/apps/agents-server/src/utils/resolveInheritedAgentSource.ts +32 -817
- package/esm/index.es.js +1431 -128
- package/esm/index.es.js.map +1 -1
- package/esm/scripts/run-agent-messages/messages/createAgentRunnerSystemMessage.d.ts +2 -1
- package/esm/scripts/run-codex-prompts/common/resolveCoderAgent.d.ts +11 -0
- package/esm/scripts/run-codex-prompts/git/commitInitializedAgentBooks.d.ts +5 -0
- package/esm/scripts/run-codex-prompts/main/resolvePromptRunner.d.ts +5 -8
- package/esm/scripts/run-codex-prompts/main/runPromptRound.d.ts +2 -4
- package/esm/scripts/run-codex-prompts/prompts/buildPromptRunTraceContent.d.ts +5 -17
- package/esm/scripts/run-codex-prompts/prompts/buildPromptStatusDetails.d.ts +3 -15
- package/esm/scripts/run-codex-prompts/prompts/formatRunnerSignature.d.ts +14 -1
- package/esm/scripts/run-codex-prompts/prompts/markPromptFailed.d.ts +2 -9
- package/esm/src/book-2.0/agent-source/AgentReferenceResolutionIssue.d.ts +45 -0
- package/esm/src/book-2.0/agent-source/createAgentModelRequirements.deduplication.test.d.ts +1 -0
- package/esm/src/book-2.0/agent-source/deduplicateSystemMessage.d.ts +14 -0
- package/esm/src/book-2.0/agent-source/deduplicateSystemMessage.test.d.ts +1 -0
- package/esm/src/book-2.0/agent-source/explicitFromCommitment.d.ts +62 -0
- package/esm/src/book-2.0/agent-source/extractAgentReferenceTokens.d.ts +32 -0
- package/esm/src/book-2.0/agent-source/resolveInheritedAgentSource.d.ts +73 -0
- package/esm/src/cli/$initializePromptbookCliProgram.d.ts +8 -0
- package/esm/src/cli/cli-commands/coder/initializeCoderProjectConfiguration.d.ts +1 -0
- package/esm/src/cli/cli-commands/common/LocalAgentBookCollection.d.ts +46 -0
- package/esm/src/cli/cli-commands/common/createLocalAgentReferenceResolver.d.ts +8 -0
- package/esm/src/cli/cli-commands/common/ensureAdamAgentBook.d.ts +12 -0
- package/esm/src/cli/cli-commands/common/resolveBundledAgentBookPath.d.ts +6 -0
- package/esm/src/cli/cli-commands/common/resolveLocalAgentSource.d.ts +19 -0
- package/esm/src/version.d.ts +1 -1
- package/package.json +2 -3
- package/src/book-2.0/agent-source/AgentReferenceResolutionIssue.ts +75 -0
- package/src/book-2.0/agent-source/createAgentModelRequirementsWithCommitments.ts +3 -2
- package/src/book-2.0/agent-source/deduplicateSystemMessage.ts +327 -0
- package/src/book-2.0/agent-source/explicitFromCommitment.ts +132 -0
- package/src/book-2.0/agent-source/extractAgentReferenceTokens.ts +65 -0
- package/src/book-2.0/agent-source/resolveInheritedAgentSource.ts +841 -0
- package/src/cli/$initializePromptbookCliProgram.ts +87 -0
- package/src/cli/cli-commands/coder/ensureCoderDeveloperAgentFile.ts +2 -28
- package/src/cli/cli-commands/coder/init.ts +3 -1
- package/src/cli/cli-commands/coder/initializeCoderProjectConfiguration.ts +5 -0
- package/src/cli/cli-commands/coder/list.ts +5 -3
- package/src/cli/cli-commands/coder/printInitializationSummary.ts +6 -0
- package/src/cli/cli-commands/coder/run.ts +4 -1
- package/src/cli/cli-commands/coder/server.ts +2 -1
- package/src/cli/cli-commands/common/LocalAgentBookCollection.ts +220 -0
- package/src/cli/cli-commands/common/createLocalAgentReferenceResolver.ts +62 -0
- package/src/cli/cli-commands/common/ensureAdamAgentBook.ts +40 -0
- package/src/cli/cli-commands/common/resolveBundledAgentBookPath.ts +38 -0
- package/src/cli/cli-commands/common/resolveLocalAgentSource.ts +127 -0
- package/src/cli/promptbookCli.ts +2 -87
- package/src/other/templates/getTemplatesPipelineCollection.ts +612 -944
- package/src/version.ts +2 -2
- package/src/versions.txt +4 -0
- package/umd/index.umd.js +1431 -128
- package/umd/index.umd.js.map +1 -1
- package/umd/scripts/run-agent-messages/messages/createAgentRunnerSystemMessage.d.ts +2 -1
- package/umd/scripts/run-codex-prompts/common/resolveCoderAgent.d.ts +11 -0
- package/umd/scripts/run-codex-prompts/git/commitInitializedAgentBooks.d.ts +5 -0
- package/umd/scripts/run-codex-prompts/main/resolvePromptRunner.d.ts +5 -8
- package/umd/scripts/run-codex-prompts/main/runPromptRound.d.ts +2 -4
- package/umd/scripts/run-codex-prompts/prompts/buildPromptRunTraceContent.d.ts +5 -17
- package/umd/scripts/run-codex-prompts/prompts/buildPromptStatusDetails.d.ts +3 -15
- package/umd/scripts/run-codex-prompts/prompts/formatRunnerSignature.d.ts +14 -1
- package/umd/scripts/run-codex-prompts/prompts/markPromptFailed.d.ts +2 -9
- package/umd/src/book-2.0/agent-source/AgentReferenceResolutionIssue.d.ts +45 -0
- package/umd/src/book-2.0/agent-source/createAgentModelRequirements.deduplication.test.d.ts +1 -0
- package/umd/src/book-2.0/agent-source/deduplicateSystemMessage.d.ts +14 -0
- package/umd/src/book-2.0/agent-source/deduplicateSystemMessage.test.d.ts +1 -0
- package/umd/src/book-2.0/agent-source/explicitFromCommitment.d.ts +62 -0
- package/umd/src/book-2.0/agent-source/extractAgentReferenceTokens.d.ts +32 -0
- package/umd/src/book-2.0/agent-source/resolveInheritedAgentSource.d.ts +73 -0
- package/umd/src/cli/$initializePromptbookCliProgram.d.ts +8 -0
- package/umd/src/cli/cli-commands/coder/initializeCoderProjectConfiguration.d.ts +1 -0
- package/umd/src/cli/cli-commands/common/LocalAgentBookCollection.d.ts +46 -0
- package/umd/src/cli/cli-commands/common/createLocalAgentReferenceResolver.d.ts +8 -0
- package/umd/src/cli/cli-commands/common/ensureAdamAgentBook.d.ts +12 -0
- package/umd/src/cli/cli-commands/common/resolveBundledAgentBookPath.d.ts +6 -0
- package/umd/src/cli/cli-commands/common/resolveLocalAgentSource.d.ts +19 -0
- package/umd/src/version.d.ts +1 -1
package/esm/index.es.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import colors from 'colors';
|
|
2
2
|
import commander, { Option } from 'commander';
|
|
3
3
|
import _spaceTrim, { spaceTrim as spaceTrim$1 } from 'spacetrim';
|
|
4
|
-
import { writeFile, stat, readdir, mkdir, readFile, rm, cp, lstat, symlink, rename, unlink, appendFile, realpath, copyFile, statfs, access, constants, watch, rmdir } from 'fs/promises';
|
|
4
|
+
import { writeFile, stat, readdir, mkdir, readFile, rm, cp, lstat, symlink, rename, unlink, appendFile, realpath, copyFile, statfs, access, constants as constants$1, watch, rmdir } from 'fs/promises';
|
|
5
5
|
import { join, delimiter, relative, basename, resolve, dirname, isAbsolute, extname } from 'path';
|
|
6
6
|
import { createHash, randomBytes } from 'crypto';
|
|
7
7
|
import { spawn, spawnSync, execFile } from 'child_process';
|
|
8
8
|
import moment from 'moment';
|
|
9
9
|
import * as fs from 'fs';
|
|
10
|
-
import { createWriteStream, mkdirSync, writeFileSync, statSync, readFileSync, existsSync, promises } from 'fs';
|
|
10
|
+
import { createWriteStream, mkdirSync, writeFileSync, constants, statSync, readFileSync, existsSync, promises } from 'fs';
|
|
11
11
|
import * as dotenv from 'dotenv';
|
|
12
12
|
import * as readline from 'readline';
|
|
13
13
|
import { createInterface, emitKeypressEvents, cursorTo, clearLine } from 'readline';
|
|
@@ -30,9 +30,9 @@ import ignore from 'ignore';
|
|
|
30
30
|
import { EventEmitter } from 'events';
|
|
31
31
|
import { tmpdir } from 'os';
|
|
32
32
|
import { lookup, extension } from 'mime-types';
|
|
33
|
+
import { pathToFileURL } from 'url';
|
|
33
34
|
import papaparse from 'papaparse';
|
|
34
35
|
import '@supabase/supabase-js';
|
|
35
|
-
import { pathToFileURL } from 'url';
|
|
36
36
|
|
|
37
37
|
// ⚠️ WARNING: This code has been generated so that any manual changes will be overwritten
|
|
38
38
|
/**
|
|
@@ -48,12 +48,42 @@ const BOOK_LANGUAGE_VERSION = '2.0.0';
|
|
|
48
48
|
* @generated
|
|
49
49
|
* @see https://github.com/webgptorg/promptbook
|
|
50
50
|
*/
|
|
51
|
-
const PROMPTBOOK_ENGINE_VERSION = '0.114.0-
|
|
51
|
+
const PROMPTBOOK_ENGINE_VERSION = '0.114.0-39';
|
|
52
52
|
/**
|
|
53
53
|
* TODO: string_promptbook_version should be constrained to the all versions of Promptbook engine
|
|
54
54
|
* Note: [💞] Ignore a discrepancy between file name and entity name
|
|
55
55
|
*/
|
|
56
56
|
|
|
57
|
+
/**
|
|
58
|
+
* This error type indicates that you try to use a feature that is not available in the current environment
|
|
59
|
+
*
|
|
60
|
+
* @public exported from `@promptbook/core`
|
|
61
|
+
*/
|
|
62
|
+
class EnvironmentMismatchError extends Error {
|
|
63
|
+
constructor(message) {
|
|
64
|
+
super(message);
|
|
65
|
+
this.name = 'EnvironmentMismatchError';
|
|
66
|
+
Object.setPrototypeOf(this, EnvironmentMismatchError.prototype);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Detects if the code is running in a Node.js environment
|
|
72
|
+
*
|
|
73
|
+
* Note: `$` is used to indicate that this function is not a pure function - it looks at the global object to determine the environment
|
|
74
|
+
*
|
|
75
|
+
* @public exported from `@promptbook/utils`
|
|
76
|
+
*/
|
|
77
|
+
function $isRunningInNode() {
|
|
78
|
+
try {
|
|
79
|
+
return typeof process !== 'undefined' && process.versions != null && process.versions.node != null;
|
|
80
|
+
}
|
|
81
|
+
catch (e) {
|
|
82
|
+
return false;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
// TODO: [🎺]
|
|
86
|
+
|
|
57
87
|
/**
|
|
58
88
|
* Trims string from all 4 sides
|
|
59
89
|
*
|
|
@@ -1289,6 +1319,12 @@ const DEFAULT_INTERMEDIATE_FILES_STRATEGY = 'HIDE_AND_KEEP';
|
|
|
1289
1319
|
* @public exported from `@promptbook/core`
|
|
1290
1320
|
*/
|
|
1291
1321
|
const DEFAULT_MAX_PARALLEL_COUNT = 5; // <- TODO: [🤹♂️]
|
|
1322
|
+
/**
|
|
1323
|
+
* The maximum depth to which recursion can occur
|
|
1324
|
+
*
|
|
1325
|
+
* @public exported from `@promptbook/core`
|
|
1326
|
+
*/
|
|
1327
|
+
const DEFAULT_MAX_RECURSION = 10;
|
|
1292
1328
|
/**
|
|
1293
1329
|
* The maximum number of attempts to execute LLM task before giving up
|
|
1294
1330
|
*
|
|
@@ -1438,36 +1474,6 @@ true);
|
|
|
1438
1474
|
* TODO: [🧠][🧜♂️] Maybe join remoteServerUrl and path into single value
|
|
1439
1475
|
*/
|
|
1440
1476
|
|
|
1441
|
-
/**
|
|
1442
|
-
* This error type indicates that you try to use a feature that is not available in the current environment
|
|
1443
|
-
*
|
|
1444
|
-
* @public exported from `@promptbook/core`
|
|
1445
|
-
*/
|
|
1446
|
-
class EnvironmentMismatchError extends Error {
|
|
1447
|
-
constructor(message) {
|
|
1448
|
-
super(message);
|
|
1449
|
-
this.name = 'EnvironmentMismatchError';
|
|
1450
|
-
Object.setPrototypeOf(this, EnvironmentMismatchError.prototype);
|
|
1451
|
-
}
|
|
1452
|
-
}
|
|
1453
|
-
|
|
1454
|
-
/**
|
|
1455
|
-
* Detects if the code is running in a Node.js environment
|
|
1456
|
-
*
|
|
1457
|
-
* Note: `$` is used to indicate that this function is not a pure function - it looks at the global object to determine the environment
|
|
1458
|
-
*
|
|
1459
|
-
* @public exported from `@promptbook/utils`
|
|
1460
|
-
*/
|
|
1461
|
-
function $isRunningInNode() {
|
|
1462
|
-
try {
|
|
1463
|
-
return typeof process !== 'undefined' && process.versions != null && process.versions.node != null;
|
|
1464
|
-
}
|
|
1465
|
-
catch (e) {
|
|
1466
|
-
return false;
|
|
1467
|
-
}
|
|
1468
|
-
}
|
|
1469
|
-
// TODO: [🎺]
|
|
1470
|
-
|
|
1471
1477
|
/**
|
|
1472
1478
|
* Detects if the code is running in a browser environment in main thread (Not in a web worker)
|
|
1473
1479
|
*
|
|
@@ -5655,6 +5661,13 @@ const PSEUDO_AGENT_REFERENCE_KIND_MAP = {
|
|
|
5655
5661
|
user: 'USER',
|
|
5656
5662
|
...Object.fromEntries(VOID_ALIAS_ENTRIES),
|
|
5657
5663
|
};
|
|
5664
|
+
/**
|
|
5665
|
+
* Maps pseudo-agent kinds to canonical pseudo-agent URLs.
|
|
5666
|
+
*/
|
|
5667
|
+
const PSEUDO_AGENT_URL_BY_KIND = {
|
|
5668
|
+
USER: PSEUDO_AGENT_USER_URL,
|
|
5669
|
+
VOID: PSEUDO_AGENT_VOID_URL,
|
|
5670
|
+
};
|
|
5658
5671
|
/**
|
|
5659
5672
|
* Unwraps a compact reference token (`{Name}` or `@Name`) to plain reference payload.
|
|
5660
5673
|
*
|
|
@@ -5720,6 +5733,28 @@ function resolvePseudoAgentKindFromUrl(agentUrl) {
|
|
|
5720
5733
|
}
|
|
5721
5734
|
return null;
|
|
5722
5735
|
}
|
|
5736
|
+
/**
|
|
5737
|
+
* Checks whether a URL points to a pseudo-agent.
|
|
5738
|
+
*
|
|
5739
|
+
* @param agentUrl - URL to inspect.
|
|
5740
|
+
* @returns True when the URL identifies a pseudo-agent.
|
|
5741
|
+
*
|
|
5742
|
+
* @private internal utility of pseudo-agent resolution
|
|
5743
|
+
*/
|
|
5744
|
+
function isPseudoAgentUrl(agentUrl) {
|
|
5745
|
+
return resolvePseudoAgentKindFromUrl(agentUrl) !== null;
|
|
5746
|
+
}
|
|
5747
|
+
/**
|
|
5748
|
+
* Creates canonical pseudo-agent URL by pseudo-agent kind.
|
|
5749
|
+
*
|
|
5750
|
+
* @param pseudoAgentKind - Pseudo-agent kind.
|
|
5751
|
+
* @returns Canonical pseudo-agent URL.
|
|
5752
|
+
*
|
|
5753
|
+
* @private internal utility of pseudo-agent resolution
|
|
5754
|
+
*/
|
|
5755
|
+
function createPseudoAgentUrl(pseudoAgentKind) {
|
|
5756
|
+
return PSEUDO_AGENT_URL_BY_KIND[pseudoAgentKind];
|
|
5757
|
+
}
|
|
5723
5758
|
/**
|
|
5724
5759
|
* Creates a deterministic human-readable pseudonym for the `{User}` pseudo-agent.
|
|
5725
5760
|
*
|
|
@@ -5758,6 +5793,23 @@ function isVoidPseudoAgentReference(rawReference) {
|
|
|
5758
5793
|
const normalizedReference = normalizePseudoReferenceKey(rawReference);
|
|
5759
5794
|
return LEGACY_VOID_ALIASES.has(normalizedReference);
|
|
5760
5795
|
}
|
|
5796
|
+
/**
|
|
5797
|
+
* Checks whether a pseudo-agent can be used inside the specified commitment.
|
|
5798
|
+
*
|
|
5799
|
+
* `USER` is intentionally disallowed in FROM/IMPORT commitments.
|
|
5800
|
+
*
|
|
5801
|
+
* @param pseudoAgentKind - Pseudo-agent kind to validate.
|
|
5802
|
+
* @param commitmentType - Commitment where it is used.
|
|
5803
|
+
* @returns True when the pseudo-agent is allowed in the commitment.
|
|
5804
|
+
*
|
|
5805
|
+
* @private internal utility of pseudo-agent resolution
|
|
5806
|
+
*/
|
|
5807
|
+
function isPseudoAgentAllowedInCommitment(pseudoAgentKind, commitmentType) {
|
|
5808
|
+
if (pseudoAgentKind === 'USER') {
|
|
5809
|
+
return commitmentType === 'TEAM';
|
|
5810
|
+
}
|
|
5811
|
+
return true;
|
|
5812
|
+
}
|
|
5761
5813
|
// Note: [💞] Ignore a discrepancy between file name and entity name
|
|
5762
5814
|
|
|
5763
5815
|
/**
|
|
@@ -39274,6 +39326,245 @@ function stripInlineKnowledgeMetadata(metadata) {
|
|
|
39274
39326
|
return Object.keys(rest).length > 0 ? rest : undefined;
|
|
39275
39327
|
}
|
|
39276
39328
|
|
|
39329
|
+
/**
|
|
39330
|
+
* Pattern matching a markdown section heading (`## Title`) that separates system-message sections
|
|
39331
|
+
*
|
|
39332
|
+
* @private internal constant of `deduplicateSystemMessage`
|
|
39333
|
+
*/
|
|
39334
|
+
const SYSTEM_MESSAGE_SECTION_HEADING_PATTERN = /^##(?!#)\s*(.+?)\s*$/;
|
|
39335
|
+
/**
|
|
39336
|
+
* Pattern matching a fenced code block delimiter which suspends section and block splitting
|
|
39337
|
+
*
|
|
39338
|
+
* @private internal constant of `deduplicateSystemMessage`
|
|
39339
|
+
*/
|
|
39340
|
+
const CODE_FENCE_PATTERN = /^\s*(?:```|~~~)/;
|
|
39341
|
+
/**
|
|
39342
|
+
* Pattern matching a markdown list item which keeps merged bullet lists visually compact
|
|
39343
|
+
*
|
|
39344
|
+
* @private internal constant of `deduplicateSystemMessage`
|
|
39345
|
+
*/
|
|
39346
|
+
const LIST_ITEM_PATTERN = /^\s*(?:[-*+]|\d+[.)])\s/;
|
|
39347
|
+
/**
|
|
39348
|
+
* Removes duplicated instructions from a generated system message
|
|
39349
|
+
*
|
|
39350
|
+
* Commitments are applied one by one, so a commitment used multiple times in one book repeats its whole
|
|
39351
|
+
* section, including the shared guidance preamble. For example two `WRITING RULES` commitments emit the
|
|
39352
|
+
* `## Writing rules` heading and its guidance paragraph twice. This function merges all sections sharing
|
|
39353
|
+
* one heading into the position of their first occurrence and keeps every identical block only once.
|
|
39354
|
+
*
|
|
39355
|
+
* @param systemMessage The assembled system message which may contain repeated sections and blocks
|
|
39356
|
+
* @returns The system message where each section heading and each identical block appears exactly once
|
|
39357
|
+
*
|
|
39358
|
+
* @private internal utility of `createAgentModelRequirementsWithCommitments`
|
|
39359
|
+
*/
|
|
39360
|
+
function deduplicateSystemMessage(systemMessage) {
|
|
39361
|
+
if (!systemMessage.trim()) {
|
|
39362
|
+
return systemMessage;
|
|
39363
|
+
}
|
|
39364
|
+
return splitSystemMessageIntoRegions(systemMessage)
|
|
39365
|
+
.reduce(mergeRegionSharingHeading, [])
|
|
39366
|
+
.map(removeDuplicateBlocksFromRegion)
|
|
39367
|
+
.map(renderRegion)
|
|
39368
|
+
.filter((renderedRegion) => renderedRegion !== '')
|
|
39369
|
+
.join('\n\n');
|
|
39370
|
+
}
|
|
39371
|
+
/**
|
|
39372
|
+
* Splits the system message into the intro region and one region per `## Title` section
|
|
39373
|
+
*
|
|
39374
|
+
* @param systemMessage The system message to split
|
|
39375
|
+
* @returns Regions in their original order, without empty ones
|
|
39376
|
+
*
|
|
39377
|
+
* @private internal utility of `deduplicateSystemMessage`
|
|
39378
|
+
*/
|
|
39379
|
+
function splitSystemMessageIntoRegions(systemMessage) {
|
|
39380
|
+
const regions = [];
|
|
39381
|
+
let headingLine = null;
|
|
39382
|
+
let bodyLines = [];
|
|
39383
|
+
let isInsideCodeFence = false;
|
|
39384
|
+
for (const line of systemMessage.split(/\r?\n/)) {
|
|
39385
|
+
if (CODE_FENCE_PATTERN.test(line)) {
|
|
39386
|
+
isInsideCodeFence = !isInsideCodeFence;
|
|
39387
|
+
}
|
|
39388
|
+
if (isInsideCodeFence || !SYSTEM_MESSAGE_SECTION_HEADING_PATTERN.test(line)) {
|
|
39389
|
+
bodyLines.push(line);
|
|
39390
|
+
continue;
|
|
39391
|
+
}
|
|
39392
|
+
regions.push(createRegion(headingLine, bodyLines));
|
|
39393
|
+
headingLine = line;
|
|
39394
|
+
bodyLines = [];
|
|
39395
|
+
}
|
|
39396
|
+
regions.push(createRegion(headingLine, bodyLines));
|
|
39397
|
+
return regions.filter((region) => region.headingLine !== null || region.blocks.length > 0);
|
|
39398
|
+
}
|
|
39399
|
+
/**
|
|
39400
|
+
* Creates one region from its heading line and its raw body lines
|
|
39401
|
+
*
|
|
39402
|
+
* @param headingLine The original `## Title` line, or `null` for the intro before the first heading
|
|
39403
|
+
* @param bodyLines The raw lines following the heading line
|
|
39404
|
+
* @returns The region with its body already split into blocks
|
|
39405
|
+
*
|
|
39406
|
+
* @private internal utility of `splitSystemMessageIntoRegions`
|
|
39407
|
+
*/
|
|
39408
|
+
function createRegion(headingLine, bodyLines) {
|
|
39409
|
+
return {
|
|
39410
|
+
titleKey: headingLine === null ? null : normalizeSectionTitle(headingLine),
|
|
39411
|
+
headingLine,
|
|
39412
|
+
isBodySeparatedByBlankLine: bodyLines[0] !== undefined && bodyLines[0].trim() === '',
|
|
39413
|
+
blocks: splitBodyIntoBlocks(bodyLines),
|
|
39414
|
+
};
|
|
39415
|
+
}
|
|
39416
|
+
/**
|
|
39417
|
+
* Normalizes a heading line into a key usable for matching sections which belong together
|
|
39418
|
+
*
|
|
39419
|
+
* @param headingLine The original `## Title` line
|
|
39420
|
+
* @returns Lowercased title without the markdown heading prefix
|
|
39421
|
+
*
|
|
39422
|
+
* @private internal utility of `createRegion`
|
|
39423
|
+
*/
|
|
39424
|
+
function normalizeSectionTitle(headingLine) {
|
|
39425
|
+
var _a, _b;
|
|
39426
|
+
return ((_b = (_a = SYSTEM_MESSAGE_SECTION_HEADING_PATTERN.exec(headingLine)) === null || _a === void 0 ? void 0 : _a[1]) !== null && _b !== void 0 ? _b : headingLine).toLowerCase();
|
|
39427
|
+
}
|
|
39428
|
+
/**
|
|
39429
|
+
* Splits raw body lines into blocks separated by blank lines while keeping fenced code blocks intact
|
|
39430
|
+
*
|
|
39431
|
+
* @param bodyLines The raw lines of one region body
|
|
39432
|
+
* @returns Non-empty blocks in their original order
|
|
39433
|
+
*
|
|
39434
|
+
* @private internal utility of `createRegion`
|
|
39435
|
+
*/
|
|
39436
|
+
function splitBodyIntoBlocks(bodyLines) {
|
|
39437
|
+
const blockTexts = [];
|
|
39438
|
+
let blockLines = [];
|
|
39439
|
+
let isInsideCodeFence = false;
|
|
39440
|
+
for (const line of bodyLines) {
|
|
39441
|
+
if (CODE_FENCE_PATTERN.test(line)) {
|
|
39442
|
+
isInsideCodeFence = !isInsideCodeFence;
|
|
39443
|
+
}
|
|
39444
|
+
if (!isInsideCodeFence && line.trim() === '') {
|
|
39445
|
+
blockTexts.push(blockLines.join('\n'));
|
|
39446
|
+
blockLines = [];
|
|
39447
|
+
continue;
|
|
39448
|
+
}
|
|
39449
|
+
blockLines.push(line);
|
|
39450
|
+
}
|
|
39451
|
+
blockTexts.push(blockLines.join('\n'));
|
|
39452
|
+
return blockTexts
|
|
39453
|
+
.filter((blockText) => blockText.trim() !== '')
|
|
39454
|
+
.map((blockText) => ({ text: blockText, isOpeningMergedSection: false }));
|
|
39455
|
+
}
|
|
39456
|
+
/**
|
|
39457
|
+
* Appends one region to the already merged regions, merging it into an earlier region with the same heading
|
|
39458
|
+
*
|
|
39459
|
+
* @param mergedRegions Regions merged so far, used as the reducer accumulator
|
|
39460
|
+
* @param region The next region in original order
|
|
39461
|
+
* @returns The accumulator with the region either appended or merged into its earlier twin
|
|
39462
|
+
*
|
|
39463
|
+
* @private internal utility of `deduplicateSystemMessage`
|
|
39464
|
+
*/
|
|
39465
|
+
function mergeRegionSharingHeading(mergedRegions, region) {
|
|
39466
|
+
const existingRegionIndex = mergedRegions.findIndex((mergedRegion) => region.titleKey !== null && mergedRegion.titleKey === region.titleKey);
|
|
39467
|
+
if (existingRegionIndex === -1) {
|
|
39468
|
+
return [...mergedRegions, region];
|
|
39469
|
+
}
|
|
39470
|
+
return mergedRegions.map((mergedRegion, index) => index !== existingRegionIndex
|
|
39471
|
+
? mergedRegion
|
|
39472
|
+
: {
|
|
39473
|
+
...mergedRegion,
|
|
39474
|
+
blocks: [...mergedRegion.blocks, ...markFirstBlockAsOpeningMergedSection(region.blocks)],
|
|
39475
|
+
});
|
|
39476
|
+
}
|
|
39477
|
+
/**
|
|
39478
|
+
* Marks the first block of a merged section occurrence so the merge seam can be rendered as one list
|
|
39479
|
+
*
|
|
39480
|
+
* @param blocks The blocks of the section occurrence being merged into an earlier section
|
|
39481
|
+
* @returns The same blocks with the first one marked as opening a merged section
|
|
39482
|
+
*
|
|
39483
|
+
* @private internal utility of `mergeRegionSharingHeading`
|
|
39484
|
+
*/
|
|
39485
|
+
function markFirstBlockAsOpeningMergedSection(blocks) {
|
|
39486
|
+
return blocks.map((block, index) => (index === 0 ? { ...block, isOpeningMergedSection: true } : block));
|
|
39487
|
+
}
|
|
39488
|
+
/**
|
|
39489
|
+
* Keeps only the first occurrence of every identical block inside one region
|
|
39490
|
+
*
|
|
39491
|
+
* @param region The region whose blocks may repeat
|
|
39492
|
+
* @returns The region without repeated blocks
|
|
39493
|
+
*
|
|
39494
|
+
* @private internal utility of `deduplicateSystemMessage`
|
|
39495
|
+
*/
|
|
39496
|
+
function removeDuplicateBlocksFromRegion(region) {
|
|
39497
|
+
const alreadyRenderedTexts = new Set();
|
|
39498
|
+
const uniqueBlocks = [];
|
|
39499
|
+
let isMergeSeamPending = false;
|
|
39500
|
+
for (const block of region.blocks) {
|
|
39501
|
+
if (alreadyRenderedTexts.has(block.text)) {
|
|
39502
|
+
// Note: A removed block must still hand its merge seam over to the next block which survives
|
|
39503
|
+
isMergeSeamPending = isMergeSeamPending || block.isOpeningMergedSection;
|
|
39504
|
+
continue;
|
|
39505
|
+
}
|
|
39506
|
+
alreadyRenderedTexts.add(block.text);
|
|
39507
|
+
uniqueBlocks.push({
|
|
39508
|
+
text: block.text,
|
|
39509
|
+
isOpeningMergedSection: block.isOpeningMergedSection || isMergeSeamPending,
|
|
39510
|
+
});
|
|
39511
|
+
isMergeSeamPending = false;
|
|
39512
|
+
}
|
|
39513
|
+
return { ...region, blocks: uniqueBlocks };
|
|
39514
|
+
}
|
|
39515
|
+
/**
|
|
39516
|
+
* Renders one region back into its markdown representation
|
|
39517
|
+
*
|
|
39518
|
+
* @param region The region to render
|
|
39519
|
+
* @returns The heading line together with its joined blocks
|
|
39520
|
+
*
|
|
39521
|
+
* @private internal utility of `deduplicateSystemMessage`
|
|
39522
|
+
*/
|
|
39523
|
+
function renderRegion(region) {
|
|
39524
|
+
const body = joinBlocks(region.blocks);
|
|
39525
|
+
if (region.headingLine === null) {
|
|
39526
|
+
return body;
|
|
39527
|
+
}
|
|
39528
|
+
if (body === '') {
|
|
39529
|
+
return region.headingLine;
|
|
39530
|
+
}
|
|
39531
|
+
return `${region.headingLine}${region.isBodySeparatedByBlankLine ? '\n\n' : '\n'}${body}`;
|
|
39532
|
+
}
|
|
39533
|
+
/**
|
|
39534
|
+
* Joins blocks of one region back together
|
|
39535
|
+
*
|
|
39536
|
+
* @param blocks The blocks to join in their original order
|
|
39537
|
+
* @returns The joined body of one region
|
|
39538
|
+
*
|
|
39539
|
+
* @private internal utility of `renderRegion`
|
|
39540
|
+
*/
|
|
39541
|
+
function joinBlocks(blocks) {
|
|
39542
|
+
return blocks
|
|
39543
|
+
.map((block, index) => index === 0 ? block.text : `${createBlockSeparator(blocks[index - 1], block)}${block.text}`)
|
|
39544
|
+
.join('');
|
|
39545
|
+
}
|
|
39546
|
+
/**
|
|
39547
|
+
* Chooses the separator between two neighboring blocks
|
|
39548
|
+
*
|
|
39549
|
+
* Blocks are normally separated by a blank line, exactly as they were written. Only where two sections were
|
|
39550
|
+
* merged together their lists are joined into one compact list instead of two separate ones.
|
|
39551
|
+
*
|
|
39552
|
+
* @param previousBlock The block rendered before the separator
|
|
39553
|
+
* @param nextBlock The block rendered after the separator
|
|
39554
|
+
* @returns Either a single or a double newline
|
|
39555
|
+
*
|
|
39556
|
+
* @private internal utility of `joinBlocks`
|
|
39557
|
+
*/
|
|
39558
|
+
function createBlockSeparator(previousBlock, nextBlock) {
|
|
39559
|
+
if (!nextBlock.isOpeningMergedSection) {
|
|
39560
|
+
return '\n\n';
|
|
39561
|
+
}
|
|
39562
|
+
const previousBlockLines = previousBlock.text.split('\n');
|
|
39563
|
+
const isListContinuing = LIST_ITEM_PATTERN.test(previousBlockLines[previousBlockLines.length - 1]) &&
|
|
39564
|
+
LIST_ITEM_PATTERN.test(nextBlock.text.split('\n')[0]);
|
|
39565
|
+
return isListContinuing ? '\n' : '\n\n';
|
|
39566
|
+
}
|
|
39567
|
+
|
|
39277
39568
|
/**
|
|
39278
39569
|
* Removes single-hash comment lines (`# Comment`) from a system message
|
|
39279
39570
|
* This is used to clean up the final system message before sending it to the AI model
|
|
@@ -39347,14 +39638,14 @@ function createInitialAgentModelRequirements(agentName, modelName) {
|
|
|
39347
39638
|
* Performs the final system-message cleanup pass after all other augmentation steps are complete.
|
|
39348
39639
|
*
|
|
39349
39640
|
* @param requirements - Fully built requirements before final cleanup.
|
|
39350
|
-
* @returns Requirements with comment lines removed
|
|
39641
|
+
* @returns Requirements with comment lines removed and repeated instructions deduplicated in the final system message.
|
|
39351
39642
|
*
|
|
39352
39643
|
* @private internal utility of `createAgentModelRequirementsWithCommitments`
|
|
39353
39644
|
*/
|
|
39354
39645
|
function finalizeRequirements(requirements) {
|
|
39355
39646
|
return {
|
|
39356
39647
|
...requirements,
|
|
39357
|
-
systemMessage: removeCommentsFromSystemMessage(requirements.systemMessage),
|
|
39648
|
+
systemMessage: deduplicateSystemMessage(removeCommentsFromSystemMessage(requirements.systemMessage)),
|
|
39358
39649
|
};
|
|
39359
39650
|
}
|
|
39360
39651
|
|
|
@@ -39443,8 +39734,8 @@ function extractMcpServers(agentSource) {
|
|
|
39443
39734
|
/**
|
|
39444
39735
|
* Compiles agent source into the behavior text passed to CLI harness runners.
|
|
39445
39736
|
*/
|
|
39446
|
-
async function createAgentRunnerSystemMessage(agentSource) {
|
|
39447
|
-
return formatAgentModelRequirementsForRunner(await createAgentModelRequirements(agentSource));
|
|
39737
|
+
async function createAgentRunnerSystemMessage(agentSource, options) {
|
|
39738
|
+
return formatAgentModelRequirementsForRunner(await createAgentModelRequirements(agentSource, undefined, undefined, undefined, options));
|
|
39448
39739
|
}
|
|
39449
39740
|
/**
|
|
39450
39741
|
* Formats prepared model requirements for a text-only CLI harness prompt.
|
|
@@ -43440,6 +43731,59 @@ function buildPromptSlug$1(templateSlugPrefix, title) {
|
|
|
43440
43731
|
// Note: [🟡] Code for CLI command [generate-boilerplates](src/cli/cli-commands/coder/generate-boilerplates.ts) should never be published outside of `@promptbook/cli`
|
|
43441
43732
|
// Note: [💞] Ignore a discrepancy between file name and entity name
|
|
43442
43733
|
|
|
43734
|
+
/**
|
|
43735
|
+
* Locates a bundled agent in either the source checkout or the generated CLI package.
|
|
43736
|
+
*
|
|
43737
|
+
* @private internal utility of CLI agent initialization
|
|
43738
|
+
*/
|
|
43739
|
+
async function resolveBundledAgentBookPath(relativeFilePath) {
|
|
43740
|
+
const candidates = [
|
|
43741
|
+
join(__dirname, '..', relativeFilePath),
|
|
43742
|
+
join(__dirname, '..', '..', '..', '..', relativeFilePath),
|
|
43743
|
+
];
|
|
43744
|
+
for (const candidate of candidates) {
|
|
43745
|
+
if (await stat(candidate).then((entry) => entry.isFile(), () => false)) {
|
|
43746
|
+
return candidate;
|
|
43747
|
+
}
|
|
43748
|
+
}
|
|
43749
|
+
throw new NotFoundError(spaceTrim$1((block) => `
|
|
43750
|
+
Cannot find the bundled agent book \`${relativeFilePath}\`.
|
|
43751
|
+
|
|
43752
|
+
Checked:
|
|
43753
|
+
${block(candidates.map((candidate) => `- \`${candidate}\``).join('\n'))}
|
|
43754
|
+
`));
|
|
43755
|
+
}
|
|
43756
|
+
|
|
43757
|
+
/**
|
|
43758
|
+
* Adam's location relative to a directory of local agents.
|
|
43759
|
+
*
|
|
43760
|
+
* @private internal constant of CLI agent initialization
|
|
43761
|
+
*/
|
|
43762
|
+
const ADAM_AGENT_BOOK_RELATIVE_PATH = '.core/adam.book';
|
|
43763
|
+
/**
|
|
43764
|
+
* Creates the same Adam book used by the Agent Server without overwriting a project-owned book.
|
|
43765
|
+
*
|
|
43766
|
+
* @private internal utility of CLI agent initialization
|
|
43767
|
+
*/
|
|
43768
|
+
async function ensureAdamAgentBook(agentDirectoryPath) {
|
|
43769
|
+
const adamBookPath = join(agentDirectoryPath, ADAM_AGENT_BOOK_RELATIVE_PATH);
|
|
43770
|
+
if (await stat(adamBookPath).then((entry) => entry.isFile(), () => false)) {
|
|
43771
|
+
return 'unchanged';
|
|
43772
|
+
}
|
|
43773
|
+
const bundledAdamBookPath = await resolveBundledAgentBookPath('agents/default/.core/adam.book');
|
|
43774
|
+
await mkdir(dirname(adamBookPath), { recursive: true });
|
|
43775
|
+
try {
|
|
43776
|
+
await copyFile(bundledAdamBookPath, adamBookPath, constants.COPYFILE_EXCL);
|
|
43777
|
+
return 'created';
|
|
43778
|
+
}
|
|
43779
|
+
catch (error) {
|
|
43780
|
+
if (error.code === 'EEXIST') {
|
|
43781
|
+
return 'unchanged';
|
|
43782
|
+
}
|
|
43783
|
+
throw error;
|
|
43784
|
+
}
|
|
43785
|
+
}
|
|
43786
|
+
|
|
43443
43787
|
/**
|
|
43444
43788
|
* Asks the user in the terminal to confirm one optional change.
|
|
43445
43789
|
*
|
|
@@ -44243,29 +44587,9 @@ async function ensureCoderDeveloperAgentFile(projectPath) {
|
|
|
44243
44587
|
if (await isExistingFile$2(absoluteFilePath)) {
|
|
44244
44588
|
return 'unchanged';
|
|
44245
44589
|
}
|
|
44246
|
-
await copyFile(await
|
|
44590
|
+
await copyFile(await resolveBundledAgentBookPath(DEFAULT_CODER_DEVELOPER_AGENT_SOURCE_FILE_PATH), absoluteFilePath);
|
|
44247
44591
|
return 'created';
|
|
44248
44592
|
}
|
|
44249
|
-
/**
|
|
44250
|
-
* Resolves the bundled developer agent from a source checkout or generated CLI package.
|
|
44251
|
-
*/
|
|
44252
|
-
async function resolveDefaultCoderDeveloperAgentFilePath() {
|
|
44253
|
-
const candidates = [
|
|
44254
|
-
join(__dirname, '..', DEFAULT_CODER_DEVELOPER_AGENT_SOURCE_FILE_PATH),
|
|
44255
|
-
join(__dirname, '..', '..', '..', '..', DEFAULT_CODER_DEVELOPER_AGENT_SOURCE_FILE_PATH),
|
|
44256
|
-
];
|
|
44257
|
-
for (const candidate of candidates) {
|
|
44258
|
-
if (await isExistingFile$2(candidate)) {
|
|
44259
|
-
return candidate;
|
|
44260
|
-
}
|
|
44261
|
-
}
|
|
44262
|
-
throw new NotAllowed(spaceTrim$1(`
|
|
44263
|
-
Cannot find the bundled Promptbook developer agent.
|
|
44264
|
-
|
|
44265
|
-
Checked:
|
|
44266
|
-
${candidates.map((candidate) => `- \`${candidate}\``).join('\n')}
|
|
44267
|
-
`));
|
|
44268
|
-
}
|
|
44269
44593
|
/**
|
|
44270
44594
|
* Checks whether a path exists and is a file.
|
|
44271
44595
|
*/
|
|
@@ -44748,6 +45072,7 @@ async function initializeCoderProjectConfiguration(projectPath) {
|
|
|
44748
45072
|
const promptsDoneDirectoryStatus = await ensureDirectory(projectPath, PROMPTS_DONE_DIRECTORY_PATH);
|
|
44749
45073
|
const promptsTemplatesDirectoryStatus = await ensureDirectory(projectPath, PROMPTS_TEMPLATES_DIRECTORY_PATH);
|
|
44750
45074
|
const agentsDirectoryStatus = await ensureDirectory(projectPath, CODER_AGENTS_DIRECTORY_PATH);
|
|
45075
|
+
const adamAgentFileStatus = await ensureAdamAgentBook(join(projectPath, CODER_AGENTS_DIRECTORY_PATH));
|
|
44751
45076
|
const { envFileStatus, initializedEnvVariableNames } = await ensureCoderEnvFile(projectPath);
|
|
44752
45077
|
const gitignoreFileStatus = await ensureCoderGitignoreFile(projectPath);
|
|
44753
45078
|
const { status: packageJsonFileStatus, addedEntryKeys: addedPackageJsonScriptNames } = await ensureCoderPackageJsonFile(projectPath);
|
|
@@ -44758,6 +45083,7 @@ async function initializeCoderProjectConfiguration(projectPath) {
|
|
|
44758
45083
|
promptsDoneDirectoryStatus,
|
|
44759
45084
|
promptsTemplatesDirectoryStatus,
|
|
44760
45085
|
agentsDirectoryStatus,
|
|
45086
|
+
adamAgentFileStatus,
|
|
44761
45087
|
envFileStatus,
|
|
44762
45088
|
gitignoreFileStatus,
|
|
44763
45089
|
packageJsonFileStatus,
|
|
@@ -44780,6 +45106,7 @@ function printInitializationSummary(summary) {
|
|
|
44780
45106
|
printInitializationStatusLine('prompts/done/', summary.promptsDoneDirectoryStatus);
|
|
44781
45107
|
printInitializationStatusLine('prompts/templates/', summary.promptsTemplatesDirectoryStatus);
|
|
44782
45108
|
printInitializationStatusLine('agents/', summary.agentsDirectoryStatus);
|
|
45109
|
+
printInitializationStatusLine(`${CODER_AGENTS_DIRECTORY_PATH}/${ADAM_AGENT_BOOK_RELATIVE_PATH}`, summary.adamAgentFileStatus);
|
|
44783
45110
|
printInitializationStatusLine('.env', summary.envFileStatus);
|
|
44784
45111
|
printInitializationStatusLine('.gitignore', summary.gitignoreFileStatus);
|
|
44785
45112
|
printInitializationStatusLine('package.json', summary.packageJsonFileStatus);
|
|
@@ -44854,6 +45181,7 @@ function $initializeCoderInitCommand(program) {
|
|
|
44854
45181
|
- prompts/done/
|
|
44855
45182
|
${block(listDefaultCoderProjectPromptTemplateDisplayPaths())}
|
|
44856
45183
|
- ${CODER_DEVELOPER_AGENT_FILE_PATH}
|
|
45184
|
+
- ${CODER_AGENTS_DIRECTORY_PATH}/${ADAM_AGENT_BOOK_RELATIVE_PATH}
|
|
44857
45185
|
- ${AGENTS_FILE_PATH}
|
|
44858
45186
|
- .gitignore with local artifacts from every supported harness
|
|
44859
45187
|
- package.json
|
|
@@ -44998,8 +45326,7 @@ function $initializeCoderListCommand(program) {
|
|
|
44998
45326
|
const runnerOptions = normalizePromptRunnerSelectionCliOptions(cliOptions, { isAgentRequired: false });
|
|
44999
45327
|
const resolvedCoderAgentBook = agent === undefined
|
|
45000
45328
|
? undefined
|
|
45001
|
-
: await (await Promise.resolve().then(function () { return resolveCoderAgent$1; }))
|
|
45002
|
-
.resolveCoderAgentBook(agent, process.cwd());
|
|
45329
|
+
: await (await Promise.resolve().then(function () { return resolveCoderAgent$1; })).resolveCoderAgentBook(agent, process.cwd());
|
|
45003
45330
|
const promptRunnerIdentity = runnerOptions.agentName === undefined &&
|
|
45004
45331
|
runnerOptions.model === undefined &&
|
|
45005
45332
|
resolvedCoderAgentBook === undefined
|
|
@@ -45756,6 +46083,8 @@ function $initializeCoderRunCommand(program) {
|
|
|
45756
46083
|
${block(QUESTIONS_DESCRIPTION)}
|
|
45757
46084
|
|
|
45758
46085
|
Features:
|
|
46086
|
+
- Resolves FROM, IMPORT and TEAM by agent name, book-relative path, project path or URL
|
|
46087
|
+
- Creates a missing .core/adam.book beside the selected agent for default inheritance
|
|
45759
46088
|
- Automatically stages and commits changes with agent identity unless --no-commit is used
|
|
45760
46089
|
- Commits only the prompt file and the files the coding agent has changed, leaving unrelated changes alone
|
|
45761
46090
|
- Refuses to start on a dirty working tree unless --git-changes says what should happen with the changes
|
|
@@ -46729,7 +47058,7 @@ function $provideFilesystemForNode(options) {
|
|
|
46729
47058
|
return {
|
|
46730
47059
|
stat,
|
|
46731
47060
|
access,
|
|
46732
|
-
constants,
|
|
47061
|
+
constants: constants$1,
|
|
46733
47062
|
readFile,
|
|
46734
47063
|
writeFile,
|
|
46735
47064
|
readdir,
|
|
@@ -58701,6 +59030,43 @@ const DEPRECATED_TOP_LEVEL_COMMAND_MESSAGES = {
|
|
|
58701
59030
|
'start-agents-server': 'Use `ptbk agents-server start` instead.',
|
|
58702
59031
|
'start-pipelines-server': OLD_PIPELINE_SYSTEM_DEPRECATION_MESSAGE,
|
|
58703
59032
|
};
|
|
59033
|
+
/**
|
|
59034
|
+
* Registers the CLI commands on a fresh Commander program without parsing arguments or running an action.
|
|
59035
|
+
* Tests can configure output and exit handling before registration, so subcommands inherit those settings.
|
|
59036
|
+
*
|
|
59037
|
+
* @private internal utility of `promptbookCli`
|
|
59038
|
+
*/
|
|
59039
|
+
function $initializePromptbookCliProgram(program) {
|
|
59040
|
+
program.name('promptbook');
|
|
59041
|
+
program.alias('ptbk');
|
|
59042
|
+
program.version(PROMPTBOOK_ENGINE_VERSION);
|
|
59043
|
+
program.description(CLAIM);
|
|
59044
|
+
// Commands are listed in registration order. Keep `coder` first and hide deprecated commands below.
|
|
59045
|
+
$initializeCoderCommand(program);
|
|
59046
|
+
$initializeAgentCommand(program);
|
|
59047
|
+
$initializeAgentFolderCommand(program);
|
|
59048
|
+
$initializeAgentsServerCommand(program);
|
|
59049
|
+
$initializeAboutCommand(program);
|
|
59050
|
+
$initializeHelloCommand(program);
|
|
59051
|
+
$initializeRunCommand(program);
|
|
59052
|
+
$initializeLoginCommand(program);
|
|
59053
|
+
$initializeMakeCommand(program);
|
|
59054
|
+
$initializePrettifyCommand(program);
|
|
59055
|
+
$initializeTestCommand(program);
|
|
59056
|
+
$initializeListModelsCommand(program);
|
|
59057
|
+
$initializeListScrapersCommand(program);
|
|
59058
|
+
$initializeStartAgentsServerCommand(program);
|
|
59059
|
+
$initializeStartPipelinesServerCommand(program);
|
|
59060
|
+
for (const command of program.commands) {
|
|
59061
|
+
const deprecationMessage = DEPRECATED_TOP_LEVEL_COMMAND_MESSAGES[command.name()];
|
|
59062
|
+
if (deprecationMessage !== undefined) {
|
|
59063
|
+
$deprecateCliCommand(command, deprecationMessage);
|
|
59064
|
+
}
|
|
59065
|
+
}
|
|
59066
|
+
program.commands.forEach($addGlobalOptionsToCommand);
|
|
59067
|
+
}
|
|
59068
|
+
// Note: [🟡] Code for CLI command registration [$initializePromptbookCliProgram](src/cli/$initializePromptbookCliProgram.ts) should never be published outside of `@promptbook/cli`
|
|
59069
|
+
|
|
58704
59070
|
/**
|
|
58705
59071
|
* Raw top-level CLI arguments that print the Promptbook version.
|
|
58706
59072
|
*
|
|
@@ -58733,32 +59099,7 @@ async function promptbookCli() {
|
|
|
58733
59099
|
console.info(colors.gray(`Promptbook CLI version ${PROMPTBOOK_ENGINE_VERSION} in ${__filename.split('\\').join('/')}`));
|
|
58734
59100
|
}
|
|
58735
59101
|
const program = new commander.Command();
|
|
58736
|
-
program
|
|
58737
|
-
program.alias('ptbk');
|
|
58738
|
-
program.version(PROMPTBOOK_ENGINE_VERSION);
|
|
58739
|
-
program.description(CLAIM);
|
|
58740
|
-
// Note: These options are valid for all commands
|
|
58741
|
-
// Note: Commands are listed in the help in the order they are registered,
|
|
58742
|
-
// `coder` is the most used one so it goes first and the deprecated ones,
|
|
58743
|
-
// which `$deprecateTopLevelCommands` hides from the help entirely, go last
|
|
58744
|
-
$initializeCoderCommand(program);
|
|
58745
|
-
$initializeAgentCommand(program);
|
|
58746
|
-
$initializeAgentFolderCommand(program);
|
|
58747
|
-
$initializeAgentsServerCommand(program);
|
|
58748
|
-
$initializeAboutCommand(program);
|
|
58749
|
-
$initializeHelloCommand(program);
|
|
58750
|
-
$initializeRunCommand(program);
|
|
58751
|
-
$initializeLoginCommand(program);
|
|
58752
|
-
$initializeMakeCommand(program);
|
|
58753
|
-
$initializePrettifyCommand(program);
|
|
58754
|
-
$initializeTestCommand(program);
|
|
58755
|
-
$initializeListModelsCommand(program);
|
|
58756
|
-
$initializeListScrapersCommand(program);
|
|
58757
|
-
$initializeStartAgentsServerCommand(program);
|
|
58758
|
-
$initializeStartPipelinesServerCommand(program);
|
|
58759
|
-
$deprecateTopLevelCommands(program);
|
|
58760
|
-
// TODO: [🧠] Should it be here or not> $addGlobalOptionsToCommand(program);
|
|
58761
|
-
program.commands.forEach($addGlobalOptionsToCommand);
|
|
59102
|
+
$initializePromptbookCliProgram(program);
|
|
58762
59103
|
// Note: There is no default command, so `ptbk` without a subcommand asks for one
|
|
58763
59104
|
// instead of running the deprecated `ptbk run`
|
|
58764
59105
|
if (commandLineArguments.length === 0) {
|
|
@@ -58775,17 +59116,6 @@ function isTopLevelVersionRequested(commandLineArguments) {
|
|
|
58775
59116
|
const firstCommandLineArgument = commandLineArguments[0];
|
|
58776
59117
|
return firstCommandLineArgument !== undefined && VERSION_OPTION_ARGUMENTS.has(firstCommandLineArgument);
|
|
58777
59118
|
}
|
|
58778
|
-
/**
|
|
58779
|
-
* Marks each configured top-level legacy command as deprecated, which keeps it usable but takes it out of the help.
|
|
58780
|
-
*/
|
|
58781
|
-
function $deprecateTopLevelCommands(program) {
|
|
58782
|
-
for (const command of program.commands) {
|
|
58783
|
-
const deprecationMessage = DEPRECATED_TOP_LEVEL_COMMAND_MESSAGES[command.name()];
|
|
58784
|
-
if (deprecationMessage !== undefined) {
|
|
58785
|
-
$deprecateCliCommand(command, deprecationMessage);
|
|
58786
|
-
}
|
|
58787
|
-
}
|
|
58788
|
-
}
|
|
58789
59119
|
// Note: [🟡] Code for CLI program [promptbookCli](src/cli/promptbookCli.ts) should never be published outside of `@promptbook/cli`
|
|
58790
59120
|
// TODO: [🥠] Do not export, its just for CLI script
|
|
58791
59121
|
// TODO: [🕌] When more functionalities, rename
|
|
@@ -75589,6 +75919,929 @@ var findUnwrittenPrompts$1 = /*#__PURE__*/Object.freeze({
|
|
|
75589
75919
|
findUnwrittenPrompts: findUnwrittenPrompts
|
|
75590
75920
|
});
|
|
75591
75921
|
|
|
75922
|
+
/**
|
|
75923
|
+
* Commitment keyword that declares the parent agent of one book.
|
|
75924
|
+
*
|
|
75925
|
+
* @private utility of Agents Server inheritance resolution
|
|
75926
|
+
*/
|
|
75927
|
+
const FROM_COMMITMENT_TYPE = 'FROM';
|
|
75928
|
+
/**
|
|
75929
|
+
* Matches one standalone `FROM` commitment line and captures its inline content.
|
|
75930
|
+
*
|
|
75931
|
+
* The Book parser accepts horizontal whitespace between a commitment keyword and its value, so inheritance resolution
|
|
75932
|
+
* must do the same. Keeping this pattern here makes every server-side consumer agree on which `FROM` lines are real.
|
|
75933
|
+
*
|
|
75934
|
+
* @private utility of Agents Server inheritance resolution
|
|
75935
|
+
*/
|
|
75936
|
+
const FROM_COMMITMENT_LINE_PATTERN = new RegExp(`^${FROM_COMMITMENT_TYPE}(?:\\s+(.*))?$`);
|
|
75937
|
+
/**
|
|
75938
|
+
* Collects every explicit single-line `FROM` commitment of one book.
|
|
75939
|
+
*
|
|
75940
|
+
* This lightweight parser is intentionally limited to the subset needed by inheritance
|
|
75941
|
+
* resolution so it stays safe to bundle into the Next.js proxy path.
|
|
75942
|
+
*
|
|
75943
|
+
* @param sourceLines - Book source already split into lines.
|
|
75944
|
+
* @returns Found `FROM` commitments in source order, empty when the book declares no parent.
|
|
75945
|
+
*
|
|
75946
|
+
* @private utility of Agents Server inheritance resolution
|
|
75947
|
+
*/
|
|
75948
|
+
function collectExplicitFromCommitments(sourceLines) {
|
|
75949
|
+
const explicitFromCommitments = [];
|
|
75950
|
+
let hasSeenTitle = false;
|
|
75951
|
+
let isInsideCodeBlock = false;
|
|
75952
|
+
for (let lineIndex = 0; lineIndex < sourceLines.length; lineIndex++) {
|
|
75953
|
+
const trimmedLine = (sourceLines[lineIndex] || '').trim();
|
|
75954
|
+
if (!hasSeenTitle) {
|
|
75955
|
+
if (!trimmedLine) {
|
|
75956
|
+
continue;
|
|
75957
|
+
}
|
|
75958
|
+
hasSeenTitle = true;
|
|
75959
|
+
continue;
|
|
75960
|
+
}
|
|
75961
|
+
if (trimmedLine.startsWith('```')) {
|
|
75962
|
+
isInsideCodeBlock = !isInsideCodeBlock;
|
|
75963
|
+
continue;
|
|
75964
|
+
}
|
|
75965
|
+
if (isInsideCodeBlock) {
|
|
75966
|
+
continue;
|
|
75967
|
+
}
|
|
75968
|
+
const fromCommitmentMatch = FROM_COMMITMENT_LINE_PATTERN.exec(trimmedLine);
|
|
75969
|
+
if (fromCommitmentMatch) {
|
|
75970
|
+
explicitFromCommitments.push({
|
|
75971
|
+
lineIndex,
|
|
75972
|
+
content: (fromCommitmentMatch[1] || '').trim(),
|
|
75973
|
+
});
|
|
75974
|
+
}
|
|
75975
|
+
}
|
|
75976
|
+
return explicitFromCommitments;
|
|
75977
|
+
}
|
|
75978
|
+
/**
|
|
75979
|
+
* Returns the effective explicit `FROM` commitment of one book.
|
|
75980
|
+
*
|
|
75981
|
+
* A book may repeat `FROM`, in which case the last one wins and overrides every earlier one.
|
|
75982
|
+
*
|
|
75983
|
+
* @param agentSource - Raw book source.
|
|
75984
|
+
* @returns The last explicit `FROM` commitment, or `undefined` when the book declares no parent.
|
|
75985
|
+
*
|
|
75986
|
+
* @private utility of Agents Server inheritance resolution
|
|
75987
|
+
*/
|
|
75988
|
+
function getEffectiveExplicitFromCommitment(agentSource) {
|
|
75989
|
+
const explicitFromCommitments = collectExplicitFromCommitments(agentSource.split(/\r?\n/));
|
|
75990
|
+
return explicitFromCommitments[explicitFromCommitments.length - 1];
|
|
75991
|
+
}
|
|
75992
|
+
/**
|
|
75993
|
+
* Returns the effective explicit `FROM` commitment content of one book.
|
|
75994
|
+
*
|
|
75995
|
+
* A book may repeat `FROM`, in which case the last one wins and overrides every earlier one.
|
|
75996
|
+
*
|
|
75997
|
+
* @param agentSource - Raw book source.
|
|
75998
|
+
* @returns Trimmed commitment content, empty string for a blank explicit `FROM`, or `undefined` when `FROM` is absent.
|
|
75999
|
+
*
|
|
76000
|
+
* @private utility of Agents Server inheritance resolution
|
|
76001
|
+
*/
|
|
76002
|
+
function getExplicitFromCommitmentContent(agentSource) {
|
|
76003
|
+
var _a;
|
|
76004
|
+
return (_a = getEffectiveExplicitFromCommitment(agentSource)) === null || _a === void 0 ? void 0 : _a.content;
|
|
76005
|
+
}
|
|
76006
|
+
// Note: [💞] Ignore a discrepancy between file name and exported helper names.
|
|
76007
|
+
|
|
76008
|
+
/**
|
|
76009
|
+
* Type guard for issue-tracking resolver implementations.
|
|
76010
|
+
*
|
|
76011
|
+
* @param resolver - Resolver instance to check.
|
|
76012
|
+
* @returns True when the resolver provides `consumeResolutionIssues`.
|
|
76013
|
+
*/
|
|
76014
|
+
function isIssueTrackingAgentReferenceResolver(resolver) {
|
|
76015
|
+
return typeof resolver.consumeResolutionIssues === 'function';
|
|
76016
|
+
}
|
|
76017
|
+
/**
|
|
76018
|
+
* Drains unresolved compact-reference issues from a resolver when supported.
|
|
76019
|
+
*
|
|
76020
|
+
* @param resolver - Resolver instance that may implement issue tracking.
|
|
76021
|
+
* @returns Collected issues or an empty list.
|
|
76022
|
+
*
|
|
76023
|
+
* @private internal utility of agent reference resolution
|
|
76024
|
+
*/
|
|
76025
|
+
function consumeAgentReferenceResolutionIssues(resolver) {
|
|
76026
|
+
if (!resolver) {
|
|
76027
|
+
return [];
|
|
76028
|
+
}
|
|
76029
|
+
if (!isIssueTrackingAgentReferenceResolver(resolver)) {
|
|
76030
|
+
return [];
|
|
76031
|
+
}
|
|
76032
|
+
return resolver.consumeResolutionIssues();
|
|
76033
|
+
}
|
|
76034
|
+
|
|
76035
|
+
/**
|
|
76036
|
+
* Gets the corpus of an agent source (removes title and trailing status)
|
|
76037
|
+
*
|
|
76038
|
+
* @param agentSource The agent source
|
|
76039
|
+
* @returns The agent source corpus
|
|
76040
|
+
*/
|
|
76041
|
+
function getAgentSourceCorpus(agentSource) {
|
|
76042
|
+
// Remove trailing OPEN or CLOSED if present
|
|
76043
|
+
const agentSourceWithoutStatus = agentSource.replace(/\n?(OPEN|CLOSED)\s*$/i, '');
|
|
76044
|
+
// <- TODO: [🈲] Simple and encapsulated way to get book corpus
|
|
76045
|
+
// Remove the first line (title) from agent source
|
|
76046
|
+
const agentSourceCorpus = spaceTrim(agentSourceWithoutStatus.replace(/^.*$/m, ''));
|
|
76047
|
+
// <- TODO: [🈲] Simple and encapsulated way to get book corpus
|
|
76048
|
+
return agentSourceCorpus;
|
|
76049
|
+
}
|
|
76050
|
+
/**
|
|
76051
|
+
* Formats a resolver issue into a visible NOTE line in resolved agent source.
|
|
76052
|
+
*
|
|
76053
|
+
* @param issue - Tracked missing-reference issue.
|
|
76054
|
+
* @returns Single-line NOTE statement.
|
|
76055
|
+
*/
|
|
76056
|
+
function formatResolutionIssueAsNote(issue) {
|
|
76057
|
+
const commitmentType = issue.commitmentType === 'IMPORTS' ? 'IMPORT' : issue.commitmentType;
|
|
76058
|
+
if (commitmentType === 'FROM') {
|
|
76059
|
+
return `NOTE Referenced agent "${issue.reference}" in FROM commitment was not found. Inheritance skipped.`;
|
|
76060
|
+
}
|
|
76061
|
+
if (commitmentType === 'IMPORT') {
|
|
76062
|
+
return `NOTE Referenced agent "${issue.reference}" in IMPORT commitment was not found. Import skipped.`;
|
|
76063
|
+
}
|
|
76064
|
+
if (commitmentType === 'TEAM') {
|
|
76065
|
+
return `NOTE Referenced agent "${issue.reference}" in TEAM commitment was not found. Teammate disabled.`;
|
|
76066
|
+
}
|
|
76067
|
+
return `NOTE Referenced agent "${issue.reference}" in ${commitmentType} commitment was not found.`;
|
|
76068
|
+
}
|
|
76069
|
+
/**
|
|
76070
|
+
* Appends NOTE lines for unresolved references while avoiding duplicates.
|
|
76071
|
+
*
|
|
76072
|
+
* @param targetChunks - Output chunks being assembled for the resolved book.
|
|
76073
|
+
* @param issues - Missing-reference issues to materialize into NOTE lines.
|
|
76074
|
+
*/
|
|
76075
|
+
function appendResolutionIssueNotes(targetChunks, issues) {
|
|
76076
|
+
const seenIssueKeys = new Set();
|
|
76077
|
+
for (const issue of issues) {
|
|
76078
|
+
const key = `${issue.commitmentType}:${issue.reference}`.toLowerCase();
|
|
76079
|
+
if (seenIssueKeys.has(key)) {
|
|
76080
|
+
continue;
|
|
76081
|
+
}
|
|
76082
|
+
seenIssueKeys.add(key);
|
|
76083
|
+
targetChunks.push(formatResolutionIssueAsNote(issue), '');
|
|
76084
|
+
}
|
|
76085
|
+
}
|
|
76086
|
+
/**
|
|
76087
|
+
* Inserts NOTE lines right after the title line in a book.
|
|
76088
|
+
*
|
|
76089
|
+
* @param agentSource - Original agent source.
|
|
76090
|
+
* @param notes - NOTE lines to insert.
|
|
76091
|
+
* @returns Updated book with notes placed after the title.
|
|
76092
|
+
*/
|
|
76093
|
+
function insertNotesAfterTitle(agentSource, notes) {
|
|
76094
|
+
if (notes.length === 0) {
|
|
76095
|
+
return agentSource;
|
|
76096
|
+
}
|
|
76097
|
+
const sourceLines = spaceTrim(agentSource).split(/\r?\n/);
|
|
76098
|
+
const titleLine = sourceLines[0] || '';
|
|
76099
|
+
const restLines = sourceLines.slice(1);
|
|
76100
|
+
const nextLines = [titleLine, '', ...notes, '', ...restLines];
|
|
76101
|
+
return padBook(validateBook(nextLines.join('\n')));
|
|
76102
|
+
}
|
|
76103
|
+
/**
|
|
76104
|
+
* Resolves the effective `FROM` parent URL using only lightweight commitment parsing.
|
|
76105
|
+
*
|
|
76106
|
+
* @param rawAgentSource - Original source used for diagnostics.
|
|
76107
|
+
* @param agentReferenceResolver - Optional compact-reference resolver.
|
|
76108
|
+
* @returns Valid parent URL, explicit `null` for `FROM VOID`/blank `FROM`, or `undefined` when `FROM` is absent.
|
|
76109
|
+
*/
|
|
76110
|
+
async function resolveParentAgentUrlFromCommitments(rawAgentSource, agentReferenceResolver) {
|
|
76111
|
+
const explicitFromContent = getExplicitFromCommitmentContent(rawAgentSource);
|
|
76112
|
+
if (explicitFromContent === undefined) {
|
|
76113
|
+
return undefined;
|
|
76114
|
+
}
|
|
76115
|
+
let resolvedParentReference = explicitFromContent.trim();
|
|
76116
|
+
if (agentReferenceResolver && resolvedParentReference) {
|
|
76117
|
+
resolvedParentReference = (await agentReferenceResolver.resolveCommitmentContent('FROM', resolvedParentReference)).trim();
|
|
76118
|
+
}
|
|
76119
|
+
if (!resolvedParentReference || isVoidPseudoAgentReference(resolvedParentReference)) {
|
|
76120
|
+
return null;
|
|
76121
|
+
}
|
|
76122
|
+
if (!isValidAgentUrl(resolvedParentReference)) {
|
|
76123
|
+
throw new ParseError(spaceTrim((block) => `
|
|
76124
|
+
Invalid parent agent URL in FROM "${resolvedParentReference}" commitment:
|
|
76125
|
+
|
|
76126
|
+
\`\`\`book
|
|
76127
|
+
${block(rawAgentSource)}
|
|
76128
|
+
\`\`\`
|
|
76129
|
+
|
|
76130
|
+
`));
|
|
76131
|
+
}
|
|
76132
|
+
return resolvedParentReference;
|
|
76133
|
+
}
|
|
76134
|
+
/**
|
|
76135
|
+
* Normalizes agent URLs used for cycle detection and lineage reporting.
|
|
76136
|
+
*
|
|
76137
|
+
* @param agentUrl - Raw agent URL.
|
|
76138
|
+
* @returns URL without trailing slashes.
|
|
76139
|
+
*/
|
|
76140
|
+
function normalizeAgentUrl(agentUrl) {
|
|
76141
|
+
return agentUrl.replace(/\/+$/g, '');
|
|
76142
|
+
}
|
|
76143
|
+
/**
|
|
76144
|
+
* Builds the current resolution lineage ending with the agent being resolved now.
|
|
76145
|
+
*
|
|
76146
|
+
* @param options - Resolution options with current agent metadata.
|
|
76147
|
+
* @returns Ordered lineage without empty values.
|
|
76148
|
+
*/
|
|
76149
|
+
function createResolutionLineage(options) {
|
|
76150
|
+
const lineage = [...((options === null || options === void 0 ? void 0 : options.inheritancePath) || [])];
|
|
76151
|
+
if (options === null || options === void 0 ? void 0 : options.currentAgentUrl) {
|
|
76152
|
+
lineage.push(options.currentAgentUrl);
|
|
76153
|
+
}
|
|
76154
|
+
for (const alias of (options === null || options === void 0 ? void 0 : options.currentAgentAliases) || []) {
|
|
76155
|
+
lineage.push(alias);
|
|
76156
|
+
}
|
|
76157
|
+
return [...new Set(lineage.map(normalizeAgentUrl))];
|
|
76158
|
+
}
|
|
76159
|
+
/**
|
|
76160
|
+
* Finds a cycle that would be closed by resolving one more agent reference.
|
|
76161
|
+
*
|
|
76162
|
+
* @param referenceUrl - Next agent reference to resolve.
|
|
76163
|
+
* @param options - Current resolution options.
|
|
76164
|
+
* @returns Cycle details, or `null` when the reference is not in the current lineage.
|
|
76165
|
+
*
|
|
76166
|
+
* @private internal helper for Agents Server inherited/imported agent resolution
|
|
76167
|
+
*/
|
|
76168
|
+
function findResolutionCycle(referenceUrl, options) {
|
|
76169
|
+
const normalizedReferenceUrl = normalizeAgentUrl(referenceUrl);
|
|
76170
|
+
const lineage = createResolutionLineage(options);
|
|
76171
|
+
const cycleStartIndex = lineage.findIndex((visitedUrl) => visitedUrl === normalizedReferenceUrl);
|
|
76172
|
+
if (cycleStartIndex === -1) {
|
|
76173
|
+
return null;
|
|
76174
|
+
}
|
|
76175
|
+
return { normalizedReferenceUrl, lineage, cycleStartIndex };
|
|
76176
|
+
}
|
|
76177
|
+
/**
|
|
76178
|
+
* Creates the shared import context used throughout one resolution pass.
|
|
76179
|
+
*
|
|
76180
|
+
* @param options - Resolution options passed to `resolveInheritedAgentSource`.
|
|
76181
|
+
* @returns Normalized shared import context.
|
|
76182
|
+
*/
|
|
76183
|
+
function createAgentImportContext(options) {
|
|
76184
|
+
return {
|
|
76185
|
+
adamAgentUrl: (options === null || options === void 0 ? void 0 : options.adamAgentUrl) || 'https://core.ptbk.io/agents/adam',
|
|
76186
|
+
agentReferenceResolver: options === null || options === void 0 ? void 0 : options.agentReferenceResolver,
|
|
76187
|
+
importAgentOptions: {
|
|
76188
|
+
recursionLevel: (options === null || options === void 0 ? void 0 : options.recursionLevel) || 0,
|
|
76189
|
+
inheritancePath: createResolutionLineage(options),
|
|
76190
|
+
},
|
|
76191
|
+
agentSourceImporter: options.agentSourceImporter,
|
|
76192
|
+
resolutionOptions: options,
|
|
76193
|
+
};
|
|
76194
|
+
}
|
|
76195
|
+
/**
|
|
76196
|
+
* Computes the effective parent URL after applying explicit `FROM` and Adam fallback rules.
|
|
76197
|
+
*
|
|
76198
|
+
* @param resolvedParentAgentUrl - Parent URL derived from lightweight commitment parsing.
|
|
76199
|
+
* @param hasExplicitFromCommitment - Whether the source explicitly declared `FROM`.
|
|
76200
|
+
* @param adamAgentUrl - Default Adam ancestor URL.
|
|
76201
|
+
* @param currentAgentUrl - Canonical URL of the source being resolved.
|
|
76202
|
+
* @param currentAgentAliases - Additional URLs that identify the source being resolved.
|
|
76203
|
+
* @param agentSource - Raw source used for unexpected diagnostics.
|
|
76204
|
+
* @returns Effective parent URL or `null` when inheritance is disabled.
|
|
76205
|
+
*/
|
|
76206
|
+
function determineParentAgentUrl(resolvedParentAgentUrl, hasExplicitFromCommitment, adamAgentUrl, currentAgentUrl, currentAgentAliases, agentSource) {
|
|
76207
|
+
if (isValidAgentUrl(resolvedParentAgentUrl)) {
|
|
76208
|
+
return resolvedParentAgentUrl;
|
|
76209
|
+
}
|
|
76210
|
+
if (resolvedParentAgentUrl === null && hasExplicitFromCommitment) {
|
|
76211
|
+
return null;
|
|
76212
|
+
}
|
|
76213
|
+
if (resolvedParentAgentUrl === undefined || resolvedParentAgentUrl === null) {
|
|
76214
|
+
const currentAgentUrls = [currentAgentUrl, ...(currentAgentAliases || [])].filter((agentUrl) => Boolean(agentUrl));
|
|
76215
|
+
const isCurrentAgentAdam = currentAgentUrls.some((agentUrl) => normalizeAgentUrl(agentUrl) === normalizeAgentUrl(adamAgentUrl));
|
|
76216
|
+
return isCurrentAgentAdam ? null : adamAgentUrl;
|
|
76217
|
+
}
|
|
76218
|
+
throw new ParseError(spaceTrim((block) => `
|
|
76219
|
+
Invalid parent agent URL in FROM "${resolvedParentAgentUrl}" commitment:
|
|
76220
|
+
|
|
76221
|
+
\`\`\`book
|
|
76222
|
+
${block(agentSource || '')}
|
|
76223
|
+
\`\`\`
|
|
76224
|
+
`));
|
|
76225
|
+
}
|
|
76226
|
+
/**
|
|
76227
|
+
* Imports one referenced agent and returns only its body content ready to be embedded as a NOTE block.
|
|
76228
|
+
*
|
|
76229
|
+
* @param agentUrl - Canonical referenced agent URL.
|
|
76230
|
+
* @param commitmentType - Commitment that introduced the reference.
|
|
76231
|
+
* @param context - Shared import context for the current resolution pass.
|
|
76232
|
+
* @returns Imported source body without title/status.
|
|
76233
|
+
*/
|
|
76234
|
+
async function importAgentCorpus(agentUrl, commitmentType, context) {
|
|
76235
|
+
assertNoResolutionCycle(agentUrl, commitmentType, context.resolutionOptions);
|
|
76236
|
+
const importedAgentSource = await context.agentSourceImporter(agentUrl, {
|
|
76237
|
+
commitmentType,
|
|
76238
|
+
importAgentOptions: context.importAgentOptions,
|
|
76239
|
+
});
|
|
76240
|
+
return getAgentSourceCorpus(importedAgentSource);
|
|
76241
|
+
}
|
|
76242
|
+
/**
|
|
76243
|
+
* Resolves the effective parent state before the source body is rewritten.
|
|
76244
|
+
*
|
|
76245
|
+
* @param agentSource - Raw child agent source.
|
|
76246
|
+
* @param context - Shared import context for the current resolution pass.
|
|
76247
|
+
* @returns Parent URL, imported parent body, and unresolved `FROM` issues.
|
|
76248
|
+
*/
|
|
76249
|
+
async function resolveParentAgentContext(agentSource, context) {
|
|
76250
|
+
var _a, _b;
|
|
76251
|
+
const explicitFromContent = getExplicitFromCommitmentContent(agentSource);
|
|
76252
|
+
const hasExplicitFromCommitment = explicitFromContent !== undefined;
|
|
76253
|
+
const resolvedParentAgentUrl = await resolveParentAgentUrlFromCommitments(agentSource, context.agentReferenceResolver);
|
|
76254
|
+
const fromResolutionIssues = consumeAgentReferenceResolutionIssues(context.agentReferenceResolver).filter((issue) => issue.commitmentType === 'FROM');
|
|
76255
|
+
const parentAgentUrl = determineParentAgentUrl(resolvedParentAgentUrl, hasExplicitFromCommitment, context.adamAgentUrl, (_a = context.resolutionOptions) === null || _a === void 0 ? void 0 : _a.currentAgentUrl, (_b = context.resolutionOptions) === null || _b === void 0 ? void 0 : _b.currentAgentAliases, agentSource);
|
|
76256
|
+
const isCyclicFrom = Boolean(parentAgentUrl && findResolutionCycle(parentAgentUrl, context.resolutionOptions));
|
|
76257
|
+
const effectiveParentAgentUrl = isCyclicFrom ? null : parentAgentUrl;
|
|
76258
|
+
const parentAgentSourceCorpus = effectiveParentAgentUrl
|
|
76259
|
+
? await importAgentCorpus(effectiveParentAgentUrl, 'FROM', context)
|
|
76260
|
+
: null;
|
|
76261
|
+
return {
|
|
76262
|
+
// A parent that closes the current lineage has the same runtime effect as `FROM @Null`.
|
|
76263
|
+
parentAgentUrl: effectiveParentAgentUrl,
|
|
76264
|
+
parentAgentSourceCorpus,
|
|
76265
|
+
fromResolutionIssues,
|
|
76266
|
+
isCyclicFrom,
|
|
76267
|
+
};
|
|
76268
|
+
}
|
|
76269
|
+
/**
|
|
76270
|
+
* Formats one embedded agent body into the NOTE block used by inheritance/import resolution.
|
|
76271
|
+
*
|
|
76272
|
+
* @param noteLine - First NOTE line describing the embedded source.
|
|
76273
|
+
* @param sourceCorpus - Imported source body to embed.
|
|
76274
|
+
* @returns Multi-line NOTE block.
|
|
76275
|
+
*/
|
|
76276
|
+
function createEmbeddedAgentSourceNote(noteLine, sourceCorpus) {
|
|
76277
|
+
return spaceTrim((block) => `
|
|
76278
|
+
|
|
76279
|
+
${noteLine}
|
|
76280
|
+
${block(sourceCorpus)}
|
|
76281
|
+
|
|
76282
|
+
NOTE ===========
|
|
76283
|
+
`);
|
|
76284
|
+
}
|
|
76285
|
+
/**
|
|
76286
|
+
* Resolves one `IMPORT ...` line into embedded source or leaves non-agent imports untouched.
|
|
76287
|
+
*
|
|
76288
|
+
* @param line - Current source line.
|
|
76289
|
+
* @param context - Shared import context for the current resolution pass.
|
|
76290
|
+
* @returns Output lines replacing the original line.
|
|
76291
|
+
*/
|
|
76292
|
+
async function resolveImportCommitmentLine(line, context) {
|
|
76293
|
+
const rawImportedUrlOrPath = line
|
|
76294
|
+
.trim()
|
|
76295
|
+
.replace(/^IMPORTS?\s+/, '')
|
|
76296
|
+
.trim();
|
|
76297
|
+
let importedUrlOrPath = rawImportedUrlOrPath;
|
|
76298
|
+
let importResolutionIssues = [];
|
|
76299
|
+
if (context.agentReferenceResolver && rawImportedUrlOrPath) {
|
|
76300
|
+
try {
|
|
76301
|
+
importedUrlOrPath = await context.agentReferenceResolver.resolveCommitmentContent('IMPORT', rawImportedUrlOrPath);
|
|
76302
|
+
}
|
|
76303
|
+
catch (error) {
|
|
76304
|
+
console.warn('[AgentReferenceResolver] Failed to resolve IMPORT commitment references:', error);
|
|
76305
|
+
}
|
|
76306
|
+
finally {
|
|
76307
|
+
importResolutionIssues = consumeAgentReferenceResolutionIssues(context.agentReferenceResolver).filter((issue) => issue.commitmentType === 'IMPORT' || issue.commitmentType === 'IMPORTS');
|
|
76308
|
+
}
|
|
76309
|
+
}
|
|
76310
|
+
const resolvedChunks = [];
|
|
76311
|
+
appendResolutionIssueNotes(resolvedChunks, importResolutionIssues);
|
|
76312
|
+
if (!importedUrlOrPath) {
|
|
76313
|
+
return resolvedChunks;
|
|
76314
|
+
}
|
|
76315
|
+
if (!isValidAgentUrl(importedUrlOrPath)) {
|
|
76316
|
+
resolvedChunks.push(line);
|
|
76317
|
+
return resolvedChunks;
|
|
76318
|
+
}
|
|
76319
|
+
const importedAgentUrl = importedUrlOrPath;
|
|
76320
|
+
const importedAgentSourceCorpus = await importAgentCorpus(importedAgentUrl, 'IMPORT', context);
|
|
76321
|
+
resolvedChunks.push(createEmbeddedAgentSourceNote(`NOTE Imported from ${importedAgentUrl}`, importedAgentSourceCorpus), '');
|
|
76322
|
+
return resolvedChunks;
|
|
76323
|
+
}
|
|
76324
|
+
/**
|
|
76325
|
+
* Resolves the effective `FROM ...` line into inherited content or fallback NOTE lines.
|
|
76326
|
+
*
|
|
76327
|
+
* @param line - Current source line.
|
|
76328
|
+
* @param parentContext - Effective parent state computed earlier in the resolution.
|
|
76329
|
+
* @returns Output lines and remaining `FROM` issues.
|
|
76330
|
+
*/
|
|
76331
|
+
function resolveFromCommitmentLine(line, parentContext) {
|
|
76332
|
+
if (parentContext.parentAgentUrl === null) {
|
|
76333
|
+
const agentSourceChunks = [parentContext.isCyclicFrom ? 'FROM @Null' : line];
|
|
76334
|
+
if (parentContext.fromResolutionIssues.length > 0) {
|
|
76335
|
+
appendResolutionIssueNotes(agentSourceChunks, parentContext.fromResolutionIssues);
|
|
76336
|
+
}
|
|
76337
|
+
return {
|
|
76338
|
+
agentSourceChunks,
|
|
76339
|
+
fromResolutionIssues: [],
|
|
76340
|
+
};
|
|
76341
|
+
}
|
|
76342
|
+
if (parentContext.parentAgentSourceCorpus) {
|
|
76343
|
+
return {
|
|
76344
|
+
agentSourceChunks: [
|
|
76345
|
+
createEmbeddedAgentSourceNote(`NOTE Inherited FROM ${parentContext.parentAgentUrl}`, parentContext.parentAgentSourceCorpus),
|
|
76346
|
+
'', // <- Note: Add an extra newline for separation
|
|
76347
|
+
],
|
|
76348
|
+
fromResolutionIssues: parentContext.fromResolutionIssues,
|
|
76349
|
+
};
|
|
76350
|
+
}
|
|
76351
|
+
return {
|
|
76352
|
+
agentSourceChunks: [
|
|
76353
|
+
`NOTE Parent agent "${parentContext.parentAgentUrl}" was not found or could not be loaded. Inheritance skipped.`,
|
|
76354
|
+
'',
|
|
76355
|
+
],
|
|
76356
|
+
fromResolutionIssues: parentContext.fromResolutionIssues,
|
|
76357
|
+
};
|
|
76358
|
+
}
|
|
76359
|
+
/**
|
|
76360
|
+
* Finds the `FROM` lines that a later `FROM` takes precedence over.
|
|
76361
|
+
*
|
|
76362
|
+
* A book is allowed to repeat `FROM`; the last one wins, so every earlier one is dropped instead of being resolved.
|
|
76363
|
+
* The Book editor warns about this while the author is still writing the book.
|
|
76364
|
+
*
|
|
76365
|
+
* @param explicitFromCommitments - Explicit parent declarations found in source order.
|
|
76366
|
+
* @returns Zero-based indexes of every overridden `FROM` line, empty when at most one `FROM` is present.
|
|
76367
|
+
*/
|
|
76368
|
+
function collectOverriddenFromLineIndexes(explicitFromCommitments) {
|
|
76369
|
+
return new Set(explicitFromCommitments.slice(0, -1).map((explicitFromCommitment) => explicitFromCommitment.lineIndex));
|
|
76370
|
+
}
|
|
76371
|
+
/**
|
|
76372
|
+
* Rewrites the source body line by line while delegating each branching step to a focused helper.
|
|
76373
|
+
*
|
|
76374
|
+
* @param agentSource - Raw child agent source.
|
|
76375
|
+
* @param context - Shared import context for the current resolution pass.
|
|
76376
|
+
* @param parentContext - Effective parent state computed earlier in the resolution.
|
|
76377
|
+
* @returns Rewritten chunks plus final `FROM` bookkeeping.
|
|
76378
|
+
*/
|
|
76379
|
+
async function resolveAgentSourceBuild(agentSource, context, parentContext) {
|
|
76380
|
+
const agentSourceChunks = spaceTrim(agentSource).split(/\r?\n/);
|
|
76381
|
+
const resolvedAgentSourceChunks = [];
|
|
76382
|
+
const explicitFromCommitments = collectExplicitFromCommitments(agentSourceChunks);
|
|
76383
|
+
const effectiveFromCommitment = explicitFromCommitments[explicitFromCommitments.length - 1];
|
|
76384
|
+
const overriddenFromLineIndexes = collectOverriddenFromLineIndexes(explicitFromCommitments);
|
|
76385
|
+
let isFromResolved = false;
|
|
76386
|
+
let isInsideCodeBlock = false;
|
|
76387
|
+
let fromResolutionIssues = parentContext.fromResolutionIssues;
|
|
76388
|
+
// <- TODO: [🈲] Simple and encapsulated way to split book into commitments
|
|
76389
|
+
for (let lineIndex = 0; lineIndex < agentSourceChunks.length; lineIndex++) {
|
|
76390
|
+
const line = agentSourceChunks[lineIndex] || '';
|
|
76391
|
+
if (line.trim().startsWith('```')) {
|
|
76392
|
+
isInsideCodeBlock = !isInsideCodeBlock;
|
|
76393
|
+
}
|
|
76394
|
+
if (isInsideCodeBlock || line.trim().startsWith('```')) {
|
|
76395
|
+
resolvedAgentSourceChunks.push(line);
|
|
76396
|
+
continue;
|
|
76397
|
+
}
|
|
76398
|
+
// Note: A repeated `FROM` is overridden by the last one, so the outdated line is dropped from the resolved source.
|
|
76399
|
+
if (overriddenFromLineIndexes.has(lineIndex)) {
|
|
76400
|
+
continue;
|
|
76401
|
+
}
|
|
76402
|
+
if (lineIndex > 0 && /^IMPORTS?\s+/.test(line.trim())) {
|
|
76403
|
+
resolvedAgentSourceChunks.push(...(await resolveImportCommitmentLine(line, context)));
|
|
76404
|
+
continue;
|
|
76405
|
+
}
|
|
76406
|
+
if ((effectiveFromCommitment === null || effectiveFromCommitment === void 0 ? void 0 : effectiveFromCommitment.lineIndex) === lineIndex) {
|
|
76407
|
+
const resolvedFromCommitment = resolveFromCommitmentLine(line, {
|
|
76408
|
+
...parentContext,
|
|
76409
|
+
fromResolutionIssues,
|
|
76410
|
+
});
|
|
76411
|
+
resolvedAgentSourceChunks.push(...resolvedFromCommitment.agentSourceChunks);
|
|
76412
|
+
fromResolutionIssues = resolvedFromCommitment.fromResolutionIssues;
|
|
76413
|
+
isFromResolved = true;
|
|
76414
|
+
continue;
|
|
76415
|
+
}
|
|
76416
|
+
resolvedAgentSourceChunks.push(line);
|
|
76417
|
+
}
|
|
76418
|
+
// <- TODO: [🈲] Simple and encapsulated way to split book into commitments
|
|
76419
|
+
return {
|
|
76420
|
+
agentSourceChunks: resolvedAgentSourceChunks,
|
|
76421
|
+
isFromResolved,
|
|
76422
|
+
fromResolutionIssues,
|
|
76423
|
+
};
|
|
76424
|
+
}
|
|
76425
|
+
/**
|
|
76426
|
+
* Materializes the implicit Adam inheritance block when no explicit `FROM ...` was present.
|
|
76427
|
+
*
|
|
76428
|
+
* @param build - Current rewritten source build.
|
|
76429
|
+
* @param parentContext - Effective parent state computed earlier in the resolution.
|
|
76430
|
+
* @param adamAgentUrl - Default Adam ancestor URL.
|
|
76431
|
+
* @returns Updated source build with implicit Adam inheritance applied when needed.
|
|
76432
|
+
*/
|
|
76433
|
+
function applyImplicitAdamInheritance(build, parentContext, adamAgentUrl) {
|
|
76434
|
+
if (build.isFromResolved || parentContext.parentAgentUrl !== adamAgentUrl) {
|
|
76435
|
+
return build;
|
|
76436
|
+
}
|
|
76437
|
+
const titleLine = build.agentSourceChunks[0] || '';
|
|
76438
|
+
const restLines = build.agentSourceChunks.slice(1);
|
|
76439
|
+
const agentSourceChunks = [titleLine, ''];
|
|
76440
|
+
if (parentContext.parentAgentSourceCorpus) {
|
|
76441
|
+
agentSourceChunks.push(createEmbeddedAgentSourceNote(`NOTE Inherited Adam FROM ${parentContext.parentAgentUrl}`, parentContext.parentAgentSourceCorpus), ...restLines);
|
|
76442
|
+
}
|
|
76443
|
+
else {
|
|
76444
|
+
agentSourceChunks.push(`NOTE Default parent agent "${parentContext.parentAgentUrl}" was not found or could not be loaded. Inheritance skipped.`, '', ...restLines);
|
|
76445
|
+
}
|
|
76446
|
+
return {
|
|
76447
|
+
...build,
|
|
76448
|
+
agentSourceChunks,
|
|
76449
|
+
};
|
|
76450
|
+
}
|
|
76451
|
+
/**
|
|
76452
|
+
* Validates and pads the resolved source, then inserts any deferred unresolved-`FROM` notes.
|
|
76453
|
+
*
|
|
76454
|
+
* @param build - Final rewritten source build.
|
|
76455
|
+
* @returns Valid resolved book.
|
|
76456
|
+
*/
|
|
76457
|
+
function finalizeResolvedAgentSource(build) {
|
|
76458
|
+
const resolvedAgentSource = padBook(validateBook(build.agentSourceChunks.join('\n')));
|
|
76459
|
+
if (build.fromResolutionIssues.length === 0) {
|
|
76460
|
+
return resolvedAgentSource;
|
|
76461
|
+
}
|
|
76462
|
+
const unresolvedFromNotes = build.fromResolutionIssues.map(formatResolutionIssueAsNote);
|
|
76463
|
+
return insertNotesAfterTitle(resolvedAgentSource, unresolvedFromNotes);
|
|
76464
|
+
}
|
|
76465
|
+
/**
|
|
76466
|
+
* Throws when a `FROM`/`IMPORT` edge would create an inheritance cycle.
|
|
76467
|
+
*
|
|
76468
|
+
* @param referenceUrl - Next referenced agent URL.
|
|
76469
|
+
* @param commitmentType - Commitment that introduced the reference.
|
|
76470
|
+
* @param options - Current resolution options.
|
|
76471
|
+
*/
|
|
76472
|
+
function assertNoResolutionCycle(referenceUrl, commitmentType, options) {
|
|
76473
|
+
const resolutionCycle = findResolutionCycle(referenceUrl, options);
|
|
76474
|
+
if (!resolutionCycle) {
|
|
76475
|
+
return;
|
|
76476
|
+
}
|
|
76477
|
+
const cycleChain = [
|
|
76478
|
+
...resolutionCycle.lineage.slice(resolutionCycle.cycleStartIndex),
|
|
76479
|
+
resolutionCycle.normalizedReferenceUrl,
|
|
76480
|
+
]
|
|
76481
|
+
.map((visitedUrl) => `- \`${visitedUrl}\``)
|
|
76482
|
+
.join('\n');
|
|
76483
|
+
throw new ParseError(spaceTrim((block) => `
|
|
76484
|
+
Cyclic \`${commitmentType}\` reference detected while resolving agent source.
|
|
76485
|
+
|
|
76486
|
+
Resolution chain:
|
|
76487
|
+
${block(cycleChain)}
|
|
76488
|
+
`));
|
|
76489
|
+
}
|
|
76490
|
+
/**
|
|
76491
|
+
* Resolves agent source with inheritance (FROM commitment)
|
|
76492
|
+
*
|
|
76493
|
+
* It recursively fetches the parent agent source and merges it with the current source.
|
|
76494
|
+
*
|
|
76495
|
+
* @param agentSource The initial agent source
|
|
76496
|
+
* @returns The resolved agent source with inheritance applied
|
|
76497
|
+
*
|
|
76498
|
+
* @private internal utility of agent source resolution
|
|
76499
|
+
*/
|
|
76500
|
+
async function resolveInheritedAgentSource(agentSource, options) {
|
|
76501
|
+
const context = createAgentImportContext(options);
|
|
76502
|
+
const parentContext = await resolveParentAgentContext(agentSource, context);
|
|
76503
|
+
const resolvedBuild = await resolveAgentSourceBuild(agentSource, context, parentContext);
|
|
76504
|
+
const finalizedBuild = applyImplicitAdamInheritance(resolvedBuild, parentContext, context.adamAgentUrl);
|
|
76505
|
+
return finalizeResolvedAgentSource(finalizedBuild);
|
|
76506
|
+
}
|
|
76507
|
+
// TODO: [🈲] Create a function that can manipulate books by modifying commitments, splitting the book up into commitments or syntactic tokens, and editing or deleting these via object methods.
|
|
76508
|
+
|
|
76509
|
+
/**
|
|
76510
|
+
* Matches supported compact reference token syntaxes in commitment content.
|
|
76511
|
+
*/
|
|
76512
|
+
const AGENT_REFERENCE_TOKEN_REGEX = /(\{([^}]+)\}|@([A-Za-z0-9_-]+))/g;
|
|
76513
|
+
/**
|
|
76514
|
+
* Extracts compact agent-reference tokens from commitment content.
|
|
76515
|
+
*
|
|
76516
|
+
* @param content - Commitment content to inspect.
|
|
76517
|
+
* @returns Matched compact reference tokens.
|
|
76518
|
+
*
|
|
76519
|
+
* @private internal utility of agent reference resolution
|
|
76520
|
+
*/
|
|
76521
|
+
function extractAgentReferenceTokens(content) {
|
|
76522
|
+
var _a, _b;
|
|
76523
|
+
const matches = [];
|
|
76524
|
+
let match;
|
|
76525
|
+
AGENT_REFERENCE_TOKEN_REGEX.lastIndex = 0;
|
|
76526
|
+
while ((match = AGENT_REFERENCE_TOKEN_REGEX.exec(content)) !== null) {
|
|
76527
|
+
const token = match[1];
|
|
76528
|
+
const reference = ((_b = (_a = match[2]) !== null && _a !== void 0 ? _a : match[3]) !== null && _b !== void 0 ? _b : '').trim();
|
|
76529
|
+
const index = match.index;
|
|
76530
|
+
if (!token || index === undefined) {
|
|
76531
|
+
continue;
|
|
76532
|
+
}
|
|
76533
|
+
matches.push({
|
|
76534
|
+
token,
|
|
76535
|
+
reference,
|
|
76536
|
+
index,
|
|
76537
|
+
length: token.length,
|
|
76538
|
+
});
|
|
76539
|
+
}
|
|
76540
|
+
return matches;
|
|
76541
|
+
}
|
|
76542
|
+
|
|
76543
|
+
/**
|
|
76544
|
+
* Creates a resolver scoped to the book which declares each reference.
|
|
76545
|
+
*
|
|
76546
|
+
* @private internal utility of CLI agent resolution
|
|
76547
|
+
*/
|
|
76548
|
+
function createLocalAgentReferenceResolver(collection, declaringBook) {
|
|
76549
|
+
/** Resolves pseudo-agents using the same aliases and restrictions as the Agent Server. */
|
|
76550
|
+
async function resolveReference(commitmentType, reference) {
|
|
76551
|
+
const pseudoAgentKind = resolvePseudoAgentKindFromReference(reference);
|
|
76552
|
+
if (!pseudoAgentKind) {
|
|
76553
|
+
return collection.resolveReference(reference, declaringBook);
|
|
76554
|
+
}
|
|
76555
|
+
if (!isPseudoAgentAllowedInCommitment(pseudoAgentKind, commitmentType)) {
|
|
76556
|
+
throw new ParseError(spaceTrim$1(`Pseudo-agent \`${reference}\` cannot be used in \`${commitmentType}\`.`));
|
|
76557
|
+
}
|
|
76558
|
+
if (pseudoAgentKind === 'VOID' && commitmentType === 'FROM') {
|
|
76559
|
+
return VOID_PSEUDO_AGENT_REFERENCE;
|
|
76560
|
+
}
|
|
76561
|
+
if (pseudoAgentKind === 'VOID' && (commitmentType === 'IMPORT' || commitmentType === 'IMPORTS')) {
|
|
76562
|
+
return '';
|
|
76563
|
+
}
|
|
76564
|
+
return createPseudoAgentUrl(pseudoAgentKind);
|
|
76565
|
+
}
|
|
76566
|
+
return {
|
|
76567
|
+
resolveCommitmentContent: async (commitmentType, content) => {
|
|
76568
|
+
const tokens = extractAgentReferenceTokens(content);
|
|
76569
|
+
if (tokens.length === 0) {
|
|
76570
|
+
if (commitmentType !== 'TEAM' && content.trim()) {
|
|
76571
|
+
return resolveReference(commitmentType, content.trim());
|
|
76572
|
+
}
|
|
76573
|
+
return content;
|
|
76574
|
+
}
|
|
76575
|
+
const parts = [];
|
|
76576
|
+
let previousEnd = 0;
|
|
76577
|
+
for (const token of tokens) {
|
|
76578
|
+
parts.push(content.slice(previousEnd, token.index));
|
|
76579
|
+
parts.push(await resolveReference(commitmentType, token.reference));
|
|
76580
|
+
previousEnd = token.index + token.length;
|
|
76581
|
+
}
|
|
76582
|
+
parts.push(content.slice(previousEnd));
|
|
76583
|
+
return parts.join('');
|
|
76584
|
+
},
|
|
76585
|
+
};
|
|
76586
|
+
}
|
|
76587
|
+
|
|
76588
|
+
/**
|
|
76589
|
+
* Internal URLs allow the shared Book commitments to identify local books without an HTTP server.
|
|
76590
|
+
* These identifiers are always intercepted by this collection and are never fetched.
|
|
76591
|
+
*/
|
|
76592
|
+
const LOCAL_AGENT_URL_PREFIX = 'https://local-agent.promptbook/';
|
|
76593
|
+
/**
|
|
76594
|
+
* Directories which cannot contain project-owned agent definitions.
|
|
76595
|
+
*/
|
|
76596
|
+
const IGNORED_DIRECTORY_NAMES = new Set(['.git', 'node_modules']);
|
|
76597
|
+
/**
|
|
76598
|
+
* Reads repository books and indexes their first-line names for CLI reference resolution.
|
|
76599
|
+
*
|
|
76600
|
+
* @private internal utility of CLI agent resolution
|
|
76601
|
+
*/
|
|
76602
|
+
class LocalAgentBookCollection {
|
|
76603
|
+
/** Creates a collection rooted at the primary book's directory. */
|
|
76604
|
+
constructor(agentDirectoryPath, currentWorkingDirectory) {
|
|
76605
|
+
this.agentDirectoryPath = agentDirectoryPath;
|
|
76606
|
+
this.currentWorkingDirectory = currentWorkingDirectory;
|
|
76607
|
+
this.booksByUrl = new Map();
|
|
76608
|
+
this.booksByName = new Map();
|
|
76609
|
+
/** Files initialized by this collection, for the coder's normal commit handling. */
|
|
76610
|
+
this.createdAgentBookPaths = [];
|
|
76611
|
+
}
|
|
76612
|
+
/** Discovers nested books, including the hidden `.core` directory. */
|
|
76613
|
+
async initialize() {
|
|
76614
|
+
await this.readDirectory(this.agentDirectoryPath);
|
|
76615
|
+
}
|
|
76616
|
+
/** Identifies the default ancestor without creating an unused book for FROM null/void. */
|
|
76617
|
+
getAdamAgentUrl() {
|
|
76618
|
+
var _a;
|
|
76619
|
+
(_a = this.adamAgentUrl) !== null && _a !== void 0 ? _a : (this.adamAgentUrl = this.booksByName.has(normalizeAgentName('Adam'))
|
|
76620
|
+
? this.findByName('Adam').url
|
|
76621
|
+
: createLocalAgentBookUrl(join(this.agentDirectoryPath, ADAM_AGENT_BOOK_RELATIVE_PATH)));
|
|
76622
|
+
return this.adamAgentUrl;
|
|
76623
|
+
}
|
|
76624
|
+
/** Resolves a unique first-line name, refusing ambiguous matches. */
|
|
76625
|
+
findByName(name) {
|
|
76626
|
+
const matches = this.booksByName.get(normalizeAgentName(name)) || [];
|
|
76627
|
+
if (matches.length === 1) {
|
|
76628
|
+
return matches[0];
|
|
76629
|
+
}
|
|
76630
|
+
if (matches.length > 1) {
|
|
76631
|
+
throw new ParseError(spaceTrim$1((block) => `
|
|
76632
|
+
Agent reference \`${name}\` is ambiguous. Use an explicit book path.
|
|
76633
|
+
|
|
76634
|
+
Matching books:
|
|
76635
|
+
${block(matches.map((book) => `- \`${book.filePath || book.url}\``).join('\n'))}
|
|
76636
|
+
`));
|
|
76637
|
+
}
|
|
76638
|
+
throw new NotFoundError(spaceTrim$1(`
|
|
76639
|
+
Agent \`${name}\` was not found in \`${this.agentDirectoryPath}\` or its subdirectories.
|
|
76640
|
+
|
|
76641
|
+
References use the agent's **first-line name**. You can also use an explicit \`.book\` path or URL.
|
|
76642
|
+
`));
|
|
76643
|
+
}
|
|
76644
|
+
/** Resolves a name, a path relative to its declaring book, or a path relative to the CLI cwd. */
|
|
76645
|
+
async resolveReference(reference, declaringBook) {
|
|
76646
|
+
const isRemoteReference = Boolean(isValidAgentUrl(reference));
|
|
76647
|
+
if (isRemoteReference) {
|
|
76648
|
+
return reference;
|
|
76649
|
+
}
|
|
76650
|
+
const isBookPath = /\.book$/i.test(reference) || isAbsolute(reference);
|
|
76651
|
+
if (!isBookPath) {
|
|
76652
|
+
if (normalizeAgentName(reference) === normalizeAgentName('Adam')) {
|
|
76653
|
+
return this.getAdamAgentUrl();
|
|
76654
|
+
}
|
|
76655
|
+
return this.findByName(reference).url;
|
|
76656
|
+
}
|
|
76657
|
+
const isRelativeToBook = /^\.{1,2}[\\/]/.test(reference);
|
|
76658
|
+
if (!declaringBook.filePath && isRelativeToBook) {
|
|
76659
|
+
return new URL(reference.replaceAll('\\', '/'), declaringBook.url).href;
|
|
76660
|
+
}
|
|
76661
|
+
const directoryPath = isRelativeToBook && declaringBook.filePath ? dirname(declaringBook.filePath) : this.currentWorkingDirectory;
|
|
76662
|
+
return (await this.readBook(resolve(directoryPath, reference))).url;
|
|
76663
|
+
}
|
|
76664
|
+
/** Reads a local book once, canonicalizing symlinks so aliases cannot bypass cycle detection. */
|
|
76665
|
+
async readBook(filePath) {
|
|
76666
|
+
try {
|
|
76667
|
+
const canonicalFilePath = await realpath(filePath);
|
|
76668
|
+
const url = createLocalAgentBookUrl(canonicalFilePath);
|
|
76669
|
+
const existingBook = this.booksByUrl.get(url);
|
|
76670
|
+
if (existingBook) {
|
|
76671
|
+
return existingBook;
|
|
76672
|
+
}
|
|
76673
|
+
return this.registerBook(url, await readFile(canonicalFilePath, 'utf-8'), canonicalFilePath);
|
|
76674
|
+
}
|
|
76675
|
+
catch (error) {
|
|
76676
|
+
if (['ENOENT', 'EISDIR', 'ENOTDIR'].includes(error.code || '')) {
|
|
76677
|
+
throw new NotFoundError(spaceTrim$1(`Agent book \`${filePath}\` was not found or is not a file.`));
|
|
76678
|
+
}
|
|
76679
|
+
throw error;
|
|
76680
|
+
}
|
|
76681
|
+
}
|
|
76682
|
+
/** Loads a referenced remote book, while keeping local identifiers entirely inside the collection. */
|
|
76683
|
+
async getBook(url) {
|
|
76684
|
+
var _a;
|
|
76685
|
+
const existingBook = this.booksByUrl.get(url);
|
|
76686
|
+
if (existingBook) {
|
|
76687
|
+
return existingBook;
|
|
76688
|
+
}
|
|
76689
|
+
if (url === this.getAdamAgentUrl()) {
|
|
76690
|
+
const adamBookPath = join(this.agentDirectoryPath, ADAM_AGENT_BOOK_RELATIVE_PATH);
|
|
76691
|
+
if ((await ensureAdamAgentBook(this.agentDirectoryPath)) === 'created') {
|
|
76692
|
+
this.createdAgentBookPaths.push(adamBookPath);
|
|
76693
|
+
}
|
|
76694
|
+
const adamBook = await this.readBook(adamBookPath);
|
|
76695
|
+
this.booksByUrl.set(url, adamBook);
|
|
76696
|
+
return adamBook;
|
|
76697
|
+
}
|
|
76698
|
+
if (url.startsWith(LOCAL_AGENT_URL_PREFIX)) {
|
|
76699
|
+
throw new NotFoundError(spaceTrim$1(`Local agent book \`${url}\` is not registered.`));
|
|
76700
|
+
}
|
|
76701
|
+
const bookUrl = new URL(url);
|
|
76702
|
+
if (!/\.(book|md)$/i.test(bookUrl.pathname) && !bookUrl.pathname.endsWith('/api/book')) {
|
|
76703
|
+
bookUrl.pathname = bookUrl.pathname.replace(/\/$/, '') + '/api/book';
|
|
76704
|
+
}
|
|
76705
|
+
const response = await fetch(bookUrl.href);
|
|
76706
|
+
if (!response.ok) {
|
|
76707
|
+
throw new NotFoundError(spaceTrim$1(`Cannot load agent book \`${url}\`: **${response.status} ${response.statusText}**.`));
|
|
76708
|
+
}
|
|
76709
|
+
let source;
|
|
76710
|
+
if ((_a = response.headers.get('content-type')) === null || _a === void 0 ? void 0 : _a.includes('application/json')) {
|
|
76711
|
+
const payload = await response.json();
|
|
76712
|
+
source = typeof payload === 'string' ? payload : payload === null || payload === void 0 ? void 0 : payload.source;
|
|
76713
|
+
}
|
|
76714
|
+
else {
|
|
76715
|
+
source = await response.text();
|
|
76716
|
+
}
|
|
76717
|
+
if (typeof source !== 'string') {
|
|
76718
|
+
throw new ParseError(spaceTrim$1(`Agent book \`${url}\` did not return a text source.`));
|
|
76719
|
+
}
|
|
76720
|
+
return this.registerBook(url, source);
|
|
76721
|
+
}
|
|
76722
|
+
/** Adds a book under its normalized first-line name and preserves the display name for TEAM. */
|
|
76723
|
+
registerBook(url, source, filePath) {
|
|
76724
|
+
const agentSource = source;
|
|
76725
|
+
const parsedSource = parseAgentSource(agentSource);
|
|
76726
|
+
const book = {
|
|
76727
|
+
url,
|
|
76728
|
+
filePath,
|
|
76729
|
+
source: agentSource,
|
|
76730
|
+
profile: {
|
|
76731
|
+
agentName: parsedSource.meta.fullname || parsedSource.agentName,
|
|
76732
|
+
personaDescription: parsedSource.personaDescription,
|
|
76733
|
+
},
|
|
76734
|
+
};
|
|
76735
|
+
this.booksByUrl.set(url, book);
|
|
76736
|
+
// Remote titles must not shadow repository-local names.
|
|
76737
|
+
if (filePath) {
|
|
76738
|
+
const agentName = normalizeAgentName(parsedSource.agentName);
|
|
76739
|
+
this.booksByName.set(agentName, [...(this.booksByName.get(agentName) || []), book]);
|
|
76740
|
+
}
|
|
76741
|
+
return book;
|
|
76742
|
+
}
|
|
76743
|
+
/** Walks real directories in deterministic order without following directory symlink loops. */
|
|
76744
|
+
async readDirectory(directoryPath) {
|
|
76745
|
+
const entries = await readdir(directoryPath, { withFileTypes: true });
|
|
76746
|
+
for (const entry of entries.sort((left, right) => left.name.localeCompare(right.name))) {
|
|
76747
|
+
const entryPath = join(directoryPath, entry.name);
|
|
76748
|
+
if (entry.isDirectory() && !IGNORED_DIRECTORY_NAMES.has(entry.name)) {
|
|
76749
|
+
await this.readDirectory(entryPath);
|
|
76750
|
+
}
|
|
76751
|
+
else if (entry.isFile() && entry.name.toLowerCase().endsWith('.book')) {
|
|
76752
|
+
await this.readBook(entryPath);
|
|
76753
|
+
}
|
|
76754
|
+
}
|
|
76755
|
+
}
|
|
76756
|
+
}
|
|
76757
|
+
/** Creates an internal URL for a local path without requiring that the file already exists. */
|
|
76758
|
+
function createLocalAgentBookUrl(filePath) {
|
|
76759
|
+
return LOCAL_AGENT_URL_PREFIX + encodeURIComponent(pathToFileURL(filePath).href);
|
|
76760
|
+
}
|
|
76761
|
+
|
|
76762
|
+
/**
|
|
76763
|
+
* Applies the shared Agent Server inheritance rules to a repository's local and remote books.
|
|
76764
|
+
*
|
|
76765
|
+
* @private internal utility of CLI agent resolution
|
|
76766
|
+
*/
|
|
76767
|
+
async function resolveLocalAgentSource(agentBookPath, currentWorkingDirectory) {
|
|
76768
|
+
const collection = new LocalAgentBookCollection(dirname(agentBookPath), currentWorkingDirectory);
|
|
76769
|
+
await collection.initialize();
|
|
76770
|
+
const primaryBook = await collection.readBook(agentBookPath);
|
|
76771
|
+
const adamAgentUrl = collection.getAdamAgentUrl();
|
|
76772
|
+
/** Resolves each dependency with its own location and the current inheritance stack. */
|
|
76773
|
+
async function resolveBook(book, inheritancePath = []) {
|
|
76774
|
+
if (inheritancePath.length > DEFAULT_MAX_RECURSION) {
|
|
76775
|
+
throw new ParseError(spaceTrim$1(`Agent inheritance exceeds **${DEFAULT_MAX_RECURSION}** levels at \`${book.filePath || book.url}\`.`));
|
|
76776
|
+
}
|
|
76777
|
+
const agentReferenceResolver = createLocalAgentReferenceResolver(collection, book);
|
|
76778
|
+
const source = await resolveBookCommitmentReferences(book.source, agentReferenceResolver);
|
|
76779
|
+
return resolveInheritedAgentSource(source, {
|
|
76780
|
+
adamAgentUrl,
|
|
76781
|
+
currentAgentUrl: book.url,
|
|
76782
|
+
inheritancePath,
|
|
76783
|
+
agentSourceImporter: async (url, context) => resolveBook(await collection.getBook(url), context.importAgentOptions.inheritancePath),
|
|
76784
|
+
});
|
|
76785
|
+
}
|
|
76786
|
+
return {
|
|
76787
|
+
agentSource: await resolveBook(primaryBook),
|
|
76788
|
+
agentReferenceResolver: {
|
|
76789
|
+
...createLocalAgentReferenceResolver(collection, primaryBook),
|
|
76790
|
+
resolveTeammateProfile: async (url) => {
|
|
76791
|
+
if (isPseudoAgentUrl(url)) {
|
|
76792
|
+
return null;
|
|
76793
|
+
}
|
|
76794
|
+
const book = await collection.getBook(url);
|
|
76795
|
+
const parsedSource = parseAgentSource(await resolveBook(book));
|
|
76796
|
+
return {
|
|
76797
|
+
agentName: book.profile.agentName,
|
|
76798
|
+
personaDescription: parsedSource.personaDescription,
|
|
76799
|
+
};
|
|
76800
|
+
},
|
|
76801
|
+
},
|
|
76802
|
+
createdAgentBookPaths: collection.createdAgentBookPaths,
|
|
76803
|
+
};
|
|
76804
|
+
}
|
|
76805
|
+
/**
|
|
76806
|
+
* Resolves reference blocks before embedding dependencies so inherited TEAM paths keep their original directory.
|
|
76807
|
+
* Parser-provided locations keep examples, unknown commitments and ordinary prose untouched.
|
|
76808
|
+
*/
|
|
76809
|
+
async function resolveBookCommitmentReferences(source, resolver) {
|
|
76810
|
+
var _a;
|
|
76811
|
+
const parsedSource = parseAgentSourceWithCommitments(source);
|
|
76812
|
+
const lines = source.split(/\r?\n/);
|
|
76813
|
+
const commitmentStartLines = [...parsedSource.commitments, ...(parsedSource.unknownCommitments || [])]
|
|
76814
|
+
.map((commitment) => commitment.lineNumber - 1)
|
|
76815
|
+
.sort((left, right) => left - right);
|
|
76816
|
+
const effectiveFrom = getEffectiveExplicitFromCommitment(source);
|
|
76817
|
+
for (const commitment of [...parsedSource.commitments].reverse()) {
|
|
76818
|
+
if (!['FROM', 'IMPORT', 'IMPORTS', 'TEAM'].includes(commitment.type)) {
|
|
76819
|
+
continue;
|
|
76820
|
+
}
|
|
76821
|
+
const startLine = commitment.lineNumber - 1;
|
|
76822
|
+
if (commitment.type === 'FROM' && (effectiveFrom === null || effectiveFrom === void 0 ? void 0 : effectiveFrom.lineIndex) !== startLine) {
|
|
76823
|
+
continue;
|
|
76824
|
+
}
|
|
76825
|
+
let endLine = (_a = commitmentStartLines.find((lineNumber) => lineNumber > startLine)) !== null && _a !== void 0 ? _a : lines.length;
|
|
76826
|
+
// A horizontal rule also terminates a commitment before the next registered keyword.
|
|
76827
|
+
for (let lineIndex = startLine + 1; lineIndex < endLine; lineIndex++) {
|
|
76828
|
+
if (/^\s*(?:-{3,}|\*{3,}|_{3,})\s*$/.test(lines[lineIndex] || '')) {
|
|
76829
|
+
endLine = lineIndex;
|
|
76830
|
+
break;
|
|
76831
|
+
}
|
|
76832
|
+
}
|
|
76833
|
+
const content = await resolver.resolveCommitmentContent(commitment.type, commitment.content);
|
|
76834
|
+
const commitmentType = commitment.type === 'IMPORTS' ? 'IMPORT' : commitment.type;
|
|
76835
|
+
const replacement = content.trim()
|
|
76836
|
+
? `${commitmentType} ${content}\n`
|
|
76837
|
+
: commitmentType === 'FROM'
|
|
76838
|
+
? 'FROM @Null\n'
|
|
76839
|
+
: '';
|
|
76840
|
+
lines.splice(startLine, endLine - startLine, ...replacement.split('\n'));
|
|
76841
|
+
}
|
|
76842
|
+
return lines.join('\n');
|
|
76843
|
+
}
|
|
76844
|
+
|
|
75592
76845
|
/**
|
|
75593
76846
|
* Reads an optional agent `.book` file and prepares the references that route prompts to it.
|
|
75594
76847
|
*
|
|
@@ -75610,13 +76863,16 @@ async function resolveCoderAgentBook(agentBookReference, currentWorkingDirectory
|
|
|
75610
76863
|
}
|
|
75611
76864
|
throw error;
|
|
75612
76865
|
}));
|
|
76866
|
+
// Note: Parsed once here, because both the display name of the agent and its routing references need it
|
|
76867
|
+
const parsedAgentSource = parseAgentSource(agentSource);
|
|
75613
76868
|
return {
|
|
75614
76869
|
agentSource,
|
|
76870
|
+
agentName: parsedAgentSource.meta.fullname || parsedAgentSource.agentName,
|
|
75615
76871
|
agentReferences: createCoderAgentReferences({
|
|
75616
76872
|
agentBookReference: normalizedAgentBookReference,
|
|
75617
76873
|
resolvedAgentBookPath,
|
|
75618
76874
|
currentWorkingDirectory,
|
|
75619
|
-
|
|
76875
|
+
normalizedAgentNameFromBook: parsedAgentSource.agentName,
|
|
75620
76876
|
}),
|
|
75621
76877
|
};
|
|
75622
76878
|
}
|
|
@@ -75630,9 +76886,14 @@ async function resolveCoderAgent(agentBookReference, currentWorkingDirectory) {
|
|
|
75630
76886
|
if (resolvedAgentBook === undefined) {
|
|
75631
76887
|
return undefined;
|
|
75632
76888
|
}
|
|
76889
|
+
const resolvedSource = await resolveLocalAgentSource(resolve(currentWorkingDirectory, agentBookReference.trim()), currentWorkingDirectory);
|
|
75633
76890
|
return {
|
|
75634
76891
|
...resolvedAgentBook,
|
|
75635
|
-
|
|
76892
|
+
agentSource: resolvedSource.agentSource,
|
|
76893
|
+
systemMessage: await createAgentRunnerSystemMessage(resolvedSource.agentSource, {
|
|
76894
|
+
agentReferenceResolver: resolvedSource.agentReferenceResolver,
|
|
76895
|
+
}),
|
|
76896
|
+
createdAgentBookPaths: resolvedSource.createdAgentBookPaths,
|
|
75636
76897
|
};
|
|
75637
76898
|
}
|
|
75638
76899
|
/**
|
|
@@ -75644,13 +76905,12 @@ function createCoderAgentReferences(options) {
|
|
|
75644
76905
|
const relativeAgentBookPath = relative(options.currentWorkingDirectory, options.resolvedAgentBookPath).replaceAll('\\', '/');
|
|
75645
76906
|
const agentBookFileName = basename(options.resolvedAgentBookPath);
|
|
75646
76907
|
const agentBookName = basename(options.resolvedAgentBookPath, extname(options.resolvedAgentBookPath));
|
|
75647
|
-
const agentNameFromBook = parseAgentSource(options.agentSource).agentName;
|
|
75648
76908
|
return Array.from(new Set([
|
|
75649
76909
|
options.agentBookReference,
|
|
75650
76910
|
relativeAgentBookPath,
|
|
75651
76911
|
agentBookFileName,
|
|
75652
76912
|
agentBookName,
|
|
75653
|
-
|
|
76913
|
+
options.normalizedAgentNameFromBook,
|
|
75654
76914
|
].filter((agentReference) => agentReference.trim() !== '')));
|
|
75655
76915
|
}
|
|
75656
76916
|
|
|
@@ -75913,11 +77173,27 @@ function formatUsagePrice(usage) {
|
|
|
75913
77173
|
|
|
75914
77174
|
/**
|
|
75915
77175
|
* Formats runner details for prompt status lines.
|
|
77176
|
+
*
|
|
77177
|
+
* Produces `` OpenAI Codex `gpt-5.6-luna` thinking `max` `` for a plain run and
|
|
77178
|
+
* `` Developer on OpenAI Codex `gpt-5.6-luna` thinking `max` `` for a run personalized with `--agent`.
|
|
75916
77179
|
*/
|
|
75917
|
-
function formatRunnerSignature(
|
|
75918
|
-
|
|
75919
|
-
const
|
|
75920
|
-
const
|
|
77180
|
+
function formatRunnerSignature(options) {
|
|
77181
|
+
var _a;
|
|
77182
|
+
const normalizedAgentName = (_a = options.agentName) === null || _a === void 0 ? void 0 : _a.trim();
|
|
77183
|
+
const harnessSignature = formatHarnessSignature(options);
|
|
77184
|
+
if (!normalizedAgentName) {
|
|
77185
|
+
return harnessSignature;
|
|
77186
|
+
}
|
|
77187
|
+
return `${normalizedAgentName} on ${harnessSignature}`;
|
|
77188
|
+
}
|
|
77189
|
+
/**
|
|
77190
|
+
* Formats the harness part of one runner signature, which names the harness, its model and its thinking level.
|
|
77191
|
+
*/
|
|
77192
|
+
function formatHarnessSignature(options) {
|
|
77193
|
+
var _a, _b;
|
|
77194
|
+
const normalizedRunner = (_a = options.runnerName) === null || _a === void 0 ? void 0 : _a.trim();
|
|
77195
|
+
const normalizedModel = (_b = options.modelName) === null || _b === void 0 ? void 0 : _b.trim();
|
|
77196
|
+
const thinkingLevelSuffix = options.thinkingLevel ? ` thinking \`${options.thinkingLevel}\`` : '';
|
|
75921
77197
|
if (!normalizedRunner && !normalizedModel) {
|
|
75922
77198
|
return 'unknown';
|
|
75923
77199
|
}
|
|
@@ -75932,7 +77208,12 @@ function formatRunnerSignature(runnerName, modelName, thinkingLevel) {
|
|
|
75932
77208
|
* Prints the compact summary of one finished `ptbk coder ping`.
|
|
75933
77209
|
*/
|
|
75934
77210
|
function printCoderPingResult(result) {
|
|
75935
|
-
|
|
77211
|
+
// Note: `ptbk coder ping` measures one harness alone, it never runs the prompts of a Book agent
|
|
77212
|
+
const runnerSignature = formatRunnerSignature({
|
|
77213
|
+
runnerName: result.runnerName,
|
|
77214
|
+
modelName: result.modelName,
|
|
77215
|
+
thinkingLevel: result.thinkingLevel,
|
|
77216
|
+
});
|
|
75936
77217
|
const loginMethodLabel = formatCodexLoginMethod(result.loginMethod);
|
|
75937
77218
|
const loginMethodSuffix = loginMethodLabel === undefined ? '' : ` (${loginMethodLabel})`;
|
|
75938
77219
|
console.info(colors.green(`🏓 ${runnerSignature}${loginMethodSuffix} answered in ${formatCoderPingResponseTime(result.durationMs)}`));
|
|
@@ -76733,6 +78014,23 @@ function listenForCoderRunControls() {
|
|
|
76733
78014
|
});
|
|
76734
78015
|
}
|
|
76735
78016
|
|
|
78017
|
+
/**
|
|
78018
|
+
* Commits newly initialized, non-ignored agent books before the coder's clean-tree checkpoint.
|
|
78019
|
+
* Only books created by this run are eligible; existing books and unrelated changes remain outside the commit.
|
|
78020
|
+
*/
|
|
78021
|
+
async function commitInitializedAgentBooks(projectPath, createdAgentBookPaths) {
|
|
78022
|
+
if (createdAgentBookPaths.length === 0) {
|
|
78023
|
+
return;
|
|
78024
|
+
}
|
|
78025
|
+
const createdPaths = new Set(createdAgentBookPaths.map((filePath) => resolve(filePath)));
|
|
78026
|
+
const changedPaths = await listWorkingTreeChangedFiles(projectPath);
|
|
78027
|
+
const relevantPaths = changedPaths.filter((filePath) => createdPaths.has(resolve(projectPath, filePath)));
|
|
78028
|
+
if (relevantPaths.length === 0) {
|
|
78029
|
+
return;
|
|
78030
|
+
}
|
|
78031
|
+
await commitChanges('Initialize Adam agent', { projectPath, relevantPaths });
|
|
78032
|
+
}
|
|
78033
|
+
|
|
76736
78034
|
/**
|
|
76737
78035
|
* Checks working tree clean.
|
|
76738
78036
|
*/
|
|
@@ -78420,11 +79718,11 @@ function toPromptRunnerAttribution(runnerSignatures) {
|
|
|
78420
79718
|
* Builds the shared body of a prompt status line, used by both the in-progress `[^]` and the done `[x]` status.
|
|
78421
79719
|
*
|
|
78422
79720
|
* Produces details such as
|
|
78423
|
-
* ``by OpenAI Codex `gpt-5.6-luna` thinking `max` (ChatGPT account) - Implementation ~$0.2036 10 minutes``.
|
|
79721
|
+
* ``by Developer on OpenAI Codex `gpt-5.6-luna` thinking `max` (ChatGPT account) - Implementation ~$0.2036 10 minutes``.
|
|
78424
79722
|
*/
|
|
78425
79723
|
function buildPromptStatusDetails(options) {
|
|
78426
|
-
const { steps, inProgressStepKind,
|
|
78427
|
-
const runnerSignature = formatRunnerSignature(
|
|
79724
|
+
const { steps, inProgressStepKind, previousRunnerSignatures, attemptCount, loginMethod } = options;
|
|
79725
|
+
const runnerSignature = formatRunnerSignature(options);
|
|
78428
79726
|
const attemptMetadata = formatPromptAttemptMetadata('done', attemptCount);
|
|
78429
79727
|
const loginMethodLabel = formatCodexLoginMethod(loginMethod);
|
|
78430
79728
|
const loginMethodSuffix = loginMethodLabel ? ` (${loginMethodLabel})` : '';
|
|
@@ -78536,9 +79834,9 @@ function markPromptDone(options) {
|
|
|
78536
79834
|
* Marks a prompt section as failed and records runner details.
|
|
78537
79835
|
*/
|
|
78538
79836
|
function markPromptFailed(options) {
|
|
78539
|
-
const { file, section,
|
|
79837
|
+
const { file, section, previousRunnerSignatures, promptExecutionStartedDate, attemptCount } = options;
|
|
78540
79838
|
const attribution = formatPromptRunnerAttribution({
|
|
78541
|
-
currentRunnerSignature: formatRunnerSignature(
|
|
79839
|
+
currentRunnerSignature: formatRunnerSignature(options),
|
|
78542
79840
|
previousRunnerSignatures,
|
|
78543
79841
|
});
|
|
78544
79842
|
const attemptMetadata = formatPromptAttemptMetadata('failed', attemptCount);
|
|
@@ -78624,9 +79922,9 @@ function getSafeCodeBlock(content, language = 'markdown') {
|
|
|
78624
79922
|
/**
|
|
78625
79923
|
* Renders the markdown run trace of one finished or failed prompt round.
|
|
78626
79924
|
*
|
|
78627
|
-
* The trace pairs the metadata of the round - which harness, model and thinking level ran it, how long
|
|
78628
|
-
* its steps took and what it cost - with the untouched runtime log, so a finished round can still be
|
|
78629
|
-
* after its temporary artifacts are cleaned up.
|
|
79925
|
+
* The trace pairs the metadata of the round - which agent, harness, model and thinking level ran it, how long
|
|
79926
|
+
* each of its steps took and what it cost - with the untouched runtime log, so a finished round can still be
|
|
79927
|
+
* analyzed after its temporary artifacts are cleaned up.
|
|
78630
79928
|
*/
|
|
78631
79929
|
function buildPromptRunTraceContent(options) {
|
|
78632
79930
|
const sections = [
|
|
@@ -78641,7 +79939,7 @@ function buildPromptRunTraceContent(options) {
|
|
|
78641
79939
|
*/
|
|
78642
79940
|
function buildPromptRunTraceSummarySection(options) {
|
|
78643
79941
|
const { file, section, outcome } = options;
|
|
78644
|
-
const runnerSignature = formatRunnerSignature(options
|
|
79942
|
+
const runnerSignature = formatRunnerSignature(options);
|
|
78645
79943
|
const loginMethodLabel = outcome.kind === 'succeeded' ? formatCodexLoginMethod(outcome.loginMethod) : undefined;
|
|
78646
79944
|
const loginMethodSuffix = loginMethodLabel ? ` (${loginMethodLabel})` : '';
|
|
78647
79945
|
const detailLines = [
|
|
@@ -78951,8 +80249,7 @@ async function recordPromptRoundInProgress(options) {
|
|
|
78951
80249
|
section: nextPrompt.section,
|
|
78952
80250
|
steps: progress.finishedSteps,
|
|
78953
80251
|
inProgressStepKind: progress.startedStepKind,
|
|
78954
|
-
|
|
78955
|
-
modelName: runnerMetadata.modelName,
|
|
80252
|
+
...runnerMetadata,
|
|
78956
80253
|
previousRunnerSignatures,
|
|
78957
80254
|
attemptCount,
|
|
78958
80255
|
loginMethod: progress.loginMethod,
|
|
@@ -79022,8 +80319,7 @@ async function finalizeSuccessfulPromptRound(options) {
|
|
|
79022
80319
|
file: nextPrompt.file,
|
|
79023
80320
|
section: nextPrompt.section,
|
|
79024
80321
|
steps: result.steps,
|
|
79025
|
-
|
|
79026
|
-
modelName: runnerMetadata.modelName,
|
|
80322
|
+
...runnerMetadata,
|
|
79027
80323
|
previousRunnerSignatures,
|
|
79028
80324
|
attemptCount: result.attemptCount,
|
|
79029
80325
|
loginMethod: result.loginMethod,
|
|
@@ -79102,8 +80398,7 @@ async function finalizeFailedPromptRound(options) {
|
|
|
79102
80398
|
markPromptFailed({
|
|
79103
80399
|
file: nextPrompt.file,
|
|
79104
80400
|
section: nextPrompt.section,
|
|
79105
|
-
|
|
79106
|
-
modelName: runnerMetadata.modelName,
|
|
80401
|
+
...runnerMetadata,
|
|
79107
80402
|
previousRunnerSignatures,
|
|
79108
80403
|
promptExecutionStartedDate,
|
|
79109
80404
|
attemptCount,
|
|
@@ -79133,16 +80428,15 @@ async function finalizeFailedPromptRound(options) {
|
|
|
79133
80428
|
* Persists the run trace of one prompt round, so the round can still be analyzed after its temporary
|
|
79134
80429
|
* artifacts are gone.
|
|
79135
80430
|
*
|
|
79136
|
-
* This is the single place where both the successful and the failed round record what they did, which
|
|
79137
|
-
* model and thinking level did it and everything that harness has written while doing it.
|
|
80431
|
+
* This is the single place where both the successful and the failed round record what they did, which agent,
|
|
80432
|
+
* harness, model and thinking level did it and everything that harness has written while doing it.
|
|
79138
80433
|
*/
|
|
79139
80434
|
async function recordPromptRoundTrace(options) {
|
|
79140
80435
|
const { options: runOptions, nextPrompt, runnerMetadata, promptExecutionStartedDate, attemptCount, logPath, outcome, } = options;
|
|
79141
80436
|
await writePromptRunTrace({
|
|
79142
80437
|
file: nextPrompt.file,
|
|
79143
80438
|
section: nextPrompt.section,
|
|
79144
|
-
|
|
79145
|
-
modelName: runnerMetadata.modelName,
|
|
80439
|
+
...runnerMetadata,
|
|
79146
80440
|
thinkingLevel: runOptions.thinkingLevel,
|
|
79147
80441
|
testCommand: runOptions.testCommand,
|
|
79148
80442
|
attemptCount,
|
|
@@ -80106,7 +81400,16 @@ async function runCodexPrompts(providedOptions) {
|
|
|
80106
81400
|
if (await runDryRunIfRequested(options)) {
|
|
80107
81401
|
return;
|
|
80108
81402
|
}
|
|
80109
|
-
|
|
81403
|
+
if (!options.noCommit && resolvedCoderAgent) {
|
|
81404
|
+
await commitInitializedAgentBooks(process.cwd(), resolvedCoderAgent.createdAgentBookPaths);
|
|
81405
|
+
}
|
|
81406
|
+
const { runner, actualRunnerModel, runnerMetadata: harnessRunnerMetadata } = resolvePromptRunner(options);
|
|
81407
|
+
// Note: The harness only knows itself, so the Book agent it runs as is joined here - this is the single
|
|
81408
|
+
// place where the whole run report of prompt status lines and run traces is put together
|
|
81409
|
+
const runnerMetadata = {
|
|
81410
|
+
...harnessRunnerMetadata,
|
|
81411
|
+
agentName: resolvedCoderAgent === null || resolvedCoderAgent === void 0 ? void 0 : resolvedCoderAgent.agentName,
|
|
81412
|
+
};
|
|
80110
81413
|
const promptRunnerIdentity = {
|
|
80111
81414
|
harnessName: options.agentName,
|
|
80112
81415
|
modelName: actualRunnerModel,
|