@promptbook/cli 0.114.0-38 → 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/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 +1069 -31
- 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 +4 -0
- package/esm/scripts/run-codex-prompts/git/commitInitializedAgentBooks.d.ts +5 -0
- package/esm/src/book-2.0/agent-source/AgentReferenceResolutionIssue.d.ts +45 -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/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 +1 -1
- package/src/book-2.0/agent-source/AgentReferenceResolutionIssue.ts +75 -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/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/other/templates/getTemplatesPipelineCollection.ts +650 -928
- package/src/version.ts +2 -2
- package/src/versions.txt +1 -0
- package/umd/index.umd.js +1069 -31
- 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 +4 -0
- package/umd/scripts/run-codex-prompts/git/commitInitializedAgentBooks.d.ts +5 -0
- package/umd/src/book-2.0/agent-source/AgentReferenceResolutionIssue.d.ts +45 -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/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,7 +48,7 @@ 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
|
|
@@ -1319,6 +1319,12 @@ const DEFAULT_INTERMEDIATE_FILES_STRATEGY = 'HIDE_AND_KEEP';
|
|
|
1319
1319
|
* @public exported from `@promptbook/core`
|
|
1320
1320
|
*/
|
|
1321
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;
|
|
1322
1328
|
/**
|
|
1323
1329
|
* The maximum number of attempts to execute LLM task before giving up
|
|
1324
1330
|
*
|
|
@@ -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
|
/**
|
|
@@ -39682,8 +39734,8 @@ function extractMcpServers(agentSource) {
|
|
|
39682
39734
|
/**
|
|
39683
39735
|
* Compiles agent source into the behavior text passed to CLI harness runners.
|
|
39684
39736
|
*/
|
|
39685
|
-
async function createAgentRunnerSystemMessage(agentSource) {
|
|
39686
|
-
return formatAgentModelRequirementsForRunner(await createAgentModelRequirements(agentSource));
|
|
39737
|
+
async function createAgentRunnerSystemMessage(agentSource, options) {
|
|
39738
|
+
return formatAgentModelRequirementsForRunner(await createAgentModelRequirements(agentSource, undefined, undefined, undefined, options));
|
|
39687
39739
|
}
|
|
39688
39740
|
/**
|
|
39689
39741
|
* Formats prepared model requirements for a text-only CLI harness prompt.
|
|
@@ -43679,6 +43731,59 @@ function buildPromptSlug$1(templateSlugPrefix, title) {
|
|
|
43679
43731
|
// Note: [🟡] Code for CLI command [generate-boilerplates](src/cli/cli-commands/coder/generate-boilerplates.ts) should never be published outside of `@promptbook/cli`
|
|
43680
43732
|
// Note: [💞] Ignore a discrepancy between file name and entity name
|
|
43681
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
|
+
|
|
43682
43787
|
/**
|
|
43683
43788
|
* Asks the user in the terminal to confirm one optional change.
|
|
43684
43789
|
*
|
|
@@ -44482,29 +44587,9 @@ async function ensureCoderDeveloperAgentFile(projectPath) {
|
|
|
44482
44587
|
if (await isExistingFile$2(absoluteFilePath)) {
|
|
44483
44588
|
return 'unchanged';
|
|
44484
44589
|
}
|
|
44485
|
-
await copyFile(await
|
|
44590
|
+
await copyFile(await resolveBundledAgentBookPath(DEFAULT_CODER_DEVELOPER_AGENT_SOURCE_FILE_PATH), absoluteFilePath);
|
|
44486
44591
|
return 'created';
|
|
44487
44592
|
}
|
|
44488
|
-
/**
|
|
44489
|
-
* Resolves the bundled developer agent from a source checkout or generated CLI package.
|
|
44490
|
-
*/
|
|
44491
|
-
async function resolveDefaultCoderDeveloperAgentFilePath() {
|
|
44492
|
-
const candidates = [
|
|
44493
|
-
join(__dirname, '..', DEFAULT_CODER_DEVELOPER_AGENT_SOURCE_FILE_PATH),
|
|
44494
|
-
join(__dirname, '..', '..', '..', '..', DEFAULT_CODER_DEVELOPER_AGENT_SOURCE_FILE_PATH),
|
|
44495
|
-
];
|
|
44496
|
-
for (const candidate of candidates) {
|
|
44497
|
-
if (await isExistingFile$2(candidate)) {
|
|
44498
|
-
return candidate;
|
|
44499
|
-
}
|
|
44500
|
-
}
|
|
44501
|
-
throw new NotAllowed(spaceTrim$1(`
|
|
44502
|
-
Cannot find the bundled Promptbook developer agent.
|
|
44503
|
-
|
|
44504
|
-
Checked:
|
|
44505
|
-
${candidates.map((candidate) => `- \`${candidate}\``).join('\n')}
|
|
44506
|
-
`));
|
|
44507
|
-
}
|
|
44508
44593
|
/**
|
|
44509
44594
|
* Checks whether a path exists and is a file.
|
|
44510
44595
|
*/
|
|
@@ -44987,6 +45072,7 @@ async function initializeCoderProjectConfiguration(projectPath) {
|
|
|
44987
45072
|
const promptsDoneDirectoryStatus = await ensureDirectory(projectPath, PROMPTS_DONE_DIRECTORY_PATH);
|
|
44988
45073
|
const promptsTemplatesDirectoryStatus = await ensureDirectory(projectPath, PROMPTS_TEMPLATES_DIRECTORY_PATH);
|
|
44989
45074
|
const agentsDirectoryStatus = await ensureDirectory(projectPath, CODER_AGENTS_DIRECTORY_PATH);
|
|
45075
|
+
const adamAgentFileStatus = await ensureAdamAgentBook(join(projectPath, CODER_AGENTS_DIRECTORY_PATH));
|
|
44990
45076
|
const { envFileStatus, initializedEnvVariableNames } = await ensureCoderEnvFile(projectPath);
|
|
44991
45077
|
const gitignoreFileStatus = await ensureCoderGitignoreFile(projectPath);
|
|
44992
45078
|
const { status: packageJsonFileStatus, addedEntryKeys: addedPackageJsonScriptNames } = await ensureCoderPackageJsonFile(projectPath);
|
|
@@ -44997,6 +45083,7 @@ async function initializeCoderProjectConfiguration(projectPath) {
|
|
|
44997
45083
|
promptsDoneDirectoryStatus,
|
|
44998
45084
|
promptsTemplatesDirectoryStatus,
|
|
44999
45085
|
agentsDirectoryStatus,
|
|
45086
|
+
adamAgentFileStatus,
|
|
45000
45087
|
envFileStatus,
|
|
45001
45088
|
gitignoreFileStatus,
|
|
45002
45089
|
packageJsonFileStatus,
|
|
@@ -45019,6 +45106,7 @@ function printInitializationSummary(summary) {
|
|
|
45019
45106
|
printInitializationStatusLine('prompts/done/', summary.promptsDoneDirectoryStatus);
|
|
45020
45107
|
printInitializationStatusLine('prompts/templates/', summary.promptsTemplatesDirectoryStatus);
|
|
45021
45108
|
printInitializationStatusLine('agents/', summary.agentsDirectoryStatus);
|
|
45109
|
+
printInitializationStatusLine(`${CODER_AGENTS_DIRECTORY_PATH}/${ADAM_AGENT_BOOK_RELATIVE_PATH}`, summary.adamAgentFileStatus);
|
|
45022
45110
|
printInitializationStatusLine('.env', summary.envFileStatus);
|
|
45023
45111
|
printInitializationStatusLine('.gitignore', summary.gitignoreFileStatus);
|
|
45024
45112
|
printInitializationStatusLine('package.json', summary.packageJsonFileStatus);
|
|
@@ -45093,6 +45181,7 @@ function $initializeCoderInitCommand(program) {
|
|
|
45093
45181
|
- prompts/done/
|
|
45094
45182
|
${block(listDefaultCoderProjectPromptTemplateDisplayPaths())}
|
|
45095
45183
|
- ${CODER_DEVELOPER_AGENT_FILE_PATH}
|
|
45184
|
+
- ${CODER_AGENTS_DIRECTORY_PATH}/${ADAM_AGENT_BOOK_RELATIVE_PATH}
|
|
45096
45185
|
- ${AGENTS_FILE_PATH}
|
|
45097
45186
|
- .gitignore with local artifacts from every supported harness
|
|
45098
45187
|
- package.json
|
|
@@ -45237,8 +45326,7 @@ function $initializeCoderListCommand(program) {
|
|
|
45237
45326
|
const runnerOptions = normalizePromptRunnerSelectionCliOptions(cliOptions, { isAgentRequired: false });
|
|
45238
45327
|
const resolvedCoderAgentBook = agent === undefined
|
|
45239
45328
|
? undefined
|
|
45240
|
-
: await (await Promise.resolve().then(function () { return resolveCoderAgent$1; }))
|
|
45241
|
-
.resolveCoderAgentBook(agent, process.cwd());
|
|
45329
|
+
: await (await Promise.resolve().then(function () { return resolveCoderAgent$1; })).resolveCoderAgentBook(agent, process.cwd());
|
|
45242
45330
|
const promptRunnerIdentity = runnerOptions.agentName === undefined &&
|
|
45243
45331
|
runnerOptions.model === undefined &&
|
|
45244
45332
|
resolvedCoderAgentBook === undefined
|
|
@@ -45995,6 +46083,8 @@ function $initializeCoderRunCommand(program) {
|
|
|
45995
46083
|
${block(QUESTIONS_DESCRIPTION)}
|
|
45996
46084
|
|
|
45997
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
|
|
45998
46088
|
- Automatically stages and commits changes with agent identity unless --no-commit is used
|
|
45999
46089
|
- Commits only the prompt file and the files the coding agent has changed, leaving unrelated changes alone
|
|
46000
46090
|
- Refuses to start on a dirty working tree unless --git-changes says what should happen with the changes
|
|
@@ -46968,7 +47058,7 @@ function $provideFilesystemForNode(options) {
|
|
|
46968
47058
|
return {
|
|
46969
47059
|
stat,
|
|
46970
47060
|
access,
|
|
46971
|
-
constants,
|
|
47061
|
+
constants: constants$1,
|
|
46972
47062
|
readFile,
|
|
46973
47063
|
writeFile,
|
|
46974
47064
|
readdir,
|
|
@@ -75829,6 +75919,929 @@ var findUnwrittenPrompts$1 = /*#__PURE__*/Object.freeze({
|
|
|
75829
75919
|
findUnwrittenPrompts: findUnwrittenPrompts
|
|
75830
75920
|
});
|
|
75831
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
|
+
|
|
75832
76845
|
/**
|
|
75833
76846
|
* Reads an optional agent `.book` file and prepares the references that route prompts to it.
|
|
75834
76847
|
*
|
|
@@ -75873,9 +76886,14 @@ async function resolveCoderAgent(agentBookReference, currentWorkingDirectory) {
|
|
|
75873
76886
|
if (resolvedAgentBook === undefined) {
|
|
75874
76887
|
return undefined;
|
|
75875
76888
|
}
|
|
76889
|
+
const resolvedSource = await resolveLocalAgentSource(resolve(currentWorkingDirectory, agentBookReference.trim()), currentWorkingDirectory);
|
|
75876
76890
|
return {
|
|
75877
76891
|
...resolvedAgentBook,
|
|
75878
|
-
|
|
76892
|
+
agentSource: resolvedSource.agentSource,
|
|
76893
|
+
systemMessage: await createAgentRunnerSystemMessage(resolvedSource.agentSource, {
|
|
76894
|
+
agentReferenceResolver: resolvedSource.agentReferenceResolver,
|
|
76895
|
+
}),
|
|
76896
|
+
createdAgentBookPaths: resolvedSource.createdAgentBookPaths,
|
|
75879
76897
|
};
|
|
75880
76898
|
}
|
|
75881
76899
|
/**
|
|
@@ -76996,6 +78014,23 @@ function listenForCoderRunControls() {
|
|
|
76996
78014
|
});
|
|
76997
78015
|
}
|
|
76998
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
|
+
|
|
76999
78034
|
/**
|
|
77000
78035
|
* Checks working tree clean.
|
|
77001
78036
|
*/
|
|
@@ -80365,6 +81400,9 @@ async function runCodexPrompts(providedOptions) {
|
|
|
80365
81400
|
if (await runDryRunIfRequested(options)) {
|
|
80366
81401
|
return;
|
|
80367
81402
|
}
|
|
81403
|
+
if (!options.noCommit && resolvedCoderAgent) {
|
|
81404
|
+
await commitInitializedAgentBooks(process.cwd(), resolvedCoderAgent.createdAgentBookPaths);
|
|
81405
|
+
}
|
|
80368
81406
|
const { runner, actualRunnerModel, runnerMetadata: harnessRunnerMetadata } = resolvePromptRunner(options);
|
|
80369
81407
|
// Note: The harness only knows itself, so the Book agent it runs as is joined here - this is the single
|
|
80370
81408
|
// place where the whole run report of prompt status lines and run traces is put together
|