instar 1.3.320 → 1.3.322
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/cli.js +24 -0
- package/dist/cli.js.map +1 -1
- package/dist/commands/intent.d.ts.map +1 -1
- package/dist/commands/intent.js +17 -0
- package/dist/commands/intent.js.map +1 -1
- package/dist/commands/postDriveTranscriptAudit.d.ts +93 -0
- package/dist/commands/postDriveTranscriptAudit.d.ts.map +1 -0
- package/dist/commands/postDriveTranscriptAudit.js +290 -0
- package/dist/commands/postDriveTranscriptAudit.js.map +1 -0
- package/dist/core/IntentTestHarness.d.ts +58 -0
- package/dist/core/IntentTestHarness.d.ts.map +1 -0
- package/dist/core/IntentTestHarness.js +119 -0
- package/dist/core/IntentTestHarness.js.map +1 -0
- package/dist/core/OrgIntentIdentityLayer.d.ts +37 -0
- package/dist/core/OrgIntentIdentityLayer.d.ts.map +1 -0
- package/dist/core/OrgIntentIdentityLayer.js +125 -0
- package/dist/core/OrgIntentIdentityLayer.js.map +1 -0
- package/dist/core/OrgIntentManager.d.ts +3 -0
- package/dist/core/OrgIntentManager.d.ts.map +1 -1
- package/dist/core/OrgIntentManager.js +4 -2
- package/dist/core/OrgIntentManager.js.map +1 -1
- package/dist/core/PostUpdateMigrator.d.ts.map +1 -1
- package/dist/core/PostUpdateMigrator.js +20 -0
- package/dist/core/PostUpdateMigrator.js.map +1 -1
- package/dist/monitoring/FrameworkIssueLedger.d.ts.map +1 -1
- package/dist/monitoring/FrameworkIssueLedger.js +5 -3
- package/dist/monitoring/FrameworkIssueLedger.js.map +1 -1
- package/dist/scaffold/templates.d.ts.map +1 -1
- package/dist/scaffold/templates.js +5 -0
- package/dist/scaffold/templates.js.map +1 -1
- package/dist/server/routes.d.ts.map +1 -1
- package/dist/server/routes.js +38 -0
- package/dist/server/routes.js.map +1 -1
- package/package.json +1 -1
- package/src/data/builtin-manifest.json +95 -95
- package/src/scaffold/templates.ts +5 -0
- package/upgrades/1.3.321.md +25 -0
- package/upgrades/1.3.322.md +56 -0
- package/upgrades/side-effects/exo3-g1-ci-greening.md +42 -0
- package/upgrades/side-effects/post-drive-transcript-audit.md +64 -0
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import type { IssueBucket, IssueSeverity } from '../monitoring/FrameworkIssueLedger.js';
|
|
2
|
+
export type TranscriptUxCategory = 'duplicate-notices-deliveries' | 'asks-of-user' | 'infra-noise' | 'content-free-updates';
|
|
3
|
+
export interface TranscriptMessage {
|
|
4
|
+
messageId: number | string;
|
|
5
|
+
topicId?: number | null;
|
|
6
|
+
channelId?: number | string | null;
|
|
7
|
+
text: string;
|
|
8
|
+
fromUser: boolean;
|
|
9
|
+
timestamp: string;
|
|
10
|
+
sessionName?: string | null;
|
|
11
|
+
senderName?: string;
|
|
12
|
+
senderUsername?: string;
|
|
13
|
+
}
|
|
14
|
+
export interface TranscriptAuditWindow {
|
|
15
|
+
start: string;
|
|
16
|
+
end: string;
|
|
17
|
+
}
|
|
18
|
+
export interface TranscriptUxFinding {
|
|
19
|
+
category: TranscriptUxCategory;
|
|
20
|
+
topicId: number;
|
|
21
|
+
messageIds: Array<number | string>;
|
|
22
|
+
timestamps: string[];
|
|
23
|
+
severity: IssueSeverity;
|
|
24
|
+
title: string;
|
|
25
|
+
reason: string;
|
|
26
|
+
excerpt: string;
|
|
27
|
+
dedupKey: string;
|
|
28
|
+
frameworkIssue: {
|
|
29
|
+
framework: string;
|
|
30
|
+
bucket: IssueBucket;
|
|
31
|
+
severity: IssueSeverity;
|
|
32
|
+
title: string;
|
|
33
|
+
dedupKey: string;
|
|
34
|
+
signature: string;
|
|
35
|
+
evidence: string;
|
|
36
|
+
observedVersion: string;
|
|
37
|
+
relatedSpec: string;
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
export interface TranscriptAuditReport {
|
|
41
|
+
topicIds: number[];
|
|
42
|
+
window: TranscriptAuditWindow;
|
|
43
|
+
generatedAt: string;
|
|
44
|
+
summary: Record<TranscriptUxCategory, number> & {
|
|
45
|
+
total: number;
|
|
46
|
+
};
|
|
47
|
+
findings: TranscriptUxFinding[];
|
|
48
|
+
observations: Array<{
|
|
49
|
+
dedupKey: string;
|
|
50
|
+
filed: boolean;
|
|
51
|
+
created?: boolean;
|
|
52
|
+
episodeRecorded?: boolean;
|
|
53
|
+
issueId?: string;
|
|
54
|
+
error?: string;
|
|
55
|
+
}>;
|
|
56
|
+
}
|
|
57
|
+
export interface TranscriptAuditDeps {
|
|
58
|
+
readTopicHistory(topicId: number, limit: number): Promise<TranscriptMessage[]>;
|
|
59
|
+
observeFinding(input: TranscriptUxFinding['frameworkIssue']): Promise<{
|
|
60
|
+
created?: boolean;
|
|
61
|
+
episodeRecorded?: boolean;
|
|
62
|
+
issueId?: string;
|
|
63
|
+
}>;
|
|
64
|
+
now?: () => Date;
|
|
65
|
+
}
|
|
66
|
+
export interface RunPostDriveTranscriptAuditOptions {
|
|
67
|
+
topicIds: number[];
|
|
68
|
+
start: string;
|
|
69
|
+
end: string;
|
|
70
|
+
limit?: number;
|
|
71
|
+
dryRun?: boolean;
|
|
72
|
+
deps: TranscriptAuditDeps;
|
|
73
|
+
}
|
|
74
|
+
export interface PostDriveTranscriptAuditCliOptions {
|
|
75
|
+
topics?: string[];
|
|
76
|
+
topic?: string[];
|
|
77
|
+
start: string;
|
|
78
|
+
end: string;
|
|
79
|
+
limit?: number;
|
|
80
|
+
baseUrl?: string;
|
|
81
|
+
dir?: string;
|
|
82
|
+
dryRun?: boolean;
|
|
83
|
+
json?: boolean;
|
|
84
|
+
}
|
|
85
|
+
export declare function classifyTranscriptUx(input: {
|
|
86
|
+
topicId: number;
|
|
87
|
+
messages: TranscriptMessage[];
|
|
88
|
+
window: TranscriptAuditWindow;
|
|
89
|
+
observedVersion?: string;
|
|
90
|
+
}): TranscriptUxFinding[];
|
|
91
|
+
export declare function runPostDriveTranscriptAudit(options: RunPostDriveTranscriptAuditOptions): Promise<TranscriptAuditReport>;
|
|
92
|
+
export declare function runPostDriveTranscriptAuditCli(options: PostDriveTranscriptAuditCliOptions): Promise<number>;
|
|
93
|
+
//# sourceMappingURL=postDriveTranscriptAudit.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"postDriveTranscriptAudit.d.ts","sourceRoot":"","sources":["../../src/commands/postDriveTranscriptAudit.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
import crypto from 'node:crypto';
|
|
2
|
+
import pc from 'picocolors';
|
|
3
|
+
import { loadConfig, getInstarVersion } from '../core/Config.js';
|
|
4
|
+
import { DegradationReporter } from '../monitoring/DegradationReporter.js';
|
|
5
|
+
const ZERO_SUMMARY = {
|
|
6
|
+
'duplicate-notices-deliveries': 0,
|
|
7
|
+
'asks-of-user': 0,
|
|
8
|
+
'infra-noise': 0,
|
|
9
|
+
'content-free-updates': 0,
|
|
10
|
+
total: 0,
|
|
11
|
+
};
|
|
12
|
+
const CATEGORY_TITLES = {
|
|
13
|
+
'duplicate-notices-deliveries': 'Post-drive transcript showed duplicate notices or deliveries',
|
|
14
|
+
'asks-of-user': 'Post-drive transcript asked the operator to resend, retry, or re-paste',
|
|
15
|
+
'infra-noise': 'Post-drive transcript surfaced internal infrastructure noise to the operator',
|
|
16
|
+
'content-free-updates': 'Post-drive transcript contained progress updates without usable content',
|
|
17
|
+
};
|
|
18
|
+
const CATEGORY_REASON = {
|
|
19
|
+
'duplicate-notices-deliveries': 'The same operator-visible notice appeared more than once in the audit window.',
|
|
20
|
+
'asks-of-user': 'The assistant shifted recovery work onto the operator by asking for a resend, retry, or re-paste.',
|
|
21
|
+
'infra-noise': 'The assistant exposed queue, restart, process, watchdog, or terminal chatter instead of translating it into user-relevant status.',
|
|
22
|
+
'content-free-updates': 'The assistant sent a progress update that did not contain a concrete state change, artifact, decision, or next action.',
|
|
23
|
+
};
|
|
24
|
+
const RELATED_SPEC = 'Observation Needs Structure (PR #861); UX-blindspot arc / operatorSeatUx gate (PR #856)';
|
|
25
|
+
const DEFAULT_FRAMEWORK = 'codex-cli';
|
|
26
|
+
const ASK_OF_USER_RE = /\b(?:re-?send|send (?:it|that|this|the file|the screenshot) again|try again|retry|re-?paste|paste (?:it|that|this) again|upload (?:it|that|this) again|can you send|could you send|please send).{0,80}\b(?:again|retry|re-?paste|re-?send)?/i;
|
|
27
|
+
const INFRA_NOISE_RE = /\b(?:restart|restarting|queue|queued|sentinel|standby|watchdog|terminal output|child process|pid|daemon|tmux|relaunch|boot loop|stalled|unstick|heartbeat|session respawn|process exited)\b/i;
|
|
28
|
+
const CONTENT_FREE_RE = /\b(?:working on it|still working|still digging|quick update|no terminal output|has not produced terminal output|actively working|continuing to monitor|unchanged|will keep going|keeping an eye on it)\b/i;
|
|
29
|
+
const SECRET_SHAPES = [
|
|
30
|
+
/\b(?:sk|pk|rk)-[A-Za-z0-9]{16,}\b/,
|
|
31
|
+
/\bBearer\s+[A-Za-z0-9._-]{12,}\b/i,
|
|
32
|
+
/\bgh[pousr]_[A-Za-z0-9]{20,}\b/,
|
|
33
|
+
/\beyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\b/,
|
|
34
|
+
];
|
|
35
|
+
function canonicalWindow(start, end) {
|
|
36
|
+
const startMs = Date.parse(start);
|
|
37
|
+
const endMs = Date.parse(end);
|
|
38
|
+
if (!Number.isFinite(startMs))
|
|
39
|
+
throw new Error(`Invalid --start timestamp: ${start}`);
|
|
40
|
+
if (!Number.isFinite(endMs))
|
|
41
|
+
throw new Error(`Invalid --end timestamp: ${end}`);
|
|
42
|
+
if (endMs < startMs)
|
|
43
|
+
throw new Error('--end must be at or after --start');
|
|
44
|
+
return { start: new Date(startMs).toISOString(), end: new Date(endMs).toISOString() };
|
|
45
|
+
}
|
|
46
|
+
function hash(s) {
|
|
47
|
+
return crypto.createHash('sha256').update(s).digest('hex').slice(0, 16);
|
|
48
|
+
}
|
|
49
|
+
function normalizeForDuplicate(s) {
|
|
50
|
+
return s
|
|
51
|
+
.toLowerCase()
|
|
52
|
+
.replace(/\[[^\]]+\]/g, '')
|
|
53
|
+
.replace(/\b\d{1,2}:\d{2}(?::\d{2})?\b/g, '<time>')
|
|
54
|
+
.replace(/\b\d+\b/g, '<n>')
|
|
55
|
+
.replace(/\s+/g, ' ')
|
|
56
|
+
.trim();
|
|
57
|
+
}
|
|
58
|
+
function sanitizeExcerpt(s) {
|
|
59
|
+
const cleaned = s.replace(/[\x00-\x1f\x7f]/g, ' ').replace(/\s+/g, ' ').trim();
|
|
60
|
+
if (SECRET_SHAPES.some((re) => re.test(cleaned)))
|
|
61
|
+
return '[redacted: secret-shaped text]';
|
|
62
|
+
return cleaned.length > 180 ? `${cleaned.slice(0, 177)}...` : cleaned;
|
|
63
|
+
}
|
|
64
|
+
function inWindow(message, window) {
|
|
65
|
+
const ts = Date.parse(message.timestamp);
|
|
66
|
+
return Number.isFinite(ts) && ts >= Date.parse(window.start) && ts <= Date.parse(window.end);
|
|
67
|
+
}
|
|
68
|
+
function isConcreteUpdate(text) {
|
|
69
|
+
return /\b(?:built|implemented|fixed|verified|opened|merged|pushed|committed|test(?:ed|s)?|report|pr #?\d+|artifact|link|blocked by|found|landed)\b/i.test(text);
|
|
70
|
+
}
|
|
71
|
+
function makeFinding(input) {
|
|
72
|
+
const ids = input.messages.map((m) => m.messageId);
|
|
73
|
+
const timestamps = input.messages.map((m) => m.timestamp);
|
|
74
|
+
const evidenceSeed = `${input.category}:${input.topicId}:${input.window.start}:${input.window.end}:${ids.join(',')}:${timestamps.join(',')}`;
|
|
75
|
+
const dedupKey = `post-drive-transcript-audit::${input.category}::topic-${input.topicId}::${hash(evidenceSeed)}`;
|
|
76
|
+
const evidence = `telegram-topic:${input.topicId}:messages:${ids.join(',')}:window:${input.window.start}..${input.window.end}`;
|
|
77
|
+
const excerpt = input.messages.map((m) => sanitizeExcerpt(m.text)).join(' | ');
|
|
78
|
+
const severity = input.category === 'asks-of-user' ? 'high' : 'medium';
|
|
79
|
+
const title = CATEGORY_TITLES[input.category];
|
|
80
|
+
return {
|
|
81
|
+
category: input.category,
|
|
82
|
+
topicId: input.topicId,
|
|
83
|
+
messageIds: ids,
|
|
84
|
+
timestamps,
|
|
85
|
+
severity,
|
|
86
|
+
title,
|
|
87
|
+
reason: CATEGORY_REASON[input.category],
|
|
88
|
+
excerpt,
|
|
89
|
+
dedupKey,
|
|
90
|
+
frameworkIssue: {
|
|
91
|
+
framework: DEFAULT_FRAMEWORK,
|
|
92
|
+
bucket: 'instar-integration-gap',
|
|
93
|
+
severity,
|
|
94
|
+
title,
|
|
95
|
+
dedupKey,
|
|
96
|
+
signature: `${input.category}:${input.topicId}:${hash(excerpt)}`,
|
|
97
|
+
evidence,
|
|
98
|
+
observedVersion: input.observedVersion,
|
|
99
|
+
relatedSpec: RELATED_SPEC,
|
|
100
|
+
},
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
export function classifyTranscriptUx(input) {
|
|
104
|
+
const observedVersion = input.observedVersion ?? getInstarVersion();
|
|
105
|
+
const scoped = input.messages
|
|
106
|
+
.filter((m) => inWindow(m, input.window))
|
|
107
|
+
.filter((m) => typeof m.text === 'string' && m.text.trim().length > 0);
|
|
108
|
+
const findings = [];
|
|
109
|
+
const duplicateGroups = new Map();
|
|
110
|
+
for (const m of scoped.filter((msg) => !msg.fromUser)) {
|
|
111
|
+
const key = normalizeForDuplicate(m.text);
|
|
112
|
+
if (key.length < 12)
|
|
113
|
+
continue;
|
|
114
|
+
if (!duplicateGroups.has(key))
|
|
115
|
+
duplicateGroups.set(key, []);
|
|
116
|
+
duplicateGroups.get(key).push(m);
|
|
117
|
+
}
|
|
118
|
+
for (const group of duplicateGroups.values()) {
|
|
119
|
+
if (group.length >= 2) {
|
|
120
|
+
findings.push(makeFinding({
|
|
121
|
+
category: 'duplicate-notices-deliveries',
|
|
122
|
+
topicId: input.topicId,
|
|
123
|
+
messages: group,
|
|
124
|
+
window: input.window,
|
|
125
|
+
observedVersion,
|
|
126
|
+
}));
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
const contentFreeGroups = new Map();
|
|
130
|
+
for (const m of scoped.filter((msg) => !msg.fromUser)) {
|
|
131
|
+
if (ASK_OF_USER_RE.test(m.text)) {
|
|
132
|
+
findings.push(makeFinding({
|
|
133
|
+
category: 'asks-of-user',
|
|
134
|
+
topicId: input.topicId,
|
|
135
|
+
messages: [m],
|
|
136
|
+
window: input.window,
|
|
137
|
+
observedVersion,
|
|
138
|
+
}));
|
|
139
|
+
}
|
|
140
|
+
if (INFRA_NOISE_RE.test(m.text)) {
|
|
141
|
+
findings.push(makeFinding({
|
|
142
|
+
category: 'infra-noise',
|
|
143
|
+
topicId: input.topicId,
|
|
144
|
+
messages: [m],
|
|
145
|
+
window: input.window,
|
|
146
|
+
observedVersion,
|
|
147
|
+
}));
|
|
148
|
+
}
|
|
149
|
+
if (CONTENT_FREE_RE.test(m.text) && !isConcreteUpdate(m.text)) {
|
|
150
|
+
const key = normalizeForDuplicate(m.text);
|
|
151
|
+
if (!contentFreeGroups.has(key))
|
|
152
|
+
contentFreeGroups.set(key, []);
|
|
153
|
+
contentFreeGroups.get(key).push(m);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
for (const group of contentFreeGroups.values()) {
|
|
157
|
+
findings.push(makeFinding({
|
|
158
|
+
category: 'content-free-updates',
|
|
159
|
+
topicId: input.topicId,
|
|
160
|
+
messages: group,
|
|
161
|
+
window: input.window,
|
|
162
|
+
observedVersion,
|
|
163
|
+
}));
|
|
164
|
+
}
|
|
165
|
+
const seen = new Set();
|
|
166
|
+
return findings.filter((f) => {
|
|
167
|
+
if (seen.has(f.dedupKey))
|
|
168
|
+
return false;
|
|
169
|
+
seen.add(f.dedupKey);
|
|
170
|
+
return true;
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
function summarize(findings) {
|
|
174
|
+
const summary = { ...ZERO_SUMMARY };
|
|
175
|
+
for (const f of findings) {
|
|
176
|
+
summary[f.category] += 1;
|
|
177
|
+
summary.total += 1;
|
|
178
|
+
}
|
|
179
|
+
return summary;
|
|
180
|
+
}
|
|
181
|
+
export async function runPostDriveTranscriptAudit(options) {
|
|
182
|
+
if (options.topicIds.length === 0)
|
|
183
|
+
throw new Error('At least one topic id is required');
|
|
184
|
+
const window = canonicalWindow(options.start, options.end);
|
|
185
|
+
const limit = Math.max(1, Math.min(100, Math.floor(options.limit ?? 100)));
|
|
186
|
+
const generatedAt = (options.deps.now ?? (() => new Date()))().toISOString();
|
|
187
|
+
const findings = [];
|
|
188
|
+
for (const topicId of options.topicIds) {
|
|
189
|
+
const messages = await options.deps.readTopicHistory(topicId, limit);
|
|
190
|
+
findings.push(...classifyTranscriptUx({ topicId, messages, window }));
|
|
191
|
+
}
|
|
192
|
+
const observations = [];
|
|
193
|
+
for (const finding of findings) {
|
|
194
|
+
if (options.dryRun) {
|
|
195
|
+
observations.push({ dedupKey: finding.dedupKey, filed: false });
|
|
196
|
+
continue;
|
|
197
|
+
}
|
|
198
|
+
try {
|
|
199
|
+
const result = await options.deps.observeFinding(finding.frameworkIssue);
|
|
200
|
+
observations.push({ dedupKey: finding.dedupKey, filed: true, ...result });
|
|
201
|
+
}
|
|
202
|
+
catch (err) {
|
|
203
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
204
|
+
DegradationReporter.getInstance().report({
|
|
205
|
+
feature: 'post-drive-transcript-audit',
|
|
206
|
+
primary: 'File transcript UX finding into the framework issue ledger',
|
|
207
|
+
fallback: 'Structured report still includes the finding; ledger write failed for this observation',
|
|
208
|
+
reason: message,
|
|
209
|
+
impact: 'The auditor found a UX antipattern but could not persist that single observation automatically.',
|
|
210
|
+
});
|
|
211
|
+
observations.push({ dedupKey: finding.dedupKey, filed: false, error: message });
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
return {
|
|
215
|
+
topicIds: options.topicIds,
|
|
216
|
+
window,
|
|
217
|
+
generatedAt,
|
|
218
|
+
summary: summarize(findings),
|
|
219
|
+
findings,
|
|
220
|
+
observations,
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
function parseTopicIds(raw) {
|
|
224
|
+
const values = [...(raw.topic ?? []), ...(raw.topics ?? [])];
|
|
225
|
+
const ids = values.flatMap((v) => String(v).split(',')).map((v) => Number.parseInt(v.trim(), 10));
|
|
226
|
+
if (ids.length === 0 || ids.some((n) => !Number.isInteger(n) || n <= 0)) {
|
|
227
|
+
throw new Error('Pass at least one positive topic id with --topic (repeatable) or --topics');
|
|
228
|
+
}
|
|
229
|
+
return [...new Set(ids)];
|
|
230
|
+
}
|
|
231
|
+
async function fetchJson(url, init) {
|
|
232
|
+
const res = await fetch(url, init);
|
|
233
|
+
if (!res.ok) {
|
|
234
|
+
const body = await res.text().catch((err) => `failed to read response body: ${err instanceof Error ? err.message : String(err)}`);
|
|
235
|
+
throw new Error(`${res.status} ${res.statusText}: ${body.slice(0, 300)}`);
|
|
236
|
+
}
|
|
237
|
+
return res.json();
|
|
238
|
+
}
|
|
239
|
+
export async function runPostDriveTranscriptAuditCli(options) {
|
|
240
|
+
const config = loadConfig(options.dir);
|
|
241
|
+
const baseUrl = (options.baseUrl ?? `http://localhost:${config.port}`).replace(/\/+$/, '');
|
|
242
|
+
const headers = {};
|
|
243
|
+
if (config.authToken)
|
|
244
|
+
headers.Authorization = `Bearer ${config.authToken}`;
|
|
245
|
+
const topicIds = parseTopicIds(options);
|
|
246
|
+
const report = await runPostDriveTranscriptAudit({
|
|
247
|
+
topicIds,
|
|
248
|
+
start: options.start,
|
|
249
|
+
end: options.end,
|
|
250
|
+
limit: options.limit,
|
|
251
|
+
dryRun: options.dryRun,
|
|
252
|
+
deps: {
|
|
253
|
+
readTopicHistory: async (topicId, limit) => {
|
|
254
|
+
const data = await fetchJson(`${baseUrl}/telegram/topics/${topicId}/messages?limit=${limit}`, { headers });
|
|
255
|
+
const messages = data.messages;
|
|
256
|
+
if (!Array.isArray(messages))
|
|
257
|
+
throw new Error(`Topic ${topicId} history response did not include messages[]`);
|
|
258
|
+
return messages;
|
|
259
|
+
},
|
|
260
|
+
observeFinding: async (input) => {
|
|
261
|
+
return await fetchJson(`${baseUrl}/framework-issues/observe`, {
|
|
262
|
+
method: 'POST',
|
|
263
|
+
headers: { ...headers, 'Content-Type': 'application/json' },
|
|
264
|
+
body: JSON.stringify(input),
|
|
265
|
+
});
|
|
266
|
+
},
|
|
267
|
+
},
|
|
268
|
+
});
|
|
269
|
+
if (options.json) {
|
|
270
|
+
process.stdout.write(`${JSON.stringify(report, null, 2)}\n`);
|
|
271
|
+
return report.observations.some((o) => o.error) ? 1 : 0;
|
|
272
|
+
}
|
|
273
|
+
process.stdout.write(`${pc.bold('post-drive transcript audit')}\n`);
|
|
274
|
+
process.stdout.write(`Topics: ${report.topicIds.join(', ')}\n`);
|
|
275
|
+
process.stdout.write(`Window: ${report.window.start} .. ${report.window.end}\n`);
|
|
276
|
+
process.stdout.write(`Findings: ${report.summary.total}\n`);
|
|
277
|
+
for (const category of Object.keys(ZERO_SUMMARY).filter((k) => k !== 'total')) {
|
|
278
|
+
process.stdout.write(` ${category}: ${report.summary[category]}\n`);
|
|
279
|
+
}
|
|
280
|
+
for (const finding of report.findings) {
|
|
281
|
+
const obs = report.observations.find((o) => o.dedupKey === finding.dedupKey);
|
|
282
|
+
const filed = obs?.filed ? (obs.episodeRecorded === false ? 'deduped' : 'filed') : options.dryRun ? 'dry-run' : 'not filed';
|
|
283
|
+
process.stdout.write(`\n- [${finding.category}] topic ${finding.topicId} ${filed}\n`);
|
|
284
|
+
process.stdout.write(` ${finding.reason}\n`);
|
|
285
|
+
process.stdout.write(` evidence: ${finding.frameworkIssue.evidence}\n`);
|
|
286
|
+
process.stdout.write(` dedupKey: ${finding.dedupKey}\n`);
|
|
287
|
+
}
|
|
288
|
+
return report.observations.some((o) => o.error) ? 1 : 0;
|
|
289
|
+
}
|
|
290
|
+
//# sourceMappingURL=postDriveTranscriptAudit.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"postDriveTranscriptAudit.js","sourceRoot":"","sources":["../../src/commands/postDriveTranscriptAudit.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* IntentTestHarness — the two MTP-Protocol tests from EXO 3.0 (Salim Ismail,
|
|
3
|
+
* "Why AI Agents Are Ignoring Your Purpose"):
|
|
4
|
+
*
|
|
5
|
+
* 1. Refusal test — "Can your MTP make an agent say NO?" If the purpose
|
|
6
|
+
* can't cause a refusal, it's cheering, not governing.
|
|
7
|
+
* 2. Endorsement test — "Would leadership endorse what the agent decided?"
|
|
8
|
+
*
|
|
9
|
+
* This operationalizes ORG-INTENT as a machine-readable protocol: a proposed
|
|
10
|
+
* action is checked against the CONSTRAINT layer (forbidden actions → refuse)
|
|
11
|
+
* and the GOAL/VALUE layers (alignment → endorse). It is deterministic and
|
|
12
|
+
* heuristic (no LLM) so two agents reading the same intent reach the same call
|
|
13
|
+
* — exactly the property EXO 3.0 demands of the decision layer. An optional
|
|
14
|
+
* LLM pass can be layered on top by callers; the core here is pure + testable.
|
|
15
|
+
*
|
|
16
|
+
* Design mirrors OrgIntentManager's existing keyword-contradiction approach
|
|
17
|
+
* (negation-aware core extraction) but is self-contained so the harness can be
|
|
18
|
+
* unit-tested in isolation.
|
|
19
|
+
*/
|
|
20
|
+
import type { ParsedOrgIntent } from './OrgIntentManager.js';
|
|
21
|
+
export interface RefusalResult {
|
|
22
|
+
/** True when a constraint forbids the action. */
|
|
23
|
+
refused: boolean;
|
|
24
|
+
/** The constraint text that triggered the refusal (if any). */
|
|
25
|
+
matchedConstraint?: string;
|
|
26
|
+
reason: string;
|
|
27
|
+
}
|
|
28
|
+
export interface EndorsementResult {
|
|
29
|
+
/** True when the action violates no constraint AND aligns with a goal/value. */
|
|
30
|
+
endorsed: boolean;
|
|
31
|
+
/** The goal/value the action aligns with (if endorsed). */
|
|
32
|
+
alignedWith?: string;
|
|
33
|
+
reason: string;
|
|
34
|
+
}
|
|
35
|
+
export declare class IntentTestHarness {
|
|
36
|
+
private readonly intent;
|
|
37
|
+
constructor(intent: ParsedOrgIntent);
|
|
38
|
+
/**
|
|
39
|
+
* Refusal test: does any constraint forbid this action?
|
|
40
|
+
* The MTP "governs" only if it can produce a NO.
|
|
41
|
+
*/
|
|
42
|
+
testRefusal(action: string): RefusalResult;
|
|
43
|
+
/**
|
|
44
|
+
* Endorsement test: would leadership endorse this?
|
|
45
|
+
* Endorsed only when (a) no constraint refuses it AND (b) it aligns with a
|
|
46
|
+
* stated goal or value. Silence is NOT endorsement — an action unrelated to
|
|
47
|
+
* every goal/value is left un-endorsed (returns false), which is the
|
|
48
|
+
* conservative, governing default.
|
|
49
|
+
*/
|
|
50
|
+
testEndorsement(action: string): EndorsementResult;
|
|
51
|
+
/**
|
|
52
|
+
* Governance self-check: an MTP that can never refuse anything is "cheering,
|
|
53
|
+
* not governing" (EXO 3.0). True when at least one machine-readable
|
|
54
|
+
* constraint exists to refuse against.
|
|
55
|
+
*/
|
|
56
|
+
canGovern(): boolean;
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=IntentTestHarness.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"IntentTestHarness.d.ts","sourceRoot":"","sources":["../../src/core/IntentTestHarness.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAI7D,MAAM,WAAW,aAAa;IAC5B,iDAAiD;IACjD,OAAO,EAAE,OAAO,CAAC;IACjB,+DAA+D;IAC/D,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,iBAAiB;IAChC,gFAAgF;IAChF,QAAQ,EAAE,OAAO,CAAC;IAClB,2DAA2D;IAC3D,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;CAChB;AA2CD,qBAAa,iBAAiB;IAChB,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAAN,MAAM,EAAE,eAAe;IAEpD;;;OAGG;IACH,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,aAAa;IAe1C;;;;;;OAMG;IACH,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,iBAAiB;IAyBlD;;;;OAIG;IACH,SAAS,IAAI,OAAO;CAGrB"}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* IntentTestHarness — the two MTP-Protocol tests from EXO 3.0 (Salim Ismail,
|
|
3
|
+
* "Why AI Agents Are Ignoring Your Purpose"):
|
|
4
|
+
*
|
|
5
|
+
* 1. Refusal test — "Can your MTP make an agent say NO?" If the purpose
|
|
6
|
+
* can't cause a refusal, it's cheering, not governing.
|
|
7
|
+
* 2. Endorsement test — "Would leadership endorse what the agent decided?"
|
|
8
|
+
*
|
|
9
|
+
* This operationalizes ORG-INTENT as a machine-readable protocol: a proposed
|
|
10
|
+
* action is checked against the CONSTRAINT layer (forbidden actions → refuse)
|
|
11
|
+
* and the GOAL/VALUE layers (alignment → endorse). It is deterministic and
|
|
12
|
+
* heuristic (no LLM) so two agents reading the same intent reach the same call
|
|
13
|
+
* — exactly the property EXO 3.0 demands of the decision layer. An optional
|
|
14
|
+
* LLM pass can be layered on top by callers; the core here is pure + testable.
|
|
15
|
+
*
|
|
16
|
+
* Design mirrors OrgIntentManager's existing keyword-contradiction approach
|
|
17
|
+
* (negation-aware core extraction) but is self-contained so the harness can be
|
|
18
|
+
* unit-tested in isolation.
|
|
19
|
+
*/
|
|
20
|
+
// ── Keyword helpers (self-contained) ─────────────────────────────────
|
|
21
|
+
function normalize(text) {
|
|
22
|
+
return text.toLowerCase().replace(/[^a-z0-9\s]/g, ' ').replace(/\s+/g, ' ').trim();
|
|
23
|
+
}
|
|
24
|
+
const NEGATIONS = [
|
|
25
|
+
/^never\s+(.+)/, /^do not\s+(.+)/, /^don t\s+(.+)/, /^dont\s+(.+)/,
|
|
26
|
+
/^no\s+(.+)/, /^avoid\s+(.+)/, /^forbidden\s*:?\s*(.+)/, /^must not\s+(.+)/,
|
|
27
|
+
/^cannot\s+(.+)/, /^can t\s+(.+)/, /^refuse to\s+(.+)/,
|
|
28
|
+
];
|
|
29
|
+
/** Strip a leading negation/imperative to get the action core. */
|
|
30
|
+
function core(text) {
|
|
31
|
+
const norm = normalize(text);
|
|
32
|
+
for (const re of NEGATIONS) {
|
|
33
|
+
const m = norm.match(re);
|
|
34
|
+
if (m)
|
|
35
|
+
return m[1].trim();
|
|
36
|
+
}
|
|
37
|
+
// strip leading positive imperatives so "always validate X" → "validate x"
|
|
38
|
+
const pos = norm.match(/^(?:always|ensure|must|please)\s+(.+)/);
|
|
39
|
+
return (pos ? pos[1] : norm).trim();
|
|
40
|
+
}
|
|
41
|
+
/** Content-word overlap ratio of the shorter phrase against the longer. */
|
|
42
|
+
const STOP = new Set(['the', 'a', 'an', 'to', 'of', 'for', 'with', 'and', 'or', 'any', 'that', 'this', 'is', 'are', 'be', 'on', 'in', 'it', 'its', 'our', 'your', 'their', 'all', 'from', 'by']);
|
|
43
|
+
function words(s) {
|
|
44
|
+
return s.split(' ').filter((w) => w.length > 2 && !STOP.has(w));
|
|
45
|
+
}
|
|
46
|
+
function overlap(a, b) {
|
|
47
|
+
const wa = words(a), wb = words(b);
|
|
48
|
+
if (wa.length === 0 || wb.length === 0)
|
|
49
|
+
return 0;
|
|
50
|
+
const setB = new Set(wb);
|
|
51
|
+
const shared = wa.filter((w) => setB.has(w)).length;
|
|
52
|
+
return shared / Math.min(wa.length, wb.length);
|
|
53
|
+
}
|
|
54
|
+
const MATCH_THRESHOLD = 0.6;
|
|
55
|
+
// ── Public API ───────────────────────────────────────────────────────
|
|
56
|
+
export class IntentTestHarness {
|
|
57
|
+
intent;
|
|
58
|
+
constructor(intent) {
|
|
59
|
+
this.intent = intent;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Refusal test: does any constraint forbid this action?
|
|
63
|
+
* The MTP "governs" only if it can produce a NO.
|
|
64
|
+
*/
|
|
65
|
+
testRefusal(action) {
|
|
66
|
+
const actCore = core(action);
|
|
67
|
+
for (const c of this.intent.constraints) {
|
|
68
|
+
const conCore = core(c.text);
|
|
69
|
+
if (overlap(actCore, conCore) >= MATCH_THRESHOLD) {
|
|
70
|
+
return {
|
|
71
|
+
refused: true,
|
|
72
|
+
matchedConstraint: c.text,
|
|
73
|
+
reason: `Refused: the action matches the constraint "${c.text}".`,
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return { refused: false, reason: 'No constraint forbids this action.' };
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Endorsement test: would leadership endorse this?
|
|
81
|
+
* Endorsed only when (a) no constraint refuses it AND (b) it aligns with a
|
|
82
|
+
* stated goal or value. Silence is NOT endorsement — an action unrelated to
|
|
83
|
+
* every goal/value is left un-endorsed (returns false), which is the
|
|
84
|
+
* conservative, governing default.
|
|
85
|
+
*/
|
|
86
|
+
testEndorsement(action) {
|
|
87
|
+
const refusal = this.testRefusal(action);
|
|
88
|
+
if (refusal.refused) {
|
|
89
|
+
return { endorsed: false, reason: `Not endorsed — ${refusal.reason}` };
|
|
90
|
+
}
|
|
91
|
+
const actCore = core(action);
|
|
92
|
+
const candidates = [
|
|
93
|
+
...this.intent.goals.map((g) => g.text),
|
|
94
|
+
...this.intent.values,
|
|
95
|
+
];
|
|
96
|
+
for (const cand of candidates) {
|
|
97
|
+
if (overlap(actCore, core(cand)) >= MATCH_THRESHOLD) {
|
|
98
|
+
return {
|
|
99
|
+
endorsed: true,
|
|
100
|
+
alignedWith: cand,
|
|
101
|
+
reason: `Endorsed: aligns with "${cand}" and violates no constraint.`,
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
return {
|
|
106
|
+
endorsed: false,
|
|
107
|
+
reason: 'Not endorsed — violates no constraint, but aligns with no stated goal or value.',
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Governance self-check: an MTP that can never refuse anything is "cheering,
|
|
112
|
+
* not governing" (EXO 3.0). True when at least one machine-readable
|
|
113
|
+
* constraint exists to refuse against.
|
|
114
|
+
*/
|
|
115
|
+
canGovern() {
|
|
116
|
+
return this.intent.constraints.length > 0;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
//# sourceMappingURL=IntentTestHarness.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"IntentTestHarness.js","sourceRoot":"","sources":["../../src/core/IntentTestHarness.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAsBH,wEAAwE;AAExE,SAAS,SAAS,CAAC,IAAY;IAC7B,OAAO,IAAI,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,cAAc,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;AACrF,CAAC;AAED,MAAM,SAAS,GAAG;IAChB,eAAe,EAAE,gBAAgB,EAAE,eAAe,EAAE,cAAc;IAClE,YAAY,EAAE,eAAe,EAAE,wBAAwB,EAAE,kBAAkB;IAC3E,gBAAgB,EAAE,eAAe,EAAE,mBAAmB;CACvD,CAAC;AAEF,kEAAkE;AAClE,SAAS,IAAI,CAAC,IAAY;IACxB,MAAM,IAAI,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;IAC7B,KAAK,MAAM,EAAE,IAAI,SAAS,EAAE,CAAC;QAC3B,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QACzB,IAAI,CAAC;YAAE,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IAC5B,CAAC;IACD,2EAA2E;IAC3E,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,uCAAuC,CAAC,CAAC;IAChE,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC;AACtC,CAAC;AAED,2EAA2E;AAC3E,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,CAAC,KAAK,EAAC,GAAG,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,KAAK,EAAC,MAAM,EAAC,KAAK,EAAC,IAAI,EAAC,KAAK,EAAC,MAAM,EAAC,MAAM,EAAC,IAAI,EAAC,KAAK,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,KAAK,EAAC,KAAK,EAAC,MAAM,EAAC,OAAO,EAAC,KAAK,EAAC,MAAM,EAAC,IAAI,CAAC,CAAC,CAAC;AACzK,SAAS,KAAK,CAAC,CAAS;IACtB,OAAO,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;AAClE,CAAC;AACD,SAAS,OAAO,CAAC,CAAS,EAAE,CAAS;IACnC,MAAM,EAAE,GAAG,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;IACnC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,CAAC,CAAC;IACjD,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,EAAE,CAAC,CAAC;IACzB,MAAM,MAAM,GAAG,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;IACpD,OAAO,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC;AACjD,CAAC;AAED,MAAM,eAAe,GAAG,GAAG,CAAC;AAE5B,wEAAwE;AAExE,MAAM,OAAO,iBAAiB;IACC;IAA7B,YAA6B,MAAuB;QAAvB,WAAM,GAAN,MAAM,CAAiB;IAAG,CAAC;IAExD;;;OAGG;IACH,WAAW,CAAC,MAAc;QACxB,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC;QAC7B,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC;YACxC,MAAM,OAAO,GAAG,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;YAC7B,IAAI,OAAO,CAAC,OAAO,EAAE,OAAO,CAAC,IAAI,eAAe,EAAE,CAAC;gBACjD,OAAO;oBACL,OAAO,EAAE,IAAI;oBACb,iBAAiB,EAAE,CAAC,CAAC,IAAI;oBACzB,MAAM,EAAE,+CAA+C,CAAC,CAAC,IAAI,IAAI;iBAClE,CAAC;YACJ,CAAC;QACH,CAAC;QACD,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,oCAAoC,EAAE,CAAC;IAC1E,CAAC;IAED;;;;;;OAMG;IACH,eAAe,CAAC,MAAc;QAC5B,MAAM,OAAO,GAAG,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;QACzC,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;YACpB,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,kBAAkB,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC;QACzE,CAAC;QACD,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC;QAC7B,MAAM,UAAU,GAAa;YAC3B,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;YACvC,GAAG,IAAI,CAAC,MAAM,CAAC,MAAM;SACtB,CAAC;QACF,KAAK,MAAM,IAAI,IAAI,UAAU,EAAE,CAAC;YAC9B,IAAI,OAAO,CAAC,OAAO,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,eAAe,EAAE,CAAC;gBACpD,OAAO;oBACL,QAAQ,EAAE,IAAI;oBACd,WAAW,EAAE,IAAI;oBACjB,MAAM,EAAE,0BAA0B,IAAI,+BAA+B;iBACtE,CAAC;YACJ,CAAC;QACH,CAAC;QACD,OAAO;YACL,QAAQ,EAAE,KAAK;YACf,MAAM,EAAE,iFAAiF;SAC1F,CAAC;IACJ,CAAC;IAED;;;;OAIG;IACH,SAAS;QACP,OAAO,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,MAAM,GAAG,CAAC,CAAC;IAC5C,CAAC;CACF"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OrgIntentIdentityLayer — the third layer of the "MTP Protocol" (EXO 3.0).
|
|
3
|
+
*
|
|
4
|
+
* Salim Ismail's EXO 3.0 frames a Massive Transformative Purpose as a
|
|
5
|
+
* machine-readable protocol with three layers:
|
|
6
|
+
* 1. Constraint layer — what agents are forbidden from doing (ORG-INTENT `constraints`)
|
|
7
|
+
* 2. Decision layer — how agents resolve trade-offs (ORG-INTENT `tradeoffHierarchy`)
|
|
8
|
+
* 3. Identity layer — why high-judgment humans stay, and what the org is NOT for
|
|
9
|
+
*
|
|
10
|
+
* Instar already has layers 1 and 2. This module parses layer 3 from an
|
|
11
|
+
* optional `## Identity` section of ORG-INTENT.md, so the purpose can bind
|
|
12
|
+
* humans (not just gate agents). It is intentionally tolerant: a missing or
|
|
13
|
+
* template-only section yields `null`, never an error.
|
|
14
|
+
*
|
|
15
|
+
* Parsing contract (all optional, order-independent):
|
|
16
|
+
* ## Identity
|
|
17
|
+
* ### Why People Stay -> bindingStatements[] (also accepts "What Binds Us")
|
|
18
|
+
* - <statement>
|
|
19
|
+
* ### What We're Not For -> disqualifiers[] (also accepts "Not For" / "Identity Disqualifiers")
|
|
20
|
+
* - <statement>
|
|
21
|
+
* Bare list items directly under `## Identity` (no subheading) are treated as
|
|
22
|
+
* bindingStatements, so a minimal section still parses.
|
|
23
|
+
*/
|
|
24
|
+
export interface OrgIdentity {
|
|
25
|
+
/** Why a high-judgment human stays — the binding statements. */
|
|
26
|
+
bindingStatements: string[];
|
|
27
|
+
/** What the org is explicitly NOT for — identity disqualifiers. */
|
|
28
|
+
disqualifiers: string[];
|
|
29
|
+
/** Raw text of the `## Identity` section (excluding the heading line). */
|
|
30
|
+
raw: string;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Parse the identity layer from full ORG-INTENT.md content.
|
|
34
|
+
* Returns null when there is no `## Identity` section or it is template-only/empty.
|
|
35
|
+
*/
|
|
36
|
+
export declare function parseIdentityLayer(orgIntentContent: string): OrgIdentity | null;
|
|
37
|
+
//# sourceMappingURL=OrgIntentIdentityLayer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"OrgIntentIdentityLayer.d.ts","sourceRoot":"","sources":["../../src/core/OrgIntentIdentityLayer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAIH,MAAM,WAAW,WAAW;IAC1B,gEAAgE;IAChE,iBAAiB,EAAE,MAAM,EAAE,CAAC;IAC5B,mEAAmE;IACnE,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,0EAA0E;IAC1E,GAAG,EAAE,MAAM,CAAC;CACb;AA6ED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,gBAAgB,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI,CAuB/E"}
|