@fro.bot/systematic 2.12.0 → 2.12.1
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
CHANGED
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
loadConfig,
|
|
14
14
|
loadConfigWithSources,
|
|
15
15
|
parseFrontmatter
|
|
16
|
-
} from "./index-
|
|
16
|
+
} from "./index-b4ht76qd.js";
|
|
17
17
|
|
|
18
18
|
// src/index.ts
|
|
19
19
|
import fs4 from "fs";
|
|
@@ -686,29 +686,6 @@ function registerSkillsPaths(config, skillsDir) {
|
|
|
686
686
|
};
|
|
687
687
|
}
|
|
688
688
|
|
|
689
|
-
// src/lib/plugin-singleton.ts
|
|
690
|
-
var SINGLETON_KEY = Symbol.for("systematic.singleton.v1");
|
|
691
|
-
async function plugInOnce({
|
|
692
|
-
doInit,
|
|
693
|
-
pid
|
|
694
|
-
}) {
|
|
695
|
-
const currentPid = pid ?? process.pid;
|
|
696
|
-
const g = globalThis;
|
|
697
|
-
const existing = g[SINGLETON_KEY];
|
|
698
|
-
if (existing && existing.pid === currentPid) {
|
|
699
|
-
const hooks2 = await existing.hooksPromise;
|
|
700
|
-
return { isFirst: false, hooks: hooks2 };
|
|
701
|
-
}
|
|
702
|
-
const hooksPromise = doInit();
|
|
703
|
-
g[SINGLETON_KEY] = {
|
|
704
|
-
pid: currentPid,
|
|
705
|
-
loadedAt: Date.now(),
|
|
706
|
-
hooksPromise
|
|
707
|
-
};
|
|
708
|
-
const hooks = await hooksPromise;
|
|
709
|
-
return { isFirst: true, hooks };
|
|
710
|
-
}
|
|
711
|
-
|
|
712
689
|
// src/lib/skill-tool.ts
|
|
713
690
|
import fs3 from "fs";
|
|
714
691
|
import path4 from "path";
|
|
@@ -871,8 +848,26 @@ var bundledSkillsDir = path5.join(packageRoot, "skills");
|
|
|
871
848
|
var bundledAgentsDir = path5.join(packageRoot, "agents");
|
|
872
849
|
var bundledCommandsDir = path5.join(packageRoot, "commands");
|
|
873
850
|
var packageJsonPath = path5.join(packageRoot, "package.json");
|
|
874
|
-
var
|
|
851
|
+
var BOOTSTRAP_MARKER_OPEN = "<SYSTEMATIC_WORKFLOWS>";
|
|
852
|
+
var BOOTSTRAP_MARKER_CLOSE = "</SYSTEMATIC_WORKFLOWS>";
|
|
853
|
+
var findBootstrapMarkerBlock = (entry) => {
|
|
854
|
+
const start = entry.indexOf(BOOTSTRAP_MARKER_OPEN);
|
|
855
|
+
if (start === -1)
|
|
856
|
+
return null;
|
|
857
|
+
const closeStart = entry.indexOf(BOOTSTRAP_MARKER_CLOSE, start + BOOTSTRAP_MARKER_OPEN.length);
|
|
858
|
+
if (closeStart === -1)
|
|
859
|
+
return null;
|
|
860
|
+
return { start, end: closeStart + BOOTSTRAP_MARKER_CLOSE.length };
|
|
861
|
+
};
|
|
875
862
|
var applyBootstrapContent = (output, content) => {
|
|
863
|
+
for (let i = 0;i < output.system.length; i++) {
|
|
864
|
+
const entry = output.system[i];
|
|
865
|
+
const block = findBootstrapMarkerBlock(entry);
|
|
866
|
+
if (block !== null) {
|
|
867
|
+
output.system[i] = entry.slice(0, block.start) + content + entry.slice(block.end);
|
|
868
|
+
return;
|
|
869
|
+
}
|
|
870
|
+
}
|
|
876
871
|
if (output.system.length > 0) {
|
|
877
872
|
output.system[output.system.length - 1] += `
|
|
878
873
|
|
|
@@ -893,6 +888,7 @@ var getPackageVersion = () => {
|
|
|
893
888
|
}
|
|
894
889
|
};
|
|
895
890
|
var initializePlugin = async ({ client, directory }) => {
|
|
891
|
+
let hasLoggedInit = false;
|
|
896
892
|
const config = loadConfig(directory);
|
|
897
893
|
const bootstrapContent = getBootstrapContent(config, { bundledSkillsDir });
|
|
898
894
|
const configHandler = createConfigHandler({
|
|
@@ -951,12 +947,10 @@ var initializePlugin = async ({ client, directory }) => {
|
|
|
951
947
|
};
|
|
952
948
|
};
|
|
953
949
|
var SystematicPlugin = async (input) => {
|
|
954
|
-
|
|
955
|
-
doInit: () => initializePlugin(input)
|
|
956
|
-
});
|
|
957
|
-
return hooks;
|
|
950
|
+
return initializePlugin(input);
|
|
958
951
|
};
|
|
959
952
|
var src_default = SystematicPlugin;
|
|
960
953
|
export {
|
|
961
|
-
src_default as default
|
|
954
|
+
src_default as default,
|
|
955
|
+
applyBootstrapContent
|
|
962
956
|
};
|
|
@@ -158,11 +158,13 @@ export declare const SystematicConfigSchema: z.ZodObject<{
|
|
|
158
158
|
file: z.ZodOptional<z.ZodString>;
|
|
159
159
|
}, z.core.$strict>>;
|
|
160
160
|
}, z.core.$strict>;
|
|
161
|
-
export
|
|
162
|
-
success:
|
|
163
|
-
data
|
|
164
|
-
|
|
165
|
-
|
|
161
|
+
export type ValidationResult = {
|
|
162
|
+
success: true;
|
|
163
|
+
data: z.infer<typeof SystematicConfigSchema>;
|
|
164
|
+
} | {
|
|
165
|
+
success: false;
|
|
166
|
+
errors: readonly z.ZodIssue[];
|
|
167
|
+
};
|
|
166
168
|
export declare function validateConfig(input: unknown): ValidationResult;
|
|
167
169
|
export declare function assertSourceCategoryModelDefaults(defaults: Record<string, unknown>): void;
|
|
168
170
|
/**
|
package/dist/lib/config.d.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import type { z } from 'zod';
|
|
2
1
|
export interface BootstrapConfig {
|
|
3
2
|
enabled: boolean;
|
|
4
3
|
file?: string;
|
|
@@ -27,26 +26,6 @@ export interface SystematicConfig {
|
|
|
27
26
|
categories?: OverlayConfigMap;
|
|
28
27
|
}
|
|
29
28
|
export declare const DEFAULT_CONFIG: SystematicConfig;
|
|
30
|
-
interface RawSystematicConfig extends Omit<Partial<SystematicConfig>, 'agents' | 'categories'> {
|
|
31
|
-
agents?: unknown;
|
|
32
|
-
categories?: unknown;
|
|
33
|
-
}
|
|
34
|
-
interface ConfigSource {
|
|
35
|
-
path: string;
|
|
36
|
-
config: RawSystematicConfig;
|
|
37
|
-
trust: 'user' | 'project' | 'custom';
|
|
38
|
-
}
|
|
39
|
-
/**
|
|
40
|
-
* Type guard for errors thrown by the top-level config schema validator.
|
|
41
|
-
* Use this to distinguish schema validation failures from JSONC parse errors
|
|
42
|
-
* or file read errors.
|
|
43
|
-
*/
|
|
44
|
-
export declare function isConfigSchemaError(err: unknown): err is Error & {
|
|
45
|
-
_tag: 'ConfigSchemaError';
|
|
46
|
-
filePath: string;
|
|
47
|
-
trust: ConfigSource['trust'];
|
|
48
|
-
issues: readonly z.core.$ZodIssue[];
|
|
49
|
-
};
|
|
50
29
|
export declare function loadConfig(projectDir: string): SystematicConfig;
|
|
51
30
|
export declare function loadConfigWithSources(projectDir: string): SourceAwareConfigResult;
|
|
52
31
|
export declare function getConfigPaths(projectDir: string): {
|
|
@@ -57,4 +36,3 @@ export declare function getConfigPaths(projectDir: string): {
|
|
|
57
36
|
userDir: string;
|
|
58
37
|
projectDir: string;
|
|
59
38
|
};
|
|
60
|
-
export {};
|
package/package.json
CHANGED
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Per-process register-once guard for the Systematic plugin factory.
|
|
3
|
-
*
|
|
4
|
-
* OpenCode invokes the plugin factory more than once per process when the
|
|
5
|
-
* same plugin is referenced by multiple config sources (for example a
|
|
6
|
-
* user-level `~/.config/opencode/opencode.json` AND a project-level
|
|
7
|
-
* `opencode.json`). Each invocation evaluates the plugin module fresh —
|
|
8
|
-
* module-local variables reset between calls — so the guard state must
|
|
9
|
-
* live on `globalThis` to persist across module instances within the
|
|
10
|
-
* same process.
|
|
11
|
-
*
|
|
12
|
-
* On the first invocation `doInit` runs and the resulting hooks promise
|
|
13
|
-
* is cached on `globalThis`; the caller receives `{ isFirst: true, hooks }`.
|
|
14
|
-
* On every subsequent invocation in the same PID `doInit` is skipped and
|
|
15
|
-
* the cached resolved hooks are returned directly to every caller.
|
|
16
|
-
* Across PIDs the guard is treated as absent and init runs fresh —
|
|
17
|
-
* `globalThis` is per-process, but the explicit PID check adds defensive
|
|
18
|
-
* belt-and-suspenders against any state-leakage edge case.
|
|
19
|
-
*
|
|
20
|
-
* The singleton returns the same hooks reference to every caller within a
|
|
21
|
-
* process — first and duplicate alike. OpenCode may register the same hook
|
|
22
|
-
* surface once per configured plugin source; that is preferable to suppressing
|
|
23
|
-
* duplicates with an empty object because every source keeps the full tools,
|
|
24
|
-
* commands, skills, and hooks surface.
|
|
25
|
-
*
|
|
26
|
-
* **Known limitation — rejected init is sticky.** If `doInit()` rejects,
|
|
27
|
-
* the rejected promise is stored on `globalThis` and every subsequent
|
|
28
|
-
* invocation in the same PID returns the same rejection without retrying
|
|
29
|
-
* init. This is intentional: re-running heavy init on every call would
|
|
30
|
-
* defeat the guard's purpose. Recovery requires a process restart.
|
|
31
|
-
*/
|
|
32
|
-
export interface PlugInOnceOptions<T> {
|
|
33
|
-
/** Heavy init work that should run at most once per process. */
|
|
34
|
-
doInit: () => Promise<T>;
|
|
35
|
-
/** Test override; defaults to `process.pid`. */
|
|
36
|
-
pid?: number;
|
|
37
|
-
}
|
|
38
|
-
/**
|
|
39
|
-
* Result envelope for `plugInOnce(...)`.
|
|
40
|
-
*
|
|
41
|
-
* - `isFirst: true` — caller was the first invocation in this process.
|
|
42
|
-
* - `isFirst: false` — `doInit` was skipped; the cached result is returned.
|
|
43
|
-
*
|
|
44
|
-
* In both cases `hooks` is the real resolved value of `doInit()`. Callers
|
|
45
|
-
* return `result.hooks` unconditionally without inspecting `isFirst`.
|
|
46
|
-
*/
|
|
47
|
-
export interface PlugInOnceResult<T> {
|
|
48
|
-
isFirst: boolean;
|
|
49
|
-
hooks: T;
|
|
50
|
-
}
|
|
51
|
-
/**
|
|
52
|
-
* Run `doInit` at most once per process; on duplicate invocations return the
|
|
53
|
-
* cached real hook surface so every config source sees the same surface.
|
|
54
|
-
*/
|
|
55
|
-
export declare function plugInOnce<T>({ doInit, pid, }: PlugInOnceOptions<T>): Promise<PlugInOnceResult<T>>;
|
|
56
|
-
/**
|
|
57
|
-
* Test-only: clear the singleton state so the next invocation re-runs
|
|
58
|
-
* init. Must not be called in production code paths.
|
|
59
|
-
*/
|
|
60
|
-
export declare function _resetPluginSingleton(): void;
|
|
File without changes
|