@etiquekit/etq 1.0.13 → 1.0.15
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/AGENTS.md +26 -19
- package/LICENSE +3 -2
- package/NOTICE +4 -6
- package/QuickStart.md +46 -35
- package/README.md +57 -55
- package/bin/etiquette +5 -1
- package/bin/etiquette-core +5 -1
- package/docs/ARCHITECTURE.md +17 -20
- package/docs/CONCEPTS.md +5 -5
- package/docs/CORE_PROFILE.md +15 -7
- package/docs/LANE_PROVISIONING.md +2 -7
- package/docs/README.md +14 -13
- package/docs/RELEASE_SURFACE_AUDIT.md +6 -7
- package/docs/SEAT_DISCIPLINE.md +91 -55
- package/docs/SEAT_PROVISIONING.md +19 -16
- package/docs/TEAM_HANDOFF.md +21 -21
- package/docs/WORKTREE_QOL.md +0 -7
- package/docs/contracts/ledger-entry/README.md +11 -11
- package/docs/contracts/ledger-entry/ledger-entry.v0.2.md +2 -2
- package/docs/contracts/ledger-entry/ledger-entry.v0.md +8 -8
- package/lib/etiquette-core.js +313 -0
- package/lib/etiquette.js +1151 -0
- package/package.json +13 -12
- package/templates/etiquette-vanilla-v0/README.md +3 -2
- package/templates/etiquette-vanilla-v0/source/control-seat/README.md +6 -0
- package/templates/etiquette-vanilla-v0/source/control-seat/bin/access-assurance-check +55 -0
- package/templates/etiquette-vanilla-v0/source/control-seat/bin/seat-doctor +5 -0
- package/templates/etiquette-vanilla-v0/source/control-seat/docs/work/access/ACCESS-ASSURANCE.md +39 -0
- package/templates/etiquette-vanilla-v0/source/control-seat/docs/work/access/workspace-secure-profile.v0.json +53 -0
- package/templates/etiquette-vanilla-v0/validate-vanilla.sh +5 -0
- package/templates/hosted-receiver/README.md +41 -0
- package/templates/hosted-receiver/w1-github-webhook-receiver.mjs +129 -0
- package/templates/seat-packs-v0/README.md +2 -3
- package/templates/seat-packs-v0/source/claude-code-seat/README.md +3 -3
- package/templates/seat-packs-v0/source/codex-seat/README.md +3 -3
- package/templates/seat-packs-v0/source/gemini-seat/README.md +3 -3
- package/templates/seat-packs-v0/source/ollama-seat/README.md +3 -3
- package/templates/seat-packs-v0/source/openrouter-seat/README.md +3 -3
- package/docs/CONCEPT_STATUS.md +0 -66
- package/packages/control/src/authority/lease.ts +0 -261
- package/packages/control/src/authority/node-delegation.ts +0 -257
- package/packages/control/src/authority/rig-conductor.ts +0 -632
- package/packages/control/src/cli/argv.ts +0 -155
- package/packages/control/src/cli/commands/console.ts +0 -200
- package/packages/control/src/cli/commands/dispatch-core.ts +0 -89
- package/packages/control/src/cli/commands/dispatch.ts +0 -279
- package/packages/control/src/cli/commands/harness.ts +0 -89
- package/packages/control/src/cli/commands/hook.ts +0 -50
- package/packages/control/src/cli/commands/ledger.ts +0 -91
- package/packages/control/src/cli/commands/local-workflow.ts +0 -4686
- package/packages/control/src/cli/commands/memory.ts +0 -445
- package/packages/control/src/cli/commands/release.ts +0 -108
- package/packages/control/src/cli/commands/rubric.ts +0 -103
- package/packages/control/src/cli/commands/seat.ts +0 -179
- package/packages/control/src/cli/commands/session.ts +0 -127
- package/packages/control/src/cli/commands/supervision.ts +0 -246
- package/packages/control/src/cli/commands/sync.ts +0 -119
- package/packages/control/src/cli/commands/workflow.ts +0 -86
- package/packages/control/src/cli/commands/workspace.ts +0 -50
- package/packages/control/src/cli/core-usage.ts +0 -34
- package/packages/control/src/cli/prompt.ts +0 -67
- package/packages/control/src/cli/supervision-deps.ts +0 -44
- package/packages/control/src/cli/usage.ts +0 -241
- package/packages/control/src/cli.ts +0 -207
- package/packages/control/src/core-cli.ts +0 -50
- package/packages/control/src/dispatch/decision.ts +0 -202
- package/packages/control/src/dispatch/projection.ts +0 -293
- package/packages/control/src/dispatch/record.ts +0 -153
- package/packages/control/src/engagement/project.ts +0 -170
- package/packages/control/src/fs.ts +0 -19
- package/packages/control/src/harness/pruning.ts +0 -406
- package/packages/control/src/hooks/dispatcher.ts +0 -117
- package/packages/control/src/hooks/outbox.ts +0 -86
- package/packages/control/src/hooks/sanitize.ts +0 -6
- package/packages/control/src/hooks/types.ts +0 -34
- package/packages/control/src/index.ts +0 -384
- package/packages/control/src/ledger/entry.ts +0 -303
- package/packages/control/src/ledger/indexer.ts +0 -542
- package/packages/control/src/memory/context.ts +0 -149
- package/packages/control/src/memory/drain-import.ts +0 -207
- package/packages/control/src/memory/indexer.ts +0 -284
- package/packages/control/src/memory/query.ts +0 -75
- package/packages/control/src/memory/sanitize.ts +0 -50
- package/packages/control/src/memory/sharded-drain-import.ts +0 -212
- package/packages/control/src/memory/status.ts +0 -211
- package/packages/control/src/memory/store-lifecycle.ts +0 -509
- package/packages/control/src/memory/store.ts +0 -284
- package/packages/control/src/memory/types.ts +0 -146
- package/packages/control/src/parity/surfaces.ts +0 -748
- package/packages/control/src/project.ts +0 -141
- package/packages/control/src/projection/local-ledger-view.ts +0 -373
- package/packages/control/src/projection/return-enforcement.ts +0 -48
- package/packages/control/src/projection/timeline-preview.ts +0 -539
- package/packages/control/src/projection/timeline.ts +0 -708
- package/packages/control/src/release/readiness.ts +0 -831
- package/packages/control/src/rubric/loader.ts +0 -326
- package/packages/control/src/rubric/promotion.ts +0 -54
- package/packages/control/src/rubric/runner.ts +0 -159
- package/packages/control/src/rubric/types.ts +0 -158
- package/packages/control/src/seat/owner-card.ts +0 -388
- package/packages/control/src/seat/readiness.ts +0 -834
- package/packages/control/src/session/runbook.ts +0 -431
- package/packages/control/src/shared/sanitize.ts +0 -49
- package/packages/control/src/supervision/action-classes.ts +0 -192
- package/packages/control/src/supervision/command-apply.ts +0 -378
- package/packages/control/src/supervision/errors.ts +0 -14
- package/packages/control/src/supervision/event-replay.ts +0 -155
- package/packages/control/src/supervision/events.ts +0 -109
- package/packages/control/src/supervision/index.ts +0 -16
- package/packages/control/src/supervision/manifest.ts +0 -127
- package/packages/control/src/supervision/paths.ts +0 -49
- package/packages/control/src/supervision/projection-adapter.ts +0 -274
- package/packages/control/src/supervision/projection.ts +0 -75
- package/packages/control/src/supervision/rebuild.ts +0 -99
- package/packages/control/src/supervision/session-open.ts +0 -131
- package/packages/control/src/supervision/session-read.ts +0 -99
- package/packages/control/src/supervision/sqlite-impl.ts +0 -71
- package/packages/control/src/supervision/sqlite.ts +0 -121
- package/packages/control/src/supervision/store-rows.ts +0 -371
- package/packages/control/src/supervision/turn-close.ts +0 -154
- package/packages/control/src/supervision/turn-open.ts +0 -284
- package/packages/control/src/sync/event-log-merge-driver.ts +0 -263
- package/packages/control/src/sync/join-plan.ts +0 -375
- package/packages/control/src/sync/outbox.ts +0 -492
- package/packages/control/src/workflow/evaluator.ts +0 -140
- package/packages/control/src/workflow/loader.ts +0 -200
- package/packages/control/src/workflow/types.ts +0 -90
- package/packages/control/src/workspace/authority.ts +0 -499
- package/packages/protocol/src/guards.ts +0 -119
- package/packages/protocol/src/huddle-board.ts +0 -198
- package/packages/protocol/src/huddle.ts +0 -295
- package/packages/protocol/src/incident.ts +0 -251
- package/packages/protocol/src/index.ts +0 -8
- package/packages/protocol/src/interfaces.ts +0 -107
- package/packages/protocol/src/packet-profile.ts +0 -195
- package/packages/protocol/src/state.ts +0 -81
- package/packages/protocol/src/types.ts +0 -434
- package/release/lineage.v0.json +0 -14
- package/scripts/release-candidate-verify.sh +0 -175
- package/scripts/release-checksum.sh +0 -25
- package/scripts/release-pack-canary.sh +0 -97
- package/scripts/release-scan.sh +0 -249
- package/scripts/release-sign.sh +0 -34
|
@@ -1,445 +0,0 @@
|
|
|
1
|
-
import { resolve } from 'node:path';
|
|
2
|
-
import { optionalString, parseInt32, parseList, requireString } from '../argv';
|
|
3
|
-
import { buildMemoryContext } from '../../memory/context';
|
|
4
|
-
import { drainImportMemoryCandidates } from '../../memory/drain-import';
|
|
5
|
-
import { shardedDrainImportMemoryCandidates } from '../../memory/sharded-drain-import';
|
|
6
|
-
import { defaultMemoryExportDir, indexMemory } from '../../memory/indexer';
|
|
7
|
-
import { preflightMemory, rejectedMemory, searchMemory, showMemory, staleMemory } from '../../memory/query';
|
|
8
|
-
import { memoryCapabilityStatus, type MemoryCapabilityStatus } from '../../memory/status';
|
|
9
|
-
import {
|
|
10
|
-
addMemoryStoreCandidate,
|
|
11
|
-
consolidateMemoryStores,
|
|
12
|
-
initMemoryStore,
|
|
13
|
-
listMemoryStores,
|
|
14
|
-
parseEvidenceRefs,
|
|
15
|
-
showMemoryStore,
|
|
16
|
-
type MemoryStoreSummary,
|
|
17
|
-
} from '../../memory/store-lifecycle';
|
|
18
|
-
import {
|
|
19
|
-
WORKSPACE_MEMORY_ACCESS,
|
|
20
|
-
WORKSPACE_MEMORY_MOUNT_MODES,
|
|
21
|
-
WORKSPACE_MEMORY_SCOPES,
|
|
22
|
-
WORKSPACE_MEMORY_WRITE_POLICIES,
|
|
23
|
-
type WorkspaceMemoryAccess,
|
|
24
|
-
type WorkspaceMemoryMountMode,
|
|
25
|
-
type WorkspaceMemoryScope,
|
|
26
|
-
type WorkspaceMemoryWritePolicy,
|
|
27
|
-
} from '../../workspace/authority';
|
|
28
|
-
|
|
29
|
-
const MEMORY_VERBS = new Set([
|
|
30
|
-
'index',
|
|
31
|
-
'search',
|
|
32
|
-
'show',
|
|
33
|
-
'preflight',
|
|
34
|
-
'context',
|
|
35
|
-
'status',
|
|
36
|
-
'stale',
|
|
37
|
-
'rejected',
|
|
38
|
-
'store',
|
|
39
|
-
'consolidate',
|
|
40
|
-
'drain-import',
|
|
41
|
-
'sharded-drain-import',
|
|
42
|
-
]);
|
|
43
|
-
|
|
44
|
-
export function isMemoryCommand(command: string): boolean {
|
|
45
|
-
return command === 'memory';
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
function asLimit(raw: string | boolean | undefined, fallback: number): number {
|
|
49
|
-
if (raw === undefined) return fallback;
|
|
50
|
-
const parsed = parseInt32(raw, 'limit');
|
|
51
|
-
if (parsed < 1 || parsed > 50) {
|
|
52
|
-
throw new Error('--limit must be between 1 and 50');
|
|
53
|
-
}
|
|
54
|
-
return parsed;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
function renderCompact(items: {
|
|
58
|
-
capsule_id: string;
|
|
59
|
-
title: string;
|
|
60
|
-
category: string;
|
|
61
|
-
confidence: string;
|
|
62
|
-
stale_status: string;
|
|
63
|
-
evidence_count: number;
|
|
64
|
-
}[]): string {
|
|
65
|
-
if (items.length === 0) return 'memory: no matching capsules\n';
|
|
66
|
-
return `${items.map((item) => [
|
|
67
|
-
`capsule: ${item.capsule_id}`,
|
|
68
|
-
`title: ${item.title}`,
|
|
69
|
-
`category: ${item.category}`,
|
|
70
|
-
`confidence: ${item.confidence}`,
|
|
71
|
-
`stale_status: ${item.stale_status}`,
|
|
72
|
-
`evidence_count: ${item.evidence_count}`,
|
|
73
|
-
].join('\n')).join('\n---\n')}\n`;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
function renderRejected(items: {
|
|
77
|
-
candidate_id: string;
|
|
78
|
-
title: string;
|
|
79
|
-
category: string;
|
|
80
|
-
risk_flags: string[];
|
|
81
|
-
rejection_reasons: string[];
|
|
82
|
-
source_refs: { type: string; ref: string }[];
|
|
83
|
-
}[]): string {
|
|
84
|
-
if (items.length === 0) return 'memory: no rejected candidates\n';
|
|
85
|
-
return `${items.map((item) => [
|
|
86
|
-
`candidate: ${item.candidate_id}`,
|
|
87
|
-
`title: ${item.title}`,
|
|
88
|
-
`category: ${item.category}`,
|
|
89
|
-
`risk_flags: ${item.risk_flags.join(', ') || 'none'}`,
|
|
90
|
-
`rejection_reasons: ${item.rejection_reasons.join(', ') || 'none'}`,
|
|
91
|
-
`source_refs: ${item.source_refs.map((ref) => `${ref.type}:${ref.ref}`).join(', ')}`,
|
|
92
|
-
].join('\n')).join('\n---\n')}\n`;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
function renderContext(context: ReturnType<typeof buildMemoryContext>): string {
|
|
96
|
-
const scope = [
|
|
97
|
-
context.scope.org_id ? `org_id=${context.scope.org_id}` : undefined,
|
|
98
|
-
context.scope.workspace_id ? `workspace_id=${context.scope.workspace_id}` : undefined,
|
|
99
|
-
context.scope.lane_ref ? `lane_ref=${context.scope.lane_ref}` : undefined,
|
|
100
|
-
context.scope.task_ref ? `task_ref=${context.scope.task_ref}` : undefined,
|
|
101
|
-
].filter(Boolean).join(' ');
|
|
102
|
-
const items = context.items.length === 0
|
|
103
|
-
? [' capsules: none']
|
|
104
|
-
: context.items.flatMap((item) => [
|
|
105
|
-
` - ${item.capsule_id}`,
|
|
106
|
-
` title: ${item.title}`,
|
|
107
|
-
` category: ${item.category}`,
|
|
108
|
-
` confidence: ${item.confidence}`,
|
|
109
|
-
` stale_status: ${item.stale_status}`,
|
|
110
|
-
` evidence_refs: ${item.evidence_refs.map((ref) => `${ref.type}:${ref.ref}`).join(', ')}`,
|
|
111
|
-
]);
|
|
112
|
-
return [
|
|
113
|
-
'memory_context:',
|
|
114
|
-
` schema: ${context.schema}`,
|
|
115
|
-
` query: ${context.query}`,
|
|
116
|
-
` scope: ${scope || 'workspace_local'}`,
|
|
117
|
-
' boundary: summaries-only; advisory memory; cannot authorize, close, replace receipts, or mutate ledger',
|
|
118
|
-
...items,
|
|
119
|
-
].join('\n') + '\n';
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
function enumValue<T extends readonly string[]>(values: T, raw: string, key: string): T[number] {
|
|
123
|
-
if (!(values as readonly string[]).includes(raw)) {
|
|
124
|
-
throw new Error(`--${key} must be one of: ${values.join(', ')}`);
|
|
125
|
-
}
|
|
126
|
-
return raw as T[number];
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
function optionalBoolean(flags: Record<string, string | boolean>, key: string): boolean | undefined {
|
|
130
|
-
const value = flags[key];
|
|
131
|
-
if (value === undefined) return undefined;
|
|
132
|
-
if (value === true) return true;
|
|
133
|
-
if (value === 'true') return true;
|
|
134
|
-
if (value === 'false') return false;
|
|
135
|
-
throw new Error(`--${key} must be true or false`);
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
function renderStoreSummary(summary: MemoryStoreSummary): string {
|
|
139
|
-
return [
|
|
140
|
-
`store: ${summary.store.store_id}`,
|
|
141
|
-
`scope: ${summary.store.scope}`,
|
|
142
|
-
`access: ${summary.store.access}`,
|
|
143
|
-
`mount_mode: ${summary.store.mount_mode}`,
|
|
144
|
-
`write_policy: ${summary.store.write_policy}`,
|
|
145
|
-
`evidence_required: ${String(summary.store.evidence_required)}`,
|
|
146
|
-
`candidate_entries: ${summary.counts.candidate_entries}`,
|
|
147
|
-
`rollups: ${summary.counts.rollups}`,
|
|
148
|
-
`agent_can_write_canonical_memory: ${String(summary.store.authority_boundary.agent_can_write_canonical_memory)}`,
|
|
149
|
-
].join('\n');
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
function renderStoreList(summaries: MemoryStoreSummary[]): string {
|
|
153
|
-
if (summaries.length === 0) return 'memory_stores: none\n';
|
|
154
|
-
return `${summaries.map(renderStoreSummary).join('\n---\n')}\n`;
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
function renderMemoryCapabilityStatus(status: MemoryCapabilityStatus): string {
|
|
158
|
-
return [
|
|
159
|
-
'memory_capability_status:',
|
|
160
|
-
` schema: ${status.schema}`,
|
|
161
|
-
` module_status: ${status.module_status}`,
|
|
162
|
-
` full_feature_parity_claimed: ${String(status.parity_posture.full_feature_parity_claimed)}`,
|
|
163
|
-
` managed_runtime_filesystem_memory: ${status.parity_posture.managed_runtime_filesystem_memory}`,
|
|
164
|
-
` mem0_style_semantic_memory: ${status.parity_posture.mem0_style_semantic_memory}`,
|
|
165
|
-
` approved_file_count: ${status.evidence_sources.approved_file_count}`,
|
|
166
|
-
` recall_capsules: ${status.recall_index.stats.recall_capsules}`,
|
|
167
|
-
` memory_candidates: ${status.recall_index.stats.candidates.total}`,
|
|
168
|
-
` rejected_candidates: ${status.recall_index.stats.candidates.rejected}`,
|
|
169
|
-
` search_adapter: ${status.recall_index.search_adapter}`,
|
|
170
|
-
` vector_adapter: ${status.recall_index.vector_adapter}`,
|
|
171
|
-
` store_count: ${status.store_lifecycle.store_count}`,
|
|
172
|
-
` store_candidate_entries: ${status.store_lifecycle.candidate_entries}`,
|
|
173
|
-
` rollups: ${status.store_lifecycle.rollups}`,
|
|
174
|
-
` drain_import_receipts: ${status.remote_writeback.drain_import_receipts}`,
|
|
175
|
-
` memory_can_authorize_work: ${String(status.authority_boundary.memory_can_authorize_work)}`,
|
|
176
|
-
` memory_can_mutate_ledger: ${String(status.authority_boundary.memory_can_mutate_ledger)}`,
|
|
177
|
-
` memory_is_execution_truth: ${String(status.authority_boundary.memory_is_execution_truth)}`,
|
|
178
|
-
` marination_is_same_primitive: ${String(status.consolidation.marination_is_same_primitive)}`,
|
|
179
|
-
` missing_for_full_parity: ${status.missing_for_full_parity.join(', ')}`,
|
|
180
|
-
].join('\n') + '\n';
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
function parseShardSpecs(raw: string | boolean | undefined): Array<{ shardId: string; sourceProjectRoot: string }> {
|
|
184
|
-
const specs = parseList(raw);
|
|
185
|
-
if (specs.length === 0) throw new Error('--shard must include at least one id=path entry');
|
|
186
|
-
return specs.map((spec) => {
|
|
187
|
-
const index = spec.indexOf('=');
|
|
188
|
-
if (index <= 0 || index === spec.length - 1) {
|
|
189
|
-
throw new Error('--shard entries must use id=path');
|
|
190
|
-
}
|
|
191
|
-
const sourceProjectRoot = spec.slice(index + 1).trim();
|
|
192
|
-
if (sourceProjectRoot.length === 0) throw new Error('--shard entries must use id=path');
|
|
193
|
-
return {
|
|
194
|
-
shardId: spec.slice(0, index).trim(),
|
|
195
|
-
sourceProjectRoot: resolve(sourceProjectRoot),
|
|
196
|
-
};
|
|
197
|
-
});
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
export async function dispatchMemory(
|
|
201
|
-
positionals: string[],
|
|
202
|
-
flags: Record<string, string | boolean>,
|
|
203
|
-
): Promise<void> {
|
|
204
|
-
const verb = positionals[1];
|
|
205
|
-
if (!verb || !MEMORY_VERBS.has(verb)) {
|
|
206
|
-
throw new Error(`memory verb must be one of: ${[...MEMORY_VERBS].join(', ')}`);
|
|
207
|
-
}
|
|
208
|
-
const projectRoot = resolve(optionalString(flags, 'project') ?? process.cwd());
|
|
209
|
-
const dbPath = optionalString(flags, 'db');
|
|
210
|
-
const json = Boolean(flags.json);
|
|
211
|
-
|
|
212
|
-
if (verb === 'index') {
|
|
213
|
-
const requestedExport = flags.export;
|
|
214
|
-
const exportDir = requestedExport === true
|
|
215
|
-
? defaultMemoryExportDir(projectRoot, optionalString(flags, 'workspace-id'))
|
|
216
|
-
: optionalString(flags, 'export');
|
|
217
|
-
const localPrivate = Boolean(flags['local-private']);
|
|
218
|
-
if (localPrivate && !json) {
|
|
219
|
-
console.error([
|
|
220
|
-
'WARNING: --local-private bypasses only the private-context promotion guard.',
|
|
221
|
-
'Local-private capsules stay local and must not be shared, exported, or used as authority.',
|
|
222
|
-
].join('\n'));
|
|
223
|
-
}
|
|
224
|
-
const result = await indexMemory({
|
|
225
|
-
projectRoot,
|
|
226
|
-
dbPath,
|
|
227
|
-
exportDir,
|
|
228
|
-
localPrivate,
|
|
229
|
-
orgId: optionalString(flags, 'org-id'),
|
|
230
|
-
workspaceId: optionalString(flags, 'workspace-id'),
|
|
231
|
-
confirmSharedExport: Boolean(flags['confirm-shared-export']),
|
|
232
|
-
});
|
|
233
|
-
console.log(json ? JSON.stringify(result, null, 2) : [
|
|
234
|
-
'memory_index:',
|
|
235
|
-
` candidates: ${result.candidates}`,
|
|
236
|
-
` promoted: ${result.promoted}`,
|
|
237
|
-
` rejected: ${result.rejected}`,
|
|
238
|
-
].join('\n'));
|
|
239
|
-
return;
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
if (verb === 'status') {
|
|
243
|
-
const storesRoot = optionalString(flags, 'root') ? resolve(requireString(flags, 'root')) : undefined;
|
|
244
|
-
const status = await memoryCapabilityStatus({ projectRoot, dbPath, storesRoot });
|
|
245
|
-
console.log(json ? JSON.stringify(status, null, 2) : renderMemoryCapabilityStatus(status));
|
|
246
|
-
return;
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
if (verb === 'store') {
|
|
250
|
-
const subverb = positionals[2];
|
|
251
|
-
if (!subverb || !['init', 'list', 'show', 'add'].includes(subverb)) {
|
|
252
|
-
throw new Error('memory store verb must be one of: init, list, show, add');
|
|
253
|
-
}
|
|
254
|
-
const storesRoot = optionalString(flags, 'root') ? resolve(requireString(flags, 'root')) : undefined;
|
|
255
|
-
if (subverb === 'init') {
|
|
256
|
-
const access = enumValue(
|
|
257
|
-
WORKSPACE_MEMORY_ACCESS,
|
|
258
|
-
requireString(flags, 'access'),
|
|
259
|
-
'access',
|
|
260
|
-
) as WorkspaceMemoryAccess;
|
|
261
|
-
const result = await initMemoryStore({
|
|
262
|
-
projectRoot,
|
|
263
|
-
storesRoot,
|
|
264
|
-
storeId: requireString(flags, 'store'),
|
|
265
|
-
scope: enumValue(WORKSPACE_MEMORY_SCOPES, requireString(flags, 'scope'), 'scope') as WorkspaceMemoryScope,
|
|
266
|
-
access,
|
|
267
|
-
mountMode: optionalString(flags, 'mount-mode')
|
|
268
|
-
? enumValue(WORKSPACE_MEMORY_MOUNT_MODES, requireString(flags, 'mount-mode'), 'mount-mode') as WorkspaceMemoryMountMode
|
|
269
|
-
: undefined,
|
|
270
|
-
writePolicy: optionalString(flags, 'write-policy')
|
|
271
|
-
? enumValue(WORKSPACE_MEMORY_WRITE_POLICIES, requireString(flags, 'write-policy'), 'write-policy') as WorkspaceMemoryWritePolicy
|
|
272
|
-
: undefined,
|
|
273
|
-
evidenceRequired: optionalBoolean(flags, 'evidence-required'),
|
|
274
|
-
at: optionalString(flags, 'at'),
|
|
275
|
-
});
|
|
276
|
-
console.log(json ? JSON.stringify(result, null, 2) : [
|
|
277
|
-
'memory_store_init:',
|
|
278
|
-
` store_id: ${result.store_id}`,
|
|
279
|
-
` scope: ${result.scope}`,
|
|
280
|
-
` access: ${result.access}`,
|
|
281
|
-
` write_policy: ${result.write_policy}`,
|
|
282
|
-
` agent_can_write_canonical_memory: ${String(result.authority_boundary.agent_can_write_canonical_memory)}`,
|
|
283
|
-
].join('\n'));
|
|
284
|
-
return;
|
|
285
|
-
}
|
|
286
|
-
if (subverb === 'list') {
|
|
287
|
-
const summaries = await listMemoryStores({ projectRoot, storesRoot });
|
|
288
|
-
console.log(json ? JSON.stringify(summaries, null, 2) : renderStoreList(summaries));
|
|
289
|
-
return;
|
|
290
|
-
}
|
|
291
|
-
if (subverb === 'show') {
|
|
292
|
-
const summary = await showMemoryStore({ projectRoot, storesRoot, storeId: requireString(flags, 'store') });
|
|
293
|
-
console.log(json ? JSON.stringify(summary, null, 2) : `${renderStoreSummary(summary)}\n`);
|
|
294
|
-
return;
|
|
295
|
-
}
|
|
296
|
-
const entry = await addMemoryStoreCandidate({
|
|
297
|
-
projectRoot,
|
|
298
|
-
storesRoot,
|
|
299
|
-
storeId: requireString(flags, 'store'),
|
|
300
|
-
path: requireString(flags, 'path'),
|
|
301
|
-
content: requireString(flags, 'content'),
|
|
302
|
-
evidenceRefs: parseEvidenceRefs(requireString(flags, 'evidence')),
|
|
303
|
-
at: optionalString(flags, 'at'),
|
|
304
|
-
});
|
|
305
|
-
console.log(json ? JSON.stringify(entry, null, 2) : [
|
|
306
|
-
'memory_store_candidate:',
|
|
307
|
-
` entry_id: ${entry.entry_id}`,
|
|
308
|
-
` store_id: ${entry.store_id}`,
|
|
309
|
-
` path: ${entry.path}`,
|
|
310
|
-
` content_ref: ${entry.content_ref}`,
|
|
311
|
-
` evidence_refs: ${entry.evidence_refs.map((ref) => `${ref.type}:${ref.ref}`).join(', ')}`,
|
|
312
|
-
` agent_wrote_canonical_memory: ${String(entry.authority_boundary.agent_wrote_canonical_memory)}`,
|
|
313
|
-
].join('\n'));
|
|
314
|
-
return;
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
if (verb === 'consolidate') {
|
|
318
|
-
const storesRoot = optionalString(flags, 'root') ? resolve(requireString(flags, 'root')) : undefined;
|
|
319
|
-
const rollup = await consolidateMemoryStores({
|
|
320
|
-
projectRoot,
|
|
321
|
-
storesRoot,
|
|
322
|
-
inputStores: parseList(flags.input),
|
|
323
|
-
outputStore: requireString(flags, 'out'),
|
|
324
|
-
at: optionalString(flags, 'at'),
|
|
325
|
-
});
|
|
326
|
-
console.log(json ? JSON.stringify(rollup, null, 2) : [
|
|
327
|
-
'memory_consolidation_rollup:',
|
|
328
|
-
` rollup_id: ${rollup.rollup_id}`,
|
|
329
|
-
` input_stores: ${rollup.input_stores.join(', ')}`,
|
|
330
|
-
` output_store: ${rollup.output_store}`,
|
|
331
|
-
` candidate_count: ${rollup.candidate_count}`,
|
|
332
|
-
` output_policy: ${rollup.output_policy}`,
|
|
333
|
-
` mutates_input_store: ${String(rollup.authority_boundary.mutates_input_store)}`,
|
|
334
|
-
` promotes_without_curator: ${String(rollup.authority_boundary.promotes_without_curator)}`,
|
|
335
|
-
].join('\n'));
|
|
336
|
-
return;
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
if (verb === 'drain-import') {
|
|
340
|
-
const receipt = await drainImportMemoryCandidates({
|
|
341
|
-
sourceProjectRoot: resolve(requireString(flags, 'from-project')),
|
|
342
|
-
targetProjectRoot: projectRoot,
|
|
343
|
-
sourceStoresRoot: optionalString(flags, 'from-root') ? resolve(requireString(flags, 'from-root')) : undefined,
|
|
344
|
-
targetStoresRoot: optionalString(flags, 'to-root') ? resolve(requireString(flags, 'to-root')) : undefined,
|
|
345
|
-
sourceStoreId: requireString(flags, 'from-store'),
|
|
346
|
-
targetStoreId: requireString(flags, 'to-store'),
|
|
347
|
-
sourceWorkspaceRef: optionalString(flags, 'source-ref'),
|
|
348
|
-
targetWorkspaceRef: optionalString(flags, 'target-ref'),
|
|
349
|
-
pathPrefix: optionalString(flags, 'path-prefix'),
|
|
350
|
-
receiptPath: optionalString(flags, 'receipt') ? resolve(requireString(flags, 'receipt')) : undefined,
|
|
351
|
-
at: optionalString(flags, 'at'),
|
|
352
|
-
});
|
|
353
|
-
console.log(json ? JSON.stringify(receipt, null, 2) : [
|
|
354
|
-
'memory_drain_import:',
|
|
355
|
-
` receipt_id: ${receipt.receipt_id}`,
|
|
356
|
-
` source: ${receipt.source.workspace_ref}/${receipt.source.store_id}`,
|
|
357
|
-
` target: ${receipt.target.workspace_ref}/${receipt.target.store_id}`,
|
|
358
|
-
` imported_count: ${receipt.target.imported_count}`,
|
|
359
|
-
` drain_can_write_parent_ledger: ${String(receipt.authority_boundary.drain_can_write_parent_ledger)}`,
|
|
360
|
-
` imported_entries_are_candidates: ${String(receipt.authority_boundary.imported_entries_are_candidates)}`,
|
|
361
|
-
` source_store_mutated: ${String(receipt.authority_boundary.source_store_mutated)}`,
|
|
362
|
-
].join('\n'));
|
|
363
|
-
return;
|
|
364
|
-
}
|
|
365
|
-
|
|
366
|
-
if (verb === 'sharded-drain-import') {
|
|
367
|
-
const receipt = await shardedDrainImportMemoryCandidates({
|
|
368
|
-
targetProjectRoot: projectRoot,
|
|
369
|
-
sourceStoreId: requireString(flags, 'from-store'),
|
|
370
|
-
targetStoreId: requireString(flags, 'to-store'),
|
|
371
|
-
shards: parseShardSpecs(flags.shard),
|
|
372
|
-
sourceStoresRoot: optionalString(flags, 'from-root') ? resolve(requireString(flags, 'from-root')) : undefined,
|
|
373
|
-
targetStoresRoot: optionalString(flags, 'to-root') ? resolve(requireString(flags, 'to-root')) : undefined,
|
|
374
|
-
targetWorkspaceRef: optionalString(flags, 'target-ref'),
|
|
375
|
-
receiptDir: optionalString(flags, 'receipt-dir'),
|
|
376
|
-
receiptPath: optionalString(flags, 'receipt') ? resolve(requireString(flags, 'receipt')) : undefined,
|
|
377
|
-
at: optionalString(flags, 'at'),
|
|
378
|
-
});
|
|
379
|
-
console.log(json ? JSON.stringify(receipt, null, 2) : [
|
|
380
|
-
'memory_sharded_drain_import:',
|
|
381
|
-
` receipt_id: ${receipt.receipt_id}`,
|
|
382
|
-
` drain_topology: ${receipt.topology.drain_topology}`,
|
|
383
|
-
` shard_key: ${receipt.topology.shard_key}`,
|
|
384
|
-
` shard_count: ${receipt.topology.shard_count}`,
|
|
385
|
-
` imported_count: ${receipt.totals.imported_count}`,
|
|
386
|
-
` promotion_gate_required: ${String(receipt.authority_boundary.promotion_gate_required)}`,
|
|
387
|
-
` sharded_drain_can_write_parent_ledger: ${String(receipt.authority_boundary.sharded_drain_can_write_parent_ledger)}`,
|
|
388
|
-
` candidate_import_is_canonical_truth: ${String(receipt.authority_boundary.candidate_import_is_canonical_truth)}`,
|
|
389
|
-
].join('\n'));
|
|
390
|
-
return;
|
|
391
|
-
}
|
|
392
|
-
|
|
393
|
-
if (verb === 'search') {
|
|
394
|
-
const query = positionals.slice(2).join(' ').trim();
|
|
395
|
-
if (!query) throw new Error('<query> is required');
|
|
396
|
-
const items = searchMemory({ projectRoot, dbPath, query, limit: asLimit(flags.limit, 10) });
|
|
397
|
-
console.log(json ? JSON.stringify(items, null, 2) : renderCompact(items));
|
|
398
|
-
return;
|
|
399
|
-
}
|
|
400
|
-
|
|
401
|
-
if (verb === 'show') {
|
|
402
|
-
const capsuleId = positionals[2];
|
|
403
|
-
if (!capsuleId) throw new Error('<capsule_id> is required');
|
|
404
|
-
const capsule = showMemory({ projectRoot, dbPath, capsuleId });
|
|
405
|
-
if (!capsule) throw new Error(`unknown capsule: ${capsuleId}`);
|
|
406
|
-
console.log(JSON.stringify(capsule, null, 2));
|
|
407
|
-
return;
|
|
408
|
-
}
|
|
409
|
-
|
|
410
|
-
if (verb === 'preflight') {
|
|
411
|
-
const topic = positionals.slice(2).join(' ').trim();
|
|
412
|
-
if (!topic) throw new Error('<lane-or-task> is required');
|
|
413
|
-
const items = preflightMemory({ projectRoot, dbPath, topic, limit: asLimit(flags.limit, 5) });
|
|
414
|
-
console.log(json ? JSON.stringify(items, null, 2) : renderCompact(items));
|
|
415
|
-
return;
|
|
416
|
-
}
|
|
417
|
-
|
|
418
|
-
if (verb === 'context') {
|
|
419
|
-
const positionalQuery = positionals.slice(2).join(' ').trim();
|
|
420
|
-
const query = optionalString(flags, 'query') ?? (positionalQuery || undefined);
|
|
421
|
-
const context = buildMemoryContext({
|
|
422
|
-
projectRoot,
|
|
423
|
-
dbPath,
|
|
424
|
-
query,
|
|
425
|
-
laneRef: optionalString(flags, 'lane'),
|
|
426
|
-
taskRef: optionalString(flags, 'task'),
|
|
427
|
-
orgId: optionalString(flags, 'org-id'),
|
|
428
|
-
workspaceId: optionalString(flags, 'workspace-id'),
|
|
429
|
-
limit: asLimit(flags.limit, 5),
|
|
430
|
-
});
|
|
431
|
-
console.log(json ? JSON.stringify(context, null, 2) : renderContext(context));
|
|
432
|
-
return;
|
|
433
|
-
}
|
|
434
|
-
|
|
435
|
-
if (verb === 'stale') {
|
|
436
|
-
const items = staleMemory({ projectRoot, dbPath, limit: asLimit(flags.limit, 10) });
|
|
437
|
-
console.log(json ? JSON.stringify(items, null, 2) : renderCompact(items));
|
|
438
|
-
return;
|
|
439
|
-
}
|
|
440
|
-
|
|
441
|
-
if (verb === 'rejected') {
|
|
442
|
-
const items = rejectedMemory({ projectRoot, dbPath, limit: asLimit(flags.limit, 10) });
|
|
443
|
-
console.log(json ? JSON.stringify(items, null, 2) : renderRejected(items));
|
|
444
|
-
}
|
|
445
|
-
}
|
|
@@ -1,108 +0,0 @@
|
|
|
1
|
-
import { resolve } from 'node:path';
|
|
2
|
-
import { optionalString } from '../argv';
|
|
3
|
-
import {
|
|
4
|
-
buildReleaseGaReadinessReport,
|
|
5
|
-
buildReleaseReadinessReport,
|
|
6
|
-
listReleaseDistributionChannels,
|
|
7
|
-
type ReleaseDistributionChannel,
|
|
8
|
-
type ReleaseGaReadinessReport,
|
|
9
|
-
type ReleaseReadinessReport,
|
|
10
|
-
} from '../../release/readiness';
|
|
11
|
-
|
|
12
|
-
const RELEASE_VERBS = new Set(['readiness', 'ga-readiness', 'channels']);
|
|
13
|
-
|
|
14
|
-
export function isReleaseCommand(command: string): boolean {
|
|
15
|
-
return command === 'release';
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
function renderReadiness(report: ReleaseReadinessReport): string {
|
|
19
|
-
const lines = [
|
|
20
|
-
'release_readiness:',
|
|
21
|
-
` schema: ${report.schema}`,
|
|
22
|
-
` verdict: ${report.verdict}`,
|
|
23
|
-
` package: ${report.package.name ?? 'unknown'}@${report.package.version ?? 'unknown'}`,
|
|
24
|
-
` private: ${String(report.package.private)}`,
|
|
25
|
-
` codex_recommended_minimum: ${report.client_compatibility.codex_recommended_minimum}`,
|
|
26
|
-
` core_release_requires_codex: ${String(report.client_compatibility.core_release_requires_codex)}`,
|
|
27
|
-
` blockers: ${report.blockers.join(', ') || 'none'}`,
|
|
28
|
-
` warnings: ${report.warnings.join(', ') || 'none'}`,
|
|
29
|
-
` command_can_publish: ${String(report.authority_boundary.command_can_publish)}`,
|
|
30
|
-
` command_can_flip_private: ${String(report.authority_boundary.command_can_flip_private)}`,
|
|
31
|
-
` command_can_create_distribution_channel: ${String(report.authority_boundary.command_can_create_distribution_channel)}`,
|
|
32
|
-
];
|
|
33
|
-
for (const item of report.checks) {
|
|
34
|
-
lines.push(` - ${item.id}: ${item.status} (${item.summary})`);
|
|
35
|
-
if (item.next_action) lines.push(` next: ${item.next_action}`);
|
|
36
|
-
}
|
|
37
|
-
return `${lines.join('\n')}\n`;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
function renderGaReadiness(report: ReleaseGaReadinessReport): string {
|
|
41
|
-
const lines = [
|
|
42
|
-
'release_ga_readiness:',
|
|
43
|
-
` schema: ${report.schema}`,
|
|
44
|
-
` verdict: ${report.verdict}`,
|
|
45
|
-
` channel: ${report.channel ?? 'missing'}`,
|
|
46
|
-
` tag: ${report.tag ?? 'unknown'}`,
|
|
47
|
-
` channels: ${report.channels.map((item) => `${item.id}(${item.kind})`).join(', ') || 'none'}`,
|
|
48
|
-
` package_readiness: ${report.package_readiness}`,
|
|
49
|
-
` blockers: ${report.blockers.join(', ') || 'none'}`,
|
|
50
|
-
` warnings: ${report.warnings.join(', ') || 'none'}`,
|
|
51
|
-
` command_can_publish: ${String(report.authority_boundary.command_can_publish)}`,
|
|
52
|
-
` command_can_sign: ${String(report.authority_boundary.command_can_sign)}`,
|
|
53
|
-
` command_can_tag: ${String(report.authority_boundary.command_can_tag)}`,
|
|
54
|
-
` command_can_create_distribution_channel: ${String(report.authority_boundary.command_can_create_distribution_channel)}`,
|
|
55
|
-
];
|
|
56
|
-
for (const item of report.checks) {
|
|
57
|
-
lines.push(` - ${item.id}: ${item.status} (${item.summary})`);
|
|
58
|
-
if (item.next_action) lines.push(` next: ${item.next_action}`);
|
|
59
|
-
}
|
|
60
|
-
return `${lines.join('\n')}\n`;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
function renderChannels(channels: ReleaseDistributionChannel[]): string {
|
|
64
|
-
const lines = ['release_channels:'];
|
|
65
|
-
for (const item of channels) {
|
|
66
|
-
lines.push(` - ${item.id}: ${item.kind}`);
|
|
67
|
-
lines.push(` label: ${item.label}`);
|
|
68
|
-
lines.push(` private_repo_compatible: ${String(item.private_repo_compatible)}`);
|
|
69
|
-
lines.push(` artifact: ${item.artifact}`);
|
|
70
|
-
}
|
|
71
|
-
return `${lines.join('\n')}\n`;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
export async function dispatchRelease(
|
|
75
|
-
positionals: string[],
|
|
76
|
-
flags: Record<string, string | boolean>,
|
|
77
|
-
): Promise<void> {
|
|
78
|
-
const verb = positionals[1];
|
|
79
|
-
if (!verb || !RELEASE_VERBS.has(verb)) {
|
|
80
|
-
throw new Error(`release verb must be one of: ${[...RELEASE_VERBS].join(', ')}`);
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
const projectRoot = resolve(optionalString(flags, 'project') ?? process.cwd());
|
|
84
|
-
if (verb === 'channels') {
|
|
85
|
-
const channels = listReleaseDistributionChannels();
|
|
86
|
-
console.log(Boolean(flags.json) ? JSON.stringify({ schema: 'release-channels.v0', channels }, null, 2) : renderChannels(channels));
|
|
87
|
-
return;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
if (verb === 'readiness') {
|
|
91
|
-
const report = await buildReleaseReadinessReport(projectRoot);
|
|
92
|
-
console.log(Boolean(flags.json) ? JSON.stringify(report, null, 2) : renderReadiness(report));
|
|
93
|
-
if (flags['fail-on-blocked'] && report.verdict === 'blocked') {
|
|
94
|
-
process.exit(1);
|
|
95
|
-
}
|
|
96
|
-
return;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
const report = await buildReleaseGaReadinessReport(projectRoot, {
|
|
100
|
-
channel: optionalString(flags, 'channel'),
|
|
101
|
-
tagFreeConfirmed: Boolean(flags['tag-free-confirmed']),
|
|
102
|
-
verifyTagRemote: optionalString(flags, 'verify-tag-remote'),
|
|
103
|
-
});
|
|
104
|
-
console.log(Boolean(flags.json) ? JSON.stringify(report, null, 2) : renderGaReadiness(report));
|
|
105
|
-
if (flags['fail-on-blocked'] && report.verdict === 'blocked') {
|
|
106
|
-
process.exit(1);
|
|
107
|
-
}
|
|
108
|
-
}
|
|
@@ -1,103 +0,0 @@
|
|
|
1
|
-
import { resolve } from 'node:path';
|
|
2
|
-
import { optionalString, requireString } from '../argv';
|
|
3
|
-
import {
|
|
4
|
-
loadFixtureSet,
|
|
5
|
-
loadPromotionPolicy,
|
|
6
|
-
loadRubric,
|
|
7
|
-
loadSandboxReceipt,
|
|
8
|
-
} from '../../rubric/loader';
|
|
9
|
-
import { runRubricSandbox } from '../../rubric/runner';
|
|
10
|
-
import { evaluatePromotionReadiness } from '../../rubric/promotion';
|
|
11
|
-
import { RUN_ENVIRONMENTS, type RunEnvironment } from '../../rubric/types';
|
|
12
|
-
|
|
13
|
-
const RUBRIC_VERBS = new Set(['validate', 'sandbox', 'promote-check']);
|
|
14
|
-
|
|
15
|
-
export function isRubricCommand(command: string): boolean {
|
|
16
|
-
return command === 'rubric';
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
function parseRunEnvironment(raw: string | boolean | undefined): RunEnvironment {
|
|
20
|
-
if (raw === undefined) return 'local';
|
|
21
|
-
if (typeof raw !== 'string' || !(RUN_ENVIRONMENTS as readonly string[]).includes(raw)) {
|
|
22
|
-
throw new Error(`--environment must be one of: ${RUN_ENVIRONMENTS.join(', ')}`);
|
|
23
|
-
}
|
|
24
|
-
return raw as RunEnvironment;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
function renderValidate(rubric: Awaited<ReturnType<typeof loadRubric>>): string {
|
|
28
|
-
return [
|
|
29
|
-
'rubric_validate:',
|
|
30
|
-
` rubric_id: ${rubric.rubric_id}`,
|
|
31
|
-
` rubric_version: ${rubric.rubric_version}`,
|
|
32
|
-
` kind: ${rubric.kind}`,
|
|
33
|
-
` status: ${rubric.status}`,
|
|
34
|
-
].join('\n');
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
function renderSandbox(receipt: Awaited<ReturnType<typeof runRubricSandbox>>): string {
|
|
38
|
-
return [
|
|
39
|
-
'rubric_sandbox:',
|
|
40
|
-
` receipt_id: ${receipt.receipt_id}`,
|
|
41
|
-
` rubric_id: ${receipt.rubric_id}`,
|
|
42
|
-
` total_fixtures: ${receipt.summary.total_fixtures}`,
|
|
43
|
-
` known_bad_rejected: ${receipt.summary.known_bad_rejected}`,
|
|
44
|
-
` known_good_accepted: ${receipt.summary.known_good_accepted}`,
|
|
45
|
-
` unexpected_outcomes: ${receipt.summary.unexpected_outcomes}`,
|
|
46
|
-
].join('\n');
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
function renderPromotion(result: Awaited<ReturnType<typeof evaluatePromotionReadiness>>): string {
|
|
50
|
-
return [
|
|
51
|
-
'rubric_promotion_check:',
|
|
52
|
-
` rubric_id: ${result.rubric_id}`,
|
|
53
|
-
` recommendation: ${result.recommendation}`,
|
|
54
|
-
` missing: ${result.missing.join(', ') || 'none'}`,
|
|
55
|
-
` can_activate_rubric: ${String(result.authority_boundary.can_activate_rubric)}`,
|
|
56
|
-
].join('\n');
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
export async function dispatchRubric(
|
|
60
|
-
positionals: string[],
|
|
61
|
-
flags: Record<string, string | boolean>,
|
|
62
|
-
): Promise<void> {
|
|
63
|
-
const verb = positionals[1];
|
|
64
|
-
if (!verb || !RUBRIC_VERBS.has(verb)) {
|
|
65
|
-
throw new Error(`rubric verb must be one of: ${[...RUBRIC_VERBS].join(', ')}`);
|
|
66
|
-
}
|
|
67
|
-
const json = Boolean(flags.json);
|
|
68
|
-
|
|
69
|
-
if (verb === 'validate') {
|
|
70
|
-
const rubric = await loadRubric(resolve(requireString(flags, 'rubric')));
|
|
71
|
-
console.log(json ? JSON.stringify(rubric, null, 2) : renderValidate(rubric));
|
|
72
|
-
return;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
if (verb === 'sandbox') {
|
|
76
|
-
const rubric = await loadRubric(resolve(requireString(flags, 'rubric')));
|
|
77
|
-
const fixtureSet = await loadFixtureSet(resolve(requireString(flags, 'fixtures')));
|
|
78
|
-
const receipt = await runRubricSandbox({
|
|
79
|
-
rubric,
|
|
80
|
-
fixtureSet,
|
|
81
|
-
runBy: requireString(flags, 'run-by'),
|
|
82
|
-
runEnvironment: parseRunEnvironment(flags.environment),
|
|
83
|
-
runAt: optionalString(flags, 'at'),
|
|
84
|
-
receiptPath: optionalString(flags, 'receipt') ? resolve(requireString(flags, 'receipt')) : undefined,
|
|
85
|
-
});
|
|
86
|
-
console.log(json ? JSON.stringify(receipt, null, 2) : renderSandbox(receipt));
|
|
87
|
-
return;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
if (verb === 'promote-check') {
|
|
91
|
-
const rubric = await loadRubric(resolve(requireString(flags, 'rubric')));
|
|
92
|
-
const receipt = await loadSandboxReceipt(resolve(requireString(flags, 'receipt')));
|
|
93
|
-
const policyPath = optionalString(flags, 'policy');
|
|
94
|
-
const policy = policyPath ? await loadPromotionPolicy(resolve(policyPath)) : undefined;
|
|
95
|
-
const result = evaluatePromotionReadiness({
|
|
96
|
-
rubric,
|
|
97
|
-
receipt,
|
|
98
|
-
policy,
|
|
99
|
-
grantRef: optionalString(flags, 'grant-ref'),
|
|
100
|
-
});
|
|
101
|
-
console.log(json ? JSON.stringify(result, null, 2) : renderPromotion(result));
|
|
102
|
-
}
|
|
103
|
-
}
|