@abaigram/abaikit 0.0.0-stage → 0.2.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.
- package/LICENSE +21 -0
- package/README.md +15 -2
- package/abai/identity.md +1 -0
- package/abai/learnabai.md +546 -0
- package/abai/use.md +1 -0
- package/abaigram.yaml +208 -0
- package/dist/abaify.d.ts +68 -0
- package/dist/abaify.d.ts.map +1 -0
- package/dist/abaify.js +310 -0
- package/dist/abaify.js.map +1 -0
- package/dist/abaigram.d.ts +18 -0
- package/dist/abaigram.d.ts.map +1 -0
- package/dist/abaigram.js +153 -0
- package/dist/abaigram.js.map +1 -0
- package/dist/app.d.ts +19 -0
- package/dist/app.d.ts.map +1 -0
- package/dist/app.js +29 -0
- package/dist/app.js.map +1 -0
- package/dist/bin.d.ts +46 -0
- package/dist/bin.d.ts.map +1 -0
- package/dist/bin.js +274 -0
- package/dist/bin.js.map +1 -0
- package/dist/check.d.ts +119 -0
- package/dist/check.d.ts.map +1 -0
- package/dist/check.js +416 -0
- package/dist/check.js.map +1 -0
- package/dist/command.d.ts +41 -0
- package/dist/command.d.ts.map +1 -0
- package/dist/command.js +179 -0
- package/dist/command.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -0
- package/dist/io.d.ts +12 -0
- package/dist/io.d.ts.map +1 -0
- package/dist/io.js +20 -0
- package/dist/io.js.map +1 -0
- package/dist/learnabai.d.ts +60 -0
- package/dist/learnabai.d.ts.map +1 -0
- package/dist/learnabai.js +199 -0
- package/dist/learnabai.js.map +1 -0
- package/dist/new.d.ts +26 -0
- package/dist/new.d.ts.map +1 -0
- package/dist/new.js +87 -0
- package/dist/new.js.map +1 -0
- package/dist/repo.d.ts +99 -0
- package/dist/repo.d.ts.map +1 -0
- package/dist/repo.js +482 -0
- package/dist/repo.js.map +1 -0
- package/dist/run.d.ts +6 -0
- package/dist/run.d.ts.map +1 -0
- package/dist/run.js +47 -0
- package/dist/run.js.map +1 -0
- package/dist/subject.d.ts +15 -0
- package/dist/subject.d.ts.map +1 -0
- package/dist/subject.js +53 -0
- package/dist/subject.js.map +1 -0
- package/dist/template-ts.d.ts +21 -0
- package/dist/template-ts.d.ts.map +1 -0
- package/dist/template-ts.js +322 -0
- package/dist/template-ts.js.map +1 -0
- package/dist/version.d.ts +3 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +3 -0
- package/dist/version.js.map +1 -0
- package/examples/hello/abai/identity.md +1 -0
- package/examples/hello/abaigram.yaml +24 -0
- package/examples/hello/hello.ts +18 -0
- package/package.json +40 -5
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { type Manifest } from "@abaigram/abai-stub";
|
|
2
|
+
export interface Subject {
|
|
3
|
+
root: string;
|
|
4
|
+
manifestPath: string;
|
|
5
|
+
manifest: Manifest;
|
|
6
|
+
}
|
|
7
|
+
/** The nearest ancestor of `start` (itself included) holding an abaigram.yaml. */
|
|
8
|
+
export declare function findSubjectRoot(start: string): string | undefined;
|
|
9
|
+
/** The subject at `path` (relative to `cwd`): a usage error when there is none or its manifest is not one. */
|
|
10
|
+
export declare function loadSubject(path: string, cwd: string): Subject;
|
|
11
|
+
/** One argument for `sh -c`, quoted so the shell passes it through whole. */
|
|
12
|
+
export declare function shellQuote(arg: string): string;
|
|
13
|
+
/** The entry's command line with words appended, for the shell in the root. */
|
|
14
|
+
export declare function entryCommand(manifest: Manifest, ...words: string[]): string;
|
|
15
|
+
//# sourceMappingURL=subject.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"subject.d.ts","sourceRoot":"","sources":["../src/subject.ts"],"names":[],"mappings":"AAMA,OAAO,EAAiB,KAAK,QAAQ,EAAuC,MAAM,qBAAqB,CAAC;AAGxG,MAAM,WAAW,OAAO;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,QAAQ,CAAC;CACnB;AAED,kFAAkF;AAClF,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAQjE;AAED,8GAA8G;AAC9G,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAiB9D;AAED,6EAA6E;AAC7E,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAG9C;AAED,+EAA+E;AAC/E,wBAAgB,YAAY,CAAC,QAAQ,EAAE,QAAQ,EAAE,GAAG,KAAK,EAAE,MAAM,EAAE,GAAG,MAAM,CAE3E","sourcesContent":["// A repository as check and run see it: its root, the nearest ancestor of\n// the given path holding abaigram.yaml, and that checked-in manifest,\n// parsed and validated. The tools reach the program only through the\n// manifest's entry, a command line run by the shell in the root.\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { dirname, join, resolve } from \"node:path\";\nimport { MANIFEST_FILE, type Manifest, parseManifestYaml, validateManifest } from \"@abaigram/abai-stub\";\nimport { UsageError } from \"./io.ts\";\n\nexport interface Subject {\n\troot: string;\n\tmanifestPath: string;\n\tmanifest: Manifest;\n}\n\n/** The nearest ancestor of `start` (itself included) holding an abaigram.yaml. */\nexport function findSubjectRoot(start: string): string | undefined {\n\tlet current = resolve(start);\n\tfor (;;) {\n\t\tif (existsSync(join(current, MANIFEST_FILE))) return current;\n\t\tconst parent = dirname(current);\n\t\tif (parent === current) return undefined;\n\t\tcurrent = parent;\n\t}\n}\n\n/** The subject at `path` (relative to `cwd`): a usage error when there is none or its manifest is not one. */\nexport function loadSubject(path: string, cwd: string): Subject {\n\tconst given = resolve(cwd, path);\n\tif (!existsSync(given)) throw new UsageError(`${path}: no such file or directory`);\n\tconst root = findSubjectRoot(given);\n\tif (root === undefined) {\n\t\tthrow new UsageError(`${path}: no ${MANIFEST_FILE} here or above it (is the repository an abaigram yet?)`);\n\t}\n\tconst manifestPath = join(root, MANIFEST_FILE);\n\tlet parsed: unknown;\n\ttry {\n\t\tparsed = parseManifestYaml(readFileSync(manifestPath, \"utf8\"));\n\t} catch (error) {\n\t\tthrow new UsageError(`${manifestPath} does not parse: ${error instanceof Error ? error.message : String(error)}`);\n\t}\n\tconst violations = validateManifest(parsed);\n\tif (violations.length > 0) throw new UsageError(`${manifestPath} does not validate: ${violations.join(\"; \")}`);\n\treturn { root, manifestPath, manifest: parsed as Manifest };\n}\n\n/** One argument for `sh -c`, quoted so the shell passes it through whole. */\nexport function shellQuote(arg: string): string {\n\tif (/^[A-Za-z0-9_./:=@%+,-]+$/.test(arg)) return arg;\n\treturn `'${arg.replaceAll(\"'\", \"'\\\\''\")}'`;\n}\n\n/** The entry's command line with words appended, for the shell in the root. */\nexport function entryCommand(manifest: Manifest, ...words: string[]): string {\n\treturn [manifest.entry, ...words.map(shellQuote)].join(\" \");\n}\n"]}
|
package/dist/subject.js
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
// A repository as check and run see it: its root, the nearest ancestor of
|
|
2
|
+
// the given path holding abaigram.yaml, and that checked-in manifest,
|
|
3
|
+
// parsed and validated. The tools reach the program only through the
|
|
4
|
+
// manifest's entry, a command line run by the shell in the root.
|
|
5
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
6
|
+
import { dirname, join, resolve } from "node:path";
|
|
7
|
+
import { MANIFEST_FILE, parseManifestYaml, validateManifest } from "@abaigram/abai-stub";
|
|
8
|
+
import { UsageError } from "./io.js";
|
|
9
|
+
/** The nearest ancestor of `start` (itself included) holding an abaigram.yaml. */
|
|
10
|
+
export function findSubjectRoot(start) {
|
|
11
|
+
let current = resolve(start);
|
|
12
|
+
for (;;) {
|
|
13
|
+
if (existsSync(join(current, MANIFEST_FILE)))
|
|
14
|
+
return current;
|
|
15
|
+
const parent = dirname(current);
|
|
16
|
+
if (parent === current)
|
|
17
|
+
return undefined;
|
|
18
|
+
current = parent;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
/** The subject at `path` (relative to `cwd`): a usage error when there is none or its manifest is not one. */
|
|
22
|
+
export function loadSubject(path, cwd) {
|
|
23
|
+
const given = resolve(cwd, path);
|
|
24
|
+
if (!existsSync(given))
|
|
25
|
+
throw new UsageError(`${path}: no such file or directory`);
|
|
26
|
+
const root = findSubjectRoot(given);
|
|
27
|
+
if (root === undefined) {
|
|
28
|
+
throw new UsageError(`${path}: no ${MANIFEST_FILE} here or above it (is the repository an abaigram yet?)`);
|
|
29
|
+
}
|
|
30
|
+
const manifestPath = join(root, MANIFEST_FILE);
|
|
31
|
+
let parsed;
|
|
32
|
+
try {
|
|
33
|
+
parsed = parseManifestYaml(readFileSync(manifestPath, "utf8"));
|
|
34
|
+
}
|
|
35
|
+
catch (error) {
|
|
36
|
+
throw new UsageError(`${manifestPath} does not parse: ${error instanceof Error ? error.message : String(error)}`);
|
|
37
|
+
}
|
|
38
|
+
const violations = validateManifest(parsed);
|
|
39
|
+
if (violations.length > 0)
|
|
40
|
+
throw new UsageError(`${manifestPath} does not validate: ${violations.join("; ")}`);
|
|
41
|
+
return { root, manifestPath, manifest: parsed };
|
|
42
|
+
}
|
|
43
|
+
/** One argument for `sh -c`, quoted so the shell passes it through whole. */
|
|
44
|
+
export function shellQuote(arg) {
|
|
45
|
+
if (/^[A-Za-z0-9_./:=@%+,-]+$/.test(arg))
|
|
46
|
+
return arg;
|
|
47
|
+
return `'${arg.replaceAll("'", "'\\''")}'`;
|
|
48
|
+
}
|
|
49
|
+
/** The entry's command line with words appended, for the shell in the root. */
|
|
50
|
+
export function entryCommand(manifest, ...words) {
|
|
51
|
+
return [manifest.entry, ...words.map(shellQuote)].join(" ");
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=subject.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"subject.js","sourceRoot":"","sources":["../src/subject.ts"],"names":[],"mappings":"AAAA,0EAA0E;AAC1E,sEAAsE;AACtE,qEAAqE;AACrE,iEAAiE;AACjE,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACnD,OAAO,EAAE,aAAa,EAAiB,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AACxG,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAQrC,kFAAkF;AAClF,MAAM,UAAU,eAAe,CAAC,KAAa,EAAsB;IAClE,IAAI,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC;IAC7B,SAAS,CAAC;QACT,IAAI,UAAU,CAAC,IAAI,CAAC,OAAO,EAAE,aAAa,CAAC,CAAC;YAAE,OAAO,OAAO,CAAC;QAC7D,MAAM,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;QAChC,IAAI,MAAM,KAAK,OAAO;YAAE,OAAO,SAAS,CAAC;QACzC,OAAO,GAAG,MAAM,CAAC;IAClB,CAAC;AAAA,CACD;AAED,8GAA8G;AAC9G,MAAM,UAAU,WAAW,CAAC,IAAY,EAAE,GAAW,EAAW;IAC/D,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;IACjC,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC;QAAE,MAAM,IAAI,UAAU,CAAC,GAAG,IAAI,6BAA6B,CAAC,CAAC;IACnF,MAAM,IAAI,GAAG,eAAe,CAAC,KAAK,CAAC,CAAC;IACpC,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;QACxB,MAAM,IAAI,UAAU,CAAC,GAAG,IAAI,QAAQ,aAAa,wDAAwD,CAAC,CAAC;IAC5G,CAAC;IACD,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,EAAE,aAAa,CAAC,CAAC;IAC/C,IAAI,MAAe,CAAC;IACpB,IAAI,CAAC;QACJ,MAAM,GAAG,iBAAiB,CAAC,YAAY,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC,CAAC;IAChE,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QAChB,MAAM,IAAI,UAAU,CAAC,GAAG,YAAY,oBAAoB,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IACnH,CAAC;IACD,MAAM,UAAU,GAAG,gBAAgB,CAAC,MAAM,CAAC,CAAC;IAC5C,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC;QAAE,MAAM,IAAI,UAAU,CAAC,GAAG,YAAY,uBAAuB,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC/G,OAAO,EAAE,IAAI,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAkB,EAAE,CAAC;AAAA,CAC5D;AAED,6EAA6E;AAC7E,MAAM,UAAU,UAAU,CAAC,GAAW,EAAU;IAC/C,IAAI,0BAA0B,CAAC,IAAI,CAAC,GAAG,CAAC;QAAE,OAAO,GAAG,CAAC;IACrD,OAAO,IAAI,GAAG,CAAC,UAAU,CAAC,GAAG,EAAE,OAAO,CAAC,GAAG,CAAC;AAAA,CAC3C;AAED,+EAA+E;AAC/E,MAAM,UAAU,YAAY,CAAC,QAAkB,EAAE,GAAG,KAAe,EAAU;IAC5E,OAAO,CAAC,QAAQ,CAAC,KAAK,EAAE,GAAG,KAAK,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAAA,CAC5D","sourcesContent":["// A repository as check and run see it: its root, the nearest ancestor of\n// the given path holding abaigram.yaml, and that checked-in manifest,\n// parsed and validated. The tools reach the program only through the\n// manifest's entry, a command line run by the shell in the root.\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { dirname, join, resolve } from \"node:path\";\nimport { MANIFEST_FILE, type Manifest, parseManifestYaml, validateManifest } from \"@abaigram/abai-stub\";\nimport { UsageError } from \"./io.ts\";\n\nexport interface Subject {\n\troot: string;\n\tmanifestPath: string;\n\tmanifest: Manifest;\n}\n\n/** The nearest ancestor of `start` (itself included) holding an abaigram.yaml. */\nexport function findSubjectRoot(start: string): string | undefined {\n\tlet current = resolve(start);\n\tfor (;;) {\n\t\tif (existsSync(join(current, MANIFEST_FILE))) return current;\n\t\tconst parent = dirname(current);\n\t\tif (parent === current) return undefined;\n\t\tcurrent = parent;\n\t}\n}\n\n/** The subject at `path` (relative to `cwd`): a usage error when there is none or its manifest is not one. */\nexport function loadSubject(path: string, cwd: string): Subject {\n\tconst given = resolve(cwd, path);\n\tif (!existsSync(given)) throw new UsageError(`${path}: no such file or directory`);\n\tconst root = findSubjectRoot(given);\n\tif (root === undefined) {\n\t\tthrow new UsageError(`${path}: no ${MANIFEST_FILE} here or above it (is the repository an abaigram yet?)`);\n\t}\n\tconst manifestPath = join(root, MANIFEST_FILE);\n\tlet parsed: unknown;\n\ttry {\n\t\tparsed = parseManifestYaml(readFileSync(manifestPath, \"utf8\"));\n\t} catch (error) {\n\t\tthrow new UsageError(`${manifestPath} does not parse: ${error instanceof Error ? error.message : String(error)}`);\n\t}\n\tconst violations = validateManifest(parsed);\n\tif (violations.length > 0) throw new UsageError(`${manifestPath} does not validate: ${violations.join(\"; \")}`);\n\treturn { root, manifestPath, manifest: parsed as Manifest };\n}\n\n/** One argument for `sh -c`, quoted so the shell passes it through whole. */\nexport function shellQuote(arg: string): string {\n\tif (/^[A-Za-z0-9_./:=@%+,-]+$/.test(arg)) return arg;\n\treturn `'${arg.replaceAll(\"'\", \"'\\\\''\")}'`;\n}\n\n/** The entry's command line with words appended, for the shell in the root. */\nexport function entryCommand(manifest: Manifest, ...words: string[]): string {\n\treturn [manifest.entry, ...words.map(shellQuote)].join(\" \");\n}\n"]}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { AbaigramOptions } from "@abaigram/abai-stub";
|
|
2
|
+
export type Level = 1 | 2 | 3 | 4;
|
|
3
|
+
export interface TemplateInput {
|
|
4
|
+
name: string;
|
|
5
|
+
level: Level;
|
|
6
|
+
/** The specifier the generated code imports the stub by; `@abaigram/abai-stub` unless a test points at the source. */
|
|
7
|
+
abaiImport: string;
|
|
8
|
+
/** What `package.json` depends on, in package.json form, and whether the packages are built workspace checkouts. */
|
|
9
|
+
packages: {
|
|
10
|
+
abai: string;
|
|
11
|
+
harness: string;
|
|
12
|
+
abaikit: string;
|
|
13
|
+
fromWorkspace: boolean;
|
|
14
|
+
built: boolean;
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
/** The declaration the program makes at this level, as the stub takes it. */
|
|
18
|
+
export declare function declarationsFor(input: TemplateInput): AbaigramOptions;
|
|
19
|
+
/** Every file of the new project, by path relative to its root. The manifest is rendered by the caller. */
|
|
20
|
+
export declare function templateFiles(input: TemplateInput): Record<string, string>;
|
|
21
|
+
//# sourceMappingURL=template-ts.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"template-ts.d.ts","sourceRoot":"","sources":["../src/template-ts.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,eAAe,EAAqB,MAAM,qBAAqB,CAAC;AAE9E,MAAM,MAAM,KAAK,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;AAElC,MAAM,WAAW,aAAa;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,KAAK,CAAC;IACb,sHAAsH;IACtH,UAAU,EAAE,MAAM,CAAC;IACnB,oHAAoH;IACpH,QAAQ,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,aAAa,EAAE,OAAO,CAAC;QAAC,KAAK,EAAE,OAAO,CAAA;KAAE,CAAC;CACrG;AAkDD,6EAA6E;AAC7E,wBAAgB,eAAe,CAAC,KAAK,EAAE,aAAa,GAAG,eAAe,CA+BrE;AAgPD,2GAA2G;AAC3G,wBAAgB,aAAa,CAAC,KAAK,EAAE,aAAa,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAqB1E","sourcesContent":["// The TypeScript template behind `abaikit new`: one declaration, as data,\n// rendered twice. Into the new project's `src/abai.ts` as source, and\n// through the stub's `buildManifest` into its `abaigram.yaml`, so file and\n// code agree without running the program. The program is a small loop\n// that works through a number of steps; at each level the declarations it\n// needs are live and the loop uses them, so `abaikit check` reaches that\n// level out of the box. Below its level every declaration kind is present\n// once, commented, as section 13 asks, and uncommenting one is all it\n// takes to make it live.\nimport type { AbaigramOptions, CapabilityOptions } from \"@abaigram/abai-stub\";\n\nexport type Level = 1 | 2 | 3 | 4;\n\nexport interface TemplateInput {\n\tname: string;\n\tlevel: Level;\n\t/** The specifier the generated code imports the stub by; `@abaigram/abai-stub` unless a test points at the source. */\n\tabaiImport: string;\n\t/** What `package.json` depends on, in package.json form, and whether the packages are built workspace checkouts. */\n\tpackages: { abai: string; harness: string; abaikit: string; fromWorkspace: boolean; built: boolean };\n}\n\n// The declaration's constants, each written once and read by both renderings.\nconst ENTRY = \"node src/main.ts abai\";\nconst MODES = [\"turns\", \"thread\", \"sidecar\"] as const;\nconst CONTENT = { identity: \"abai/identity.md\", use: \"abai/use.md\" };\nconst AUDIT = { path: \"./abai-audit.log\" };\nconst CHECK = { run: \"node src/main.ts 4\" };\nconst CELL_DONE = { type: \"int\", access: \"read\", doc: \"Steps finished so far.\" } as const;\nconst KNOB_PACE = {\n\ttype: \"int\",\n\taccess: \"readwrite\",\n\tdefault: 10,\n\trange: [1, 1000],\n\tdoc: \"Milliseconds a step takes; the agent may slow or hasten the work.\",\n} as const;\nconst EVENT_STEP = { payload: { n: \"int\" }, wakes: \"never\", doc: \"A step finished.\" } as const;\nconst CAPABILITY_SKIP: Omit<CapabilityOptions, \"handler\"> = {\n\tparams: { n: \"int\" },\n\tresult: { ok: \"bool\" },\n\teffect: \"mutate\",\n\tpolicy: \"confirm\",\n\tdispatch: \"immediate\",\n\t// step 2: the exercise's call lands while step 1 already runs, so this one is seen skipped under check\n\texample: { n: 2 },\n\tdoc: \"Skip step n when the loop reaches it.\",\n};\n/** The handler as source, indented from column zero; the renderer places it. */\nconst SKIP_HANDLER = \"({ n }) => {\\n\\tskipped.add(Number(n));\\n\\treturn { ok: true };\\n}\";\nconst DECISION_HALFWAY = {\n\tcontext: { done: \"int\", total: \"int\" },\n\toptions: [\"continue\", \"stop\"],\n\tdefault: \"continue\",\n\t// long enough for an agent to answer under `abai run`; past it the default applies\n\ttimeout: \"15s\",\n\tdoc: \"Asked halfway through the work: go on, or stop here.\",\n} as const;\nconst TURN_STEP = { timeout: \"5s\", doc: \"After each step. The agent may skip a step or change the pace.\" } as const;\n\n/** The level each declaration becomes live at. */\nconst LIVE_FROM = {\n\tcheck: 2,\n\t\"work.done\": 2,\n\t\"work.step\": 2,\n\tend_of_step: 2,\n\t\"work.pace_ms\": 3,\n\t\"work.skip\": 3,\n\ton_halfway: 4,\n} as const;\n\n/** The declaration the program makes at this level, as the stub takes it. */\nexport function declarationsFor(input: TemplateInput): AbaigramOptions {\n\tconst { name, level } = input;\n\tconst options: AbaigramOptions = {\n\t\tname,\n\t\tentry: ENTRY,\n\t\tmodes: [...MODES],\n\t\tcontent: { ...CONTENT },\n\t\taudit: { ...AUDIT },\n\t};\n\tif (level >= LIVE_FROM.check) options.check = { ...CHECK };\n\tconst cells: NonNullable<AbaigramOptions[\"cells\"]> = {};\n\tif (level >= LIVE_FROM[\"work.done\"]) cells[\"work.done\"] = { ...CELL_DONE };\n\tif (level >= LIVE_FROM[\"work.pace_ms\"]) cells[\"work.pace_ms\"] = { ...KNOB_PACE, range: [...KNOB_PACE.range] };\n\tif (Object.keys(cells).length > 0) options.cells = cells;\n\tif (level >= LIVE_FROM[\"work.step\"])\n\t\toptions.events = { \"work.step\": { ...EVENT_STEP, payload: { ...EVENT_STEP.payload } } };\n\tif (level >= LIVE_FROM[\"work.skip\"]) {\n\t\t// the handler here is a stand-in: the manifest never sees it, and the generated module has the real one\n\t\toptions.capabilities = { \"work.skip\": { ...CAPABILITY_SKIP, handler: () => ({ ok: true }) } };\n\t}\n\tif (level >= LIVE_FROM.on_halfway) {\n\t\toptions.decisions = {\n\t\t\ton_halfway: {\n\t\t\t\t...DECISION_HALFWAY,\n\t\t\t\toptions: [...DECISION_HALFWAY.options],\n\t\t\t\tcontext: { ...DECISION_HALFWAY.context },\n\t\t\t},\n\t\t};\n\t}\n\tif (level >= LIVE_FROM.end_of_step) options.turns = { end_of_step: { ...TURN_STEP } };\n\treturn options;\n}\n\n// ---------------------------------------------------------------------------\n// Rendering source\n// ---------------------------------------------------------------------------\n\nconst IDENT = /^[A-Za-z_$][A-Za-z0-9_$]*$/;\nconst WIDTH = 110;\n\n/** A value rendered verbatim, at the current indent: a handler's source. */\nclass Raw {\n\treadonly source: string;\n\tconstructor(source: string) {\n\t\tthis.source = source;\n\t}\n}\n\nfunction key(k: string): string {\n\treturn IDENT.test(k) ? k : JSON.stringify(k);\n}\n\n/** A value as a TypeScript literal, on one line when it fits in `room` columns, else nested by `indent` tabs. */\nfunction literal(value: unknown, indent: number, room: number): string {\n\tif (value instanceof Raw) {\n\t\tconst pad = \"\\t\".repeat(indent);\n\t\treturn value.source\n\t\t\t.split(\"\\n\")\n\t\t\t.map((line, i) => (i === 0 ? line : `${pad}${line}`))\n\t\t\t.join(\"\\n\");\n\t}\n\tif (Array.isArray(value)) return `[${value.map((v) => literal(v, indent, room)).join(\", \")}]`;\n\tif (typeof value === \"object\" && value !== null) {\n\t\tconst entries = Object.entries(value);\n\t\tif (entries.length === 0) return \"{}\";\n\t\tconst inline = entries.map(([k, v]) => `${key(k)}: ${literal(v, indent, room)}`).join(\", \");\n\t\tif (!inline.includes(\"\\n\") && inline.length + 4 <= room) return `{ ${inline} }`;\n\t\tconst pad = \"\\t\".repeat(indent + 1);\n\t\tconst lines = entries.map(([k, v]) => {\n\t\t\tconst head = `${pad}${key(k)}: `;\n\t\t\treturn `${head}${literal(v, indent + 1, WIDTH - head.length * 2)},`;\n\t\t});\n\t\treturn `{\\n${lines.join(\"\\n\")}\\n${\"\\t\".repeat(indent)}}`;\n\t}\n\treturn JSON.stringify(value);\n}\n\n/** Comment out a rendered piece, every line. */\nfunction commented(text: string, indent: number): string {\n\tconst pad = \"\\t\".repeat(indent);\n\treturn text\n\t\t.split(\"\\n\")\n\t\t.map((line) => (line.startsWith(pad) ? `${pad}// ${line.slice(pad.length)}` : `${pad}// ${line.trimStart()}`))\n\t\t.join(\"\\n\");\n}\n\n/**\n * One declaration block, `cells: { ... },` with each entry live or\n * commented on its own, so uncommenting an entry is all it takes; a block\n * with no live entry is commented whole, as the example of its kind.\n */\nfunction block(name: string, entries: Array<{ key: string; value: unknown; live: boolean }>, indent: number): string {\n\tconst pad = \"\\t\".repeat(indent);\n\tconst inner = \"\\t\".repeat(indent + 1);\n\tconst raw = entries.map((e) => {\n\t\tconst head = `${inner}${key(e.key)}: `;\n\t\treturn { text: `${head}${literal(e.value, indent + 1, WIDTH - head.length * 2)},`, live: e.live };\n\t});\n\tif (!raw.some((e) => e.live)) {\n\t\t// no live entry: the whole block is the example, commented once\n\t\treturn commented(`${pad}${name}: {\\n${raw.map((e) => e.text).join(\"\\n\")}\\n${pad}},`, indent);\n\t}\n\tconst rendered = raw.map((e) => (e.live ? e.text : commented(e.text, indent + 1)));\n\treturn `${pad}${name}: {\\n${rendered.join(\"\\n\")}\\n${pad}},`;\n}\n\nfunction declarationModule(input: TemplateInput): string {\n\tconst { name, level, abaiImport } = input;\n\tconst live = (from: number) => level >= from;\n\tconst lines: string[] = [];\n\tlines.push(`// ${name} as an abaigram: what the agent may observe and steer, declared once.`);\n\tlines.push(\"// The manifest (abaigram.yaml) is generated from this: after a change, run\");\n\tlines.push(\"// node src/main.ts abai manifest > abaigram.yaml\");\n\tlines.push(\"// and check it with: abaikit check .\");\n\tif (level < 4) {\n\t\tlines.push(\"// A commented declaration is the example of its kind: uncomment it (and the lines\");\n\t\tlines.push(\"// in src/main.ts that use it) when the program has the fact or the fork.\");\n\t}\n\tlines.push('import { fileURLToPath } from \"node:url\";');\n\tlines.push(`import { createAbaigram } from ${JSON.stringify(abaiImport)};`);\n\tlines.push(\"\");\n\tlines.push(\"/** Steps the agent asked to skip (work.skip); the loop in main.ts honours it. */\");\n\tlines.push(\n\t\tlive(LIVE_FROM[\"work.skip\"])\n\t\t\t? \"export const skipped = new Set<number>();\"\n\t\t\t: \"// export const skipped = new Set<number>();\",\n\t);\n\tlines.push(\"\");\n\tlines.push(\"export const app = createAbaigram(\");\n\tlines.push(\"\\t{\");\n\tlines.push(`\\t\\tname: ${JSON.stringify(name)},`);\n\tlines.push(\"\\t\\t// a runnable entry: the tools reach the program through it, in this directory\");\n\tlines.push(`\\t\\tentry: ${JSON.stringify(ENTRY)},`);\n\tlines.push(`\\t\\tmodes: ${literal([...MODES], 2, WIDTH)},`);\n\tlines.push(`\\t\\tcontent: ${literal(CONTENT, 2, WIDTH)},`);\n\tlines.push(`\\t\\taudit: ${literal(AUDIT, 2, WIDTH)},`);\n\tlines.push(\"\\t\\t// a short run that exercises every channel: what abaikit check runs for the levels above 1\");\n\tconst checkLine = `\\t\\tcheck: ${literal(CHECK, 2, WIDTH)},`;\n\tlines.push(live(LIVE_FROM.check) ? checkLine : commented(checkLine, 2));\n\tlines.push(\"\\t\\t// cells the program writes; a readwrite cell is a knob the agent may set within its range\");\n\tlines.push(\n\t\tblock(\n\t\t\t\"cells\",\n\t\t\t[\n\t\t\t\t{ key: \"work.done\", value: CELL_DONE, live: live(LIVE_FROM[\"work.done\"]) },\n\t\t\t\t{ key: \"work.pace_ms\", value: KNOB_PACE, live: live(LIVE_FROM[\"work.pace_ms\"]) },\n\t\t\t],\n\t\t\t2,\n\t\t),\n\t);\n\tlines.push(\"\\t\\t// events the program emits; wakes says when one wakes the agent\");\n\tlines.push(block(\"events\", [{ key: \"work.step\", value: EVENT_STEP, live: live(LIVE_FROM[\"work.step\"]) }], 2));\n\tlines.push(\"\\t\\t// capabilities the agent may call. dispatch immediate runs the handler at once; the default\");\n\tlines.push(\"\\t\\t// (safepoint) waits for app.safepoint(). check calls the example, so keep it harmless\");\n\tlines.push(\n\t\tblock(\n\t\t\t\"capabilities\",\n\t\t\t[\n\t\t\t\t{\n\t\t\t\t\tkey: \"work.skip\",\n\t\t\t\t\tvalue: { ...CAPABILITY_SKIP, handler: new Raw(SKIP_HANDLER) },\n\t\t\t\t\tlive: live(LIVE_FROM[\"work.skip\"]),\n\t\t\t\t},\n\t\t\t],\n\t\t\t2,\n\t\t),\n\t);\n\tlines.push(\"\\t\\t// decisions the program asks at a real fork; the default is what it does when nobody answers\");\n\tlines.push(\n\t\tblock(\"decisions\", [{ key: \"on_halfway\", value: DECISION_HALFWAY, live: live(LIVE_FROM.on_halfway) }], 2),\n\t);\n\tlines.push(\"\\t\\t// turns: bounded moments the program hands the agent\");\n\tlines.push(block(\"turns\", [{ key: \"end_of_step\", value: TURN_STEP, live: live(LIVE_FROM.end_of_step) }], 2));\n\tlines.push(\"\\t},\");\n\tlines.push(\"\\t// the directory holding abaigram.yaml and abai/: one level up from this file\");\n\tlines.push('\\t{ root: fileURLToPath(new URL(\"..\", import.meta.url)) },');\n\tlines.push(\");\");\n\treturn `${lines.join(\"\\n\")}\\n`;\n}\n\nfunction mainModule(input: TemplateInput): string {\n\tconst { name, level, abaiImport } = input;\n\tconst live = (from: number) => level >= from;\n\tconst lines: string[] = [];\n\tlines.push(`// ${name}: works through a number of steps and prints each. Node 22.19 and`);\n\tlines.push(\"// later run this file as it is (node src/main.ts 5); the first lines hand the\");\n\tlines.push(\"// standard agent entry to the stub, and the program's own run follows.\");\n\tlines.push(`import { runEntry } from ${JSON.stringify(abaiImport)};`);\n\tlines.push(\n\t\tlive(LIVE_FROM[\"work.skip\"]) ? 'import { app, skipped } from \"./abai.ts\";' : 'import { app } from \"./abai.ts\";',\n\t);\n\tlines.push(\"\");\n\tlines.push(\"const code = await runEntry(app, process.argv.slice(2));\");\n\tlines.push(\"if (code >= 0) process.exit(code); // an abai verb ran; otherwise the program's own run begins\");\n\tlines.push(\"\");\n\tlines.push(\"const total = Number(process.argv[2] ?? 5);\");\n\tlines.push(\"const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));\");\n\tif (live(LIVE_FROM[\"work.done\"])) {\n\t\tlines.push(\"// handles once, at startup; set and emit are the cheap calls\");\n\t\tlines.push('const done = app.cell<number>(\"work.done\");');\n\t\tlines.push('const step = app.event(\"work.step\");');\n\t}\n\tif (live(LIVE_FROM[\"work.pace_ms\"])) lines.push('const pace = app.knob<number>(\"work.pace_ms\");');\n\tlines.push(\"\");\n\tlines.push(\"for (let n = 1; n <= total; n++) {\");\n\tif (live(LIVE_FROM.on_halfway)) {\n\t\tlines.push(\"\\tif (n === Math.ceil(total / 2)) {\");\n\t\tlines.push(\"\\t\\t// a real fork: the default is what the program did before it was an abaigram\");\n\t\tlines.push('\\t\\tconst choice = await app.decide<string>(\"on_halfway\", { done: n - 1, total });');\n\t\tlines.push('\\t\\tif (choice === \"stop\") {');\n\t\tlines.push(`\\t\\t\\tconsole.log(\"${name}: stopped halfway, as asked\");`);\n\t\tlines.push(\"\\t\\t\\tbreak;\");\n\t\tlines.push(\"\\t\\t}\");\n\t\tlines.push(\"\\t}\");\n\t}\n\tif (live(LIVE_FROM[\"work.skip\"])) {\n\t\tlines.push(\"\\tif (skipped.has(n)) {\");\n\t\t// biome-ignore lint/suspicious/noTemplateCurlyInString: this is the generated program's source, a template literal in it\n\t\tlines.push(\"\\t\\tconsole.log(`step ${n} skipped`);\");\n\t\tlines.push(\"\\t\\tcontinue;\");\n\t\tlines.push(\"\\t}\");\n\t\tlines.push(\"\\tawait sleep(pace.get());\");\n\t} else {\n\t\tlines.push(\"\\tawait sleep(10);\");\n\t}\n\tif (live(LIVE_FROM[\"work.done\"])) {\n\t\tlines.push(\"\\tdone.set(n);\");\n\t\tlines.push(\"\\tstep.emit({ n });\");\n\t}\n\t// biome-ignore lint/suspicious/noTemplateCurlyInString: this is the generated program's source, a template literal in it\n\tlines.push(\"\\tconsole.log(`step ${n} of ${total}`);\");\n\tlines.push(\"\\tapp.safepoint();\");\n\tif (live(LIVE_FROM.end_of_step)) lines.push('\\tawait app.turn(\"end_of_step\");');\n\tlines.push(\"}\");\n\tlines.push(\n\t\tlive(LIVE_FROM[\"work.done\"])\n\t\t\t? `console.log(\\`${name}: \\${done.get()} steps done\\`);`\n\t\t\t: `console.log(\"${name}: done\");`,\n\t);\n\treturn `${lines.join(\"\\n\")}\\n`;\n}\n\nfunction readme(input: TemplateInput): string {\n\tconst { name, level, packages } = input;\n\tconst where = packages.fromWorkspace\n\t\t? `The two packages come from the abai workspace checkout (\\`file:\\` dependencies)${packages.built ? \"\" : \", which is not built yet: run `npm run build` there first\"}; abaikit itself is a devDependency, so \\`npm run check\\` finds it.`\n\t\t: \"The packages come from npm; abaikit itself is a devDependency, so `npm run check` finds it.\";\n\treturn [\n\t\t`# ${name}`,\n\t\t\"\",\n\t\t`An abaigram at level ${level}, made by \\`abaikit new\\`: a small program that works through a number of steps,`,\n\t\t\"with an agent fused in through the abai stub. Node 22.19 or later runs the TypeScript as it is.\",\n\t\t\"\",\n\t\t\"```\",\n\t\t\"npm install # the stub, the harness, and abaikit for check\",\n\t\t\"node src/main.ts 5 # the program, as itself\",\n\t\t\"node src/main.ts abai doctor --offline # the manifest, the content, the modes\",\n\t\t\"npm run check # abaikit check .: the conformance level, with no model\",\n\t\t\"node src/main.ts abai # a session with the agent about the program (needs a model: node src/main.ts abai config)\",\n\t\t\"node src/main.ts abai run -- 5 # the harness starts the program as its child; the loop meets the agent here\",\n\t\t\"```\",\n\t\t\"\",\n\t\twhere,\n\t\t\"\",\n\t\t\"`src/abai.ts` declares what the agent may observe and steer; `src/main.ts` is the program. After a change to\",\n\t\t\"the declaration, regenerate the manifest: `node src/main.ts abai manifest > abaigram.yaml`. The agent's prompt is\",\n\t\t\"`abai/identity.md`. For the next level, `abaikit learnabai --section retrofit` says what to add.\",\n\t\t\"\",\n\t].join(\"\\n\");\n}\n\n/** Every file of the new project, by path relative to its root. The manifest is rendered by the caller. */\nexport function templateFiles(input: TemplateInput): Record<string, string> {\n\tconst { name, packages } = input;\n\tconst pkg = {\n\t\tname,\n\t\tversion: \"0.1.0\",\n\t\tprivate: true,\n\t\ttype: \"module\",\n\t\tscripts: { start: \"node src/main.ts\", abai: \"node src/main.ts abai\", check: \"abaikit check .\" },\n\t\tdependencies: { \"@abaigram/abai-embedded-harness\": packages.harness, \"@abaigram/abai-stub\": packages.abai },\n\t\tdevDependencies: { \"@abaigram/abaikit\": packages.abaikit },\n\t\tengines: { node: \">=22.19.0\" },\n\t};\n\treturn {\n\t\t\"package.json\": `${JSON.stringify(pkg, null, 2)}\\n`,\n\t\t\"src/abai.ts\": declarationModule(input),\n\t\t\"src/main.ts\": mainModule(input),\n\t\t\"abai/identity.md\": `You are the agent fused into ${name}, a small program that works through a number of steps and prints each. Watch its progress, skip or pace steps only when that serves the person, and say why in every act.\\n`,\n\t\t\"abai/use.md\": `<!-- The use slot (abaigrammar section 8): what the agent should know during sessions and live operation, beyond its identity. -->\\nUnder \\`node src/main.ts abai\\` the program opens a session before its loop: answer about the manifest and the plan. Under \\`node src/main.ts abai run -- N\\` the loop runs while you watch: read the cells before you act, and prefer watching to steering.\\n`,\n\t\t\"README.md\": readme(input),\n\t\t\".gitignore\": \"node_modules/\\nabai-audit.log\\n\",\n\t};\n}\n"]}
|
|
@@ -0,0 +1,322 @@
|
|
|
1
|
+
// The declaration's constants, each written once and read by both renderings.
|
|
2
|
+
const ENTRY = "node src/main.ts abai";
|
|
3
|
+
const MODES = ["turns", "thread", "sidecar"];
|
|
4
|
+
const CONTENT = { identity: "abai/identity.md", use: "abai/use.md" };
|
|
5
|
+
const AUDIT = { path: "./abai-audit.log" };
|
|
6
|
+
const CHECK = { run: "node src/main.ts 4" };
|
|
7
|
+
const CELL_DONE = { type: "int", access: "read", doc: "Steps finished so far." };
|
|
8
|
+
const KNOB_PACE = {
|
|
9
|
+
type: "int",
|
|
10
|
+
access: "readwrite",
|
|
11
|
+
default: 10,
|
|
12
|
+
range: [1, 1000],
|
|
13
|
+
doc: "Milliseconds a step takes; the agent may slow or hasten the work.",
|
|
14
|
+
};
|
|
15
|
+
const EVENT_STEP = { payload: { n: "int" }, wakes: "never", doc: "A step finished." };
|
|
16
|
+
const CAPABILITY_SKIP = {
|
|
17
|
+
params: { n: "int" },
|
|
18
|
+
result: { ok: "bool" },
|
|
19
|
+
effect: "mutate",
|
|
20
|
+
policy: "confirm",
|
|
21
|
+
dispatch: "immediate",
|
|
22
|
+
// step 2: the exercise's call lands while step 1 already runs, so this one is seen skipped under check
|
|
23
|
+
example: { n: 2 },
|
|
24
|
+
doc: "Skip step n when the loop reaches it.",
|
|
25
|
+
};
|
|
26
|
+
/** The handler as source, indented from column zero; the renderer places it. */
|
|
27
|
+
const SKIP_HANDLER = "({ n }) => {\n\tskipped.add(Number(n));\n\treturn { ok: true };\n}";
|
|
28
|
+
const DECISION_HALFWAY = {
|
|
29
|
+
context: { done: "int", total: "int" },
|
|
30
|
+
options: ["continue", "stop"],
|
|
31
|
+
default: "continue",
|
|
32
|
+
// long enough for an agent to answer under `abai run`; past it the default applies
|
|
33
|
+
timeout: "15s",
|
|
34
|
+
doc: "Asked halfway through the work: go on, or stop here.",
|
|
35
|
+
};
|
|
36
|
+
const TURN_STEP = { timeout: "5s", doc: "After each step. The agent may skip a step or change the pace." };
|
|
37
|
+
/** The level each declaration becomes live at. */
|
|
38
|
+
const LIVE_FROM = {
|
|
39
|
+
check: 2,
|
|
40
|
+
"work.done": 2,
|
|
41
|
+
"work.step": 2,
|
|
42
|
+
end_of_step: 2,
|
|
43
|
+
"work.pace_ms": 3,
|
|
44
|
+
"work.skip": 3,
|
|
45
|
+
on_halfway: 4,
|
|
46
|
+
};
|
|
47
|
+
/** The declaration the program makes at this level, as the stub takes it. */
|
|
48
|
+
export function declarationsFor(input) {
|
|
49
|
+
const { name, level } = input;
|
|
50
|
+
const options = {
|
|
51
|
+
name,
|
|
52
|
+
entry: ENTRY,
|
|
53
|
+
modes: [...MODES],
|
|
54
|
+
content: { ...CONTENT },
|
|
55
|
+
audit: { ...AUDIT },
|
|
56
|
+
};
|
|
57
|
+
if (level >= LIVE_FROM.check)
|
|
58
|
+
options.check = { ...CHECK };
|
|
59
|
+
const cells = {};
|
|
60
|
+
if (level >= LIVE_FROM["work.done"])
|
|
61
|
+
cells["work.done"] = { ...CELL_DONE };
|
|
62
|
+
if (level >= LIVE_FROM["work.pace_ms"])
|
|
63
|
+
cells["work.pace_ms"] = { ...KNOB_PACE, range: [...KNOB_PACE.range] };
|
|
64
|
+
if (Object.keys(cells).length > 0)
|
|
65
|
+
options.cells = cells;
|
|
66
|
+
if (level >= LIVE_FROM["work.step"])
|
|
67
|
+
options.events = { "work.step": { ...EVENT_STEP, payload: { ...EVENT_STEP.payload } } };
|
|
68
|
+
if (level >= LIVE_FROM["work.skip"]) {
|
|
69
|
+
// the handler here is a stand-in: the manifest never sees it, and the generated module has the real one
|
|
70
|
+
options.capabilities = { "work.skip": { ...CAPABILITY_SKIP, handler: () => ({ ok: true }) } };
|
|
71
|
+
}
|
|
72
|
+
if (level >= LIVE_FROM.on_halfway) {
|
|
73
|
+
options.decisions = {
|
|
74
|
+
on_halfway: {
|
|
75
|
+
...DECISION_HALFWAY,
|
|
76
|
+
options: [...DECISION_HALFWAY.options],
|
|
77
|
+
context: { ...DECISION_HALFWAY.context },
|
|
78
|
+
},
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
if (level >= LIVE_FROM.end_of_step)
|
|
82
|
+
options.turns = { end_of_step: { ...TURN_STEP } };
|
|
83
|
+
return options;
|
|
84
|
+
}
|
|
85
|
+
// ---------------------------------------------------------------------------
|
|
86
|
+
// Rendering source
|
|
87
|
+
// ---------------------------------------------------------------------------
|
|
88
|
+
const IDENT = /^[A-Za-z_$][A-Za-z0-9_$]*$/;
|
|
89
|
+
const WIDTH = 110;
|
|
90
|
+
/** A value rendered verbatim, at the current indent: a handler's source. */
|
|
91
|
+
class Raw {
|
|
92
|
+
source;
|
|
93
|
+
constructor(source) {
|
|
94
|
+
this.source = source;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
function key(k) {
|
|
98
|
+
return IDENT.test(k) ? k : JSON.stringify(k);
|
|
99
|
+
}
|
|
100
|
+
/** A value as a TypeScript literal, on one line when it fits in `room` columns, else nested by `indent` tabs. */
|
|
101
|
+
function literal(value, indent, room) {
|
|
102
|
+
if (value instanceof Raw) {
|
|
103
|
+
const pad = "\t".repeat(indent);
|
|
104
|
+
return value.source
|
|
105
|
+
.split("\n")
|
|
106
|
+
.map((line, i) => (i === 0 ? line : `${pad}${line}`))
|
|
107
|
+
.join("\n");
|
|
108
|
+
}
|
|
109
|
+
if (Array.isArray(value))
|
|
110
|
+
return `[${value.map((v) => literal(v, indent, room)).join(", ")}]`;
|
|
111
|
+
if (typeof value === "object" && value !== null) {
|
|
112
|
+
const entries = Object.entries(value);
|
|
113
|
+
if (entries.length === 0)
|
|
114
|
+
return "{}";
|
|
115
|
+
const inline = entries.map(([k, v]) => `${key(k)}: ${literal(v, indent, room)}`).join(", ");
|
|
116
|
+
if (!inline.includes("\n") && inline.length + 4 <= room)
|
|
117
|
+
return `{ ${inline} }`;
|
|
118
|
+
const pad = "\t".repeat(indent + 1);
|
|
119
|
+
const lines = entries.map(([k, v]) => {
|
|
120
|
+
const head = `${pad}${key(k)}: `;
|
|
121
|
+
return `${head}${literal(v, indent + 1, WIDTH - head.length * 2)},`;
|
|
122
|
+
});
|
|
123
|
+
return `{\n${lines.join("\n")}\n${"\t".repeat(indent)}}`;
|
|
124
|
+
}
|
|
125
|
+
return JSON.stringify(value);
|
|
126
|
+
}
|
|
127
|
+
/** Comment out a rendered piece, every line. */
|
|
128
|
+
function commented(text, indent) {
|
|
129
|
+
const pad = "\t".repeat(indent);
|
|
130
|
+
return text
|
|
131
|
+
.split("\n")
|
|
132
|
+
.map((line) => (line.startsWith(pad) ? `${pad}// ${line.slice(pad.length)}` : `${pad}// ${line.trimStart()}`))
|
|
133
|
+
.join("\n");
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* One declaration block, `cells: { ... },` with each entry live or
|
|
137
|
+
* commented on its own, so uncommenting an entry is all it takes; a block
|
|
138
|
+
* with no live entry is commented whole, as the example of its kind.
|
|
139
|
+
*/
|
|
140
|
+
function block(name, entries, indent) {
|
|
141
|
+
const pad = "\t".repeat(indent);
|
|
142
|
+
const inner = "\t".repeat(indent + 1);
|
|
143
|
+
const raw = entries.map((e) => {
|
|
144
|
+
const head = `${inner}${key(e.key)}: `;
|
|
145
|
+
return { text: `${head}${literal(e.value, indent + 1, WIDTH - head.length * 2)},`, live: e.live };
|
|
146
|
+
});
|
|
147
|
+
if (!raw.some((e) => e.live)) {
|
|
148
|
+
// no live entry: the whole block is the example, commented once
|
|
149
|
+
return commented(`${pad}${name}: {\n${raw.map((e) => e.text).join("\n")}\n${pad}},`, indent);
|
|
150
|
+
}
|
|
151
|
+
const rendered = raw.map((e) => (e.live ? e.text : commented(e.text, indent + 1)));
|
|
152
|
+
return `${pad}${name}: {\n${rendered.join("\n")}\n${pad}},`;
|
|
153
|
+
}
|
|
154
|
+
function declarationModule(input) {
|
|
155
|
+
const { name, level, abaiImport } = input;
|
|
156
|
+
const live = (from) => level >= from;
|
|
157
|
+
const lines = [];
|
|
158
|
+
lines.push(`// ${name} as an abaigram: what the agent may observe and steer, declared once.`);
|
|
159
|
+
lines.push("// The manifest (abaigram.yaml) is generated from this: after a change, run");
|
|
160
|
+
lines.push("// node src/main.ts abai manifest > abaigram.yaml");
|
|
161
|
+
lines.push("// and check it with: abaikit check .");
|
|
162
|
+
if (level < 4) {
|
|
163
|
+
lines.push("// A commented declaration is the example of its kind: uncomment it (and the lines");
|
|
164
|
+
lines.push("// in src/main.ts that use it) when the program has the fact or the fork.");
|
|
165
|
+
}
|
|
166
|
+
lines.push('import { fileURLToPath } from "node:url";');
|
|
167
|
+
lines.push(`import { createAbaigram } from ${JSON.stringify(abaiImport)};`);
|
|
168
|
+
lines.push("");
|
|
169
|
+
lines.push("/** Steps the agent asked to skip (work.skip); the loop in main.ts honours it. */");
|
|
170
|
+
lines.push(live(LIVE_FROM["work.skip"])
|
|
171
|
+
? "export const skipped = new Set<number>();"
|
|
172
|
+
: "// export const skipped = new Set<number>();");
|
|
173
|
+
lines.push("");
|
|
174
|
+
lines.push("export const app = createAbaigram(");
|
|
175
|
+
lines.push("\t{");
|
|
176
|
+
lines.push(`\t\tname: ${JSON.stringify(name)},`);
|
|
177
|
+
lines.push("\t\t// a runnable entry: the tools reach the program through it, in this directory");
|
|
178
|
+
lines.push(`\t\tentry: ${JSON.stringify(ENTRY)},`);
|
|
179
|
+
lines.push(`\t\tmodes: ${literal([...MODES], 2, WIDTH)},`);
|
|
180
|
+
lines.push(`\t\tcontent: ${literal(CONTENT, 2, WIDTH)},`);
|
|
181
|
+
lines.push(`\t\taudit: ${literal(AUDIT, 2, WIDTH)},`);
|
|
182
|
+
lines.push("\t\t// a short run that exercises every channel: what abaikit check runs for the levels above 1");
|
|
183
|
+
const checkLine = `\t\tcheck: ${literal(CHECK, 2, WIDTH)},`;
|
|
184
|
+
lines.push(live(LIVE_FROM.check) ? checkLine : commented(checkLine, 2));
|
|
185
|
+
lines.push("\t\t// cells the program writes; a readwrite cell is a knob the agent may set within its range");
|
|
186
|
+
lines.push(block("cells", [
|
|
187
|
+
{ key: "work.done", value: CELL_DONE, live: live(LIVE_FROM["work.done"]) },
|
|
188
|
+
{ key: "work.pace_ms", value: KNOB_PACE, live: live(LIVE_FROM["work.pace_ms"]) },
|
|
189
|
+
], 2));
|
|
190
|
+
lines.push("\t\t// events the program emits; wakes says when one wakes the agent");
|
|
191
|
+
lines.push(block("events", [{ key: "work.step", value: EVENT_STEP, live: live(LIVE_FROM["work.step"]) }], 2));
|
|
192
|
+
lines.push("\t\t// capabilities the agent may call. dispatch immediate runs the handler at once; the default");
|
|
193
|
+
lines.push("\t\t// (safepoint) waits for app.safepoint(). check calls the example, so keep it harmless");
|
|
194
|
+
lines.push(block("capabilities", [
|
|
195
|
+
{
|
|
196
|
+
key: "work.skip",
|
|
197
|
+
value: { ...CAPABILITY_SKIP, handler: new Raw(SKIP_HANDLER) },
|
|
198
|
+
live: live(LIVE_FROM["work.skip"]),
|
|
199
|
+
},
|
|
200
|
+
], 2));
|
|
201
|
+
lines.push("\t\t// decisions the program asks at a real fork; the default is what it does when nobody answers");
|
|
202
|
+
lines.push(block("decisions", [{ key: "on_halfway", value: DECISION_HALFWAY, live: live(LIVE_FROM.on_halfway) }], 2));
|
|
203
|
+
lines.push("\t\t// turns: bounded moments the program hands the agent");
|
|
204
|
+
lines.push(block("turns", [{ key: "end_of_step", value: TURN_STEP, live: live(LIVE_FROM.end_of_step) }], 2));
|
|
205
|
+
lines.push("\t},");
|
|
206
|
+
lines.push("\t// the directory holding abaigram.yaml and abai/: one level up from this file");
|
|
207
|
+
lines.push('\t{ root: fileURLToPath(new URL("..", import.meta.url)) },');
|
|
208
|
+
lines.push(");");
|
|
209
|
+
return `${lines.join("\n")}\n`;
|
|
210
|
+
}
|
|
211
|
+
function mainModule(input) {
|
|
212
|
+
const { name, level, abaiImport } = input;
|
|
213
|
+
const live = (from) => level >= from;
|
|
214
|
+
const lines = [];
|
|
215
|
+
lines.push(`// ${name}: works through a number of steps and prints each. Node 22.19 and`);
|
|
216
|
+
lines.push("// later run this file as it is (node src/main.ts 5); the first lines hand the");
|
|
217
|
+
lines.push("// standard agent entry to the stub, and the program's own run follows.");
|
|
218
|
+
lines.push(`import { runEntry } from ${JSON.stringify(abaiImport)};`);
|
|
219
|
+
lines.push(live(LIVE_FROM["work.skip"]) ? 'import { app, skipped } from "./abai.ts";' : 'import { app } from "./abai.ts";');
|
|
220
|
+
lines.push("");
|
|
221
|
+
lines.push("const code = await runEntry(app, process.argv.slice(2));");
|
|
222
|
+
lines.push("if (code >= 0) process.exit(code); // an abai verb ran; otherwise the program's own run begins");
|
|
223
|
+
lines.push("");
|
|
224
|
+
lines.push("const total = Number(process.argv[2] ?? 5);");
|
|
225
|
+
lines.push("const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));");
|
|
226
|
+
if (live(LIVE_FROM["work.done"])) {
|
|
227
|
+
lines.push("// handles once, at startup; set and emit are the cheap calls");
|
|
228
|
+
lines.push('const done = app.cell<number>("work.done");');
|
|
229
|
+
lines.push('const step = app.event("work.step");');
|
|
230
|
+
}
|
|
231
|
+
if (live(LIVE_FROM["work.pace_ms"]))
|
|
232
|
+
lines.push('const pace = app.knob<number>("work.pace_ms");');
|
|
233
|
+
lines.push("");
|
|
234
|
+
lines.push("for (let n = 1; n <= total; n++) {");
|
|
235
|
+
if (live(LIVE_FROM.on_halfway)) {
|
|
236
|
+
lines.push("\tif (n === Math.ceil(total / 2)) {");
|
|
237
|
+
lines.push("\t\t// a real fork: the default is what the program did before it was an abaigram");
|
|
238
|
+
lines.push('\t\tconst choice = await app.decide<string>("on_halfway", { done: n - 1, total });');
|
|
239
|
+
lines.push('\t\tif (choice === "stop") {');
|
|
240
|
+
lines.push(`\t\t\tconsole.log("${name}: stopped halfway, as asked");`);
|
|
241
|
+
lines.push("\t\t\tbreak;");
|
|
242
|
+
lines.push("\t\t}");
|
|
243
|
+
lines.push("\t}");
|
|
244
|
+
}
|
|
245
|
+
if (live(LIVE_FROM["work.skip"])) {
|
|
246
|
+
lines.push("\tif (skipped.has(n)) {");
|
|
247
|
+
// biome-ignore lint/suspicious/noTemplateCurlyInString: this is the generated program's source, a template literal in it
|
|
248
|
+
lines.push("\t\tconsole.log(`step ${n} skipped`);");
|
|
249
|
+
lines.push("\t\tcontinue;");
|
|
250
|
+
lines.push("\t}");
|
|
251
|
+
lines.push("\tawait sleep(pace.get());");
|
|
252
|
+
}
|
|
253
|
+
else {
|
|
254
|
+
lines.push("\tawait sleep(10);");
|
|
255
|
+
}
|
|
256
|
+
if (live(LIVE_FROM["work.done"])) {
|
|
257
|
+
lines.push("\tdone.set(n);");
|
|
258
|
+
lines.push("\tstep.emit({ n });");
|
|
259
|
+
}
|
|
260
|
+
// biome-ignore lint/suspicious/noTemplateCurlyInString: this is the generated program's source, a template literal in it
|
|
261
|
+
lines.push("\tconsole.log(`step ${n} of ${total}`);");
|
|
262
|
+
lines.push("\tapp.safepoint();");
|
|
263
|
+
if (live(LIVE_FROM.end_of_step))
|
|
264
|
+
lines.push('\tawait app.turn("end_of_step");');
|
|
265
|
+
lines.push("}");
|
|
266
|
+
lines.push(live(LIVE_FROM["work.done"])
|
|
267
|
+
? `console.log(\`${name}: \${done.get()} steps done\`);`
|
|
268
|
+
: `console.log("${name}: done");`);
|
|
269
|
+
return `${lines.join("\n")}\n`;
|
|
270
|
+
}
|
|
271
|
+
function readme(input) {
|
|
272
|
+
const { name, level, packages } = input;
|
|
273
|
+
const where = packages.fromWorkspace
|
|
274
|
+
? `The two packages come from the abai workspace checkout (\`file:\` dependencies)${packages.built ? "" : ", which is not built yet: run `npm run build` there first"}; abaikit itself is a devDependency, so \`npm run check\` finds it.`
|
|
275
|
+
: "The packages come from npm; abaikit itself is a devDependency, so `npm run check` finds it.";
|
|
276
|
+
return [
|
|
277
|
+
`# ${name}`,
|
|
278
|
+
"",
|
|
279
|
+
`An abaigram at level ${level}, made by \`abaikit new\`: a small program that works through a number of steps,`,
|
|
280
|
+
"with an agent fused in through the abai stub. Node 22.19 or later runs the TypeScript as it is.",
|
|
281
|
+
"",
|
|
282
|
+
"```",
|
|
283
|
+
"npm install # the stub, the harness, and abaikit for check",
|
|
284
|
+
"node src/main.ts 5 # the program, as itself",
|
|
285
|
+
"node src/main.ts abai doctor --offline # the manifest, the content, the modes",
|
|
286
|
+
"npm run check # abaikit check .: the conformance level, with no model",
|
|
287
|
+
"node src/main.ts abai # a session with the agent about the program (needs a model: node src/main.ts abai config)",
|
|
288
|
+
"node src/main.ts abai run -- 5 # the harness starts the program as its child; the loop meets the agent here",
|
|
289
|
+
"```",
|
|
290
|
+
"",
|
|
291
|
+
where,
|
|
292
|
+
"",
|
|
293
|
+
"`src/abai.ts` declares what the agent may observe and steer; `src/main.ts` is the program. After a change to",
|
|
294
|
+
"the declaration, regenerate the manifest: `node src/main.ts abai manifest > abaigram.yaml`. The agent's prompt is",
|
|
295
|
+
"`abai/identity.md`. For the next level, `abaikit learnabai --section retrofit` says what to add.",
|
|
296
|
+
"",
|
|
297
|
+
].join("\n");
|
|
298
|
+
}
|
|
299
|
+
/** Every file of the new project, by path relative to its root. The manifest is rendered by the caller. */
|
|
300
|
+
export function templateFiles(input) {
|
|
301
|
+
const { name, packages } = input;
|
|
302
|
+
const pkg = {
|
|
303
|
+
name,
|
|
304
|
+
version: "0.1.0",
|
|
305
|
+
private: true,
|
|
306
|
+
type: "module",
|
|
307
|
+
scripts: { start: "node src/main.ts", abai: "node src/main.ts abai", check: "abaikit check ." },
|
|
308
|
+
dependencies: { "@abaigram/abai-embedded-harness": packages.harness, "@abaigram/abai-stub": packages.abai },
|
|
309
|
+
devDependencies: { "@abaigram/abaikit": packages.abaikit },
|
|
310
|
+
engines: { node: ">=22.19.0" },
|
|
311
|
+
};
|
|
312
|
+
return {
|
|
313
|
+
"package.json": `${JSON.stringify(pkg, null, 2)}\n`,
|
|
314
|
+
"src/abai.ts": declarationModule(input),
|
|
315
|
+
"src/main.ts": mainModule(input),
|
|
316
|
+
"abai/identity.md": `You are the agent fused into ${name}, a small program that works through a number of steps and prints each. Watch its progress, skip or pace steps only when that serves the person, and say why in every act.\n`,
|
|
317
|
+
"abai/use.md": `<!-- The use slot (abaigrammar section 8): what the agent should know during sessions and live operation, beyond its identity. -->\nUnder \`node src/main.ts abai\` the program opens a session before its loop: answer about the manifest and the plan. Under \`node src/main.ts abai run -- N\` the loop runs while you watch: read the cells before you act, and prefer watching to steering.\n`,
|
|
318
|
+
"README.md": readme(input),
|
|
319
|
+
".gitignore": "node_modules/\nabai-audit.log\n",
|
|
320
|
+
};
|
|
321
|
+
}
|
|
322
|
+
//# sourceMappingURL=template-ts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"template-ts.js","sourceRoot":"","sources":["../src/template-ts.ts"],"names":[],"mappings":"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","sourcesContent":["// The TypeScript template behind `abaikit new`: one declaration, as data,\n// rendered twice. Into the new project's `src/abai.ts` as source, and\n// through the stub's `buildManifest` into its `abaigram.yaml`, so file and\n// code agree without running the program. The program is a small loop\n// that works through a number of steps; at each level the declarations it\n// needs are live and the loop uses them, so `abaikit check` reaches that\n// level out of the box. Below its level every declaration kind is present\n// once, commented, as section 13 asks, and uncommenting one is all it\n// takes to make it live.\nimport type { AbaigramOptions, CapabilityOptions } from \"@abaigram/abai-stub\";\n\nexport type Level = 1 | 2 | 3 | 4;\n\nexport interface TemplateInput {\n\tname: string;\n\tlevel: Level;\n\t/** The specifier the generated code imports the stub by; `@abaigram/abai-stub` unless a test points at the source. */\n\tabaiImport: string;\n\t/** What `package.json` depends on, in package.json form, and whether the packages are built workspace checkouts. */\n\tpackages: { abai: string; harness: string; abaikit: string; fromWorkspace: boolean; built: boolean };\n}\n\n// The declaration's constants, each written once and read by both renderings.\nconst ENTRY = \"node src/main.ts abai\";\nconst MODES = [\"turns\", \"thread\", \"sidecar\"] as const;\nconst CONTENT = { identity: \"abai/identity.md\", use: \"abai/use.md\" };\nconst AUDIT = { path: \"./abai-audit.log\" };\nconst CHECK = { run: \"node src/main.ts 4\" };\nconst CELL_DONE = { type: \"int\", access: \"read\", doc: \"Steps finished so far.\" } as const;\nconst KNOB_PACE = {\n\ttype: \"int\",\n\taccess: \"readwrite\",\n\tdefault: 10,\n\trange: [1, 1000],\n\tdoc: \"Milliseconds a step takes; the agent may slow or hasten the work.\",\n} as const;\nconst EVENT_STEP = { payload: { n: \"int\" }, wakes: \"never\", doc: \"A step finished.\" } as const;\nconst CAPABILITY_SKIP: Omit<CapabilityOptions, \"handler\"> = {\n\tparams: { n: \"int\" },\n\tresult: { ok: \"bool\" },\n\teffect: \"mutate\",\n\tpolicy: \"confirm\",\n\tdispatch: \"immediate\",\n\t// step 2: the exercise's call lands while step 1 already runs, so this one is seen skipped under check\n\texample: { n: 2 },\n\tdoc: \"Skip step n when the loop reaches it.\",\n};\n/** The handler as source, indented from column zero; the renderer places it. */\nconst SKIP_HANDLER = \"({ n }) => {\\n\\tskipped.add(Number(n));\\n\\treturn { ok: true };\\n}\";\nconst DECISION_HALFWAY = {\n\tcontext: { done: \"int\", total: \"int\" },\n\toptions: [\"continue\", \"stop\"],\n\tdefault: \"continue\",\n\t// long enough for an agent to answer under `abai run`; past it the default applies\n\ttimeout: \"15s\",\n\tdoc: \"Asked halfway through the work: go on, or stop here.\",\n} as const;\nconst TURN_STEP = { timeout: \"5s\", doc: \"After each step. The agent may skip a step or change the pace.\" } as const;\n\n/** The level each declaration becomes live at. */\nconst LIVE_FROM = {\n\tcheck: 2,\n\t\"work.done\": 2,\n\t\"work.step\": 2,\n\tend_of_step: 2,\n\t\"work.pace_ms\": 3,\n\t\"work.skip\": 3,\n\ton_halfway: 4,\n} as const;\n\n/** The declaration the program makes at this level, as the stub takes it. */\nexport function declarationsFor(input: TemplateInput): AbaigramOptions {\n\tconst { name, level } = input;\n\tconst options: AbaigramOptions = {\n\t\tname,\n\t\tentry: ENTRY,\n\t\tmodes: [...MODES],\n\t\tcontent: { ...CONTENT },\n\t\taudit: { ...AUDIT },\n\t};\n\tif (level >= LIVE_FROM.check) options.check = { ...CHECK };\n\tconst cells: NonNullable<AbaigramOptions[\"cells\"]> = {};\n\tif (level >= LIVE_FROM[\"work.done\"]) cells[\"work.done\"] = { ...CELL_DONE };\n\tif (level >= LIVE_FROM[\"work.pace_ms\"]) cells[\"work.pace_ms\"] = { ...KNOB_PACE, range: [...KNOB_PACE.range] };\n\tif (Object.keys(cells).length > 0) options.cells = cells;\n\tif (level >= LIVE_FROM[\"work.step\"])\n\t\toptions.events = { \"work.step\": { ...EVENT_STEP, payload: { ...EVENT_STEP.payload } } };\n\tif (level >= LIVE_FROM[\"work.skip\"]) {\n\t\t// the handler here is a stand-in: the manifest never sees it, and the generated module has the real one\n\t\toptions.capabilities = { \"work.skip\": { ...CAPABILITY_SKIP, handler: () => ({ ok: true }) } };\n\t}\n\tif (level >= LIVE_FROM.on_halfway) {\n\t\toptions.decisions = {\n\t\t\ton_halfway: {\n\t\t\t\t...DECISION_HALFWAY,\n\t\t\t\toptions: [...DECISION_HALFWAY.options],\n\t\t\t\tcontext: { ...DECISION_HALFWAY.context },\n\t\t\t},\n\t\t};\n\t}\n\tif (level >= LIVE_FROM.end_of_step) options.turns = { end_of_step: { ...TURN_STEP } };\n\treturn options;\n}\n\n// ---------------------------------------------------------------------------\n// Rendering source\n// ---------------------------------------------------------------------------\n\nconst IDENT = /^[A-Za-z_$][A-Za-z0-9_$]*$/;\nconst WIDTH = 110;\n\n/** A value rendered verbatim, at the current indent: a handler's source. */\nclass Raw {\n\treadonly source: string;\n\tconstructor(source: string) {\n\t\tthis.source = source;\n\t}\n}\n\nfunction key(k: string): string {\n\treturn IDENT.test(k) ? k : JSON.stringify(k);\n}\n\n/** A value as a TypeScript literal, on one line when it fits in `room` columns, else nested by `indent` tabs. */\nfunction literal(value: unknown, indent: number, room: number): string {\n\tif (value instanceof Raw) {\n\t\tconst pad = \"\\t\".repeat(indent);\n\t\treturn value.source\n\t\t\t.split(\"\\n\")\n\t\t\t.map((line, i) => (i === 0 ? line : `${pad}${line}`))\n\t\t\t.join(\"\\n\");\n\t}\n\tif (Array.isArray(value)) return `[${value.map((v) => literal(v, indent, room)).join(\", \")}]`;\n\tif (typeof value === \"object\" && value !== null) {\n\t\tconst entries = Object.entries(value);\n\t\tif (entries.length === 0) return \"{}\";\n\t\tconst inline = entries.map(([k, v]) => `${key(k)}: ${literal(v, indent, room)}`).join(\", \");\n\t\tif (!inline.includes(\"\\n\") && inline.length + 4 <= room) return `{ ${inline} }`;\n\t\tconst pad = \"\\t\".repeat(indent + 1);\n\t\tconst lines = entries.map(([k, v]) => {\n\t\t\tconst head = `${pad}${key(k)}: `;\n\t\t\treturn `${head}${literal(v, indent + 1, WIDTH - head.length * 2)},`;\n\t\t});\n\t\treturn `{\\n${lines.join(\"\\n\")}\\n${\"\\t\".repeat(indent)}}`;\n\t}\n\treturn JSON.stringify(value);\n}\n\n/** Comment out a rendered piece, every line. */\nfunction commented(text: string, indent: number): string {\n\tconst pad = \"\\t\".repeat(indent);\n\treturn text\n\t\t.split(\"\\n\")\n\t\t.map((line) => (line.startsWith(pad) ? `${pad}// ${line.slice(pad.length)}` : `${pad}// ${line.trimStart()}`))\n\t\t.join(\"\\n\");\n}\n\n/**\n * One declaration block, `cells: { ... },` with each entry live or\n * commented on its own, so uncommenting an entry is all it takes; a block\n * with no live entry is commented whole, as the example of its kind.\n */\nfunction block(name: string, entries: Array<{ key: string; value: unknown; live: boolean }>, indent: number): string {\n\tconst pad = \"\\t\".repeat(indent);\n\tconst inner = \"\\t\".repeat(indent + 1);\n\tconst raw = entries.map((e) => {\n\t\tconst head = `${inner}${key(e.key)}: `;\n\t\treturn { text: `${head}${literal(e.value, indent + 1, WIDTH - head.length * 2)},`, live: e.live };\n\t});\n\tif (!raw.some((e) => e.live)) {\n\t\t// no live entry: the whole block is the example, commented once\n\t\treturn commented(`${pad}${name}: {\\n${raw.map((e) => e.text).join(\"\\n\")}\\n${pad}},`, indent);\n\t}\n\tconst rendered = raw.map((e) => (e.live ? e.text : commented(e.text, indent + 1)));\n\treturn `${pad}${name}: {\\n${rendered.join(\"\\n\")}\\n${pad}},`;\n}\n\nfunction declarationModule(input: TemplateInput): string {\n\tconst { name, level, abaiImport } = input;\n\tconst live = (from: number) => level >= from;\n\tconst lines: string[] = [];\n\tlines.push(`// ${name} as an abaigram: what the agent may observe and steer, declared once.`);\n\tlines.push(\"// The manifest (abaigram.yaml) is generated from this: after a change, run\");\n\tlines.push(\"// node src/main.ts abai manifest > abaigram.yaml\");\n\tlines.push(\"// and check it with: abaikit check .\");\n\tif (level < 4) {\n\t\tlines.push(\"// A commented declaration is the example of its kind: uncomment it (and the lines\");\n\t\tlines.push(\"// in src/main.ts that use it) when the program has the fact or the fork.\");\n\t}\n\tlines.push('import { fileURLToPath } from \"node:url\";');\n\tlines.push(`import { createAbaigram } from ${JSON.stringify(abaiImport)};`);\n\tlines.push(\"\");\n\tlines.push(\"/** Steps the agent asked to skip (work.skip); the loop in main.ts honours it. */\");\n\tlines.push(\n\t\tlive(LIVE_FROM[\"work.skip\"])\n\t\t\t? \"export const skipped = new Set<number>();\"\n\t\t\t: \"// export const skipped = new Set<number>();\",\n\t);\n\tlines.push(\"\");\n\tlines.push(\"export const app = createAbaigram(\");\n\tlines.push(\"\\t{\");\n\tlines.push(`\\t\\tname: ${JSON.stringify(name)},`);\n\tlines.push(\"\\t\\t// a runnable entry: the tools reach the program through it, in this directory\");\n\tlines.push(`\\t\\tentry: ${JSON.stringify(ENTRY)},`);\n\tlines.push(`\\t\\tmodes: ${literal([...MODES], 2, WIDTH)},`);\n\tlines.push(`\\t\\tcontent: ${literal(CONTENT, 2, WIDTH)},`);\n\tlines.push(`\\t\\taudit: ${literal(AUDIT, 2, WIDTH)},`);\n\tlines.push(\"\\t\\t// a short run that exercises every channel: what abaikit check runs for the levels above 1\");\n\tconst checkLine = `\\t\\tcheck: ${literal(CHECK, 2, WIDTH)},`;\n\tlines.push(live(LIVE_FROM.check) ? checkLine : commented(checkLine, 2));\n\tlines.push(\"\\t\\t// cells the program writes; a readwrite cell is a knob the agent may set within its range\");\n\tlines.push(\n\t\tblock(\n\t\t\t\"cells\",\n\t\t\t[\n\t\t\t\t{ key: \"work.done\", value: CELL_DONE, live: live(LIVE_FROM[\"work.done\"]) },\n\t\t\t\t{ key: \"work.pace_ms\", value: KNOB_PACE, live: live(LIVE_FROM[\"work.pace_ms\"]) },\n\t\t\t],\n\t\t\t2,\n\t\t),\n\t);\n\tlines.push(\"\\t\\t// events the program emits; wakes says when one wakes the agent\");\n\tlines.push(block(\"events\", [{ key: \"work.step\", value: EVENT_STEP, live: live(LIVE_FROM[\"work.step\"]) }], 2));\n\tlines.push(\"\\t\\t// capabilities the agent may call. dispatch immediate runs the handler at once; the default\");\n\tlines.push(\"\\t\\t// (safepoint) waits for app.safepoint(). check calls the example, so keep it harmless\");\n\tlines.push(\n\t\tblock(\n\t\t\t\"capabilities\",\n\t\t\t[\n\t\t\t\t{\n\t\t\t\t\tkey: \"work.skip\",\n\t\t\t\t\tvalue: { ...CAPABILITY_SKIP, handler: new Raw(SKIP_HANDLER) },\n\t\t\t\t\tlive: live(LIVE_FROM[\"work.skip\"]),\n\t\t\t\t},\n\t\t\t],\n\t\t\t2,\n\t\t),\n\t);\n\tlines.push(\"\\t\\t// decisions the program asks at a real fork; the default is what it does when nobody answers\");\n\tlines.push(\n\t\tblock(\"decisions\", [{ key: \"on_halfway\", value: DECISION_HALFWAY, live: live(LIVE_FROM.on_halfway) }], 2),\n\t);\n\tlines.push(\"\\t\\t// turns: bounded moments the program hands the agent\");\n\tlines.push(block(\"turns\", [{ key: \"end_of_step\", value: TURN_STEP, live: live(LIVE_FROM.end_of_step) }], 2));\n\tlines.push(\"\\t},\");\n\tlines.push(\"\\t// the directory holding abaigram.yaml and abai/: one level up from this file\");\n\tlines.push('\\t{ root: fileURLToPath(new URL(\"..\", import.meta.url)) },');\n\tlines.push(\");\");\n\treturn `${lines.join(\"\\n\")}\\n`;\n}\n\nfunction mainModule(input: TemplateInput): string {\n\tconst { name, level, abaiImport } = input;\n\tconst live = (from: number) => level >= from;\n\tconst lines: string[] = [];\n\tlines.push(`// ${name}: works through a number of steps and prints each. Node 22.19 and`);\n\tlines.push(\"// later run this file as it is (node src/main.ts 5); the first lines hand the\");\n\tlines.push(\"// standard agent entry to the stub, and the program's own run follows.\");\n\tlines.push(`import { runEntry } from ${JSON.stringify(abaiImport)};`);\n\tlines.push(\n\t\tlive(LIVE_FROM[\"work.skip\"]) ? 'import { app, skipped } from \"./abai.ts\";' : 'import { app } from \"./abai.ts\";',\n\t);\n\tlines.push(\"\");\n\tlines.push(\"const code = await runEntry(app, process.argv.slice(2));\");\n\tlines.push(\"if (code >= 0) process.exit(code); // an abai verb ran; otherwise the program's own run begins\");\n\tlines.push(\"\");\n\tlines.push(\"const total = Number(process.argv[2] ?? 5);\");\n\tlines.push(\"const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));\");\n\tif (live(LIVE_FROM[\"work.done\"])) {\n\t\tlines.push(\"// handles once, at startup; set and emit are the cheap calls\");\n\t\tlines.push('const done = app.cell<number>(\"work.done\");');\n\t\tlines.push('const step = app.event(\"work.step\");');\n\t}\n\tif (live(LIVE_FROM[\"work.pace_ms\"])) lines.push('const pace = app.knob<number>(\"work.pace_ms\");');\n\tlines.push(\"\");\n\tlines.push(\"for (let n = 1; n <= total; n++) {\");\n\tif (live(LIVE_FROM.on_halfway)) {\n\t\tlines.push(\"\\tif (n === Math.ceil(total / 2)) {\");\n\t\tlines.push(\"\\t\\t// a real fork: the default is what the program did before it was an abaigram\");\n\t\tlines.push('\\t\\tconst choice = await app.decide<string>(\"on_halfway\", { done: n - 1, total });');\n\t\tlines.push('\\t\\tif (choice === \"stop\") {');\n\t\tlines.push(`\\t\\t\\tconsole.log(\"${name}: stopped halfway, as asked\");`);\n\t\tlines.push(\"\\t\\t\\tbreak;\");\n\t\tlines.push(\"\\t\\t}\");\n\t\tlines.push(\"\\t}\");\n\t}\n\tif (live(LIVE_FROM[\"work.skip\"])) {\n\t\tlines.push(\"\\tif (skipped.has(n)) {\");\n\t\t// biome-ignore lint/suspicious/noTemplateCurlyInString: this is the generated program's source, a template literal in it\n\t\tlines.push(\"\\t\\tconsole.log(`step ${n} skipped`);\");\n\t\tlines.push(\"\\t\\tcontinue;\");\n\t\tlines.push(\"\\t}\");\n\t\tlines.push(\"\\tawait sleep(pace.get());\");\n\t} else {\n\t\tlines.push(\"\\tawait sleep(10);\");\n\t}\n\tif (live(LIVE_FROM[\"work.done\"])) {\n\t\tlines.push(\"\\tdone.set(n);\");\n\t\tlines.push(\"\\tstep.emit({ n });\");\n\t}\n\t// biome-ignore lint/suspicious/noTemplateCurlyInString: this is the generated program's source, a template literal in it\n\tlines.push(\"\\tconsole.log(`step ${n} of ${total}`);\");\n\tlines.push(\"\\tapp.safepoint();\");\n\tif (live(LIVE_FROM.end_of_step)) lines.push('\\tawait app.turn(\"end_of_step\");');\n\tlines.push(\"}\");\n\tlines.push(\n\t\tlive(LIVE_FROM[\"work.done\"])\n\t\t\t? `console.log(\\`${name}: \\${done.get()} steps done\\`);`\n\t\t\t: `console.log(\"${name}: done\");`,\n\t);\n\treturn `${lines.join(\"\\n\")}\\n`;\n}\n\nfunction readme(input: TemplateInput): string {\n\tconst { name, level, packages } = input;\n\tconst where = packages.fromWorkspace\n\t\t? `The two packages come from the abai workspace checkout (\\`file:\\` dependencies)${packages.built ? \"\" : \", which is not built yet: run `npm run build` there first\"}; abaikit itself is a devDependency, so \\`npm run check\\` finds it.`\n\t\t: \"The packages come from npm; abaikit itself is a devDependency, so `npm run check` finds it.\";\n\treturn [\n\t\t`# ${name}`,\n\t\t\"\",\n\t\t`An abaigram at level ${level}, made by \\`abaikit new\\`: a small program that works through a number of steps,`,\n\t\t\"with an agent fused in through the abai stub. Node 22.19 or later runs the TypeScript as it is.\",\n\t\t\"\",\n\t\t\"```\",\n\t\t\"npm install # the stub, the harness, and abaikit for check\",\n\t\t\"node src/main.ts 5 # the program, as itself\",\n\t\t\"node src/main.ts abai doctor --offline # the manifest, the content, the modes\",\n\t\t\"npm run check # abaikit check .: the conformance level, with no model\",\n\t\t\"node src/main.ts abai # a session with the agent about the program (needs a model: node src/main.ts abai config)\",\n\t\t\"node src/main.ts abai run -- 5 # the harness starts the program as its child; the loop meets the agent here\",\n\t\t\"```\",\n\t\t\"\",\n\t\twhere,\n\t\t\"\",\n\t\t\"`src/abai.ts` declares what the agent may observe and steer; `src/main.ts` is the program. After a change to\",\n\t\t\"the declaration, regenerate the manifest: `node src/main.ts abai manifest > abaigram.yaml`. The agent's prompt is\",\n\t\t\"`abai/identity.md`. For the next level, `abaikit learnabai --section retrofit` says what to add.\",\n\t\t\"\",\n\t].join(\"\\n\");\n}\n\n/** Every file of the new project, by path relative to its root. The manifest is rendered by the caller. */\nexport function templateFiles(input: TemplateInput): Record<string, string> {\n\tconst { name, packages } = input;\n\tconst pkg = {\n\t\tname,\n\t\tversion: \"0.1.0\",\n\t\tprivate: true,\n\t\ttype: \"module\",\n\t\tscripts: { start: \"node src/main.ts\", abai: \"node src/main.ts abai\", check: \"abaikit check .\" },\n\t\tdependencies: { \"@abaigram/abai-embedded-harness\": packages.harness, \"@abaigram/abai-stub\": packages.abai },\n\t\tdevDependencies: { \"@abaigram/abaikit\": packages.abaikit },\n\t\tengines: { node: \">=22.19.0\" },\n\t};\n\treturn {\n\t\t\"package.json\": `${JSON.stringify(pkg, null, 2)}\\n`,\n\t\t\"src/abai.ts\": declarationModule(input),\n\t\t\"src/main.ts\": mainModule(input),\n\t\t\"abai/identity.md\": `You are the agent fused into ${name}, a small program that works through a number of steps and prints each. Watch its progress, skip or pace steps only when that serves the person, and say why in every act.\\n`,\n\t\t\"abai/use.md\": `<!-- The use slot (abaigrammar section 8): what the agent should know during sessions and live operation, beyond its identity. -->\\nUnder \\`node src/main.ts abai\\` the program opens a session before its loop: answer about the manifest and the plan. Under \\`node src/main.ts abai run -- N\\` the loop runs while you watch: read the cells before you act, and prefer watching to steering.\\n`,\n\t\t\"README.md\": readme(input),\n\t\t\".gitignore\": \"node_modules/\\nabai-audit.log\\n\",\n\t};\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"version.d.ts","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA,yCAAyC;AACzC,eAAO,MAAM,eAAe,UAAU,CAAC","sourcesContent":["/** The abaikit package's own version. */\nexport const ABAIKIT_VERSION = \"0.2.0\";\n"]}
|
package/dist/version.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"version.js","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA,yCAAyC;AACzC,MAAM,CAAC,MAAM,eAAe,GAAG,OAAO,CAAC","sourcesContent":["/** The abaikit package's own version. */\nexport const ABAIKIT_VERSION = \"0.2.0\";\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
You are the agent fused into hello, the smallest abaigram: it prints one word and exits.
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# abaigram.yaml: the manifest of hello as an abaigram (abaigrammar 0.1).
|
|
2
|
+
# Generated by `node hello.ts abai manifest` from the program's declarations in code.
|
|
3
|
+
# Do not edit by hand: `node hello.ts abai doctor` and the test suite check that this file
|
|
4
|
+
# agrees with the code. Regenerate with `node hello.ts abai manifest > abaigram.yaml`.
|
|
5
|
+
|
|
6
|
+
abaigrammar: "0.1"
|
|
7
|
+
name: hello
|
|
8
|
+
entry: node hello.ts abai
|
|
9
|
+
modes:
|
|
10
|
+
- turns
|
|
11
|
+
content:
|
|
12
|
+
identity: abai/identity.md
|
|
13
|
+
audit:
|
|
14
|
+
path: ./abai-audit.log
|
|
15
|
+
deviations:
|
|
16
|
+
- "Touchpoints are awaited promises: Node cannot block its only thread while the agent loop runs on it, so the program's logic pauses at the await while its own timers and I/O callbacks keep running (section 4.3)."
|
|
17
|
+
- "Sized cell writes and event payload copies allocate: JavaScript has no copy into a preallocated byte slot; scalar rows meet section 11.2, sized rows are measured and reported."
|
|
18
|
+
- "A cooperative pause holds the program at its next touchpoint, not inside safepoint(): a safepoint cannot block, since the resume arrives on the same event loop that would be blocked. The flag is still one load at a safepoint, and os pause (the launcher's signal) holds the program anywhere (section 5.5)."
|
|
19
|
+
- "Under launch the child is attached as soon as its endpoint is accepted, a moment after its first statement rather than before it: Node cannot listen in a constructor. A program that wants the agent present from its first line awaits attach() (section 6.3)."
|
|
20
|
+
cells: []
|
|
21
|
+
events: []
|
|
22
|
+
capabilities: []
|
|
23
|
+
decisions: []
|
|
24
|
+
turns: []
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
// hello: the smallest abaigram. It declares a name, an entry, one mode and
|
|
2
|
+
// an audit path, serves the standard agent entry, and prints one word.
|
|
3
|
+
//
|
|
4
|
+
// node examples/hello/hello.ts run the program
|
|
5
|
+
// node examples/hello/hello.ts abai doctor
|
|
6
|
+
import { dirname } from "node:path";
|
|
7
|
+
import { fileURLToPath } from "node:url";
|
|
8
|
+
import { createAbaigram, runEntry } from "@abaigram/abai-stub";
|
|
9
|
+
|
|
10
|
+
const app = createAbaigram(
|
|
11
|
+
{ name: "hello", entry: "node hello.ts abai", modes: ["turns"], audit: { path: "./abai-audit.log" } },
|
|
12
|
+
{ root: dirname(fileURLToPath(import.meta.url)) },
|
|
13
|
+
);
|
|
14
|
+
|
|
15
|
+
const code = await runEntry(app, process.argv.slice(2));
|
|
16
|
+
if (code >= 0) process.exit(code);
|
|
17
|
+
|
|
18
|
+
console.log("hello");
|