@graview/skills 0.0.0-stage → 0.1.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 +96 -0
- package/README.md +46 -2
- package/dist/cli.d.ts +15 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +54 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.d.ts +25 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +53 -0
- package/dist/index.js.map +1 -0
- package/package.json +50 -3
- package/skills/graview-agent-seat/SKILL.md +159 -0
- package/skills/graview-brand/SKILL.md +137 -0
- package/skills/graview-desk/SKILL.md +84 -0
- package/skills/graview-embed/SKILL.md +86 -0
- package/skills/graview-invariant/SKILL.md +112 -0
- package/skills/graview-lens/SKILL.md +187 -0
- package/skills/graview-new-app/SKILL.md +195 -0
- package/skills/graview-node-kind/SKILL.md +159 -0
- package/skills/graview-pages/SKILL.md +206 -0
- package/skills/graview-permissions/SKILL.md +145 -0
- package/skills/graview-port-app/SKILL.md +95 -0
- package/skills/graview-seed/SKILL.md +103 -0
- package/skills/graview-ship/SKILL.md +154 -0
- package/skills/graview-studio/SKILL.md +85 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
Elastic License 2.0
|
|
2
|
+
|
|
3
|
+
## Acceptance
|
|
4
|
+
|
|
5
|
+
By using the software, you agree to all of the terms and conditions below.
|
|
6
|
+
|
|
7
|
+
## Copyright License
|
|
8
|
+
|
|
9
|
+
The licensor grants you a non-exclusive, royalty-free, worldwide,
|
|
10
|
+
non-sublicensable, non-transferable license to use, copy, distribute, make
|
|
11
|
+
available, and prepare derivative works of the software, in each case subject
|
|
12
|
+
to the limitations and conditions below.
|
|
13
|
+
|
|
14
|
+
## Limitations
|
|
15
|
+
|
|
16
|
+
You may not provide the software to third parties as a hosted or managed
|
|
17
|
+
service, where the service provides users with access to any substantial set
|
|
18
|
+
of the features or functionality of the software.
|
|
19
|
+
|
|
20
|
+
You may not move, change, disable, or circumvent the license key
|
|
21
|
+
functionality in the software, and you may not remove or obscure any
|
|
22
|
+
functionality in the software that is protected by the license key.
|
|
23
|
+
|
|
24
|
+
You may not alter, remove, or obscure any licensing, copyright, or other
|
|
25
|
+
notices of the licensor in the software. Any use of the licensor's trademarks
|
|
26
|
+
is subject to applicable law.
|
|
27
|
+
|
|
28
|
+
## Patents
|
|
29
|
+
|
|
30
|
+
The licensor grants you a license, under any patent claims the licensor can
|
|
31
|
+
license, or becomes able to license, to make, have made, use, sell, offer for
|
|
32
|
+
sale, import and have imported the software, in each case subject to the
|
|
33
|
+
limitations and conditions in this license. This license does not cover any
|
|
34
|
+
patent claims that you cause to be infringed by modifications or additions to
|
|
35
|
+
the software. If you or your company make any written claim that the software
|
|
36
|
+
infringes or contributes to infringement of any patent, your patent license
|
|
37
|
+
for the software granted under these terms ends immediately. If your company
|
|
38
|
+
makes such a claim, your patent license ends immediately for work on behalf
|
|
39
|
+
of your company.
|
|
40
|
+
|
|
41
|
+
## Notices
|
|
42
|
+
|
|
43
|
+
You must ensure that anyone who gets a copy of any part of the software from
|
|
44
|
+
you also gets a copy of these terms.
|
|
45
|
+
|
|
46
|
+
If you modify the software, you must include in any modified copies of the
|
|
47
|
+
software prominent notices stating that you have modified the software.
|
|
48
|
+
|
|
49
|
+
## No Other Rights
|
|
50
|
+
|
|
51
|
+
These terms do not imply any licenses other than those expressly granted in
|
|
52
|
+
these terms.
|
|
53
|
+
|
|
54
|
+
## Termination
|
|
55
|
+
|
|
56
|
+
If you use the software in violation of these terms, such use is not
|
|
57
|
+
licensed, and your licenses will automatically terminate. If the licensor
|
|
58
|
+
provides you with a notice of your violation, and you cease all violation of
|
|
59
|
+
this license no later than 30 days after you receive that notice, your
|
|
60
|
+
licenses will be reinstated retroactively. However, if you violate these
|
|
61
|
+
terms after such reinstatement, any additional violation of these terms will
|
|
62
|
+
cause your licenses to terminate automatically and permanently.
|
|
63
|
+
|
|
64
|
+
## No Liability
|
|
65
|
+
|
|
66
|
+
*As far as the law allows, the software comes as is, without any warranty or
|
|
67
|
+
condition, and the licensor will not be liable to you for any damages arising
|
|
68
|
+
out of these terms or the use or nature of the software, under any kind of
|
|
69
|
+
legal claim.*
|
|
70
|
+
|
|
71
|
+
## Definitions
|
|
72
|
+
|
|
73
|
+
The **licensor** is the entity offering these terms, and the **software** is
|
|
74
|
+
the software the licensor makes available under these terms, including any
|
|
75
|
+
portion of it.
|
|
76
|
+
|
|
77
|
+
**you** refers to the individual or entity agreeing to these terms.
|
|
78
|
+
|
|
79
|
+
**your company** is any legal entity, sole proprietorship, or other kind of
|
|
80
|
+
organization that you work for, plus all organizations that have control
|
|
81
|
+
over, are under the control of, or are under common control with that
|
|
82
|
+
organization. **control** means ownership of substantially all the assets of
|
|
83
|
+
an entity, or the power to direct its management and policies by vote,
|
|
84
|
+
contract, or otherwise. Control can be direct or indirect.
|
|
85
|
+
|
|
86
|
+
**your licenses** are all the licenses granted to you for the software under
|
|
87
|
+
these terms.
|
|
88
|
+
|
|
89
|
+
**use** means anything you do with the software requiring one of your
|
|
90
|
+
licenses.
|
|
91
|
+
|
|
92
|
+
**trademark** means trademarks, service marks, and similar rights.
|
|
93
|
+
|
|
94
|
+
---
|
|
95
|
+
|
|
96
|
+
Copyright 2025-2026 En Dash Consulting
|
package/README.md
CHANGED
|
@@ -1,3 +1,47 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @graview/skills
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Skills that teach an assistant how to build with Graview — and, more usefully,
|
|
4
|
+
how to find out whether it worked.
|
|
5
|
+
|
|
6
|
+
```sh
|
|
7
|
+
npx graview skills install . # into .claude/skills and .agents/skills
|
|
8
|
+
npx graview skills list
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
The command line is the `graview` package; this one ships the skills and
|
|
12
|
+
the move, and `graview skills` dispatches here.
|
|
13
|
+
|
|
14
|
+
## Why this framework is worth having skills for
|
|
15
|
+
|
|
16
|
+
Most skills end in a claim: "you have added a node kind." That is worth very
|
|
17
|
+
little, because the assistant writing it is the same one that just decided it
|
|
18
|
+
was done.
|
|
19
|
+
|
|
20
|
+
Graview can answer the question itself. `graview check` reads the declaration
|
|
21
|
+
and reports an edge to a kind nobody wrote, an invariant scoped to a kind that
|
|
22
|
+
does not exist, a repair naming a mutation nobody registered, a lens role
|
|
23
|
+
bound to a missing field, a mutation with no title, a palette pair that fails
|
|
24
|
+
WCAG AA, a role that may do nothing. So every skill here **ends in a check and
|
|
25
|
+
reports the real verdict** — including when the verdict is bad.
|
|
26
|
+
|
|
27
|
+
A skill that cannot verify its own outcome says so. That is the rule, and the
|
|
28
|
+
skills say which parts of their work the checker cannot see.
|
|
29
|
+
|
|
30
|
+
## The skills
|
|
31
|
+
|
|
32
|
+
| Skill | The move it teaches |
|
|
33
|
+
|---|---|
|
|
34
|
+
| `graview-node-kind` | Add a node kind: fields, edges, plural, roles, and what renders for free |
|
|
35
|
+
| `graview-invariant` | Write a rule that names the mutations that would repair it |
|
|
36
|
+
| `graview-lens` | Build a lens that binds roles rather than field names, so another domain can reuse it |
|
|
37
|
+
| `graview-agent-seat` | Wire an agent seat that shares the interface's actions rather than shadowing them |
|
|
38
|
+
| `graview-permissions` | Declare who may do what, once, and let the strip and the seat narrow themselves |
|
|
39
|
+
| `graview-brand` | Put someone's name on an installation without forking a package |
|
|
40
|
+
| `graview-new-app` | Start a product on Graview in its own repository, with the CI that keeps it honest |
|
|
41
|
+
| `graview-pages` | The routed face: derived pages, one page in the app's words, a product design over every surface, and the embed |
|
|
42
|
+
| `graview-port-app` | Port an existing application onto Graview, deciding what is a node and what is a field |
|
|
43
|
+
| `graview-studio` | Open the declaration as a graph, change it with acts, check before applying, migrate, and write it back as the scaffold's files |
|
|
44
|
+
|
|
45
|
+
The worked examples live in `apps/` in the framework repository. The skills
|
|
46
|
+
point at them rather than restating them — a skill that copies an example goes
|
|
47
|
+
stale the moment the example changes.
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `graview skills` — installs the skills where Claude Code and Codex look
|
|
3
|
+
* for them.
|
|
4
|
+
*
|
|
5
|
+
* Copies rather than symlinks: a symlink into `node_modules` breaks the moment
|
|
6
|
+
* somebody prunes or reinstalls, and a skill that silently stops existing is
|
|
7
|
+
* worse than one that is a little stale. `install` is idempotent and replaces
|
|
8
|
+
* what it wrote before.
|
|
9
|
+
*
|
|
10
|
+
* Reached through the `graview` command line, which dispatches here; this
|
|
11
|
+
* package ships the skills and the move, not a bin of its own.
|
|
12
|
+
*/
|
|
13
|
+
export declare const SKILLS_USAGE: string;
|
|
14
|
+
export declare function skills(argv: readonly string[]): number;
|
|
15
|
+
//# sourceMappingURL=cli.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;;GAWG;AAEH,eAAO,MAAM,YAAY,QAGxB,CAAC;AAEF,wBAAgB,MAAM,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,CAiCtD"}
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { cpSync, existsSync, mkdirSync, rmSync } from "node:fs";
|
|
2
|
+
import { join, relative, resolve } from "node:path";
|
|
3
|
+
import { readSkills, SKILLS_DIR, SKILL_DESTINATIONS } from "./index.js";
|
|
4
|
+
/**
|
|
5
|
+
* `graview skills` — installs the skills where Claude Code and Codex look
|
|
6
|
+
* for them.
|
|
7
|
+
*
|
|
8
|
+
* Copies rather than symlinks: a symlink into `node_modules` breaks the moment
|
|
9
|
+
* somebody prunes or reinstalls, and a skill that silently stops existing is
|
|
10
|
+
* worse than one that is a little stale. `install` is idempotent and replaces
|
|
11
|
+
* what it wrote before.
|
|
12
|
+
*
|
|
13
|
+
* Reached through the `graview` command line, which dispatches here; this
|
|
14
|
+
* package ships the skills and the move, not a bin of its own.
|
|
15
|
+
*/
|
|
16
|
+
export const SKILLS_USAGE = ` graview skills install [dir] copy the skills into ${SKILL_DESTINATIONS.join(" and ")}
|
|
17
|
+
graview skills list what is in this package
|
|
18
|
+
graview skills path where the skill files live
|
|
19
|
+
`;
|
|
20
|
+
export function skills(argv) {
|
|
21
|
+
const [command = "help", target = process.cwd()] = argv;
|
|
22
|
+
const root = resolve(target);
|
|
23
|
+
if (command === "list") {
|
|
24
|
+
for (const skill of readSkills()) {
|
|
25
|
+
process.stdout.write(`${skill.name.padEnd(22)} ${skill.description}\n`);
|
|
26
|
+
}
|
|
27
|
+
return 0;
|
|
28
|
+
}
|
|
29
|
+
if (command === "path") {
|
|
30
|
+
process.stdout.write(`${SKILLS_DIR}\n`);
|
|
31
|
+
return 0;
|
|
32
|
+
}
|
|
33
|
+
if (command === "install") {
|
|
34
|
+
const all = readSkills();
|
|
35
|
+
for (const destination of SKILL_DESTINATIONS) {
|
|
36
|
+
const dir = join(root, destination);
|
|
37
|
+
mkdirSync(dir, { recursive: true });
|
|
38
|
+
for (const skill of all) {
|
|
39
|
+
const into = join(dir, skill.name);
|
|
40
|
+
// Replace rather than merge: a stale file left behind from an older
|
|
41
|
+
// version of a skill is a instruction nobody meant to give.
|
|
42
|
+
if (existsSync(into))
|
|
43
|
+
rmSync(into, { recursive: true, force: true });
|
|
44
|
+
cpSync(join(SKILLS_DIR, skill.name), into, { recursive: true });
|
|
45
|
+
}
|
|
46
|
+
process.stdout.write(`${all.length} skills → ${relative(root, dir) || destination}\n`);
|
|
47
|
+
}
|
|
48
|
+
process.stdout.write("\nEvery one of them ends in `graview check` and reports what it actually said.\n");
|
|
49
|
+
return 0;
|
|
50
|
+
}
|
|
51
|
+
process.stdout.write(`graview skills — the authoring moves, each ending in a real check\n\n${SKILLS_USAGE}`);
|
|
52
|
+
return command === "help" ? 0 : 1;
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAChE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpD,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAExE;;;;;;;;;;;GAWG;AAEH,MAAM,CAAC,MAAM,YAAY,GAAG,yDAAyD,kBAAkB,CAAC,IAAI,CAAC,OAAO,CAAC;;;CAGpH,CAAC;AAEF,MAAM,UAAU,MAAM,CAAC,IAAuB;IAC5C,MAAM,CAAC,OAAO,GAAG,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC,GAAG,IAAI,CAAC;IACxD,MAAM,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAE7B,IAAI,OAAO,KAAK,MAAM,EAAE,CAAC;QACvB,KAAK,MAAM,KAAK,IAAI,UAAU,EAAE,EAAE,CAAC;YACjC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,KAAK,CAAC,WAAW,IAAI,CAAC,CAAC;QAC1E,CAAC;QACD,OAAO,CAAC,CAAC;IACX,CAAC;IACD,IAAI,OAAO,KAAK,MAAM,EAAE,CAAC;QACvB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,UAAU,IAAI,CAAC,CAAC;QACxC,OAAO,CAAC,CAAC;IACX,CAAC;IACD,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;QAC1B,MAAM,GAAG,GAAG,UAAU,EAAE,CAAC;QACzB,KAAK,MAAM,WAAW,IAAI,kBAAkB,EAAE,CAAC;YAC7C,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC;YACpC,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YACpC,KAAK,MAAM,KAAK,IAAI,GAAG,EAAE,CAAC;gBACxB,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;gBACnC,oEAAoE;gBACpE,4DAA4D;gBAC5D,IAAI,UAAU,CAAC,IAAI,CAAC;oBAAE,MAAM,CAAC,IAAI,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;gBACrE,MAAM,CAAC,IAAI,CAAC,UAAU,EAAE,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YAClE,CAAC;YACD,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,GAAG,CAAC,MAAM,aAAa,QAAQ,CAAC,IAAI,EAAE,GAAG,CAAC,IAAI,WAAW,IAAI,CAAC,CAAC;QACzF,CAAC;QACD,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,kFAAkF,CAAC,CAAC;QACzG,OAAO,CAAC,CAAC;IACX,CAAC;IACD,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,wEAAwE,YAAY,EAAE,CAAC,CAAC;IAC7G,OAAO,OAAO,KAAK,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACpC,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Where the skill files live, relative to this module.
|
|
3
|
+
*
|
|
4
|
+
* `dist/` sits one level below the package root and `skills/` sits at it, so
|
|
5
|
+
* this resolves the same whether it is running from source or from an
|
|
6
|
+
* installed tarball — both of which ship `skills/`.
|
|
7
|
+
*/
|
|
8
|
+
export declare const SKILLS_DIR: string;
|
|
9
|
+
export interface SkillFile {
|
|
10
|
+
readonly name: string;
|
|
11
|
+
readonly description: string;
|
|
12
|
+
readonly path: string;
|
|
13
|
+
readonly body: string;
|
|
14
|
+
}
|
|
15
|
+
/** Every skill this package ships, read from disk. */
|
|
16
|
+
export declare function readSkills(dir?: string): readonly SkillFile[];
|
|
17
|
+
/**
|
|
18
|
+
* Where each assistant looks for skills.
|
|
19
|
+
*
|
|
20
|
+
* Both, always. A skill installed for one and not the other is a skill that
|
|
21
|
+
* works until somebody opens the project in the other editor, and finding out
|
|
22
|
+
* that way is worse than not having it.
|
|
23
|
+
*/
|
|
24
|
+
export declare const SKILL_DESTINATIONS: readonly [".claude/skills", ".agents/skills"];
|
|
25
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAIA;;;;;;GAMG;AACH,eAAO,MAAM,UAAU,QAItB,CAAC;AAEF,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAgBD,sDAAsD;AACtD,wBAAgB,UAAU,CAAC,GAAG,GAAE,MAAmB,GAAG,SAAS,SAAS,EAAE,CAezE;AAED;;;;;;GAMG;AACH,eAAO,MAAM,kBAAkB,+CAAgD,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { readdirSync, readFileSync } from "node:fs";
|
|
2
|
+
import { dirname, join, resolve } from "node:path";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
|
+
/**
|
|
5
|
+
* Where the skill files live, relative to this module.
|
|
6
|
+
*
|
|
7
|
+
* `dist/` sits one level below the package root and `skills/` sits at it, so
|
|
8
|
+
* this resolves the same whether it is running from source or from an
|
|
9
|
+
* installed tarball — both of which ship `skills/`.
|
|
10
|
+
*/
|
|
11
|
+
export const SKILLS_DIR = resolve(dirname(fileURLToPath(import.meta.url)), "..", "skills");
|
|
12
|
+
/** Reads the frontmatter a skill is required to carry. */
|
|
13
|
+
function frontmatter(text) {
|
|
14
|
+
if (!text.startsWith("---\n"))
|
|
15
|
+
return {};
|
|
16
|
+
const end = text.indexOf("\n---", 4);
|
|
17
|
+
if (end === -1)
|
|
18
|
+
return {};
|
|
19
|
+
const fields = {};
|
|
20
|
+
for (const line of text.slice(4, end).split("\n")) {
|
|
21
|
+
const colon = line.indexOf(":");
|
|
22
|
+
if (colon === -1)
|
|
23
|
+
continue;
|
|
24
|
+
fields[line.slice(0, colon).trim()] = line.slice(colon + 1).trim();
|
|
25
|
+
}
|
|
26
|
+
return fields;
|
|
27
|
+
}
|
|
28
|
+
/** Every skill this package ships, read from disk. */
|
|
29
|
+
export function readSkills(dir = SKILLS_DIR) {
|
|
30
|
+
return readdirSync(dir, { withFileTypes: true })
|
|
31
|
+
.filter((entry) => entry.isDirectory())
|
|
32
|
+
.map((entry) => {
|
|
33
|
+
const path = join(dir, entry.name, "SKILL.md");
|
|
34
|
+
const body = readFileSync(path, "utf8");
|
|
35
|
+
const fields = frontmatter(body);
|
|
36
|
+
return {
|
|
37
|
+
name: fields["name"] ?? entry.name,
|
|
38
|
+
description: fields["description"] ?? "",
|
|
39
|
+
path,
|
|
40
|
+
body,
|
|
41
|
+
};
|
|
42
|
+
})
|
|
43
|
+
.sort((a, b) => a.name.localeCompare(b.name));
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Where each assistant looks for skills.
|
|
47
|
+
*
|
|
48
|
+
* Both, always. A skill installed for one and not the other is a skill that
|
|
49
|
+
* works until somebody opens the project in the other editor, and finding out
|
|
50
|
+
* that way is worse than not having it.
|
|
51
|
+
*/
|
|
52
|
+
export const SKILL_DESTINATIONS = [".claude/skills", ".agents/skills"];
|
|
53
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACpD,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACnD,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG,OAAO,CAC/B,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EACvC,IAAI,EACJ,QAAQ,CACT,CAAC;AASF,0DAA0D;AAC1D,SAAS,WAAW,CAAC,IAAY;IAC/B,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC;QAAE,OAAO,EAAE,CAAC;IACzC,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;IACrC,IAAI,GAAG,KAAK,CAAC,CAAC;QAAE,OAAO,EAAE,CAAC;IAC1B,MAAM,MAAM,GAA2B,EAAE,CAAC;IAC1C,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;QAClD,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QAChC,IAAI,KAAK,KAAK,CAAC,CAAC;YAAE,SAAS;QAC3B,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,IAAI,EAAE,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IACrE,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,sDAAsD;AACtD,MAAM,UAAU,UAAU,CAAC,MAAc,UAAU;IACjD,OAAO,WAAW,CAAC,GAAG,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC;SAC7C,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC;SACtC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE;QACb,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;QAC/C,MAAM,IAAI,GAAG,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QACxC,MAAM,MAAM,GAAG,WAAW,CAAC,IAAI,CAAC,CAAC;QACjC,OAAO;YACL,IAAI,EAAE,MAAM,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,IAAI;YAClC,WAAW,EAAE,MAAM,CAAC,aAAa,CAAC,IAAI,EAAE;YACxC,IAAI;YACJ,IAAI;SACL,CAAC;IACJ,CAAC,CAAC;SACD,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;AAClD,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,gBAAgB,EAAE,gBAAgB,CAAU,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,53 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@graview/skills",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"description": "
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "Skills that teach an assistant the authoring moves, each ending in a real graview check verdict.",
|
|
6
|
+
"keywords": [
|
|
7
|
+
"graview",
|
|
8
|
+
"context-graph",
|
|
9
|
+
"typed-graph",
|
|
10
|
+
"interface",
|
|
11
|
+
"declarative",
|
|
12
|
+
"claude-code",
|
|
13
|
+
"agent-skills",
|
|
14
|
+
"ai-assistant"
|
|
15
|
+
],
|
|
16
|
+
"main": "./dist/index.js",
|
|
17
|
+
"types": "./dist/index.d.ts",
|
|
18
|
+
"exports": {
|
|
19
|
+
".": {
|
|
20
|
+
"types": "./dist/index.d.ts",
|
|
21
|
+
"default": "./dist/index.js"
|
|
22
|
+
},
|
|
23
|
+
"./cli": {
|
|
24
|
+
"types": "./dist/cli.d.ts",
|
|
25
|
+
"default": "./dist/cli.js"
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
"files": [
|
|
29
|
+
"dist",
|
|
30
|
+
"skills",
|
|
31
|
+
"README.md"
|
|
32
|
+
],
|
|
33
|
+
"sideEffects": false,
|
|
34
|
+
"repository": {
|
|
35
|
+
"type": "git",
|
|
36
|
+
"url": "git+https://github.com/en-dash-consulting/graview.git",
|
|
37
|
+
"directory": "packages/skills"
|
|
38
|
+
},
|
|
39
|
+
"publishConfig": {
|
|
40
|
+
"access": "public"
|
|
41
|
+
},
|
|
42
|
+
"license": "Elastic-2.0",
|
|
43
|
+
"homepage": "https://graview.dev/docs/packages/skills.html",
|
|
44
|
+
"bugs": {
|
|
45
|
+
"url": "https://github.com/en-dash-consulting/graview/issues"
|
|
46
|
+
},
|
|
47
|
+
"engines": {
|
|
48
|
+
"node": ">=22"
|
|
49
|
+
},
|
|
50
|
+
"scripts": {
|
|
51
|
+
"build": "tsc -b"
|
|
52
|
+
}
|
|
6
53
|
}
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: graview-agent-seat
|
|
3
|
+
description: Wire an agent seat into a Graview app that shares the interface's own actions rather than shadowing them, and verify the diffs are identical rather than assuming they are.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Wire an agent seat
|
|
7
|
+
|
|
8
|
+
There is no agent API to build. The tools generate from the same mutation
|
|
9
|
+
declarations a person's buttons come from, which is why an agent's edit
|
|
10
|
+
produces literally the same diff, lands in the same op log with an author, and
|
|
11
|
+
is undone by the same control. If you find yourself writing a second code path
|
|
12
|
+
for the agent, stop: that path is the one that will drift.
|
|
13
|
+
|
|
14
|
+
## Do this
|
|
15
|
+
|
|
16
|
+
1. **Create the runtime with a principal.**
|
|
17
|
+
|
|
18
|
+
```ts
|
|
19
|
+
const runtime = createToolRuntime(store, {
|
|
20
|
+
author: { kind: "agent", id: "claude", session: "ui", roles: ["analyst"] },
|
|
21
|
+
});
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
The author is a `Principal` — an author with roles — so what the log blames
|
|
25
|
+
and what the policy judged are one object. A seat's tools narrow to what
|
|
26
|
+
that principal may run, with no second list to keep in step. See
|
|
27
|
+
`graview-permissions`.
|
|
28
|
+
|
|
29
|
+
2. **Pick a transport.** `createInAppAdapter(runtime)` for a seat inside the
|
|
30
|
+
interface; `createMcpAdapter(runtime)` for an external client. Both are thin
|
|
31
|
+
wrappers over the same runtime — that is the whole design.
|
|
32
|
+
|
|
33
|
+
3. **Show the calls.** `runtime.onCall(listener)` announces every call as it
|
|
34
|
+
starts and as it settles. Feed it to `ActivityRail`. A diff says what
|
|
35
|
+
changed and never what was *considered*, so an agent turn without this is a
|
|
36
|
+
spinner and a toast.
|
|
37
|
+
|
|
38
|
+
4. **Report what it READ.** `useAttention(runtime)` pipes a settled read-only
|
|
39
|
+
call's node ids into the picture, so a kind lights faintly where the agent
|
|
40
|
+
looked. That is the half a diff cannot show, and the half that says whether
|
|
41
|
+
to trust what it then did.
|
|
42
|
+
|
|
43
|
+
5. **Find by name with `search_graph`, before `get_graph`.** It is the Find
|
|
44
|
+
box's matcher: hits with why they matched, `key:value` conditions
|
|
45
|
+
(`done:false`, `is:any` for the past, `kind:task`), and the records it
|
|
46
|
+
names counted as reads. Reading the whole graph to scan it is the move a
|
|
47
|
+
person with a search box never makes.
|
|
48
|
+
|
|
49
|
+
6. **Prefer `get_affordances` over composing calls by hand.** The tool
|
|
50
|
+
descriptions say so, and it matters: derived affordances cannot name an
|
|
51
|
+
action that does not exist or is not legal on this selection.
|
|
52
|
+
|
|
53
|
+
7. **Host the seat where the data is, for an agent outside the page.** An
|
|
54
|
+
editor's assistant or a scheduled worker does not need glue of its own:
|
|
55
|
+
|
|
56
|
+
```sh
|
|
57
|
+
graview mcp ./dist/domain/app.js --data ./data --as cursor --roles keeper
|
|
58
|
+
graview mcp ./dist/domain/app.js --remote-url http://localhost:5196 --roles keeper
|
|
59
|
+
graview apply ./dist/domain/app.js --data ./data --roles keeper \
|
|
60
|
+
--call add-task --args '{"listId":"today","label":"Book the van","id":"t-van"}'
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
`mcp` is MCP over stdio around this same runtime; `apply` is one act, a
|
|
64
|
+
plan of many as one batch, or an undo, from a shell. Both open the store
|
|
65
|
+
`graview serve` opens — a folder, SQLite, or a running server — and act
|
|
66
|
+
under the seat you name, so the policy refuses there what it refuses here.
|
|
67
|
+
Put `serve` and `mcp` in the app's scripts so the door is always there,
|
|
68
|
+
and tell the agent the seed is a first-install snapshot: it changes the
|
|
69
|
+
live graph through these, never by editing `example.json` and wiping.
|
|
70
|
+
`graview mcp <entry> --list --roles …` prints the seat's tools as
|
|
71
|
+
`tools/list` JSON — the catalog a host registers without writing one.
|
|
72
|
+
|
|
73
|
+
## Worked examples
|
|
74
|
+
|
|
75
|
+
- `apps/todo/src/ui/app.tsx` — the seat, the runtime, and an agent that finds
|
|
76
|
+
what it will change with `search_graph` before it moves
|
|
77
|
+
- `packages/tools/src/agent/tools.ts` — how the tools generate, and what a
|
|
78
|
+
read-only call reports about what it looked at
|
|
79
|
+
|
|
80
|
+
## Then find out whether it worked
|
|
81
|
+
|
|
82
|
+
```sh
|
|
83
|
+
pnpm build && npx graview check ./dist/domain/app.js
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
The checker verifies the mutations behind the tools: `mutation-untitled`,
|
|
87
|
+
`mutation-undescribed`, `mutation-title-ambiguous`. A tool description that
|
|
88
|
+
falls back to a title is a LABEL where an instruction belongs, and an agent
|
|
89
|
+
reads that string to decide whether to reach for it.
|
|
90
|
+
|
|
91
|
+
**And prove the paths are one path**, which is the claim this design exists to
|
|
92
|
+
support:
|
|
93
|
+
|
|
94
|
+
```ts
|
|
95
|
+
it("produces the same diff whether a human or an agent acts", async () => {
|
|
96
|
+
const byHand = human.apply({ name: "reassign", args });
|
|
97
|
+
const byAgent = await seat.call("reassign", args);
|
|
98
|
+
// A refusal is a RESULT, so `ToolResult` is a union: establish there was a
|
|
99
|
+
// diff before claiming anything about it, or this does not compile.
|
|
100
|
+
if (!byAgent.ok) throw new Error(byAgent.error);
|
|
101
|
+
expect(byAgent.diff).toEqual(byHand.diff);
|
|
102
|
+
});
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
**And prove the seat is bounded**, if it holds a restricted principal: call a
|
|
106
|
+
mutation it was not given a tool for and check it is refused by the STORE
|
|
107
|
+
rather than merely absent from the schema.
|
|
108
|
+
|
|
109
|
+
## What the check cannot see
|
|
110
|
+
|
|
111
|
+
- Whether the agent's turn is legible while it is happening. Open the app and
|
|
112
|
+
watch one; `pnpm watching` measures the marks but not whether they read.
|
|
113
|
+
- Whether the tool descriptions are good instructions. They are prose an agent
|
|
114
|
+
reasons from, and "get the graph" is worse than "read the whole graph: start
|
|
115
|
+
here when you need the shape of the domain rather than one thing in it".
|
|
116
|
+
- Whether the agent should be doing this at all.
|
|
117
|
+
|
|
118
|
+
## The seat is one of four surfaces on one seam
|
|
119
|
+
|
|
120
|
+
Everything intelligent travels the same contract — validated proposed calls
|
|
121
|
+
to declared mutations — so adding AI is choosing a provider, never a second
|
|
122
|
+
path to the store:
|
|
123
|
+
|
|
124
|
+
- **Providers** whisper suggestions into the companion's acts
|
|
125
|
+
(`insightProvider` ships in the defaults; `intelligenceProvider(...)`
|
|
126
|
+
wraps any `Intelligence`).
|
|
127
|
+
- **The seat** (this skill) runs one-press turns.
|
|
128
|
+
- **The companion** — `<Companion />`, the scene's left rail — is the one
|
|
129
|
+
place the seat lives: it names its subject (the selection, else the pick
|
|
130
|
+
the pointer settled on, else where you are), lists that subject's acts,
|
|
131
|
+
its relations, the conversation and the key. Right-click opens the same
|
|
132
|
+
acts at the pointer, so the context menu and the assistant are one
|
|
133
|
+
construct. The seat has no figure in the picture; other people's agents
|
|
134
|
+
still have theirs. `useSubject()` gives the same answer to any surface.
|
|
135
|
+
- **The conversation** — a section of that rail — answers questions in words.
|
|
136
|
+
Keyless it answers from the graph (`graphResponder`: standings, named
|
|
137
|
+
things, when/who, mutations phrased in their own titles); a model plugs in
|
|
138
|
+
through one completion function (`llmResponder`, `xaiCompletion`,
|
|
139
|
+
`localCompletion`), chosen by the person in the panel's gear. **Your own
|
|
140
|
+
responder goes in through the shell**: `<Shell chat={{ respond }} />`,
|
|
141
|
+
which hands it to the companion.
|
|
142
|
+
"Why do I still have mosquitoes?" is a walk through THIS graph, and the
|
|
143
|
+
generic answer to it is a plausible paragraph about gardens.
|
|
144
|
+
- **External agents** arrive over the derived tool surface with a scoped
|
|
145
|
+
principal.
|
|
146
|
+
- **A desk** — the model INSIDE the product, taking photographs or words and
|
|
147
|
+
proposing a plan somebody reviews. That is `graview-desk`; this skill is
|
|
148
|
+
the seat beside the product rather than the surface in it.
|
|
149
|
+
|
|
150
|
+
Declare what runs where on the app: `intelligence: [{ name, kind:
|
|
151
|
+
"graph" | "llm" | "external" | "decision", may: [...mutations] }]` —
|
|
152
|
+
`graview check` refuses an allowlist naming a mutation nobody registered,
|
|
153
|
+
refuses a `"decision"` provider (one that answers typed questions — a
|
|
154
|
+
choice, a truth, a score — and never prose) any act whose required
|
|
155
|
+
arguments want text, and the STORE
|
|
156
|
+
enforces it: hand the store `intelligence` and an author
|
|
157
|
+
`{ kind: "agent", id: "<provider name>" }` is refused anything outside its
|
|
158
|
+
`may`, on `apply` as on a tool call. `openStore` and the embed pass it
|
|
159
|
+
through for you.
|