agentic-workflow-manager 9.7.0 → 9.8.0
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/README.md +5 -1
- package/dist/src/commands/doctor.js +4 -2
- package/dist/src/commands/export.js +3 -0
- package/dist/src/commands/init.js +10 -2
- package/dist/src/commands/job/exec-wrapper.js +53 -3
- package/dist/src/commands/plan/index.js +124 -6
- package/dist/src/commands/registry/add.js +2 -2
- package/dist/src/commands/registry/index.js +7 -5
- package/dist/src/commands/registry/install-bundles.js +4 -4
- package/dist/src/commands/registry/status.js +4 -4
- package/dist/src/commands/sensors/bootstrap.js +36 -5
- package/dist/src/commands/sensors/compatibility/contract.js +19 -4
- package/dist/src/commands/sensors/compatibility/discovery.js +23 -3
- package/dist/src/commands/sensors/compatibility/live.js +18 -1
- package/dist/src/commands/sensors/compatibility/probe.js +8 -2
- package/dist/src/commands/sensors/compatibility/resolve.js +5 -2
- package/dist/src/commands/sensors/coverage/evidence.js +19 -10
- package/dist/src/commands/sensors/coverage/index.js +11 -2
- package/dist/src/commands/sensors/coverage/resolve.js +10 -0
- package/dist/src/commands/sensors/exec.js +16 -1
- package/dist/src/commands/sensors/migrate.js +62 -2
- package/dist/src/commands/sensors/prepare.js +2 -0
- package/dist/src/commands/sensors/result.js +2 -0
- package/dist/src/commands/sensors/run.js +64 -1
- package/dist/src/commands/sensors/status.js +6 -4
- package/dist/src/commands/sync.js +2 -1
- package/dist/src/commands/update.js +3 -1
- package/dist/src/commands/watch/archive-unused.js +138 -0
- package/dist/src/commands/watch/generations.js +32 -9
- package/dist/src/commands/watch/index.js +108 -2
- package/dist/src/commands/watch/init.js +149 -18
- package/dist/src/commands/watch/supervisor.js +167 -13
- package/dist/src/commands/watch/teardown-driver.js +13 -13
- package/dist/src/commands/watch/track-state.js +59 -0
- package/dist/src/commands/watch/tracks.js +38 -102
- package/dist/src/core/admission/index.js +181 -0
- package/dist/src/core/admission/registry-contracts.js +290 -0
- package/dist/src/core/bundle-install.js +2 -2
- package/dist/src/core/bundles.js +92 -19
- package/dist/src/core/diagnostics/context.js +1 -1
- package/dist/src/core/export/index.js +1 -1
- package/dist/src/core/export/resolve.js +2 -2
- package/dist/src/core/journal/fingerprint.js +35 -1
- package/dist/src/core/journal/paths.js +11 -0
- package/dist/src/core/journal/store.js +146 -4
- package/dist/src/core/journal/types.js +35 -1
- package/dist/src/core/migration/historical-provenance.js +18 -0
- package/dist/src/core/migration/index.js +322 -0
- package/dist/src/core/plan/identity.js +75 -0
- package/dist/src/core/plan/validate.js +178 -64
- package/dist/src/core/reconciliation.js +1 -1
- package/dist/src/index.js +46 -39
- package/dist/src/utils/grouping.js +1 -1
- package/dist/src/utils/registry-view.js +1 -1
- package/dist/tests/commands/bundle-diagnostics.test.js +145 -0
- package/dist/tests/commands/export.test.js +28 -2
- package/dist/tests/commands/job/exec-wrapper.test.js +16 -0
- package/dist/tests/commands/job/gate-reconcile.test.js +24 -10
- package/dist/tests/commands/multi-agent-targeting.test.js +1 -1
- package/dist/tests/commands/pin.test.js +23 -23
- package/dist/tests/commands/plan/index.test.js +630 -14
- package/dist/tests/commands/sensors/bootstrap.test.js +57 -4
- package/dist/tests/commands/sensors/compatibility/contract.test.js +21 -0
- package/dist/tests/commands/sensors/compatibility/discovery.test.js +19 -0
- package/dist/tests/commands/sensors/compatibility/probe.test.js +14 -1
- package/dist/tests/commands/sensors/compatibility/resolve.test.js +17 -0
- package/dist/tests/commands/sensors/coverage/evidence.test.js +51 -27
- package/dist/tests/commands/sensors/coverage/resolve.test.js +51 -0
- package/dist/tests/commands/sensors/exec.test.js +112 -0
- package/dist/tests/commands/sensors/run-changed.test.js +11 -0
- package/dist/tests/commands/sensors/run.test.js +15 -2
- package/dist/tests/commands/sensors/status.test.js +3 -3
- package/dist/tests/commands/watch/e2e-crash.test.js +126 -11
- package/dist/tests/commands/watch/generations.test.js +113 -4
- package/dist/tests/commands/watch/plan-lifecycle.test.js +263 -0
- package/dist/tests/commands/watch/supervisor-loop.test.js +247 -49
- package/dist/tests/commands/watch/track-finalize.test.js +20 -3
- package/dist/tests/commands/watch/track-freeze.test.js +43 -30
- package/dist/tests/commands/watch/track-state-dependency.test.js +15 -0
- package/dist/tests/commands/watch/watch-init.test.js +244 -0
- package/dist/tests/core/admission/index.test.js +87 -0
- package/dist/tests/core/bundle-install.test.js +36 -0
- package/dist/tests/core/bundles-multiroot.test.js +24 -2
- package/dist/tests/core/bundles-overrides.test.js +10 -7
- package/dist/tests/core/bundles.test.js +75 -6
- package/dist/tests/core/diagnostics/context.test.js +2 -2
- package/dist/tests/core/export/engine.test.js +1 -1
- package/dist/tests/core/export/resolve.test.js +1 -1
- package/dist/tests/core/init/mutation-targets.test.js +1 -1
- package/dist/tests/core/init/orchestrator.test.js +1 -1
- package/dist/tests/core/init/steps.test.js +1 -1
- package/dist/tests/core/journal/fingerprint.test.js +22 -0
- package/dist/tests/core/journal/store.test.js +53 -0
- package/dist/tests/core/journal/types.test.js +7 -0
- package/dist/tests/core/migration/facts.test.js +289 -0
- package/dist/tests/core/migration/historical-provenance.test.js +25 -0
- package/dist/tests/core/plan/validate.test.js +320 -6
- package/dist/tests/core/reconciliation.test.js +1 -1
- package/dist/tests/core/sync-profile-atomicity.test.js +1 -1
- package/dist/tests/integration/pack-e2e.test.js +4 -1
- package/dist/tests/integration/preflight-json-pipe.e2e.test.js +7 -3
- package/dist/tests/integration/sensor-bootstrap.e2e.test.js +37 -0
- package/dist/tests/integration/sensor-structured-run.e2e.test.js +12 -10
- package/dist/tests/providers/injection-config.test.js +14 -6
- package/dist/tests/structural/bundle-skill-reference-contract.test.js +56 -0
- package/dist/tests/structural/jest-environment-is-isolated.test.js +29 -24
- package/dist/tests/structural/native-release-artifacts.test.js +16 -0
- package/dist/tests/utils/grouping.test.js +2 -2
- package/dist/tests/utils/registry-view.test.js +7 -7
- package/package.json +2 -2
- package/prebuilds/darwin-arm64/secure_fs.node +0 -0
- package/prebuilds/darwin-x64/secure_fs.node +0 -0
- package/prebuilds/win32-arm64/secure_fs.node +0 -0
- package/prebuilds/win32-x64/secure_fs.node +0 -0
package/dist/src/index.js
CHANGED
|
@@ -4,6 +4,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
5
5
|
};
|
|
6
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.program = void 0;
|
|
7
8
|
const prompts_1 = require("@clack/prompts");
|
|
8
9
|
const commander_1 = require("commander");
|
|
9
10
|
const config_1 = require("./utils/config");
|
|
@@ -51,9 +52,9 @@ const update_1 = require("./commands/update");
|
|
|
51
52
|
const agent_targets_1 = require("./core/agent-targets");
|
|
52
53
|
const update_check_1 = require("./core/update-check");
|
|
53
54
|
const cli_version_1 = require("./core/cli-version");
|
|
54
|
-
|
|
55
|
-
program.name('awm').description('Agentic Workflow Manager').version((0, cli_version_1.cliVersion)());
|
|
56
|
-
program.hook('postAction', (_command, actionCommand) => {
|
|
55
|
+
exports.program = new commander_1.Command();
|
|
56
|
+
exports.program.name('awm').description('Agentic Workflow Manager').version((0, cli_version_1.cliVersion)());
|
|
57
|
+
exports.program.hook('postAction', (_command, actionCommand) => {
|
|
57
58
|
if (actionCommand.name() === 'preflight')
|
|
58
59
|
return;
|
|
59
60
|
if (actionCommand.parent?.name() === 'plan' && actionCommand.name() === 'validate' && actionCommand.opts().json === true)
|
|
@@ -108,7 +109,7 @@ function resolveSelectedArtifacts(selections) {
|
|
|
108
109
|
// --type skill` como el camino scripteado — una invocacion que siempre fallo con
|
|
109
110
|
// «Bundle "<skill>" not found». Los playbooks se escribieron contra la documentacion, no
|
|
110
111
|
// contra el comportamiento. Un flag que no se lee es peor que uno ausente: promete.
|
|
111
|
-
program.command('add [name]')
|
|
112
|
+
exports.program.command('add [name]')
|
|
112
113
|
.description('Add a bundle (package of skills) interactively, or non-interactively with flags')
|
|
113
114
|
.option('-a, --agent <agent>', `Target agent: ${providers_1.AGENT_TARGETS.join(', ')}`)
|
|
114
115
|
.option('-s, --scope <scope>', 'Scope: local or global')
|
|
@@ -117,6 +118,7 @@ program.command('add [name]')
|
|
|
117
118
|
.option('--all', 'install all artifacts from all packages without prompting')
|
|
118
119
|
.action(async (name, options) => {
|
|
119
120
|
(0, prompts_1.intro)(picocolors_1.default.bgCyan(picocolors_1.default.black(' AWM - Agentic Workflow Manager ')));
|
|
121
|
+
const reporter = (0, bundles_1.createBundleDiagnosticReporter)((message) => process.stderr.write(`${message}\n`));
|
|
120
122
|
// 1. Sync the registry
|
|
121
123
|
const s = (0, prompts_1.spinner)();
|
|
122
124
|
s.start('Syncing registries...');
|
|
@@ -137,7 +139,7 @@ program.command('add [name]')
|
|
|
137
139
|
}
|
|
138
140
|
// 1b. If `name` matches a bundle, run the bundle-activation flow and exit.
|
|
139
141
|
if (name) {
|
|
140
|
-
const allBundles = (0, bundles_1.discoverAllBundles)();
|
|
142
|
+
const allBundles = (0, bundles_1.discoverAllBundles)(undefined, reporter);
|
|
141
143
|
const prefs = (0, config_1.getPreferences)();
|
|
142
144
|
const outcome = (0, add_1.runAddBundleCore)({ name, agent: options.agent, scope: options.scope, method: options.method }, prefs, allBundles);
|
|
143
145
|
if (outcome.code !== 0)
|
|
@@ -181,7 +183,7 @@ program.command('add [name]')
|
|
|
181
183
|
}
|
|
182
184
|
const includeWorkflows = targetAgents.some((a) => (0, providers_1.providerFor)(a).workflow !== null);
|
|
183
185
|
const includeAgents = targetAgents.some((a) => (0, providers_1.providerFor)(a).agent !== null);
|
|
184
|
-
const allView = (0, registry_view_1.buildPackageView)(skills, includeWorkflows ? workflows : [], includeAgents ? agents : [], (0, bundles_1.discoverAllBundles)());
|
|
186
|
+
const allView = (0, registry_view_1.buildPackageView)(skills, includeWorkflows ? workflows : [], includeAgents ? agents : [], (0, bundles_1.discoverAllBundles)(undefined, reporter));
|
|
185
187
|
const allDedup = new Map();
|
|
186
188
|
for (const pkg of allView) {
|
|
187
189
|
for (const a of pkg.artifacts) {
|
|
@@ -294,7 +296,7 @@ program.command('add [name]')
|
|
|
294
296
|
// 4. Build the package view, filtered to artifact types the target agent(s) support
|
|
295
297
|
const includeWorkflows = targetAgents.some(a => (0, providers_1.providerFor)(a).workflow !== null);
|
|
296
298
|
const includeAgents = targetAgents.some(a => (0, providers_1.providerFor)(a).agent !== null);
|
|
297
|
-
const view = (0, registry_view_1.buildPackageView)(skills, includeWorkflows ? workflows : [], includeAgents ? agents : [], (0, bundles_1.discoverAllBundles)());
|
|
299
|
+
const view = (0, registry_view_1.buildPackageView)(skills, includeWorkflows ? workflows : [], includeAgents ? agents : [], (0, bundles_1.discoverAllBundles)(undefined, reporter));
|
|
298
300
|
if (view.length === 0) {
|
|
299
301
|
(0, prompts_1.outro)(picocolors_1.default.yellow('No artifacts available for the selected agent(s).'));
|
|
300
302
|
process.exit(0);
|
|
@@ -417,7 +419,7 @@ program.command('add [name]')
|
|
|
417
419
|
process.exit(1);
|
|
418
420
|
}
|
|
419
421
|
});
|
|
420
|
-
program.command('update')
|
|
422
|
+
exports.program.command('update')
|
|
421
423
|
.description('Sync all configured registries, reconcile artifacts and re-sync hooks')
|
|
422
424
|
.option('-a, --agent <agent>', `Target agent(s), comma-separated: ${providers_1.AGENT_TARGETS.join(', ')} (defaults to every enabled agent)`)
|
|
423
425
|
.option('-y, --yes', 'Non-interactive: never prompt, and self-update the CLI without asking')
|
|
@@ -431,7 +433,7 @@ program.command('update')
|
|
|
431
433
|
(0, prompts_1.outro)(result.code === 0 ? message : picocolors_1.default.red(message));
|
|
432
434
|
process.exitCode = result.code;
|
|
433
435
|
});
|
|
434
|
-
program.command('sync')
|
|
436
|
+
exports.program.command('sync')
|
|
435
437
|
.description('Rebuild local skill symlinks from .awm/profile.json (e.g. after cloning on a new machine)')
|
|
436
438
|
.option('-a, --agent <agent>', `Target agent(s), comma-separated: ${providers_1.AGENT_TARGETS.join(', ')} (defaults to every enabled agent)`)
|
|
437
439
|
.option('-m, --method <method>', 'Install method: symlink or copy', 'symlink')
|
|
@@ -441,11 +443,12 @@ program.command('sync')
|
|
|
441
443
|
(0, prompts_1.outro)(code === 0 ? 'Done.' : picocolors_1.default.red('Sync failed — see errors above.'));
|
|
442
444
|
process.exitCode = code;
|
|
443
445
|
});
|
|
444
|
-
program.command('list [package]')
|
|
446
|
+
exports.program.command('list [package]')
|
|
445
447
|
.description('List available artifacts. With no argument shows a package summary; pass a package name or --all for detail.')
|
|
446
448
|
.option('-a, --all', 'Expand every package')
|
|
447
449
|
.action(async (packageName, options) => {
|
|
448
450
|
(0, prompts_1.intro)(picocolors_1.default.bgCyan(picocolors_1.default.black(' AWM - Registry Listing ')));
|
|
451
|
+
const reporter = (0, bundles_1.createBundleDiagnosticReporter)((message) => process.stderr.write(`${message}\n`));
|
|
449
452
|
const s = (0, prompts_1.spinner)();
|
|
450
453
|
s.start('Syncing registries...');
|
|
451
454
|
const listSyncResults = await (0, registries_1.syncRegistries)();
|
|
@@ -462,7 +465,7 @@ program.command('list [package]')
|
|
|
462
465
|
process.exitCode = 1;
|
|
463
466
|
return;
|
|
464
467
|
}
|
|
465
|
-
const fullView = (0, registry_view_1.buildPackageView)((0, discovery_1.discoverSkills)(), (0, discovery_1.discoverWorkflows)(), (0, discovery_1.discoverAgents)(), (0, bundles_1.discoverAllBundles)());
|
|
468
|
+
const fullView = (0, registry_view_1.buildPackageView)((0, discovery_1.discoverSkills)(), (0, discovery_1.discoverWorkflows)(), (0, discovery_1.discoverAgents)(), (0, bundles_1.discoverAllBundles)(undefined, reporter));
|
|
466
469
|
const view = options.all ? fullView : fullView.filter((p) => p.visibility !== 'private');
|
|
467
470
|
if (view.length === 0) {
|
|
468
471
|
(0, prompts_1.outro)(picocolors_1.default.yellow('No artifacts found in the registry. Run `awm update` or check your registry content.'));
|
|
@@ -516,13 +519,14 @@ program.command('list [package]')
|
|
|
516
519
|
// prometia y no contra el comportamiento. Ver docs/decisions.md, D-006.
|
|
517
520
|
//
|
|
518
521
|
// El nombre es de BUNDLE, igual que en `add` (D-001).
|
|
519
|
-
program.command('remove [name]')
|
|
522
|
+
exports.program.command('remove [name]')
|
|
520
523
|
.description('Remove an installed bundle interactively, or non-interactively with flags')
|
|
521
524
|
.option('-a, --agent <agent>', `Target agent(s), comma-separated: ${providers_1.AGENT_TARGETS.join(', ')} (defaults to every enabled agent)`)
|
|
522
525
|
.option('-s, --scope <scope>', 'Scope: local or global (skips the prompt)')
|
|
523
526
|
.option('-y, --yes', 'Skip the confirmation prompt (requires a name)')
|
|
524
527
|
.action(async (name, options) => {
|
|
525
528
|
(0, prompts_1.intro)(picocolors_1.default.bgCyan(picocolors_1.default.black(' AWM - Remove Artifact ')));
|
|
529
|
+
const reporter = (0, bundles_1.createBundleDiagnosticReporter)((message) => process.stderr.write(`${message}\n`));
|
|
526
530
|
const prefs = (0, config_1.getPreferences)();
|
|
527
531
|
// `--yes` sin nombre borraria lo que el usuario nunca eligio: un `rm -rf` silencioso
|
|
528
532
|
// sobre todo lo instalado. Se rechaza antes de tocar nada.
|
|
@@ -591,7 +595,8 @@ program.command('remove [name]')
|
|
|
591
595
|
(0, prompts_1.outro)(picocolors_1.default.yellow('No installed artifacts found for the selected agents/scope.'));
|
|
592
596
|
process.exit(0);
|
|
593
597
|
}
|
|
594
|
-
const
|
|
598
|
+
const bundles = (0, bundles_1.discoverAllBundles)(undefined, reporter);
|
|
599
|
+
const groupedOpts = (0, grouping_1.buildGroupedOptions)(installed, bundles, (c) => {
|
|
595
600
|
const hasSkill = c.artifacts.some(a => a.type === 'skill');
|
|
596
601
|
const hasWf = c.artifacts.some(a => a.type === 'workflow');
|
|
597
602
|
const hasAgent = c.artifacts.some(a => a.type === 'agent');
|
|
@@ -608,14 +613,14 @@ program.command('remove [name]')
|
|
|
608
613
|
// Los artefactos del bundle pedido que estan REALMENTE instalados en este
|
|
609
614
|
// scope. Se cruza contra `installed`: lo que no esta instalado no se puede
|
|
610
615
|
// remover, y decirlo es mejor que borrar un subconjunto en silencio.
|
|
611
|
-
const bundle =
|
|
616
|
+
const bundle = bundles.find((b) => b.name === name);
|
|
612
617
|
if (!bundle) {
|
|
613
618
|
console.error(picocolors_1.default.red(`Bundle "${name}" not found in registry.`));
|
|
614
619
|
console.error(picocolors_1.default.dim('Run `awm list` to see available packages.'));
|
|
615
620
|
process.exit(1);
|
|
616
621
|
}
|
|
617
622
|
const owned = new Set([
|
|
618
|
-
...bundle.skills
|
|
623
|
+
...bundle.skills,
|
|
619
624
|
...bundle.workflows,
|
|
620
625
|
...bundle.agents,
|
|
621
626
|
]);
|
|
@@ -677,7 +682,7 @@ function loadEnvFile(cwd) {
|
|
|
677
682
|
}
|
|
678
683
|
return env;
|
|
679
684
|
}
|
|
680
|
-
const miroCmd = program.command('miro').description('Miro board integration');
|
|
685
|
+
const miroCmd = exports.program.command('miro').description('Miro board integration');
|
|
681
686
|
miroCmd.command('sync <storyMapPath>')
|
|
682
687
|
.description('Sync a story-map.md file to a Miro board frame')
|
|
683
688
|
.action(async (storyMapPath) => {
|
|
@@ -726,29 +731,31 @@ miroCmd.command('sync <storyMapPath>')
|
|
|
726
731
|
process.exit(1);
|
|
727
732
|
}
|
|
728
733
|
});
|
|
729
|
-
(0, hooks_1.registerHooksCommand)(program);
|
|
730
|
-
(0, sensors_1.registerSensorsCommand)(program);
|
|
731
|
-
(0, ledger_1.registerLedgerCommand)(program);
|
|
732
|
-
(0, context_budget_1.registerContextBudgetCommand)(program);
|
|
733
|
-
(0, preflight_1.registerPreflightCommand)(program);
|
|
734
|
-
(0, plan_1.registerPlanCommand)(program);
|
|
735
|
-
(0, doctor_1.registerDoctorCommand)(program);
|
|
736
|
-
(0, backup_1.registerBackupCommand)(program);
|
|
737
|
-
(0, init_1.registerInitCommand)(program);
|
|
738
|
-
(0, registry_1.registerRegistryCommand)(program);
|
|
739
|
-
(0, pin_1.registerPinCommands)(program);
|
|
740
|
-
(0, export_1.registerExportCommand)(program);
|
|
741
|
-
(0, agent_1.registerAgentCommand)(program);
|
|
742
|
-
(0, job_1.registerJobCommand)(program);
|
|
743
|
-
(0, watch_1.registerWatchCommand)(program);
|
|
744
|
-
(0, track_1.registerTrackCommand)(program);
|
|
745
|
-
(0, evidence_1.registerEvidenceCommand)(program);
|
|
746
|
-
(0, process_1.registerProcessCommand)(program);
|
|
747
|
-
(0, context_1.registerContextCommand)(program);
|
|
734
|
+
(0, hooks_1.registerHooksCommand)(exports.program);
|
|
735
|
+
(0, sensors_1.registerSensorsCommand)(exports.program);
|
|
736
|
+
(0, ledger_1.registerLedgerCommand)(exports.program);
|
|
737
|
+
(0, context_budget_1.registerContextBudgetCommand)(exports.program);
|
|
738
|
+
(0, preflight_1.registerPreflightCommand)(exports.program);
|
|
739
|
+
(0, plan_1.registerPlanCommand)(exports.program);
|
|
740
|
+
(0, doctor_1.registerDoctorCommand)(exports.program);
|
|
741
|
+
(0, backup_1.registerBackupCommand)(exports.program);
|
|
742
|
+
(0, init_1.registerInitCommand)(exports.program);
|
|
743
|
+
(0, registry_1.registerRegistryCommand)(exports.program);
|
|
744
|
+
(0, pin_1.registerPinCommands)(exports.program);
|
|
745
|
+
(0, export_1.registerExportCommand)(exports.program);
|
|
746
|
+
(0, agent_1.registerAgentCommand)(exports.program);
|
|
747
|
+
(0, job_1.registerJobCommand)(exports.program);
|
|
748
|
+
(0, watch_1.registerWatchCommand)(exports.program);
|
|
749
|
+
(0, track_1.registerTrackCommand)(exports.program);
|
|
750
|
+
(0, evidence_1.registerEvidenceCommand)(exports.program);
|
|
751
|
+
(0, process_1.registerProcessCommand)(exports.program);
|
|
752
|
+
(0, context_1.registerContextCommand)(exports.program);
|
|
748
753
|
// Commander only waits for async action handlers through parseAsync(). The CLI has
|
|
749
754
|
// async commands (including `sensors coverage`), so returning its promise keeps the
|
|
750
755
|
// process alive until their JSON/output contract has been completed.
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
756
|
+
if (require.main === module) {
|
|
757
|
+
exports.program.parseAsync().catch((error) => {
|
|
758
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
759
|
+
process.exitCode = 1;
|
|
760
|
+
});
|
|
761
|
+
}
|
|
@@ -8,7 +8,7 @@ function buildGroupedOptions(artifacts, bundles, formatLabel) {
|
|
|
8
8
|
let foundParent = false;
|
|
9
9
|
const baseName = (a.type === 'workflow' || a.type === 'agent') ? a.name.replace(/\.md$/, '') : a.name;
|
|
10
10
|
for (const p of bundles) {
|
|
11
|
-
const skillNames = p.skills
|
|
11
|
+
const skillNames = p.skills;
|
|
12
12
|
if ((a.type === 'skill' && skillNames.includes(baseName)) ||
|
|
13
13
|
(a.type === 'workflow' && p.workflows.includes(baseName)) ||
|
|
14
14
|
(a.type === 'agent' && p.agents.includes(baseName))) {
|
|
@@ -40,7 +40,7 @@ function buildPackageView(skills, workflows, agents, bundles) {
|
|
|
40
40
|
const packages = [];
|
|
41
41
|
const claimed = new Set();
|
|
42
42
|
for (const b of bundles) {
|
|
43
|
-
const skillNames = b.skills
|
|
43
|
+
const skillNames = b.skills;
|
|
44
44
|
const arts = all.filter((a) => (a.type === 'skill' && skillNames.includes(a.name)) ||
|
|
45
45
|
(a.type === 'workflow' && b.workflows.includes(a.name)) ||
|
|
46
46
|
(a.type === 'agent' && b.agents.includes(a.name)));
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const child_process_1 = require("child_process");
|
|
7
|
+
const fs_1 = __importDefault(require("fs"));
|
|
8
|
+
const os_1 = __importDefault(require("os"));
|
|
9
|
+
const path_1 = __importDefault(require("path"));
|
|
10
|
+
jest.mock('@clack/prompts', () => ({
|
|
11
|
+
intro: jest.fn(), outro: jest.fn(), spinner: () => ({ start: jest.fn(), stop: jest.fn() }),
|
|
12
|
+
select: jest.fn(), multiselect: jest.fn(), confirm: jest.fn(), isCancel: jest.fn(() => false),
|
|
13
|
+
}));
|
|
14
|
+
function writeManifest(root, legacy) {
|
|
15
|
+
fs_1.default.mkdirSync(path_1.default.join(root, 'bundles', 'demo'), { recursive: true });
|
|
16
|
+
fs_1.default.mkdirSync(path_1.default.join(root, 'skills', 'demo-skill'), { recursive: true });
|
|
17
|
+
fs_1.default.writeFileSync(path_1.default.join(root, 'catalog.json'), JSON.stringify({ version: 1, bundles: [{ name: 'demo', source: './bundles/demo', version: '1.0.0', scope: 'baseline' }] }));
|
|
18
|
+
fs_1.default.writeFileSync(path_1.default.join(root, 'bundles', 'demo', 'bundle.json'), JSON.stringify({
|
|
19
|
+
name: 'demo', description: 'Diagnostic fixture', version: '1.0.0', scope: 'baseline', dependsOn: [],
|
|
20
|
+
skills: legacy ? [{ name: 'demo-skill', onSignal: true }] : ['demo-skill'], workflows: [], agents: [],
|
|
21
|
+
}));
|
|
22
|
+
fs_1.default.writeFileSync(path_1.default.join(root, 'skills', 'demo-skill', 'SKILL.md'), '---\nname: demo-skill\nportable: true\ndescription: fixture\n---\n');
|
|
23
|
+
}
|
|
24
|
+
function git(cwd, args) {
|
|
25
|
+
(0, child_process_1.execFileSync)('git', ['-c', 'user.email=test@example.test', '-c', 'user.name=Test', ...args], { cwd, stdio: 'pipe' });
|
|
26
|
+
}
|
|
27
|
+
describe('S2 bundle compatibility diagnostic command routes', () => {
|
|
28
|
+
let home;
|
|
29
|
+
let work;
|
|
30
|
+
let priorHome;
|
|
31
|
+
let priorAwmHome;
|
|
32
|
+
let stdout;
|
|
33
|
+
beforeEach(() => {
|
|
34
|
+
home = fs_1.default.mkdtempSync(path_1.default.join(os_1.default.tmpdir(), 'awm-bundle-command-home-'));
|
|
35
|
+
work = fs_1.default.mkdtempSync(path_1.default.join(os_1.default.tmpdir(), 'awm-bundle-command-work-'));
|
|
36
|
+
priorHome = process.env.HOME;
|
|
37
|
+
priorAwmHome = process.env.AWM_HOME;
|
|
38
|
+
process.env.HOME = home;
|
|
39
|
+
process.env.AWM_HOME = path_1.default.join(home, '.awm');
|
|
40
|
+
stdout = jest.spyOn(process.stdout, 'write').mockImplementation(() => true);
|
|
41
|
+
jest.spyOn(process.stderr, 'write').mockImplementation(() => true);
|
|
42
|
+
jest.spyOn(process, 'exit').mockImplementation(((code) => {
|
|
43
|
+
throw new Error(`unexpected process.exit(${code ?? 0})`);
|
|
44
|
+
}));
|
|
45
|
+
jest.spyOn(console, 'log').mockImplementation(() => undefined);
|
|
46
|
+
jest.spyOn(console, 'warn').mockImplementation(() => undefined);
|
|
47
|
+
jest.spyOn(console, 'error').mockImplementation(() => undefined);
|
|
48
|
+
});
|
|
49
|
+
afterEach(() => {
|
|
50
|
+
jest.restoreAllMocks();
|
|
51
|
+
jest.resetModules();
|
|
52
|
+
fs_1.default.rmSync(home, { recursive: true, force: true });
|
|
53
|
+
fs_1.default.rmSync(work, { recursive: true, force: true });
|
|
54
|
+
if (priorHome === undefined)
|
|
55
|
+
delete process.env.HOME;
|
|
56
|
+
else
|
|
57
|
+
process.env.HOME = priorHome;
|
|
58
|
+
if (priorAwmHome === undefined)
|
|
59
|
+
delete process.env.AWM_HOME;
|
|
60
|
+
else
|
|
61
|
+
process.env.AWM_HOME = priorAwmHome;
|
|
62
|
+
});
|
|
63
|
+
function configureRegistry(legacy) {
|
|
64
|
+
fs_1.default.rmSync(path_1.default.join(process.env.AWM_HOME, 'registries'), { recursive: true, force: true });
|
|
65
|
+
const root = path_1.default.join(process.env.AWM_HOME, 'registries', 'baseline');
|
|
66
|
+
writeManifest(root, legacy);
|
|
67
|
+
fs_1.default.mkdirSync(process.env.AWM_HOME, { recursive: true });
|
|
68
|
+
fs_1.default.writeFileSync(path_1.default.join(process.env.AWM_HOME, 'registries.json'), JSON.stringify([{ name: 'baseline', remote: root }]));
|
|
69
|
+
fs_1.default.writeFileSync(path_1.default.join(process.env.AWM_HOME, 'preferences.json'), JSON.stringify({
|
|
70
|
+
defaultAgent: 'claude-code', enabledAgents: ['claude-code'], installMethod: 'symlink', defaultScope: 'local',
|
|
71
|
+
}));
|
|
72
|
+
return root;
|
|
73
|
+
}
|
|
74
|
+
function stdoutText() {
|
|
75
|
+
return stdout.mock.calls.map((call) => String(call[0])).join('');
|
|
76
|
+
}
|
|
77
|
+
async function run(route, legacy) {
|
|
78
|
+
fs_1.default.rmSync(work, { recursive: true, force: true });
|
|
79
|
+
fs_1.default.mkdirSync(work, { recursive: true });
|
|
80
|
+
if (route === 'registry-add')
|
|
81
|
+
fs_1.default.rmSync(process.env.AWM_HOME, { recursive: true, force: true });
|
|
82
|
+
const root = route === 'registry-add' ? undefined : configureRegistry(legacy);
|
|
83
|
+
const warnings = [];
|
|
84
|
+
const reporter = (warning) => warnings.push(warning);
|
|
85
|
+
if (route === 'init') {
|
|
86
|
+
const { runInit } = require('../../src/commands/init');
|
|
87
|
+
await runInit({ cwd: work, yes: true, json: true, reporter, assertProviderSupported: () => { }, actions: { syncCache: async () => [], installHook: () => ({ status: 'installed' }) } });
|
|
88
|
+
expect(JSON.parse(stdoutText())).toHaveProperty('result');
|
|
89
|
+
}
|
|
90
|
+
else if (route === 'sync') {
|
|
91
|
+
fs_1.default.mkdirSync(path_1.default.join(work, '.awm'), { recursive: true });
|
|
92
|
+
fs_1.default.writeFileSync(path_1.default.join(work, 'package.json'), '{}');
|
|
93
|
+
fs_1.default.writeFileSync(path_1.default.join(work, '.awm', 'profile.json'), JSON.stringify({ extensions: ['demo'] }));
|
|
94
|
+
const { runSyncCore } = require('../../src/commands/sync');
|
|
95
|
+
await runSyncCore({ cwd: work, reporter }, {
|
|
96
|
+
syncRegistries: async () => [], verifyMinCliVersions: () => [], verifyProjectPins: async () => [],
|
|
97
|
+
syncProfile: () => ({ extensions: ['demo'], installed: [], skipped: [], transactionIds: [] }), reconcileProjectSkillLinks: () => [],
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
else if (route === 'update') {
|
|
101
|
+
const { runUpdateCore } = require('../../src/commands/update');
|
|
102
|
+
const { planReconciliation } = require('../../src/core/reconciliation');
|
|
103
|
+
await runUpdateCore({ yes: true, reporter }, {
|
|
104
|
+
syncRegistries: async () => [{ name: 'baseline', action: 'pulled', version: 'v1.0.0' }], verifyMinCliVersions: () => [],
|
|
105
|
+
regenerateGlobalContext: () => [], planReconciliation, applyInstallPlan: () => ({ installed: [], skipped: [], transactionId: 'test', modifiedFiles: [] }),
|
|
106
|
+
resyncInstalledHooks: () => [], offerSelfUpdate: async () => { },
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
else if (route === 'doctor') {
|
|
110
|
+
const { runDoctor } = require('../../src/commands/doctor');
|
|
111
|
+
runDoctor({ cwd: work, json: true, reporter });
|
|
112
|
+
expect(JSON.parse(stdoutText())).toHaveProperty('providers');
|
|
113
|
+
}
|
|
114
|
+
else if (route === 'export') {
|
|
115
|
+
const { runExportCommand } = require('../../src/commands/export');
|
|
116
|
+
runExportCommand('demo', { target: 'claude-ai', out: path_1.default.join(work, 'export') }, { roots: [root], reporter, log: () => { }, zip: () => ({ ok: false, missing: true }) });
|
|
117
|
+
}
|
|
118
|
+
else {
|
|
119
|
+
jest.resetModules();
|
|
120
|
+
const bundles = require('../../src/core/bundles');
|
|
121
|
+
const createReporter = bundles.createBundleDiagnosticReporter;
|
|
122
|
+
jest.spyOn(bundles, 'createBundleDiagnosticReporter').mockImplementation(() => createReporter((warning) => warnings.push(warning)));
|
|
123
|
+
const { registerRegistryCommand } = require('../../src/commands/registry');
|
|
124
|
+
const program = new (require('commander').Command)();
|
|
125
|
+
registerRegistryCommand(program);
|
|
126
|
+
if (route === 'registry-add') {
|
|
127
|
+
const source = path_1.default.join(work, 'source');
|
|
128
|
+
writeManifest(source, legacy);
|
|
129
|
+
git(source, ['init', '-q']);
|
|
130
|
+
git(source, ['add', '-A']);
|
|
131
|
+
git(source, ['commit', '-qm', 'fixture']);
|
|
132
|
+
await program.parseAsync(['node', 'awm', 'registry', 'add', source, '--name', 'fixture', '--no-install']);
|
|
133
|
+
}
|
|
134
|
+
else {
|
|
135
|
+
await program.parseAsync(['node', 'awm', 'registry', 'list']);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
return { warnings };
|
|
139
|
+
}
|
|
140
|
+
it.each(['init', 'sync', 'update', 'doctor', 'export', 'registry-add', 'registry-status'])('%s emits one legacy warning and none for canonical manifests', async (route) => {
|
|
141
|
+
expect((await run(route, true)).warnings).toHaveLength(1);
|
|
142
|
+
stdout.mockClear();
|
|
143
|
+
expect((await run(route, false)).warnings).toEqual([]);
|
|
144
|
+
});
|
|
145
|
+
});
|
|
@@ -11,7 +11,7 @@ const okZip = (cwd, zipName) => {
|
|
|
11
11
|
fs_1.default.writeFileSync(path_1.default.join(cwd, zipName), 'fake-zip');
|
|
12
12
|
return { ok: true, missing: false };
|
|
13
13
|
};
|
|
14
|
-
function makeRoot() {
|
|
14
|
+
function makeRoot(legacy = false) {
|
|
15
15
|
const root = fs_1.default.mkdtempSync(path_1.default.join(os_1.default.tmpdir(), 'awm-cmd-root-'));
|
|
16
16
|
fs_1.default.mkdirSync(path_1.default.join(root, 'bundles/dev'), { recursive: true });
|
|
17
17
|
fs_1.default.writeFileSync(path_1.default.join(root, 'catalog.json'), JSON.stringify({
|
|
@@ -20,7 +20,7 @@ function makeRoot() {
|
|
|
20
20
|
}));
|
|
21
21
|
fs_1.default.writeFileSync(path_1.default.join(root, 'bundles/dev/bundle.json'), JSON.stringify({
|
|
22
22
|
name: 'dev', version: '1.0.0', scope: 'baseline', dependsOn: [],
|
|
23
|
-
skills: ['proc-skill', { name: 'mermaid', onSignal: true }], workflows: [], agents: [],
|
|
23
|
+
skills: legacy ? ['proc-skill', { name: 'mermaid', onSignal: true }] : ['proc-skill', 'mermaid'], workflows: [], agents: [],
|
|
24
24
|
}));
|
|
25
25
|
const mk = (name, fm) => {
|
|
26
26
|
const dir = path_1.default.join(root, 'skills', name);
|
|
@@ -61,4 +61,30 @@ describe('runExportCommand (salida al usuario)', () => {
|
|
|
61
61
|
expect(() => (0, export_1.runExportCommand)('dev', { target: 'nope', out }, { roots: [root], zip: okZip, log }))
|
|
62
62
|
.toThrow(/Valid targets/);
|
|
63
63
|
});
|
|
64
|
+
it('reports one legacy warning and no canonical warning through the command reporter seam', () => {
|
|
65
|
+
const legacyWarnings = [];
|
|
66
|
+
const legacy = makeRoot(true);
|
|
67
|
+
try {
|
|
68
|
+
(0, export_1.runExportCommand)('dev', { target: 'claude-ai', out }, {
|
|
69
|
+
roots: [legacy], zip: okZip, log,
|
|
70
|
+
reporter: (message) => legacyWarnings.push(message),
|
|
71
|
+
});
|
|
72
|
+
expect(legacyWarnings).toHaveLength(1);
|
|
73
|
+
}
|
|
74
|
+
finally {
|
|
75
|
+
fs_1.default.rmSync(legacy, { recursive: true, force: true });
|
|
76
|
+
}
|
|
77
|
+
const canonicalWarnings = [];
|
|
78
|
+
const canonical = makeRoot(false);
|
|
79
|
+
try {
|
|
80
|
+
(0, export_1.runExportCommand)('dev', { target: 'claude-ai', out }, {
|
|
81
|
+
roots: [canonical], zip: okZip, log,
|
|
82
|
+
reporter: (message) => canonicalWarnings.push(message),
|
|
83
|
+
});
|
|
84
|
+
expect(canonicalWarnings).toEqual([]);
|
|
85
|
+
}
|
|
86
|
+
finally {
|
|
87
|
+
fs_1.default.rmSync(canonical, { recursive: true, force: true });
|
|
88
|
+
}
|
|
89
|
+
});
|
|
64
90
|
});
|
|
@@ -17,6 +17,22 @@ describe('exec-wrapper', () => {
|
|
|
17
17
|
let dir;
|
|
18
18
|
beforeEach(() => { dir = fs_1.default.mkdtempSync(path_1.default.join(os_1.default.tmpdir(), 'awm-wrap-')); });
|
|
19
19
|
afterEach(() => { fs_1.default.rmSync(dir, { recursive: true, force: true }); });
|
|
20
|
+
test.each(['../escape', '..\\escape', '/escape', 'C:\\escape', '', '.', '..', 'sentinel\n', 'x'.repeat(129)])('rejects unsafe sidecar components before writes (%#)', async (value) => {
|
|
21
|
+
for (const helper of [exec_wrapper_1.claimPath, exec_wrapper_1.identityPath, exec_wrapper_1.resultPath, exec_wrapper_1.logPath, exec_wrapper_1.replayVerdict]) {
|
|
22
|
+
expect(() => helper(dir, value, 'nonce')).toThrow(/sidecar/);
|
|
23
|
+
expect(() => helper(dir, 'job', value)).toThrow(/sidecar/);
|
|
24
|
+
}
|
|
25
|
+
await expect((0, exec_wrapper_1.runExecWrapper)({ logsRoot: path_1.default.join(dir, 'unused'), jobId: value, nonce: 'nonce', argv: ['node', '-e', 'process.exit(0)'], cwd: '.' })).rejects.toThrow(/sidecar/);
|
|
26
|
+
expect(fs_1.default.readdirSync(dir)).toEqual([]);
|
|
27
|
+
});
|
|
28
|
+
test.each([
|
|
29
|
+
{ argv: ['node'], cwd: '../escape' },
|
|
30
|
+
{ argv: [undefined], cwd: '.' },
|
|
31
|
+
{ argv: ['node', 'sentinel\u0000'], cwd: '.' },
|
|
32
|
+
])('rejects invalid execution inputs before sidecar writes (%#)', async (inputs) => {
|
|
33
|
+
await expect((0, exec_wrapper_1.runExecWrapper)({ logsRoot: path_1.default.join(dir, 'unused'), jobId: 'job', nonce: 'nonce', repoRoot: dir, ...inputs })).rejects.toThrow();
|
|
34
|
+
expect(fs_1.default.readdirSync(dir)).toEqual([]);
|
|
35
|
+
});
|
|
20
36
|
test('claim + identity sidecar + resultado terminal atomico (R1.8)', async () => {
|
|
21
37
|
const out = await (0, exec_wrapper_1.runExecWrapper)({ logsRoot: dir, jobId: 'job1', nonce: 'nonceA', argv: ['node', '-e', 'setTimeout(()=>process.exit(0), 300)'], cwd: '.' });
|
|
22
38
|
expect(out.exitCode).toBe(0);
|
|
@@ -13,6 +13,8 @@ const reconcile_1 = require("../../../src/commands/job/reconcile");
|
|
|
13
13
|
const reap_1 = require("../../../src/commands/job/reap");
|
|
14
14
|
const job_1 = require("../../../src/commands/job");
|
|
15
15
|
const watch_1 = require("../../../src/commands/watch");
|
|
16
|
+
const init_1 = require("../../../src/commands/watch/init");
|
|
17
|
+
const validate_1 = require("../../../src/core/plan/validate");
|
|
16
18
|
const types_1 = require("../../../src/core/journal/types");
|
|
17
19
|
const store_1 = require("../../../src/core/journal/store");
|
|
18
20
|
const descriptor_1 = require("../../../src/core/tracks/descriptor");
|
|
@@ -501,6 +503,16 @@ function trackRefFixture(overrides, worktreePath) {
|
|
|
501
503
|
function descriptorFixture(overrides, planRoot) {
|
|
502
504
|
return { schema: 1, planRoot, planBranch: 'main', trackId: 'cli', planJournalId: 'j-1', fencingToken: 'f'.repeat(32), ...overrides };
|
|
503
505
|
}
|
|
506
|
+
function initCompactJournal(repo, branch) {
|
|
507
|
+
const planPath = path_1.default.join(repo, 'plans', 'fixture.md');
|
|
508
|
+
fs_1.default.mkdirSync(path_1.default.dirname(planPath), { recursive: true });
|
|
509
|
+
fs_1.default.writeFileSync(planPath, fs_1.default.readFileSync(path_1.default.join(__dirname, '../../core/plan/fixtures/compact-slices-v1/valid.md'), 'utf8'));
|
|
510
|
+
fs_1.default.writeFileSync(path_1.default.join(repo, 'source.md'), '## Canonical source\nfixture source\n');
|
|
511
|
+
const report = (0, validate_1.validatePlanFile)('plans/fixture.md', repo);
|
|
512
|
+
if (report.state !== 'valid')
|
|
513
|
+
throw new Error(`compact fixture must validate: ${JSON.stringify(report)}`);
|
|
514
|
+
(0, init_1.initWatch)(repo, branch, { path: 'plans/fixture.md', report });
|
|
515
|
+
}
|
|
504
516
|
async function runCommand(register, argv, cwd) {
|
|
505
517
|
const prog = new commander_1.Command();
|
|
506
518
|
prog.exitOverride();
|
|
@@ -543,12 +555,12 @@ describe('guard de contexto en awm job / awm watch (R9.4)', () => {
|
|
|
543
555
|
gitInitAt(planRoot, 'main');
|
|
544
556
|
gitInitAt(trackRoot, 'track/cli');
|
|
545
557
|
gitInitAt(otherRoot, 'track/cli');
|
|
546
|
-
(
|
|
558
|
+
initCompactJournal(planRoot, 'main');
|
|
547
559
|
const planState = (0, store_1.readJournal)(planRoot, 'main').state;
|
|
548
560
|
planState.journalId = 'j-1';
|
|
549
561
|
planState.tracks = [trackRefFixture({ fencingToken: 'f'.repeat(32) }, trackRoot)];
|
|
550
562
|
(0, store_1.writeJournal)(planRoot, 'main', planState);
|
|
551
|
-
(
|
|
563
|
+
initCompactJournal(trackRoot, 'track/cli');
|
|
552
564
|
const trackState = (0, store_1.readJournal)(trackRoot, 'track/cli').state;
|
|
553
565
|
trackState.trackContext = { trackId: 'cli', taskIds: [], planDigest: 'x', baseSha: 'y', planJournalId: 'j-1' };
|
|
554
566
|
(0, store_1.writeJournal)(trackRoot, 'track/cli', trackState);
|
|
@@ -556,7 +568,7 @@ describe('guard de contexto en awm job / awm watch (R9.4)', () => {
|
|
|
556
568
|
// otherRoot: mismo descriptor (mismo plan/trackId/fencing) pero NO es
|
|
557
569
|
// el worktree que el TrackRef del plan declara — su realpath jamas
|
|
558
570
|
// puede autenticar (R9.4), aunque el resto del descriptor "calce".
|
|
559
|
-
(
|
|
571
|
+
initCompactJournal(otherRoot, 'track/cli');
|
|
560
572
|
const otherState = (0, store_1.readJournal)(otherRoot, 'track/cli').state;
|
|
561
573
|
otherState.trackContext = { trackId: 'cli', taskIds: [], planDigest: 'x', baseSha: 'y', planJournalId: 'j-1' };
|
|
562
574
|
(0, store_1.writeJournal)(otherRoot, 'track/cli', otherState);
|
|
@@ -580,24 +592,26 @@ describe('guard de contexto en awm job / awm watch (R9.4)', () => {
|
|
|
580
592
|
expect(exitCode).toBe(1);
|
|
581
593
|
expect(JSON.parse(out).pass).toBe(false);
|
|
582
594
|
});
|
|
583
|
-
test('`watch --init` desde un cwd SIN descriptor
|
|
595
|
+
test('`watch --init --plan` desde un cwd SIN descriptor crea un binding compacto', async () => {
|
|
584
596
|
const plainRepo = fs_1.default.mkdtempSync(path_1.default.join(os_1.default.tmpdir(), 'awm-guard-plain-'));
|
|
585
597
|
try {
|
|
586
598
|
gitInitAt(plainRepo, 'main');
|
|
587
|
-
const
|
|
599
|
+
const planPath = path_1.default.join(plainRepo, 'plans', 'fixture.md');
|
|
600
|
+
fs_1.default.mkdirSync(path_1.default.dirname(planPath), { recursive: true });
|
|
601
|
+
fs_1.default.writeFileSync(planPath, fs_1.default.readFileSync(path_1.default.join(__dirname, '../../core/plan/fixtures/compact-slices-v1/valid.md'), 'utf8'));
|
|
602
|
+
fs_1.default.writeFileSync(path_1.default.join(plainRepo, 'source.md'), '## Canonical source\nfixture source\n');
|
|
603
|
+
const { out, err, exitCode } = await runWatch(['--init', '--plan', 'plans/fixture.md'], plainRepo);
|
|
588
604
|
expect(exitCode).toBeNull();
|
|
589
605
|
expect(err).toBe('');
|
|
590
606
|
expect(out).toContain('journal inicializado');
|
|
607
|
+
expect((0, store_1.readJournal)(plainRepo, 'main').state).toMatchObject({ schema: 2, planBinding: { path: 'plans/fixture.md', executionMode: 'desatendido' } });
|
|
591
608
|
}
|
|
592
609
|
finally {
|
|
593
610
|
fs_1.default.rmSync(plainRepo, { recursive: true, force: true });
|
|
594
611
|
}
|
|
595
612
|
});
|
|
596
|
-
test('`watch --init` desde el cwd autenticado
|
|
597
|
-
|
|
598
|
-
expect(err).not.toContain('cwd no autenticado');
|
|
599
|
-
expect(exitCode).toBeNull();
|
|
600
|
-
expect(out).toContain('journal inicializado');
|
|
613
|
+
test('`watch --init --plan` desde el cwd autenticado alcanza la guarda de lifecycle y rechaza sobrescribir el binding', async () => {
|
|
614
|
+
await expect(runWatch(['--init', '--plan', 'plans/fixture.md'], trackRoot)).rejects.toThrow(/overwrite|sobrescribir/i);
|
|
601
615
|
});
|
|
602
616
|
test('`watch --init` desde un cwd cuyo descriptor no autentica rechaza con "cwd no autenticado"', async () => {
|
|
603
617
|
const { err, exitCode } = await runWatch(['--init'], otherRoot);
|
|
@@ -60,7 +60,7 @@ describe('multi-agent targeting (add/remove/sync/update/doctor)', () => {
|
|
|
60
60
|
function bundle(over = {}) {
|
|
61
61
|
return {
|
|
62
62
|
name: 'demo', description: '', version: '1.0.0', scope: 'baseline', visibility: 'public',
|
|
63
|
-
dependsOn: [], skills: [
|
|
63
|
+
dependsOn: [], skills: ['demo-skill'], workflows: [], agents: [],
|
|
64
64
|
...over,
|
|
65
65
|
};
|
|
66
66
|
}
|
|
@@ -7,30 +7,30 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
7
7
|
const fs_1 = __importDefault(require("fs"));
|
|
8
8
|
const path_1 = __importDefault(require("path"));
|
|
9
9
|
const os_1 = __importDefault(require("os"));
|
|
10
|
+
let tmpHome;
|
|
11
|
+
let originalHome;
|
|
12
|
+
let originalAwmHome;
|
|
13
|
+
beforeEach(() => {
|
|
14
|
+
tmpHome = fs_1.default.mkdtempSync(path_1.default.join(os_1.default.tmpdir(), 'awm-pin-home-'));
|
|
15
|
+
originalHome = process.env.HOME;
|
|
16
|
+
originalAwmHome = process.env.AWM_HOME;
|
|
17
|
+
process.env.HOME = tmpHome;
|
|
18
|
+
process.env.AWM_HOME = path_1.default.join(tmpHome, '.awm');
|
|
19
|
+
jest.resetModules();
|
|
20
|
+
});
|
|
21
|
+
afterEach(() => {
|
|
22
|
+
fs_1.default.rmSync(tmpHome, { recursive: true, force: true });
|
|
23
|
+
if (originalHome === undefined)
|
|
24
|
+
delete process.env.HOME;
|
|
25
|
+
else
|
|
26
|
+
process.env.HOME = originalHome;
|
|
27
|
+
if (originalAwmHome === undefined)
|
|
28
|
+
delete process.env.AWM_HOME;
|
|
29
|
+
else
|
|
30
|
+
process.env.AWM_HOME = originalAwmHome;
|
|
31
|
+
});
|
|
32
|
+
const readPrefs = () => JSON.parse(fs_1.default.readFileSync(path_1.default.join(tmpHome, '.awm/preferences.json'), 'utf-8'));
|
|
10
33
|
describe('pin/unpin (editores de preferences)', () => {
|
|
11
|
-
let tmpHome;
|
|
12
|
-
let originalHome;
|
|
13
|
-
let originalAwmHome;
|
|
14
|
-
beforeEach(() => {
|
|
15
|
-
tmpHome = fs_1.default.mkdtempSync(path_1.default.join(os_1.default.tmpdir(), 'awm-pin-home-'));
|
|
16
|
-
originalHome = process.env.HOME;
|
|
17
|
-
originalAwmHome = process.env.AWM_HOME;
|
|
18
|
-
process.env.HOME = tmpHome;
|
|
19
|
-
process.env.AWM_HOME = path_1.default.join(tmpHome, '.awm');
|
|
20
|
-
jest.resetModules();
|
|
21
|
-
});
|
|
22
|
-
afterEach(() => {
|
|
23
|
-
fs_1.default.rmSync(tmpHome, { recursive: true, force: true });
|
|
24
|
-
if (originalHome === undefined)
|
|
25
|
-
delete process.env.HOME;
|
|
26
|
-
else
|
|
27
|
-
process.env.HOME = originalHome;
|
|
28
|
-
if (originalAwmHome === undefined)
|
|
29
|
-
delete process.env.AWM_HOME;
|
|
30
|
-
else
|
|
31
|
-
process.env.AWM_HOME = originalAwmHome;
|
|
32
|
-
});
|
|
33
|
-
const readPrefs = () => JSON.parse(fs_1.default.readFileSync(path_1.default.join(tmpHome, '.awm/preferences.json'), 'utf-8'));
|
|
34
34
|
it('setPin escribe pins.base normalizado (acepta prefijo v)', () => {
|
|
35
35
|
const { setPin } = require('../../src/commands/pin');
|
|
36
36
|
setPin('base', 'v1.2.0');
|