omkit 0.4.8 → 0.8.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/CHANGELOG.md +188 -0
- package/README.md +169 -13
- package/dist/actions/chrome-page.d.ts +41 -0
- package/dist/actions/chrome-page.js +77 -29
- package/dist/actions/drive-page.d.ts +50 -0
- package/dist/actions/drive-page.js +68 -0
- package/dist/actions/index.d.ts +5 -3
- package/dist/actions/index.js +2 -1
- package/dist/actions/prompt.d.ts +32 -5
- package/dist/actions/prompt.js +92 -8
- package/dist/cli/commands/help.js +7 -0
- package/dist/cli/commands/init.js +1 -1
- package/dist/cli/commands/ls.d.ts +11 -4
- package/dist/cli/commands/ls.js +35 -15
- package/dist/cli/commands/mcp.d.ts +10 -0
- package/dist/cli/commands/mcp.js +13 -0
- package/dist/cli/commands/skill.d.ts +18 -0
- package/dist/cli/commands/skill.js +62 -0
- package/dist/cli/index.d.ts +8 -0
- package/dist/cli/index.js +78 -30
- package/dist/client/discover-child.d.ts +12 -0
- package/dist/client/discover-child.js +71 -0
- package/dist/client/discovery.d.ts +21 -1
- package/dist/client/discovery.js +139 -2
- package/dist/client/index.d.ts +2 -1
- package/dist/client/index.js +15 -5
- package/dist/client/outline.d.ts +35 -0
- package/dist/client/outline.js +100 -0
- package/dist/client/registry.d.ts +59 -0
- package/dist/client/runner.d.ts +12 -0
- package/dist/client/runner.js +16 -7
- package/dist/client/types.d.ts +14 -1
- package/dist/client/types.js +5 -1
- package/dist/core/ActionRun.d.ts +5 -0
- package/dist/core/ActionRun.js +9 -0
- package/dist/core/ExecutionTree.d.ts +40 -2
- package/dist/core/ExecutionTree.js +66 -2
- package/dist/core/action.d.ts +2 -1
- package/dist/core/action.js +93 -9
- package/dist/core/args.d.ts +50 -0
- package/dist/core/args.js +166 -0
- package/dist/core/discovery-mode.d.ts +37 -0
- package/dist/core/discovery-mode.js +54 -0
- package/dist/core/interaction.d.ts +3 -1
- package/dist/core/om.d.ts +11 -9
- package/dist/core/om.js +182 -13
- package/dist/core/schema-hint.d.ts +20 -0
- package/dist/core/schema-hint.js +73 -0
- package/dist/core/schema-json.d.ts +12 -0
- package/dist/core/schema-json.js +12 -0
- package/dist/core/types.d.ts +113 -1
- package/dist/foundation/LogEntry.d.ts +1 -1
- package/dist/foundation/canonicalPath.d.ts +26 -0
- package/dist/foundation/canonicalPath.js +34 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/dist/mcp/action-host.d.ts +1 -0
- package/dist/mcp/action-host.js +65 -0
- package/dist/mcp/action-identity.d.ts +23 -0
- package/dist/mcp/action-identity.js +35 -0
- package/dist/mcp/progress.d.ts +61 -0
- package/dist/mcp/progress.js +92 -0
- package/dist/mcp/resources.d.ts +55 -0
- package/dist/mcp/resources.js +208 -0
- package/dist/mcp/runs.d.ts +37 -0
- package/dist/mcp/runs.js +60 -0
- package/dist/mcp/server.d.ts +19 -0
- package/dist/mcp/server.js +38 -0
- package/dist/mcp/tail.d.ts +37 -0
- package/dist/mcp/tail.js +64 -0
- package/dist/mcp/tools.d.ts +54 -0
- package/dist/mcp/tools.js +378 -0
- package/dist/mcp/validate.d.ts +14 -0
- package/dist/mcp/validate.js +54 -0
- package/dist/mcp/verdict.d.ts +31 -0
- package/dist/mcp/verdict.js +47 -0
- package/dist/output/artifact/ArtifactStore.d.ts +24 -0
- package/dist/output/artifact/ArtifactStore.js +49 -0
- package/dist/output/folder/RunFolder.d.ts +23 -1
- package/dist/output/folder/RunFolder.js +70 -11
- package/dist/output/writers/views.d.ts +10 -0
- package/dist/skill/file.d.ts +26 -0
- package/dist/skill/file.js +58 -0
- package/dist/skill/index.d.ts +12 -0
- package/dist/skill/index.js +10 -0
- package/dist/skill/model.d.ts +69 -0
- package/dist/skill/model.js +200 -0
- package/dist/skill/render.d.ts +18 -0
- package/dist/skill/render.js +159 -0
- package/dist/skill/root.d.ts +15 -0
- package/dist/skill/root.js +27 -0
- package/package.json +5 -2
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
/** The skill's directory name, and so the `name:` in its frontmatter. */
|
|
2
|
+
export const SKILL_NAME = "omkit-runs";
|
|
3
|
+
/**
|
|
4
|
+
* The marker line that carries the staleness hash. Written by {@link renderSkill} and read
|
|
5
|
+
* back by the file layer, so the two agree on one format rather than two regexes.
|
|
6
|
+
*/
|
|
7
|
+
export const generatedBy = (hash) => `<!-- GENERATED by \`omkit skill\`. Do not edit. registry-hash: ${hash} -->`;
|
|
8
|
+
/**
|
|
9
|
+
* Render the model as the skill's markdown.
|
|
10
|
+
*
|
|
11
|
+
* Deterministic by construction: no timestamps, no absolute paths, no iteration over unordered
|
|
12
|
+
* collections — the model arrives sorted. A generated file that is committed and churns on
|
|
13
|
+
* every run is a file people stop reading.
|
|
14
|
+
*/
|
|
15
|
+
export function renderSkill(model, opts) {
|
|
16
|
+
const lines = [
|
|
17
|
+
"---",
|
|
18
|
+
`name: ${SKILL_NAME}`,
|
|
19
|
+
`description: ${opts.description}`,
|
|
20
|
+
"---",
|
|
21
|
+
"",
|
|
22
|
+
"# omkit — runnable workflows",
|
|
23
|
+
"",
|
|
24
|
+
generatedBy(model.hash),
|
|
25
|
+
"",
|
|
26
|
+
...howToRun(model),
|
|
27
|
+
...workflows(model),
|
|
28
|
+
...actions(model),
|
|
29
|
+
...whereOutputLands(model),
|
|
30
|
+
];
|
|
31
|
+
return `${lines.join("\n")}\n`;
|
|
32
|
+
}
|
|
33
|
+
function howToRun(model) {
|
|
34
|
+
// A long-lived om is the wrong thing to demonstrate `run` with: it never returns, and the
|
|
35
|
+
// entry's own heading says so a few lines further down. Prefer one that settles, and fall
|
|
36
|
+
// back to the long-lived one only when the project has nothing else — annotated, so the
|
|
37
|
+
// command still reads as deliberate rather than as an example that hangs.
|
|
38
|
+
const settling = model.oms.filter((o) => o.mode !== "long-lived");
|
|
39
|
+
const pool = settling.length ? settling : model.oms;
|
|
40
|
+
const example = pool[0];
|
|
41
|
+
const withArgs = pool.find((o) => o.argExample !== undefined);
|
|
42
|
+
const name = example?.name ?? "<om>";
|
|
43
|
+
const holds = example?.mode === "long-lived" ? " # long-lived: runs until you stop it" : "";
|
|
44
|
+
// Appended to every command, because omkit resolves its config against the working directory
|
|
45
|
+
// and this file's reader is at the project root, which is not necessarily where the config is.
|
|
46
|
+
const config = model.tsconfig ? ` --tsconfig ${model.tsconfig}` : "";
|
|
47
|
+
return [
|
|
48
|
+
"## How to run",
|
|
49
|
+
"",
|
|
50
|
+
"**Shell — always available.** Run these from the project root (the directory holding",
|
|
51
|
+
"`.claude/`); every path here is relative to it.",
|
|
52
|
+
"",
|
|
53
|
+
"```bash",
|
|
54
|
+
`npx omkit run ${shellName(name)}${config}${holds}`,
|
|
55
|
+
// Only when there is a real one to show. An `OMKIT_ARGS='{}'` line teaches the syntax and
|
|
56
|
+
// nothing else, and reads as though this project's runs take no arguments — which is the
|
|
57
|
+
// opposite of what it means when a project's args could not be sampled.
|
|
58
|
+
...(withArgs
|
|
59
|
+
? [
|
|
60
|
+
`OMKIT_ARGS='${JSON.stringify(withArgs.argExample)}' npx omkit run ${shellName(withArgs.name)}${config}`,
|
|
61
|
+
]
|
|
62
|
+
: []),
|
|
63
|
+
"```",
|
|
64
|
+
"",
|
|
65
|
+
"Arguments travel as one JSON object in `OMKIT_ARGS`. Anything an om declares but does not",
|
|
66
|
+
"receive is filled from the schema's defaults, and only then by asking.",
|
|
67
|
+
"",
|
|
68
|
+
'**MCP — if configured:** `run_om("<name>", { …args })` runs a settling workflow to',
|
|
69
|
+
"completion and returns its verdict; `start_om` starts a long-lived one and returns a run id",
|
|
70
|
+
"to poll with `get_run`, read with `tail_run`, and end with `cancel_run`.",
|
|
71
|
+
"",
|
|
72
|
+
`To wire it up: \`claude mcp add omkit -- npx omkit mcp${config}\``,
|
|
73
|
+
"",
|
|
74
|
+
"At runtime `list_oms` is authoritative — this file is orientation, and can drift.",
|
|
75
|
+
"",
|
|
76
|
+
];
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* An om's name as one shell argument.
|
|
80
|
+
*
|
|
81
|
+
* A name is free text — `om("DTF Tests")` is legal, and reads well in a log — but written bare
|
|
82
|
+
* into a command it stops being one argument: `omkit run DTF Tests` resolves the target as
|
|
83
|
+
* "DTF" and leaves "Tests" as a stray positional. So the file carries the quotes rather than
|
|
84
|
+
* leaving the reader to notice they are missing.
|
|
85
|
+
*
|
|
86
|
+
* Double quotes, not single, because cmd.exe and PowerShell understand them too. Names built
|
|
87
|
+
* from shell metacharacters beyond a quote or a backslash (`$`, backticks) are the author's to
|
|
88
|
+
* avoid — there is no quoting form that is literal in every shell at once.
|
|
89
|
+
*/
|
|
90
|
+
const shellName = (name) => /^[\w:.@/-]+$/.test(name) ? name : `"${name.replace(/([\\"])/g, "\\$1")}"`;
|
|
91
|
+
function workflows(model) {
|
|
92
|
+
if (model.oms.length === 0) {
|
|
93
|
+
return ["## Workflows", "", "_None exposed. Mark an om with `.mcp()` to list it here._", ""];
|
|
94
|
+
}
|
|
95
|
+
return ["## Workflows", "", ...model.oms.flatMap((om) => entry(om, omHeading(om)))];
|
|
96
|
+
}
|
|
97
|
+
function actions(model) {
|
|
98
|
+
if (model.actions.length === 0)
|
|
99
|
+
return [];
|
|
100
|
+
return [
|
|
101
|
+
"## Actions",
|
|
102
|
+
"",
|
|
103
|
+
"An action is a step, not a run. It cannot execute on its own — omkit hosts it in a",
|
|
104
|
+
"generated om so it has a run to belong to, which means it gets its own run folder and",
|
|
105
|
+
"verdict like anything else.",
|
|
106
|
+
"",
|
|
107
|
+
...model.actions.flatMap((a) => entry(a, `### \`${a.name}\``)),
|
|
108
|
+
];
|
|
109
|
+
}
|
|
110
|
+
function omHeading(om) {
|
|
111
|
+
const mode = om.mode === "long-lived" ? "long-lived · `start_om` only, it does not finish" : "settling";
|
|
112
|
+
return `### \`${om.name}\` — ${mode}`;
|
|
113
|
+
}
|
|
114
|
+
function entry(e, heading) {
|
|
115
|
+
const lines = [heading, ""];
|
|
116
|
+
lines.push(e.summary ?? "_No summary. The author can add one with `.describe({ summary })`._", "");
|
|
117
|
+
lines.push(`- **Defined in:** \`${e.file}\``);
|
|
118
|
+
if (e.kind === "action" && e.exportName)
|
|
119
|
+
lines.push(`- **Exported as:** \`${e.exportName}\``);
|
|
120
|
+
if (e.argHint)
|
|
121
|
+
lines.push(`- **Args:** \`${e.argHint}\``);
|
|
122
|
+
if (e.calls?.length)
|
|
123
|
+
lines.push(`- **Calls:** ${e.calls.map(renderCall).join(" → ")}`);
|
|
124
|
+
if (e.publishesCapability) {
|
|
125
|
+
lines.push("- **Publishes a capability.** It hands a live handle to whatever runs after it. Run on", " its own there is no downstream, so the handle goes nowhere — useful for a smoke test,", " not for the thing the capability was for.");
|
|
126
|
+
}
|
|
127
|
+
if (e.unavailable)
|
|
128
|
+
lines.push(`- **Not callable:** ${e.unavailable}`);
|
|
129
|
+
if (e.argSchema) {
|
|
130
|
+
lines.push("- **Args** (no short form — the schema is the contract):", "", "```json");
|
|
131
|
+
lines.push(JSON.stringify(e.argSchema, null, 2));
|
|
132
|
+
lines.push("```");
|
|
133
|
+
}
|
|
134
|
+
lines.push("");
|
|
135
|
+
return lines;
|
|
136
|
+
}
|
|
137
|
+
/** The model's paths are already posix, so the directory half is a plain string operation. */
|
|
138
|
+
const posixDirname = (file) => file.slice(0, Math.max(0, file.lastIndexOf("/")));
|
|
139
|
+
const renderCall = (c) => c.tag ? `\`${c.name}\` [${c.tag}]` : `\`${c.name}\``;
|
|
140
|
+
function whereOutputLands(model) {
|
|
141
|
+
// Spelled from the root the reader stands at, not as a bare `logs/`: the folder belongs to
|
|
142
|
+
// the project that owns the config, which in a subfolder layout is not where they are.
|
|
143
|
+
const dir = model.tsconfig ? posixDirname(model.tsconfig) : "";
|
|
144
|
+
const logs = dir ? `${dir}/logs` : "logs";
|
|
145
|
+
return [
|
|
146
|
+
"## Where output lands",
|
|
147
|
+
"",
|
|
148
|
+
`\`${logs}/<name>-<hash8>/<date>/<time>/\` — \`main.log\`, \`result.json\`, \`artifacts.log\`,`,
|
|
149
|
+
"`events.log`, `asserts.log`, `raw.jsonl`. A run's identity is its name plus its defining",
|
|
150
|
+
'file, so "the latest run of X" is always resolvable without parsing scrollback.',
|
|
151
|
+
"",
|
|
152
|
+
"## What the outlines above do and do not tell you",
|
|
153
|
+
"",
|
|
154
|
+
"**Calls** is a static reading of the body, not a trace. A conditional call is listed",
|
|
155
|
+
"unconditionally, a loop is listed once, an action chosen at runtime is not listed at all,",
|
|
156
|
+
'and a call made inside a helper function is invisible to it. Read it as "roughly what',
|
|
157
|
+
'happens in here" and read `result.json` for what actually did.',
|
|
158
|
+
];
|
|
159
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The directory a generated skill is written for: the nearest enclosing repository, or the
|
|
3
|
+
* project itself when there is none.
|
|
4
|
+
*
|
|
5
|
+
* The root is not really a free choice. A skill file lives at `.claude/skills/<name>/SKILL.md`,
|
|
6
|
+
* an assistant reads it with the repository as its working directory, and so every path and
|
|
7
|
+
* command inside has to be relative to *that* — not to wherever the om project's tsconfig
|
|
8
|
+
* happens to sit. Defaulting to the tsconfig's own directory made the common monorepo layout
|
|
9
|
+
* (an `om/` folder beside the code it drives) wrong by default, and needed a second flag to
|
|
10
|
+
* correct what the first flag had just decided.
|
|
11
|
+
*
|
|
12
|
+
* `.git` is checked as an entry, not as a directory: a worktree or submodule records it as a
|
|
13
|
+
* file containing a `gitdir:` pointer, and that is still the top of the checkout.
|
|
14
|
+
*/
|
|
15
|
+
export declare function skillRoot(projectDir: string): string;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
/**
|
|
4
|
+
* The directory a generated skill is written for: the nearest enclosing repository, or the
|
|
5
|
+
* project itself when there is none.
|
|
6
|
+
*
|
|
7
|
+
* The root is not really a free choice. A skill file lives at `.claude/skills/<name>/SKILL.md`,
|
|
8
|
+
* an assistant reads it with the repository as its working directory, and so every path and
|
|
9
|
+
* command inside has to be relative to *that* — not to wherever the om project's tsconfig
|
|
10
|
+
* happens to sit. Defaulting to the tsconfig's own directory made the common monorepo layout
|
|
11
|
+
* (an `om/` folder beside the code it drives) wrong by default, and needed a second flag to
|
|
12
|
+
* correct what the first flag had just decided.
|
|
13
|
+
*
|
|
14
|
+
* `.git` is checked as an entry, not as a directory: a worktree or submodule records it as a
|
|
15
|
+
* file containing a `gitdir:` pointer, and that is still the top of the checkout.
|
|
16
|
+
*/
|
|
17
|
+
export function skillRoot(projectDir) {
|
|
18
|
+
let dir = path.resolve(projectDir);
|
|
19
|
+
for (;;) {
|
|
20
|
+
if (fs.existsSync(path.join(dir, ".git")))
|
|
21
|
+
return dir;
|
|
22
|
+
const parent = path.dirname(dir);
|
|
23
|
+
if (parent === dir)
|
|
24
|
+
return path.resolve(projectDir);
|
|
25
|
+
dir = parent;
|
|
26
|
+
}
|
|
27
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "omkit",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.1",
|
|
4
4
|
"description": "A tiny runtime for developer workflows: typed actions that pass runtime capabilities and emit typed events, under one run and one shared log. The operational/runtime layer to tskb's knowledge layer.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -10,7 +10,8 @@
|
|
|
10
10
|
},
|
|
11
11
|
"files": [
|
|
12
12
|
"dist",
|
|
13
|
-
"LICENSE"
|
|
13
|
+
"LICENSE",
|
|
14
|
+
"CHANGELOG.md"
|
|
14
15
|
],
|
|
15
16
|
"exports": {
|
|
16
17
|
".": {
|
|
@@ -52,11 +53,13 @@
|
|
|
52
53
|
"developer-tools"
|
|
53
54
|
],
|
|
54
55
|
"dependencies": {
|
|
56
|
+
"@modelcontextprotocol/sdk": "^1.30.0",
|
|
55
57
|
"ink": "^7.1.1",
|
|
56
58
|
"patch-console": "^2.0.0",
|
|
57
59
|
"playwright-core": "^1.49.0",
|
|
58
60
|
"react": "^19.2.8",
|
|
59
61
|
"tsx": "4.23.1",
|
|
62
|
+
"zod": "^4.4.3",
|
|
60
63
|
"zx": "^8.8.5"
|
|
61
64
|
},
|
|
62
65
|
"devDependencies": {
|