@aligndottech/cli 0.37.1 → 0.38.1
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 +16 -10
- package/dist/cli.d.ts +28 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +98 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/check.d.ts +1 -1
- package/dist/commands/check.d.ts.map +1 -1
- package/dist/commands/check.js +44 -2
- package/dist/commands/check.js.map +1 -1
- package/dist/commands/connect-agents.d.ts +1 -0
- package/dist/commands/connect-agents.d.ts.map +1 -1
- package/dist/commands/connect-agents.js +10 -6
- package/dist/commands/connect-agents.js.map +1 -1
- package/dist/commands/connect.d.ts +31 -0
- package/dist/commands/connect.d.ts.map +1 -0
- package/dist/commands/connect.js +92 -0
- package/dist/commands/connect.js.map +1 -0
- package/dist/commands/context.d.ts.map +1 -1
- package/dist/commands/context.js +52 -10
- package/dist/commands/context.js.map +1 -1
- package/dist/commands/decisions/index.d.ts.map +1 -1
- package/dist/commands/decisions/index.js +5 -0
- package/dist/commands/decisions/index.js.map +1 -1
- package/dist/commands/default-action.d.ts +3 -1
- package/dist/commands/default-action.d.ts.map +1 -1
- package/dist/commands/default-action.js +29 -27
- package/dist/commands/default-action.js.map +1 -1
- package/dist/commands/export.d.ts.map +1 -1
- package/dist/commands/export.js +3 -0
- package/dist/commands/export.js.map +1 -1
- package/dist/commands/import/sessions.d.ts +10 -2
- package/dist/commands/import/sessions.d.ts.map +1 -1
- package/dist/commands/import/sessions.js +98 -3
- package/dist/commands/import/sessions.js.map +1 -1
- package/dist/commands/import.d.ts +7 -0
- package/dist/commands/import.d.ts.map +1 -1
- package/dist/commands/import.js +42 -2
- package/dist/commands/import.js.map +1 -1
- package/dist/commands/invite.d.ts +25 -0
- package/dist/commands/invite.d.ts.map +1 -0
- package/dist/commands/invite.js +68 -0
- package/dist/commands/invite.js.map +1 -0
- package/dist/commands/links.d.ts.map +1 -1
- package/dist/commands/links.js +5 -0
- package/dist/commands/links.js.map +1 -1
- package/dist/commands/mcp.d.ts +64 -35
- package/dist/commands/mcp.d.ts.map +1 -1
- package/dist/commands/mcp.js +94 -41
- package/dist/commands/mcp.js.map +1 -1
- package/dist/commands/ratify.d.ts.map +1 -1
- package/dist/commands/ratify.js +21 -0
- package/dist/commands/ratify.js.map +1 -1
- package/dist/commands/registry.d.ts +30 -0
- package/dist/commands/registry.d.ts.map +1 -0
- package/dist/commands/registry.js +70 -0
- package/dist/commands/registry.js.map +1 -0
- package/dist/commands/setup.d.ts +45 -1
- package/dist/commands/setup.d.ts.map +1 -1
- package/dist/commands/setup.js +197 -88
- package/dist/commands/setup.js.map +1 -1
- package/dist/commands/status.d.ts.map +1 -1
- package/dist/commands/status.js +10 -22
- package/dist/commands/status.js.map +1 -1
- package/dist/commands/telemetry.d.ts +7 -3
- package/dist/commands/telemetry.d.ts.map +1 -1
- package/dist/commands/telemetry.js +12 -7
- package/dist/commands/telemetry.js.map +1 -1
- package/dist/commands/why.d.ts.map +1 -1
- package/dist/commands/why.js +52 -10
- package/dist/commands/why.js.map +1 -1
- package/dist/index.js +4 -90
- package/dist/index.js.map +1 -1
- package/dist/lib/agent-rules.d.ts +1 -0
- package/dist/lib/agent-rules.d.ts.map +1 -1
- package/dist/lib/agent-rules.js +60 -0
- package/dist/lib/agent-rules.js.map +1 -1
- package/dist/lib/commands-doc.d.ts +15 -0
- package/dist/lib/commands-doc.d.ts.map +1 -0
- package/dist/lib/commands-doc.js +85 -0
- package/dist/lib/commands-doc.js.map +1 -0
- package/dist/lib/config.d.ts +7 -2
- package/dist/lib/config.d.ts.map +1 -1
- package/dist/lib/config.js.map +1 -1
- package/dist/lib/connect-prompt.d.ts +1 -1
- package/dist/lib/connect-prompt.js +2 -2
- package/dist/lib/connect-prompt.js.map +1 -1
- package/dist/lib/decision-links.d.ts +39 -0
- package/dist/lib/decision-links.d.ts.map +1 -1
- package/dist/lib/decision-links.js +51 -0
- package/dist/lib/decision-links.js.map +1 -1
- package/dist/lib/first-decision.d.ts +22 -0
- package/dist/lib/first-decision.d.ts.map +1 -0
- package/dist/lib/first-decision.js +22 -0
- package/dist/lib/first-decision.js.map +1 -0
- package/dist/lib/gateway-client.d.ts +14 -1
- package/dist/lib/gateway-client.d.ts.map +1 -1
- package/dist/lib/gateway-client.js +14 -0
- package/dist/lib/gateway-client.js.map +1 -1
- package/dist/lib/git.d.ts +28 -0
- package/dist/lib/git.d.ts.map +1 -1
- package/dist/lib/git.js +42 -0
- package/dist/lib/git.js.map +1 -1
- package/dist/lib/hook-context.d.ts +7 -0
- package/dist/lib/hook-context.d.ts.map +1 -0
- package/dist/lib/hook-context.js +37 -0
- package/dist/lib/hook-context.js.map +1 -0
- package/dist/lib/hook-payload.d.ts +7 -0
- package/dist/lib/hook-payload.d.ts.map +1 -1
- package/dist/lib/hook-payload.js +56 -8
- package/dist/lib/hook-payload.js.map +1 -1
- package/dist/lib/invite-prompt.d.ts +46 -0
- package/dist/lib/invite-prompt.d.ts.map +1 -0
- package/dist/lib/invite-prompt.js +63 -0
- package/dist/lib/invite-prompt.js.map +1 -0
- package/dist/lib/local-gateway-client.d.ts +0 -1
- package/dist/lib/local-gateway-client.d.ts.map +1 -1
- package/dist/lib/local-gateway-client.js +5 -2
- package/dist/lib/local-gateway-client.js.map +1 -1
- package/dist/lib/mcp-instructions.shared.d.ts +40 -0
- package/dist/lib/mcp-instructions.shared.d.ts.map +1 -0
- package/dist/lib/mcp-instructions.shared.js +56 -0
- package/dist/lib/mcp-instructions.shared.js.map +1 -0
- package/dist/lib/mcp-setup.d.ts +32 -2
- package/dist/lib/mcp-setup.d.ts.map +1 -1
- package/dist/lib/mcp-setup.js +92 -6
- package/dist/lib/mcp-setup.js.map +1 -1
- package/dist/lib/next-step.d.ts +92 -0
- package/dist/lib/next-step.d.ts.map +1 -0
- package/dist/lib/next-step.js +116 -0
- package/dist/lib/next-step.js.map +1 -0
- package/dist/lib/personal-email-domains.d.ts +8 -0
- package/dist/lib/personal-email-domains.d.ts.map +1 -0
- package/dist/lib/personal-email-domains.js +39 -0
- package/dist/lib/personal-email-domains.js.map +1 -0
- package/dist/lib/personal-import.d.ts +2 -0
- package/dist/lib/personal-import.d.ts.map +1 -1
- package/dist/lib/personal-import.js +4 -1
- package/dist/lib/personal-import.js.map +1 -1
- package/dist/lib/read-value-rollup.d.ts +18 -0
- package/dist/lib/read-value-rollup.d.ts.map +1 -0
- package/dist/lib/read-value-rollup.js +33 -0
- package/dist/lib/read-value-rollup.js.map +1 -0
- package/dist/lib/sessions/import-summary.d.ts +39 -0
- package/dist/lib/sessions/import-summary.d.ts.map +1 -0
- package/dist/lib/sessions/import-summary.js +41 -0
- package/dist/lib/sessions/import-summary.js.map +1 -0
- package/dist/lib/sessions/memory-files.d.ts +85 -0
- package/dist/lib/sessions/memory-files.d.ts.map +1 -0
- package/dist/lib/sessions/memory-files.js +235 -0
- package/dist/lib/sessions/memory-files.js.map +1 -0
- package/dist/lib/sessions/source-url.d.ts +11 -0
- package/dist/lib/sessions/source-url.d.ts.map +1 -1
- package/dist/lib/sessions/source-url.js +15 -0
- package/dist/lib/sessions/source-url.js.map +1 -1
- package/dist/lib/setup-funnel.d.ts +41 -0
- package/dist/lib/setup-funnel.d.ts.map +1 -0
- package/dist/lib/setup-funnel.js +28 -0
- package/dist/lib/setup-funnel.js.map +1 -0
- package/dist/lib/telemetry-consent.d.ts +17 -8
- package/dist/lib/telemetry-consent.d.ts.map +1 -1
- package/dist/lib/telemetry-consent.js +21 -6
- package/dist/lib/telemetry-consent.js.map +1 -1
- package/dist/lib/telemetry-env.d.ts +19 -0
- package/dist/lib/telemetry-env.d.ts.map +1 -0
- package/dist/lib/telemetry-env.js +13 -0
- package/dist/lib/telemetry-env.js.map +1 -0
- package/dist/lib/usage-telemetry.d.ts +108 -13
- package/dist/lib/usage-telemetry.d.ts.map +1 -1
- package/dist/lib/usage-telemetry.js +227 -55
- package/dist/lib/usage-telemetry.js.map +1 -1
- package/dist/lib/user-hooks.d.ts +15 -0
- package/dist/lib/user-hooks.d.ts.map +1 -0
- package/dist/lib/user-hooks.js +144 -0
- package/dist/lib/user-hooks.js.map +1 -0
- package/dist/lib/value-rollup.d.ts +10 -3
- package/dist/lib/value-rollup.d.ts.map +1 -1
- package/dist/lib/value-rollup.js +11 -4
- package/dist/lib/value-rollup.js.map +1 -1
- package/package.json +2 -1
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ALI-835: the line a human reads at the end of `align import sessions`, and the counts the
|
|
3
|
+
* funnel reports.
|
|
4
|
+
*
|
|
5
|
+
* The line is the product moment; the ping is the measurement. They are built from ONE object
|
|
6
|
+
* here so the two can never disagree - a summary saying 41 beside a ping saying 40 would make
|
|
7
|
+
* both unusable, and nothing downstream could tell which was wrong.
|
|
8
|
+
*
|
|
9
|
+
* The demo beat this exists for (Madhuri, 2026-08-25): run the import on the prospect's own
|
|
10
|
+
* repo, read the line aloud, ask who in the room knew.
|
|
11
|
+
*/
|
|
12
|
+
export interface SessionImportCounts {
|
|
13
|
+
/** Session files read, across every detected agent. */
|
|
14
|
+
sessionsScanned: number;
|
|
15
|
+
/** Decision-shaped moments found, before review. */
|
|
16
|
+
candidatesFound: number;
|
|
17
|
+
/** How many of those a human confirmed into the graph this run. */
|
|
18
|
+
candidatesConfirmed: number;
|
|
19
|
+
/**
|
|
20
|
+
* How many of the confirmed claims already carry a human ratification.
|
|
21
|
+
*
|
|
22
|
+
* Structurally 0 at import: `align import sessions` writes claims, and ratifying is a
|
|
23
|
+
* separate human act (`align ratify`). It is reported anyway, because "0 have been ratified"
|
|
24
|
+
* is the sentence the demo turns on - the point is that nobody has stood behind any of them
|
|
25
|
+
* yet. The funnel's own decisions_ratified stage is emitted from `align ratify`, where the
|
|
26
|
+
* number actually moves, rather than from here where it could only ever be zero.
|
|
27
|
+
*/
|
|
28
|
+
ratified: number;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* The summary line.
|
|
32
|
+
*
|
|
33
|
+
* Renders honestly at zero rather than crashing or printing a line about nothing: "Found 0
|
|
34
|
+
* decisions in 3 sessions" is a different sentence from "Found 0 decisions across 0 sessions",
|
|
35
|
+
* and both are different from an exception. Singular and plural are handled for every count,
|
|
36
|
+
* because "1 sessions" in a demo is the kind of detail that costs more attention than it saves.
|
|
37
|
+
*/
|
|
38
|
+
export declare function renderImportSummary(counts: SessionImportCounts): string;
|
|
39
|
+
//# sourceMappingURL=import-summary.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"import-summary.d.ts","sourceRoot":"","sources":["../../../src/lib/sessions/import-summary.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,MAAM,WAAW,mBAAmB;IAClC,uDAAuD;IACvD,eAAe,EAAE,MAAM,CAAC;IACxB,oDAAoD;IACpD,eAAe,EAAE,MAAM,CAAC;IACxB,mEAAmE;IACnE,mBAAmB,EAAE,MAAM,CAAC;IAC5B;;;;;;;;OAQG;IACH,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,mBAAmB,GAAG,MAAM,CAyBvE"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ALI-835: the line a human reads at the end of `align import sessions`, and the counts the
|
|
3
|
+
* funnel reports.
|
|
4
|
+
*
|
|
5
|
+
* The line is the product moment; the ping is the measurement. They are built from ONE object
|
|
6
|
+
* here so the two can never disagree - a summary saying 41 beside a ping saying 40 would make
|
|
7
|
+
* both unusable, and nothing downstream could tell which was wrong.
|
|
8
|
+
*
|
|
9
|
+
* The demo beat this exists for (Madhuri, 2026-08-25): run the import on the prospect's own
|
|
10
|
+
* repo, read the line aloud, ask who in the room knew.
|
|
11
|
+
*/
|
|
12
|
+
/**
|
|
13
|
+
* The summary line.
|
|
14
|
+
*
|
|
15
|
+
* Renders honestly at zero rather than crashing or printing a line about nothing: "Found 0
|
|
16
|
+
* decisions in 3 sessions" is a different sentence from "Found 0 decisions across 0 sessions",
|
|
17
|
+
* and both are different from an exception. Singular and plural are handled for every count,
|
|
18
|
+
* because "1 sessions" in a demo is the kind of detail that costs more attention than it saves.
|
|
19
|
+
*/
|
|
20
|
+
export function renderImportSummary(counts) {
|
|
21
|
+
const { sessionsScanned, candidatesFound, candidatesConfirmed, ratified } = counts;
|
|
22
|
+
const sessions = `${sessionsScanned} session${sessionsScanned === 1 ? '' : 's'}`;
|
|
23
|
+
if (candidatesFound === 0) {
|
|
24
|
+
// The ticket's own wording for the empty case. A run that found nothing is a real result,
|
|
25
|
+
// not a failure, and it must not read like one.
|
|
26
|
+
return `Found 0 decisions in ${sessions}.`;
|
|
27
|
+
}
|
|
28
|
+
const decisions = `${candidatesFound} decision${candidatesFound === 1 ? '' : 's'}`;
|
|
29
|
+
const parts = [`Found ${decisions} across ${sessions}.`];
|
|
30
|
+
// Every candidate here came from an agent's own session, so "made by an agent" is the whole
|
|
31
|
+
// found set by construction rather than a second measurement. Stated as its own sentence
|
|
32
|
+
// because it is the one a prospect reacts to.
|
|
33
|
+
parts.push(`${candidatesFound} ${candidatesFound === 1 ? 'was' : 'were'} made by an agent.`);
|
|
34
|
+
parts.push(`${ratified} ${ratified === 1 ? 'has' : 'have'} been ratified.`);
|
|
35
|
+
if (candidatesConfirmed !== candidatesFound) {
|
|
36
|
+
// Only when it differs, so the common "reviewed them all" run keeps a short line.
|
|
37
|
+
parts.push(`${candidatesConfirmed} confirmed this run.`);
|
|
38
|
+
}
|
|
39
|
+
return parts.join(' ');
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=import-summary.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"import-summary.js","sourceRoot":"","sources":["../../../src/lib/sessions/import-summary.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAqBH;;;;;;;GAOG;AACH,MAAM,UAAU,mBAAmB,CAAC,MAA2B;IAC7D,MAAM,EAAE,eAAe,EAAE,eAAe,EAAE,mBAAmB,EAAE,QAAQ,EAAE,GAAG,MAAM,CAAC;IACnF,MAAM,QAAQ,GAAG,GAAG,eAAe,WAAW,eAAe,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC;IAEjF,IAAI,eAAe,KAAK,CAAC,EAAE,CAAC;QAC1B,0FAA0F;QAC1F,gDAAgD;QAChD,OAAO,wBAAwB,QAAQ,GAAG,CAAC;IAC7C,CAAC;IAED,MAAM,SAAS,GAAG,GAAG,eAAe,YAAY,eAAe,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC;IACnF,MAAM,KAAK,GAAG,CAAC,SAAS,SAAS,WAAW,QAAQ,GAAG,CAAC,CAAC;IAEzD,4FAA4F;IAC5F,yFAAyF;IACzF,8CAA8C;IAC9C,KAAK,CAAC,IAAI,CAAC,GAAG,eAAe,IAAI,eAAe,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,oBAAoB,CAAC,CAAC;IAC7F,KAAK,CAAC,IAAI,CAAC,GAAG,QAAQ,IAAI,QAAQ,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,iBAAiB,CAAC,CAAC;IAE5E,IAAI,mBAAmB,KAAK,eAAe,EAAE,CAAC;QAC5C,kFAAkF;QAClF,KAAK,CAAC,IAAI,CAAC,GAAG,mBAAmB,sBAAsB,CAAC,CAAC;IAC3D,CAAC;IAED,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACzB,CAAC"}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/** The four kinds Claude Code records, verbatim from the documentation. */
|
|
2
|
+
export declare const MEMORY_TYPES: readonly ["user", "feedback", "project", "reference"];
|
|
3
|
+
export type MemoryType = (typeof MEMORY_TYPES)[number];
|
|
4
|
+
/**
|
|
5
|
+
* The two kinds that are decision-shaped.
|
|
6
|
+
*
|
|
7
|
+
* `project` is "ongoing work, deadlines, and decisions that Claude can't derive from the code
|
|
8
|
+
* or git history" and `feedback` is "corrections you give Claude and approaches you confirm" -
|
|
9
|
+
* both are things somebody decided. `user` is a person's role and working preferences, and
|
|
10
|
+
* `reference` is where to find a dashboard. Neither is a decision, and importing them would
|
|
11
|
+
* put personal notes into a decision graph.
|
|
12
|
+
*/
|
|
13
|
+
export declare const DECISION_MEMORY_TYPES: readonly MemoryType[];
|
|
14
|
+
/** The index file, never a memory in its own right. */
|
|
15
|
+
export declare const MEMORY_INDEX_FILENAME = "MEMORY.md";
|
|
16
|
+
export interface MemoryFile {
|
|
17
|
+
filePath: string;
|
|
18
|
+
/** Null when the file carries no frontmatter, or carries frontmatter with no `type`, or a
|
|
19
|
+
* `type` outside the four documented values. All three are "cannot classify", which is a
|
|
20
|
+
* different fact from "classified as something we skip" - see extractMemoryDecisions. */
|
|
21
|
+
type: MemoryType | null;
|
|
22
|
+
/** ISO-8601 from the `modified` field, or null when absent (the field only appears on files
|
|
23
|
+
* Claude has written since v2.1.214, and never on a file that has no frontmatter). */
|
|
24
|
+
modified: string | null;
|
|
25
|
+
/** Every other scalar frontmatter key, unparsed. Nothing depends on these; they exist so a
|
|
26
|
+
* later ticket can confirm `description`/`originSessionId` from real data without a reparse. */
|
|
27
|
+
extra: Record<string, string>;
|
|
28
|
+
/** The markdown below the frontmatter, trimmed. */
|
|
29
|
+
body: string;
|
|
30
|
+
}
|
|
31
|
+
export interface MemoryDecisionCandidate {
|
|
32
|
+
filePath: string;
|
|
33
|
+
type: MemoryType;
|
|
34
|
+
/** The file's first markdown heading, else its filename stem with separators as spaces. */
|
|
35
|
+
title: string;
|
|
36
|
+
body: string;
|
|
37
|
+
/** ISO-8601 or null, from `modified`. */
|
|
38
|
+
timestamp: string | null;
|
|
39
|
+
/** The memory directory this file came from, used to build a stable source_url. */
|
|
40
|
+
memoryDir: string;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Where this project's memory directory is, if anywhere.
|
|
44
|
+
*
|
|
45
|
+
* Resolution order, and the reason for it:
|
|
46
|
+
*
|
|
47
|
+
* 1. `autoMemoryDirectory` from `~/.claude/settings.json`. Reading it matters because the
|
|
48
|
+
* failure direction without it is silent: a user who relocated the directory would get an
|
|
49
|
+
* empty list, which is indistinguishable from "no memories yet".
|
|
50
|
+
* 2. Otherwise, the `memory/` sibling of this project's Claude Code session files. The docs
|
|
51
|
+
* say `<project>` is derived from the git repository, and the exact slug encoding is not
|
|
52
|
+
* documented - so rather than guess at it, this reuses the cwd matching ALI-808 already
|
|
53
|
+
* proved (each session file records its own `cwd`) and takes the directory those files
|
|
54
|
+
* sit in. That is correct for worktrees and subdirectories for free, because they share
|
|
55
|
+
* one project directory.
|
|
56
|
+
*
|
|
57
|
+
* Returns [] when the agent has never run here, which is the normal case and not an error.
|
|
58
|
+
*/
|
|
59
|
+
export declare function locateMemoryDirs(cwd: string): string[];
|
|
60
|
+
/** Memory topic files for this project, newest first. `MEMORY.md` is excluded: it is an index
|
|
61
|
+
* of the others, so importing it would duplicate every memory as one more candidate. */
|
|
62
|
+
export declare function locateMemoryFiles(cwd: string): string[];
|
|
63
|
+
/**
|
|
64
|
+
* Parses one memory file.
|
|
65
|
+
*
|
|
66
|
+
* The frontmatter reader deliberately handles only `key: value` scalars on one line, which is
|
|
67
|
+
* every field the documentation describes. Anything else - a nested map, a list, a block
|
|
68
|
+
* scalar - is left in `extra` as its raw text if it is a simple scalar and otherwise ignored,
|
|
69
|
+
* rather than half-understood. js-yaml is a devDependency here, not a runtime one, so pulling
|
|
70
|
+
* a YAML parser into shipped CLI code would be a new dependency for two scalar fields.
|
|
71
|
+
*
|
|
72
|
+
* Returns null only for an unreadable file.
|
|
73
|
+
*/
|
|
74
|
+
export declare function parseMemoryFile(filePath: string): MemoryFile | null;
|
|
75
|
+
/**
|
|
76
|
+
* The decision-shaped memories among these files.
|
|
77
|
+
*
|
|
78
|
+
* Three separate reasons a file is dropped, all deliberate:
|
|
79
|
+
* - `type` is `user` or `reference`: classified, and not a decision.
|
|
80
|
+
* - `type` is absent or unrecognised: NOT classified. Importing it would be a guess about
|
|
81
|
+
* personal notes, so it is skipped rather than defaulted into a decision.
|
|
82
|
+
* - the body is empty: nothing to review.
|
|
83
|
+
*/
|
|
84
|
+
export declare function extractMemoryDecisions(filePaths: string[]): MemoryDecisionCandidate[];
|
|
85
|
+
//# sourceMappingURL=memory-files.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memory-files.d.ts","sourceRoot":"","sources":["../../../src/lib/sessions/memory-files.ts"],"names":[],"mappings":"AA4CA,2EAA2E;AAC3E,eAAO,MAAM,YAAY,uDAAwD,CAAC;AAClF,MAAM,MAAM,UAAU,GAAG,CAAC,OAAO,YAAY,CAAC,CAAC,MAAM,CAAC,CAAC;AAEvD;;;;;;;;GAQG;AACH,eAAO,MAAM,qBAAqB,EAAE,SAAS,UAAU,EAA4B,CAAC;AAEpF,uDAAuD;AACvD,eAAO,MAAM,qBAAqB,cAAc,CAAC;AAEjD,MAAM,WAAW,UAAU;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB;;8FAE0F;IAC1F,IAAI,EAAE,UAAU,GAAG,IAAI,CAAC;IACxB;2FACuF;IACvF,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB;qGACiG;IACjG,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC9B,mDAAmD;IACnD,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,uBAAuB;IACtC,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,UAAU,CAAC;IACjB,2FAA2F;IAC3F,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,yCAAyC;IACzC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,mFAAmF;IACnF,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,CAQtD;AAED;yFACyF;AACzF,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,CAQvD;AAwBD;;;;;;;;;;GAUG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI,CAmBnE;AAiDD;;;;;;;;GAQG;AACH,wBAAgB,sBAAsB,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,uBAAuB,EAAE,CAyBrF"}
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ALI-810: Claude Code's own auto-memory as a second, already-curated decision source.
|
|
3
|
+
*
|
|
4
|
+
* ALI-808 mines raw transcripts. This reads the notes the harness already decided were worth
|
|
5
|
+
* keeping: `~/.claude/projects/<project>/memory/*.md`, one fact per file, with a `type` in
|
|
6
|
+
* frontmatter. Higher precision per file and far cheaper to parse - no noise filtering, no
|
|
7
|
+
* repeat-loop exclusion, no plan-file resolution.
|
|
8
|
+
*
|
|
9
|
+
* ## What is verified, and what is not
|
|
10
|
+
*
|
|
11
|
+
* There is no captured memory-file fixture, because this environment has no memory directory
|
|
12
|
+
* at all (checked: `find ~/.claude -type d -name memory` is empty while `~/.claude/projects`
|
|
13
|
+
* exists). Under ALI-808's own gate - "the gate is the fixture, not the agent name" - that
|
|
14
|
+
* would normally mean shipping `locate` and refusing to parse, the way `gemini-cli` and
|
|
15
|
+
* `cursor` do.
|
|
16
|
+
*
|
|
17
|
+
* The difference here is that the format is DOCUMENTED by its producer rather than reverse
|
|
18
|
+
* engineered, so the fixtures are built from Anthropic's own published description rather
|
|
19
|
+
* than from a guess (https://code.claude.com/docs/en/memory, read 2026-09-09). Everything
|
|
20
|
+
* this module relies on is quoted from that page:
|
|
21
|
+
*
|
|
22
|
+
* - the directory is `~/.claude/projects/<project>/memory/`, `<project>` derived from the
|
|
23
|
+
* git repository, so all worktrees and subdirectories of one repo share it;
|
|
24
|
+
* - it holds a `MEMORY.md` index plus one topic file per memory, with arbitrary names;
|
|
25
|
+
* - Claude records the kind in a `type` frontmatter field with exactly four values:
|
|
26
|
+
* `user`, `feedback`, `project`, `reference`;
|
|
27
|
+
* - a `modified` frontmatter field carries an ISO-8601 write time;
|
|
28
|
+
* - "Claude Code never adds frontmatter to a file that has none", so a memory file may
|
|
29
|
+
* legitimately carry no frontmatter at all;
|
|
30
|
+
* - `autoMemoryDirectory` in settings.json relocates the directory.
|
|
31
|
+
*
|
|
32
|
+
* **The ALI-810 ticket also names `description` and `originSessionId` frontmatter fields.
|
|
33
|
+
* The documentation describes neither.** They may well exist - the ticket was written from a
|
|
34
|
+
* real machine and this one has no memory directory to check - but nothing here depends on
|
|
35
|
+
* them, because a field this module cannot confirm is a field it must not require. If they
|
|
36
|
+
* turn out to be real, `parseMemoryFile` already returns them under `extra` and a follow-up
|
|
37
|
+
* can promote them without touching any caller.
|
|
38
|
+
*/
|
|
39
|
+
import { readFileSync } from 'node:fs';
|
|
40
|
+
import { homedir } from 'node:os';
|
|
41
|
+
import { basename, dirname, join } from 'node:path';
|
|
42
|
+
import { findFilesRecursive, sortByMtimeDesc } from './fs-scan.js';
|
|
43
|
+
import { claudeCodeAdapter } from './adapters/claude-code.js';
|
|
44
|
+
/** The four kinds Claude Code records, verbatim from the documentation. */
|
|
45
|
+
export const MEMORY_TYPES = ['user', 'feedback', 'project', 'reference'];
|
|
46
|
+
/**
|
|
47
|
+
* The two kinds that are decision-shaped.
|
|
48
|
+
*
|
|
49
|
+
* `project` is "ongoing work, deadlines, and decisions that Claude can't derive from the code
|
|
50
|
+
* or git history" and `feedback` is "corrections you give Claude and approaches you confirm" -
|
|
51
|
+
* both are things somebody decided. `user` is a person's role and working preferences, and
|
|
52
|
+
* `reference` is where to find a dashboard. Neither is a decision, and importing them would
|
|
53
|
+
* put personal notes into a decision graph.
|
|
54
|
+
*/
|
|
55
|
+
export const DECISION_MEMORY_TYPES = ['project', 'feedback'];
|
|
56
|
+
/** The index file, never a memory in its own right. */
|
|
57
|
+
export const MEMORY_INDEX_FILENAME = 'MEMORY.md';
|
|
58
|
+
/**
|
|
59
|
+
* Where this project's memory directory is, if anywhere.
|
|
60
|
+
*
|
|
61
|
+
* Resolution order, and the reason for it:
|
|
62
|
+
*
|
|
63
|
+
* 1. `autoMemoryDirectory` from `~/.claude/settings.json`. Reading it matters because the
|
|
64
|
+
* failure direction without it is silent: a user who relocated the directory would get an
|
|
65
|
+
* empty list, which is indistinguishable from "no memories yet".
|
|
66
|
+
* 2. Otherwise, the `memory/` sibling of this project's Claude Code session files. The docs
|
|
67
|
+
* say `<project>` is derived from the git repository, and the exact slug encoding is not
|
|
68
|
+
* documented - so rather than guess at it, this reuses the cwd matching ALI-808 already
|
|
69
|
+
* proved (each session file records its own `cwd`) and takes the directory those files
|
|
70
|
+
* sit in. That is correct for worktrees and subdirectories for free, because they share
|
|
71
|
+
* one project directory.
|
|
72
|
+
*
|
|
73
|
+
* Returns [] when the agent has never run here, which is the normal case and not an error.
|
|
74
|
+
*/
|
|
75
|
+
export function locateMemoryDirs(cwd) {
|
|
76
|
+
const configured = readAutoMemoryDirectory();
|
|
77
|
+
if (configured)
|
|
78
|
+
return [configured];
|
|
79
|
+
const sessionFiles = claudeCodeAdapter.locateSessionFiles(cwd);
|
|
80
|
+
const dirs = new Set();
|
|
81
|
+
for (const file of sessionFiles)
|
|
82
|
+
dirs.add(join(dirname(file), 'memory'));
|
|
83
|
+
return [...dirs];
|
|
84
|
+
}
|
|
85
|
+
/** Memory topic files for this project, newest first. `MEMORY.md` is excluded: it is an index
|
|
86
|
+
* of the others, so importing it would duplicate every memory as one more candidate. */
|
|
87
|
+
export function locateMemoryFiles(cwd) {
|
|
88
|
+
const found = [];
|
|
89
|
+
for (const dir of locateMemoryDirs(cwd)) {
|
|
90
|
+
for (const file of findFilesRecursive(dir, /\.md$/)) {
|
|
91
|
+
if (basename(file) !== MEMORY_INDEX_FILENAME)
|
|
92
|
+
found.push(file);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
return sortByMtimeDesc(found);
|
|
96
|
+
}
|
|
97
|
+
function readAutoMemoryDirectory() {
|
|
98
|
+
let raw;
|
|
99
|
+
try {
|
|
100
|
+
raw = readFileSync(join(homedir(), '.claude', 'settings.json'), 'utf8');
|
|
101
|
+
}
|
|
102
|
+
catch {
|
|
103
|
+
return null;
|
|
104
|
+
}
|
|
105
|
+
let parsed;
|
|
106
|
+
try {
|
|
107
|
+
parsed = JSON.parse(raw);
|
|
108
|
+
}
|
|
109
|
+
catch {
|
|
110
|
+
// A settings file we cannot parse is not ours to repair, and guessing past it would be
|
|
111
|
+
// worse than falling back to the documented default location.
|
|
112
|
+
return null;
|
|
113
|
+
}
|
|
114
|
+
const value = parsed?.['autoMemoryDirectory'];
|
|
115
|
+
if (typeof value !== 'string' || value.length === 0)
|
|
116
|
+
return null;
|
|
117
|
+
// Documented constraint: "must be an absolute path or start with ~/".
|
|
118
|
+
if (value.startsWith('~/'))
|
|
119
|
+
return join(homedir(), value.slice(2));
|
|
120
|
+
return value;
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Parses one memory file.
|
|
124
|
+
*
|
|
125
|
+
* The frontmatter reader deliberately handles only `key: value` scalars on one line, which is
|
|
126
|
+
* every field the documentation describes. Anything else - a nested map, a list, a block
|
|
127
|
+
* scalar - is left in `extra` as its raw text if it is a simple scalar and otherwise ignored,
|
|
128
|
+
* rather than half-understood. js-yaml is a devDependency here, not a runtime one, so pulling
|
|
129
|
+
* a YAML parser into shipped CLI code would be a new dependency for two scalar fields.
|
|
130
|
+
*
|
|
131
|
+
* Returns null only for an unreadable file.
|
|
132
|
+
*/
|
|
133
|
+
export function parseMemoryFile(filePath) {
|
|
134
|
+
let text;
|
|
135
|
+
try {
|
|
136
|
+
text = readFileSync(filePath, 'utf8');
|
|
137
|
+
}
|
|
138
|
+
catch {
|
|
139
|
+
return null;
|
|
140
|
+
}
|
|
141
|
+
const { frontmatter, body } = splitFrontmatter(text);
|
|
142
|
+
const rawType = frontmatter['type'];
|
|
143
|
+
const type = isMemoryType(rawType) ? rawType : null;
|
|
144
|
+
const modified = frontmatter['modified'] ?? null;
|
|
145
|
+
const extra = {};
|
|
146
|
+
for (const [k, v] of Object.entries(frontmatter)) {
|
|
147
|
+
if (k !== 'type' && k !== 'modified')
|
|
148
|
+
extra[k] = v;
|
|
149
|
+
}
|
|
150
|
+
return { filePath, type, modified, extra, body };
|
|
151
|
+
}
|
|
152
|
+
function isMemoryType(value) {
|
|
153
|
+
return value !== undefined && MEMORY_TYPES.includes(value);
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Splits `---\n...\n---\n` off the front. A file with no frontmatter is the documented normal
|
|
157
|
+
* case, not a malformed one, so it yields an empty map and the whole text as the body.
|
|
158
|
+
*/
|
|
159
|
+
function splitFrontmatter(text) {
|
|
160
|
+
const normalized = text.replace(/\r\n/g, '\n');
|
|
161
|
+
if (!normalized.startsWith('---\n'))
|
|
162
|
+
return { frontmatter: {}, body: normalized.trim() };
|
|
163
|
+
const end = normalized.indexOf('\n---', 3);
|
|
164
|
+
if (end === -1) {
|
|
165
|
+
// An opening fence with no closing one is not frontmatter. Treating the rest of the file
|
|
166
|
+
// as key/value would silently swallow the content.
|
|
167
|
+
return { frontmatter: {}, body: normalized.trim() };
|
|
168
|
+
}
|
|
169
|
+
const block = normalized.slice(4, end);
|
|
170
|
+
const after = normalized.slice(end + 4);
|
|
171
|
+
const frontmatter = {};
|
|
172
|
+
for (const line of block.split('\n')) {
|
|
173
|
+
const colon = line.indexOf(':');
|
|
174
|
+
if (colon === -1)
|
|
175
|
+
continue;
|
|
176
|
+
const key = line.slice(0, colon).trim();
|
|
177
|
+
let value = line.slice(colon + 1).trim();
|
|
178
|
+
if (!key || !value)
|
|
179
|
+
continue;
|
|
180
|
+
// Strip one layer of matching quotes, which is how an ISO timestamp is often written.
|
|
181
|
+
if ((value.startsWith('"') && value.endsWith('"') && value.length > 1) ||
|
|
182
|
+
(value.startsWith("'") && value.endsWith("'") && value.length > 1)) {
|
|
183
|
+
value = value.slice(1, -1);
|
|
184
|
+
}
|
|
185
|
+
frontmatter[key] = value;
|
|
186
|
+
}
|
|
187
|
+
return { frontmatter, body: after.trim() };
|
|
188
|
+
}
|
|
189
|
+
/** First markdown heading, else the filename stem with `_`/`-` as spaces. */
|
|
190
|
+
function titleFor(file) {
|
|
191
|
+
const heading = file.body.split('\n').find(l => /^#{1,6}\s+\S/.test(l));
|
|
192
|
+
if (heading)
|
|
193
|
+
return heading.replace(/^#{1,6}\s+/, '').trim();
|
|
194
|
+
return basename(file.filePath).replace(/\.md$/, '').replace(/[_-]+/g, ' ').trim();
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* The decision-shaped memories among these files.
|
|
198
|
+
*
|
|
199
|
+
* Three separate reasons a file is dropped, all deliberate:
|
|
200
|
+
* - `type` is `user` or `reference`: classified, and not a decision.
|
|
201
|
+
* - `type` is absent or unrecognised: NOT classified. Importing it would be a guess about
|
|
202
|
+
* personal notes, so it is skipped rather than defaulted into a decision.
|
|
203
|
+
* - the body is empty: nothing to review.
|
|
204
|
+
*/
|
|
205
|
+
export function extractMemoryDecisions(filePaths) {
|
|
206
|
+
const candidates = [];
|
|
207
|
+
for (const filePath of filePaths) {
|
|
208
|
+
const parsed = parseMemoryFile(filePath);
|
|
209
|
+
if (!parsed)
|
|
210
|
+
continue;
|
|
211
|
+
// This null check is RUNTIME-REDUNDANT and kept deliberately. Replacing it with a no-op
|
|
212
|
+
// leaves every test green, because DECISION_MEMORY_TYPES cannot contain null so the next
|
|
213
|
+
// line drops an unclassified file anyway. Deleting it does NOT leave the suite green:
|
|
214
|
+
// `tsc` then reports TS2345 and TS2322, because the narrowing to MemoryType is what lets
|
|
215
|
+
// the next line and the push below compile. The enforcing mechanism is the compiler
|
|
216
|
+
// rather than a test, which is the honest reason it survives a mutation run - so do not
|
|
217
|
+
// remove it as dead code.
|
|
218
|
+
if (parsed.type === null)
|
|
219
|
+
continue;
|
|
220
|
+
if (!DECISION_MEMORY_TYPES.includes(parsed.type))
|
|
221
|
+
continue;
|
|
222
|
+
if (parsed.body.length === 0)
|
|
223
|
+
continue;
|
|
224
|
+
candidates.push({
|
|
225
|
+
filePath,
|
|
226
|
+
type: parsed.type,
|
|
227
|
+
title: titleFor(parsed),
|
|
228
|
+
body: parsed.body,
|
|
229
|
+
timestamp: parsed.modified,
|
|
230
|
+
memoryDir: dirname(filePath),
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
return candidates;
|
|
234
|
+
}
|
|
235
|
+
//# sourceMappingURL=memory-files.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memory-files.js","sourceRoot":"","sources":["../../../src/lib/sessions/memory-files.ts"],"names":[],"mappings":"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"}
|
|
@@ -7,4 +7,15 @@ export declare function parseSessionSourceUrl(url: string): {
|
|
|
7
7
|
sessionId: string;
|
|
8
8
|
messageId: string;
|
|
9
9
|
} | null;
|
|
10
|
+
/**
|
|
11
|
+
* ALI-810: memory files are not sessions, so they get their own scheme rather than being
|
|
12
|
+
* squeezed into `<agent>-session://<sessionId>/<messageId>` with invented ids.
|
|
13
|
+
*
|
|
14
|
+
* Built from the project directory name and the topic file's stem, both of which are stable
|
|
15
|
+
* for a given memory across rewrites - Claude edits a topic file in place rather than making
|
|
16
|
+
* a new one. That stability is the point: the gateway upserts on `(tenant_id, source_url)`,
|
|
17
|
+
* so re-running the import after Claude has revised a memory updates the decision instead of
|
|
18
|
+
* adding a second copy of it.
|
|
19
|
+
*/
|
|
20
|
+
export declare function buildMemorySourceUrl(memoryDir: string, filePath: string): string;
|
|
10
21
|
//# sourceMappingURL=source-url.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"source-url.d.ts","sourceRoot":"","sources":["../../../src/lib/sessions/source-url.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAI5C;6CAC6C;AAC7C,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAEpG;AAED,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,MAAM,GAAG;IAAE,KAAK,EAAE,SAAS,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAWpH"}
|
|
1
|
+
{"version":3,"file":"source-url.d.ts","sourceRoot":"","sources":["../../../src/lib/sessions/source-url.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAI5C;6CAC6C;AAC7C,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAEpG;AAED,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,MAAM,GAAG;IAAE,KAAK,EAAE,SAAS,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAWpH;AAED;;;;;;;;;GASG;AACH,wBAAgB,oBAAoB,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAIhF"}
|
|
@@ -17,4 +17,19 @@ export function parseSessionSourceUrl(url) {
|
|
|
17
17
|
}
|
|
18
18
|
return null;
|
|
19
19
|
}
|
|
20
|
+
/**
|
|
21
|
+
* ALI-810: memory files are not sessions, so they get their own scheme rather than being
|
|
22
|
+
* squeezed into `<agent>-session://<sessionId>/<messageId>` with invented ids.
|
|
23
|
+
*
|
|
24
|
+
* Built from the project directory name and the topic file's stem, both of which are stable
|
|
25
|
+
* for a given memory across rewrites - Claude edits a topic file in place rather than making
|
|
26
|
+
* a new one. That stability is the point: the gateway upserts on `(tenant_id, source_url)`,
|
|
27
|
+
* so re-running the import after Claude has revised a memory updates the decision instead of
|
|
28
|
+
* adding a second copy of it.
|
|
29
|
+
*/
|
|
30
|
+
export function buildMemorySourceUrl(memoryDir, filePath) {
|
|
31
|
+
const project = memoryDir.split(/[\\/]/).filter(Boolean).at(-2) ?? 'unknown-project';
|
|
32
|
+
const topic = (filePath.split(/[\\/]/).pop() ?? 'unknown').replace(/\.md$/, '');
|
|
33
|
+
return `claude-code-memory://${project}/${topic}`;
|
|
34
|
+
}
|
|
20
35
|
//# sourceMappingURL=source-url.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"source-url.js","sourceRoot":"","sources":["../../../src/lib/sessions/source-url.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,GAAyB,CAAC,aAAa,EAAE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,UAAU,EAAE,IAAI,CAAC,CAAC;AAExG;6CAC6C;AAC7C,MAAM,UAAU,qBAAqB,CAAC,KAAgB,EAAE,SAAiB,EAAE,SAAiB;IAC1F,OAAO,GAAG,KAAK,cAAc,SAAS,IAAI,SAAS,EAAE,CAAC;AACxD,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,GAAW;IAC/C,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,MAAM,MAAM,GAAG,GAAG,KAAK,aAAa,CAAC;QACrC,IAAI,GAAG,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;YAC3B,MAAM,IAAI,GAAG,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;YACtC,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;YAChC,IAAI,KAAK,KAAK,CAAC,CAAC;gBAAE,OAAO,IAAI,CAAC;YAC9B,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,EAAE,SAAS,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC,EAAE,CAAC;QACtF,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC"}
|
|
1
|
+
{"version":3,"file":"source-url.js","sourceRoot":"","sources":["../../../src/lib/sessions/source-url.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,GAAyB,CAAC,aAAa,EAAE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,UAAU,EAAE,IAAI,CAAC,CAAC;AAExG;6CAC6C;AAC7C,MAAM,UAAU,qBAAqB,CAAC,KAAgB,EAAE,SAAiB,EAAE,SAAiB;IAC1F,OAAO,GAAG,KAAK,cAAc,SAAS,IAAI,SAAS,EAAE,CAAC;AACxD,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,GAAW;IAC/C,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,MAAM,MAAM,GAAG,GAAG,KAAK,aAAa,CAAC;QACrC,IAAI,GAAG,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;YAC3B,MAAM,IAAI,GAAG,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;YACtC,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;YAChC,IAAI,KAAK,KAAK,CAAC,CAAC;gBAAE,OAAO,IAAI,CAAC;YAC9B,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,EAAE,SAAS,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC,EAAE,CAAC;QACtF,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,oBAAoB,CAAC,SAAiB,EAAE,QAAgB;IACtE,MAAM,OAAO,GAAG,SAAS,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,iBAAiB,CAAC;IACrF,MAAM,KAAK,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,IAAI,SAAS,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;IAChF,OAAO,wBAAwB,OAAO,IAAI,KAAK,EAAE,CAAC;AACpD,CAAC"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { EnvironmentConfig } from './config.js';
|
|
2
|
+
/**
|
|
3
|
+
* ALI-949: the setup wizard's two funnel stages, carried through `runSetup` so bare
|
|
4
|
+
* `align` and `align setup` share one emitter (both run runSetup's body).
|
|
5
|
+
*
|
|
6
|
+
* `started` BUFFERS rather than sends. When a mode branch begins nothing may be sendable
|
|
7
|
+
* on a fresh install: cloud has no token until login, and local mode asks for consent
|
|
8
|
+
* mid-wizard (ALI-794 puts the found-decisions moment before any question, and that order
|
|
9
|
+
* is not negotiable here). So the wizard offers the current env at each checkpoint - the
|
|
10
|
+
* top of the local value phase, after consent, the top of cloud setup, after login - and
|
|
11
|
+
* this object sends at the first offer the emitter reports as sent. Sendability is
|
|
12
|
+
* recordFunnelStage's decision, not repeated here.
|
|
13
|
+
*
|
|
14
|
+
* Within one wizard run, "once" is per IDENTITY rather than once in total. A local-mode
|
|
15
|
+
* ping is keyed on the machine's installId; a cloud ping on the tenant. Nothing joins the
|
|
16
|
+
* two, so a fresh-install user who consents locally and then chooses "sync to the cloud"
|
|
17
|
+
* would otherwise leave `setup_started` under one identity and `setup_completed` under the
|
|
18
|
+
* other (fresh-context review on #279). A later checkpoint on the OTHER transport therefore
|
|
19
|
+
* sends again under its own identity; the same transport never repeats in the run. There is
|
|
20
|
+
* no cross-run memory here: one object is created per `runSetup` call, and a re-run of the
|
|
21
|
+
* wizard is a new setup_started, which is what the funnel wants (the reader counts an
|
|
22
|
+
* install once per stage regardless - `cli_activation_funnel.py`'s countIf(> 0)).
|
|
23
|
+
*
|
|
24
|
+
* What that means for the funnel: in local mode `setup_started` says "started, and got as
|
|
25
|
+
* far as consenting" rather than "typed the command". A user who declines consent is never
|
|
26
|
+
* counted at any stage, which is the consent model, not a gap.
|
|
27
|
+
*
|
|
28
|
+
* Offers are serialised through one promise chain because call sites fire them without
|
|
29
|
+
* awaiting (`void funnel.started(env)` - a slow gateway must not delay the wizard), so two
|
|
30
|
+
* offers can overlap; the second waits for the first's verdict before deciding to send.
|
|
31
|
+
* `completed` queues behind the started chain too (Copilot on #279): a started send still
|
|
32
|
+
* in flight when the wizard finishes must not be overtaken, or the install's two events
|
|
33
|
+
* reach the gateway out of order. By the outro the started send has long settled, so this
|
|
34
|
+
* costs nothing in practice and is the ordering guarantee when it has not.
|
|
35
|
+
*/
|
|
36
|
+
export interface SetupFunnel {
|
|
37
|
+
started(env: EnvironmentConfig): Promise<void>;
|
|
38
|
+
completed(env: EnvironmentConfig): Promise<void>;
|
|
39
|
+
}
|
|
40
|
+
export declare function createSetupFunnel(): SetupFunnel;
|
|
41
|
+
//# sourceMappingURL=setup-funnel.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"setup-funnel.d.ts","sourceRoot":"","sources":["../../src/lib/setup-funnel.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAGrD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,MAAM,WAAW,WAAW;IAC1B,OAAO,CAAC,GAAG,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/C,SAAS,CAAC,GAAG,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAClD;AAMD,wBAAgB,iBAAiB,IAAI,WAAW,CAuB/C"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { recordFunnelStage } from './usage-telemetry.js';
|
|
2
|
+
const transportOf = (env) => (env.mode === 'local-embedded' ? 'anonymous' : 'cloud');
|
|
3
|
+
export function createSetupFunnel() {
|
|
4
|
+
// The transports setup_started has been sent on so far.
|
|
5
|
+
let startedChain = Promise.resolve(new Set());
|
|
6
|
+
let completedChain = Promise.resolve(false);
|
|
7
|
+
return {
|
|
8
|
+
async started(env) {
|
|
9
|
+
startedChain = startedChain.then(async (sentOn) => {
|
|
10
|
+
const transport = transportOf(env);
|
|
11
|
+
if (sentOn.has(transport))
|
|
12
|
+
return sentOn;
|
|
13
|
+
const sent = await recordFunnelStage(env, 'setup_started', 'setup');
|
|
14
|
+
return sent ? new Set([...sentOn, transport]) : sentOn;
|
|
15
|
+
});
|
|
16
|
+
await startedChain;
|
|
17
|
+
},
|
|
18
|
+
async completed(env) {
|
|
19
|
+
// Capture the previous link BEFORE reassigning, or the new chain waits on itself.
|
|
20
|
+
const previous = completedChain;
|
|
21
|
+
completedChain = startedChain
|
|
22
|
+
.then(() => previous)
|
|
23
|
+
.then((sent) => (sent ? true : recordFunnelStage(env, 'setup_completed', 'setup')));
|
|
24
|
+
await completedChain;
|
|
25
|
+
},
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=setup-funnel.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"setup-funnel.js","sourceRoot":"","sources":["../../src/lib/setup-funnel.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AA2CzD,MAAM,WAAW,GAAG,CAAC,GAAsB,EAAa,EAAE,CAAC,CAAC,GAAG,CAAC,IAAI,KAAK,gBAAgB,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;AAEnH,MAAM,UAAU,iBAAiB;IAC/B,wDAAwD;IACxD,IAAI,YAAY,GAAoC,OAAO,CAAC,OAAO,CAAC,IAAI,GAAG,EAAE,CAAC,CAAC;IAC/E,IAAI,cAAc,GAAqB,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IAC9D,OAAO;QACL,KAAK,CAAC,OAAO,CAAC,GAAG;YACf,YAAY,GAAG,YAAY,CAAC,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE;gBAChD,MAAM,SAAS,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC;gBACnC,IAAI,MAAM,CAAC,GAAG,CAAC,SAAS,CAAC;oBAAE,OAAO,MAAM,CAAC;gBACzC,MAAM,IAAI,GAAG,MAAM,iBAAiB,CAAC,GAAG,EAAE,eAAe,EAAE,OAAO,CAAC,CAAC;gBACpE,OAAO,IAAI,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,GAAG,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;YACzD,CAAC,CAAC,CAAC;YACH,MAAM,YAAY,CAAC;QACrB,CAAC;QACD,KAAK,CAAC,SAAS,CAAC,GAAG;YACjB,kFAAkF;YAClF,MAAM,QAAQ,GAAG,cAAc,CAAC;YAChC,cAAc,GAAG,YAAY;iBAC1B,IAAI,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC;iBACpB,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,iBAAiB,CAAC,GAAG,EAAE,iBAAiB,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC;YACtF,MAAM,cAAc,CAAC;QACvB,CAAC;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -3,18 +3,27 @@
|
|
|
3
3
|
* carry every unrelated accessor `createConfigStore()` exposes.
|
|
4
4
|
*/
|
|
5
5
|
export interface TelemetryConsentStore {
|
|
6
|
-
getTelemetryConsent(): 'granted' | 'declined' | undefined;
|
|
7
|
-
setTelemetryConsent(value: 'granted' | 'declined'): void;
|
|
6
|
+
getTelemetryConsent(): 'granted' | 'declined' | 'off' | undefined;
|
|
7
|
+
setTelemetryConsent(value: 'granted' | 'declined' | 'off'): void;
|
|
8
8
|
}
|
|
9
9
|
/**
|
|
10
10
|
* ALI-618 D3: the one-time local-mode consent prompt, shown from `runLocalSetup()`.
|
|
11
11
|
*
|
|
12
|
-
* Never asks twice - a decision already on disk (granted
|
|
13
|
-
* prompts without a TTY on both streams: a piped `setup --local` run
|
|
14
|
-
* cannot answer, and a closed stdin crashes clack's raw-mode init AFTER
|
|
15
|
-
* already succeeded (the align-cli#118 lesson,
|
|
16
|
-
* run leaves consent UNSET rather than
|
|
17
|
-
*
|
|
12
|
+
* Never asks twice - a decision already on disk (granted, declined, or `align telemetry off`)
|
|
13
|
+
* is left alone. Never prompts without a TTY on both streams: a piped `setup --local` run
|
|
14
|
+
* hangs on a prompt it cannot answer, and a closed stdin crashes clack's raw-mode init AFTER
|
|
15
|
+
* the real setup work has already succeeded (the align-cli#118 lesson,
|
|
16
|
+
* `setup-local-non-tty.test.ts`). A non-interactive run leaves consent UNSET rather than
|
|
17
|
+
* implicitly declined - a scripted first run may be a CI smoke test, not a real user's choice,
|
|
18
|
+
* and it can still be asked on a later interactive run.
|
|
19
|
+
*
|
|
20
|
+
* ALI-954: an env var that already turns everything off (`DO_NOT_TRACK=1`, `ALIGN_TELEMETRY=0`)
|
|
21
|
+
* skips the question with a one-line note - asking would imply the answer matters - and
|
|
22
|
+
* leaves the decision unset for the same reason as the non-interactive case.
|
|
23
|
+
*
|
|
24
|
+
* The question is about USAGE (which commands you run). The two anonymous counts the docs
|
|
25
|
+
* describe (install, setup completed) are not what is being asked about here and send either
|
|
26
|
+
* way; `align telemetry off` is what stops those (docs/telemetry.md).
|
|
18
27
|
*
|
|
19
28
|
* Default is No: anything other than an explicit yes - the default answer, or Ctrl-C - leaves
|
|
20
29
|
* telemetry off (D3).
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"telemetry-consent.d.ts","sourceRoot":"","sources":["../../src/lib/telemetry-consent.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"telemetry-consent.d.ts","sourceRoot":"","sources":["../../src/lib/telemetry-consent.ts"],"names":[],"mappings":"AAGA;;;GAGG;AACH,MAAM,WAAW,qBAAqB;IACpC,mBAAmB,IAAI,SAAS,GAAG,UAAU,GAAG,KAAK,GAAG,SAAS,CAAC;IAClE,mBAAmB,CAAC,KAAK,EAAE,SAAS,GAAG,UAAU,GAAG,KAAK,GAAG,IAAI,CAAC;CAClE;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAsB,4BAA4B,CAChD,MAAM,EAAE,qBAAqB,EAC7B,WAAW,EAAE,OAAO,GACnB,OAAO,CAAC,IAAI,CAAC,CAkBf"}
|