paqad-ai 1.2.0 → 1.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +14 -0
- package/dist/cli/index.js +72 -55
- package/dist/cli/index.js.map +1 -1
- package/dist/index.d.ts +11 -0
- package/dist/index.js +59 -15
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# paqad-ai
|
|
2
2
|
|
|
3
|
+
## 1.2.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [#65](https://github.com/Eliyce/paqad-ai/pull/65) [`f398b00`](https://github.com/Eliyce/paqad-ai/commit/f398b00ced1d676a5e35452a3da7d143431569a0) Thanks [@HLasani](https://github.com/HLasani)! - Fix `paqad-ai onboard` hanging on the RAG "No, skip" path at the end of the full interactive prompt chain.
|
|
8
|
+
|
|
9
|
+
The orchestrator previously interleaved the RAG inquirer prompt with file writes: `resolveRagSelection()` ran early, and `writeDetectionReport` / `writeFrameworkMetadata` / `writeOnboardingManifest` / `writeDecisionPauseContractDocument` / `compileRules` / `initializeModuleHealth` / `classifier-config.json` / `next-steps.md` all ran _after_ it. When inquirer left a stuck readline handle on Node's event loop — observed reliably with the full prompt chain on the No-skip branch — every post-RAG write was silently dropped. Users were left with an incomplete `.paqad/**` and no `ONBOARDING COMPLETE` banner.
|
|
10
|
+
|
|
11
|
+
Onboarding is now two-phase. Phase 1 writes every core `.paqad/**` artifact and `CLAUDE.md`-equivalents with no inquirer prompts in the path. The new `onPhase1Complete` callback fires only after the onboarding manifest is on disk, so the success banner prints before phase 2 begins. Phase 2 owns the RAG opt-in (prompt → optional index build → idempotent `writeProjectProfile` update). If phase 2 prompts, hangs, fails, or is interrupted, every phase 1 artifact is already durable on disk.
|
|
12
|
+
|
|
13
|
+
Adds three orchestrator invariant unit tests that pin the new contract (`onPhase1Complete` fires after all core artifacts exist; a thrown `RagService.configureAndBuild` does not drop core writes; a thrown `resolveRagSelection` does not drop core writes) and a PTY-driven E2E (gated on the system `expect(1)` binary, skipped on platforms without it) that drives the real built CLI through the full interactive Laravel prompt chain, picks "No, skip" on RAG, and asserts the complete `.paqad/**` artifact set on disk.
|
|
14
|
+
|
|
15
|
+
Closes [#62](https://github.com/Eliyce/paqad-ai/issues/62).
|
|
16
|
+
|
|
3
17
|
## 1.2.0
|
|
4
18
|
|
|
5
19
|
### Minor Changes
|
package/dist/cli/index.js
CHANGED
|
@@ -22042,7 +22042,33 @@ function toProjectRulePath(source) {
|
|
|
22042
22042
|
}
|
|
22043
22043
|
|
|
22044
22044
|
// src/onboarding/orchestrator.ts
|
|
22045
|
+
var NEXT_STEPS_MD = [
|
|
22046
|
+
"## Required: Create Documentation Foundation",
|
|
22047
|
+
"",
|
|
22048
|
+
"Before starting feature work, prompt your AI agent with:",
|
|
22049
|
+
"",
|
|
22050
|
+
"```text",
|
|
22051
|
+
"create documentation",
|
|
22052
|
+
"```",
|
|
22053
|
+
"",
|
|
22054
|
+
"This generates:",
|
|
22055
|
+
"- `docs/instructions/**`",
|
|
22056
|
+
"- `docs/instructions/rules/module-map.yml`",
|
|
22057
|
+
"",
|
|
22058
|
+
"Review `docs/instructions/rules/module-map.yml` first. Confirm that module and feature names use business language, then prompt your AI agent with:",
|
|
22059
|
+
"",
|
|
22060
|
+
"```text",
|
|
22061
|
+
"create module documentation",
|
|
22062
|
+
"```",
|
|
22063
|
+
"",
|
|
22064
|
+
"That second prompt generates `docs/modules/**` from the reviewed module map."
|
|
22065
|
+
].join("\n");
|
|
22045
22066
|
var OnboardingOrchestrator = class {
|
|
22067
|
+
/**
|
|
22068
|
+
* Two-phase onboarding. Phase 1 generates and writes every core artifact deterministically,
|
|
22069
|
+
* with no inquirer prompts. Phase 2 is the optional RAG opt-in: it can prompt, fail, or hang
|
|
22070
|
+
* and the project is still fully onboarded. See issue #62 for the regression this protects.
|
|
22071
|
+
*/
|
|
22046
22072
|
async run(options) {
|
|
22047
22073
|
const detector = new Detector();
|
|
22048
22074
|
const detection = await detector.detect(options.projectRoot);
|
|
@@ -22060,8 +22086,7 @@ var OnboardingOrchestrator = class {
|
|
|
22060
22086
|
options.profileOverrides,
|
|
22061
22087
|
options.projectRoot
|
|
22062
22088
|
);
|
|
22063
|
-
|
|
22064
|
-
profile.intelligence = applyRagSelection(profile.intelligence, ragSelection);
|
|
22089
|
+
profile.intelligence = applyRagSelection(profile.intelligence, void 0);
|
|
22065
22090
|
const validator = new SchemaValidator();
|
|
22066
22091
|
const validation = validator.validate("project-profile", profile);
|
|
22067
22092
|
const modules = await discoverModules(options.projectRoot);
|
|
@@ -22120,17 +22145,6 @@ var OnboardingOrchestrator = class {
|
|
|
22120
22145
|
const onboardingWarnings = [];
|
|
22121
22146
|
writeProjectProfile2(options.projectRoot, profile);
|
|
22122
22147
|
writeGitignore(options.projectRoot);
|
|
22123
|
-
if (ragSelection?.enabled && ragSelection.provider) {
|
|
22124
|
-
try {
|
|
22125
|
-
await enableRagDuringOnboarding(options.projectRoot, ragSelection);
|
|
22126
|
-
} catch (error) {
|
|
22127
|
-
profile.intelligence = applyRagSelection(profile.intelligence, { enabled: false });
|
|
22128
|
-
writeProjectProfile2(options.projectRoot, profile);
|
|
22129
|
-
onboardingWarnings.push(
|
|
22130
|
-
`RAG setup failed during onboarding: ${error instanceof Error ? error.message : "unknown error"}. Onboarding completed with RAG disabled.`
|
|
22131
|
-
);
|
|
22132
|
-
}
|
|
22133
|
-
}
|
|
22134
22148
|
writeDetectionReport(options.projectRoot, detection);
|
|
22135
22149
|
writeFrameworkMetadata(options.projectRoot, VERSION);
|
|
22136
22150
|
bootstrapFramework(options.projectRoot);
|
|
@@ -22213,6 +22227,15 @@ var OnboardingOrchestrator = class {
|
|
|
22213
22227
|
`Classifier config initialization failed during onboarding: ${error instanceof Error ? error.message : "unknown error"}.`
|
|
22214
22228
|
);
|
|
22215
22229
|
}
|
|
22230
|
+
try {
|
|
22231
|
+
const nextStepsPath = join76(options.projectRoot, ".paqad", "next-steps.md");
|
|
22232
|
+
writeFileSync10(nextStepsPath, NEXT_STEPS_MD);
|
|
22233
|
+
writeResult.written.push(".paqad/next-steps.md");
|
|
22234
|
+
} catch (error) {
|
|
22235
|
+
onboardingWarnings.push(
|
|
22236
|
+
`Next-steps doc write failed: ${error instanceof Error ? error.message : "unknown error"}.`
|
|
22237
|
+
);
|
|
22238
|
+
}
|
|
22216
22239
|
const manifestPath = writeOnboardingManifest(options.projectRoot, {
|
|
22217
22240
|
framework_version: VERSION,
|
|
22218
22241
|
adapter: adapters[0],
|
|
@@ -22232,7 +22255,7 @@ var OnboardingOrchestrator = class {
|
|
|
22232
22255
|
classifier_config_path: ".paqad/classifier-config.json"
|
|
22233
22256
|
}
|
|
22234
22257
|
});
|
|
22235
|
-
|
|
22258
|
+
const phase1Output = {
|
|
22236
22259
|
adapter: adapters[0],
|
|
22237
22260
|
decision_pause_supported_adapters: adapters,
|
|
22238
22261
|
generated_files: writeResult.written.map(toPosixPath),
|
|
@@ -22241,6 +22264,27 @@ var OnboardingOrchestrator = class {
|
|
|
22241
22264
|
manifest_path: toPosixPath(manifestPath),
|
|
22242
22265
|
warnings: [...writeResult.skipped, ...drift.review_targets, ...onboardingWarnings]
|
|
22243
22266
|
};
|
|
22267
|
+
options.onPhase1Complete?.(phase1Output);
|
|
22268
|
+
const ragSelection = await resolveRagSelection(selections.domain, options.selections?.rag);
|
|
22269
|
+
if (ragSelection) {
|
|
22270
|
+
profile.intelligence = applyRagSelection(profile.intelligence, ragSelection);
|
|
22271
|
+
writeProjectProfile2(options.projectRoot, profile);
|
|
22272
|
+
}
|
|
22273
|
+
if (ragSelection?.enabled && ragSelection.provider) {
|
|
22274
|
+
try {
|
|
22275
|
+
await enableRagDuringOnboarding(options.projectRoot, ragSelection);
|
|
22276
|
+
} catch (error) {
|
|
22277
|
+
profile.intelligence = applyRagSelection(profile.intelligence, { enabled: false });
|
|
22278
|
+
writeProjectProfile2(options.projectRoot, profile);
|
|
22279
|
+
onboardingWarnings.push(
|
|
22280
|
+
`RAG setup failed during onboarding: ${error instanceof Error ? error.message : "unknown error"}. Onboarding completed with RAG disabled.`
|
|
22281
|
+
);
|
|
22282
|
+
}
|
|
22283
|
+
}
|
|
22284
|
+
return {
|
|
22285
|
+
...phase1Output,
|
|
22286
|
+
warnings: [...writeResult.skipped, ...drift.review_targets, ...onboardingWarnings]
|
|
22287
|
+
};
|
|
22244
22288
|
}
|
|
22245
22289
|
};
|
|
22246
22290
|
function buildProjectProfile(selections, snapshot, overrides, projectRoot) {
|
|
@@ -27935,7 +27979,7 @@ init_esm_shims();
|
|
|
27935
27979
|
init_esm_shims();
|
|
27936
27980
|
|
|
27937
27981
|
// src/index.ts
|
|
27938
|
-
var VERSION = "1.2.
|
|
27982
|
+
var VERSION = "1.2.1";
|
|
27939
27983
|
|
|
27940
27984
|
// src/cli/commands/capabilities.ts
|
|
27941
27985
|
init_esm_shims();
|
|
@@ -29678,8 +29722,6 @@ function parseOptionalInteger(value) {
|
|
|
29678
29722
|
|
|
29679
29723
|
// src/cli/commands/onboard.ts
|
|
29680
29724
|
init_esm_shims();
|
|
29681
|
-
import { mkdirSync as mkdirSync14, writeFileSync as writeFileSync12 } from "fs";
|
|
29682
|
-
import { join as join113 } from "path";
|
|
29683
29725
|
import { Command as Command7 } from "commander";
|
|
29684
29726
|
|
|
29685
29727
|
// src/cli/ui/banner.ts
|
|
@@ -29754,42 +29796,17 @@ function createOnboardCommand() {
|
|
|
29754
29796
|
stack: options.stack,
|
|
29755
29797
|
capabilities: options.capability,
|
|
29756
29798
|
providers: options.providers
|
|
29757
|
-
} : void 0
|
|
29799
|
+
} : void 0,
|
|
29800
|
+
// Print the success banner as soon as the project is fully written to disk.
|
|
29801
|
+
// The optional RAG phase runs after this and cannot drop core onboarding state
|
|
29802
|
+
// even if it prompts, hangs, or fails. See #62.
|
|
29803
|
+
onPhase1Complete: () => {
|
|
29804
|
+
printNextSteps();
|
|
29805
|
+
}
|
|
29758
29806
|
});
|
|
29759
|
-
printNextSteps();
|
|
29760
|
-
writeNextStepsFile(options.projectRoot);
|
|
29761
29807
|
}
|
|
29762
29808
|
);
|
|
29763
29809
|
}
|
|
29764
|
-
function writeNextStepsFile(projectRoot) {
|
|
29765
|
-
const paqadDir = join113(projectRoot, ".paqad");
|
|
29766
|
-
mkdirSync14(paqadDir, { recursive: true });
|
|
29767
|
-
writeFileSync12(
|
|
29768
|
-
join113(paqadDir, "next-steps.md"),
|
|
29769
|
-
[
|
|
29770
|
-
"## Required: Create Documentation Foundation",
|
|
29771
|
-
"",
|
|
29772
|
-
"Before starting feature work, prompt your AI agent with:",
|
|
29773
|
-
"",
|
|
29774
|
-
"```text",
|
|
29775
|
-
"create documentation",
|
|
29776
|
-
"```",
|
|
29777
|
-
"",
|
|
29778
|
-
"This generates:",
|
|
29779
|
-
"- `docs/instructions/**`",
|
|
29780
|
-
"- `docs/instructions/rules/module-map.yml`",
|
|
29781
|
-
"",
|
|
29782
|
-
"Review `docs/instructions/rules/module-map.yml` first. Confirm that module and feature names use business language, then prompt your AI agent with:",
|
|
29783
|
-
"",
|
|
29784
|
-
"```text",
|
|
29785
|
-
"create module documentation",
|
|
29786
|
-
"```",
|
|
29787
|
-
"",
|
|
29788
|
-
"That second prompt generates `docs/modules/**` from the reviewed module map."
|
|
29789
|
-
].join("\n"),
|
|
29790
|
-
"utf8"
|
|
29791
|
-
);
|
|
29792
|
-
}
|
|
29793
29810
|
|
|
29794
29811
|
// src/cli/commands/plan.ts
|
|
29795
29812
|
init_esm_shims();
|
|
@@ -30384,8 +30401,8 @@ function createRagCommand() {
|
|
|
30384
30401
|
// src/cli/commands/refresh.ts
|
|
30385
30402
|
init_esm_shims();
|
|
30386
30403
|
import { Command as Command12 } from "commander";
|
|
30387
|
-
import { existsSync as existsSync57, readFileSync as readFileSync31, writeFileSync as
|
|
30388
|
-
import { join as
|
|
30404
|
+
import { existsSync as existsSync57, readFileSync as readFileSync31, writeFileSync as writeFileSync12 } from "fs";
|
|
30405
|
+
import { join as join113 } from "path";
|
|
30389
30406
|
init_paths();
|
|
30390
30407
|
init_domain();
|
|
30391
30408
|
init_project_profile();
|
|
@@ -30462,7 +30479,7 @@ async function refreshProviderEntries(projectRoot) {
|
|
|
30462
30479
|
writeDecisionPauseContractDocument(projectRoot);
|
|
30463
30480
|
for (const type of ADAPTER_TYPES) {
|
|
30464
30481
|
const adapter = AdapterFactory.create(type);
|
|
30465
|
-
const configPath =
|
|
30482
|
+
const configPath = join113(projectRoot, adapter.getConfigPath());
|
|
30466
30483
|
if (!existsSync57(configPath)) {
|
|
30467
30484
|
continue;
|
|
30468
30485
|
}
|
|
@@ -30478,9 +30495,9 @@ function resolveRefreshStack(value) {
|
|
|
30478
30495
|
return value !== void 0 && STACKS.includes(value) ? value : null;
|
|
30479
30496
|
}
|
|
30480
30497
|
function writeRefreshDrift(projectRoot, refreshDrift) {
|
|
30481
|
-
const path11 =
|
|
30498
|
+
const path11 = join113(projectRoot, PATHS.STACK_DRIFT);
|
|
30482
30499
|
const current = readExistingJson(path11);
|
|
30483
|
-
|
|
30500
|
+
writeFileSync12(path11, `${JSON.stringify({ ...current ?? {}, ...refreshDrift }, null, 2)}
|
|
30484
30501
|
`);
|
|
30485
30502
|
}
|
|
30486
30503
|
function readExistingJson(path11) {
|
|
@@ -30494,7 +30511,7 @@ function resolveChangedFiles(projectRoot, contextChangedFiles) {
|
|
|
30494
30511
|
if (contextChangedFiles.length > 0) {
|
|
30495
30512
|
return [...new Set(contextChangedFiles)].sort();
|
|
30496
30513
|
}
|
|
30497
|
-
const trackedPath =
|
|
30514
|
+
const trackedPath = join113(projectRoot, PATHS.CHANGED_FILES);
|
|
30498
30515
|
if (!existsSync57(trackedPath)) {
|
|
30499
30516
|
return [];
|
|
30500
30517
|
}
|