chati-dev 4.5.16 → 4.5.27
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 +8 -3
- package/bin/chati.js +124 -66
- package/framework/agents/build/dev.md +5 -5
- package/framework/agents/deploy/devops.md +7 -7
- package/framework/agents/discover/brief.md +4 -4
- package/framework/agents/discover/brownfield-wu.md +3 -3
- package/framework/agents/discover/greenfield-wu.md +3 -3
- package/framework/agents/plan/architect.md +2 -2
- package/framework/agents/plan/detail.md +4 -4
- package/framework/agents/plan/phases.md +2 -2
- package/framework/agents/plan/tasks.md +2 -2
- package/framework/agents/plan/ux.md +2 -2
- package/framework/agents/quality/qa-implementation.md +11 -10
- package/framework/agents/quality/qa-planning.md +3 -3
- package/framework/agents/quality/qa-visual.md +1 -1
- package/framework/config.yaml +3 -3
- package/framework/constitution.md +18 -18
- package/framework/context/protocols.md +1 -1
- package/framework/context/quality.md +1 -1
- package/framework/context/root.md +4 -4
- package/framework/data/entity-registry.yaml +1 -1
- package/framework/domains/agents/orchestrator.yaml +2 -2
- package/framework/domains/constitution.yaml +1 -1
- package/framework/hooks/advance-trigger.js +4 -6
- package/framework/hooks/git-push-authority.js +45 -37
- package/framework/hooks/mode-governance.js +149 -40
- package/framework/hooks/model-governance.js +13 -20
- package/framework/hooks/prism-engine.js +74 -92
- package/framework/hooks/reasoning-escalator.js +23 -40
- package/framework/hooks/session-digest.js +12 -13
- package/framework/hooks/session-reader.js +224 -0
- package/framework/hooks/session-writer.js +195 -0
- package/framework/hooks/team-quality-gate.js +34 -24
- package/framework/i18n/en.yaml +2 -2
- package/framework/i18n/es.yaml +2 -2
- package/framework/i18n/fr.yaml +2 -2
- package/framework/i18n/pt.yaml +2 -2
- package/framework/intelligence/context-engine.md +4 -4
- package/framework/intelligence/memory-layer.md +1 -1
- package/framework/manifest.json +129 -119
- package/framework/manifest.sig +1 -1
- package/framework/orchestrator/chati-router.js +252 -25
- package/framework/orchestrator/chati.md +238 -70
- package/framework/schemas/session.schema.json +1 -1
- package/framework/tasks/orchestrator-deviation.md +1 -1
- package/framework/tasks/orchestrator-escalate.md +1 -1
- package/framework/tasks/orchestrator-handoff.md +6 -6
- package/framework/tasks/orchestrator-health.md +5 -9
- package/framework/tasks/orchestrator-mode-switch.md +3 -7
- package/framework/tasks/orchestrator-resume.md +10 -14
- package/framework/tasks/orchestrator-route.md +3 -3
- package/framework/tasks/orchestrator-spawn-terminal.md +1 -1
- package/framework/tasks/orchestrator-status.md +9 -9
- package/framework/tasks/orchestrator-suggest-mode.md +1 -1
- package/framework/tasks/qa-impl-consolidate.md +2 -2
- package/framework/tasks/qa-impl-performance-test.md +4 -4
- package/framework/tasks/qa-impl-regression-check.md +4 -4
- package/framework/tasks/qa-impl-sast-scan.md +1 -1
- package/framework/tasks/qa-impl-test-execute.md +1 -1
- package/framework/tasks/qa-impl-verdict.md +2 -2
- package/framework/tasks/qa-planning-consolidate.md +3 -3
- package/framework/tasks/qa-planning-coverage-plan.md +2 -2
- package/framework/tasks/qa-planning-gate-define.md +4 -4
- package/framework/tasks/qa-planning-risk-matrix.md +4 -4
- package/framework/tasks/qa-planning-test-strategy.md +2 -2
- package/node_modules/@chati/browser-capability/src/index.js +12 -2
- package/node_modules/@chati/planning/src/index.js +24 -4
- package/node_modules/@chati/provider-registry/src/index.js +11 -0
- package/node_modules/@chati/rail/src/index.js +1967 -83
- package/node_modules/@chati/release-lane/README.md +12 -8
- package/node_modules/@chati/release-lane/package.json +1 -1
- package/node_modules/@chati/release-lane/src/index.js +1426 -58
- package/node_modules/@chati/review-council/src/index.js +63 -0
- package/node_modules/@chati/tracking-clickup/README.md +13 -0
- package/node_modules/@chati/tracking-clickup/src/index.js +690 -30
- package/package-artifact-manifest.json +1 -0
- package/package-artifact-manifest.sig +1 -0
- package/package.json +16 -7
- package/scripts/verify-real-harness-e2e.js +1581 -0
- package/src/config/framework-adapter.js +4 -4
- package/src/installer/core.js +148 -53
- package/src/installer/manifest.js +140 -9
- package/src/installer/package-artifact.js +249 -0
- package/src/installer/templates.js +65 -20
- package/src/installer-v2/catalog-client.js +531 -23
- package/src/installer-v2/index.js +91 -34
- package/src/installer-v2/installation-authority.js +327 -0
- package/src/installer-v2/provider-executable.js +235 -0
- package/src/installer-v2/wizard-installation.js +1 -1
- package/src/orchestrator/browser-runtime.js +44 -13
- package/src/orchestrator/cli.js +1545 -174
- package/src/orchestrator/clickup-projection.js +43 -1
- package/src/orchestrator/clickup-runtime.js +355 -39
- package/src/orchestrator/doctor.js +16 -3
- package/src/orchestrator/index.js +16 -0
- package/src/orchestrator/planning-runtime.js +20 -2
- package/src/orchestrator/rail-adjudication-evidence.js +234 -0
- package/src/orchestrator/rail-evidence-authority.js +147 -0
- package/src/orchestrator/rail-execution-evidence.js +45 -0
- package/src/orchestrator/rail-runtime.js +836 -56
- package/src/orchestrator/release-runtime.js +65 -6
- package/src/orchestrator/review-runtime.js +186 -41
- package/src/orchestrator/runtime-installation-v2.js +236 -20
- package/src/orchestrator/session-manager.js +1167 -53
- package/src/terminal/adapters/claude-adapter.js +3 -1
- package/src/terminal/adapters/codex-adapter.js +2 -0
- package/src/terminal/adapters/grok-adapter.js +7 -4
- package/src/terminal/handoff-parser.js +19 -1
- package/src/terminal/prompt-builder.js +9 -1
- package/src/terminal/provider-preflight.js +36 -3
- package/src/terminal/rail-execution-worktree.js +213 -0
- package/src/terminal/rail-prompts.js +169 -0
- package/src/terminal/rail-readonly-workspace.js +324 -0
- package/src/terminal/run-agent.js +384 -24
- package/src/terminal/run-parallel.js +5 -0
- package/src/terminal/run-rail-adjudication.js +323 -0
- package/src/terminal/run-rail-review.js +291 -0
- package/src/terminal/run-rail-rework.js +325 -0
- package/src/terminal/run-rail-task.js +380 -0
- package/src/terminal/run-team.js +5 -0
- package/src/terminal/spawner.js +1225 -77
- package/src/wizard/index.js +3 -2
|
@@ -16,7 +16,9 @@
|
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
18
|
import { existsSync, readFileSync } from 'fs';
|
|
19
|
-
import {
|
|
19
|
+
import { randomUUID } from 'crypto';
|
|
20
|
+
import { join, resolve } from 'path';
|
|
21
|
+
import { readHookSession } from '../hooks/session-reader.js';
|
|
20
22
|
|
|
21
23
|
const PROJECT_DIR = process.cwd();
|
|
22
24
|
const RAW_ROUTER_ARGS = process.argv.slice(2);
|
|
@@ -45,6 +47,7 @@ async function readEnabledHarnesses(projectDir) {
|
|
|
45
47
|
|
|
46
48
|
const detected = [];
|
|
47
49
|
if (existsSync(join(projectDir, '.claude', 'commands', 'chati.md'))) detected.push('claude');
|
|
50
|
+
if (existsSync(join(projectDir, '.gemini', 'commands', 'chati.toml'))) detected.push('gemini');
|
|
48
51
|
if (existsSync(join(projectDir, '.agents', 'skills', 'chati', 'SKILL.md'))) detected.push('codex');
|
|
49
52
|
if (existsSync(join(projectDir, '.grok', 'commands', 'chati.md'))) detected.push('grok');
|
|
50
53
|
return { harnesses: detected, error: null };
|
|
@@ -69,7 +72,7 @@ export async function validateProviderIntegrity(projectDir) {
|
|
|
69
72
|
const { harnesses, error } = await readEnabledHarnesses(projectDir);
|
|
70
73
|
|
|
71
74
|
if (error) missing.push(error);
|
|
72
|
-
const supportedHarnesses = new Set(['claude', 'codex', 'grok']);
|
|
75
|
+
const supportedHarnesses = new Set(['claude', 'gemini', 'codex', 'grok']);
|
|
73
76
|
for (const harness of harnesses) {
|
|
74
77
|
if (!supportedHarnesses.has(harness)) missing.push(`unsupported harness ${harness}`);
|
|
75
78
|
}
|
|
@@ -137,9 +140,40 @@ export async function validateProviderIntegrity(projectDir) {
|
|
|
137
140
|
}
|
|
138
141
|
}
|
|
139
142
|
|
|
143
|
+
if (harnesses.includes('gemini')) {
|
|
144
|
+
for (const [label, relativePath] of [
|
|
145
|
+
['gemini command', '.gemini/commands/chati.toml'],
|
|
146
|
+
['gemini session lock', '.gemini/session-lock.md'],
|
|
147
|
+
['gemini governance context', '.gemini/context/governance.md'],
|
|
148
|
+
['gemini license hook file', '.gemini/hooks/license-guard.js'],
|
|
149
|
+
]) {
|
|
150
|
+
if (!hasContent(join(projectDir, relativePath))) missing.push(label);
|
|
151
|
+
}
|
|
152
|
+
const settingsPath = join(projectDir, '.gemini', 'settings.json');
|
|
153
|
+
if (!hasContent(settingsPath)) {
|
|
154
|
+
missing.push('gemini settings');
|
|
155
|
+
} else {
|
|
156
|
+
try {
|
|
157
|
+
const settings = JSON.parse(readFileSync(settingsPath, 'utf-8'));
|
|
158
|
+
const firstHook = settings.hooks?.BeforeModel?.[0]?.hooks?.[0];
|
|
159
|
+
if (firstHook?.name !== 'license-guard'
|
|
160
|
+
|| firstHook?.command !== 'node .gemini/hooks/license-guard.js') {
|
|
161
|
+
missing.push('gemini license hook');
|
|
162
|
+
}
|
|
163
|
+
} catch {
|
|
164
|
+
missing.push('gemini settings invalid');
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
140
169
|
if (harnesses.includes('grok')) {
|
|
141
170
|
if (!hasContent(join(projectDir, '.grok', 'commands', 'chati.md'))) missing.push('grok command');
|
|
142
171
|
if (!hasContent(join(projectDir, '.grok', 'session-lock.md'))) missing.push('grok session lock');
|
|
172
|
+
const governancePath = join(projectDir, '.grok', 'rules', 'chati-governance.md');
|
|
173
|
+
if (!hasContent(governancePath)
|
|
174
|
+
|| !readFileSync(governancePath, 'utf-8').includes('chati-router.js --harness grok')) {
|
|
175
|
+
missing.push('grok governance rule');
|
|
176
|
+
}
|
|
143
177
|
}
|
|
144
178
|
|
|
145
179
|
return { valid: missing.length === 0, missing };
|
|
@@ -320,7 +354,20 @@ const VALID_ORCHESTRATE_SUBS = new Set([
|
|
|
320
354
|
'activate-harness',
|
|
321
355
|
]);
|
|
322
356
|
|
|
323
|
-
const VALID_RAIL_SUBS = new Set([
|
|
357
|
+
const VALID_RAIL_SUBS = new Set([
|
|
358
|
+
'rail-next',
|
|
359
|
+
'rail-dispatch',
|
|
360
|
+
'rail-review-run',
|
|
361
|
+
'rail-rework',
|
|
362
|
+
'rail-adjudicate',
|
|
363
|
+
'rail-recover',
|
|
364
|
+
'rail-complete',
|
|
365
|
+
'rail-release-ready',
|
|
366
|
+
'rail-tracking-reconcile',
|
|
367
|
+
'rail-tracking-pending',
|
|
368
|
+
'rail-tracking-ack',
|
|
369
|
+
'rail-tracking-lookup',
|
|
370
|
+
]);
|
|
324
371
|
|
|
325
372
|
/**
|
|
326
373
|
* Parse --flag value pairs and standalone --flag bools from argv.
|
|
@@ -386,8 +433,17 @@ async function dispatchRail(subCommand, argv) {
|
|
|
386
433
|
}
|
|
387
434
|
|
|
388
435
|
const flags = parseFlagArgs(argv);
|
|
436
|
+
const parseJsonFlag = (name, { required = false } = {}) => {
|
|
437
|
+
const raw = flags[name];
|
|
438
|
+
if (raw === undefined) {
|
|
439
|
+
if (required) throw Object.assign(new Error(`Missing --${name}`), { code: 'RAIL_INPUT_REQUIRED' });
|
|
440
|
+
return undefined;
|
|
441
|
+
}
|
|
442
|
+
try { return JSON.parse(raw); }
|
|
443
|
+
catch (error) { throw Object.assign(new Error(`Invalid JSON in --${name}: ${error.message}`), { code: 'RAIL_INPUT_INVALID' }); }
|
|
444
|
+
};
|
|
389
445
|
if (subCommand === 'rail-next') {
|
|
390
|
-
if (!flags['handoff-id']) return { ok: false, error: 'Missing --handoff-id' };
|
|
446
|
+
if (!flags['handoff-id']) return { ok: false, action: 'error', error: 'RAIL_INPUT_REQUIRED', detail: 'Missing --handoff-id' };
|
|
391
447
|
try {
|
|
392
448
|
const { selectReadyRailTasks } = await import(runtimePath);
|
|
393
449
|
return selectReadyRailTasks({ projectDir: PROJECT_DIR, handoff_id: flags['handoff-id'] });
|
|
@@ -395,6 +451,173 @@ async function dispatchRail(subCommand, argv) {
|
|
|
395
451
|
return { ok: false, action: 'error', error: error.code || error.message };
|
|
396
452
|
}
|
|
397
453
|
}
|
|
454
|
+
if (subCommand === 'rail-dispatch') {
|
|
455
|
+
if (!flags['handoff-id'] || !flags['task-id']) return { ok: false, action: 'error', error: 'RAIL_INPUT_REQUIRED', detail: 'Missing --handoff-id or --task-id' };
|
|
456
|
+
const attemptId = flags['attempt-id'] || `attempt-${randomUUID()}`;
|
|
457
|
+
try {
|
|
458
|
+
const runnerPath = join(PROJECT_DIR, fwDir, '_cli', 'terminal', 'run-rail-task.js');
|
|
459
|
+
if (!existsSync(runnerPath)) return { ok: false, action: 'error', error: 'rail_dispatch_runtime_not_found' };
|
|
460
|
+
const { executeReadyRailTask } = await import(runnerPath);
|
|
461
|
+
const browserRequest = flags['browser-request-json']
|
|
462
|
+
? JSON.parse(flags['browser-request-json'])
|
|
463
|
+
: undefined;
|
|
464
|
+
return await executeReadyRailTask({
|
|
465
|
+
projectDir: PROJECT_DIR,
|
|
466
|
+
handoff_id: flags['handoff-id'],
|
|
467
|
+
task_id: flags['task-id'],
|
|
468
|
+
attempt_id: attemptId,
|
|
469
|
+
operator_id: flags['operator-id'] || `operator://chati/${ACTIVE_HARNESS || 'runtime'}`,
|
|
470
|
+
...(flags.timeout ? { timeout: Number(flags.timeout) } : {}),
|
|
471
|
+
...(browserRequest === undefined ? {} : { browser_request: browserRequest }),
|
|
472
|
+
});
|
|
473
|
+
} catch (error) {
|
|
474
|
+
let nextRequiredAction = 'rail_retry_same_attempt';
|
|
475
|
+
try {
|
|
476
|
+
const runtime = await import(runtimePath);
|
|
477
|
+
runtime.resolveRailAttemptContext({ projectDir: PROJECT_DIR, handoff_id: flags['handoff-id'], attempt_id: attemptId });
|
|
478
|
+
nextRequiredAction = 'rail_recover_same_attempt_after_lease_expiry';
|
|
479
|
+
} catch {
|
|
480
|
+
// The dispatch never created a canonical claim.
|
|
481
|
+
}
|
|
482
|
+
return {
|
|
483
|
+
ok: false, action: 'error', error: error.code || 'RAIL_DISPATCH_FAILED',
|
|
484
|
+
detail: error.message, attempt_id: error.details?.attempt_id || attemptId,
|
|
485
|
+
next_required_action: nextRequiredAction,
|
|
486
|
+
};
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
if (subCommand === 'rail-recover') {
|
|
490
|
+
if (!flags['handoff-id'] || !flags['attempt-id'] || !flags['operator-id']) {
|
|
491
|
+
return { ok: false, action: 'error', error: 'RAIL_INPUT_REQUIRED', detail: 'Missing --handoff-id, --attempt-id or --operator-id' };
|
|
492
|
+
}
|
|
493
|
+
const attemptId = flags['attempt-id'];
|
|
494
|
+
try {
|
|
495
|
+
const runnerPath = join(PROJECT_DIR, fwDir, '_cli', 'terminal', 'run-rail-task.js');
|
|
496
|
+
if (!existsSync(runnerPath)) return { ok: false, action: 'error', error: 'rail_dispatch_runtime_not_found' };
|
|
497
|
+
const runtime = await import(runtimePath);
|
|
498
|
+
const { executeReadyRailTask } = await import(runnerPath);
|
|
499
|
+
const context = runtime.resolveRailAttemptContext({
|
|
500
|
+
projectDir: PROJECT_DIR,
|
|
501
|
+
handoff_id: flags['handoff-id'],
|
|
502
|
+
attempt_id: attemptId,
|
|
503
|
+
});
|
|
504
|
+
const browserRequest = flags['browser-request-json']
|
|
505
|
+
? JSON.parse(flags['browser-request-json'])
|
|
506
|
+
: undefined;
|
|
507
|
+
return await executeReadyRailTask({
|
|
508
|
+
projectDir: PROJECT_DIR,
|
|
509
|
+
handoff_id: flags['handoff-id'],
|
|
510
|
+
task_id: context.task.task_id,
|
|
511
|
+
attempt_id: attemptId,
|
|
512
|
+
operator_id: flags['operator-id'],
|
|
513
|
+
recover_expired: true,
|
|
514
|
+
...(flags.timeout ? { timeout: Number(flags.timeout) } : {}),
|
|
515
|
+
...(browserRequest === undefined ? {} : { browser_request: browserRequest }),
|
|
516
|
+
});
|
|
517
|
+
} catch (error) {
|
|
518
|
+
return {
|
|
519
|
+
ok: false, action: 'error', error: error.code || 'RAIL_RECOVERY_FAILED',
|
|
520
|
+
detail: error.message, attempt_id: error.details?.attempt_id || attemptId,
|
|
521
|
+
next_required_action: 'rail_recover_and_dispatch_same_attempt',
|
|
522
|
+
};
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
if (subCommand === 'rail-review-run') {
|
|
526
|
+
if (!flags['handoff-id'] || !flags['attempt-id']) return { ok: false, action: 'error', error: 'Missing --handoff-id or --attempt-id' };
|
|
527
|
+
try {
|
|
528
|
+
const runnerPath = join(PROJECT_DIR, fwDir, '_cli', 'terminal', 'run-rail-review.js');
|
|
529
|
+
if (!existsSync(runnerPath)) return { ok: false, action: 'error', error: 'rail_review_runtime_not_found' };
|
|
530
|
+
const { executeRailReview } = await import(runnerPath);
|
|
531
|
+
return await executeRailReview({
|
|
532
|
+
projectDir: PROJECT_DIR,
|
|
533
|
+
handoff_id: flags['handoff-id'],
|
|
534
|
+
attempt_id: flags['attempt-id'],
|
|
535
|
+
...(flags.timeout ? { timeout: Number(flags.timeout) } : {}),
|
|
536
|
+
});
|
|
537
|
+
} catch (error) {
|
|
538
|
+
return { ok: false, action: 'error', error: error.code || 'RAIL_REVIEW_FAILED', detail: error.message };
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
if (subCommand === 'rail-rework') {
|
|
542
|
+
if (!flags['handoff-id'] || !flags['attempt-id']) return { ok: false, action: 'error', error: 'Missing --handoff-id or --attempt-id' };
|
|
543
|
+
try {
|
|
544
|
+
const runnerPath = join(PROJECT_DIR, fwDir, '_cli', 'terminal', 'run-rail-rework.js');
|
|
545
|
+
if (!existsSync(runnerPath)) return { ok: false, action: 'error', error: 'rail_rework_runtime_not_found' };
|
|
546
|
+
const { executeRailRework } = await import(runnerPath);
|
|
547
|
+
return await executeRailRework({
|
|
548
|
+
projectDir: PROJECT_DIR,
|
|
549
|
+
handoff_id: flags['handoff-id'],
|
|
550
|
+
attempt_id: flags['attempt-id'],
|
|
551
|
+
...(flags.timeout ? { timeout: Number(flags.timeout) } : {}),
|
|
552
|
+
});
|
|
553
|
+
} catch (error) {
|
|
554
|
+
return { ok: false, action: 'error', error: error.code || 'RAIL_REWORK_FAILED', detail: error.message };
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
if (subCommand === 'rail-adjudicate') {
|
|
558
|
+
if (!flags['handoff-id'] || !flags['attempt-id']) return { ok: false, action: 'error', error: 'Missing --handoff-id or --attempt-id' };
|
|
559
|
+
try {
|
|
560
|
+
const runnerPath = join(PROJECT_DIR, fwDir, '_cli', 'terminal', 'run-rail-adjudication.js');
|
|
561
|
+
if (!existsSync(runnerPath)) return { ok: false, action: 'error', error: 'rail_adjudication_runtime_not_found' };
|
|
562
|
+
const { executeRailAdjudication } = await import(runnerPath);
|
|
563
|
+
return await executeRailAdjudication({
|
|
564
|
+
projectDir: PROJECT_DIR,
|
|
565
|
+
handoff_id: flags['handoff-id'],
|
|
566
|
+
attempt_id: flags['attempt-id'],
|
|
567
|
+
...(flags.timeout ? { timeout: Number(flags.timeout) } : {}),
|
|
568
|
+
});
|
|
569
|
+
} catch (error) {
|
|
570
|
+
return { ok: false, action: 'error', error: error.code || 'RAIL_ADJUDICATION_FAILED', detail: error.message };
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
try {
|
|
574
|
+
const runtime = await import(runtimePath);
|
|
575
|
+
if (subCommand === 'rail-complete') {
|
|
576
|
+
const completion = parseJsonFlag('completion-json', { required: true });
|
|
577
|
+
const { completion_id, attempt_id, claim_id, operator_id, state, git, ci, reviews, acceptance_evidence_refs, acceptance_authority_receipt, completed_at, metrics } = completion;
|
|
578
|
+
return runtime.completeRailTask({
|
|
579
|
+
projectDir: PROJECT_DIR, handoff_id: flags['handoff-id'], completion_id, attempt_id, claim_id, operator_id, state, git, ci,
|
|
580
|
+
reviews, acceptance_evidence_refs, acceptance_authority_receipt, ...(completed_at === undefined ? {} : { completed_at }), ...(metrics === undefined ? {} : { metrics }),
|
|
581
|
+
});
|
|
582
|
+
}
|
|
583
|
+
if (subCommand === 'rail-release-ready') {
|
|
584
|
+
return runtime.selectRailReleaseReadiness({ projectDir: PROJECT_DIR, handoff_id: flags['handoff-id'] });
|
|
585
|
+
}
|
|
586
|
+
if (subCommand === 'rail-tracking-reconcile') {
|
|
587
|
+
return runtime.reconcileProjectClickUpTracking({ projectDir: PROJECT_DIR, handoff_id: flags['handoff-id'] });
|
|
588
|
+
}
|
|
589
|
+
if (subCommand === 'rail-tracking-pending') {
|
|
590
|
+
const clickUpRuntimePath = join(PROJECT_DIR, fwDir, '_cli', 'orchestrator', 'clickup-runtime.js');
|
|
591
|
+
const clickUpRuntime = await import(clickUpRuntimePath);
|
|
592
|
+
return clickUpRuntime.preparePendingClickUpProjections({ projectDir: PROJECT_DIR });
|
|
593
|
+
}
|
|
594
|
+
if (subCommand === 'rail-tracking-ack') {
|
|
595
|
+
if (!flags['handoff-id'] || !flags['projection-id'] || !flags.receipt) {
|
|
596
|
+
throw Object.assign(new Error('Missing --handoff-id, --projection-id or --receipt'), { code: 'RAIL_INPUT_REQUIRED' });
|
|
597
|
+
}
|
|
598
|
+
const clickUpRuntimePath = join(PROJECT_DIR, fwDir, '_cli', 'orchestrator', 'clickup-runtime.js');
|
|
599
|
+
const clickUpRuntime = await import(clickUpRuntimePath);
|
|
600
|
+
const receipt = JSON.parse(readFileSync(resolve(flags.receipt), 'utf8'));
|
|
601
|
+
return clickUpRuntime.acknowledgeClickUpProjection({
|
|
602
|
+
projectDir: PROJECT_DIR, handoff_id: flags['handoff-id'],
|
|
603
|
+
projection_id: flags['projection-id'], receipt,
|
|
604
|
+
});
|
|
605
|
+
}
|
|
606
|
+
if (subCommand === 'rail-tracking-lookup') {
|
|
607
|
+
if (!flags['handoff-id'] || !flags['projection-id'] || !flags.result) {
|
|
608
|
+
throw Object.assign(new Error('Missing --handoff-id, --projection-id or --result'), { code: 'RAIL_INPUT_REQUIRED' });
|
|
609
|
+
}
|
|
610
|
+
const clickUpRuntimePath = join(PROJECT_DIR, fwDir, '_cli', 'orchestrator', 'clickup-runtime.js');
|
|
611
|
+
const clickUpRuntime = await import(clickUpRuntimePath);
|
|
612
|
+
const result = JSON.parse(readFileSync(resolve(flags.result), 'utf8'));
|
|
613
|
+
return clickUpRuntime.resolveClickUpProjectionLookup({
|
|
614
|
+
projectDir: PROJECT_DIR, handoff_id: flags['handoff-id'],
|
|
615
|
+
projection_id: flags['projection-id'], result,
|
|
616
|
+
});
|
|
617
|
+
}
|
|
618
|
+
} catch (error) {
|
|
619
|
+
return { ok: false, action: 'error', error: error.code || 'RAIL_RUNTIME_FAILED', detail: error.message };
|
|
620
|
+
}
|
|
398
621
|
return { ok: false, action: 'error', error: `Unsupported RAIL command: ${subCommand}` };
|
|
399
622
|
}
|
|
400
623
|
|
|
@@ -495,8 +718,15 @@ async function main() {
|
|
|
495
718
|
active_harness: ACTIVE_HARNESS,
|
|
496
719
|
};
|
|
497
720
|
|
|
498
|
-
const
|
|
499
|
-
if (
|
|
721
|
+
const sessionRead = readHookSession(PROJECT_DIR);
|
|
722
|
+
if (!sessionRead.loaded && !sessionRead.missing) {
|
|
723
|
+
result.ok = false;
|
|
724
|
+
result.action = 'error';
|
|
725
|
+
result.error = `unsafe_session: ${sessionRead.error}`;
|
|
726
|
+
console.log(JSON.stringify(result));
|
|
727
|
+
return;
|
|
728
|
+
}
|
|
729
|
+
if (ACTIVE_HARNESS && sessionRead.loaded) {
|
|
500
730
|
const cliMod = await findCliModule(PROJECT_DIR);
|
|
501
731
|
if (!cliMod) {
|
|
502
732
|
result.ok = false;
|
|
@@ -518,25 +748,16 @@ async function main() {
|
|
|
518
748
|
// -----------------------------------------------------------------------
|
|
519
749
|
// 1. Session state
|
|
520
750
|
// -----------------------------------------------------------------------
|
|
521
|
-
|
|
522
|
-
const
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
project_name: extract('name') || '',
|
|
532
|
-
project_type: extract('type') || 'greenfield',
|
|
533
|
-
state: extract('state') || 'discover',
|
|
534
|
-
current_agent: extract('current_agent') || '',
|
|
535
|
-
workflow: extract('workflow') || 'full',
|
|
536
|
-
};
|
|
537
|
-
}
|
|
538
|
-
} catch {
|
|
539
|
-
result.session = null;
|
|
751
|
+
if (sessionRead.loaded) {
|
|
752
|
+
const session = sessionRead.session;
|
|
753
|
+
result.session = {
|
|
754
|
+
language: session.language || 'en',
|
|
755
|
+
project_name: session.project?.name || '',
|
|
756
|
+
project_type: session.project?.type || session.project_type || 'greenfield',
|
|
757
|
+
state: session.project?.state || session.mode || 'discover',
|
|
758
|
+
current_agent: session.current_agent || '',
|
|
759
|
+
workflow: session.workflow || 'full',
|
|
760
|
+
};
|
|
540
761
|
}
|
|
541
762
|
|
|
542
763
|
// -----------------------------------------------------------------------
|
|
@@ -548,14 +769,20 @@ async function main() {
|
|
|
548
769
|
const cliMod = await findCliModule(PROJECT_DIR);
|
|
549
770
|
if (findCliModule._mismatch) result.version_mismatch = findCliModule._mismatch;
|
|
550
771
|
if (!cliMod) {
|
|
772
|
+
result.ok = false;
|
|
551
773
|
result.action = 'error';
|
|
552
774
|
result.error = 'cli_module_not_found';
|
|
553
775
|
result.reason = 'Bundled CLI missing in .chati.dev/_cli/. Reinstall with: npx chati-dev upgrade';
|
|
554
776
|
} else {
|
|
555
777
|
result.pipeline = await captureOrchestrate(cliMod, 'next', [], PROJECT_DIR);
|
|
556
778
|
result.action = result.pipeline.action;
|
|
779
|
+
if (result.action === 'error' || result.pipeline?.ok === false) {
|
|
780
|
+
result.ok = false;
|
|
781
|
+
result.error = result.pipeline?.error || result.pipeline?.code || 'pipeline_routing_failed';
|
|
782
|
+
}
|
|
557
783
|
}
|
|
558
784
|
} catch (err) {
|
|
785
|
+
result.ok = false;
|
|
559
786
|
result.action = 'error';
|
|
560
787
|
result.error = `pipeline_routing_failed: ${err.message?.slice(0, 200)}`;
|
|
561
788
|
}
|