@graphit/cli 0.2.208 → 0.2.242
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/.claude-plugin/marketplace.json +3 -3
- package/.claude-plugin/plugin.json +1 -1
- package/.codex-plugin/plugin.json +1 -1
- package/bin/graphit +1 -1
- package/bin/graphit.ps1 +1 -1
- package/dist/api/client.d.ts +36 -0
- package/dist/api/client.js +42 -0
- package/dist/api/client.js.map +1 -1
- package/dist/auth/credentials.d.ts +0 -1
- package/dist/auth/credentials.js.map +1 -1
- package/dist/auth/login.js +0 -1
- package/dist/auth/login.js.map +1 -1
- package/dist/commands/auth.js +0 -3
- package/dist/commands/auth.js.map +1 -1
- package/dist/commands/ds.js +67 -9
- package/dist/commands/ds.js.map +1 -1
- package/dist/commands/status.d.ts +51 -0
- package/dist/commands/status.js +117 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/output/format.js +18 -1
- package/dist/output/format.js.map +1 -1
- package/package.json +1 -1
- package/scripts/generate-commands-doc.mjs +1 -1
- package/skills/graphit/SKILL.md +11 -5
- package/skills/graphit/VERSION.json +1 -1
- package/skills/graphit/references/chart-patterns.md +1 -1
- package/skills/graphit/references/data-sources.md +9 -3
- package/skills/graphit/references/governance-explained.md +1 -1
- package/skills/graphit/references/kb-actions.md +13 -2
- package/skills/graphit/references/migration.md +89 -0
- package/skills/graphit/references/operations.md +6 -10
- package/skills/graphit/references/runtime.md +39 -59
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { apiClient } from "../api/client.js";
|
|
2
|
+
import { output, errorOutput, getOutputFormat, note } from "../output/format.js";
|
|
3
|
+
import { styledIntro, styledOutro, styledMessage, styledTable, } from "../output/styled.js";
|
|
4
|
+
export const DOMAIN_COLUMNS = ["domain", "query_access", "data_sources", "knowledge_base"];
|
|
5
|
+
// Scopes this CLI version knows how to render in the human views. Anything else
|
|
6
|
+
// the server sends still reaches the caller verbatim in --output json; the human
|
|
7
|
+
// views name it without guessing at its shape (FC-4).
|
|
8
|
+
const KNOWN_SCOPES = new Set(["templates"]);
|
|
9
|
+
const DEFAULT_ADVISORY = "Advisory only. Every operation is re-authorized at execution time and " +
|
|
10
|
+
"other permissions may still apply.";
|
|
11
|
+
/** Readable-domain rows for the table view. Tolerates a missing/!array field. */
|
|
12
|
+
export function statusDomainRows(status) {
|
|
13
|
+
return Array.isArray(status.domains) ? status.domains : [];
|
|
14
|
+
}
|
|
15
|
+
// A capability the server did not state is UNKNOWN, not denied. Rendering an
|
|
16
|
+
// absent field as "no" would invent a restriction the response never described -
|
|
17
|
+
// the same forward-compatibility trap as failing on an unknown key (FC-4).
|
|
18
|
+
function yesNo(value) {
|
|
19
|
+
if (value === true)
|
|
20
|
+
return "yes";
|
|
21
|
+
if (value === false)
|
|
22
|
+
return "no";
|
|
23
|
+
return "unknown";
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Human summary lines shared by the table and styled views: identity, profile,
|
|
27
|
+
* domain counts, the Templates scope, warehouse access, and policy freshness.
|
|
28
|
+
* Renders only what the server sent - it never infers a capability the response
|
|
29
|
+
* did not state, and hidden domains stay a count.
|
|
30
|
+
*/
|
|
31
|
+
export function statusLines(status) {
|
|
32
|
+
const identity = status.identity ?? {};
|
|
33
|
+
const profile = status.profile ?? {};
|
|
34
|
+
const policy = status.policy ?? {};
|
|
35
|
+
const scopes = status.special_scopes ?? {};
|
|
36
|
+
const domains = statusDomainRows(status);
|
|
37
|
+
const hidden = status.summary?.inaccessible_domain_count ?? 0;
|
|
38
|
+
const lines = [];
|
|
39
|
+
lines.push(`User: ${identity.user_id ?? "unknown"}`);
|
|
40
|
+
lines.push(`Organization: ${identity.org_id ?? "unknown"} (role: ${identity.org_role ?? "unknown"})`);
|
|
41
|
+
lines.push(profile.id
|
|
42
|
+
? `Profile: ${profile.name ?? profile.id}${profile.mode ? ` (${profile.mode})` : ""}`
|
|
43
|
+
: "Profile: none assigned");
|
|
44
|
+
if (profile.not_migrated) {
|
|
45
|
+
lines.push(" Profile predates domain permissions - ask an org admin to update it.");
|
|
46
|
+
}
|
|
47
|
+
lines.push(`Domains: ${domains.length} readable` + (hidden > 0 ? `, ${hidden} not visible` : ""));
|
|
48
|
+
const templates = scopes.templates;
|
|
49
|
+
if (templates) {
|
|
50
|
+
lines.push(`Templates: read/use ${yesNo(templates.read_use)}, write ${yesNo(templates.write)}`);
|
|
51
|
+
}
|
|
52
|
+
if (policy.allow_direct_warehouse !== undefined) {
|
|
53
|
+
lines.push(`Warehouse: direct queries ${policy.allow_direct_warehouse ? "allowed" : "not allowed"}`);
|
|
54
|
+
}
|
|
55
|
+
const freshness = [
|
|
56
|
+
policy.version != null ? `version ${policy.version}` : null,
|
|
57
|
+
policy.evaluated_at ? `evaluated ${policy.evaluated_at}` : null,
|
|
58
|
+
policy.max_cache_age_seconds != null ? `cached up to ${policy.max_cache_age_seconds}s` : null,
|
|
59
|
+
].filter(Boolean);
|
|
60
|
+
if (freshness.length > 0)
|
|
61
|
+
lines.push(`Policy: ${freshness.join(", ")}`);
|
|
62
|
+
const extra = Object.keys(scopes).filter((key) => !KNOWN_SCOPES.has(key));
|
|
63
|
+
if (extra.length > 0) {
|
|
64
|
+
lines.push(`Other scopes: ${extra.join(", ")} (see --output json)`);
|
|
65
|
+
}
|
|
66
|
+
lines.push("");
|
|
67
|
+
lines.push(typeof status.advisory === "string" && status.advisory ? status.advisory : DEFAULT_ADVISORY);
|
|
68
|
+
return lines;
|
|
69
|
+
}
|
|
70
|
+
export function registerStatusCommand(program) {
|
|
71
|
+
program
|
|
72
|
+
.command("status")
|
|
73
|
+
// Kept to one clause: a top-level leaf command's description is emitted TWICE
|
|
74
|
+
// in the generated table (group header + row), against a capped always-loaded
|
|
75
|
+
// file. The depth lives in references/operations.md.
|
|
76
|
+
.description("Show your effective permissions per domain (advisory; the server re-authorizes every operation)")
|
|
77
|
+
.action(async function () {
|
|
78
|
+
try {
|
|
79
|
+
const status = await apiClient.get("/api/v1/cli/status");
|
|
80
|
+
const fmt = getOutputFormat(this);
|
|
81
|
+
const rows = statusDomainRows(status);
|
|
82
|
+
if (fmt === "styled") {
|
|
83
|
+
styledIntro("graphit status");
|
|
84
|
+
// The same lines the table view prints, verbatim: any per-format
|
|
85
|
+
// reshaping here (e.g. splitting on ":") silently drops the lines that
|
|
86
|
+
// do not fit the shape, and the formats stop agreeing.
|
|
87
|
+
styledMessage(statusLines(status).join("\n"));
|
|
88
|
+
if (rows.length > 0) {
|
|
89
|
+
styledMessage(styledTable(DOMAIN_COLUMNS, rows.map((r) => [
|
|
90
|
+
r.domain,
|
|
91
|
+
r.query_access ?? "",
|
|
92
|
+
r.data_sources ?? "",
|
|
93
|
+
r.knowledge_base ?? "",
|
|
94
|
+
])));
|
|
95
|
+
}
|
|
96
|
+
// The advisory already closes the summary block above - repeating it in
|
|
97
|
+
// the outro reads as two different warnings.
|
|
98
|
+
styledOutro();
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
if (fmt === "json") {
|
|
102
|
+
// Verbatim server payload: unknown special_scopes keys and unknown
|
|
103
|
+
// top-level fields reach the caller untouched (FC-4).
|
|
104
|
+
output(this, status);
|
|
105
|
+
}
|
|
106
|
+
else {
|
|
107
|
+
output(this, rows, { columns: DOMAIN_COLUMNS });
|
|
108
|
+
}
|
|
109
|
+
for (const line of statusLines(status))
|
|
110
|
+
note(line);
|
|
111
|
+
}
|
|
112
|
+
catch (err) {
|
|
113
|
+
errorOutput(err);
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
//# sourceMappingURL=status.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"status.js","sourceRoot":"","sources":["../../src/commands/status.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,eAAe,EAAE,IAAI,EAAE,MAAM,qBAAqB,CAAC;AACjF,OAAO,EACL,WAAW,EACX,WAAW,EACX,aAAa,EACb,WAAW,GACZ,MAAM,qBAAqB,CAAC;AA6C7B,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,QAAQ,EAAE,cAAc,EAAE,cAAc,EAAE,gBAAgB,CAAC,CAAC;AAE3F,gFAAgF;AAChF,iFAAiF;AACjF,sDAAsD;AACtD,MAAM,YAAY,GAAG,IAAI,GAAG,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC;AAE5C,MAAM,gBAAgB,GACpB,wEAAwE;IACxE,oCAAoC,CAAC;AAEvC,iFAAiF;AACjF,MAAM,UAAU,gBAAgB,CAAC,MAAuB;IACtD,OAAO,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC;AAC7D,CAAC;AAED,6EAA6E;AAC7E,iFAAiF;AACjF,2EAA2E;AAC3E,SAAS,KAAK,CAAC,KAAc;IAC3B,IAAI,KAAK,KAAK,IAAI;QAAE,OAAO,KAAK,CAAC;IACjC,IAAI,KAAK,KAAK,KAAK;QAAE,OAAO,IAAI,CAAC;IACjC,OAAO,SAAS,CAAC;AACnB,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,WAAW,CAAC,MAAuB;IACjD,MAAM,QAAQ,GAAG,MAAM,CAAC,QAAQ,IAAI,EAAE,CAAC;IACvC,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,IAAI,EAAE,CAAC;IACrC,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,IAAI,EAAE,CAAC;IACnC,MAAM,MAAM,GAAG,MAAM,CAAC,cAAc,IAAI,EAAE,CAAC;IAC3C,MAAM,OAAO,GAAG,gBAAgB,CAAC,MAAM,CAAC,CAAC;IACzC,MAAM,MAAM,GAAG,MAAM,CAAC,OAAO,EAAE,yBAAyB,IAAI,CAAC,CAAC;IAC9D,MAAM,KAAK,GAAa,EAAE,CAAC;IAE3B,KAAK,CAAC,IAAI,CAAC,iBAAiB,QAAQ,CAAC,OAAO,IAAI,SAAS,EAAE,CAAC,CAAC;IAC7D,KAAK,CAAC,IAAI,CACR,iBAAiB,QAAQ,CAAC,MAAM,IAAI,SAAS,WAAW,QAAQ,CAAC,QAAQ,IAAI,SAAS,GAAG,CAC1F,CAAC;IACF,KAAK,CAAC,IAAI,CACR,OAAO,CAAC,EAAE;QACR,CAAC,CAAC,iBAAiB,OAAO,CAAC,IAAI,IAAI,OAAO,CAAC,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,OAAO,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;QAC1F,CAAC,CAAC,6BAA6B,CAClC,CAAC;IACF,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC;QACzB,KAAK,CAAC,IAAI,CAAC,oFAAoF,CAAC,CAAC;IACnG,CAAC;IACD,KAAK,CAAC,IAAI,CACR,iBAAiB,OAAO,CAAC,MAAM,WAAW,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,MAAM,cAAc,CAAC,CAAC,CAAC,EAAE,CAAC,CAC3F,CAAC;IAEF,MAAM,SAAS,GAAG,MAAM,CAAC,SAAgD,CAAC;IAC1E,IAAI,SAAS,EAAE,CAAC;QACd,KAAK,CAAC,IAAI,CACR,0BAA0B,KAAK,CAAC,SAAS,CAAC,QAAQ,CAAC,WAAW,KAAK,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,CACvF,CAAC;IACJ,CAAC;IAED,IAAI,MAAM,CAAC,sBAAsB,KAAK,SAAS,EAAE,CAAC;QAChD,KAAK,CAAC,IAAI,CACR,gCAAgC,MAAM,CAAC,sBAAsB,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,aAAa,EAAE,CAC5F,CAAC;IACJ,CAAC;IAED,MAAM,SAAS,GAAG;QAChB,MAAM,CAAC,OAAO,IAAI,IAAI,CAAC,CAAC,CAAC,WAAW,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,IAAI;QAC3D,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC,aAAa,MAAM,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC,IAAI;QAC/D,MAAM,CAAC,qBAAqB,IAAI,IAAI,CAAC,CAAC,CAAC,gBAAgB,MAAM,CAAC,qBAAqB,GAAG,CAAC,CAAC,CAAC,IAAI;KAC9F,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAClB,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC;QAAE,KAAK,CAAC,IAAI,CAAC,iBAAiB,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAE9E,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,YAAY,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;IAC1E,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACrB,KAAK,CAAC,IAAI,CAAC,iBAAiB,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAC;IACtE,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACf,KAAK,CAAC,IAAI,CAAC,OAAO,MAAM,CAAC,QAAQ,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC;IACxG,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,OAAgB;IACpD,OAAO;SACJ,OAAO,CAAC,QAAQ,CAAC;QAClB,8EAA8E;QAC9E,8EAA8E;QAC9E,qDAAqD;SACpD,WAAW,CAAC,iGAAiG,CAAC;SAC9G,MAAM,CAAC,KAAK;QACX,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,GAAG,CAAkB,oBAAoB,CAAC,CAAC;YAC1E,MAAM,GAAG,GAAG,eAAe,CAAC,IAAI,CAAC,CAAC;YAClC,MAAM,IAAI,GAAG,gBAAgB,CAAC,MAAM,CAAC,CAAC;YAEtC,IAAI,GAAG,KAAK,QAAQ,EAAE,CAAC;gBACrB,WAAW,CAAC,gBAAgB,CAAC,CAAC;gBAC9B,iEAAiE;gBACjE,uEAAuE;gBACvE,uDAAuD;gBACvD,aAAa,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;gBAC9C,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;oBACpB,aAAa,CACX,WAAW,CACT,cAAc,EACd,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;wBACd,CAAC,CAAC,MAAM;wBACR,CAAC,CAAC,YAAY,IAAI,EAAE;wBACpB,CAAC,CAAC,YAAY,IAAI,EAAE;wBACpB,CAAC,CAAC,cAAc,IAAI,EAAE;qBACvB,CAAC,CACH,CACF,CAAC;gBACJ,CAAC;gBACD,wEAAwE;gBACxE,6CAA6C;gBAC7C,WAAW,EAAE,CAAC;gBACd,OAAO;YACT,CAAC;YAED,IAAI,GAAG,KAAK,MAAM,EAAE,CAAC;gBACnB,mEAAmE;gBACnE,sDAAsD;gBACtD,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;YACvB,CAAC;iBAAM,CAAC;gBACN,MAAM,CAAC,IAAI,EAAE,IAAI,EAAE,EAAE,OAAO,EAAE,cAAc,EAAE,CAAC,CAAC;YAClD,CAAC;YACD,KAAK,MAAM,IAAI,IAAI,WAAW,CAAC,MAAM,CAAC;gBAAE,IAAI,CAAC,IAAI,CAAC,CAAC;QACrD,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,WAAW,CAAC,GAAG,CAAC,CAAC;QACnB,CAAC;IACH,CAAC,CAAC,CAAC;AACP,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
import "./ca-guard.js";
|
|
6
6
|
import { Command } from "commander";
|
|
7
7
|
import { registerAuthCommands } from "./commands/auth.js";
|
|
8
|
+
import { registerStatusCommand } from "./commands/status.js";
|
|
8
9
|
import { registerKBCommands } from "./commands/kb.js";
|
|
9
10
|
import { registerQueryCommands } from "./commands/query.js";
|
|
10
11
|
import { registerDSCommands } from "./commands/ds.js";
|
|
@@ -27,6 +28,7 @@ program
|
|
|
27
28
|
.version(getCurrentVersion())
|
|
28
29
|
.option("--output <format>", "Output format: json (default), table, or styled", "json");
|
|
29
30
|
registerAuthCommands(program);
|
|
31
|
+
registerStatusCommand(program);
|
|
30
32
|
registerKBCommands(program);
|
|
31
33
|
registerQueryCommands(program);
|
|
32
34
|
registerDSCommands(program);
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/output/format.js
CHANGED
|
@@ -28,9 +28,15 @@ export function output(cmd, data, opts) {
|
|
|
28
28
|
export function note(message = "") {
|
|
29
29
|
console.error(message);
|
|
30
30
|
}
|
|
31
|
+
// Project #263: a denial reaches the caller with its machine-readable problem
|
|
32
|
+
// intact, alongside the human message. The message carries only the server's own
|
|
33
|
+
// safe `detail` and `next_step` - never a raw status code, a hidden resource
|
|
34
|
+
// name, or a locally invented explanation - and a denial always exits nonzero,
|
|
35
|
+
// so a deterministic "you cannot do this" can never read as success.
|
|
31
36
|
export function errorOutput(err) {
|
|
32
37
|
let message;
|
|
33
38
|
let retryAfter;
|
|
39
|
+
let problem;
|
|
34
40
|
if (err instanceof Error) {
|
|
35
41
|
message = err.message;
|
|
36
42
|
}
|
|
@@ -40,6 +46,9 @@ export function errorOutput(err) {
|
|
|
40
46
|
if (typeof obj.retry_after_seconds === "number") {
|
|
41
47
|
retryAfter = obj.retry_after_seconds;
|
|
42
48
|
}
|
|
49
|
+
if (obj.problem && typeof obj.problem === "object" && !Array.isArray(obj.problem)) {
|
|
50
|
+
problem = obj.problem;
|
|
51
|
+
}
|
|
43
52
|
}
|
|
44
53
|
else {
|
|
45
54
|
message = String(err);
|
|
@@ -47,7 +56,15 @@ export function errorOutput(err) {
|
|
|
47
56
|
if (retryAfter !== undefined) {
|
|
48
57
|
message = `${message} Retry in ${retryAfter}s.`;
|
|
49
58
|
}
|
|
50
|
-
|
|
59
|
+
// Read the field, never match the prose: the server owns the corrective step.
|
|
60
|
+
const nextStep = problem?.next_step;
|
|
61
|
+
if (typeof nextStep === "string" && nextStep && !message.includes(nextStep)) {
|
|
62
|
+
message = `${message} ${nextStep}`;
|
|
63
|
+
}
|
|
64
|
+
const payload = { error: message };
|
|
65
|
+
if (problem)
|
|
66
|
+
payload.problem = problem;
|
|
67
|
+
console.error(JSON.stringify(payload));
|
|
51
68
|
process.exit(1);
|
|
52
69
|
}
|
|
53
70
|
//# sourceMappingURL=format.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"format.js","sourceRoot":"","sources":["../../src/output/format.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACvC,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAoBzD,MAAM,UAAU,eAAe,CAAC,GAAY;IAC1C,IAAI,IAAI,GAAG,GAAG,CAAC;IACf,OAAO,IAAI,CAAC,MAAM;QAAE,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC;IACvC,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC,MAAgB,CAAC;IAC5C,IAAI,MAAM,KAAK,QAAQ;QAAE,OAAO,QAAQ,CAAC;IACzC,OAAO,MAAM,KAAK,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC;AAC/C,CAAC;AAED,MAAM,UAAU,MAAM,CACpB,GAAY,EACZ,IAAa,EACb,IAAiD;IAEjD,MAAM,MAAM,GAAG,eAAe,CAAC,GAAG,CAAC,CAAC;IAEpC,IAAI,MAAM,KAAK,MAAM,EAAE,CAAC;QACtB,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC;QAC9B,OAAO;IACT,CAAC;IAED,IAAI,IAAI,EAAE,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;QAC3C,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,IAA+B,CAAC,CAAC,CAAC;QAC7D,OAAO;IACT,CAAC;IAED,MAAM,IAAI,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IACjD,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC,IAAiC,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC;AAC7E,CAAC;AAED,8EAA8E;AAC9E,iFAAiF;AACjF,+EAA+E;AAC/E,MAAM,UAAU,IAAI,CAAC,OAAO,GAAG,EAAE;IAC/B,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;AACzB,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,GAAY;IACtC,IAAI,OAAe,CAAC;IACpB,IAAI,UAA8B,CAAC;
|
|
1
|
+
{"version":3,"file":"format.js","sourceRoot":"","sources":["../../src/output/format.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -28,7 +28,7 @@ const END = "<!-- COMMANDS:END -->";
|
|
|
28
28
|
|
|
29
29
|
// Mirrors index.ts registration order; groups not listed are appended alphabetically.
|
|
30
30
|
const GROUP_ORDER = [
|
|
31
|
-
"auth", "kb", "query", "metadata", "ds", "dashboard",
|
|
31
|
+
"auth", "status", "kb", "query", "metadata", "ds", "dashboard",
|
|
32
32
|
"connector", "governance", "team", "plugin", "setup",
|
|
33
33
|
];
|
|
34
34
|
|
package/skills/graphit/SKILL.md
CHANGED
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
name: graphit
|
|
3
3
|
description: >-
|
|
4
4
|
Use Graphit for ANY question about the user's business or product data: metrics, KPIs, revenue, retention, spend, users, cohorts, funnels, trends, comparisons, "why did X change", "how are we doing on Y", analysis, reports, or dashboards. Activate even when the user does not say "Graphit" or name any tool: if someone wants to understand their numbers, this is the tool. Graphit answers through a governed semantic layer (computed the team's way, reusable and safe to share) and delivers the answer as a fast cached-data query or a hand-authored interactive HTML dashboard, and can create the metrics, dimensions, and rules an answer needs. Prefer Graphit over hand-rolled one-off analysis whenever the data is, or could be, the user's business data. Skip only for pure software tasks (code, logs, config, infra) or data with nothing to do with the user's business.
|
|
5
|
-
skill_version: "0.2.
|
|
5
|
+
skill_version: "0.2.242"
|
|
6
6
|
---
|
|
7
7
|
|
|
8
|
-
<!-- SIZE EXEMPTION (SKILL.md): standard hard limit 12,288 chars, exempted ceiling
|
|
8
|
+
<!-- SIZE EXEMPTION (SKILL.md): standard hard limit 12,288 chars, exempted ceiling 29,696. Always-loaded: the collaboration/pace spine, hard constraints + scope gate, the loop, and the generated command table (COMMANDS markers, scripts/generate-commands-doc.mjs) - needed every turn, cannot defer to a reference. Marker sits after the frontmatter so the loader and sync-plugin-version.mjs parse it. Reviewed 2026-07-20. -->
|
|
9
9
|
|
|
10
10
|
# Graphit CLI
|
|
11
11
|
|
|
@@ -105,7 +105,7 @@ One loop serves both jobs. Each step names the reference to read when you need d
|
|
|
105
105
|
- Data source. `graphit kb explore domain <NAME>` returns that domain's data sources plus their metrics, dimensions, and rules in one traversal (`graphit ds list` for the full list); present the sources, ask which one, or offer to create one if none fits.
|
|
106
106
|
- Assets. Present the chosen source's metrics, dimensions, and rules as the working set and confirm it. If the user's wording doesn't match an asset, resolve it with `graphit kb search` (semantic, ranked by relevance) before assuming a mapping; for a cross-domain investigation, broaden across the whole KB. A 0-result search is not proof of absence (results are ranked and capped) - confirm a specific name with `kb get` first. Then proceed.
|
|
107
107
|
Ask via the structured ask-user tool above, options pre-populated from what you listed. Read references/kb-discovery.md, references/kb-traversal.md, references/data-sources.md.
|
|
108
|
-
3. KB-readiness gate (BLOCKING). Check the knowledge base has the metrics and dimensions this question needs - name them from the user's ask and the domain's real assets you just listed. If they exist, proceed. If any are missing, STOP and build the knowledge base first: identify the missing concepts, show a gap table (what is missing, the proposed definition, which rules apply), get approval, then create and verify the assets. Read references/kb-structure.md, references/kb-actions.md, and references/parameterized-metrics.md for variant axes (D7/D30, gross/net). This gate is not optional - do not reframe it as the user's choice.
|
|
108
|
+
3. KB-readiness gate (BLOCKING). Check the knowledge base has the metrics and dimensions this question needs - name them from the user's ask and the domain's real assets you just listed. If they exist, proceed. If any are missing, STOP and build the knowledge base first: identify the missing concepts, show a gap table (what is missing, the proposed definition, which rules apply), get approval, then create and verify the assets. Run `graphit status` first for the domains you can write to - advisory (the server still decides). Read references/kb-structure.md, references/kb-actions.md, and references/parameterized-metrics.md for variant axes (D7/D30, gross/net). This gate is not optional - do not reframe it as the user's choice.
|
|
109
109
|
4. Investigate. Write governed queries with `{{metric:NAME}}` / `{{dim:NAME}}` reference syntax, validate before you rely on them, show the rows, then propose the next cut or the first graph before building it. Ad-hoc only at the frontier, provenance-tagged. Read references/sql-reference.md, references/governance.md.
|
|
110
110
|
5. Deliver. A quick query result for a one-off; a designed HTML dashboard for anything recurring or shared; or a written report artifact - insight digest, analysis one-pager, postmortem - when narrative should lead. Build and show one section at a time, not one finished deliverable at the end. Pull only the reference for the move you are making:
|
|
111
111
|
- Frame and plan the dashboard (or report artifact): references/dashboard-planning.md.
|
|
@@ -148,13 +148,14 @@ Read the one that matches what you are doing now. Do not preload them. Exact com
|
|
|
148
148
|
| designing and rendering the dashboard | dashboard-planning.md, chart-selection.md, chart-patterns.md, graphit-style.md, runtime.md, kpi.md, table.md |
|
|
149
149
|
| adding interactivity (filters, parameters, saved views) | filters.md, filters-advanced.md |
|
|
150
150
|
| building a slide deck | presentations.md |
|
|
151
|
+
| moving an existing dashboard's queries onto its entities, or explaining a legacy-query save warning | migration.md |
|
|
151
152
|
| the CLI or plugin itself (health, permission errors, local working artifacts) | operations.md |
|
|
152
153
|
| installing, updating, or repairing Graphit itself | install-update.md |
|
|
153
154
|
| reporting a failure or a partial result | reporting.md |
|
|
154
155
|
|
|
155
156
|
## Commands
|
|
156
157
|
|
|
157
|
-
Graphit is one CLI, but how you invoke it depends on your environment. On Claude Code the plugin provides a `graphit` wrapper, so `graphit <command>` runs the current CLI. On Codex, Cursor, a terminal, or CI there is no `graphit` wrapper - invoke the CLI explicitly with `npx -y @graphit/cli@0.2.
|
|
158
|
+
Graphit is one CLI, but how you invoke it depends on your environment. On Claude Code the plugin provides a `graphit` wrapper, so `graphit <command>` runs the current CLI. On Codex, Cursor, a terminal, or CI there is no `graphit` wrapper - invoke the CLI explicitly with `npx -y @graphit/cli@0.2.242 <command>` (a stamped version, kept current by the build; pin an exact version for a reproducible run). The table below is generated from the CLI itself. For exact flags, run `graphit <command> --help` - never guess a flag.
|
|
158
159
|
|
|
159
160
|
<!-- COMMANDS:START -->
|
|
160
161
|
|
|
@@ -165,6 +166,9 @@ _Generated from the CLI by `npm run gen:commands` - do not hand-edit between the
|
|
|
165
166
|
- `auth status` - Show current authentication status
|
|
166
167
|
- `auth logout` - Log out and clear stored credentials
|
|
167
168
|
|
|
169
|
+
**status** - Show your effective permissions per domain (advisory; the server re-authorizes every operation)
|
|
170
|
+
- `status` - Show your effective permissions per domain (advisory; the server re-authorizes every operation)
|
|
171
|
+
|
|
168
172
|
**kb** - Knowledge Base operations
|
|
169
173
|
- `kb list <type>` - List KB entities (metric, dimension, table, rule, domain, synonym) - the inventory verb. Parameterized metrics are collapsed: each template shows a variant_count, child variants are hidden. Use --include-variants for the full flat set, kb explore metric <name> to enumerate one template's variants, kb get for the full definition. The response carries total/truncated, so fewer rows than total means raise --limit. - `--limit --verified --unverified --include-variants`
|
|
170
174
|
- `kb get <type> <name>` - Get a KB entity by name
|
|
@@ -201,10 +205,12 @@ _Generated from the CLI by `npm run gen:commands` - do not hand-edit between the
|
|
|
201
205
|
|
|
202
206
|
**ds** - Data source management
|
|
203
207
|
- `ds refresh-history <id>` - Show recent refresh runs for a data source with the Snowflake query id per run (status, time, rows, duration). Runs from before query-id capture - or a failure before any query ran - show 'not captured'. Read-only; no ds refresh-history delete. - `--limit`
|
|
208
|
+
- `ds delete <id>` - Delete a data source - not available on the CLI, use the Sources Hub
|
|
209
|
+
- `ds move <id>` - Move a data source between domains - not available on the CLI, use the Sources Hub
|
|
204
210
|
- `ds list` - List data sources - `--limit`
|
|
205
211
|
- `ds create` - Create a data source from a SQL query (--sql) or a local Excel/CSV file (--file) - `--sql --name --connection --schema --skip-scan --detect-tables --source-tables --file --domain --sheet`
|
|
206
212
|
- `ds refresh [ids...]` - Refresh data sources (use --all for all, or pass one or more IDs). On a breaking schema change a refresh is paused (status 'schema_changed') and the old data keeps serving; re-run with --force to accept the new schema. - `--all --no-wait --skip-empty --force`
|
|
207
|
-
- `ds verify <id>` - Scan an unverified data source's schema and review it. Warehouse/SQL sources print a verification link; add --accept-schema to accept the AI schema and activate from the CLI. File uploads activate
|
|
213
|
+
- `ds verify <id>` - Scan an unverified data source's schema and review it, and activate it. Warehouse/SQL sources print a verification link; add --accept-schema to accept the AI schema and activate from the CLI. File uploads activate on this command without --accept-schema, but NOT on create: `ds create --file` leaves them at pending_verification until you run this. Requires data_source_write in the source's domain. - `--force --accept-schema`
|
|
208
214
|
- `ds update <id>` - Update a data source row cap - `--max-rows`
|
|
209
215
|
- `ds refresh-config <id>` - Configure a data source's refresh mode (full or incremental/watermark) and settings. Sets the complete incremental config each call - omitted flags reset to server defaults (e.g. omitting --table-lookback clears existing lookback windows). - `--mode --watermark-column --watermark-type --merge-key --merge-window --table-lookback --reconciliation`
|
|
210
216
|
|
|
@@ -56,7 +56,7 @@ For a custom look, draw your own SVG through the same entry: `graphit.graph(el,
|
|
|
56
56
|
Escaping is yours: data-derived text through `ctx.esc()`, author colors through `ctx.safeColor()` - the runtime does not auto-escape your marks. Opt out per concern with `responsive: false` (render once) or `themed: false` (no dark re-draw).
|
|
57
57
|
|
|
58
58
|
```js
|
|
59
|
-
const r = await graphit.resolve({
|
|
59
|
+
const r = await graphit.resolve({ target: "#chart" });
|
|
60
60
|
graphit.graph("#chart", { type: "custom", draw: (ctx) => r.data.map(function (row, i) {
|
|
61
61
|
var h = ctx.num(row.value) / 100 * ctx.height, x = (ctx.width / r.data.length) * i;
|
|
62
62
|
return '<rect x="' + x + '" y="' + (ctx.height - h) + '" width="22" height="' + h +
|
|
@@ -55,7 +55,7 @@ graphit ds create --name "MY_DS" --sql "SELECT ..." --skip-scan
|
|
|
55
55
|
|
|
56
56
|
**Warehouse connection.** `--connection` names the warehouse a `--sql` source reads from. Add BigQuery with `graphit connector add bigquery-serviceaccount --key-file <path> [--project --dataset --location]` (org admin; project defaults from the key). The pipeline routes by connection type - the same `ds create` works for either warehouse.
|
|
57
57
|
|
|
58
|
-
For existing unverified sources, `graphit ds verify <id>` scans and shows the schema; add `--accept-schema` to accept the AI schema and activate a warehouse/SQL source from the CLI
|
|
58
|
+
For existing unverified sources, `graphit ds verify <id>` scans and shows the schema; add `--accept-schema` to accept the AI schema and activate a warehouse/SQL source from the CLI. A file upload needs `ds verify` too - it activates without `--accept-schema`, but never at create time, so it stays unqueryable until you run it.
|
|
59
59
|
|
|
60
60
|
## Refreshing data sources
|
|
61
61
|
|
|
@@ -80,7 +80,7 @@ Refreshes fire in parallel; polls to completion (large sources 30-60s), or retur
|
|
|
80
80
|
|
|
81
81
|
## Incremental refresh and early-filtering (advanced)
|
|
82
82
|
|
|
83
|
-
Incremental mode fetches only rows past a watermark and merges them in. Three windows govern it: the **watermark column** (which output rows are new), the **merge window** (`--merge-window` - how far back each run re-fetches and upserts, healing late data; API responses call it `lookback_periods`), and per-table **lookback windows** (`--table-lookback` - how far back each source table is *read*). Set on a scanned source
|
|
83
|
+
Incremental mode fetches only rows past a watermark and merges them in. Three windows govern it: the **watermark column** (which output rows are new), the **merge window** (`--merge-window` - how far back each run re-fetches and upserts, healing late data; API responses call it `lookback_periods`), and per-table **lookback windows** (`--table-lookback` - how far back each source table is *read*). Set on a scanned source; each call sets the COMPLETE config - omitted flags reset to defaults (no `--table-lookback` = windows cleared).
|
|
84
84
|
|
|
85
85
|
When a source aggregates over a wide internal window (e.g. a multi-year rollup), incremental refresh is nearly as slow as full: the outer watermark filter can't prune the inner scan. Early-filtering fixes that - get the contract right first, or older periods silently corrupt on merge:
|
|
86
86
|
|
|
@@ -104,9 +104,15 @@ graphit ds refresh-config <id> --mode incremental \
|
|
|
104
104
|
|
|
105
105
|
Only early-filter when an incremental source is slow for this reason; the default refresh is correct and simpler otherwise.
|
|
106
106
|
|
|
107
|
+
## What needs write access
|
|
108
|
+
|
|
109
|
+
Querying a source, listing sources, reading schema or refresh history, and an ordinary `graphit ds refresh` are reads - any member who can read that source's domain can run them, and a source in a domain they cannot read returns the same uniform 404 as one that does not exist. These need `data_source_write` in the source's domain: `ds create`, editing its SQL, `ds refresh-config`, a `--force` refresh or accepting a schema, `ds verify`, scanning, per-source governance settings, and deletion. Moving a source to another domain needs write in both the old and the new domain, and `ds create` must name a domain the caller can write to.
|
|
110
|
+
|
|
111
|
+
Check `graphit status` for those domains before proposing a create or a config change. It is advisory - the server authorizes each operation when it runs, and a denial with `retryable: false` is a stop, not a retry (`operations.md`).
|
|
112
|
+
|
|
107
113
|
## Deleting data sources
|
|
108
114
|
|
|
109
|
-
|
|
115
|
+
`ds delete` is not available on the CLI. Deleting a data source cascades to storage and the KB table, removing all metrics, dimensions, and rules on it. Direct the user to the platform UI (Sources Hub), whose confirmation flow shows what will be affected.
|
|
110
116
|
|
|
111
117
|
## Presenting data source results
|
|
112
118
|
|
|
@@ -33,7 +33,7 @@ Enforcement is server-side and identical on every channel (agent, CLI, dashboard
|
|
|
33
33
|
| Unenforced rule | A rule that structurally cannot act on anything |
|
|
34
34
|
| Missing owner | Assets with nobody responsible for them |
|
|
35
35
|
|
|
36
|
-
Fix is a guided one-click resolution: it drafts and previews the exact change, you apply it (
|
|
36
|
+
Fix is a guided one-click resolution: it drafts and previews the exact change, you apply it (same validation as a manual edit), then Graphit re-checks and clears the card. This queue lives only in the **web app's Governance page** - the CLI cannot list or fix Insights cards (`governance status` and `governance audit` report conformance only). When a user asks about a finding, explain what it means and point them to the Governance page to Fix it.
|
|
37
37
|
|
|
38
38
|
## Relaying it
|
|
39
39
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# KB Actions (Execute)
|
|
2
2
|
|
|
3
|
-
The execute side of KB work: run approved create / update / delete through the `graphit kb` commands. The plan side - what a domain or topic is, why an asset sits where it does - lives in `kb-structure.md`.
|
|
3
|
+
The execute side of KB work: run approved create / update / delete through the `graphit kb` commands. The plan side - what a domain or topic is, why an asset sits where it does - lives in `kb-structure.md`.
|
|
4
4
|
|
|
5
5
|
Create only after the user approves the gap plan below. Names are stored UPPER_SNAKE_CASE. Run `graphit kb create <type> --help` for the exact flag spelling - this file teaches the recipes and policy, the CLI owns the syntax.
|
|
6
6
|
|
|
@@ -77,7 +77,18 @@ Reference a **metric or dimension** onto another table with `graphit kb update m
|
|
|
77
77
|
|
|
78
78
|
Domain is set on the TABLE, never per asset, and cascades to every asset on it (model in `kb-structure.md`). To re-home a whole table at once: `graphit kb update table NAME --domain MARKETING`. Change it once on the table, never asset by asset.
|
|
79
79
|
|
|
80
|
-
##
|
|
80
|
+
## Who can write what
|
|
81
|
+
|
|
82
|
+
Reads are open to every member; writes are scoped by the caller's data access profile. Check `graphit status` before presenting a gap plan, so the plan is one they can execute.
|
|
83
|
+
|
|
84
|
+
| Write | Needs |
|
|
85
|
+
|---|---|
|
|
86
|
+
| Metric, dimension, rule, synonym, relationship, table | `kb_write` in the asset's domain |
|
|
87
|
+
| Moving an asset or table to another domain | `kb_write` in BOTH domains - the one it leaves and the one it enters |
|
|
88
|
+
| Domain and topic create / update / delete | Org admin; a profile never grants it |
|
|
89
|
+
| Template create / update / delete | Org admin, OR `kb_write` in any one domain - never a per-template or per-domain grant |
|
|
90
|
+
|
|
91
|
+
Every member can read and use templates. Status is advisory; a denial with `retryable: false` is a stop, not a retry (`operations.md`).
|
|
81
92
|
|
|
82
93
|
To find what exists and how it connects, use the read recipes in `kb-traversal.md`.
|
|
83
94
|
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
# Migrating a dashboard to entity-owned queries
|
|
2
|
+
|
|
3
|
+
Load when the user asks to move an existing dashboard's queries onto its entities, or what a
|
|
4
|
+
`legacy_query_source` save warning means. Not for authoring new dashboards: new work is canonical
|
|
5
|
+
from the start (references/runtime.md).
|
|
6
|
+
|
|
7
|
+
## What the old shape is
|
|
8
|
+
|
|
9
|
+
Older dashboards author the same query twice. The call carries it:
|
|
10
|
+
|
|
11
|
+
```js
|
|
12
|
+
graphit.resolve({ sql: "SELECT ... WHERE d >= :start", dataSourceId: "MARKETING_UA_DS",
|
|
13
|
+
params: { start: pStart.get() }, sourceEntityId: "spend-trend" })
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
and the entity carries a copy in `data-graphit-sql` / `data-graphit-ds`. Both still work, and they
|
|
17
|
+
drift: only the call executes, only the attribute is inspected.
|
|
18
|
+
|
|
19
|
+
Canonical is the same query written once, on the entity, the call naming which entity to run:
|
|
20
|
+
|
|
21
|
+
```js
|
|
22
|
+
graphit.resolve({ sourceEntityId: "spend-trend", params: { start: pStart.get() } })
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Hard rules
|
|
26
|
+
|
|
27
|
+
**NEVER migrate a dashboard the user did not ask about.** This is opt-in. An unrelated edit never
|
|
28
|
+
rewires where a query lives, and "while I was in there" is not a reason.
|
|
29
|
+
|
|
30
|
+
**NEVER save a partial or unverified migration.** Half-moved is worse than not moved. If you cannot
|
|
31
|
+
finish and verify a query, put it back the way you found it.
|
|
32
|
+
|
|
33
|
+
**MUST leave the dashboard untouched when you cannot prove equivalence.** Stop, change nothing, and
|
|
34
|
+
name the exact branch you could not compare. That is a successful outcome, not a failure.
|
|
35
|
+
|
|
36
|
+
## Procedure
|
|
37
|
+
|
|
38
|
+
1. **Read everything first.** Get the full HTML and all its wiring before changing one call.
|
|
39
|
+
Migrating call by call misses shared queries and conditional branches.
|
|
40
|
+
2. **Find the owner of each query.** One source entity owns it; any other entity rendered from the
|
|
41
|
+
same result is a target. A query feeding three graphs still has exactly one owner.
|
|
42
|
+
3. **Lift the complete template onto the owner.** The whole statement in `data-graphit-sql`, the data
|
|
43
|
+
source in `data-graphit-ds`. Complete means executable and parameterized:
|
|
44
|
+
- Keep every `:named` placeholder. Do not bake current filter values in.
|
|
45
|
+
- Keep `{{metric:NAME}}` / `{{dim:NAME}}` references as they are.
|
|
46
|
+
- No ellipsis, no abbreviation, real table names, full WITH clause.
|
|
47
|
+
4. **Preserve the rest exactly.** `params`, `deps`, the `render` callback, any branch that picks
|
|
48
|
+
different SQL, and `sourceEntityId` / `targetEntityIds` attribution all stay as they were.
|
|
49
|
+
Migration moves where the query lives; it does not rewrite the query, wiring, or layout.
|
|
50
|
+
5. **Build the filter-state matrix.** The default state, plus every materially distinct non-default
|
|
51
|
+
or conditional branch found in step 1. A branch that selects different SQL is its own state.
|
|
52
|
+
6. **Prove equivalence per state, on four signals.** For each state, compare before and after:
|
|
53
|
+
|
|
54
|
+
| Signal | Where it comes from |
|
|
55
|
+
|---|---|
|
|
56
|
+
| Effective SQL | the details panel's Current query (the server's execution receipt) |
|
|
57
|
+
| Bound parameter values | the same receipt |
|
|
58
|
+
| Row count | the resolve result |
|
|
59
|
+
| Hash of the complete result | hash all returned rows, not a sample |
|
|
60
|
+
|
|
61
|
+
All four must match. Sample rows are a sanity check, never the proof. If a result is too large to
|
|
62
|
+
hash completely, say so and treat that state as unverified.
|
|
63
|
+
7. **Remove the explicit values only after that state passes.** Delete `sql` and `dataSourceId` only
|
|
64
|
+
once the entity owns the equivalent query and the comparison passed.
|
|
65
|
+
8. **Save a named version,** so the migration is one recoverable step in version history.
|
|
66
|
+
|
|
67
|
+
## Verifying
|
|
68
|
+
|
|
69
|
+
Read the entity back rather than trusting what you wrote:
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
graphit dashboard get-entity <dashboard-id> <entity-id>
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Act on `entity_sql_warnings` before reporting success. A parameterized template keeps its `:name`
|
|
76
|
+
placeholders; save-time validation binds them before checking, so a warning is a real SQL problem,
|
|
77
|
+
not the placeholders.
|
|
78
|
+
|
|
79
|
+
## When to stop
|
|
80
|
+
|
|
81
|
+
Stop, save nothing, and report the branch when:
|
|
82
|
+
|
|
83
|
+
- SQL is composed by logic you cannot fully enumerate, so you cannot list every branch.
|
|
84
|
+
- A code path exists that you cannot reach or trigger, so you cannot compare it.
|
|
85
|
+
- A result is too large to hash completely.
|
|
86
|
+
- Any state's four signals do not all match.
|
|
87
|
+
|
|
88
|
+
Report which query, which branch, and which signal. The user can migrate the rest and leave that one
|
|
89
|
+
query on the old shape, which is a legitimate end state.
|
|
@@ -2,14 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
Load this when the concern is the Graphit CLI or plugin itself, not the analysis: the session-start check, a health check, a permission error (403/404/423), the output contract, or local working artifacts. Skip it on every healthy build or query turn.
|
|
4
4
|
|
|
5
|
-
## Contents
|
|
6
|
-
|
|
7
|
-
- [Session start](#session-start)
|
|
8
|
-
- [Health gate](#health-gate)
|
|
9
|
-
- [Permission errors](#permission-errors)
|
|
10
|
-
- [Output contract](#output-contract)
|
|
11
|
-
- [Working artifacts](#working-artifacts)
|
|
12
|
-
|
|
13
5
|
Depth that lives elsewhere: installing, updating, or repairing Graphit -> references/install-update.md. Reporting a failure or a partial result -> references/reporting.md.
|
|
14
6
|
|
|
15
7
|
Governance itself is enforced server-side by the query gateway: a governed query is rejected by the platform, not the CLI, so never claim to have blocked a query locally. The one local guard is a session tripwire - until this skill attests at session start (below), the CLI declines commands that change org state or that assert a governance decision (`--adhoc-reason`, `--override-rules`, `--skip-conditional`). That guard is about this session, never about the query itself, and dropping those flags does not skip governance - the server still decides.
|
|
@@ -46,10 +38,14 @@ The CLI enforces the same permission model as the platform. Three codes:
|
|
|
46
38
|
|
|
47
39
|
| Code | Meaning | What to tell the user |
|
|
48
40
|
|---|---|---|
|
|
49
|
-
| 403 |
|
|
50
|
-
| 404 | Not found, or no access |
|
|
41
|
+
| 403 | Your org role or data access profile does not allow this | Every signed-in member can use the CLI. This action needs more than the caller has: connector create/delete needs org owner or admin, and data source or knowledge-base writes are limited to the domains an admin granted on their data access profile. |
|
|
42
|
+
| 404 | Not found, or no access | A permission 404 is uniform across a resource that does not exist, one the caller cannot see, and another org's id - deliberately indistinguishable, to prevent id enumeration (some older routes still name the missing entity). Never assume the thing is gone or tell the user it was deleted. |
|
|
51
43
|
| 423 | Shared dashboard needs an active editing session | Catch one from the CLI: `graphit dashboard edit <id>` acquires the session and starts a draft; make the edits, then `graphit dashboard publish <id>` to go live (or `graphit dashboard release <id> --yes` to abandon). 409 = someone else is editing; 423 = locked; 403 = view-only. Private dashboards need no session. |
|
|
52
44
|
|
|
45
|
+
A 403 body is structured: `code` (e.g. `domain.kb_write_required`), `required_capability`, `retryable`, `next_step`. Read those fields, never the prose. `retryable: false` is a decision, not a hiccup - stop, give the user the `next_step`, and never retry, route around it, or report the write as done. A 404 carries none of those by design.
|
|
46
|
+
|
|
47
|
+
`graphit status` lists the caller's writable domains and Templates result - check it before planning writes, never reuse an older answer. Advisory only: the server re-authorizes every operation, so neither a past status nor a command's existence is permission.
|
|
48
|
+
|
|
53
49
|
For the exact remediation flags on the failed command, run it with `--help`.
|
|
54
50
|
|
|
55
51
|
## Output contract
|