@shrkcrft/pipelines 0.1.0-alpha.2
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/LICENSE +21 -0
- package/README.md +15 -0
- package/dist/define/define-pipeline.d.ts +3 -0
- package/dist/define/define-pipeline.d.ts.map +1 -0
- package/dist/define/define-pipeline.js +28 -0
- package/dist/format/pipeline-formatter.d.ts +4 -0
- package/dist/format/pipeline-formatter.d.ts.map +1 -0
- package/dist/format/pipeline-formatter.js +57 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +9 -0
- package/dist/load/pipeline-loader.d.ts +12 -0
- package/dist/load/pipeline-loader.d.ts.map +1 -0
- package/dist/load/pipeline-loader.js +52 -0
- package/dist/model/pipeline-definition.d.ts +21 -0
- package/dist/model/pipeline-definition.d.ts.map +1 -0
- package/dist/model/pipeline-definition.js +1 -0
- package/dist/model/pipeline-input.d.ts +10 -0
- package/dist/model/pipeline-input.d.ts.map +1 -0
- package/dist/model/pipeline-input.js +1 -0
- package/dist/model/pipeline-step.d.ts +43 -0
- package/dist/model/pipeline-step.d.ts.map +1 -0
- package/dist/model/pipeline-step.js +19 -0
- package/dist/registry/pipeline-registry.d.ts +16 -0
- package/dist/registry/pipeline-registry.d.ts.map +1 -0
- package/dist/registry/pipeline-registry.js +64 -0
- package/dist/runtime/interpolate.d.ts +48 -0
- package/dist/runtime/interpolate.d.ts.map +1 -0
- package/dist/runtime/interpolate.js +67 -0
- package/dist/runtime/render-script.d.ts +19 -0
- package/dist/runtime/render-script.d.ts.map +1 -0
- package/dist/runtime/render-script.js +68 -0
- package/package.json +51 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 SharkCraft contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# @shrkcrft/pipelines
|
|
2
|
+
|
|
3
|
+
SharkCraft AI development pipelines: typed flow definitions, registry, loader, formatter.
|
|
4
|
+
|
|
5
|
+
Part of [SharkCraft](https://github.com/shrkcrft/sharkcraft) — a deterministic, local-first toolkit that gives AI coding agents durable project context. See the main repo for documentation, examples, and the `shrk` CLI.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
bun add @shrkcrft/pipelines
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## License
|
|
14
|
+
|
|
15
|
+
MIT — see [LICENSE](./LICENSE).
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"define-pipeline.d.ts","sourceRoot":"","sources":["../../src/define/define-pipeline.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,mBAAmB,EACnB,uBAAuB,EACxB,MAAM,iCAAiC,CAAC;AAEzC,wBAAgB,cAAc,CAAC,KAAK,EAAE,uBAAuB,GAAG,mBAAmB,CAyBlF"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export function definePipeline(input) {
|
|
2
|
+
if (!input.id)
|
|
3
|
+
throw new Error("definePipeline: 'id' is required");
|
|
4
|
+
if (!input.title)
|
|
5
|
+
throw new Error(`definePipeline: 'title' is required for ${input.id}`);
|
|
6
|
+
if (!Array.isArray(input.steps) || input.steps.length === 0) {
|
|
7
|
+
throw new Error(`definePipeline: ${input.id} must have at least one step`);
|
|
8
|
+
}
|
|
9
|
+
const ids = new Set();
|
|
10
|
+
for (const step of input.steps) {
|
|
11
|
+
if (!step.id) {
|
|
12
|
+
throw new Error(`definePipeline: ${input.id}: every step needs an id`);
|
|
13
|
+
}
|
|
14
|
+
if (ids.has(step.id)) {
|
|
15
|
+
throw new Error(`definePipeline: ${input.id}: duplicate step id "${step.id}"`);
|
|
16
|
+
}
|
|
17
|
+
ids.add(step.id);
|
|
18
|
+
}
|
|
19
|
+
return {
|
|
20
|
+
...input,
|
|
21
|
+
tags: input.tags ? Object.freeze([...input.tags]) : undefined,
|
|
22
|
+
scope: input.scope ? Object.freeze([...input.scope]) : undefined,
|
|
23
|
+
appliesWhen: input.appliesWhen ? Object.freeze([...input.appliesWhen]) : undefined,
|
|
24
|
+
inputs: input.inputs ? Object.freeze([...input.inputs]) : undefined,
|
|
25
|
+
steps: Object.freeze([...input.steps]),
|
|
26
|
+
notes: input.notes ? Object.freeze([...input.notes]) : undefined,
|
|
27
|
+
};
|
|
28
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { IPipelineDefinition } from '../model/pipeline-definition.js';
|
|
2
|
+
export declare function formatPipelineCompact(p: IPipelineDefinition): string;
|
|
3
|
+
export declare function formatPipelineFull(p: IPipelineDefinition): string;
|
|
4
|
+
//# sourceMappingURL=pipeline-formatter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pipeline-formatter.d.ts","sourceRoot":"","sources":["../../src/format/pipeline-formatter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,iCAAiC,CAAC;AAE3E,wBAAgB,qBAAqB,CAAC,CAAC,EAAE,mBAAmB,GAAG,MAAM,CAIpE;AAED,wBAAgB,kBAAkB,CAAC,CAAC,EAAE,mBAAmB,GAAG,MAAM,CA0CjE"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
export function formatPipelineCompact(p) {
|
|
2
|
+
const tags = (p.tags ?? []).length ? ` tags=[${(p.tags ?? []).join(', ')}]` : '';
|
|
3
|
+
const stepWord = p.steps.length === 1 ? 'step' : 'steps';
|
|
4
|
+
return `${p.id.padEnd(28)} ${p.steps.length} ${stepWord} — ${p.title}${tags}`;
|
|
5
|
+
}
|
|
6
|
+
export function formatPipelineFull(p) {
|
|
7
|
+
const lines = [];
|
|
8
|
+
lines.push(`# Pipeline: ${p.title}`);
|
|
9
|
+
lines.push(`id: ${p.id}`);
|
|
10
|
+
if (p.tags?.length)
|
|
11
|
+
lines.push(`tags: ${p.tags.join(', ')}`);
|
|
12
|
+
if (p.scope?.length)
|
|
13
|
+
lines.push(`scope: ${p.scope.join(', ')}`);
|
|
14
|
+
if (p.appliesWhen?.length)
|
|
15
|
+
lines.push(`appliesWhen: ${p.appliesWhen.join(', ')}`);
|
|
16
|
+
lines.push('');
|
|
17
|
+
lines.push(p.description);
|
|
18
|
+
if (p.inputs?.length) {
|
|
19
|
+
lines.push('');
|
|
20
|
+
lines.push('## Inputs');
|
|
21
|
+
for (const i of p.inputs) {
|
|
22
|
+
const req = i.required ? ' (required)' : '';
|
|
23
|
+
const def = i.default !== undefined ? ` = ${i.default}` : '';
|
|
24
|
+
const choices = i.choices?.length ? ` choices=[${i.choices.join(', ')}]` : '';
|
|
25
|
+
const desc = i.description ? ` — ${i.description}` : '';
|
|
26
|
+
lines.push(`- ${i.name}${req}${def}${choices}${desc}`);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
lines.push('');
|
|
30
|
+
lines.push('## Steps');
|
|
31
|
+
for (let idx = 0; idx < p.steps.length; idx += 1) {
|
|
32
|
+
const step = p.steps[idx];
|
|
33
|
+
const req = step.required === false ? ' (optional)' : '';
|
|
34
|
+
const review = step.humanReview ? ' — human review' : '';
|
|
35
|
+
const when = step.enabledWhen ? ` — enabledWhen ${step.enabledWhen}` : '';
|
|
36
|
+
lines.push(`${idx + 1}. [${step.type}] ${step.id}${req}${review}${when}`);
|
|
37
|
+
if (step.description)
|
|
38
|
+
lines.push(` ${step.description}`);
|
|
39
|
+
if (step.instruction)
|
|
40
|
+
lines.push(` instruction: ${step.instruction}`);
|
|
41
|
+
if (step.mcpTools?.length)
|
|
42
|
+
lines.push(` mcpTools: ${step.mcpTools.join(', ')}`);
|
|
43
|
+
if (step.cliCommands?.length) {
|
|
44
|
+
for (const c of step.cliCommands)
|
|
45
|
+
lines.push(` $ ${c}`);
|
|
46
|
+
}
|
|
47
|
+
if (step.references?.length)
|
|
48
|
+
lines.push(` references: ${step.references.join(', ')}`);
|
|
49
|
+
}
|
|
50
|
+
if (p.notes?.length) {
|
|
51
|
+
lines.push('');
|
|
52
|
+
lines.push('## Notes');
|
|
53
|
+
for (const n of p.notes)
|
|
54
|
+
lines.push(`- ${n}`);
|
|
55
|
+
}
|
|
56
|
+
return lines.join('\n');
|
|
57
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export * from './model/pipeline-step.js';
|
|
2
|
+
export * from './model/pipeline-input.js';
|
|
3
|
+
export * from './model/pipeline-definition.js';
|
|
4
|
+
export * from './define/define-pipeline.js';
|
|
5
|
+
export * from './registry/pipeline-registry.js';
|
|
6
|
+
export * from './load/pipeline-loader.js';
|
|
7
|
+
export * from './format/pipeline-formatter.js';
|
|
8
|
+
export * from './runtime/interpolate.js';
|
|
9
|
+
export * from './runtime/render-script.js';
|
|
10
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,0BAA0B,CAAC;AACzC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,gCAAgC,CAAC;AAC/C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,iCAAiC,CAAC;AAChD,cAAc,2BAA2B,CAAC;AAC1C,cAAc,gCAAgC,CAAC;AAC/C,cAAc,0BAA0B,CAAC;AACzC,cAAc,4BAA4B,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export * from "./model/pipeline-step.js";
|
|
2
|
+
export * from "./model/pipeline-input.js";
|
|
3
|
+
export * from "./model/pipeline-definition.js";
|
|
4
|
+
export * from "./define/define-pipeline.js";
|
|
5
|
+
export * from "./registry/pipeline-registry.js";
|
|
6
|
+
export * from "./load/pipeline-loader.js";
|
|
7
|
+
export * from "./format/pipeline-formatter.js";
|
|
8
|
+
export * from "./runtime/interpolate.js";
|
|
9
|
+
export * from "./runtime/render-script.js";
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { type IImportContext } from '@shrkcrft/core';
|
|
2
|
+
import type { IPipelineDefinition } from '../model/pipeline-definition.js';
|
|
3
|
+
export interface ILoadedPipelines {
|
|
4
|
+
pipelines: IPipelineDefinition[];
|
|
5
|
+
warnings: string[];
|
|
6
|
+
sourceFiles: string[];
|
|
7
|
+
}
|
|
8
|
+
export interface ILoadPipelinesOptions {
|
|
9
|
+
importContext?: IImportContext;
|
|
10
|
+
}
|
|
11
|
+
export declare function loadPipelinesFromFile(filePath: string, options?: ILoadPipelinesOptions): Promise<ILoadedPipelines>;
|
|
12
|
+
//# sourceMappingURL=pipeline-loader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pipeline-loader.d.ts","sourceRoot":"","sources":["../../src/load/pipeline-loader.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,cAAc,EAAc,MAAM,gBAAgB,CAAC;AACjE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,iCAAiC,CAAC;AAa3E,MAAM,WAAW,gBAAgB;IAC/B,SAAS,EAAE,mBAAmB,EAAE,CAAC;IACjC,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,WAAW,EAAE,MAAM,EAAE,CAAC;CACvB;AAED,MAAM,WAAW,qBAAqB;IACpC,aAAa,CAAC,EAAE,cAAc,CAAC;CAChC;AAED,wBAAsB,qBAAqB,CACzC,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,qBAA0B,GAClC,OAAO,CAAC,gBAAgB,CAAC,CAwC3B"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { existsSync } from 'node:fs';
|
|
2
|
+
import { safeImport } from '@shrkcrft/core';
|
|
3
|
+
function isPipeline(value) {
|
|
4
|
+
if (!value || typeof value !== 'object')
|
|
5
|
+
return false;
|
|
6
|
+
const v = value;
|
|
7
|
+
return (typeof v.id === 'string' &&
|
|
8
|
+
typeof v.title === 'string' &&
|
|
9
|
+
typeof v.description === 'string' &&
|
|
10
|
+
Array.isArray(v.steps));
|
|
11
|
+
}
|
|
12
|
+
export async function loadPipelinesFromFile(filePath, options = {}) {
|
|
13
|
+
const warnings = [];
|
|
14
|
+
const pipelines = [];
|
|
15
|
+
const sourceFiles = [];
|
|
16
|
+
if (!existsSync(filePath)) {
|
|
17
|
+
warnings.push(`Pipeline file not found: ${filePath}`);
|
|
18
|
+
return { pipelines, warnings, sourceFiles };
|
|
19
|
+
}
|
|
20
|
+
sourceFiles.push(filePath);
|
|
21
|
+
const result = options.importContext
|
|
22
|
+
? await options.importContext.load(filePath)
|
|
23
|
+
: await safeImport(filePath, { skipExistsCheck: true });
|
|
24
|
+
if (!result.ok) {
|
|
25
|
+
const label = result.timedOut ? 'timed out importing' : 'Failed to import';
|
|
26
|
+
warnings.push(`${label} ${filePath}: ${result.error.message}`);
|
|
27
|
+
return { pipelines, warnings, sourceFiles };
|
|
28
|
+
}
|
|
29
|
+
const seen = new Set();
|
|
30
|
+
const tryPush = (v) => {
|
|
31
|
+
if (!isPipeline(v))
|
|
32
|
+
return;
|
|
33
|
+
if (seen.has(v.id))
|
|
34
|
+
return;
|
|
35
|
+
seen.add(v.id);
|
|
36
|
+
const p = { ...v, source: v.source ?? { origin: filePath } };
|
|
37
|
+
pipelines.push(p);
|
|
38
|
+
};
|
|
39
|
+
for (const key of Object.keys(result.module)) {
|
|
40
|
+
const v = result.module[key];
|
|
41
|
+
if (isPipeline(v)) {
|
|
42
|
+
tryPush(v);
|
|
43
|
+
}
|
|
44
|
+
else if (Array.isArray(v)) {
|
|
45
|
+
for (const item of v)
|
|
46
|
+
tryPush(item);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
if (pipelines.length === 0)
|
|
50
|
+
warnings.push(`No pipelines exported by ${filePath}`);
|
|
51
|
+
return { pipelines, warnings, sourceFiles };
|
|
52
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { IPipelineInput } from './pipeline-input.js';
|
|
2
|
+
import type { IPipelineStep } from './pipeline-step.js';
|
|
3
|
+
export interface IPipelineDefinition {
|
|
4
|
+
id: string;
|
|
5
|
+
title: string;
|
|
6
|
+
description: string;
|
|
7
|
+
tags?: readonly string[];
|
|
8
|
+
scope?: readonly string[];
|
|
9
|
+
/** Free-form task hints (e.g. "create-plugin"). Used for relevance lookup. */
|
|
10
|
+
appliesWhen?: readonly string[];
|
|
11
|
+
inputs?: readonly IPipelineInput[];
|
|
12
|
+
steps: readonly IPipelineStep[];
|
|
13
|
+
/** Free-form notes shown after the steps. */
|
|
14
|
+
notes?: readonly string[];
|
|
15
|
+
/** Originating file path. */
|
|
16
|
+
source?: {
|
|
17
|
+
origin?: string;
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
export type PipelineDefinitionInput = Omit<IPipelineDefinition, 'source'>;
|
|
21
|
+
//# sourceMappingURL=pipeline-definition.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pipeline-definition.d.ts","sourceRoot":"","sources":["../../src/model/pipeline-definition.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAC1D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAExD,MAAM,WAAW,mBAAmB;IAClC,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACzB,KAAK,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC1B,8EAA8E;IAC9E,WAAW,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAChC,MAAM,CAAC,EAAE,SAAS,cAAc,EAAE,CAAC;IACnC,KAAK,EAAE,SAAS,aAAa,EAAE,CAAC;IAChC,6CAA6C;IAC7C,KAAK,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC1B,6BAA6B;IAC7B,MAAM,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CAC9B;AAED,MAAM,MAAM,uBAAuB,GAAG,IAAI,CAAC,mBAAmB,EAAE,QAAQ,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export interface IPipelineInput {
|
|
2
|
+
name: string;
|
|
3
|
+
description?: string;
|
|
4
|
+
required?: boolean;
|
|
5
|
+
/** Optional default value (string). */
|
|
6
|
+
default?: string;
|
|
7
|
+
/** Restricted set of allowed values. */
|
|
8
|
+
choices?: readonly string[];
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=pipeline-input.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pipeline-input.d.ts","sourceRoot":"","sources":["../../src/model/pipeline-input.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,uCAAuC;IACvC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,wCAAwC;IACxC,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CAC7B"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Step type taxonomy. Steps are declarative; SharkCraft does not run them.
|
|
3
|
+
* Pipelines are retrieval-shaped so an agent can read the plan and follow it.
|
|
4
|
+
*/
|
|
5
|
+
export declare enum PipelineStepType {
|
|
6
|
+
/** Build / load context (no side effects). */
|
|
7
|
+
Context = "context",
|
|
8
|
+
/** Agent-driven thinking step (instruction-only). */
|
|
9
|
+
Agent = "agent",
|
|
10
|
+
/** Produce a generation plan (dry-run only via MCP / CLI gen --dry-run). */
|
|
11
|
+
GenerationPlan = "generation-plan",
|
|
12
|
+
/** Apply a saved plan (CLI-only). */
|
|
13
|
+
ApplyPlan = "apply-plan",
|
|
14
|
+
/** Run a shell command. */
|
|
15
|
+
Command = "command",
|
|
16
|
+
/** Call an MCP tool. */
|
|
17
|
+
McpTool = "mcp-tool"
|
|
18
|
+
}
|
|
19
|
+
export interface IPipelineStep {
|
|
20
|
+
id: string;
|
|
21
|
+
/** Step type — gives the agent a clear class of action. */
|
|
22
|
+
type: PipelineStepType | string;
|
|
23
|
+
/** Short description shown alongside the step. */
|
|
24
|
+
description?: string;
|
|
25
|
+
/** MCP tool names referenced by this step. */
|
|
26
|
+
mcpTools?: readonly string[];
|
|
27
|
+
/** CLI command strings (with <placeholder> tokens). */
|
|
28
|
+
cliCommands?: readonly string[];
|
|
29
|
+
/** Agent instruction text (for type=agent). */
|
|
30
|
+
instruction?: string;
|
|
31
|
+
/** Default true: this step must run for the pipeline to succeed. */
|
|
32
|
+
required?: boolean;
|
|
33
|
+
/** True if a human must review the result before continuing. */
|
|
34
|
+
humanReview?: boolean;
|
|
35
|
+
/**
|
|
36
|
+
* Optional input name that gates this step. The CLI / MCP context builders
|
|
37
|
+
* pass it through as informational metadata; v1 does not evaluate it.
|
|
38
|
+
*/
|
|
39
|
+
enabledWhen?: string;
|
|
40
|
+
/** Optional reference to a knowledge entry / template / path convention. */
|
|
41
|
+
references?: readonly string[];
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=pipeline-step.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pipeline-step.d.ts","sourceRoot":"","sources":["../../src/model/pipeline-step.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,oBAAY,gBAAgB;IAC1B,8CAA8C;IAC9C,OAAO,YAAY;IACnB,qDAAqD;IACrD,KAAK,UAAU;IACf,4EAA4E;IAC5E,cAAc,oBAAoB;IAClC,qCAAqC;IACrC,SAAS,eAAe;IACxB,2BAA2B;IAC3B,OAAO,YAAY;IACnB,wBAAwB;IACxB,OAAO,aAAa;CACrB;AAED,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,2DAA2D;IAC3D,IAAI,EAAE,gBAAgB,GAAG,MAAM,CAAC;IAChC,kDAAkD;IAClD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,8CAA8C;IAC9C,QAAQ,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC7B,uDAAuD;IACvD,WAAW,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAChC,+CAA+C;IAC/C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,oEAAoE;IACpE,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,gEAAgE;IAChE,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,4EAA4E;IAC5E,UAAU,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CAChC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Step type taxonomy. Steps are declarative; SharkCraft does not run them.
|
|
3
|
+
* Pipelines are retrieval-shaped so an agent can read the plan and follow it.
|
|
4
|
+
*/
|
|
5
|
+
export var PipelineStepType;
|
|
6
|
+
(function (PipelineStepType) {
|
|
7
|
+
/** Build / load context (no side effects). */
|
|
8
|
+
PipelineStepType["Context"] = "context";
|
|
9
|
+
/** Agent-driven thinking step (instruction-only). */
|
|
10
|
+
PipelineStepType["Agent"] = "agent";
|
|
11
|
+
/** Produce a generation plan (dry-run only via MCP / CLI gen --dry-run). */
|
|
12
|
+
PipelineStepType["GenerationPlan"] = "generation-plan";
|
|
13
|
+
/** Apply a saved plan (CLI-only). */
|
|
14
|
+
PipelineStepType["ApplyPlan"] = "apply-plan";
|
|
15
|
+
/** Run a shell command. */
|
|
16
|
+
PipelineStepType["Command"] = "command";
|
|
17
|
+
/** Call an MCP tool. */
|
|
18
|
+
PipelineStepType["McpTool"] = "mcp-tool";
|
|
19
|
+
})(PipelineStepType || (PipelineStepType = {}));
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { IPipelineDefinition } from '../model/pipeline-definition.js';
|
|
2
|
+
export declare class PipelineRegistry {
|
|
3
|
+
private readonly byId;
|
|
4
|
+
constructor(pipelines?: readonly IPipelineDefinition[]);
|
|
5
|
+
register(pipeline: IPipelineDefinition): void;
|
|
6
|
+
has(id: string): boolean;
|
|
7
|
+
get(id: string): IPipelineDefinition | null;
|
|
8
|
+
list(): IPipelineDefinition[];
|
|
9
|
+
search(query: string): IPipelineDefinition[];
|
|
10
|
+
/**
|
|
11
|
+
* Crude relevance: bias by overlap of task words with appliesWhen / tags /
|
|
12
|
+
* title. Returns the top `limit` pipelines (default 5).
|
|
13
|
+
*/
|
|
14
|
+
relevantFor(task: string, limit?: number): IPipelineDefinition[];
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=pipeline-registry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pipeline-registry.d.ts","sourceRoot":"","sources":["../../src/registry/pipeline-registry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,iCAAiC,CAAC;AAE3E,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,QAAQ,CAAC,IAAI,CAA0C;gBAEnD,SAAS,GAAE,SAAS,mBAAmB,EAAO;IAI1D,QAAQ,CAAC,QAAQ,EAAE,mBAAmB,GAAG,IAAI;IAI7C,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO;IAIxB,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,mBAAmB,GAAG,IAAI;IAI3C,IAAI,IAAI,mBAAmB,EAAE;IAI7B,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,mBAAmB,EAAE;IAc5C;;;OAGG;IACH,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,SAAI,GAAG,mBAAmB,EAAE;CAwB5D"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
export class PipelineRegistry {
|
|
2
|
+
byId = new Map();
|
|
3
|
+
constructor(pipelines = []) {
|
|
4
|
+
for (const p of pipelines)
|
|
5
|
+
this.register(p);
|
|
6
|
+
}
|
|
7
|
+
register(pipeline) {
|
|
8
|
+
this.byId.set(pipeline.id, pipeline);
|
|
9
|
+
}
|
|
10
|
+
has(id) {
|
|
11
|
+
return this.byId.has(id);
|
|
12
|
+
}
|
|
13
|
+
get(id) {
|
|
14
|
+
return this.byId.get(id) ?? null;
|
|
15
|
+
}
|
|
16
|
+
list() {
|
|
17
|
+
return [...this.byId.values()];
|
|
18
|
+
}
|
|
19
|
+
search(query) {
|
|
20
|
+
const q = query.trim().toLowerCase();
|
|
21
|
+
if (!q)
|
|
22
|
+
return this.list();
|
|
23
|
+
return this.list().filter((p) => {
|
|
24
|
+
return (p.id.toLowerCase().includes(q) ||
|
|
25
|
+
p.title.toLowerCase().includes(q) ||
|
|
26
|
+
p.description.toLowerCase().includes(q) ||
|
|
27
|
+
(p.tags ?? []).some((t) => t.toLowerCase().includes(q)) ||
|
|
28
|
+
(p.appliesWhen ?? []).some((a) => a.toLowerCase().includes(q)));
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Crude relevance: bias by overlap of task words with appliesWhen / tags /
|
|
33
|
+
* title. Returns the top `limit` pipelines (default 5).
|
|
34
|
+
*/
|
|
35
|
+
relevantFor(task, limit = 5) {
|
|
36
|
+
const taskLower = task.toLowerCase();
|
|
37
|
+
const words = taskLower.split(/\W+/).filter((w) => w.length >= 3);
|
|
38
|
+
const scored = this.list().map((p) => {
|
|
39
|
+
let score = 0;
|
|
40
|
+
for (const tag of p.tags ?? []) {
|
|
41
|
+
if (taskLower.includes(tag.toLowerCase()))
|
|
42
|
+
score += 5;
|
|
43
|
+
}
|
|
44
|
+
for (const a of p.appliesWhen ?? []) {
|
|
45
|
+
if (taskLower.includes(a.toLowerCase()))
|
|
46
|
+
score += 6;
|
|
47
|
+
}
|
|
48
|
+
if (p.title.toLowerCase().includes(taskLower))
|
|
49
|
+
score += 4;
|
|
50
|
+
for (const w of words) {
|
|
51
|
+
if (p.id.toLowerCase().includes(w))
|
|
52
|
+
score += 2;
|
|
53
|
+
if (p.description.toLowerCase().includes(w))
|
|
54
|
+
score += 1;
|
|
55
|
+
}
|
|
56
|
+
return { p, score };
|
|
57
|
+
});
|
|
58
|
+
return scored
|
|
59
|
+
.filter((s) => s.score > 0)
|
|
60
|
+
.sort((a, b) => b.score - a.score)
|
|
61
|
+
.slice(0, limit)
|
|
62
|
+
.map((s) => s.p);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import type { IPipelineDefinition } from '../model/pipeline-definition.js';
|
|
2
|
+
export interface IInterpolatedStep {
|
|
3
|
+
id: string;
|
|
4
|
+
type: string;
|
|
5
|
+
description?: string;
|
|
6
|
+
instruction?: string;
|
|
7
|
+
mcpTools: readonly string[];
|
|
8
|
+
cliCommands: readonly string[];
|
|
9
|
+
references: readonly string[];
|
|
10
|
+
required: boolean;
|
|
11
|
+
humanReview: boolean;
|
|
12
|
+
enabledWhen?: string;
|
|
13
|
+
/** True if this step was skipped because of enabledWhen and the user did not opt in. */
|
|
14
|
+
skipped: boolean;
|
|
15
|
+
}
|
|
16
|
+
export interface IInterpolatedPipeline {
|
|
17
|
+
id: string;
|
|
18
|
+
title: string;
|
|
19
|
+
description: string;
|
|
20
|
+
task: string;
|
|
21
|
+
inputs: Record<string, string>;
|
|
22
|
+
steps: IInterpolatedStep[];
|
|
23
|
+
}
|
|
24
|
+
export interface InterpolatePipelineOptions {
|
|
25
|
+
task: string;
|
|
26
|
+
projectRoot?: string;
|
|
27
|
+
/** Named inputs passed by the agent / user. */
|
|
28
|
+
inputs?: Record<string, string>;
|
|
29
|
+
/** Set of optional step ids to include. Pass '*' to include all optional steps. */
|
|
30
|
+
includeOptional?: readonly string[];
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Interpolate placeholders in the pipeline's CLI commands / instructions /
|
|
34
|
+
* descriptions. Returns the resolved step list and a record of every value
|
|
35
|
+
* used (for traceability).
|
|
36
|
+
*
|
|
37
|
+
* Placeholders supported:
|
|
38
|
+
* - <task> → options.task
|
|
39
|
+
* - <repo> → options.projectRoot
|
|
40
|
+
* - <pipelineId> → the pipeline id
|
|
41
|
+
* - <name> → options.inputs.name etc.
|
|
42
|
+
*
|
|
43
|
+
* Optional steps (`required: false`) are dropped unless their id is listed in
|
|
44
|
+
* `includeOptional` (or `*`). Steps with `enabledWhen` are dropped unless
|
|
45
|
+
* `enabledWhen` is included in `includeOptional`.
|
|
46
|
+
*/
|
|
47
|
+
export declare function interpolatePipeline(pipeline: IPipelineDefinition, options: InterpolatePipelineOptions): IInterpolatedPipeline;
|
|
48
|
+
//# sourceMappingURL=interpolate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"interpolate.d.ts","sourceRoot":"","sources":["../../src/runtime/interpolate.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,iCAAiC,CAAC;AAG3E,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAC;IAC5B,WAAW,EAAE,SAAS,MAAM,EAAE,CAAC;IAC/B,UAAU,EAAE,SAAS,MAAM,EAAE,CAAC;IAC9B,QAAQ,EAAE,OAAO,CAAC;IAClB,WAAW,EAAE,OAAO,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,wFAAwF;IACxF,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,qBAAqB;IACpC,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/B,KAAK,EAAE,iBAAiB,EAAE,CAAC;CAC5B;AAED,MAAM,WAAW,0BAA0B;IACzC,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,+CAA+C;IAC/C,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,mFAAmF;IACnF,eAAe,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CACrC;AASD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,mBAAmB,EAC7B,OAAO,EAAE,0BAA0B,GAClC,qBAAqB,CA2CvB"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
function applyPlaceholders(input, values) {
|
|
2
|
+
return input.replace(/<([a-zA-Z][a-zA-Z0-9_-]*)>/g, (whole, key) => {
|
|
3
|
+
if (Object.prototype.hasOwnProperty.call(values, key))
|
|
4
|
+
return values[key];
|
|
5
|
+
return whole;
|
|
6
|
+
});
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Interpolate placeholders in the pipeline's CLI commands / instructions /
|
|
10
|
+
* descriptions. Returns the resolved step list and a record of every value
|
|
11
|
+
* used (for traceability).
|
|
12
|
+
*
|
|
13
|
+
* Placeholders supported:
|
|
14
|
+
* - <task> → options.task
|
|
15
|
+
* - <repo> → options.projectRoot
|
|
16
|
+
* - <pipelineId> → the pipeline id
|
|
17
|
+
* - <name> → options.inputs.name etc.
|
|
18
|
+
*
|
|
19
|
+
* Optional steps (`required: false`) are dropped unless their id is listed in
|
|
20
|
+
* `includeOptional` (or `*`). Steps with `enabledWhen` are dropped unless
|
|
21
|
+
* `enabledWhen` is included in `includeOptional`.
|
|
22
|
+
*/
|
|
23
|
+
export function interpolatePipeline(pipeline, options) {
|
|
24
|
+
const values = {
|
|
25
|
+
task: options.task,
|
|
26
|
+
repo: options.projectRoot ?? '<repo>',
|
|
27
|
+
pipelineId: pipeline.id,
|
|
28
|
+
...(options.inputs),
|
|
29
|
+
};
|
|
30
|
+
const includeAll = options.includeOptional?.includes('*') === true;
|
|
31
|
+
const includeSet = new Set(options.includeOptional ?? []);
|
|
32
|
+
function resolveStep(step) {
|
|
33
|
+
const requiredDefault = step.required !== false;
|
|
34
|
+
let skipped = false;
|
|
35
|
+
if (!requiredDefault && !includeAll && !includeSet.has(step.id)) {
|
|
36
|
+
skipped = true;
|
|
37
|
+
}
|
|
38
|
+
if (step.enabledWhen && !includeAll && !includeSet.has(step.enabledWhen) && !includeSet.has(step.id)) {
|
|
39
|
+
skipped = true;
|
|
40
|
+
}
|
|
41
|
+
const out = {
|
|
42
|
+
id: step.id,
|
|
43
|
+
type: step.type,
|
|
44
|
+
required: requiredDefault,
|
|
45
|
+
humanReview: step.humanReview === true,
|
|
46
|
+
mcpTools: step.mcpTools ?? [],
|
|
47
|
+
cliCommands: (step.cliCommands ?? []).map((c) => applyPlaceholders(c, values)),
|
|
48
|
+
references: step.references ?? [],
|
|
49
|
+
skipped,
|
|
50
|
+
};
|
|
51
|
+
if (step.description !== undefined)
|
|
52
|
+
out.description = applyPlaceholders(step.description, values);
|
|
53
|
+
if (step.instruction !== undefined)
|
|
54
|
+
out.instruction = applyPlaceholders(step.instruction, values);
|
|
55
|
+
if (step.enabledWhen !== undefined)
|
|
56
|
+
out.enabledWhen = step.enabledWhen;
|
|
57
|
+
return out;
|
|
58
|
+
}
|
|
59
|
+
return {
|
|
60
|
+
id: pipeline.id,
|
|
61
|
+
title: pipeline.title,
|
|
62
|
+
description: pipeline.description,
|
|
63
|
+
task: options.task,
|
|
64
|
+
inputs: values,
|
|
65
|
+
steps: pipeline.steps.map(resolveStep),
|
|
66
|
+
};
|
|
67
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { IInterpolatedPipeline } from './interpolate.js';
|
|
2
|
+
/**
|
|
3
|
+
* Render a copy-pasteable shell script from an interpolated pipeline. The
|
|
4
|
+
* script:
|
|
5
|
+
* - sets `set -euo pipefail` at the top so failures stop the chain
|
|
6
|
+
* - prefixes each step with a `# === N. step-id ===` header
|
|
7
|
+
* - emits CLI commands verbatim (already interpolated)
|
|
8
|
+
* - skips steps marked `skipped`
|
|
9
|
+
* - inserts an "echo + manual confirm" stanza in front of write/apply steps
|
|
10
|
+
* - leaves agent / mcp-tool steps as no-op `echo` lines (those are agent
|
|
11
|
+
* actions, not shell commands)
|
|
12
|
+
*/
|
|
13
|
+
export declare function renderPipelineScript(pipeline: IInterpolatedPipeline): string;
|
|
14
|
+
/**
|
|
15
|
+
* Find the next required, not-yet-marked-done step. Useful for an agent or
|
|
16
|
+
* the CLI that wants to ask "what should I do now?".
|
|
17
|
+
*/
|
|
18
|
+
export declare function findNextStep(pipeline: IInterpolatedPipeline): IInterpolatedPipeline['steps'][number] | null;
|
|
19
|
+
//# sourceMappingURL=render-script.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"render-script.d.ts","sourceRoot":"","sources":["../../src/runtime/render-script.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,kBAAkB,CAAC;AAI9D;;;;;;;;;;GAUG;AACH,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,qBAAqB,GAAG,MAAM,CA0C5E;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,qBAAqB,GAAG,qBAAqB,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,GAAG,IAAI,CAM3G"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
const WRITE_STEP_TYPES = new Set(['apply-plan']);
|
|
2
|
+
/**
|
|
3
|
+
* Render a copy-pasteable shell script from an interpolated pipeline. The
|
|
4
|
+
* script:
|
|
5
|
+
* - sets `set -euo pipefail` at the top so failures stop the chain
|
|
6
|
+
* - prefixes each step with a `# === N. step-id ===` header
|
|
7
|
+
* - emits CLI commands verbatim (already interpolated)
|
|
8
|
+
* - skips steps marked `skipped`
|
|
9
|
+
* - inserts an "echo + manual confirm" stanza in front of write/apply steps
|
|
10
|
+
* - leaves agent / mcp-tool steps as no-op `echo` lines (those are agent
|
|
11
|
+
* actions, not shell commands)
|
|
12
|
+
*/
|
|
13
|
+
export function renderPipelineScript(pipeline) {
|
|
14
|
+
const lines = [];
|
|
15
|
+
lines.push('#!/usr/bin/env bash');
|
|
16
|
+
lines.push('# Generated by `shrk pipelines script`.');
|
|
17
|
+
lines.push(`# Pipeline: ${pipeline.id} — ${pipeline.title}`);
|
|
18
|
+
lines.push(`# Task: ${pipeline.task}`);
|
|
19
|
+
lines.push('set -euo pipefail');
|
|
20
|
+
lines.push('');
|
|
21
|
+
let stepIndex = 0;
|
|
22
|
+
for (const step of pipeline.steps) {
|
|
23
|
+
stepIndex += 1;
|
|
24
|
+
if (step.skipped) {
|
|
25
|
+
lines.push(`# === ${stepIndex}. ${step.id} (skipped — optional, not included) ===`);
|
|
26
|
+
lines.push('');
|
|
27
|
+
continue;
|
|
28
|
+
}
|
|
29
|
+
const reviewTag = step.humanReview ? ' [HUMAN REVIEW]' : '';
|
|
30
|
+
const optionalTag = step.required ? '' : ' (optional)';
|
|
31
|
+
lines.push(`# === ${stepIndex}. [${step.type}] ${step.id}${optionalTag}${reviewTag} ===`);
|
|
32
|
+
if (step.description)
|
|
33
|
+
lines.push(`# ${step.description.replace(/\n/g, '\n# ')}`);
|
|
34
|
+
if (step.instruction)
|
|
35
|
+
lines.push(`# instruction: ${step.instruction.replace(/\n/g, '\n# ')}`);
|
|
36
|
+
if (step.references.length) {
|
|
37
|
+
lines.push(`# references: ${step.references.join(', ')}`);
|
|
38
|
+
}
|
|
39
|
+
if (step.mcpTools.length) {
|
|
40
|
+
lines.push(`# mcpTools: ${step.mcpTools.join(', ')}`);
|
|
41
|
+
}
|
|
42
|
+
if (WRITE_STEP_TYPES.has(step.type)) {
|
|
43
|
+
lines.push('echo "About to write files. Confirm by pressing Enter, or Ctrl-C to abort."');
|
|
44
|
+
lines.push('read -r _');
|
|
45
|
+
}
|
|
46
|
+
if (step.cliCommands.length === 0 && step.type !== 'command' && step.type !== 'apply-plan') {
|
|
47
|
+
// Agent-only step: emit an echo so the script remains valid but no-op.
|
|
48
|
+
lines.push(`echo "→ ${step.id}: agent/mcp action — no shell command"`);
|
|
49
|
+
}
|
|
50
|
+
for (const cmd of step.cliCommands) {
|
|
51
|
+
lines.push(cmd);
|
|
52
|
+
}
|
|
53
|
+
lines.push('');
|
|
54
|
+
}
|
|
55
|
+
return lines.join('\n');
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Find the next required, not-yet-marked-done step. Useful for an agent or
|
|
59
|
+
* the CLI that wants to ask "what should I do now?".
|
|
60
|
+
*/
|
|
61
|
+
export function findNextStep(pipeline) {
|
|
62
|
+
for (const step of pipeline.steps) {
|
|
63
|
+
if (step.skipped)
|
|
64
|
+
continue;
|
|
65
|
+
return step;
|
|
66
|
+
}
|
|
67
|
+
return null;
|
|
68
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@shrkcrft/pipelines",
|
|
3
|
+
"version": "0.1.0-alpha.2",
|
|
4
|
+
"description": "SharkCraft AI development pipelines: typed flow definitions, registry, loader, formatter.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"author": "SharkCraft contributors",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"main": "./dist/index.js",
|
|
9
|
+
"types": "./dist/index.d.d.ts",
|
|
10
|
+
"exports": {
|
|
11
|
+
".": {
|
|
12
|
+
"types": "./dist/index.d.ts",
|
|
13
|
+
"bun": "./src/index.ts",
|
|
14
|
+
"import": "./dist/index.js",
|
|
15
|
+
"default": "./dist/index.js"
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
"files": [
|
|
19
|
+
"dist",
|
|
20
|
+
"README.md",
|
|
21
|
+
"LICENSE"
|
|
22
|
+
],
|
|
23
|
+
"repository": {
|
|
24
|
+
"type": "git",
|
|
25
|
+
"url": "git+https://github.com/shrkcrft/sharkcraft.git",
|
|
26
|
+
"directory": "packages/pipelines"
|
|
27
|
+
},
|
|
28
|
+
"homepage": "https://github.com/shrkcrft/sharkcraft",
|
|
29
|
+
"bugs": {
|
|
30
|
+
"url": "https://github.com/shrkcrft/sharkcraft/issues"
|
|
31
|
+
},
|
|
32
|
+
"keywords": [
|
|
33
|
+
"sharkcraft",
|
|
34
|
+
"pipelines",
|
|
35
|
+
"workflows",
|
|
36
|
+
"ai-agent"
|
|
37
|
+
],
|
|
38
|
+
"engines": {
|
|
39
|
+
"bun": ">=1.1.0",
|
|
40
|
+
"node": ">=18"
|
|
41
|
+
},
|
|
42
|
+
"scripts": {
|
|
43
|
+
"typecheck": "tsc --noEmit -p tsconfig.json"
|
|
44
|
+
},
|
|
45
|
+
"dependencies": {
|
|
46
|
+
"@shrkcrft/core": "^0.1.0-alpha.2"
|
|
47
|
+
},
|
|
48
|
+
"publishConfig": {
|
|
49
|
+
"access": "public"
|
|
50
|
+
}
|
|
51
|
+
}
|