@aligndottech/cli 0.50.0 → 0.52.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/README.md +1 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +6 -0
- package/dist/cli.js.map +1 -1
- package/dist/commands/config.d.ts +8 -0
- package/dist/commands/config.d.ts.map +1 -0
- package/dist/commands/config.js +33 -0
- package/dist/commands/config.js.map +1 -0
- package/dist/commands/connect-agents.d.ts.map +1 -1
- package/dist/commands/connect-agents.js +3 -1
- package/dist/commands/connect-agents.js.map +1 -1
- package/dist/commands/env.d.ts.map +1 -1
- package/dist/commands/env.js +11 -0
- package/dist/commands/env.js.map +1 -1
- package/dist/commands/invite.d.ts +8 -18
- package/dist/commands/invite.d.ts.map +1 -1
- package/dist/commands/invite.js +23 -46
- package/dist/commands/invite.js.map +1 -1
- package/dist/commands/join.d.ts +5 -0
- package/dist/commands/join.d.ts.map +1 -0
- package/dist/commands/join.js +49 -0
- package/dist/commands/join.js.map +1 -0
- package/dist/commands/local-relink.d.ts +35 -0
- package/dist/commands/local-relink.d.ts.map +1 -0
- package/dist/commands/local-relink.js +72 -0
- package/dist/commands/local-relink.js.map +1 -0
- package/dist/commands/local.d.ts.map +1 -1
- package/dist/commands/local.js +37 -0
- package/dist/commands/local.js.map +1 -1
- package/dist/commands/login.d.ts.map +1 -1
- package/dist/commands/login.js +21 -2
- package/dist/commands/login.js.map +1 -1
- package/dist/commands/mcp.d.ts +8 -0
- package/dist/commands/mcp.d.ts.map +1 -1
- package/dist/commands/mcp.js +12 -5
- package/dist/commands/mcp.js.map +1 -1
- package/dist/commands/registry.d.ts.map +1 -1
- package/dist/commands/registry.js +4 -0
- package/dist/commands/registry.js.map +1 -1
- package/dist/commands/share.d.ts.map +1 -1
- package/dist/commands/share.js +81 -12
- package/dist/commands/share.js.map +1 -1
- package/dist/commands/status.d.ts.map +1 -1
- package/dist/commands/status.js +10 -0
- package/dist/commands/status.js.map +1 -1
- package/dist/detector/detector-version.d.ts +16 -0
- package/dist/detector/detector-version.d.ts.map +1 -0
- package/dist/detector/detector-version.js +36 -0
- package/dist/detector/detector-version.js.map +1 -0
- package/dist/detector/relationship-contract.d.ts +30 -0
- package/dist/detector/relationship-contract.d.ts.map +1 -0
- package/dist/detector/relationship-contract.js +120 -0
- package/dist/detector/relationship-contract.js.map +1 -0
- package/dist/detector/relationship-contract.v1.json +53 -0
- package/dist/detector/relationship-prompt.d.ts +20 -0
- package/dist/detector/relationship-prompt.d.ts.map +1 -0
- package/dist/detector/relationship-prompt.js +55 -0
- package/dist/detector/relationship-prompt.js.map +1 -0
- package/dist/detector/relationship-prompt.v1.json +13 -0
- package/dist/detector/resolve-pair.d.ts +39 -0
- package/dist/detector/resolve-pair.d.ts.map +1 -0
- package/dist/detector/resolve-pair.js +345 -0
- package/dist/detector/resolve-pair.js.map +1 -0
- package/dist/detector/similar-item.d.ts +20 -0
- package/dist/detector/similar-item.d.ts.map +1 -0
- package/dist/detector/similar-item.js +16 -0
- package/dist/detector/similar-item.js.map +1 -0
- package/dist/index.js +37 -13
- package/dist/index.js.map +1 -1
- package/dist/lib/advisory-dedup.d.ts.map +1 -1
- package/dist/lib/advisory-dedup.js +16 -8
- package/dist/lib/advisory-dedup.js.map +1 -1
- package/dist/lib/advisory-verdict.d.ts +19 -0
- package/dist/lib/advisory-verdict.d.ts.map +1 -1
- package/dist/lib/advisory-verdict.js +6 -3
- package/dist/lib/advisory-verdict.js.map +1 -1
- package/dist/lib/backup-exclusion.d.ts +10 -0
- package/dist/lib/backup-exclusion.d.ts.map +1 -0
- package/dist/lib/backup-exclusion.js +58 -0
- package/dist/lib/backup-exclusion.js.map +1 -0
- package/dist/lib/cli-oauth.d.ts +2 -0
- package/dist/lib/cli-oauth.d.ts.map +1 -1
- package/dist/lib/cli-oauth.js +61 -10
- package/dist/lib/cli-oauth.js.map +1 -1
- package/dist/lib/config.d.ts +41 -1
- package/dist/lib/config.d.ts.map +1 -1
- package/dist/lib/config.js +109 -1
- package/dist/lib/config.js.map +1 -1
- package/dist/lib/curation/guardrail.d.ts.map +1 -1
- package/dist/lib/curation/guardrail.js +2 -0
- package/dist/lib/curation/guardrail.js.map +1 -1
- package/dist/lib/curation/judgements-db.d.ts +1 -0
- package/dist/lib/curation/judgements-db.d.ts.map +1 -1
- package/dist/lib/curation/judgements-db.js +9 -3
- package/dist/lib/curation/judgements-db.js.map +1 -1
- package/dist/lib/curation/mark.js +4 -2
- package/dist/lib/curation/mark.js.map +1 -1
- package/dist/lib/destination-name.d.ts +24 -0
- package/dist/lib/destination-name.d.ts.map +1 -0
- package/dist/lib/destination-name.js +39 -0
- package/dist/lib/destination-name.js.map +1 -0
- package/dist/lib/destination-summary.d.ts +6 -0
- package/dist/lib/destination-summary.d.ts.map +1 -0
- package/dist/lib/destination-summary.js +27 -0
- package/dist/lib/destination-summary.js.map +1 -0
- package/dist/lib/destination-trust.d.ts +54 -0
- package/dist/lib/destination-trust.d.ts.map +1 -0
- package/dist/lib/destination-trust.js +107 -0
- package/dist/lib/destination-trust.js.map +1 -0
- package/dist/lib/env-resolver.d.ts.map +1 -1
- package/dist/lib/env-resolver.js +3 -0
- package/dist/lib/env-resolver.js.map +1 -1
- package/dist/lib/fatal.d.ts +11 -0
- package/dist/lib/fatal.d.ts.map +1 -0
- package/dist/lib/fatal.js +22 -0
- package/dist/lib/fatal.js.map +1 -0
- package/dist/lib/gateway-client.d.ts +8 -16
- package/dist/lib/gateway-client.d.ts.map +1 -1
- package/dist/lib/gateway-client.js +30 -20
- package/dist/lib/gateway-client.js.map +1 -1
- package/dist/lib/invite-prompt.d.ts +4 -4
- package/dist/lib/invite-prompt.d.ts.map +1 -1
- package/dist/lib/invite-prompt.js +4 -4
- package/dist/lib/invite-prompt.js.map +1 -1
- package/dist/lib/invite-settings.d.ts +18 -0
- package/dist/lib/invite-settings.d.ts.map +1 -0
- package/dist/lib/invite-settings.js +29 -0
- package/dist/lib/invite-settings.js.map +1 -0
- package/dist/lib/join-flow.d.ts +60 -0
- package/dist/lib/join-flow.d.ts.map +1 -0
- package/dist/lib/join-flow.js +282 -0
- package/dist/lib/join-flow.js.map +1 -0
- package/dist/lib/launch/mcp-child-env.d.ts.map +1 -1
- package/dist/lib/launch/mcp-child-env.js +5 -2
- package/dist/lib/launch/mcp-child-env.js.map +1 -1
- package/dist/lib/lead-prompt.d.ts +106 -0
- package/dist/lib/lead-prompt.d.ts.map +1 -0
- package/dist/lib/lead-prompt.js +175 -0
- package/dist/lib/lead-prompt.js.map +1 -0
- package/dist/lib/local-candidate-classify.d.ts +26 -0
- package/dist/lib/local-candidate-classify.d.ts.map +1 -0
- package/dist/lib/local-candidate-classify.js +53 -0
- package/dist/lib/local-candidate-classify.js.map +1 -0
- package/dist/lib/local-db-migrate.d.ts +1 -1
- package/dist/lib/local-db-migrate.d.ts.map +1 -1
- package/dist/lib/local-db-migrate.js +45 -1
- package/dist/lib/local-db-migrate.js.map +1 -1
- package/dist/lib/local-db-v12.d.ts +17 -0
- package/dist/lib/local-db-v12.d.ts.map +1 -0
- package/dist/lib/local-db-v12.js +8 -0
- package/dist/lib/local-db-v12.js.map +1 -0
- package/dist/lib/local-db.d.ts +13 -13
- package/dist/lib/local-db.d.ts.map +1 -1
- package/dist/lib/local-db.js +41 -6
- package/dist/lib/local-db.js.map +1 -1
- package/dist/lib/local-gateway-client.d.ts +1 -0
- package/dist/lib/local-gateway-client.d.ts.map +1 -1
- package/dist/lib/local-gateway-client.js +31 -20
- package/dist/lib/local-gateway-client.js.map +1 -1
- package/dist/lib/local-ingest.d.ts +2 -0
- package/dist/lib/local-ingest.d.ts.map +1 -1
- package/dist/lib/local-ingest.js.map +1 -1
- package/dist/lib/local-link-pass.d.ts.map +1 -1
- package/dist/lib/local-link-pass.js +25 -29
- package/dist/lib/local-link-pass.js.map +1 -1
- package/dist/lib/local-llm.d.ts +1 -1
- package/dist/lib/local-llm.d.ts.map +1 -1
- package/dist/lib/local-llm.js +3 -2
- package/dist/lib/local-llm.js.map +1 -1
- package/dist/lib/local-mode.d.ts +5 -1
- package/dist/lib/local-mode.d.ts.map +1 -1
- package/dist/lib/local-mode.js +11 -6
- package/dist/lib/local-mode.js.map +1 -1
- package/dist/lib/local-relationship-classifier.d.ts +4 -0
- package/dist/lib/local-relationship-classifier.d.ts.map +1 -1
- package/dist/lib/local-relationship-classifier.js +9 -4
- package/dist/lib/local-relationship-classifier.js.map +1 -1
- package/dist/lib/local-relink.d.ts +59 -0
- package/dist/lib/local-relink.d.ts.map +1 -0
- package/dist/lib/local-relink.js +171 -0
- package/dist/lib/local-relink.js.map +1 -0
- package/dist/lib/local-set-classifier.d.ts +36 -0
- package/dist/lib/local-set-classifier.d.ts.map +1 -0
- package/dist/lib/local-set-classifier.js +81 -0
- package/dist/lib/local-set-classifier.js.map +1 -0
- package/dist/lib/local-snapshot-loader.d.ts +29 -0
- package/dist/lib/local-snapshot-loader.d.ts.map +1 -0
- package/dist/lib/local-snapshot-loader.js +108 -0
- package/dist/lib/local-snapshot-loader.js.map +1 -0
- package/dist/lib/login-flow.d.ts +15 -0
- package/dist/lib/login-flow.d.ts.map +1 -1
- package/dist/lib/login-flow.js +80 -4
- package/dist/lib/login-flow.js.map +1 -1
- package/dist/lib/mcp/share-status-tool.d.ts +13 -0
- package/dist/lib/mcp/share-status-tool.d.ts.map +1 -0
- package/dist/lib/mcp/share-status-tool.js +116 -0
- package/dist/lib/mcp/share-status-tool.js.map +1 -0
- package/dist/lib/mcp/share-tool.d.ts +18 -14
- package/dist/lib/mcp/share-tool.d.ts.map +1 -1
- package/dist/lib/mcp/share-tool.js +127 -21
- package/dist/lib/mcp/share-tool.js.map +1 -1
- package/dist/lib/model-cache.d.ts +10 -0
- package/dist/lib/model-cache.d.ts.map +1 -0
- package/dist/lib/model-cache.js +35 -0
- package/dist/lib/model-cache.js.map +1 -0
- package/dist/lib/next-step.d.ts.map +1 -1
- package/dist/lib/next-step.js +2 -1
- package/dist/lib/next-step.js.map +1 -1
- package/dist/lib/private-files.d.ts +38 -0
- package/dist/lib/private-files.d.ts.map +1 -0
- package/dist/lib/private-files.js +102 -0
- package/dist/lib/private-files.js.map +1 -0
- package/dist/lib/redaction-notice.d.ts +7 -0
- package/dist/lib/redaction-notice.d.ts.map +1 -0
- package/dist/lib/redaction-notice.js +32 -0
- package/dist/lib/redaction-notice.js.map +1 -0
- package/dist/lib/relink-estimate.d.ts +16 -0
- package/dist/lib/relink-estimate.d.ts.map +1 -0
- package/dist/lib/relink-estimate.js +30 -0
- package/dist/lib/relink-estimate.js.map +1 -0
- package/dist/lib/resolve-env.d.ts +15 -1
- package/dist/lib/resolve-env.d.ts.map +1 -1
- package/dist/lib/resolve-env.js +27 -7
- package/dist/lib/resolve-env.js.map +1 -1
- package/dist/lib/scope-defaults.d.ts.map +1 -1
- package/dist/lib/scope-defaults.js +2 -0
- package/dist/lib/scope-defaults.js.map +1 -1
- package/dist/lib/scope-real.d.ts +57 -0
- package/dist/lib/scope-real.d.ts.map +1 -1
- package/dist/lib/setup-route.d.ts +4 -2
- package/dist/lib/setup-route.d.ts.map +1 -1
- package/dist/lib/setup-route.js +12 -6
- package/dist/lib/setup-route.js.map +1 -1
- package/dist/lib/share/approval.d.ts +71 -0
- package/dist/lib/share/approval.d.ts.map +1 -0
- package/dist/lib/share/approval.js +139 -0
- package/dist/lib/share/approval.js.map +1 -0
- package/dist/lib/share/approve-link.d.ts +31 -0
- package/dist/lib/share/approve-link.d.ts.map +1 -0
- package/dist/lib/share/approve-link.js +46 -0
- package/dist/lib/share/approve-link.js.map +1 -0
- package/dist/lib/share/browser-flow.d.ts +85 -0
- package/dist/lib/share/browser-flow.d.ts.map +1 -0
- package/dist/lib/share/browser-flow.js +168 -0
- package/dist/lib/share/browser-flow.js.map +1 -0
- package/dist/lib/share/command.d.ts +34 -1
- package/dist/lib/share/command.d.ts.map +1 -1
- package/dist/lib/share/command.js +153 -11
- package/dist/lib/share/command.js.map +1 -1
- package/dist/lib/share/delivery-options.d.ts +15 -0
- package/dist/lib/share/delivery-options.d.ts.map +1 -0
- package/dist/lib/share/delivery-options.js +16 -0
- package/dist/lib/share/delivery-options.js.map +1 -0
- package/dist/lib/share/delivery.d.ts +83 -0
- package/dist/lib/share/delivery.d.ts.map +1 -0
- package/dist/lib/share/delivery.js +134 -0
- package/dist/lib/share/delivery.js.map +1 -0
- package/dist/lib/share/envelope.d.ts +61 -0
- package/dist/lib/share/envelope.d.ts.map +1 -0
- package/dist/lib/share/envelope.js +99 -0
- package/dist/lib/share/envelope.js.map +1 -0
- package/dist/lib/share/ledger.d.ts.map +1 -1
- package/dist/lib/share/ledger.js +3 -1
- package/dist/lib/share/ledger.js.map +1 -1
- package/dist/lib/share/payload.d.ts +9 -0
- package/dist/lib/share/payload.d.ts.map +1 -1
- package/dist/lib/share/payload.js +9 -0
- package/dist/lib/share/payload.js.map +1 -1
- package/dist/lib/share/pending.d.ts +47 -1
- package/dist/lib/share/pending.d.ts.map +1 -1
- package/dist/lib/share/pending.js +139 -13
- package/dist/lib/share/pending.js.map +1 -1
- package/dist/lib/share/preview.d.ts +5 -1
- package/dist/lib/share/preview.d.ts.map +1 -1
- package/dist/lib/share/preview.js +3 -1
- package/dist/lib/share/preview.js.map +1 -1
- package/dist/lib/share/qr.d.ts +13 -0
- package/dist/lib/share/qr.d.ts.map +1 -0
- package/dist/lib/share/qr.js +77 -0
- package/dist/lib/share/qr.js.map +1 -0
- package/dist/lib/share/requests-client.d.ts +63 -0
- package/dist/lib/share/requests-client.d.ts.map +1 -0
- package/dist/lib/share/requests-client.js +69 -0
- package/dist/lib/share/requests-client.js.map +1 -0
- package/dist/lib/share/run.d.ts +20 -1
- package/dist/lib/share/run.d.ts.map +1 -1
- package/dist/lib/share/run.js +27 -10
- package/dist/lib/share/run.js.map +1 -1
- package/dist/lib/share/secret-scan.d.ts +5 -0
- package/dist/lib/share/secret-scan.d.ts.map +1 -1
- package/dist/lib/share/secret-scan.js +43 -2
- package/dist/lib/share/secret-scan.js.map +1 -1
- package/dist/lib/share/target.d.ts +38 -0
- package/dist/lib/share/target.d.ts.map +1 -0
- package/dist/lib/share/target.js +80 -0
- package/dist/lib/share/target.js.map +1 -0
- package/dist/lib/share/tty.d.ts +8 -0
- package/dist/lib/share/tty.d.ts.map +1 -1
- package/dist/lib/share/tty.js +45 -0
- package/dist/lib/share/tty.js.map +1 -1
- package/dist/lib/source-sync-state.d.ts.map +1 -1
- package/dist/lib/source-sync-state.js +2 -0
- package/dist/lib/source-sync-state.js.map +1 -1
- package/dist/lib/sync/blocked.d.ts.map +1 -1
- package/dist/lib/sync/blocked.js +2 -1
- package/dist/lib/sync/blocked.js.map +1 -1
- package/dist/lib/sync/classify.d.ts.map +1 -1
- package/dist/lib/sync/classify.js +2 -0
- package/dist/lib/sync/classify.js.map +1 -1
- package/dist/lib/sync/real-env.d.ts +57 -0
- package/dist/lib/sync/real-env.d.ts.map +1 -1
- package/dist/lib/sync/sync-state.d.ts.map +1 -1
- package/dist/lib/sync/sync-state.js +3 -1
- package/dist/lib/sync/sync-state.js.map +1 -1
- package/dist/lib/usage-telemetry.d.ts +2 -2
- package/dist/lib/usage-telemetry.d.ts.map +1 -1
- package/dist/lib/usage-telemetry.js +21 -3
- package/dist/lib/usage-telemetry.js.map +1 -1
- package/package.json +4 -2
- package/dist/lib/personal-email-domains.d.ts +0 -8
- package/dist/lib/personal-email-domains.d.ts.map +0 -1
- package/dist/lib/personal-email-domains.js +0 -39
- package/dist/lib/personal-email-domains.js.map +0 -1
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The v1 local relationship classifier (ALIGN_DETECTOR=v1): ONE model call per check over every
|
|
3
|
+
* candidate, using the shared detector prompt (src/detector), parsed with the shared contract, and
|
|
4
|
+
* with `incompatible` resolved to `supersedes` or `conflicts_with` by the deterministic resolver,
|
|
5
|
+
* never by the model's own label.
|
|
6
|
+
*
|
|
7
|
+
* Authorship: the local graph stores no author per decision, so every side is passed with
|
|
8
|
+
* author null. The resolver reads null as UNKNOWN, and two unknown authors are never the same
|
|
9
|
+
* author, so the same-author supersession rule cannot fire locally; only a replacement claim
|
|
10
|
+
* that agrees with the clock can earn `supersedes`. Standing is also null on both sides, which
|
|
11
|
+
* the resolver treats as equal.
|
|
12
|
+
*
|
|
13
|
+
* A candidate the model omits, or whose entry fails the contract, gets `relation: null`: it was
|
|
14
|
+
* judged and has no typed relationship. A whole-call failure is reported once, for the set.
|
|
15
|
+
*/
|
|
16
|
+
import { DETERMINISTIC_TEMPERATURE } from '@aligndottech/connector-core';
|
|
17
|
+
import { parseRelationshipItem } from '../detector/relationship-contract.js';
|
|
18
|
+
import { buildV1SystemPrompt, buildV1UserPrompt, v1MaxTokens } from '../detector/relationship-prompt.js';
|
|
19
|
+
import { NEW_DECISION_REF, resolveSimilarItem } from '../detector/similar-item.js';
|
|
20
|
+
import { callChatDetailed } from './local-llm.js';
|
|
21
|
+
import { failureReason } from './local-relationship-classifier.js';
|
|
22
|
+
/** The `similar` array from the model's answer, or null when there is none to read. */
|
|
23
|
+
function similarEntries(text) {
|
|
24
|
+
const start = text.indexOf('{');
|
|
25
|
+
const end = text.lastIndexOf('}');
|
|
26
|
+
if (start < 0 || end <= start)
|
|
27
|
+
return null;
|
|
28
|
+
let obj;
|
|
29
|
+
try {
|
|
30
|
+
obj = JSON.parse(text.slice(start, end + 1));
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
if (typeof obj !== 'object' || obj === null)
|
|
36
|
+
return null;
|
|
37
|
+
const record = obj;
|
|
38
|
+
const rel = record['relationships'];
|
|
39
|
+
const similar = typeof rel === 'object' && rel !== null ? rel['similar'] : record['similar'];
|
|
40
|
+
return Array.isArray(similar) ? similar : null;
|
|
41
|
+
}
|
|
42
|
+
/** 1-based ordinal as printed in the prompt, as a number or a digit string; anything else is null. */
|
|
43
|
+
function ordinal(value, count) {
|
|
44
|
+
const n = typeof value === 'number' ? value : typeof value === 'string' && /^\d+$/.test(value.trim()) ? Number(value) : NaN;
|
|
45
|
+
return Number.isInteger(n) && n >= 1 && n <= count ? n : null;
|
|
46
|
+
}
|
|
47
|
+
export async function classifyCandidateSet(subject, candidates, call = callChatDetailed) {
|
|
48
|
+
if (!candidates.length)
|
|
49
|
+
return { ok: true, verdicts: [] };
|
|
50
|
+
const maxTokens = v1MaxTokens(candidates.length);
|
|
51
|
+
const result = await call(buildV1SystemPrompt(), (windowTokens) => buildV1UserPrompt(subject, candidates, windowTokens, maxTokens), { temperature: DETERMINISTIC_TEMPERATURE, maxTokens });
|
|
52
|
+
if (!result.ok)
|
|
53
|
+
return { ok: false, reason: failureReason(result.failure), failure: result.failure };
|
|
54
|
+
const entries = similarEntries(result.text);
|
|
55
|
+
if (entries === null)
|
|
56
|
+
return { ok: false, reason: 'classifier_unparseable' };
|
|
57
|
+
const verdicts = candidates.map((c) => ({ relation: null, confidence: c.similarity }));
|
|
58
|
+
const seen = new Set();
|
|
59
|
+
const newSide = { id: NEW_DECISION_REF, decidedAt: subject.decidedAt, author: null };
|
|
60
|
+
for (const entry of entries) {
|
|
61
|
+
if (typeof entry !== 'object' || entry === null)
|
|
62
|
+
continue;
|
|
63
|
+
const ref = ordinal(entry['decision_ref'], candidates.length);
|
|
64
|
+
if (ref === null || seen.has(ref))
|
|
65
|
+
continue;
|
|
66
|
+
seen.add(ref);
|
|
67
|
+
// The shared schema asks for "reasons": [...]; the contract parser reads one "reason" string.
|
|
68
|
+
const raw = entry;
|
|
69
|
+
const reasons = Array.isArray(raw['reasons']) ? raw['reasons'].filter((r) => typeof r === 'string') : [];
|
|
70
|
+
const item = parseRelationshipItem(JSON.stringify(raw['reason'] === undefined && reasons.length ? { ...raw, reason: reasons.join('; ') } : raw), 'v1Candidate');
|
|
71
|
+
if (item === null)
|
|
72
|
+
continue;
|
|
73
|
+
const c = candidates[ref - 1];
|
|
74
|
+
const resolved = resolveSimilarItem(item, newSide, { id: c.id, decidedAt: c.decidedAt, author: null, status: c.status ?? null });
|
|
75
|
+
if (resolved === null)
|
|
76
|
+
continue;
|
|
77
|
+
verdicts[ref - 1] = { relation: resolved.type, confidence: resolved.confidence, ...(resolved.reason ? { reason: resolved.reason } : {}) };
|
|
78
|
+
}
|
|
79
|
+
return { ok: true, verdicts };
|
|
80
|
+
}
|
|
81
|
+
//# sourceMappingURL=local-set-classifier.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"local-set-classifier.js","sourceRoot":"","sources":["../../src/lib/local-set-classifier.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,EAAE,yBAAyB,EAAE,MAAM,8BAA8B,CAAC;AACzE,OAAO,EAAE,qBAAqB,EAAE,MAAM,sCAAsC,CAAC;AAC7E,OAAO,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,WAAW,EAAE,MAAM,oCAAoC,CAAC;AACzG,OAAO,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,MAAM,6BAA6B,CAAC;AACnF,OAAO,EAAE,gBAAgB,EAAmB,MAAM,gBAAgB,CAAC;AACnE,OAAO,EAAgC,aAAa,EAAE,MAAM,oCAAoC,CAAC;AAiCjG,uFAAuF;AACvF,SAAS,cAAc,CAAC,IAAY;IAClC,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IAChC,MAAM,GAAG,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;IAClC,IAAI,KAAK,GAAG,CAAC,IAAI,GAAG,IAAI,KAAK;QAAE,OAAO,IAAI,CAAC;IAC3C,IAAI,GAAY,CAAC;IACjB,IAAI,CAAC;QACH,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC;IAC/C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;IACD,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IACzD,MAAM,MAAM,GAAG,GAA8B,CAAC;IAC9C,MAAM,GAAG,GAAG,MAAM,CAAC,eAAe,CAAC,CAAC;IACpC,MAAM,OAAO,GAAG,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,IAAI,CAAC,CAAC,CAAE,GAA+B,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;IAC1H,OAAO,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC;AACjD,CAAC;AAED,sGAAsG;AACtG,SAAS,OAAO,CAAC,KAAc,EAAE,KAAa;IAC5C,MAAM,CAAC,GAAG,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,KAAK,KAAK,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;IAC5H,OAAO,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AAChE,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,oBAAoB,CAAC,OAAmB,EAAE,UAAmC,EAAE,OAAa,gBAAgB;IAChI,IAAI,CAAC,UAAU,CAAC,MAAM;QAAE,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC;IAC1D,MAAM,SAAS,GAAG,WAAW,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;IACjD,MAAM,MAAM,GAAG,MAAM,IAAI,CACvB,mBAAmB,EAAE,EACrB,CAAC,YAAoB,EAAE,EAAE,CAAC,iBAAiB,CAAC,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,SAAS,CAAC,EACzF,EAAE,WAAW,EAAE,yBAAyB,EAAE,SAAS,EAAE,CACtD,CAAC;IACF,IAAI,CAAC,MAAM,CAAC,EAAE;QAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,aAAa,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,CAAC;IACrG,MAAM,OAAO,GAAG,cAAc,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IAC5C,IAAI,OAAO,KAAK,IAAI;QAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,wBAAwB,EAAE,CAAC;IAE7E,MAAM,QAAQ,GAAiB,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC;IACrG,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAC/B,MAAM,OAAO,GAAG,EAAE,EAAE,EAAE,gBAAgB,EAAE,SAAS,EAAE,OAAO,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;IACrF,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI;YAAE,SAAS;QAC1D,MAAM,GAAG,GAAG,OAAO,CAAE,KAAiC,CAAC,cAAc,CAAC,EAAE,UAAU,CAAC,MAAM,CAAC,CAAC;QAC3F,IAAI,GAAG,KAAK,IAAI,IAAI,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC;YAAE,SAAS;QAC5C,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACd,8FAA8F;QAC9F,MAAM,GAAG,GAAG,KAAgC,CAAC;QAC7C,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAe,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QACtH,MAAM,IAAI,GAAG,qBAAqB,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,KAAK,SAAS,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,GAAG,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,aAAa,CAAC,CAAC;QAChK,IAAI,IAAI,KAAK,IAAI;YAAE,SAAS;QAC5B,MAAM,CAAC,GAAG,UAAU,CAAC,GAAG,GAAG,CAAC,CAAE,CAAC;QAC/B,MAAM,QAAQ,GAAG,kBAAkB,CAAC,IAAI,EAAE,OAAO,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,SAAS,EAAE,CAAC,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,IAAI,IAAI,EAAE,CAAC,CAAC;QACjI,IAAI,QAAQ,KAAK,IAAI;YAAE,SAAS;QAChC,QAAQ,CAAC,GAAG,GAAG,CAAC,CAAC,GAAG,EAAE,QAAQ,EAAE,QAAQ,CAAC,IAAI,EAAE,UAAU,EAAE,QAAQ,CAAC,UAAU,EAAE,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;IAC5I,CAAC;IACD,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;AAChC,CAAC"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export interface SnapshotDecision {
|
|
2
|
+
id: string;
|
|
3
|
+
title: string;
|
|
4
|
+
summary: string;
|
|
5
|
+
source_url: string | null;
|
|
6
|
+
platform: string;
|
|
7
|
+
decided_at: string | null;
|
|
8
|
+
repo?: string | null;
|
|
9
|
+
}
|
|
10
|
+
export interface SnapshotLink {
|
|
11
|
+
source_id: string;
|
|
12
|
+
target_id: string;
|
|
13
|
+
relation: string;
|
|
14
|
+
confidence: number;
|
|
15
|
+
}
|
|
16
|
+
export interface Snapshot {
|
|
17
|
+
snapshot: string;
|
|
18
|
+
decisions: SnapshotDecision[];
|
|
19
|
+
links?: SnapshotLink[];
|
|
20
|
+
}
|
|
21
|
+
export declare function loadSnapshot(s: Snapshot, dbPath: string, opts: {
|
|
22
|
+
links: boolean;
|
|
23
|
+
realDbPath?: string;
|
|
24
|
+
alsoRefuse?: readonly string[];
|
|
25
|
+
}): {
|
|
26
|
+
decisions: number;
|
|
27
|
+
links: number;
|
|
28
|
+
};
|
|
29
|
+
//# sourceMappingURL=local-snapshot-loader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"local-snapshot-loader.d.ts","sourceRoot":"","sources":["../../src/lib/local-snapshot-loader.ts"],"names":[],"mappings":"AAoBA,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB;AAED,MAAM,WAAW,YAAY;IAAG,SAAS,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE;AAE5G,MAAM,WAAW,QAAQ;IAAG,QAAQ,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,gBAAgB,EAAE,CAAC;IAAC,KAAK,CAAC,EAAE,YAAY,EAAE,CAAA;CAAE;AAuCrG,wBAAgB,YAAY,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE;IAAE,KAAK,EAAE,OAAO,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;CAAE,GAAG;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CA4B7K"}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Load a frozen JSON snapshot into a THROWAWAY local graph (shared detector plan, Phase B).
|
|
3
|
+
*
|
|
4
|
+
* No user command reaches this: it is driven by scripts/load-local-snapshot.ts, so a benchmark
|
|
5
|
+
* can build a local graph from the same decisions the hosted arm reads. It keeps each decision's
|
|
6
|
+
* id, decided_at and platform exactly (ingestBatch re-extracts and cannot), and imports the
|
|
7
|
+
* snapshot's links only when asked, stamped detector_version 'snapshot' so `align local relink`
|
|
8
|
+
* (which reads v0 rows only) never re-types them and a count by version separates them.
|
|
9
|
+
*
|
|
10
|
+
* It never writes the user's real graph: it refuses a path that already exists (a dangling
|
|
11
|
+
* symlink included), and any path that lands on the default or the configured local.db, through
|
|
12
|
+
* symlinks; it validates the whole snapshot before creating any file.
|
|
13
|
+
*/
|
|
14
|
+
import { lstatSync, readlinkSync, realpathSync } from 'node:fs';
|
|
15
|
+
import { basename, dirname, resolve } from 'node:path';
|
|
16
|
+
import { DatabaseSync } from 'node:sqlite';
|
|
17
|
+
import { RELATIONSHIP_CONTRACT } from '../detector/relationship-contract.js';
|
|
18
|
+
import { createLocalDb } from './local-db.js';
|
|
19
|
+
import { getLocalDbPath } from './local-mode.js';
|
|
20
|
+
function validate(s, withLinks) {
|
|
21
|
+
if (!s.decisions.length)
|
|
22
|
+
throw new Error('The snapshot holds no decisions; refusing to write an empty graph.');
|
|
23
|
+
const ids = new Set();
|
|
24
|
+
for (const d of s.decisions) {
|
|
25
|
+
if (ids.has(d.id))
|
|
26
|
+
throw new Error(`The snapshot has a duplicate id "${d.id}".`);
|
|
27
|
+
ids.add(d.id);
|
|
28
|
+
}
|
|
29
|
+
if (!withLinks)
|
|
30
|
+
return;
|
|
31
|
+
const types = RELATIONSHIP_CONTRACT.types;
|
|
32
|
+
for (const l of s.links ?? []) {
|
|
33
|
+
for (const id of [l.source_id, l.target_id])
|
|
34
|
+
if (!ids.has(id))
|
|
35
|
+
throw new Error(`A snapshot link names "${id}", which the snapshot does not hold.`);
|
|
36
|
+
if (!types.includes(l.relation))
|
|
37
|
+
throw new Error(`A snapshot link has relation "${l.relation}", which is not in the contract vocabulary.`);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Where a path really lands, without requiring it to exist (review F9): the parent directory's
|
|
42
|
+
* realpath plus the name, following a symlink at the name even when it dangles, so a link to a
|
|
43
|
+
* real graph that has not been created yet still resolves to that graph's location.
|
|
44
|
+
*/
|
|
45
|
+
function landsAt(p, hops = 0) {
|
|
46
|
+
const abs = resolve(p);
|
|
47
|
+
let parent;
|
|
48
|
+
try {
|
|
49
|
+
parent = realpathSync(dirname(abs));
|
|
50
|
+
}
|
|
51
|
+
catch {
|
|
52
|
+
parent = dirname(abs);
|
|
53
|
+
}
|
|
54
|
+
const here = resolve(parent, basename(abs));
|
|
55
|
+
if (hops < 40) {
|
|
56
|
+
try {
|
|
57
|
+
if (lstatSync(here).isSymbolicLink())
|
|
58
|
+
return landsAt(resolve(parent, readlinkSync(here)), hops + 1);
|
|
59
|
+
}
|
|
60
|
+
catch { /* nothing there: here is where it lands */ }
|
|
61
|
+
}
|
|
62
|
+
return here;
|
|
63
|
+
}
|
|
64
|
+
function occupied(p) {
|
|
65
|
+
try {
|
|
66
|
+
lstatSync(p);
|
|
67
|
+
return true;
|
|
68
|
+
}
|
|
69
|
+
catch {
|
|
70
|
+
return false;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
export function loadSnapshot(s, dbPath, opts) {
|
|
74
|
+
const target = landsAt(dbPath);
|
|
75
|
+
for (const real of [opts.realDbPath ?? getLocalDbPath(), ...(opts.alsoRefuse ?? [])]) {
|
|
76
|
+
if (target === landsAt(real))
|
|
77
|
+
throw new Error(`${dbPath} is the real local graph; load a snapshot into a throwaway path instead.`);
|
|
78
|
+
}
|
|
79
|
+
// lstat, not exists: a dangling symlink is occupied too.
|
|
80
|
+
if (occupied(dbPath) || occupied(target))
|
|
81
|
+
throw new Error(`${dbPath} already exists; the loader only writes a new, throwaway graph.`);
|
|
82
|
+
validate(s, opts.links);
|
|
83
|
+
createLocalDb(dbPath).close(); // creates and migrates the schema
|
|
84
|
+
const db = new DatabaseSync(dbPath);
|
|
85
|
+
try {
|
|
86
|
+
db.exec('BEGIN IMMEDIATE');
|
|
87
|
+
const insertDecision = db.prepare('INSERT INTO decisions (id, title, summary, source_url, platform, decided_at, repo) VALUES (?, ?, ?, ?, ?, ?, ?)');
|
|
88
|
+
for (const d of s.decisions)
|
|
89
|
+
insertDecision.run(d.id, d.title, d.summary, d.source_url, d.platform, d.decided_at, d.repo ?? null);
|
|
90
|
+
let links = 0;
|
|
91
|
+
if (opts.links) {
|
|
92
|
+
const insertLink = db.prepare(`INSERT OR IGNORE INTO decision_links (id, source_id, target_id, relation, confidence, detector_version) VALUES (?, ?, ?, ?, ?, 'snapshot')`);
|
|
93
|
+
for (const [i, l] of (s.links ?? []).entries())
|
|
94
|
+
links += Number(insertLink.run(`snapshot:${i}`, l.source_id, l.target_id, l.relation, l.confidence).changes);
|
|
95
|
+
}
|
|
96
|
+
db.exec('COMMIT');
|
|
97
|
+
return { decisions: s.decisions.length, links };
|
|
98
|
+
}
|
|
99
|
+
catch (err) {
|
|
100
|
+
if (db.isTransaction)
|
|
101
|
+
db.exec('ROLLBACK');
|
|
102
|
+
throw err;
|
|
103
|
+
}
|
|
104
|
+
finally {
|
|
105
|
+
db.close();
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
//# sourceMappingURL=local-snapshot-loader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"local-snapshot-loader.js","sourceRoot":"","sources":["../../src/lib/local-snapshot-loader.ts"],"names":[],"mappings":"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"}
|
package/dist/lib/login-flow.d.ts
CHANGED
|
@@ -1,5 +1,20 @@
|
|
|
1
|
+
import { type VerifiedIdentity } from './join-flow.js';
|
|
1
2
|
import type { createConfigStore, EnvironmentConfig, EnvName } from './config.js';
|
|
2
3
|
type ConfigStore = ReturnType<typeof createConfigStore>;
|
|
4
|
+
/**
|
|
5
|
+
* The address /auth/cli-init hands back is opened in a browser, so it is checked first: http(s) only, and for a team destination its
|
|
6
|
+
* origin must be the saved gateway's or web app's (a joined gateway is whatever was joined, so its word is not enough). A string
|
|
7
|
+
* starting with '!' is the reason it was refused.
|
|
8
|
+
*/
|
|
9
|
+
export declare function checkLoginUrl(raw: unknown, env: EnvironmentConfig): string;
|
|
10
|
+
/**
|
|
11
|
+
* `align login --env <team> --token X`: the no-browser renewal. A person at a terminal only, never inside an agent, and the token is
|
|
12
|
+
* kept only once the destination's gateway says whose it is; the tenant saved is THAT one, never the previous token's.
|
|
13
|
+
*/
|
|
14
|
+
export declare function saveTeamToken(env: EnvironmentConfig, envName: EnvName, token: string, config: ConfigStore, ctx: {
|
|
15
|
+
wrapped: boolean;
|
|
16
|
+
tty: boolean;
|
|
17
|
+
}): Promise<VerifiedIdentity | string>;
|
|
3
18
|
export declare function loginInteractive(env: EnvironmentConfig, envName: EnvName, config: ConfigStore): Promise<boolean>;
|
|
4
19
|
export {};
|
|
5
20
|
//# sourceMappingURL=login-flow.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"login-flow.d.ts","sourceRoot":"","sources":["../../src/lib/login-flow.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"login-flow.d.ts","sourceRoot":"","sources":["../../src/lib/login-flow.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,gBAAgB,EAAe,MAAM,gBAAgB,CAAC;AAKpE,OAAO,KAAK,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAEjF,KAAK,WAAW,GAAG,UAAU,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAMxD;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,iBAAiB,GAAG,MAAM,CAY1E;AAED;;;GAGG;AACH,wBAAsB,aAAa,CACjC,GAAG,EAAE,iBAAiB,EAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,GAAG,EAAE;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,GAAG,EAAE,OAAO,CAAA;CAAE,GACpH,OAAO,CAAC,gBAAgB,GAAG,MAAM,CAAC,CAQpC;AAED,wBAAsB,gBAAgB,CACpC,GAAG,EAAE,iBAAiB,EACtB,OAAO,EAAE,OAAO,EAChB,MAAM,EAAE,WAAW,GAClB,OAAO,CAAC,OAAO,CAAC,CA+FlB"}
|
package/dist/lib/login-flow.js
CHANGED
|
@@ -1,32 +1,92 @@
|
|
|
1
1
|
import * as p from '@clack/prompts';
|
|
2
2
|
import chalk from 'chalk';
|
|
3
|
+
import { assertTransport } from './destination-trust.js';
|
|
4
|
+
import { verifyToken } from './join-flow.js';
|
|
3
5
|
import { tryOpenUrl } from './open-url.js';
|
|
6
|
+
import { visible } from './share/visible.js';
|
|
4
7
|
import { createGatewayClient, GatewayError } from './gateway-client.js';
|
|
5
8
|
import { CLI_CALLBACK_PORTS, waitForCallback } from './cli-oauth.js';
|
|
6
9
|
// Browser-based CLI login. Starts a local callback server, opens the branded
|
|
7
10
|
// login page, exchanges the returned token, verifies it, and persists the
|
|
8
11
|
// token + tenant id. Returns true on success. Shared by `align login` and the
|
|
9
12
|
// inline login on the cloud `align setup` path.
|
|
13
|
+
/**
|
|
14
|
+
* The address /auth/cli-init hands back is opened in a browser, so it is checked first: http(s) only, and for a team destination its
|
|
15
|
+
* origin must be the saved gateway's or web app's (a joined gateway is whatever was joined, so its word is not enough). A string
|
|
16
|
+
* starting with '!' is the reason it was refused.
|
|
17
|
+
*/
|
|
18
|
+
export function checkLoginUrl(raw, env) {
|
|
19
|
+
if (typeof raw !== 'string' || raw === '')
|
|
20
|
+
return '!the gateway sent no login address';
|
|
21
|
+
let u;
|
|
22
|
+
try {
|
|
23
|
+
u = new URL(raw);
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
return '!the gateway sent something that is not a web address';
|
|
27
|
+
}
|
|
28
|
+
if (u.protocol !== 'https:' && u.protocol !== 'http:')
|
|
29
|
+
return `!it is not a web address (${visible(u.protocol)})`;
|
|
30
|
+
if (env.kind === 'team') {
|
|
31
|
+
let origin;
|
|
32
|
+
try {
|
|
33
|
+
origin = assertTransport(u.origin);
|
|
34
|
+
}
|
|
35
|
+
catch (e) {
|
|
36
|
+
return `!${visible(e.message)}`;
|
|
37
|
+
}
|
|
38
|
+
const own = [env.gatewayUrl, env.appUrl].filter((x) => typeof x === 'string').map((x) => x.replace(/\/+$/, ''));
|
|
39
|
+
if (!own.includes(origin))
|
|
40
|
+
return `!${visible(u.host)} is not this destination's gateway or web app`;
|
|
41
|
+
}
|
|
42
|
+
return raw;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* `align login --env <team> --token X`: the no-browser renewal. A person at a terminal only, never inside an agent, and the token is
|
|
46
|
+
* kept only once the destination's gateway says whose it is; the tenant saved is THAT one, never the previous token's.
|
|
47
|
+
*/
|
|
48
|
+
export async function saveTeamToken(env, envName, token, config, ctx) {
|
|
49
|
+
if (ctx.wrapped)
|
|
50
|
+
return 'A token for a team destination has to be saved by you, in your own terminal, not from inside an agent. Nothing was saved.';
|
|
51
|
+
if (!ctx.tty)
|
|
52
|
+
return 'Saving a token for a team destination needs a terminal. Nothing was saved.';
|
|
53
|
+
const who = await verifyToken(env.gatewayUrl, token);
|
|
54
|
+
if (typeof who === 'string')
|
|
55
|
+
return `${new URL(env.gatewayUrl).host} ${who}`;
|
|
56
|
+
config.setAuthToken(envName, token);
|
|
57
|
+
config.setTenantId(envName, who.tenantId);
|
|
58
|
+
return who;
|
|
59
|
+
}
|
|
10
60
|
export async function loginInteractive(env, envName, config) {
|
|
11
61
|
const spinner = p.spinner();
|
|
12
62
|
spinner.start('Opening browser for login...');
|
|
13
63
|
let loginUrl = '';
|
|
64
|
+
const stop = new AbortController();
|
|
65
|
+
let refused = '';
|
|
14
66
|
const callbackPromise = waitForCallback({
|
|
15
67
|
ports: CLI_CALLBACK_PORTS,
|
|
16
68
|
timeoutMs: 120_000,
|
|
69
|
+
signal: stop.signal,
|
|
17
70
|
onBound: async (port, nonce) => {
|
|
18
71
|
try {
|
|
19
72
|
const res = await fetch(`${env.gatewayUrl}/auth/cli-init?port=${port}&nonce=${nonce}`);
|
|
20
73
|
if (!res.ok)
|
|
21
74
|
throw new Error(`Gateway returned ${res.status}`);
|
|
22
75
|
const body = await res.json();
|
|
23
|
-
|
|
76
|
+
const checked = checkLoginUrl(body.url, env);
|
|
77
|
+
if (typeof checked !== 'string' || checked.startsWith('!')) {
|
|
78
|
+
refused = typeof checked === 'string' ? checked.slice(1) : 'the gateway sent no login address';
|
|
79
|
+
spinner.stop(`Not opening that address: ${refused}`);
|
|
80
|
+
stop.abort();
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
loginUrl = checked;
|
|
24
84
|
const opened = await tryOpenUrl(loginUrl);
|
|
25
85
|
// The message follows the boolean: claiming "Browser opened" over a detected
|
|
26
86
|
// failure is the same lie the paste path told in 0.28.0.
|
|
27
87
|
spinner.stop(opened
|
|
28
|
-
? `Browser opened. If nothing happened, visit:\n ${chalk.bold(loginUrl)}`
|
|
29
|
-
: `Could not open a browser here. Log in at:\n ${chalk.bold(loginUrl)}`);
|
|
88
|
+
? `Browser opened. If nothing happened, visit:\n ${chalk.bold(visible(loginUrl))}`
|
|
89
|
+
: `Could not open a browser here. Log in at:\n ${chalk.bold(visible(loginUrl))}`);
|
|
30
90
|
p.log.info('Waiting for you to log in (2 min timeout)...');
|
|
31
91
|
}
|
|
32
92
|
catch (e) {
|
|
@@ -39,7 +99,7 @@ export async function loginInteractive(env, envName, config) {
|
|
|
39
99
|
result = await callbackPromise;
|
|
40
100
|
}
|
|
41
101
|
catch (e) {
|
|
42
|
-
p.log.error(`Login failed: ${e.message}`);
|
|
102
|
+
p.log.error(refused ? `Login stopped: ${refused}. Nothing was saved.` : `Login failed: ${e.message}`);
|
|
43
103
|
return false;
|
|
44
104
|
}
|
|
45
105
|
const token = result.data['token'];
|
|
@@ -47,6 +107,22 @@ export async function loginInteractive(env, envName, config) {
|
|
|
47
107
|
p.log.error('No token received. Try again or use: align login --token <token>');
|
|
48
108
|
return false;
|
|
49
109
|
}
|
|
110
|
+
// A team destination is renewed the way it was joined: the token is only kept once the gateway has answered who it belongs to,
|
|
111
|
+
// in the shape an Align gateway uses. "Unreachable" is not "verified" here, unlike the builtins below (join review F10).
|
|
112
|
+
if (env.kind === 'team') {
|
|
113
|
+
const spin = p.spinner();
|
|
114
|
+
spin.start('Verifying token...');
|
|
115
|
+
const who = await verifyToken(env.gatewayUrl, token);
|
|
116
|
+
if (typeof who === 'string') {
|
|
117
|
+
spin.stop('Login failed: the new token could not be verified.');
|
|
118
|
+
p.log.error(`${new URL(env.gatewayUrl).host} ${who}`);
|
|
119
|
+
return false;
|
|
120
|
+
}
|
|
121
|
+
config.setAuthToken(envName, token);
|
|
122
|
+
config.setTenantId(envName, who.tenantId);
|
|
123
|
+
spin.stop(`Logged in as ${visible(who.email)} (${visible(who.tenantName)}) [${envName}]`);
|
|
124
|
+
return true;
|
|
125
|
+
}
|
|
50
126
|
const verifySpinner = p.spinner();
|
|
51
127
|
verifySpinner.start('Verifying token...');
|
|
52
128
|
try {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"login-flow.js","sourceRoot":"","sources":["../../src/lib/login-flow.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,gBAAgB,CAAC;AACpC,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAC3C,OAAO,EAAE,mBAAmB,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACxE,OAAO,EAAE,kBAAkB,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAKrE,6EAA6E;AAC7E,0EAA0E;AAC1E,8EAA8E;AAC9E,gDAAgD;AAChD,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,GAAsB,EACtB,OAAgB,EAChB,MAAmB;IAEnB,MAAM,OAAO,GAAG,CAAC,CAAC,OAAO,EAAE,CAAC;IAC5B,OAAO,CAAC,KAAK,CAAC,8BAA8B,CAAC,CAAC;IAE9C,IAAI,QAAQ,GAAG,EAAE,CAAC;IAClB,MAAM,eAAe,GAAG,eAAe,CAAC;QACtC,KAAK,EAAE,kBAAkB;QACzB,SAAS,EAAE,OAAO;QAClB,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE;YAC7B,IAAI,CAAC;gBACH,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,GAAG,CAAC,UAAU,uBAAuB,IAAI,UAAU,KAAK,EAAE,CAAC,CAAC;gBACvF,IAAI,CAAC,GAAG,CAAC,EAAE;oBAAE,MAAM,IAAI,KAAK,CAAC,oBAAoB,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC;gBAC/D,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,
|
|
1
|
+
{"version":3,"file":"login-flow.js","sourceRoot":"","sources":["../../src/lib/login-flow.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { EnvironmentConfig } from '../config.js';
|
|
2
|
+
import { type ShareToolContext, type ShareToolResult } from './share-tool.js';
|
|
3
|
+
export declare const SHARE_STATUS_TOOL_SCHEMA: {
|
|
4
|
+
readonly name: "align_share_status";
|
|
5
|
+
readonly annotations: {
|
|
6
|
+
readonly readOnlyHint: false;
|
|
7
|
+
readonly destructiveHint: false;
|
|
8
|
+
};
|
|
9
|
+
readonly description: string;
|
|
10
|
+
readonly inputSchema: Record<string, unknown>;
|
|
11
|
+
};
|
|
12
|
+
export declare function runShareStatusTool(args: Record<string, unknown> | undefined, env: EnvironmentConfig, ctx?: ShareToolContext): Promise<ShareToolResult>;
|
|
13
|
+
//# sourceMappingURL=share-status-tool.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"share-status-tool.d.ts","sourceRoot":"","sources":["../../../src/lib/mcp/share-status-tool.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAQtD,OAAO,EAA6D,KAAK,gBAAgB,EAAE,KAAK,eAAe,EAAE,MAAM,iBAAiB,CAAC;AASzI,eAAO,MAAM,wBAAwB;;;;;;;;CAU3B,CAAC;AAIX,wBAAsB,kBAAkB,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,EAAE,GAAG,EAAE,iBAAiB,EAAE,GAAG,GAAE,gBAAqB,GAAG,OAAO,CAAC,eAAe,CAAC,CA+DhK"}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ALI-1540: the MCP tool `align_share_status` - the second half of an approved share.
|
|
3
|
+
*
|
|
4
|
+
* `align_share` stages a request and hands the person a link. This tool reads where that request stands and, ONLY
|
|
5
|
+
* when the gateway says the person approved it, sends the exact bytes that were approved (the completion call).
|
|
6
|
+
* Everything else it does is read-only: waiting, declined, expired and cancelled change nothing on the team graph.
|
|
7
|
+
*
|
|
8
|
+
* It completes at most once: the pending file is taken by an atomic rename, so a second call finds nothing to
|
|
9
|
+
* complete. Before it completes it rebuilds the share from the local graph and refuses (and cancels the request)
|
|
10
|
+
* if what would be shared changed since the person was shown it, the same rule `--confirm` applies to a code.
|
|
11
|
+
*
|
|
12
|
+
* Input: one string, the request id. No token or key can be passed.
|
|
13
|
+
*/
|
|
14
|
+
import { createHash } from 'node:crypto';
|
|
15
|
+
import { defaultJudge } from '../curation/judge.js';
|
|
16
|
+
import { defaultGatewayUrlFor } from '../config.js';
|
|
17
|
+
import { completeRequest, CompletionError } from '../share/approval.js';
|
|
18
|
+
import { buildPlaintext } from '../share/envelope.js';
|
|
19
|
+
import { getPromotion } from '../share/ledger.js';
|
|
20
|
+
import { claimRequest, combinedHash, deleteRequest, loadRequest, sweepPending } from '../share/pending.js';
|
|
21
|
+
import { REQUEST_ID_RE } from '../share/requests-client.js';
|
|
22
|
+
import { prepare, renderResults, send, ShareError } from '../share/run.js';
|
|
23
|
+
import { visible } from '../share/visible.js';
|
|
24
|
+
import { hasLogin, NO_LOGIN, resolveShareTarget, SHARE_STATUS_TOOL } from './share-tool.js';
|
|
25
|
+
import { jsonSchemaOf, strictInput } from './tool-rules.js';
|
|
26
|
+
const SPEC = {
|
|
27
|
+
tool: SHARE_STATUS_TOOL,
|
|
28
|
+
required: ['request_id'],
|
|
29
|
+
properties: { request_id: { type: 'string', description: 'The request_id align_share returned', maxLength: 64 } },
|
|
30
|
+
};
|
|
31
|
+
export const SHARE_STATUS_TOOL_SCHEMA = {
|
|
32
|
+
name: SHARE_STATUS_TOOL,
|
|
33
|
+
// It writes: once the user has approved, it completes the share, which creates or updates decisions on the team graph. It deletes nothing there.
|
|
34
|
+
annotations: { readOnlyHint: false, destructiveHint: false },
|
|
35
|
+
description: 'Check a share the user was asked to approve in their browser (from align_share), and finish it once they have. ' +
|
|
36
|
+
'It reports waiting, declined, expired or cancelled, and changes nothing in those cases. When the user HAS approved, the first call sends exactly what they approved and returns the result; a second call sends nothing. ' +
|
|
37
|
+
'A completed share stays with the team as its record, even if the user later leaves. It does not approve anything: approving is the user\'s act, in their browser, and you must not attempt it. Call it after the user says they approved, or to see whether they have. ' +
|
|
38
|
+
'It never takes a token or key.',
|
|
39
|
+
inputSchema: jsonSchemaOf(SPEC),
|
|
40
|
+
};
|
|
41
|
+
const minutes = (iso, now = Date.now()) => Math.max(0, Math.round((Date.parse(iso) - now) / 60000));
|
|
42
|
+
export async function runShareStatusTool(args, env, ctx = {}) {
|
|
43
|
+
const input = strictInput(SPEC, args);
|
|
44
|
+
const id = input['request_id'];
|
|
45
|
+
const t = resolveShareTarget(env, ctx, SHARE_STATUS_TOOL);
|
|
46
|
+
sweepPending();
|
|
47
|
+
if (!hasLogin(t.cloudEnv))
|
|
48
|
+
return { text: NO_LOGIN(), shared: false };
|
|
49
|
+
if (!REQUEST_ID_RE.test(id))
|
|
50
|
+
return { text: 'That is not a share request id. Use the request_id align_share returned.', shared: false };
|
|
51
|
+
const rec = loadRequest(id);
|
|
52
|
+
if (rec === null)
|
|
53
|
+
return { text: 'No share is waiting under that id on this machine. It may already be finished, cancelled or expired. Call align_share again to start a new one.', shared: false, state: 'unknown' };
|
|
54
|
+
try {
|
|
55
|
+
const { state } = await t.client.getShareRequest(id);
|
|
56
|
+
const ended = (text, st) => { deleteRequest(id); return { text, shared: false, state: st }; };
|
|
57
|
+
switch (state) {
|
|
58
|
+
case 'pending': return { text: `Still waiting for the user to approve it in their browser. Code ${visible(rec.userCode)}; it expires in about ${minutes(rec.expiresAt)} minutes. Nothing has been sent. Ask the user to open the link align_share gave them.`, shared: false, state, request_id: id };
|
|
59
|
+
case 'declined': return ended('The user declined it in their browser. Nothing was sent.', state);
|
|
60
|
+
case 'expired': return ended('The request expired before it was approved. Nothing was sent. Call align_share again to start a new one.', state);
|
|
61
|
+
case 'cancelled': return ended('The request was cancelled. Nothing was sent.', state);
|
|
62
|
+
case 'failed': return ended('The gateway marked the request as failed. Nothing was sent. Call align_share again to start a new one.', state);
|
|
63
|
+
case 'completed': {
|
|
64
|
+
// Completed by this process (the answer was lost) or by another. If this machine has no ledger row for what it staged,
|
|
65
|
+
// say so: a later retract cannot find an unrecorded share, and "already completed" alone would read as fully done.
|
|
66
|
+
const unrecorded = rec.localIds.filter((l) => getPromotion(env.localDbPath, l, rec.envName, rec.tenantId) === null);
|
|
67
|
+
return ended(unrecorded.length === 0
|
|
68
|
+
? 'That share was already completed, and this machine has the record of it.'
|
|
69
|
+
: 'The gateway says that share was completed (by this machine, whose answer was lost, or by another process). This machine has NO record of the result, so it is not in the local ledger and `align share --retract` cannot find it. Check the team graph. Sharing the same decision again is safe (it will not make a second copy) and records it here.', state);
|
|
70
|
+
}
|
|
71
|
+
case 'completing': return { text: 'The gateway is finishing that share now. Check again in a moment.', shared: false, state, request_id: id };
|
|
72
|
+
case 'approved': break;
|
|
73
|
+
}
|
|
74
|
+
// Approved: take the request (atomically), so two calls cannot both complete it.
|
|
75
|
+
const claim = claimRequest(id);
|
|
76
|
+
if (claim === null)
|
|
77
|
+
return { text: 'That share is already being completed or has been. Nothing more was sent by this call.', shared: false, state: 'completing', request_id: id };
|
|
78
|
+
try {
|
|
79
|
+
const shareCtx = { dbPath: env.localDbPath, envName: t.envName, client: t.client, judge: await (ctx.judge ?? defaultJudge)(), salt: t.salt, gatewayUrl: t.cloudEnv.gatewayUrl, defaultGatewayUrl: defaultGatewayUrlFor(t.envName) };
|
|
80
|
+
const prep = await prepare(shareCtx, claim.request.localIds);
|
|
81
|
+
// Rebuild what would be sent NOW and require it to be byte-for-byte what was approved, with the hash and the decisions this record names.
|
|
82
|
+
// A pending file edited to point at other decisions (or a stale copy) can never record one decision's share under another's id.
|
|
83
|
+
const rebuilt = prep.payloads.length === 0 ? null : buildPlaintext({ kind: 'share', tenantId: prep.tenantId, gatewayUrl: prep.gatewayUrl, payloads: prep.payloads });
|
|
84
|
+
const unchanged = rebuilt !== null
|
|
85
|
+
&& rebuilt.equals(Buffer.from(claim.request.bytesB64, 'base64'))
|
|
86
|
+
&& createHash('sha256').update(rebuilt).digest('hex') === claim.request.sha256
|
|
87
|
+
&& prep.payloads.map((p) => p.localId).join('\n') === claim.request.localIds.join('\n');
|
|
88
|
+
if (prep.secrets.length || !unchanged || combinedHash(prep.payloads, prep) !== claim.request.hash || claim.request.envName !== t.envName) {
|
|
89
|
+
// What the user approved is no longer what this machine would send: do not send it.
|
|
90
|
+
await t.client.cancelShareRequest(id).catch(() => undefined);
|
|
91
|
+
claim.finish();
|
|
92
|
+
return { text: 'What would be shared, or where it would go, changed since the user was shown it, so nothing was sent and the request was cancelled. Call align_share to start again.', shared: false, state: 'changed' };
|
|
93
|
+
}
|
|
94
|
+
const response = await completeRequest(t.client, id, claim.request.bytesB64);
|
|
95
|
+
const rows = await send(shareCtx, prep, { post: async (_b, phase) => (phase === 'share' ? response : null) });
|
|
96
|
+
claim.finish();
|
|
97
|
+
const waiting = rows.some((r) => r.judgementFailures.some((f) => f.error === 'needs_confirmation'));
|
|
98
|
+
const more = waiting ? `\n\nSome of the user's judgements wait for the team's existing text to be confirmed. Tell the user to run align share ${visible(claim.request.localIds[0] ?? '<id>')} in their own terminal: they approve that second step in the browser too.` : '';
|
|
99
|
+
return { text: `Approved by the user, and sent:\n${renderResults(rows)}${more}`, shared: !rows.every((r) => r.outcome.kind === 'refused' || r.outcome.kind === 'unknown'), state: 'completed' };
|
|
100
|
+
}
|
|
101
|
+
catch (e) {
|
|
102
|
+
// No verdict from the gateway means the same bytes may be sent again; any other failure is final for this request.
|
|
103
|
+
if (e instanceof CompletionError && e.retryable)
|
|
104
|
+
claim.release();
|
|
105
|
+
else
|
|
106
|
+
claim.finish();
|
|
107
|
+
throw e;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
catch (e) {
|
|
111
|
+
if (e instanceof ShareError)
|
|
112
|
+
throw new Error(e.message);
|
|
113
|
+
throw new Error(visible(e.message));
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
//# sourceMappingURL=share-status-tool.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"share-status-tool.js","sourceRoot":"","sources":["../../../src/lib/mcp/share-status-tool.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,20 +1,8 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* L9: the MCP tool `align_share` - step ONE of a two-step share, and never step two.
|
|
3
|
-
*
|
|
4
|
-
* What it does: builds the exact preview of what would leave this machine, runs the secret scan,
|
|
5
|
-
* stores the payload under a short-lived single-use code and returns the preview plus the command
|
|
6
|
-
* a PERSON runs: `align share --confirm <code>`. What it cannot do: send. Nothing in this module
|
|
7
|
-
* calls `shareBatch`; the only network call is `whoami` (a read) to name the destination. There is
|
|
8
|
-
* no elicitation path here either: an answer shown by the client is only as trustworthy as the
|
|
9
|
-
* client, so completion is reserved for the CLI at a controlling terminal (Decision 17, stage 1).
|
|
10
|
-
*
|
|
11
|
-
* The input schema is closed and has one property, the decision id: a token or key cannot be
|
|
12
|
-
* passed, and the destination is the user's own logged-in environment, never an argument.
|
|
13
|
-
*/
|
|
14
1
|
import type { EnvironmentConfig } from '../config.js';
|
|
15
2
|
import type { Judge } from '../curation/judgements-db.js';
|
|
16
3
|
import { type ShareClient } from '../share/run.js';
|
|
17
4
|
export declare const SHARE_TOOL = "align_share";
|
|
5
|
+
export declare const SHARE_STATUS_TOOL = "align_share_status";
|
|
18
6
|
export declare const SHARE_TOOL_SCHEMA: {
|
|
19
7
|
readonly name: "align_share";
|
|
20
8
|
readonly annotations: {
|
|
@@ -29,12 +17,15 @@ export interface ShareToolContext {
|
|
|
29
17
|
name?: unknown;
|
|
30
18
|
};
|
|
31
19
|
judge?: () => Promise<Judge>;
|
|
32
|
-
/** Test seam: the destination and the
|
|
20
|
+
/** Test seam: the destination and the client. Production resolves the user's default cloud env. */
|
|
33
21
|
share?: {
|
|
34
22
|
cloudEnv: EnvironmentConfig;
|
|
35
23
|
envName: string;
|
|
36
24
|
client: ShareClient;
|
|
37
25
|
salt?: string;
|
|
26
|
+
appUrl?: string;
|
|
27
|
+
label?: string;
|
|
28
|
+
teamAppUrl?: string;
|
|
38
29
|
};
|
|
39
30
|
}
|
|
40
31
|
export interface ShareToolResult {
|
|
@@ -42,5 +33,18 @@ export interface ShareToolResult {
|
|
|
42
33
|
code?: string;
|
|
43
34
|
[k: string]: unknown;
|
|
44
35
|
}
|
|
36
|
+
export interface ShareTarget {
|
|
37
|
+
cloudEnv: EnvironmentConfig;
|
|
38
|
+
envName: string;
|
|
39
|
+
client: ShareClient;
|
|
40
|
+
salt: string;
|
|
41
|
+
appUrl: string;
|
|
42
|
+
label: string; /** Set for a team destination: the web app saved at join time. */
|
|
43
|
+
teamAppUrl?: string;
|
|
44
|
+
}
|
|
45
|
+
/** The local graph this server reads, and the cloud environment a share goes to. Shared with align_share_status. */
|
|
46
|
+
export declare function resolveShareTarget(env: EnvironmentConfig, ctx: ShareToolContext, tool: string): ShareTarget;
|
|
47
|
+
export declare const NO_LOGIN: () => string;
|
|
48
|
+
export declare const hasLogin: (e: EnvironmentConfig) => boolean;
|
|
45
49
|
export declare function runShareTool(args: Record<string, unknown> | undefined, env: EnvironmentConfig, ctx?: ShareToolContext): Promise<ShareToolResult>;
|
|
46
50
|
//# sourceMappingURL=share-tool.d.ts.map
|