@fro.bot/systematic 3.6.1 → 3.7.0

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.
@@ -0,0 +1,195 @@
1
+ declare const CAPABILITY_SNAPSHOT_SCHEMA_VERSION: 'cli-capabilities.v1';
2
+ declare const CAPABILITY_SNAPSHOT_COMMAND: 'systematic capabilities';
3
+ declare const CAPABILITY_SOURCE_IDS: readonly ['config:custom', 'config:global', 'config:project', 'config:user', 'discovery:agents', 'discovery:skills', 'host:runtime', 'package'];
4
+ declare const CONFIG_SOURCE_KINDS: readonly ['custom', 'project', 'user'];
5
+ declare const CONFIG_AUTHORITY_FIELD_PATHS: readonly ['bootstrap.enabled', 'bootstrap.file', 'skills_as_commands', 'workflow_guard.debug', 'workflow_guard.mode'];
6
+ declare const CONFIG_PROTECTED_FIELD_PATHS: readonly ['workflow_guard', 'agents.*.model', 'agents.*.permission', 'agents.*.skills', 'agents.*.variant', 'categories.*.model', 'categories.*.permission', 'categories.*.skills', 'categories.*.variant'];
7
+ declare const CONFIG_SOURCE_ERROR_CODES: readonly ['parse-failed', 'read-failed', 'schema-invalid', 'source-invalid'];
8
+ declare const CAPABILITY_SOURCE_PRESENCE: readonly ['absent', 'invalid', 'present'];
9
+ declare const CAPABILITY_STATUSES: readonly ['available', 'unknown', 'unavailable'];
10
+ declare const CAPABILITY_FACT_IDS: readonly ['config-authority', 'config-field-authority', 'config-protected-field', 'discovery-summary', 'discovery-source-issue', 'host-runtime'];
11
+ declare const CAPABILITY_DISCOVERY_IDS: readonly ['agents', 'skills'];
12
+ declare const CAPABILITY_LIMITATION_CODES: readonly ['authority-unproven', 'discovery-not-collected', 'host-runtime-unobservable'];
13
+ declare const CAPABILITY_ERROR_CODES: readonly ['source-malformed', 'source-read-failed', 'source-unsupported', 'structural-invalid'];
14
+ declare const CAPABILITY_ROOT_IDS: readonly ['agents', 'cwd', 'global', 'package', 'project', 'skills', 'user', 'workspace'];
15
+ type CapabilitySourceId = (typeof CAPABILITY_SOURCE_IDS)[number];
16
+ type ConfigSourceKind = (typeof CONFIG_SOURCE_KINDS)[number];
17
+ type ConfigAuthorityFieldPath = (typeof CONFIG_AUTHORITY_FIELD_PATHS)[number];
18
+ type ConfigProtectedFieldPath = (typeof CONFIG_PROTECTED_FIELD_PATHS)[number];
19
+ type ConfigSourceErrorCode = (typeof CONFIG_SOURCE_ERROR_CODES)[number];
20
+ type CapabilitySourcePresence = (typeof CAPABILITY_SOURCE_PRESENCE)[number];
21
+ type CapabilityStatus = (typeof CAPABILITY_STATUSES)[number];
22
+ type CapabilityFactId = (typeof CAPABILITY_FACT_IDS)[number];
23
+ type CapabilityStatusFactId = Exclude<CapabilityFactId, 'discovery-source-issue' | 'discovery-summary'>;
24
+ type CapabilityDiscoveryIssueErrorCode = Extract<CapabilityErrorCode, 'source-malformed' | 'source-read-failed'>;
25
+ type CapabilityDiscoveryId = (typeof CAPABILITY_DISCOVERY_IDS)[number];
26
+ type CapabilityLimitationCode = (typeof CAPABILITY_LIMITATION_CODES)[number];
27
+ type CapabilityErrorCode = (typeof CAPABILITY_ERROR_CODES)[number];
28
+ type CapabilityRootId = (typeof CAPABILITY_ROOT_IDS)[number] | string;
29
+ interface CapabilityPackageIdentity {
30
+ readonly name: string;
31
+ readonly version: string;
32
+ }
33
+ interface CapabilityRootInput {
34
+ readonly id: CapabilityRootId;
35
+ readonly path: string;
36
+ }
37
+ interface CapabilitySourceInput {
38
+ readonly sourceId: CapabilitySourceId;
39
+ readonly presence: CapabilitySourcePresence;
40
+ readonly sourceKind?: ConfigSourceKind;
41
+ readonly path?: string;
42
+ readonly errorCode?: CapabilityErrorCode;
43
+ }
44
+ export type CapabilityFactInput = {
45
+ readonly factId: Exclude<CapabilityFactId, 'config-field-authority' | 'config-protected-field' | 'discovery-source-issue' | 'discovery-summary'>;
46
+ readonly status: CapabilityStatus;
47
+ readonly sourceId?: CapabilitySourceId;
48
+ readonly limitationCode?: CapabilityLimitationCode;
49
+ readonly errorCode?: CapabilityErrorCode;
50
+ } | {
51
+ readonly factId: 'config-field-authority';
52
+ readonly fieldPath: ConfigAuthorityFieldPath;
53
+ readonly kind: 'authority';
54
+ readonly sourceId: CapabilitySourceId;
55
+ readonly status: 'available';
56
+ } | {
57
+ readonly errorCode: CapabilityDiscoveryIssueErrorCode;
58
+ readonly factId: 'discovery-source-issue';
59
+ readonly kind: 'status';
60
+ readonly sourceId: 'discovery:skills';
61
+ readonly status: 'unavailable';
62
+ } | {
63
+ readonly errorCode: CapabilityErrorCode;
64
+ readonly factId: 'discovery-summary';
65
+ readonly kind?: 'status';
66
+ readonly sourceId: CapabilitySourceId;
67
+ readonly status: 'unavailable';
68
+ } | {
69
+ readonly factId: 'config-protected-field';
70
+ readonly fieldPath: ConfigProtectedFieldPath;
71
+ readonly kind: 'protection';
72
+ readonly outcome: 'blocked';
73
+ readonly sourceId: CapabilitySourceId;
74
+ readonly status: 'available';
75
+ } | {
76
+ readonly count: number;
77
+ readonly discoveryId: CapabilityDiscoveryId;
78
+ readonly factId: 'discovery-summary';
79
+ readonly kind: 'discovery';
80
+ readonly sourceId: CapabilitySourceId;
81
+ readonly status: 'available';
82
+ readonly winningRoots: readonly string[];
83
+ };
84
+ interface ConfigSourceMetadata {
85
+ readonly errorCode?: ConfigSourceErrorCode;
86
+ readonly kind: ConfigSourceKind;
87
+ readonly path?: string;
88
+ readonly presence: CapabilitySourcePresence;
89
+ }
90
+ interface ConfigAuthorityMetadata {
91
+ readonly fieldPath: ConfigAuthorityFieldPath;
92
+ readonly sourceKind: ConfigSourceKind;
93
+ }
94
+ interface ConfigProtectedFieldMetadata {
95
+ readonly fieldPath: ConfigProtectedFieldPath;
96
+ readonly outcome: 'blocked';
97
+ readonly sourceKind: ConfigSourceKind;
98
+ }
99
+ export interface ConfigObservationMetadata {
100
+ readonly authorities: readonly ConfigAuthorityMetadata[];
101
+ readonly protectedFields: readonly ConfigProtectedFieldMetadata[];
102
+ readonly sources: readonly ConfigSourceMetadata[];
103
+ }
104
+ export type CapabilityClock = () => number | Date;
105
+ export type CapabilityOutputSink = (serialized: string) => void;
106
+ interface CapabilitySnapshotBuilderOptions {
107
+ readonly argv: readonly string[];
108
+ readonly package: CapabilityPackageIdentity;
109
+ readonly roots: readonly CapabilityRootInput[];
110
+ readonly sources?: readonly CapabilitySourceInput[];
111
+ readonly facts?: readonly CapabilityFactInput[];
112
+ readonly config?: ConfigObservationMetadata;
113
+ readonly observedAt?: string;
114
+ readonly clock?: CapabilityClock;
115
+ readonly outputSink?: CapabilityOutputSink;
116
+ }
117
+ interface CapabilitySnapshotArgvIdentity {
118
+ readonly executable: string;
119
+ readonly subcommand: 'capabilities';
120
+ }
121
+ interface CapabilitySnapshotIdentity {
122
+ readonly argv: CapabilitySnapshotArgvIdentity;
123
+ readonly package: CapabilityPackageIdentity;
124
+ }
125
+ interface CapabilitySnapshotRoot {
126
+ readonly id: string;
127
+ }
128
+ interface CapabilitySnapshotSource {
129
+ readonly errorCode?: CapabilityErrorCode;
130
+ readonly kind: 'source';
131
+ readonly presence: CapabilitySourcePresence;
132
+ readonly sourceId: CapabilitySourceId;
133
+ readonly sourceKind?: ConfigSourceKind;
134
+ }
135
+ type CapabilitySnapshotFact = {
136
+ readonly factId: CapabilityStatusFactId;
137
+ readonly kind: 'status';
138
+ readonly status: 'available';
139
+ } | {
140
+ readonly factId: CapabilityStatusFactId;
141
+ readonly kind: 'status';
142
+ readonly limitationCode: CapabilityLimitationCode;
143
+ readonly status: 'unknown';
144
+ } | {
145
+ readonly errorCode: CapabilityErrorCode;
146
+ readonly factId: CapabilityStatusFactId;
147
+ readonly kind: 'status';
148
+ readonly sourceId?: CapabilitySourceId;
149
+ readonly status: 'unavailable';
150
+ } | {
151
+ readonly errorCode: CapabilityErrorCode;
152
+ readonly factId: 'discovery-summary';
153
+ readonly kind: 'status';
154
+ readonly sourceId: CapabilitySourceId;
155
+ readonly status: 'unavailable';
156
+ } | {
157
+ readonly errorCode: CapabilityDiscoveryIssueErrorCode;
158
+ readonly factId: 'discovery-source-issue';
159
+ readonly kind: 'status';
160
+ readonly sourceId: 'discovery:skills';
161
+ readonly status: 'unavailable';
162
+ } | {
163
+ readonly factId: 'config-field-authority';
164
+ readonly fieldPath: ConfigAuthorityFieldPath;
165
+ readonly kind: 'authority';
166
+ readonly sourceId: CapabilitySourceId;
167
+ readonly status: 'available';
168
+ } | {
169
+ readonly factId: 'config-protected-field';
170
+ readonly fieldPath: ConfigProtectedFieldPath;
171
+ readonly kind: 'protection';
172
+ readonly outcome: 'blocked';
173
+ readonly sourceId: CapabilitySourceId;
174
+ readonly status: 'available';
175
+ } | {
176
+ readonly count: number;
177
+ readonly discoveryId: CapabilityDiscoveryId;
178
+ readonly factId: 'discovery-summary';
179
+ readonly kind: 'discovery';
180
+ readonly sourceId: CapabilitySourceId;
181
+ readonly status: 'available';
182
+ readonly winningRoots: readonly string[];
183
+ };
184
+ interface CapabilitySnapshot {
185
+ readonly command: typeof CAPABILITY_SNAPSHOT_COMMAND;
186
+ readonly facts: readonly CapabilitySnapshotFact[];
187
+ readonly identity: CapabilitySnapshotIdentity;
188
+ readonly observedAt: string;
189
+ readonly roots: readonly CapabilitySnapshotRoot[];
190
+ readonly schemaVersion: typeof CAPABILITY_SNAPSHOT_SCHEMA_VERSION;
191
+ readonly sources: readonly CapabilitySnapshotSource[];
192
+ }
193
+ export declare function buildCapabilitySnapshot(options: CapabilitySnapshotBuilderOptions): CapabilitySnapshot;
194
+ export declare function serializeCapabilitySnapshot(snapshot: CapabilitySnapshot): string;
195
+ export {};
@@ -201,4 +201,4 @@ export declare function validateConfig(input: unknown): ValidationResult;
201
201
  *
202
202
  * Matches the hand-coded `SECURITY_OVERLAY_FIELDS` set in `src/lib/config.ts`.
203
203
  */
204
- export declare const SECURITY_OVERLAY_FIELDS: readonly string[];
204
+ export declare const SECURITY_OVERLAY_FIELDS: readonly ['model', 'variant', 'skills', 'permission'];
@@ -18,8 +18,35 @@ export interface SourcedOverlayConfigMap {
18
18
  agents: Record<string, SourcedOverlayConfig>;
19
19
  categories: Record<string, SourcedOverlayConfig>;
20
20
  }
21
+ export declare const CONFIG_AUTHORITY_FIELD_PATHS: readonly ['bootstrap.enabled', 'bootstrap.file', 'skills_as_commands', 'workflow_guard.debug', 'workflow_guard.mode'];
22
+ export declare const CONFIG_PROTECTED_FIELD_PATHS: readonly ['workflow_guard', 'agents.*.model', 'agents.*.permission', 'agents.*.skills', 'agents.*.variant', 'categories.*.model', 'categories.*.permission', 'categories.*.skills', 'categories.*.variant'];
23
+ export type ConfigSourceKind = 'custom' | 'project' | 'user';
24
+ export type ConfigSourcePresence = 'absent' | 'invalid' | 'present';
25
+ export type ConfigSourceErrorCode = 'parse-failed' | 'read-failed' | 'schema-invalid' | 'source-invalid';
26
+ export type ConfigAuthorityFieldPath = (typeof CONFIG_AUTHORITY_FIELD_PATHS)[number];
27
+ export type ConfigProtectedFieldPath = (typeof CONFIG_PROTECTED_FIELD_PATHS)[number];
28
+ export interface ConfigSourceMetadata {
29
+ readonly errorCode?: ConfigSourceErrorCode;
30
+ readonly kind: ConfigSourceKind;
31
+ readonly presence: ConfigSourcePresence;
32
+ }
33
+ export interface ConfigAuthorityMetadata {
34
+ readonly fieldPath: ConfigAuthorityFieldPath;
35
+ readonly sourceKind: ConfigSourceKind;
36
+ }
37
+ export interface ConfigProtectedFieldMetadata {
38
+ readonly fieldPath: ConfigProtectedFieldPath;
39
+ readonly outcome: 'blocked';
40
+ readonly sourceKind: ConfigSourceKind;
41
+ }
42
+ export interface ConfigObservationMetadata {
43
+ readonly authorities: readonly ConfigAuthorityMetadata[];
44
+ readonly protectedFields: readonly ConfigProtectedFieldMetadata[];
45
+ readonly sources: readonly ConfigSourceMetadata[];
46
+ }
21
47
  export interface SourceAwareConfigResult {
22
48
  config: SystematicConfig;
49
+ metadata: ConfigObservationMetadata;
23
50
  overlays: SourcedOverlayConfigMap;
24
51
  }
25
52
  export interface PiSubagentsOverlayMap {
@@ -51,7 +78,7 @@ export declare function computeDroppedNames(names: readonly string[], allowedSet
51
78
  * single load call -- callers must NOT share it across independent loads.
52
79
  * Passing a fresh set per load ensures no cross-load suppression.
53
80
  */
54
- export declare function warnDroppedNames(dropped: string[], field: string, warned: Set<string>, removalVersion?: string): void;
81
+ export declare function warnDroppedNames(dropped: string[], field: string, warned: Set<string>, removalVersion?: string, warningSink?: (message: string) => void): void;
55
82
  export interface LoadConfigOptions {
56
83
  /**
57
84
  * When false, the project-level config source (`<cwd>/.opencode/systematic.json`)
@@ -60,10 +87,20 @@ export interface LoadConfigOptions {
60
87
  * absorbs cwd project overlays (plan R7/R19). Defaults to true.
61
88
  */
62
89
  includeProject?: boolean;
90
+ invalidSource?: 'throw' | 'report';
91
+ homeDir?: string;
92
+ userConfigDir?: string;
93
+ customConfigDir?: string | null;
94
+ warningSink?: (message: string) => void;
63
95
  }
64
96
  export declare function loadConfig(projectDir: string, options?: LoadConfigOptions): SystematicConfig;
65
97
  export declare function loadConfigWithSources(projectDir: string, options?: LoadConfigOptions): SourceAwareConfigResult;
66
- export declare function getConfigPaths(projectDir: string): {
98
+ interface ConfigPathOptions {
99
+ readonly homeDir?: string;
100
+ readonly userConfigDir?: string;
101
+ readonly customConfigDir?: string | null;
102
+ }
103
+ export declare function getConfigPaths(projectDir: string, options?: ConfigPathOptions): {
67
104
  userConfig: string;
68
105
  projectConfig: string;
69
106
  userDir: string;
@@ -71,3 +108,4 @@ export declare function getConfigPaths(projectDir: string): {
71
108
  customConfig?: string | undefined;
72
109
  customDir?: string | undefined;
73
110
  };
111
+ export {};
@@ -11,6 +11,7 @@ import { type SkillFrontmatter } from './skills.js';
11
11
  * upstream.
12
12
  */
13
13
  type DiscoveryRootId = 'global-claude' | 'global-agents' | 'project-claude' | 'project-agents' | 'project-opencode' | 'global-opencode-config';
14
+ export type SkillDiscoveryIssueCode = 'read-failed' | 'source-invalid';
14
15
  export interface DiscoveredSkill {
15
16
  name: string;
16
17
  description: string;
@@ -40,6 +41,8 @@ export interface DiscoverSkillsOptions {
40
41
  * discovery pure and testable.
41
42
  */
42
43
  opencodeConfigDirOverride?: string;
44
+ /** Optional bounded issue sink; discovery winners and precedence are unchanged. */
45
+ onIssue?: (issue: SkillDiscoveryIssueCode) => void;
43
46
  }
44
47
  /**
45
48
  * Discover user/project skills, replicating OpenCode v1.17.6's real
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fro.bot/systematic",
3
- "version": "3.6.1",
3
+ "version": "3.7.0",
4
4
  "description": "Compound-engineering loops for OpenCode, Pi, and Claude Code",
5
5
  "type": "module",
6
6
  "homepage": "https://fro.bot/systematic",
@@ -103,7 +103,7 @@
103
103
  "agent-browser": "0.33.1",
104
104
  "ajv": "8.20.0",
105
105
  "ajv-formats": "3.0.1",
106
- "conventional-changelog-conventionalcommits": "10.2.1",
106
+ "conventional-changelog-conventionalcommits": "10.3.0",
107
107
  "markdownlint-cli": "0.49.1",
108
108
  "rimraf": "6.1.3",
109
109
  "semantic-release": "25.0.9",