geotechcli 0.4.77 → 0.4.79
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/dist/commands/ai.d.ts.map +1 -1
- package/dist/commands/ai.js +236 -7
- package/dist/commands/ai.js.map +1 -1
- package/dist/commands/fem.d.ts.map +1 -1
- package/dist/commands/fem.js +45 -2
- package/dist/commands/fem.js.map +1 -1
- package/dist/commands/ingest.d.ts.map +1 -1
- package/dist/commands/ingest.js +31 -3
- package/dist/commands/ingest.js.map +1 -1
- package/dist/commands/signal.d.ts +3 -0
- package/dist/commands/signal.d.ts.map +1 -0
- package/dist/commands/signal.js +236 -0
- package/dist/commands/signal.js.map +1 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ai.d.ts","sourceRoot":"","sources":["../../src/commands/ai.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"ai.d.ts","sourceRoot":"","sources":["../../src/commands/ai.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAw3DpC,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAmU5D;AAMD,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAwChE;AAMD,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAgDzD;AA4GD,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAuX3D;AAMD,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CA0J1D;AAMD,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAuF5D"}
|
package/dist/commands/ai.js
CHANGED
|
@@ -3,7 +3,7 @@ import { appendFileSync, existsSync, mkdirSync, readFileSync, writeFileSync } fr
|
|
|
3
3
|
import { join, relative, resolve } from 'node:path';
|
|
4
4
|
import chalk from 'chalk';
|
|
5
5
|
import ora from 'ora';
|
|
6
|
-
import { buildLLMConfig, DEFAULT_LLM_VISION_MODEL, analyzeCoreBox, classifyRMRFromImage, classifySoilFromDescription, ingestBoreholeLogDocument, inspectPdfDocument, queryGBRDocument, interpretSensorImage, runAgent, runSwarm, AgentConversation, loadProject, getProjectAgentContext, addAgentSession, addArtifact, addNote, saveNamedDataset, saveDerivedParameter, setActiveAnalysisContext, generateReport, generateReportFromCaseFile, buildProjectWorkflowReport, renderReportAsPdf, renderReportAsDocx, buildSwarmSessionProjectRecord, persistSwarmCaseFile, persistCaseFileEvidence, analyzeWorkspace, resolveWorkspaceRoot, buildProjectWorkflowRouterPrompt, generateText, routeProjectWorkflowRequest, runProjectWorkflow, } from '@geotechcli/core';
|
|
6
|
+
import { buildLLMConfig, DEFAULT_LLM_VISION_MODEL, analyzeCoreBox, classifyRMRFromImage, classifySoilFromDescription, ingestBoreholeLogDocument, inspectPdfDocument, queryGBRDocument, interpretSensorImage, runAgent, runSwarm, AgentConversation, loadProject, getProjectAgentContext, addAgentSession, addArtifact, addNote, saveNamedDataset, saveDerivedParameter, setActiveAnalysisContext, generateReport, generateReportFromCaseFile, buildProjectWorkflowReport, renderReportAsPdf, renderReportAsDocx, buildSwarmSessionProjectRecord, persistSwarmCaseFile, persistCaseFileEvidence, analyzeWorkspace, resolveWorkspaceRoot, buildProjectWorkflowRouterPrompt, generateText, routeProjectWorkflowRequest, runProjectWorkflow, analyzeSignalFile, } from '@geotechcli/core';
|
|
7
7
|
import { heading, keyValue, renderJSON, renderRichText, success, error, warn, renderTable, info } from '../ui/terminal.js';
|
|
8
8
|
import { addGlobalFlags, getGlobalFlags } from '../util/flags.js';
|
|
9
9
|
import { estimateHostedBetaVisionBodyBytes, formatByteSize, HOSTED_BETA_REQUEST_LIMIT_BYTES, readVisionInput, readVisionPdfPageInputs, resolveStructuredOutputTarget, HOSTED_BETA_REQUEST_SAFE_BYTES, } from '../util/vision-output.js';
|
|
@@ -101,6 +101,11 @@ const PROJECT_AGENT_TASKS = [
|
|
|
101
101
|
label: 'Preliminary recommendations',
|
|
102
102
|
prompt: 'Prepare preliminary geotechnical recommendations from the attached workspace manifest. Clearly mark what is evidence-backed, assumption-bound, or blocked by missing inputs.',
|
|
103
103
|
},
|
|
104
|
+
{
|
|
105
|
+
task: 'signal-analysis',
|
|
106
|
+
label: 'Signal analysis',
|
|
107
|
+
prompt: 'Route monitoring, instrumentation, settlement, piezometer, inclinometer, vibration, and load-test files into deterministic geotech signal analyze commands. Summarize available sources, missing threshold assumptions, and review gates without inventing signal metrics.',
|
|
108
|
+
},
|
|
104
109
|
{
|
|
105
110
|
task: 'visualization',
|
|
106
111
|
label: 'Visualizations and maps',
|
|
@@ -164,6 +169,26 @@ function normalizeProjectTask(value) {
|
|
|
164
169
|
case 'fem-foundation-settlement':
|
|
165
170
|
case 'fem-excavation':
|
|
166
171
|
case 'fem-excavation-deformation':
|
|
172
|
+
case 'fem-tunnel':
|
|
173
|
+
case 'fem-tunnel-settlement':
|
|
174
|
+
case 'fem-tunnel-volume-loss-settlement':
|
|
175
|
+
case 'fem-shaft':
|
|
176
|
+
case 'fem-shaft-deformation':
|
|
177
|
+
case 'fem-pile-group':
|
|
178
|
+
case 'fem-pile-group-elastic-interaction':
|
|
179
|
+
case 'fem-slope':
|
|
180
|
+
case 'fem-slope-embankment':
|
|
181
|
+
case 'fem-slope-embankment-deformation':
|
|
182
|
+
case 'fem-embankment':
|
|
183
|
+
case 'fem-retaining-wall':
|
|
184
|
+
case 'fem-retaining-wall-excavation-support':
|
|
185
|
+
case 'fem-excavation-support':
|
|
186
|
+
case 'fem-seepage':
|
|
187
|
+
case 'fem-seepage-groundwater-coupling':
|
|
188
|
+
case 'fem-groundwater-coupling':
|
|
189
|
+
case 'fem-staged-settlement':
|
|
190
|
+
case 'fem-staged-settlement-consolidation':
|
|
191
|
+
case 'fem-consolidation':
|
|
167
192
|
return 'calculation-readiness';
|
|
168
193
|
case 'risk':
|
|
169
194
|
case 'risk-analysis':
|
|
@@ -176,6 +201,24 @@ function normalizeProjectTask(value) {
|
|
|
176
201
|
case 'recommendations':
|
|
177
202
|
case 'foundation-recommendations':
|
|
178
203
|
return 'recommendations';
|
|
204
|
+
case 'signal':
|
|
205
|
+
case 'signals':
|
|
206
|
+
case 'signal-analysis':
|
|
207
|
+
case 'signal-analytics':
|
|
208
|
+
case 'monitoring':
|
|
209
|
+
case 'monitoring-analysis':
|
|
210
|
+
case 'time-series':
|
|
211
|
+
case 'timeseries':
|
|
212
|
+
case 'instrumentation':
|
|
213
|
+
case 'piezometer':
|
|
214
|
+
case 'piezometers':
|
|
215
|
+
case 'inclinometer':
|
|
216
|
+
case 'inclinometers':
|
|
217
|
+
case 'vibration':
|
|
218
|
+
case 'load-test':
|
|
219
|
+
case 'load-tests':
|
|
220
|
+
case 'pile-load-test':
|
|
221
|
+
return 'signal-analysis';
|
|
179
222
|
case 'viz':
|
|
180
223
|
case 'visualize':
|
|
181
224
|
case 'visualization':
|
|
@@ -227,10 +270,11 @@ function inferProjectIntent(rawPrompt, selectedTask) {
|
|
|
227
270
|
};
|
|
228
271
|
add('data-quality', /\b(?:data quality|inventory|missing data|quality report|duplicate)\b/);
|
|
229
272
|
add('ground-model', /\b(?:ground model|interpret|strata|stratigraphy|lithology|hydrogeology)\b/);
|
|
230
|
-
add('calculation-readiness', /\b(?:calculation readiness|calculation route|calculation routing|design readiness|design route|bearing(?: capacity| calculation| readiness)?|settlement(?: calculation| readiness)
|
|
273
|
+
add('calculation-readiness', /\b(?:calculation readiness|calculation route|calculation routing|design readiness|design route|bearing(?: capacity| calculation| readiness)?|settlement(?: calculation| readiness| design| route| workflow)|pile(?: capacity| calculation| readiness)?|liquefaction(?: calculation| readiness)?|slope(?: stability| calculation| readiness)?|fem(?: draft| readiness| foundation settlement| excavation deformation)?|ready for calculation|ready for design)\b/);
|
|
231
274
|
add('risk-analysis', /\b(?:risk|hazard|limitation|uncertainty|mitigation)\b/);
|
|
232
275
|
add('anomaly-detection', /\b(?:anomal\w*|conflict|outlier|inconsistent|inconsistency)\b/);
|
|
233
276
|
add('recommendations', /\b(?:recommend|foundation option|advice|next action)\b/);
|
|
277
|
+
add('signal-analysis', /\b(?:signal analysis|signal analytics|monitoring analysis|time[-\s]?series|instrumentation|piezometer|pore pressure|inclinometer|vibration|accelerometer|settlement monitoring|monitoring trend|threshold|trigger level|load[-\s]?test)\b/);
|
|
234
278
|
add('visualization', /\b(?:visual\w*|map|plot|chart|section|profile|strip log)\b/);
|
|
235
279
|
const uniqueTasks = [...new Set(tasks)];
|
|
236
280
|
if (uniqueTasks.length === 0) {
|
|
@@ -254,6 +298,9 @@ function projectReadinessFromManifest(manifest) {
|
|
|
254
298
|
const hasGroundModel = Boolean(manifest.groundModel && manifest.groundModel.stats.evidenceRefs > 0);
|
|
255
299
|
const hasCoordinates = Boolean(manifest.groundModel?.map?.points?.length);
|
|
256
300
|
const hasVerifier = Boolean(manifest.verifier);
|
|
301
|
+
const signalSources = (manifest.summary.datasetTypes['monitoring-time-series'] ?? 0)
|
|
302
|
+
+ (manifest.summary.datasetTypes['signal-record'] ?? 0)
|
|
303
|
+
+ (manifest.summary.datasetTypes['pile-load-test'] ?? 0);
|
|
257
304
|
const calculationWorkflows = manifest.verifier?.calculationReadiness.workflows ?? [];
|
|
258
305
|
const readyWorkflowCount = calculationWorkflows.filter((workflow) => workflow.status !== 'blocked').length;
|
|
259
306
|
const verifierMissing = calculationWorkflows.flatMap((workflow) => workflow.missing).slice(0, 8);
|
|
@@ -313,6 +360,15 @@ function projectReadinessFromManifest(manifest) {
|
|
|
313
360
|
: ['No downstream calculation workflow is ready yet.'],
|
|
314
361
|
missing: verifierMissing,
|
|
315
362
|
},
|
|
363
|
+
{
|
|
364
|
+
task: 'signal-analysis',
|
|
365
|
+
label: 'Signal analysis',
|
|
366
|
+
status: signalSources > 0 ? 'partially_ready' : 'blocked',
|
|
367
|
+
reasons: signalSources > 0
|
|
368
|
+
? [`${signalSources} monitoring/signal/load-test source(s) can be routed into deterministic signal analysis.`]
|
|
369
|
+
: ['Signal analysis needs settlement, piezometer, inclinometer, vibration, load-test, or time-series data.'],
|
|
370
|
+
missing: signalSources > 0 ? ['project-specific thresholds / trigger levels'] : ['monitoring/signal CSV, TSV, or XLSX files'],
|
|
371
|
+
},
|
|
316
372
|
{
|
|
317
373
|
task: 'visualization',
|
|
318
374
|
label: 'Visualizations and maps',
|
|
@@ -529,6 +585,177 @@ function relativeArtifactPath(rootPath, filePath) {
|
|
|
529
585
|
const rel = relative(rootPath, filePath);
|
|
530
586
|
return rel && !rel.startsWith('..') ? rel : filePath;
|
|
531
587
|
}
|
|
588
|
+
const SIGNAL_WORKFLOW_DATASET_TYPES = new Set(['monitoring-time-series', 'signal-record', 'pile-load-test']);
|
|
589
|
+
function detectSignalWorkflowSources(manifest) {
|
|
590
|
+
const sources = [];
|
|
591
|
+
const seen = new Set();
|
|
592
|
+
for (const file of manifest.files) {
|
|
593
|
+
const schemas = file.schemas ?? [];
|
|
594
|
+
const matchingSchemas = schemas.filter((schema) => SIGNAL_WORKFLOW_DATASET_TYPES.has(schema.datasetType));
|
|
595
|
+
if (matchingSchemas.length > 0) {
|
|
596
|
+
for (const schema of matchingSchemas) {
|
|
597
|
+
const key = `${file.absolutePath}#${schema.sheetName ?? ''}`;
|
|
598
|
+
if (seen.has(key))
|
|
599
|
+
continue;
|
|
600
|
+
seen.add(key);
|
|
601
|
+
sources.push({
|
|
602
|
+
file,
|
|
603
|
+
label: schema.sheetName ? `${file.path}#${schema.sheetName}` : file.path,
|
|
604
|
+
signalType: inferSignalWorkflowType(file, schema),
|
|
605
|
+
sheetName: schema.sheetName,
|
|
606
|
+
});
|
|
607
|
+
}
|
|
608
|
+
continue;
|
|
609
|
+
}
|
|
610
|
+
if (SIGNAL_WORKFLOW_DATASET_TYPES.has(file.classification.datasetType)) {
|
|
611
|
+
const key = `${file.absolutePath}#`;
|
|
612
|
+
if (seen.has(key))
|
|
613
|
+
continue;
|
|
614
|
+
seen.add(key);
|
|
615
|
+
sources.push({
|
|
616
|
+
file,
|
|
617
|
+
label: file.path,
|
|
618
|
+
signalType: inferSignalWorkflowType(file),
|
|
619
|
+
});
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
return sources;
|
|
623
|
+
}
|
|
624
|
+
function inferSignalWorkflowType(file, schema) {
|
|
625
|
+
if (schema?.datasetType === 'pile-load-test' || file.classification.datasetType === 'pile-load-test')
|
|
626
|
+
return 'load-test';
|
|
627
|
+
const roles = new Set(schema?.columns.flatMap((column) => column.roles) ?? []);
|
|
628
|
+
if (roles.has('settlement'))
|
|
629
|
+
return 'settlement';
|
|
630
|
+
if (roles.has('pore_pressure'))
|
|
631
|
+
return 'piezometer';
|
|
632
|
+
if (roles.has('inclination'))
|
|
633
|
+
return 'inclinometer';
|
|
634
|
+
if (roles.has('vibration'))
|
|
635
|
+
return 'vibration';
|
|
636
|
+
const text = [file.path, file.classification.datasetType, ...file.classification.signals].join(' ').toLowerCase();
|
|
637
|
+
if (/\b(load[-_\s]?test|pile[-_\s]?load)\b/.test(text))
|
|
638
|
+
return 'load-test';
|
|
639
|
+
if (/\b(settlement|heave|subsidence)\b/.test(text))
|
|
640
|
+
return 'settlement';
|
|
641
|
+
if (/\b(piezometer|pore[-_\s]?pressure|groundwater|water[-_\s]?level)\b/.test(text))
|
|
642
|
+
return 'piezometer';
|
|
643
|
+
if (/\b(inclinometer|inclination|tilt|deflection)\b/.test(text))
|
|
644
|
+
return 'inclinometer';
|
|
645
|
+
if (/\b(vibration|accelerometer|seismic|fft|psd)\b/.test(text))
|
|
646
|
+
return 'vibration';
|
|
647
|
+
return 'unknown';
|
|
648
|
+
}
|
|
649
|
+
function signalArtifactSlug(value) {
|
|
650
|
+
return value.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-|-$/g, '').slice(0, 64) || 'signal';
|
|
651
|
+
}
|
|
652
|
+
async function persistSignalAnalysisArtifacts(options) {
|
|
653
|
+
if (options.workflowRun.task !== 'signal-analysis')
|
|
654
|
+
return;
|
|
655
|
+
const sources = detectSignalWorkflowSources(options.manifest).slice(0, 12);
|
|
656
|
+
if (sources.length === 0)
|
|
657
|
+
return;
|
|
658
|
+
const signalDir = join(options.runDir, 'signals');
|
|
659
|
+
mkdirSync(signalDir, { recursive: true });
|
|
660
|
+
const indexEntries = [];
|
|
661
|
+
let successCount = 0;
|
|
662
|
+
let failureCount = 0;
|
|
663
|
+
for (const [index, source] of sources.entries()) {
|
|
664
|
+
const artifactPath = join(signalDir, `${String(index + 1).padStart(2, '0')}-${signalArtifactSlug(source.label)}.analysis.json`);
|
|
665
|
+
const analyzeOptions = {
|
|
666
|
+
...(source.signalType !== 'unknown' ? { type: source.signalType } : {}),
|
|
667
|
+
...(source.sheetName ? { sheetName: source.sheetName } : {}),
|
|
668
|
+
maxRows: 5000,
|
|
669
|
+
};
|
|
670
|
+
try {
|
|
671
|
+
const result = await analyzeSignalFile(source.file.absolutePath, analyzeOptions);
|
|
672
|
+
writeFileSync(artifactPath, JSON.stringify(result, null, 2), 'utf-8');
|
|
673
|
+
successCount += 1;
|
|
674
|
+
const relativePath = relativeArtifactPath(options.plan.workspace.rootPath, artifactPath);
|
|
675
|
+
const status = result.warnings.length > 0 ? 'review' : 'pass';
|
|
676
|
+
indexEntries.push({
|
|
677
|
+
source: source.file.path,
|
|
678
|
+
absolutePath: source.file.absolutePath,
|
|
679
|
+
sheetName: source.sheetName,
|
|
680
|
+
status,
|
|
681
|
+
signalType: result.signalType,
|
|
682
|
+
rowsAnalyzed: result.source.rowsAnalyzed,
|
|
683
|
+
rowsRejected: result.source.rowsRejected,
|
|
684
|
+
series: result.series.length,
|
|
685
|
+
thresholdFlags: result.thresholdFlags.length,
|
|
686
|
+
missingIntervals: result.missingIntervals.length,
|
|
687
|
+
warnings: result.warnings,
|
|
688
|
+
artifact: relativePath,
|
|
689
|
+
});
|
|
690
|
+
options.workflowRun.artifacts.push({
|
|
691
|
+
kind: 'json',
|
|
692
|
+
path: relativePath,
|
|
693
|
+
description: `Deterministic signal analysis for ${source.label}`,
|
|
694
|
+
});
|
|
695
|
+
options.workflowRun.trace.steps.push({
|
|
696
|
+
type: 'tool_call',
|
|
697
|
+
name: 'signal.analyze_file',
|
|
698
|
+
status,
|
|
699
|
+
detail: `Analyzed ${source.label} into ${relativePath}.`,
|
|
700
|
+
});
|
|
701
|
+
options.workflowRun.toolCalls.push({
|
|
702
|
+
type: 'tool_call',
|
|
703
|
+
tool: 'signal.analyze_file',
|
|
704
|
+
status,
|
|
705
|
+
summary: `Analyzed ${source.label}: ${result.source.rowsAnalyzed} rows, ${result.series.length} series, ${result.thresholdFlags.length} threshold flag(s), ${result.missingIntervals.length} missing interval(s).`,
|
|
706
|
+
});
|
|
707
|
+
}
|
|
708
|
+
catch (err) {
|
|
709
|
+
failureCount += 1;
|
|
710
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
711
|
+
indexEntries.push({
|
|
712
|
+
source: source.file.path,
|
|
713
|
+
absolutePath: source.file.absolutePath,
|
|
714
|
+
sheetName: source.sheetName,
|
|
715
|
+
status: 'blocked',
|
|
716
|
+
signalType: source.signalType,
|
|
717
|
+
error: message,
|
|
718
|
+
});
|
|
719
|
+
options.workflowRun.trace.steps.push({
|
|
720
|
+
type: 'tool_call',
|
|
721
|
+
name: 'signal.analyze_file',
|
|
722
|
+
status: 'blocked',
|
|
723
|
+
detail: `Could not analyze ${source.label}: ${message}`,
|
|
724
|
+
});
|
|
725
|
+
options.workflowRun.toolCalls.push({
|
|
726
|
+
type: 'tool_call',
|
|
727
|
+
tool: 'signal.analyze_file',
|
|
728
|
+
status: 'blocked',
|
|
729
|
+
summary: `Could not analyze ${source.label}: ${message}`,
|
|
730
|
+
});
|
|
731
|
+
}
|
|
732
|
+
}
|
|
733
|
+
if (failureCount > 0) {
|
|
734
|
+
options.workflowRun.status = successCount > 0 && options.workflowRun.status !== 'blocked' ? 'review' : 'blocked';
|
|
735
|
+
}
|
|
736
|
+
const indexPath = join(signalDir, 'index.json');
|
|
737
|
+
const indexPayload = {
|
|
738
|
+
schemaVersion: 'geotech.signal-analysis-artifact-index.v1',
|
|
739
|
+
generatedAt: options.workflowRun.generatedAt,
|
|
740
|
+
runId: options.workflowRun.runId,
|
|
741
|
+
task: options.workflowRun.task,
|
|
742
|
+
sources: indexEntries,
|
|
743
|
+
};
|
|
744
|
+
writeFileSync(indexPath, JSON.stringify(indexPayload, null, 2), 'utf-8');
|
|
745
|
+
const relativeIndexPath = relativeArtifactPath(options.plan.workspace.rootPath, indexPath);
|
|
746
|
+
options.workflowRun.artifacts.push({
|
|
747
|
+
kind: 'json',
|
|
748
|
+
path: relativeIndexPath,
|
|
749
|
+
description: 'Deterministic signal analysis artifact index',
|
|
750
|
+
});
|
|
751
|
+
options.workflowRun.summary.push(`Signal analyses persisted: ${successCount}/${sources.length} source(s) under ${relativeArtifactPath(options.plan.workspace.rootPath, signalDir)}.`);
|
|
752
|
+
options.workflowRun.toolCalls.push({
|
|
753
|
+
type: 'tool_call',
|
|
754
|
+
tool: 'signal.analysis_artifacts',
|
|
755
|
+
status: failureCount > 0 ? 'review' : 'pass',
|
|
756
|
+
summary: `Persisted ${successCount}/${sources.length} deterministic signal analysis artifact(s).`,
|
|
757
|
+
});
|
|
758
|
+
}
|
|
532
759
|
async function requestProjectWorkflowRouteProposal(options) {
|
|
533
760
|
const routePrompt = buildProjectWorkflowRouterPrompt({
|
|
534
761
|
prompt: options.prompt,
|
|
@@ -612,7 +839,7 @@ function renderProjectAwarePlan(plan, flags) {
|
|
|
612
839
|
}
|
|
613
840
|
console.log('');
|
|
614
841
|
warn('No model-heavy workflow has run yet. Choose a task with --task, or ask a project question with --workspace.');
|
|
615
|
-
console.log(chalk.gray(' Next actions: geotech agent --task data-quality | --task ground-model | --task calculation-readiness | --task risk-analysis | --task anomaly-detection | --task recommendations | --task visualization'));
|
|
842
|
+
console.log(chalk.gray(' Next actions: geotech agent --task data-quality | --task ground-model | --task calculation-readiness | --task risk-analysis | --task anomaly-detection | --task recommendations | --task signal-analysis | --task visualization'));
|
|
616
843
|
success(`Project state written to ${relativeArtifactPath(plan.workspace.rootPath, join(plan.workspace.rootPath, '.geotech'))}`);
|
|
617
844
|
}
|
|
618
845
|
async function renderAndPersistProjectWorkflow(plan, manifest, task, flags) {
|
|
@@ -622,11 +849,12 @@ async function renderAndPersistProjectWorkflow(plan, manifest, task, flags) {
|
|
|
622
849
|
runId: plan.runId,
|
|
623
850
|
now: plan.project.generatedAt,
|
|
624
851
|
});
|
|
625
|
-
const report = buildProjectWorkflowReport(workflowRun);
|
|
626
852
|
const runDir = join(plan.workspace.rootPath, '.geotech', 'runs', plan.runId);
|
|
627
853
|
const resultPath = join(runDir, 'workflow_result.json');
|
|
628
854
|
const reportPath = join(runDir, 'workflow_report.md');
|
|
629
855
|
const tracePath = join(runDir, 'workflow_trace.json');
|
|
856
|
+
await persistSignalAnalysisArtifacts({ plan, manifest, workflowRun, runDir });
|
|
857
|
+
const report = buildProjectWorkflowReport(workflowRun);
|
|
630
858
|
writeFileSync(resultPath, JSON.stringify(workflowRun, null, 2), 'utf-8');
|
|
631
859
|
writeFileSync(reportPath, report.fullMarkdown, 'utf-8');
|
|
632
860
|
writeFileSync(tracePath, JSON.stringify(workflowRun.trace, null, 2), 'utf-8');
|
|
@@ -699,12 +927,13 @@ async function renderAndPersistProjectWorkflowRoute(plan, manifest, route, flags
|
|
|
699
927
|
runId: workflowRunId,
|
|
700
928
|
now: plan.project.generatedAt,
|
|
701
929
|
});
|
|
702
|
-
const report = buildProjectWorkflowReport(workflowRun);
|
|
703
930
|
const runDir = join(plan.workspace.rootPath, '.geotech', 'runs', workflowRun.runId);
|
|
704
931
|
mkdirSync(runDir, { recursive: true });
|
|
705
932
|
const resultPath = join(runDir, 'workflow_result.json');
|
|
706
933
|
const reportPath = join(runDir, 'workflow_report.md');
|
|
707
934
|
const tracePath = join(runDir, 'workflow_trace.json');
|
|
935
|
+
await persistSignalAnalysisArtifacts({ plan, manifest, workflowRun, runDir });
|
|
936
|
+
const report = buildProjectWorkflowReport(workflowRun);
|
|
708
937
|
writeFileSync(resultPath, JSON.stringify(workflowRun, null, 2), 'utf-8');
|
|
709
938
|
writeFileSync(reportPath, report.fullMarkdown, 'utf-8');
|
|
710
939
|
writeFileSync(tracePath, JSON.stringify(workflowRun.trace, null, 2), 'utf-8');
|
|
@@ -1830,14 +2059,14 @@ function renderSwarmStep(step, json, quiet = false) {
|
|
|
1830
2059
|
}
|
|
1831
2060
|
export function registerAgentCommand(program) {
|
|
1832
2061
|
const cmd = new Command('agent')
|
|
1833
|
-
.description('Agentic AI -
|
|
2062
|
+
.description('Agentic AI - routes evidence into deterministic tools; FEM execution remains human-invoked and experimental')
|
|
1834
2063
|
.argument('[task...]', 'Engineering task in natural language')
|
|
1835
2064
|
.option('--swarm', 'Use the role-based multi-agent swarm planner and specialist review loop')
|
|
1836
2065
|
.option('--skills', 'Enable installed skill tools for this session')
|
|
1837
2066
|
.option('--project <id>', 'Load and persist context to a stored project')
|
|
1838
2067
|
.option('--workspace <dir>', 'Scan a local workspace and attach its manifest summary to the agent task')
|
|
1839
2068
|
.option('--no-workspace', 'Disable automatic project-aware workspace discovery')
|
|
1840
|
-
.option('--task <task>', 'Run a project-aware task: data-quality, ground-model, calculation-readiness, risk-analysis, anomaly-detection, recommendations, visualization')
|
|
2069
|
+
.option('--task <task>', 'Run a project-aware task: data-quality, ground-model, calculation-readiness, risk-analysis, anomaly-detection, recommendations, signal-analysis, visualization')
|
|
1841
2070
|
.option('--route-with-model', 'Let the configured LLM propose a validated workflow route when deterministic routing needs selection')
|
|
1842
2071
|
.option('--plan-only', 'Scan the workspace, write .geotech project state, and show workflow readiness without calling an LLM')
|
|
1843
2072
|
.option('--refresh', 'Refresh the deterministic workspace manifest and .geotech project state')
|