@graphit/cli 0.1.51 → 0.1.106
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 +2 -2
- package/.codex-plugin/plugin.json +3 -2
- package/README.md +99 -0
- package/bin/graphit +45 -0
- package/bin/graphit.cmd +8 -0
- package/bin/graphit.ps1 +38 -0
- package/dist/api/client.js +11 -0
- package/dist/api/client.js.map +1 -1
- package/dist/commands/auth.js +14 -6
- package/dist/commands/auth.js.map +1 -1
- package/dist/commands/ds-poll.d.ts +8 -0
- package/dist/commands/ds-poll.js +53 -0
- package/dist/commands/ds-poll.js.map +1 -0
- package/dist/commands/ds.js +113 -57
- package/dist/commands/ds.js.map +1 -1
- package/dist/commands/governance.js +15 -11
- package/dist/commands/governance.js.map +1 -1
- package/dist/commands/kb.js +14 -4
- package/dist/commands/kb.js.map +1 -1
- package/dist/commands/query.js +9 -7
- package/dist/commands/query.js.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/output/format.d.ts +1 -0
- package/dist/output/format.js +6 -0
- package/dist/output/format.js.map +1 -1
- package/dist/output/table.d.ts +1 -0
- package/dist/output/table.js +20 -3
- package/dist/output/table.js.map +1 -1
- package/dist/skill-version.d.ts +12 -0
- package/dist/skill-version.js +21 -0
- package/dist/skill-version.js.map +1 -1
- package/dist/update-check.d.ts +19 -0
- package/dist/update-check.js +105 -12
- package/dist/update-check.js.map +1 -1
- package/hooks/hooks.json +13 -0
- package/package.json +11 -3
- package/scripts/block-legacy-setup.mjs +90 -0
- package/scripts/generate-commands-doc.mjs +182 -0
- package/scripts/plugin-status.mjs +179 -29
- package/scripts/sync-plugin-version.mjs +26 -4
- package/skills/graphit/SKILL.md +172 -433
- package/skills/graphit/VERSION.json +1 -1
- package/skills/graphit/cursor/README.md +11 -0
- package/skills/graphit/graphit.mdc +3 -1
- package/skills/graphit/references/dashboard-planning.md +1 -7
- package/skills/graphit/references/data-sources.md +30 -1
- package/skills/graphit/references/filters-advanced.md +61 -0
- package/skills/graphit/references/filters.md +27 -93
- package/skills/graphit/references/governance.md +49 -66
- package/skills/graphit/references/graphit-style.md +6 -18
- package/skills/graphit/references/kb-actions.md +44 -52
- package/skills/graphit/references/kb-discovery.md +10 -13
- package/skills/graphit/references/kb-structure.md +10 -8
- package/skills/graphit/references/kb-traversal.md +16 -16
- package/skills/graphit/references/operations.md +115 -0
- package/skills/graphit/references/parameterized-metrics.md +32 -44
- package/skills/graphit/references/runtime.md +172 -0
- package/skills/graphit/references/sql-reference.md +5 -42
- package/skills/graphit/references/domain-lenses.md +0 -116
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
},
|
|
8
8
|
"metadata": {
|
|
9
9
|
"description": "Graphit CLI plugin for AI coding assistants",
|
|
10
|
-
"version": "0.1.
|
|
10
|
+
"version": "0.1.106"
|
|
11
11
|
},
|
|
12
12
|
"plugins": [
|
|
13
13
|
{
|
|
@@ -16,9 +16,9 @@
|
|
|
16
16
|
"source": {
|
|
17
17
|
"source": "npm",
|
|
18
18
|
"package": "@graphit/cli",
|
|
19
|
-
"version": "0.1.
|
|
19
|
+
"version": "0.1.106"
|
|
20
20
|
},
|
|
21
|
-
"version": "0.1.
|
|
21
|
+
"version": "0.1.106",
|
|
22
22
|
"category": "data-visualization",
|
|
23
23
|
"tags": [
|
|
24
24
|
"bi",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "graphit",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.106",
|
|
4
4
|
"description": "Build custom HTML dashboards from real data using the Graphit CLI. KB-aware queries, entity wrapping, cached data sources.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Graphit",
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
"url": "https://graphit-app.com"
|
|
9
9
|
},
|
|
10
10
|
"homepage": "https://graphit-app.com",
|
|
11
|
-
"repository": "https://github.com/graphit
|
|
11
|
+
"repository": "https://github.com/omry-graphit/graphit-plugin",
|
|
12
12
|
"license": "UNLICENSED",
|
|
13
13
|
"keywords": [
|
|
14
14
|
"graphit",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "graphit",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.106",
|
|
4
4
|
"description": "Build custom HTML dashboards from real data using the Graphit CLI. KB-aware queries, entity wrapping, cached data sources.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Graphit",
|
|
@@ -8,7 +8,8 @@
|
|
|
8
8
|
"url": "https://graphit-app.com"
|
|
9
9
|
},
|
|
10
10
|
"homepage": "https://graphit-app.com",
|
|
11
|
-
"repository": "https://github.com/graphit
|
|
11
|
+
"repository": "https://github.com/omry-graphit/graphit-plugin",
|
|
12
|
+
"skills": "./skills/",
|
|
12
13
|
"keywords": [
|
|
13
14
|
"graphit",
|
|
14
15
|
"bi",
|
package/README.md
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
|
|
3
|
+
# Graphit CLI
|
|
4
|
+
|
|
5
|
+
### If you can talk it, you can graph it.
|
|
6
|
+
|
|
7
|
+
AI-native business intelligence for your terminal and your AI coding assistant.<br/>
|
|
8
|
+
Turn natural language into governed SQL and bespoke, hand-authored HTML dashboards.
|
|
9
|
+
|
|
10
|
+
[](https://www.npmjs.com/package/@graphit/cli)
|
|
11
|
+
[](https://nodejs.org)
|
|
12
|
+
[](https://graphit-app.com)
|
|
13
|
+
|
|
14
|
+
</div>
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
`@graphit/cli` exposes the [Graphit](https://graphit-app.com) platform as commands your AI coding assistant - **Claude Code** or **Codex** - or you can drive directly: explore the governed semantic layer (the "knowledge base"), run governed queries against cached data sources, and build custom HTML/SVG/CSS dashboards on a bespoke canvas.
|
|
19
|
+
|
|
20
|
+
It installs as a plugin/skill, so your assistant knows how to reach for Graphit on any question about your business data - even when you never say "Graphit."
|
|
21
|
+
|
|
22
|
+
## Install
|
|
23
|
+
|
|
24
|
+
**1. Install the CLI** - the `graphit` binary, needed either way (requires Node.js 18+):
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
npm install -g @graphit/cli
|
|
28
|
+
graphit auth login
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
**2. Connect it to your AI coding assistant.** Either install the plugin from the marketplace, or copy the skill in with `graphit setup`.
|
|
32
|
+
|
|
33
|
+
Plugin marketplace - **Claude Code**:
|
|
34
|
+
|
|
35
|
+
```text
|
|
36
|
+
/plugin marketplace add omry-graphit/graphit-plugin
|
|
37
|
+
/plugin install graphit@graphit-plugin
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Plugin marketplace - **Codex**:
|
|
41
|
+
|
|
42
|
+
```text
|
|
43
|
+
codex plugin marketplace add omry-graphit/graphit-plugin
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Or, on any supported editor (**Claude Code, Codex, Cursor, VS Code**):
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
graphit setup
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Either path installs the Graphit skill so the assistant can drive the CLI on your behalf.
|
|
53
|
+
|
|
54
|
+
## Authenticate
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
graphit auth login # Open the browser login flow
|
|
58
|
+
graphit auth status # Show the current account and org
|
|
59
|
+
graphit auth logout # Clear stored credentials
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
The CLI talks to `https://api.graphit-app.com` by default. Set `GRAPHIT_API_URL` to point at a different backend.
|
|
63
|
+
|
|
64
|
+
## Commands
|
|
65
|
+
|
|
66
|
+
| Group | What it does |
|
|
67
|
+
|-------|--------------|
|
|
68
|
+
| `graphit auth` | Log in, check status, log out |
|
|
69
|
+
| `graphit kb` | Knowledge base: list, get, search, explore, and full CRUD for metrics, dimensions, rules, synonyms, domains, relationships, topics, tables, and templates |
|
|
70
|
+
| `graphit query` | Run a governed SQL query against your data |
|
|
71
|
+
| `graphit ds` | Data sources: list, create, refresh, verify, update cached sources |
|
|
72
|
+
| `graphit dashboard` | Custom dashboards: list, create, get, update HTML or a single entity, export to PNG/PDF, delete |
|
|
73
|
+
| `graphit connector` | Connections: list, add (Snowflake key pair, Snowflake OAuth, GitHub), test, remove |
|
|
74
|
+
| `graphit governance` | Query governance: inspect and set the enforcement mode |
|
|
75
|
+
| `graphit setup` | Install the Graphit skill into your AI coding assistant |
|
|
76
|
+
|
|
77
|
+
Run any command with `--help` for its exact flags and subcommands:
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
graphit kb create metric --help
|
|
81
|
+
graphit dashboard export --help
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Global `--output <json|table|styled>` controls how results print (defaults to `json`, the machine-readable form agents rely on).
|
|
85
|
+
|
|
86
|
+
## Why Graphit
|
|
87
|
+
|
|
88
|
+
- **Governed by default.** Every query passes through a server-side governance gateway. Curated metrics and dimensions resolve through reference syntax (`{{metric:NAME}}`, `{{dim:NAME}}`), and the enforcement mode (observe / warn / strict) is set per org. Ad-hoc measures on a governed source require explicit approval and can be hard-blocked under strict mode.
|
|
89
|
+
- **Cached and fast.** Create a data source once and query it in milliseconds instead of hitting the live warehouse on every request.
|
|
90
|
+
- **A bespoke canvas, not template tiles.** Dashboards are real, hand-authored HTML, SVG, and CSS. The CLI manages the dashboard document; the rendering runtime resolves live data and wires interactivity (filters, parameters, saved views).
|
|
91
|
+
- **Retrieve to predict.** Look up a number, monitor it, diagnose why it moved, or project where it is headed - all through one governed semantic layer.
|
|
92
|
+
|
|
93
|
+
## Documentation
|
|
94
|
+
|
|
95
|
+
Full docs, the complete CLI reference, and the dashboard build workflow live at **[graphit-app.com](https://graphit-app.com)**.
|
|
96
|
+
|
|
97
|
+
## License
|
|
98
|
+
|
|
99
|
+
UNLICENSED. Copyright Graphit.
|
package/bin/graphit
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Graphit CLI plugin wrapper (Project #246): run the current @graphit/cli via npx
|
|
3
|
+
# with no global install and no npm-prefix dependency. plugin-status.mjs resolves
|
|
4
|
+
# the npm "latest" dist-tag to a concrete version once per session and caches it;
|
|
5
|
+
# this wrapper reads that cache, validates it (the file is user-writable, so it is
|
|
6
|
+
# untrusted), and falls back to the stamped floor version when the cache is absent
|
|
7
|
+
# or invalid. The floor keeps first-run and offline working.
|
|
8
|
+
|
|
9
|
+
# graphit:floor (stamped by scripts/sync-plugin-version.mjs from cli/package.json)
|
|
10
|
+
FLOOR_VERSION="0.1.106"
|
|
11
|
+
|
|
12
|
+
PACKAGE_NAME="@graphit/cli"
|
|
13
|
+
# Strict semver: anything else is rejected so a tampered cache cannot inject.
|
|
14
|
+
SEMVER_RE='^[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.-]+)?(\+[0-9A-Za-z.-]+)?$'
|
|
15
|
+
|
|
16
|
+
# Fixed, graphit-owned cache dir shared with the resolver. CLAUDE_PLUGIN_DATA is
|
|
17
|
+
# deliberately NOT used: it is set per-plugin/per-context by Claude Code and is
|
|
18
|
+
# not guaranteed identical between the SessionStart hook and the agent Bash tool,
|
|
19
|
+
# which would break cache sharing. GRAPHIT_PLUGIN_DATA overrides for tests/enterprise.
|
|
20
|
+
cache_dir="${GRAPHIT_PLUGIN_DATA:-${HOME:-}/.graphit}"
|
|
21
|
+
cache_file="${cache_dir}/plugin-status.json"
|
|
22
|
+
version="$FLOOR_VERSION"
|
|
23
|
+
|
|
24
|
+
if [ -r "$cache_file" ]; then
|
|
25
|
+
contents="$(cat "$cache_file" 2>/dev/null)"
|
|
26
|
+
# SEC-6: require the expected schema version + package name, then a strict-semver
|
|
27
|
+
# concrete version. Any mismatch falls back to the floor (fail-closed).
|
|
28
|
+
if printf '%s' "$contents" | grep -Eq '"schemaVersion"[[:space:]]*:[[:space:]]*1[,}[:space:]]' \
|
|
29
|
+
&& printf '%s' "$contents" | grep -Fq "\"packageName\":\"${PACKAGE_NAME}\""; then
|
|
30
|
+
candidate="$(printf '%s' "$contents" | sed -n 's/.*"latestVersion"[[:space:]]*:[[:space:]]*"\([^"][^"]*\)".*/\1/p' | head -n1)"
|
|
31
|
+
if [[ "$candidate" =~ $SEMVER_RE ]]; then
|
|
32
|
+
version="$candidate"
|
|
33
|
+
fi
|
|
34
|
+
fi
|
|
35
|
+
fi
|
|
36
|
+
|
|
37
|
+
if ! command -v npx >/dev/null 2>&1; then
|
|
38
|
+
echo "graphit: npx (Node.js >=18) is required but was not found on PATH." >&2
|
|
39
|
+
exit 127
|
|
40
|
+
fi
|
|
41
|
+
|
|
42
|
+
# Safe argv: the version is strict-semver-validated and passed as one quoted token,
|
|
43
|
+
# and user arguments are forwarded verbatim via "$@", so a malformed or tampered
|
|
44
|
+
# cache value can neither break execution nor widen command construction.
|
|
45
|
+
exec npx -y "${PACKAGE_NAME}@${version}" "$@"
|
package/bin/graphit.cmd
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
@echo off
|
|
2
|
+
REM Graphit CLI plugin wrapper for Windows (Project #246). The directly-runnable
|
|
3
|
+
REM entry point: delegates to graphit.ps1, which reads/validates the resolver
|
|
4
|
+
REM cache and runs the current @graphit/cli via npx (falling back to the stamped
|
|
5
|
+
REM floor version). PowerShell is used because it can parse + validate JSON.
|
|
6
|
+
setlocal
|
|
7
|
+
powershell -NoProfile -ExecutionPolicy Bypass -File "%~dp0graphit.ps1" %*
|
|
8
|
+
exit /b %ERRORLEVEL%
|
package/bin/graphit.ps1
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# Graphit CLI plugin wrapper for Windows (Project #246): run the current
|
|
2
|
+
# @graphit/cli via npx. Reads + validates the resolver cache (user-writable, so
|
|
3
|
+
# untrusted) and falls back to the stamped floor version when absent/invalid.
|
|
4
|
+
|
|
5
|
+
# graphit:floor (stamped by scripts/sync-plugin-version.mjs from cli/package.json)
|
|
6
|
+
$FloorVersion = "0.1.106"
|
|
7
|
+
|
|
8
|
+
$PackageName = "@graphit/cli"
|
|
9
|
+
# Strict semver: anything else is rejected so a tampered cache cannot inject.
|
|
10
|
+
$SemverRe = '^[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.-]+)?(\+[0-9A-Za-z.-]+)?$'
|
|
11
|
+
|
|
12
|
+
# Fixed, graphit-owned cache dir shared with the resolver (see the bash wrapper for
|
|
13
|
+
# why CLAUDE_PLUGIN_DATA is intentionally not used). GRAPHIT_PLUGIN_DATA overrides.
|
|
14
|
+
$cacheDir = if ($env:GRAPHIT_PLUGIN_DATA) { $env:GRAPHIT_PLUGIN_DATA } else { Join-Path $env:USERPROFILE ".graphit" }
|
|
15
|
+
$cacheFile = Join-Path $cacheDir "plugin-status.json"
|
|
16
|
+
$version = $FloorVersion
|
|
17
|
+
|
|
18
|
+
if (Test-Path -LiteralPath $cacheFile) {
|
|
19
|
+
try {
|
|
20
|
+
$cache = Get-Content -Raw -LiteralPath $cacheFile | ConvertFrom-Json
|
|
21
|
+
# SEC-6: validate the untrusted cache before use (fail-closed to floor).
|
|
22
|
+
if ($cache.schemaVersion -eq 1 -and $cache.packageName -eq $PackageName -and `
|
|
23
|
+
$cache.latestVersion -is [string] -and $cache.latestVersion -match $SemverRe) {
|
|
24
|
+
$version = $cache.latestVersion
|
|
25
|
+
}
|
|
26
|
+
} catch {
|
|
27
|
+
# Malformed cache -> floor.
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (-not (Get-Command npx -ErrorAction SilentlyContinue)) {
|
|
32
|
+
Write-Error "graphit: npx (Node.js >=18) is required but was not found on PATH."
|
|
33
|
+
exit 127
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
# Safe argv: $version is strict-semver-validated; user args forwarded verbatim.
|
|
37
|
+
& npx -y "$PackageName@$version" @args
|
|
38
|
+
exit $LASTEXITCODE
|
package/dist/api/client.js
CHANGED
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
import { getValidIdToken } from "../auth/token.js";
|
|
2
2
|
import { getApiBaseUrl } from "../config.js";
|
|
3
|
+
import { getCurrentVersion } from "../update-check.js";
|
|
4
|
+
import { getBundledSkillVersion } from "../skill-version.js";
|
|
3
5
|
const REQUEST_TIMEOUT_MS = 30_000;
|
|
6
|
+
// Project #245: version telemetry headers (computed once; static per process).
|
|
7
|
+
// Backend reads them at the CLI set-point and stamps client_version/skill_version
|
|
8
|
+
// onto every CLI-originated event. RFC 6648: no X- prefix on the new headers.
|
|
9
|
+
const CLIENT_VERSION = getCurrentVersion();
|
|
10
|
+
const SKILL_VERSION = getBundledSkillVersion(CLIENT_VERSION);
|
|
4
11
|
class ApiClient {
|
|
5
12
|
async request(method, path, body, opts) {
|
|
6
13
|
const { id_token } = await getValidIdToken();
|
|
@@ -33,6 +40,8 @@ class ApiClient {
|
|
|
33
40
|
const headers = {
|
|
34
41
|
"Content-Type": "application/json",
|
|
35
42
|
"X-Graphit-Source": "cli",
|
|
43
|
+
"Graphit-Client-Version": CLIENT_VERSION,
|
|
44
|
+
"Graphit-Skill-Version": SKILL_VERSION,
|
|
36
45
|
Authorization: `Bearer ${id_token}`,
|
|
37
46
|
};
|
|
38
47
|
let resp;
|
|
@@ -73,6 +82,8 @@ class ApiClient {
|
|
|
73
82
|
const headers = {
|
|
74
83
|
"Content-Type": "application/json",
|
|
75
84
|
"X-Graphit-Source": "cli",
|
|
85
|
+
"Graphit-Client-Version": CLIENT_VERSION,
|
|
86
|
+
"Graphit-Skill-Version": SKILL_VERSION,
|
|
76
87
|
...extraHeaders,
|
|
77
88
|
};
|
|
78
89
|
let resp;
|
package/dist/api/client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/api/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/api/client.ts"],"names":[],"mappings":"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"}
|
package/dist/commands/auth.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { readCredentials, deleteCredentials, getCredentialsPath } from "../auth/credentials.js";
|
|
2
2
|
import { performLogin } from "../auth/login.js";
|
|
3
3
|
import { apiClient } from "../api/client.js";
|
|
4
|
-
import { output, errorOutput } from "../output/format.js";
|
|
4
|
+
import { output, errorOutput, note } from "../output/format.js";
|
|
5
5
|
export function registerAuthCommands(program) {
|
|
6
6
|
const auth = program.command("auth").description("Authentication commands");
|
|
7
7
|
auth
|
|
@@ -10,10 +10,17 @@ export function registerAuthCommands(program) {
|
|
|
10
10
|
.action(async function () {
|
|
11
11
|
try {
|
|
12
12
|
const creds = await performLogin();
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
13
|
+
// Human confirmation -> stderr; the result payload -> stdout (valid JSON in json mode).
|
|
14
|
+
note(`Logged in as ${creds.email}`);
|
|
15
|
+
note(`Organization: ${creds.org_name}`);
|
|
16
|
+
note(`Seat type: ${creds.seat_type}`);
|
|
17
|
+
note(`\nCredentials saved to ${getCredentialsPath()}`);
|
|
18
|
+
output(this, {
|
|
19
|
+
email: creds.email,
|
|
20
|
+
org_name: creds.org_name,
|
|
21
|
+
seat_type: creds.seat_type,
|
|
22
|
+
credentials: getCredentialsPath(),
|
|
23
|
+
}, { keyValue: true });
|
|
17
24
|
}
|
|
18
25
|
catch (err) {
|
|
19
26
|
errorOutput(err);
|
|
@@ -58,7 +65,8 @@ export function registerAuthCommands(program) {
|
|
|
58
65
|
// Best-effort server-side revocation
|
|
59
66
|
}
|
|
60
67
|
await deleteCredentials();
|
|
61
|
-
|
|
68
|
+
note("Logged out. Credentials removed.");
|
|
69
|
+
output(this, { status: "logged_out" }, { keyValue: true });
|
|
62
70
|
}
|
|
63
71
|
catch (err) {
|
|
64
72
|
errorOutput(err);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/commands/auth.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAChG,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAChD,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/commands/auth.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export declare const NOT_FOUND_STATUS = "not_found";
|
|
2
|
+
export declare const NOT_FOUND_POLL_THRESHOLD = 2;
|
|
3
|
+
interface PollDS {
|
|
4
|
+
id: string;
|
|
5
|
+
status: string;
|
|
6
|
+
}
|
|
7
|
+
export declare function reconcilePoll<T extends PollDS>(targetIds: Iterable<string>, freshMap: Map<string, T>, statuses: Map<string, string>, targets: Map<string, T>, missCounts: Map<string, number>, notFoundThreshold?: number): boolean;
|
|
8
|
+
export {};
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
// Pure poll-reconciliation logic for `graphit ds refresh --wait`, split out of
|
|
2
|
+
// ds.ts so it can be unit-tested without a live backend or timers.
|
|
3
|
+
// Terminal status for a target that vanished from the DS list mid-refresh -
|
|
4
|
+
// deleted during the wait, or transiently omitted from fetchDSList(). Distinct
|
|
5
|
+
// from "ready" / "error" so the JSON summary and the progress table can report
|
|
6
|
+
// it accurately. A not_found target is terminal: it lets the wait loop finish
|
|
7
|
+
// promptly instead of spinning to the timeout, and the caller does NOT count it
|
|
8
|
+
// as a timeout.
|
|
9
|
+
export const NOT_FOUND_STATUS = "not_found";
|
|
10
|
+
// Consecutive polls a target may be absent before it is declared not_found. A
|
|
11
|
+
// small threshold rides out a single transient omission from fetchDSList()
|
|
12
|
+
// while still resolving in a few seconds rather than the full poll timeout.
|
|
13
|
+
export const NOT_FOUND_POLL_THRESHOLD = 2;
|
|
14
|
+
// Reconcile one poll's fresh DS list against the targets being waited on.
|
|
15
|
+
// Mutates `statuses`, `targets`, and `missCounts` in place; returns true when
|
|
16
|
+
// every target has reached a terminal state (ready / error / not_found).
|
|
17
|
+
//
|
|
18
|
+
// When a target is missing from the fresh list, its consecutive-miss count is
|
|
19
|
+
// bumped; once it crosses `notFoundThreshold` the target is marked not_found
|
|
20
|
+
// (status recorded on both `statuses` and the `targets` entry the JSON summary
|
|
21
|
+
// reads) and no longer blocks completion. A target that reappears before the
|
|
22
|
+
// threshold resets its miss count.
|
|
23
|
+
export function reconcilePoll(targetIds, freshMap, statuses, targets, missCounts, notFoundThreshold = NOT_FOUND_POLL_THRESHOLD) {
|
|
24
|
+
let allDone = true;
|
|
25
|
+
for (const id of targetIds) {
|
|
26
|
+
const ds = freshMap.get(id);
|
|
27
|
+
if (ds) {
|
|
28
|
+
missCounts.delete(id);
|
|
29
|
+
statuses.set(id, ds.status);
|
|
30
|
+
targets.set(id, ds);
|
|
31
|
+
if (ds.status !== "ready" && ds.status !== "error")
|
|
32
|
+
allDone = false;
|
|
33
|
+
}
|
|
34
|
+
else if (statuses.get(id) === NOT_FOUND_STATUS) {
|
|
35
|
+
// Already terminal - does not block completion, nothing to update.
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
const misses = (missCounts.get(id) ?? 0) + 1;
|
|
39
|
+
missCounts.set(id, misses);
|
|
40
|
+
if (misses >= notFoundThreshold) {
|
|
41
|
+
statuses.set(id, NOT_FOUND_STATUS);
|
|
42
|
+
const prev = targets.get(id);
|
|
43
|
+
if (prev)
|
|
44
|
+
targets.set(id, { ...prev, status: NOT_FOUND_STATUS });
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
allDone = false;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return allDone;
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=ds-poll.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ds-poll.js","sourceRoot":"","sources":["../../src/commands/ds-poll.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,mEAAmE;AAEnE,4EAA4E;AAC5E,+EAA+E;AAC/E,+EAA+E;AAC/E,8EAA8E;AAC9E,gFAAgF;AAChF,gBAAgB;AAChB,MAAM,CAAC,MAAM,gBAAgB,GAAG,WAAW,CAAC;AAE5C,8EAA8E;AAC9E,2EAA2E;AAC3E,4EAA4E;AAC5E,MAAM,CAAC,MAAM,wBAAwB,GAAG,CAAC,CAAC;AAO1C,0EAA0E;AAC1E,8EAA8E;AAC9E,yEAAyE;AACzE,EAAE;AACF,8EAA8E;AAC9E,6EAA6E;AAC7E,+EAA+E;AAC/E,6EAA6E;AAC7E,mCAAmC;AACnC,MAAM,UAAU,aAAa,CAC3B,SAA2B,EAC3B,QAAwB,EACxB,QAA6B,EAC7B,OAAuB,EACvB,UAA+B,EAC/B,oBAA4B,wBAAwB;IAEpD,IAAI,OAAO,GAAG,IAAI,CAAC;IACnB,KAAK,MAAM,EAAE,IAAI,SAAS,EAAE,CAAC;QAC3B,MAAM,EAAE,GAAG,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAC5B,IAAI,EAAE,EAAE,CAAC;YACP,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;YACtB,QAAQ,CAAC,GAAG,CAAC,EAAE,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC;YAC5B,OAAO,CAAC,GAAG,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;YACpB,IAAI,EAAE,CAAC,MAAM,KAAK,OAAO,IAAI,EAAE,CAAC,MAAM,KAAK,OAAO;gBAAE,OAAO,GAAG,KAAK,CAAC;QACtE,CAAC;aAAM,IAAI,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK,gBAAgB,EAAE,CAAC;YACjD,mEAAmE;QACrE,CAAC;aAAM,CAAC;YACN,MAAM,MAAM,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;YAC7C,UAAU,CAAC,GAAG,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC;YAC3B,IAAI,MAAM,IAAI,iBAAiB,EAAE,CAAC;gBAChC,QAAQ,CAAC,GAAG,CAAC,EAAE,EAAE,gBAAgB,CAAC,CAAC;gBACnC,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;gBAC7B,IAAI,IAAI;oBAAE,OAAO,CAAC,GAAG,CAAC,EAAE,EAAE,EAAE,GAAG,IAAI,EAAE,MAAM,EAAE,gBAAgB,EAAE,CAAC,CAAC;YACnE,CAAC;iBAAM,CAAC;gBACN,OAAO,GAAG,KAAK,CAAC;YAClB,CAAC;QACH,CAAC;IACH,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC"}
|