yam-flow 0.1.7 → 0.1.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +50 -0
- package/COMMANDS.md +6 -1
- package/README.md +9 -1
- package/dist/bin/yam.js +278 -10
- package/dist/lib/trust-kernel.d.ts +48 -0
- package/dist/lib/trust-kernel.js +166 -0
- package/package.json +1 -1
- package/references/final-report.md +26 -0
- package/skills/deep/SKILL.md +2 -2
- package/skills/mission/SKILL.md +2 -2
- package/skills/quick/SKILL.md +2 -1
- package/skills/ueye/SKILL.md +2 -1
- package/src/bin/yam.ts +289 -11
- package/src/lib/trust-kernel.ts +206 -0
- package/yam.manifest.json +4 -2
package/src/lib/trust-kernel.ts
CHANGED
|
@@ -17,6 +17,8 @@ export type EvidenceKind = 'command' | 'evidence' | 'visual' | 'runtime' | 'skip
|
|
|
17
17
|
export type RuntimeSubsystem = 'real_runtime' | 'tmux_physical' | 'process_cleanup' | 'browser_visual' | 'db_safety';
|
|
18
18
|
export type RuntimeBackend = 'none' | 'in_app_browser' | 'playwright' | 'terminal' | 'tmux' | 'zellij' | 'unknown';
|
|
19
19
|
export type RuntimeClaim = 'not_started' | 'started' | 'observed' | 'stopped' | 'cleanup_verified' | 'blocked' | 'unknown';
|
|
20
|
+
export type LoopStageStatus = 'passed' | 'failed' | 'blocked' | 'skipped' | 'partial' | 'pending' | 'recorded';
|
|
21
|
+
export type ToolIntent = 'read_only' | 'write' | 'destructive' | 'runtime' | 'visual' | 'publish';
|
|
20
22
|
|
|
21
23
|
export interface SafetyHit {
|
|
22
24
|
level: SafetyLevel;
|
|
@@ -149,6 +151,54 @@ export interface RuntimeBackendEvidence {
|
|
|
149
151
|
truth_status: TruthStatus;
|
|
150
152
|
}
|
|
151
153
|
|
|
154
|
+
export interface StudyNoteSection {
|
|
155
|
+
code: string;
|
|
156
|
+
role: string;
|
|
157
|
+
symptom?: string;
|
|
158
|
+
summary?: string;
|
|
159
|
+
truth_status: TruthStatus;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
export interface StudyNote {
|
|
163
|
+
schema: 'yam.study-note.v1';
|
|
164
|
+
problem: StudyNoteSection;
|
|
165
|
+
change: StudyNoteSection;
|
|
166
|
+
why_it_matters: string;
|
|
167
|
+
learning_note: string;
|
|
168
|
+
limits: string[];
|
|
169
|
+
truth_status: TruthStatus;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
export interface LoopStage {
|
|
173
|
+
id: string;
|
|
174
|
+
status: LoopStageStatus;
|
|
175
|
+
note: string;
|
|
176
|
+
truth_status: TruthStatus;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
export interface LoopReport {
|
|
180
|
+
schema: 'yam.loop-report.v1';
|
|
181
|
+
generated_at: string;
|
|
182
|
+
route: string;
|
|
183
|
+
intent: string;
|
|
184
|
+
loop_kind: string;
|
|
185
|
+
stages: LoopStage[];
|
|
186
|
+
evidence: string[];
|
|
187
|
+
blockers: string[];
|
|
188
|
+
truth_status: TruthStatus;
|
|
189
|
+
intent_label: ToolIntent;
|
|
190
|
+
tool_intent: ToolIntent;
|
|
191
|
+
next_action: string;
|
|
192
|
+
fix_first_items: string[];
|
|
193
|
+
remaining_tasks: string[];
|
|
194
|
+
recommended_direction: string;
|
|
195
|
+
implementation_notes: string[];
|
|
196
|
+
why_this_next: string;
|
|
197
|
+
blocked_by: string[];
|
|
198
|
+
owner_route: string;
|
|
199
|
+
study_note: StudyNote;
|
|
200
|
+
}
|
|
201
|
+
|
|
152
202
|
export interface UeyeRunReport {
|
|
153
203
|
schema: 'yam.ueye-run-report.v1';
|
|
154
204
|
reference_sources: UeyeVisualProvenance[];
|
|
@@ -452,6 +502,78 @@ export function buildRuntimeBackendEvidence(input: Partial<RuntimeBackendEvidenc
|
|
|
452
502
|
};
|
|
453
503
|
}
|
|
454
504
|
|
|
505
|
+
export function buildStudyNote(input: Partial<StudyNote> & Record<string, unknown> = {}): StudyNote {
|
|
506
|
+
const problem = buildStudyNoteSection(input.problem, {
|
|
507
|
+
code: input.issue_code,
|
|
508
|
+
role: input.issue_role,
|
|
509
|
+
symptom: input.issue_symptom
|
|
510
|
+
}, 'problem');
|
|
511
|
+
const change = buildStudyNoteSection(input.change, {
|
|
512
|
+
code: input.changed_code,
|
|
513
|
+
role: input.changed_role,
|
|
514
|
+
summary: input.change_summary
|
|
515
|
+
}, 'change');
|
|
516
|
+
const whyItMatters = shortText(input.why_it_matters || input.why_important);
|
|
517
|
+
const learningNote = shortText(input.learning_note);
|
|
518
|
+
const limits = [
|
|
519
|
+
...asList(input.limits),
|
|
520
|
+
...missingStudyNoteLimits(problem, change, whyItMatters, learningNote)
|
|
521
|
+
];
|
|
522
|
+
const hasProblem = Boolean(problem.code || problem.role || problem.symptom);
|
|
523
|
+
const hasChange = Boolean(change.code || change.role || change.summary);
|
|
524
|
+
const truth: TruthStatus = isTruthStatus(input.truth_status) ? input.truth_status
|
|
525
|
+
: hasProblem || hasChange || whyItMatters || learningNote ? 'partial'
|
|
526
|
+
: 'assumed';
|
|
527
|
+
return {
|
|
528
|
+
schema: 'yam.study-note.v1',
|
|
529
|
+
problem,
|
|
530
|
+
change,
|
|
531
|
+
why_it_matters: whyItMatters,
|
|
532
|
+
learning_note: learningNote,
|
|
533
|
+
limits: [...new Set(limits)],
|
|
534
|
+
truth_status: truth
|
|
535
|
+
};
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
export function buildLoopReport(input: Partial<LoopReport> & Record<string, unknown> = {}): LoopReport {
|
|
539
|
+
const stages = Array.isArray(input.stages)
|
|
540
|
+
? input.stages.map((stage) => buildLoopStage(stage))
|
|
541
|
+
: [];
|
|
542
|
+
const evidence = asList(input.evidence);
|
|
543
|
+
const blockers = asList(input.blockers || input.blocked);
|
|
544
|
+
const hasBlockedStage = stages.some((stage) => stage.status === 'blocked' || stage.status === 'failed');
|
|
545
|
+
const requestedTruth = isTruthStatus(input.truth_status) ? input.truth_status : '';
|
|
546
|
+
const derivedTruth: TruthStatus = blockers.length || hasBlockedStage ? 'blocked'
|
|
547
|
+
: evidence.length && stages.some((stage) => stage.status === 'passed') ? 'verified'
|
|
548
|
+
: evidence.length || stages.length ? 'partial'
|
|
549
|
+
: 'assumed';
|
|
550
|
+
const truth = requestedTruth ? weakestTruth(requestedTruth, derivedTruth) : derivedTruth;
|
|
551
|
+
const studyNote = buildStudyNote(input.study_note && typeof input.study_note === 'object' ? input.study_note as unknown as Record<string, unknown> : input);
|
|
552
|
+
const intentLabel = normalizeToolIntentLabel(input.intent_label || input.tool_intent);
|
|
553
|
+
return {
|
|
554
|
+
schema: 'yam.loop-report.v1',
|
|
555
|
+
generated_at: String(input.generated_at || new Date().toISOString()),
|
|
556
|
+
route: String(input.route || ''),
|
|
557
|
+
intent: shortText(input.intent),
|
|
558
|
+
loop_kind: String(input.loop_kind || 'harness'),
|
|
559
|
+
stages,
|
|
560
|
+
evidence,
|
|
561
|
+
blockers,
|
|
562
|
+
truth_status: truth,
|
|
563
|
+
intent_label: intentLabel,
|
|
564
|
+
tool_intent: intentLabel,
|
|
565
|
+
next_action: shortText(input.next_action || (blockers[0] ? 'resolve the blocker before claiming this loop complete' : 'record the next smallest useful action')),
|
|
566
|
+
fix_first_items: asList(input.fix_first_items || input.fix_first_item),
|
|
567
|
+
remaining_tasks: asList(input.remaining_tasks || input.remaining_task),
|
|
568
|
+
recommended_direction: shortText(input.recommended_direction || input.direction),
|
|
569
|
+
implementation_notes: asList(input.implementation_notes || input.implementation_note),
|
|
570
|
+
why_this_next: shortText(input.why_this_next),
|
|
571
|
+
blocked_by: asList(input.blocked_by),
|
|
572
|
+
owner_route: normalizeOwnerRoute(input.owner_route || input.route),
|
|
573
|
+
study_note: studyNote
|
|
574
|
+
};
|
|
575
|
+
}
|
|
576
|
+
|
|
455
577
|
export function buildUeyeRunReport(input: UeyeRunReportInput = {}): UeyeRunReport {
|
|
456
578
|
const references = Array.isArray(input.reference_sources)
|
|
457
579
|
? input.reference_sources.map((item) => buildUeyeVisualProvenance(item))
|
|
@@ -494,6 +616,90 @@ export function buildUeyeRunReport(input: UeyeRunReportInput = {}): UeyeRunRepor
|
|
|
494
616
|
};
|
|
495
617
|
}
|
|
496
618
|
|
|
619
|
+
function buildStudyNoteSection(section: unknown, fallback: Record<string, unknown>, kind: 'problem' | 'change'): StudyNoteSection {
|
|
620
|
+
const source = section && typeof section === 'object' ? section as Record<string, unknown> : fallback;
|
|
621
|
+
const code = shortText(source.code);
|
|
622
|
+
const role = shortText(source.role);
|
|
623
|
+
const symptom = kind === 'problem' ? shortText(source.symptom) : undefined;
|
|
624
|
+
const summary = kind === 'change' ? shortText(source.summary) : undefined;
|
|
625
|
+
return {
|
|
626
|
+
code,
|
|
627
|
+
role,
|
|
628
|
+
...(symptom !== undefined ? { symptom } : {}),
|
|
629
|
+
...(summary !== undefined ? { summary } : {}),
|
|
630
|
+
truth_status: code || role || symptom || summary ? 'partial' : 'assumed'
|
|
631
|
+
};
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
function missingStudyNoteLimits(problem: StudyNoteSection, change: StudyNoteSection, whyItMatters = '', learningNote = ''): string[] {
|
|
635
|
+
const limits: string[] = [];
|
|
636
|
+
if (!problem.code) limits.push('issue_code not provided');
|
|
637
|
+
if (!problem.role) limits.push('issue_role not provided');
|
|
638
|
+
if (!problem.symptom) limits.push('issue_symptom not provided');
|
|
639
|
+
if (!change.code) limits.push('changed_code not provided');
|
|
640
|
+
if (!change.role) limits.push('changed_role not provided');
|
|
641
|
+
if (!change.summary) limits.push('change_summary not provided');
|
|
642
|
+
if (!whyItMatters) limits.push('why_it_matters not provided');
|
|
643
|
+
if (!learningNote) limits.push('learning_note not provided');
|
|
644
|
+
return limits;
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
function buildLoopStage(value: unknown = ''): LoopStage {
|
|
648
|
+
if (value && typeof value === 'object') {
|
|
649
|
+
const item = value as Partial<LoopStage>;
|
|
650
|
+
return loopStage(String(item.id || ''), item.status, String(item.note || ''));
|
|
651
|
+
}
|
|
652
|
+
const [id = '', rawStatus = '', ...noteParts] = String(value || '').split(':');
|
|
653
|
+
return loopStage(id, rawStatus, noteParts.join(':'));
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
function loopStage(id = '', rawStatus: unknown = '', note = ''): LoopStage {
|
|
657
|
+
const status = normalizeLoopStageStatus(rawStatus);
|
|
658
|
+
return {
|
|
659
|
+
id: shortText(id || 'stage'),
|
|
660
|
+
status,
|
|
661
|
+
note: shortText(note),
|
|
662
|
+
truth_status: stageTruth(status)
|
|
663
|
+
};
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
function normalizeLoopStageStatus(value: unknown = ''): LoopStageStatus {
|
|
667
|
+
const text = String(value || '').toLowerCase().replace(/[-\s]/g, '_');
|
|
668
|
+
if (text === 'pass' || text === 'passed' || text === 'ok') return 'passed';
|
|
669
|
+
if (text === 'fail' || text === 'failed' || text === 'error') return 'failed';
|
|
670
|
+
if (text === 'block' || text === 'blocked') return 'blocked';
|
|
671
|
+
if (text === 'skip' || text === 'skipped') return 'skipped';
|
|
672
|
+
if (text === 'partial') return 'partial';
|
|
673
|
+
if (text === 'pending') return 'pending';
|
|
674
|
+
return 'recorded';
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
function stageTruth(status: LoopStageStatus): TruthStatus {
|
|
678
|
+
if (status === 'passed') return 'verified';
|
|
679
|
+
if (status === 'failed' || status === 'blocked') return 'blocked';
|
|
680
|
+
if (status === 'skipped') return 'skipped';
|
|
681
|
+
if (status === 'pending') return 'assumed';
|
|
682
|
+
return 'partial';
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
function normalizeToolIntentLabel(value: unknown = ''): ToolIntent {
|
|
686
|
+
const text = String(value || '').toLowerCase().replace(/[-\s]/g, '_');
|
|
687
|
+
if (['read_only', 'write', 'destructive', 'runtime', 'visual', 'publish'].includes(text)) return text as ToolIntent;
|
|
688
|
+
return 'read_only';
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
function normalizeOwnerRoute(value: unknown = ''): string {
|
|
692
|
+
const text = String(value || '').trim().replace(/^\$/, '').replace(/^yam-/, '');
|
|
693
|
+
if (['quick', 'ueye', 'question', 'scout', 'deep', 'mission'].includes(text)) return `$${text}`;
|
|
694
|
+
return text ? shortText(text, 80) : '';
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
function shortText(value: unknown = '', limit = 240): string {
|
|
698
|
+
const text = String(value || '').trim().replace(/\s+/g, ' ');
|
|
699
|
+
if (text.length <= limit) return text;
|
|
700
|
+
return `${text.slice(0, limit - 3)}...`;
|
|
701
|
+
}
|
|
702
|
+
|
|
497
703
|
export function buildMediaGenerationProof(input: Partial<MediaGenerationProof> = {}): MediaGenerationProof {
|
|
498
704
|
const requested = Boolean(input.generation_requested);
|
|
499
705
|
const attempted = Boolean(input.generation_attempted);
|
package/yam.manifest.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "yam",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.9",
|
|
4
4
|
"principles": [
|
|
5
5
|
"Direction before execution.",
|
|
6
6
|
"Start fast.",
|
|
@@ -10,7 +10,9 @@
|
|
|
10
10
|
"Heavy proof when risk or user intent calls for it.",
|
|
11
11
|
"Token-aware by default.",
|
|
12
12
|
"Context-reuse first.",
|
|
13
|
-
"End with remaining tasks and fix-first items."
|
|
13
|
+
"End with remaining tasks and fix-first items.",
|
|
14
|
+
"Explain what failed, what changed, and why it matters in short non-specialist language when useful.",
|
|
15
|
+
"Use handoff notes for fix-first items, remaining tasks, and recommended next direction when useful."
|
|
14
16
|
],
|
|
15
17
|
"defaultHooks": false,
|
|
16
18
|
"routes": [
|