@promptbook/cli 0.114.0-30 → 0.114.0-32
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/esm/index.es.js +197 -25
- package/esm/index.es.js.map +1 -1
- package/esm/scripts/run-codex-prompts/prompts/findFirstNonEmptyLineIndex.d.ts +6 -0
- package/esm/scripts/run-codex-prompts/prompts/writePromptStatusLine.d.ts +3 -2
- package/esm/src/cli/cli-commands/coder/$ensureCoderHarnessGitignoreRules.d.ts +9 -0
- package/esm/src/cli/cli-commands/coder/$ensureCoderHarnessGitignoreRules.test.d.ts +1 -0
- package/esm/src/cli/cli-commands/coder/ensureCoderGitignoreFile.d.ts +14 -1
- package/esm/src/cli/cli-commands/coder/server.test.d.ts +1 -0
- package/esm/src/cli/cli-commands/common/$askForConfirmation.d.ts +9 -0
- package/esm/src/cli/cli-commands/common/harness/HarnessDefinition.d.ts +10 -0
- package/esm/src/cli/cli-commands/common/projectInitialization.d.ts +6 -0
- package/esm/src/version.d.ts +1 -1
- package/package.json +1 -1
- package/src/cli/cli-commands/coder/$ensureCoderHarnessGitignoreRules.ts +51 -0
- package/src/cli/cli-commands/coder/ensureCoderGitignoreFile.ts +37 -3
- package/src/cli/cli-commands/coder/init.ts +1 -1
- package/src/cli/cli-commands/coder/ping.ts +3 -1
- package/src/cli/cli-commands/coder/run.ts +3 -0
- package/src/cli/cli-commands/coder/server.ts +3 -0
- package/src/cli/cli-commands/common/$askForConfirmation.ts +31 -0
- package/src/cli/cli-commands/common/harness/HarnessDefinition.ts +25 -0
- package/src/cli/cli-commands/common/npm/$askForNpmPackageInstallationApproval.ts +2 -18
- package/src/cli/cli-commands/common/projectInitialization.ts +25 -2
- package/src/other/templates/getTemplatesPipelineCollection.ts +645 -964
- package/src/version.ts +2 -2
- package/src/versions.txt +2 -0
- package/umd/index.umd.js +197 -25
- package/umd/index.umd.js.map +1 -1
- package/umd/scripts/run-codex-prompts/prompts/findFirstNonEmptyLineIndex.d.ts +6 -0
- package/umd/scripts/run-codex-prompts/prompts/writePromptStatusLine.d.ts +3 -2
- package/umd/src/cli/cli-commands/coder/$ensureCoderHarnessGitignoreRules.d.ts +9 -0
- package/umd/src/cli/cli-commands/coder/$ensureCoderHarnessGitignoreRules.test.d.ts +1 -0
- package/umd/src/cli/cli-commands/coder/ensureCoderGitignoreFile.d.ts +14 -1
- package/umd/src/cli/cli-commands/coder/server.test.d.ts +1 -0
- package/umd/src/cli/cli-commands/common/$askForConfirmation.d.ts +9 -0
- package/umd/src/cli/cli-commands/common/harness/HarnessDefinition.d.ts +10 -0
- package/umd/src/cli/cli-commands/common/projectInitialization.d.ts +6 -0
- package/umd/src/version.d.ts +1 -1
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Finds the first non-empty line within the inclusive bounds.
|
|
3
|
+
*
|
|
4
|
+
* @private internal utility of prompt parsing and status writing
|
|
5
|
+
*/
|
|
6
|
+
export declare function findFirstNonEmptyLineIndex(lines: readonly string[], startLine: number, endLine: number): number | undefined;
|
|
@@ -3,7 +3,8 @@ import type { PromptSection } from './types/PromptSection';
|
|
|
3
3
|
/**
|
|
4
4
|
* Rewrites the status line of one prompt section while preserving its indentation.
|
|
5
5
|
*
|
|
6
|
-
*
|
|
7
|
-
* `[
|
|
6
|
+
* An unmarked prompt is implicitly a todo, so its first live status line is inserted immediately before its content.
|
|
7
|
+
* Only a todo `[ ]` or an in-progress `[^]` status line is otherwise rewritten, so an already finalized `[x]`, `[!]`
|
|
8
|
+
* or `[-]` status is never overwritten by accident.
|
|
8
9
|
*/
|
|
9
10
|
export declare function writePromptStatusLine(file: PromptFile, section: PromptSection, replacementStatusLine: string): void;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { PromptRunnerHarnessName } from '../common/promptRunnerCliOptions';
|
|
2
|
+
/**
|
|
3
|
+
* Offers to add missing project-local ignore rules for the selected coding harness.
|
|
4
|
+
*
|
|
5
|
+
* Note: `$` is used to indicate that this function is not a pure function - it may ask the user and update `.gitignore`.
|
|
6
|
+
*
|
|
7
|
+
* @private internal utility of `ptbk coder`
|
|
8
|
+
*/
|
|
9
|
+
export declare function $ensureCoderHarnessGitignoreRules(projectPath: string, harnessName: PromptRunnerHarnessName | undefined): Promise<void>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1,7 +1,20 @@
|
|
|
1
|
+
import { type PromptRunnerHarnessName } from '../common/promptRunnerCliOptions';
|
|
1
2
|
import type { InitializationStatus } from './boilerplateTemplates';
|
|
2
3
|
/**
|
|
3
|
-
* Ensures `.gitignore` contains
|
|
4
|
+
* Ensures `.gitignore` contains Promptbook Coder's local artifacts and every supported harness's local artifacts.
|
|
4
5
|
*
|
|
5
6
|
* @private function of `initializeCoderProjectConfiguration`
|
|
6
7
|
*/
|
|
7
8
|
export declare function ensureCoderGitignoreFile(projectPath: string): Promise<InitializationStatus>;
|
|
9
|
+
/**
|
|
10
|
+
* Lists missing project-local ignore rules for the selected harnesses.
|
|
11
|
+
*
|
|
12
|
+
* @private internal utility of `ptbk coder`
|
|
13
|
+
*/
|
|
14
|
+
export declare function getMissingCoderHarnessGitignoreRules(projectPath: string, harnessNames: ReadonlyArray<PromptRunnerHarnessName>): Promise<ReadonlyArray<string>>;
|
|
15
|
+
/**
|
|
16
|
+
* Adds the given Promptbook Coder rules to a project's `.gitignore` file.
|
|
17
|
+
*
|
|
18
|
+
* @private internal utility of `ptbk coder`
|
|
19
|
+
*/
|
|
20
|
+
export declare function ensureCoderGitignoreRules(projectPath: string, rules: ReadonlyArray<string>): Promise<InitializationStatus>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Asks the user in the terminal to confirm one optional change.
|
|
3
|
+
*
|
|
4
|
+
* Note: `$` is used to indicate that this function is not a pure function - it reads the answer from stdin.
|
|
5
|
+
*
|
|
6
|
+
* @returns `true` when the user confirms, `false` when the user declines or the terminal is not interactive.
|
|
7
|
+
* @private internal utility of `promptbookCli`
|
|
8
|
+
*/
|
|
9
|
+
export declare function $askForConfirmation(question: string): Promise<boolean>;
|
|
@@ -45,6 +45,10 @@ export type HarnessDefinition = {
|
|
|
45
45
|
* Extra environment variables required by the global npm installation of this harness.
|
|
46
46
|
*/
|
|
47
47
|
readonly npmInstallEnvironment?: Readonly<Record<string, string>>;
|
|
48
|
+
/**
|
|
49
|
+
* Project-local files or directories which this harness can create and which should not be committed.
|
|
50
|
+
*/
|
|
51
|
+
readonly projectGitignoreRules: ReadonlyArray<string>;
|
|
48
52
|
/**
|
|
49
53
|
* How a standalone installation of this harness is recognized and updated.
|
|
50
54
|
*
|
|
@@ -64,3 +68,9 @@ export declare const HARNESS_DEFINITIONS: Readonly<Record<PromptRunnerHarnessNam
|
|
|
64
68
|
* @private internal utility of `promptbookCli`
|
|
65
69
|
*/
|
|
66
70
|
export declare function getHarnessDefinition(harnessName: PromptRunnerHarnessName): HarnessDefinition;
|
|
71
|
+
/**
|
|
72
|
+
* Lists the unique project ignore rules required by the selected harnesses, in selection order.
|
|
73
|
+
*
|
|
74
|
+
* @private internal utility of `promptbookCli`
|
|
75
|
+
*/
|
|
76
|
+
export declare function getHarnessProjectGitignoreRules(harnessNames: ReadonlyArray<PromptRunnerHarnessName>): ReadonlyArray<string>;
|
|
@@ -50,6 +50,12 @@ export declare function ensureProjectEnvFile<TEnvVariable extends ProjectEnvVari
|
|
|
50
50
|
* @private internal utility of Promptbook CLI project initialization
|
|
51
51
|
*/
|
|
52
52
|
export declare function ensureProjectGitignoreFile({ projectPath, blockHeader, rules, }: EnsureProjectGitignoreFileOptions): Promise<ProjectInitializationStatus>;
|
|
53
|
+
/**
|
|
54
|
+
* Lists the ignore rules which are not yet present in a project's `.gitignore` file.
|
|
55
|
+
*
|
|
56
|
+
* @private internal utility of Promptbook CLI project initialization
|
|
57
|
+
*/
|
|
58
|
+
export declare function getMissingProjectGitignoreRules(projectPath: string, rules: ReadonlyArray<string>): Promise<ReadonlyArray<string>>;
|
|
53
59
|
/**
|
|
54
60
|
* Reads one text file when it exists, otherwise returns `undefined`.
|
|
55
61
|
*
|
package/esm/src/version.d.ts
CHANGED
|
@@ -15,7 +15,7 @@ export declare const BOOK_LANGUAGE_VERSION: string_semantic_version;
|
|
|
15
15
|
export declare const PROMPTBOOK_ENGINE_VERSION: string_promptbook_version;
|
|
16
16
|
/**
|
|
17
17
|
* Represents the version string of the Promptbook engine.
|
|
18
|
-
* It follows semantic versioning (e.g., `0.114.0-
|
|
18
|
+
* It follows semantic versioning (e.g., `0.114.0-31`).
|
|
19
19
|
*
|
|
20
20
|
* @generated
|
|
21
21
|
*/
|
package/package.json
CHANGED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import colors from 'colors';
|
|
2
|
+
import type { PromptRunnerHarnessName } from '../common/promptRunnerCliOptions';
|
|
3
|
+
import { $askForConfirmation } from '../common/$askForConfirmation';
|
|
4
|
+
import { getHarnessDefinition } from '../common/harness/HarnessDefinition';
|
|
5
|
+
import { ensureCoderGitignoreRules, getMissingCoderHarnessGitignoreRules } from './ensureCoderGitignoreFile';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Offers to add missing project-local ignore rules for the selected coding harness.
|
|
9
|
+
*
|
|
10
|
+
* Note: `$` is used to indicate that this function is not a pure function - it may ask the user and update `.gitignore`.
|
|
11
|
+
*
|
|
12
|
+
* @private internal utility of `ptbk coder`
|
|
13
|
+
*/
|
|
14
|
+
export async function $ensureCoderHarnessGitignoreRules(
|
|
15
|
+
projectPath: string,
|
|
16
|
+
harnessName: PromptRunnerHarnessName | undefined,
|
|
17
|
+
): Promise<void> {
|
|
18
|
+
if (harnessName === undefined) {
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const missingRules = await getMissingCoderHarnessGitignoreRules(projectPath, [harnessName]);
|
|
23
|
+
|
|
24
|
+
if (missingRules.length === 0) {
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const { label } = getHarnessDefinition(harnessName);
|
|
29
|
+
const formattedRules = formatGitignoreRules(missingRules);
|
|
30
|
+
const entryLabel = missingRules.length === 1 ? 'entry' : 'entries';
|
|
31
|
+
const isAdditionApproved = await $askForConfirmation(
|
|
32
|
+
`Add the missing ${label} ignore ${entryLabel} ${formattedRules} to \`.gitignore\` now?`,
|
|
33
|
+
);
|
|
34
|
+
|
|
35
|
+
if (!isAdditionApproved) {
|
|
36
|
+
console.info(colors.gray(`Skipped, add ${formattedRules} to \`.gitignore\` manually.`));
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
await ensureCoderGitignoreRules(projectPath, missingRules);
|
|
41
|
+
console.info(colors.gray(`✔ Added ${formattedRules} to \`.gitignore\`.`));
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Formats one or more `.gitignore` rules for a terminal confirmation message.
|
|
46
|
+
*/
|
|
47
|
+
function formatGitignoreRules(rules: ReadonlyArray<string>): string {
|
|
48
|
+
return rules.map((rule) => `\`${rule}\``).join(', ');
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Note: [🟡] Code for coder harness gitignore prompts [$ensureCoderHarnessGitignoreRules](src/cli/cli-commands/coder/$ensureCoderHarnessGitignoreRules.ts) should never be published outside of `@promptbook/cli`
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { getPromptbookTemporaryGitignoreRule } from '../../../utils/filesystem/promptbookTemporaryPath';
|
|
2
|
+
import { PROMPT_RUNNER_HARNESS_NAMES, type PromptRunnerHarnessName } from '../common/promptRunnerCliOptions';
|
|
3
|
+
import { getHarnessProjectGitignoreRules } from '../common/harness/HarnessDefinition';
|
|
2
4
|
import type { InitializationStatus } from './boilerplateTemplates';
|
|
3
|
-
import { ensureProjectGitignoreFile } from '../common/projectInitialization';
|
|
5
|
+
import { ensureProjectGitignoreFile, getMissingProjectGitignoreRules } from '../common/projectInitialization';
|
|
4
6
|
|
|
5
7
|
/**
|
|
6
8
|
* Promptbook temporary root directory that should stay out of version control.
|
|
@@ -18,15 +20,47 @@ const CODER_ENV_GITIGNORE_RULE = '.env';
|
|
|
18
20
|
const CODER_GITIGNORE_HEADER = '# Promptbook Coder';
|
|
19
21
|
|
|
20
22
|
/**
|
|
21
|
-
*
|
|
23
|
+
* Coder-owned local artifacts which every initialized project should ignore.
|
|
24
|
+
*/
|
|
25
|
+
const CODER_GITIGNORE_RULES = [PROMPTBOOK_TEMP_GITIGNORE_RULE, CODER_ENV_GITIGNORE_RULE] as const;
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Ensures `.gitignore` contains Promptbook Coder's local artifacts and every supported harness's local artifacts.
|
|
22
29
|
*
|
|
23
30
|
* @private function of `initializeCoderProjectConfiguration`
|
|
24
31
|
*/
|
|
25
32
|
export async function ensureCoderGitignoreFile(projectPath: string): Promise<InitializationStatus> {
|
|
33
|
+
return ensureCoderGitignoreRules(projectPath, [
|
|
34
|
+
...CODER_GITIGNORE_RULES,
|
|
35
|
+
...getHarnessProjectGitignoreRules(PROMPT_RUNNER_HARNESS_NAMES),
|
|
36
|
+
]);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Lists missing project-local ignore rules for the selected harnesses.
|
|
41
|
+
*
|
|
42
|
+
* @private internal utility of `ptbk coder`
|
|
43
|
+
*/
|
|
44
|
+
export async function getMissingCoderHarnessGitignoreRules(
|
|
45
|
+
projectPath: string,
|
|
46
|
+
harnessNames: ReadonlyArray<PromptRunnerHarnessName>,
|
|
47
|
+
): Promise<ReadonlyArray<string>> {
|
|
48
|
+
return getMissingProjectGitignoreRules(projectPath, getHarnessProjectGitignoreRules(harnessNames));
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Adds the given Promptbook Coder rules to a project's `.gitignore` file.
|
|
53
|
+
*
|
|
54
|
+
* @private internal utility of `ptbk coder`
|
|
55
|
+
*/
|
|
56
|
+
export async function ensureCoderGitignoreRules(
|
|
57
|
+
projectPath: string,
|
|
58
|
+
rules: ReadonlyArray<string>,
|
|
59
|
+
): Promise<InitializationStatus> {
|
|
26
60
|
return ensureProjectGitignoreFile({
|
|
27
61
|
projectPath,
|
|
28
62
|
blockHeader: CODER_GITIGNORE_HEADER,
|
|
29
|
-
rules
|
|
63
|
+
rules,
|
|
30
64
|
});
|
|
31
65
|
}
|
|
32
66
|
|
|
@@ -62,7 +62,7 @@ export function $initializeCoderInitCommand(program: Program): $side_effect {
|
|
|
62
62
|
- ${CODER_DEVELOPER_AGENT_FILE_PATH}
|
|
63
63
|
- ${AGENTS_FILE_PATH}
|
|
64
64
|
- ${AGENT_CODING_FILE_PATH}
|
|
65
|
-
- .gitignore
|
|
65
|
+
- .gitignore with local artifacts from every supported harness
|
|
66
66
|
- package.json
|
|
67
67
|
- .vscode/settings.json
|
|
68
68
|
|
|
@@ -18,6 +18,7 @@ import {
|
|
|
18
18
|
PROMPT_RUNNER_DESCRIPTION,
|
|
19
19
|
} from '../common/promptRunnerCliOptions';
|
|
20
20
|
import { parseOptionalPeriodDuration } from './waitOptions';
|
|
21
|
+
import { $ensureCoderHarnessGitignoreRules } from './$ensureCoderHarnessGitignoreRules';
|
|
21
22
|
|
|
22
23
|
/**
|
|
23
24
|
* Initializes `coder ping` command for Promptbook CLI utilities
|
|
@@ -39,7 +40,7 @@ export function $initializeCoderPingCommand(program: Program): $side_effect {
|
|
|
39
40
|
- Reports the answer of the harness, the response time and the reported usage
|
|
40
41
|
- Starts the hourly/weekly quota window before you need it, so it is already refreshing when you do
|
|
41
42
|
- Optional --period keeps the quota window refreshing by pinging once per period until stopped
|
|
42
|
-
-
|
|
43
|
+
- Makes no coding changes or commits; if the selected harness has missing local ignore rules, offers to add them to .gitignore
|
|
43
44
|
- Checks that the selected harness is installed and up to date unless --no-harness-update is used
|
|
44
45
|
- Use --no-ui to stream the raw harness output instead of only the compact result
|
|
45
46
|
`),
|
|
@@ -74,6 +75,7 @@ export function $initializeCoderPingCommand(program: Program): $side_effect {
|
|
|
74
75
|
const periodMs = parseOptionalPeriodDuration('--period', periodValue);
|
|
75
76
|
|
|
76
77
|
await $ensureHarnessInstallations([runnerOptions.agentName], isHarnessUpdateCheckEnabled);
|
|
78
|
+
await $ensureCoderHarnessGitignoreRules(process.cwd(), runnerOptions.agentName);
|
|
77
79
|
|
|
78
80
|
const pingOptions = {
|
|
79
81
|
agentName: runnerOptions.agentName,
|
|
@@ -29,6 +29,7 @@ import {
|
|
|
29
29
|
type TestBeforeMode,
|
|
30
30
|
} from '../../../../scripts/run-codex-prompts/testing/TestBeforeMode';
|
|
31
31
|
import { DEFAULT_WAIT_AFTER_ERROR_MS, parseOptionalWaitDuration } from './waitOptions';
|
|
32
|
+
import { $ensureCoderHarnessGitignoreRules } from './$ensureCoderHarnessGitignoreRules';
|
|
32
33
|
|
|
33
34
|
/**
|
|
34
35
|
* Initializes `coder run` command for Promptbook CLI utilities
|
|
@@ -56,6 +57,7 @@ export function $initializeCoderRunCommand(program: Program): $side_effect {
|
|
|
56
57
|
- Optional --preserve-logs keeps temp prompt/log artifacts after successful rounds
|
|
57
58
|
- Optional --no-ui keeps plain streaming console output for logging and debugging
|
|
58
59
|
- Checks that the selected harness is installed and up to date before the first prompt unless --no-harness-update is used
|
|
60
|
+
- Offers to add missing project-local ignore rules for the selected harness
|
|
59
61
|
- In interactive mode, checks local and global Promptbook CLI installations and offers to update them
|
|
60
62
|
- Supports GPG signing of commits
|
|
61
63
|
- Optional pre-coding test run that can stop or repair pre-existing failures
|
|
@@ -223,6 +225,7 @@ export function $initializeCoderRunCommand(program: Program): $side_effect {
|
|
|
223
225
|
}
|
|
224
226
|
|
|
225
227
|
await $ensureHarnessInstallations([runnerOptions.agentName], isHarnessUpdateCheckEnabled);
|
|
228
|
+
await $ensureCoderHarnessGitignoreRules(process.cwd(), runnerOptions.agentName);
|
|
226
229
|
|
|
227
230
|
const waitAfterPrompt = parseOptionalWaitDuration(waitAfterPromptValue, 0);
|
|
228
231
|
const waitBetweenPrompts = parseOptionalWaitDuration(waitBetweenPromptsValue, 0);
|
|
@@ -25,6 +25,7 @@ import {
|
|
|
25
25
|
PROMPT_RUNNER_DESCRIPTION,
|
|
26
26
|
} from '../common/promptRunnerCliOptions';
|
|
27
27
|
import { DEFAULT_WAIT_AFTER_ERROR_MS, parseOptionalWaitDuration } from './waitOptions';
|
|
28
|
+
import { $ensureCoderHarnessGitignoreRules } from './$ensureCoderHarnessGitignoreRules';
|
|
28
29
|
|
|
29
30
|
/**
|
|
30
31
|
* Default port used by `ptbk coder server`.
|
|
@@ -54,6 +55,7 @@ export function $initializeCoderServerCommand(program: Program): $side_effect {
|
|
|
54
55
|
Features:
|
|
55
56
|
- Runs the same prompt processing as \`ptbk coder run\`
|
|
56
57
|
- Checks that the selected harness is installed and up to date on startup unless --no-harness-update is used
|
|
58
|
+
- Offers to add missing project-local ignore rules for the selected harness
|
|
57
59
|
- Does not exit when all prompts are done; polls for new prompt files instead
|
|
58
60
|
- Serves a kanban board at http://localhost:<port> for visual progress tracking
|
|
59
61
|
- Allows editing prompt files directly from the browser (Trello-style)
|
|
@@ -184,6 +186,7 @@ export function $initializeCoderServerCommand(program: Program): $side_effect {
|
|
|
184
186
|
);
|
|
185
187
|
|
|
186
188
|
await $ensureHarnessInstallations([runnerOptions.agentName], isHarnessUpdateCheckEnabled);
|
|
189
|
+
await $ensureCoderHarnessGitignoreRules(process.cwd(), runnerOptions.agentName);
|
|
187
190
|
|
|
188
191
|
// [1] Parse the wait options and --no-auto (same logic as `coder run`)
|
|
189
192
|
const waitForUser = !auto;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import colors from 'colors';
|
|
2
|
+
import { createInterface } from 'readline';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Asks the user in the terminal to confirm one optional change.
|
|
6
|
+
*
|
|
7
|
+
* Note: `$` is used to indicate that this function is not a pure function - it reads the answer from stdin.
|
|
8
|
+
*
|
|
9
|
+
* @returns `true` when the user confirms, `false` when the user declines or the terminal is not interactive.
|
|
10
|
+
* @private internal utility of `promptbookCli`
|
|
11
|
+
*/
|
|
12
|
+
export async function $askForConfirmation(question: string): Promise<boolean> {
|
|
13
|
+
if (!process.stdin.isTTY) {
|
|
14
|
+
// Note: In non-interactive environments like CI there is nobody who could confirm the change.
|
|
15
|
+
return false;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const readlineInterface = createInterface({ input: process.stdin, output: process.stdout });
|
|
19
|
+
|
|
20
|
+
try {
|
|
21
|
+
const answer = await new Promise<string>((resolve) => {
|
|
22
|
+
readlineInterface.question(colors.cyan(`${question} [y/N] `), resolve);
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
return ['y', 'yes'].includes(answer.trim().toLowerCase());
|
|
26
|
+
} finally {
|
|
27
|
+
readlineInterface.close();
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Note: [🟡] Code for CLI confirmations [$askForConfirmation](src/cli/cli-commands/common/$askForConfirmation.ts) should never be published outside of `@promptbook/cli`
|
|
@@ -55,6 +55,11 @@ export type HarnessDefinition = {
|
|
|
55
55
|
*/
|
|
56
56
|
readonly npmInstallEnvironment?: Readonly<Record<string, string>>;
|
|
57
57
|
|
|
58
|
+
/**
|
|
59
|
+
* Project-local files or directories which this harness can create and which should not be committed.
|
|
60
|
+
*/
|
|
61
|
+
readonly projectGitignoreRules: ReadonlyArray<string>;
|
|
62
|
+
|
|
58
63
|
/**
|
|
59
64
|
* How a standalone installation of this harness is recognized and updated.
|
|
60
65
|
*
|
|
@@ -74,6 +79,7 @@ export const HARNESS_DEFINITIONS: Readonly<Record<PromptRunnerHarnessName, Harne
|
|
|
74
79
|
label: 'OpenAI Codex',
|
|
75
80
|
commandName: 'codex',
|
|
76
81
|
npmPackageName: '@openai/codex',
|
|
82
|
+
projectGitignoreRules: ['.codex'],
|
|
77
83
|
// Note: The official standalone installer keeps its package in `~/.codex` and links it onto the `PATH`
|
|
78
84
|
standaloneInstallation: {
|
|
79
85
|
directoryNames: ['.codex'],
|
|
@@ -85,6 +91,7 @@ export const HARNESS_DEFINITIONS: Readonly<Record<PromptRunnerHarnessName, Harne
|
|
|
85
91
|
label: 'GitHub Copilot',
|
|
86
92
|
commandName: 'copilot',
|
|
87
93
|
npmPackageName: '@github/copilot',
|
|
94
|
+
projectGitignoreRules: ['.github/copilot/settings.local.json'],
|
|
88
95
|
// Note: The GitHub Copilot CLI downloads its native binary in a postinstall script
|
|
89
96
|
npmInstallEnvironment: { npm_config_ignore_scripts: 'false' },
|
|
90
97
|
},
|
|
@@ -93,30 +100,35 @@ export const HARNESS_DEFINITIONS: Readonly<Record<PromptRunnerHarnessName, Harne
|
|
|
93
100
|
label: 'Cline',
|
|
94
101
|
commandName: 'cline',
|
|
95
102
|
npmPackageName: 'cline',
|
|
103
|
+
projectGitignoreRules: ['.cline'],
|
|
96
104
|
},
|
|
97
105
|
'claude-code': {
|
|
98
106
|
harnessName: 'claude-code',
|
|
99
107
|
label: 'Claude Code',
|
|
100
108
|
commandName: 'claude',
|
|
101
109
|
npmPackageName: '@anthropic-ai/claude-code',
|
|
110
|
+
projectGitignoreRules: ['.claude'],
|
|
102
111
|
},
|
|
103
112
|
opencode: {
|
|
104
113
|
harnessName: 'opencode',
|
|
105
114
|
label: 'Opencode',
|
|
106
115
|
commandName: 'opencode',
|
|
107
116
|
npmPackageName: 'opencode-ai',
|
|
117
|
+
projectGitignoreRules: ['.opencode'],
|
|
108
118
|
},
|
|
109
119
|
gemini: {
|
|
110
120
|
harnessName: 'gemini',
|
|
111
121
|
label: 'Gemini CLI',
|
|
112
122
|
commandName: 'gemini',
|
|
113
123
|
npmPackageName: '@google/gemini-cli',
|
|
124
|
+
projectGitignoreRules: ['.gemini'],
|
|
114
125
|
},
|
|
115
126
|
'qwen-code': {
|
|
116
127
|
harnessName: 'qwen-code',
|
|
117
128
|
label: 'Qwen Code',
|
|
118
129
|
commandName: 'qwen',
|
|
119
130
|
npmPackageName: '@qwen-code/qwen-code',
|
|
131
|
+
projectGitignoreRules: ['.qwen'],
|
|
120
132
|
},
|
|
121
133
|
};
|
|
122
134
|
|
|
@@ -140,3 +152,16 @@ export function getHarnessDefinition(harnessName: PromptRunnerHarnessName): Harn
|
|
|
140
152
|
|
|
141
153
|
return definition;
|
|
142
154
|
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Lists the unique project ignore rules required by the selected harnesses, in selection order.
|
|
158
|
+
*
|
|
159
|
+
* @private internal utility of `promptbookCli`
|
|
160
|
+
*/
|
|
161
|
+
export function getHarnessProjectGitignoreRules(
|
|
162
|
+
harnessNames: ReadonlyArray<PromptRunnerHarnessName>,
|
|
163
|
+
): ReadonlyArray<string> {
|
|
164
|
+
return Array.from(
|
|
165
|
+
new Set(harnessNames.flatMap((harnessName) => getHarnessDefinition(harnessName).projectGitignoreRules)),
|
|
166
|
+
);
|
|
167
|
+
}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { createInterface } from 'readline';
|
|
1
|
+
import { $askForConfirmation } from '../$askForConfirmation';
|
|
3
2
|
|
|
4
3
|
/**
|
|
5
4
|
* Asks the user in the terminal whether an npm package should be installed or updated now.
|
|
@@ -10,22 +9,7 @@ import { createInterface } from 'readline';
|
|
|
10
9
|
* @private internal utility of `promptbookCli`
|
|
11
10
|
*/
|
|
12
11
|
export async function $askForNpmPackageInstallationApproval(question: string): Promise<boolean> {
|
|
13
|
-
|
|
14
|
-
// Note: In non-interactive environments like CI there is nobody who could confirm the installation
|
|
15
|
-
return false;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
const readlineInterface = createInterface({ input: process.stdin, output: process.stdout });
|
|
19
|
-
|
|
20
|
-
try {
|
|
21
|
-
const answer = await new Promise<string>((resolve) => {
|
|
22
|
-
readlineInterface.question(colors.cyan(`${question} [y/N] `), resolve);
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
return ['y', 'yes'].includes(answer.trim().toLowerCase());
|
|
26
|
-
} finally {
|
|
27
|
-
readlineInterface.close();
|
|
28
|
-
}
|
|
12
|
+
return $askForConfirmation(question);
|
|
29
13
|
}
|
|
30
14
|
|
|
31
15
|
// Note: [🟡] Code for CLI npm package installation approval [$askForNpmPackageInstallationApproval](src/cli/cli-commands/common/npm/$askForNpmPackageInstallationApproval.ts) should never be published outside of `@promptbook/cli`
|
|
@@ -113,7 +113,7 @@ export async function ensureProjectGitignoreFile({
|
|
|
113
113
|
}: EnsureProjectGitignoreFileOptions): Promise<ProjectInitializationStatus> {
|
|
114
114
|
const gitignorePath = join(projectPath, GITIGNORE_FILE_PATH);
|
|
115
115
|
const currentGitignoreContent = await readTextFileIfExists(gitignorePath);
|
|
116
|
-
const missingRules =
|
|
116
|
+
const missingRules = getMissingGitignoreRules(currentGitignoreContent || '', rules);
|
|
117
117
|
|
|
118
118
|
if (currentGitignoreContent !== undefined && missingRules.length === 0) {
|
|
119
119
|
return 'unchanged';
|
|
@@ -132,6 +132,21 @@ export async function ensureProjectGitignoreFile({
|
|
|
132
132
|
return currentGitignoreContent === undefined ? 'created' : 'updated';
|
|
133
133
|
}
|
|
134
134
|
|
|
135
|
+
/**
|
|
136
|
+
* Lists the ignore rules which are not yet present in a project's `.gitignore` file.
|
|
137
|
+
*
|
|
138
|
+
* @private internal utility of Promptbook CLI project initialization
|
|
139
|
+
*/
|
|
140
|
+
export async function getMissingProjectGitignoreRules(
|
|
141
|
+
projectPath: string,
|
|
142
|
+
rules: ReadonlyArray<string>,
|
|
143
|
+
): Promise<ReadonlyArray<string>> {
|
|
144
|
+
const gitignorePath = join(projectPath, GITIGNORE_FILE_PATH);
|
|
145
|
+
const currentGitignoreContent = (await readTextFileIfExists(gitignorePath)) || '';
|
|
146
|
+
|
|
147
|
+
return getMissingGitignoreRules(currentGitignoreContent, rules);
|
|
148
|
+
}
|
|
149
|
+
|
|
135
150
|
/**
|
|
136
151
|
* Reads one text file when it exists, otherwise returns `undefined`.
|
|
137
152
|
*
|
|
@@ -191,9 +206,17 @@ function parseEnvVariableNames(envContent: string): Set<string> {
|
|
|
191
206
|
* Detects whether `.gitignore` already covers one exact rule.
|
|
192
207
|
*/
|
|
193
208
|
function hasGitignoreRule(gitignoreContent: string, rule: string): boolean {
|
|
194
|
-
const
|
|
209
|
+
const normalizedRule = rule.startsWith('/') ? rule.slice(1) : rule;
|
|
210
|
+
const normalizedRulePattern = `/?${escapeRegExp(normalizedRule)}`;
|
|
195
211
|
return new RegExp(`(^|[\\r\\n])${normalizedRulePattern}(?:[\\r\\n]|$)`, 'u').test(gitignoreContent);
|
|
196
212
|
}
|
|
197
213
|
|
|
214
|
+
/**
|
|
215
|
+
* Finds the unique rules which are not covered by existing `.gitignore` content.
|
|
216
|
+
*/
|
|
217
|
+
function getMissingGitignoreRules(gitignoreContent: string, rules: ReadonlyArray<string>): ReadonlyArray<string> {
|
|
218
|
+
return Array.from(new Set(rules)).filter((rule) => !hasGitignoreRule(gitignoreContent, rule));
|
|
219
|
+
}
|
|
220
|
+
|
|
198
221
|
// Note: [🟡] Code for CLI project initialization [projectInitialization](src/cli/cli-commands/common/projectInitialization.ts) should never be published outside of `@promptbook/cli`
|
|
199
222
|
// Note: [💞] Ignore a discrepancy between file name and entity name
|