wave-agent-sdk 0.15.8 → 0.16.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/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/managers/aiManager.d.ts.map +1 -1
- package/dist/managers/aiManager.js +24 -0
- package/dist/managers/hookManager.d.ts +1 -1
- package/dist/managers/hookManager.d.ts.map +1 -1
- package/dist/managers/slashCommandManager.d.ts +1 -0
- package/dist/managers/slashCommandManager.d.ts.map +1 -1
- package/dist/managers/slashCommandManager.js +40 -0
- package/dist/services/authService.d.ts +28 -0
- package/dist/services/authService.d.ts.map +1 -0
- package/dist/services/authService.js +175 -0
- package/dist/services/configurationService.d.ts +5 -1
- package/dist/services/configurationService.d.ts.map +1 -1
- package/dist/services/configurationService.js +37 -1
- package/dist/types/auth.d.ts +4 -0
- package/dist/types/auth.d.ts.map +1 -0
- package/dist/types/auth.js +1 -0
- package/dist/types/hooks.d.ts +2 -2
- package/dist/types/hooks.d.ts.map +1 -1
- package/dist/types/index.d.ts +1 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +1 -0
- package/package.json +1 -1
- package/src/index.ts +1 -0
- package/src/managers/aiManager.ts +34 -0
- package/src/managers/hookManager.ts +1 -1
- package/src/managers/slashCommandManager.ts +59 -0
- package/src/services/authService.ts +234 -0
- package/src/services/configurationService.ts +43 -1
- package/src/types/auth.ts +3 -0
- package/src/types/hooks.ts +2 -2
- package/src/types/index.ts +1 -0
package/dist/index.d.ts
CHANGED
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,cAAc,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,cAAc,mBAAmB,CAAC;AAClC,cAAc,2BAA2B,CAAC;AAG1C,cAAc,sBAAsB,CAAC;AAGrC,cAAc,YAAY,CAAC;AAC3B,cAAc,kBAAkB,CAAC;AACjC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,4BAA4B,CAAC;AAG3C,cAAc,uBAAuB,CAAC;AACtC,cAAc,kCAAkC,CAAC;AACjD,cAAc,uBAAuB,CAAC;AACtC,cAAc,yBAAyB,CAAC;AACxC,cAAc,qBAAqB,CAAC;AACpC,cAAc,8BAA8B,CAAC;AAC7C,cAAc,4BAA4B,CAAC;AAC3C,cAAc,iBAAiB,CAAC;AAChC,cAAc,0BAA0B,CAAC;AACzC,cAAc,wBAAwB,CAAC;AACvC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,wBAAwB,CAAC;AACvC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,qBAAqB,CAAC;AACpC,cAAc,0BAA0B,CAAC;AACzC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,kBAAkB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"aiManager.d.ts","sourceRoot":"","sources":["../../src/managers/aiManager.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EACV,aAAa,EACb,WAAW,EACX,KAAK,EAGN,MAAM,mBAAmB,CAAC;AAY3B,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAclD,MAAM,WAAW,kBAAkB;IACjC,uBAAuB,CAAC,EAAE,CAAC,YAAY,EAAE,OAAO,KAAK,IAAI,CAAC;IAC1D,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;CACvC;AAED,MAAM,WAAW,gBAAgB;IAC/B,SAAS,CAAC,EAAE,kBAAkB,CAAC;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,uEAAuE;IACvE,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,kDAAkD;IAClD,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,6FAA6F;IAC7F,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,qBAAa,SAAS;IAgBlB,OAAO,CAAC,SAAS;IAfZ,SAAS,EAAE,OAAO,CAAS;IAClC,OAAO,CAAC,eAAe,CAAgC;IACvD,eAAe,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;IAC7C,OAAO,CAAC,mBAAmB,CAAgC;IAC3D,OAAO,CAAC,YAAY,CAAC,CAAS;IAC9B,OAAO,CAAC,YAAY,CAAC,CAAS;IAC9B,OAAO,CAAC,MAAM,CAAU;IACxB,OAAO,CAAC,aAAa,CAAC,CAAS;IAC/B,OAAO,CAAC,6BAA6B,CAAa;IAClD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAS;IACnC,sEAAsE;IACtE,OAAO,CAAC,eAAe,CAAqB;gBAIlC,SAAS,EAAE,SAAS,EAC5B,OAAO,EAAE,gBAAgB;IAU3B,OAAO,KAAK,WAAW,GAEtB;IAED,OAAO,KAAK,cAAc,GAEzB;IAED,OAAO,KAAK,aAAa,GAIxB;IAED,OAAO,KAAK,WAAW,GAItB;IAED,OAAO,KAAK,qBAAqB,GAEhC;IAED,OAAO,KAAK,WAAW,GAEtB;IAED,OAAO,KAAK,gBAAgB,GAM3B;IAED,OAAO,KAAK,iBAAiB,GAE5B;IAED,OAAO,KAAK,oBAAoB,GAE/B;IAGM,gBAAgB,IAAI,aAAa;IAIjC,cAAc,IAAI,WAAW;IA6B7B,iBAAiB,IAAI,MAAM;IAI3B,WAAW,IAAI,MAAM,GAAG,SAAS;IAIjC,oBAAoB,IAAI,OAAO;IAI/B,UAAU,IAAI,MAAM;IAI3B;;;OAGG;IACI,UAAU,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI;IAK3C,OAAO,CAAC,YAAY,CAAkB;IACtC,OAAO,CAAC,SAAS,CAAqB;IAEtC;;OAEG;IACH,OAAO,CAAC,sBAAsB;IAgBvB,YAAY,CAAC,SAAS,EAAE,OAAO,GAAG,IAAI;IAUtC,cAAc,IAAI,IAAI;IAuB7B,OAAO,CAAC,qBAAqB;YAsBf,6BAA6B;
|
|
1
|
+
{"version":3,"file":"aiManager.d.ts","sourceRoot":"","sources":["../../src/managers/aiManager.ts"],"names":[],"mappings":"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"}
|
|
@@ -340,6 +340,30 @@ export class AIManager {
|
|
|
340
340
|
afterTokens: "1",
|
|
341
341
|
model: this.getModelConfig().fastModel,
|
|
342
342
|
}).catch(() => { });
|
|
343
|
+
// Run SessionStart hooks after compaction to restore context
|
|
344
|
+
if (this.hookManager) {
|
|
345
|
+
try {
|
|
346
|
+
const newSessionId = this.messageManager.getSessionId();
|
|
347
|
+
const sessionStartResult = await this.hookManager.executeSessionStartHooks("compact", newSessionId, this.messageManager.getTranscriptPath(), this.subagentType);
|
|
348
|
+
// Inject additionalContext as a meta user message
|
|
349
|
+
if (sessionStartResult.additionalContext) {
|
|
350
|
+
this.messageManager.addUserMessage({
|
|
351
|
+
content: `<system-reminder>\nSessionStart hook additional context: ${sessionStartResult.additionalContext}\n</system-reminder>`,
|
|
352
|
+
isMeta: true,
|
|
353
|
+
});
|
|
354
|
+
}
|
|
355
|
+
// Inject initialUserMessage as a meta user message
|
|
356
|
+
if (sessionStartResult.initialUserMessage) {
|
|
357
|
+
this.messageManager.addUserMessage({
|
|
358
|
+
content: sessionStartResult.initialUserMessage,
|
|
359
|
+
isMeta: true,
|
|
360
|
+
});
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
catch (error) {
|
|
364
|
+
logger?.warn(`SessionStart hooks on compact failed: ${error.message}`);
|
|
365
|
+
}
|
|
366
|
+
}
|
|
343
367
|
}
|
|
344
368
|
catch (compactError) {
|
|
345
369
|
this.consecutiveCompactionFailures++;
|
|
@@ -106,7 +106,7 @@ export declare class HookManager {
|
|
|
106
106
|
* Execute SessionStart hooks during initialization.
|
|
107
107
|
* Collects additionalContext and initialUserMessage from hook stdout.
|
|
108
108
|
*/
|
|
109
|
-
executeSessionStartHooks(source: "startup" | "
|
|
109
|
+
executeSessionStartHooks(source: "startup" | "compact" | "clear", sessionId: string, transcriptPath: string, agentType?: string): Promise<{
|
|
110
110
|
results: HookExecutionResult[];
|
|
111
111
|
additionalContext?: string;
|
|
112
112
|
initialUserMessage?: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hookManager.d.ts","sourceRoot":"","sources":["../../src/managers/hookManager.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EACL,KAAK,SAAS,EAEd,KAAK,oBAAoB,EACzB,KAAK,4BAA4B,EACjC,KAAK,mBAAmB,EACxB,KAAK,oBAAoB,EACzB,KAAK,gBAAgB,EAItB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,KAAK,EACV,iBAAiB,EACjB,wBAAwB,EACzB,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAGtD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAC1D,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAIlD,qBAAa,WAAW;IAMpB,OAAO,CAAC,SAAS;IALnB,OAAO,CAAC,aAAa,CAAuC;IAC5D,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAc;IACtC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;gBAGvB,SAAS,EAAE,SAAS,EAC5B,OAAO,EAAE,MAAM,EACf,OAAO,GAAE,WAA+B;IAM1C;;;OAGG;IACH,iBAAiB,CACf,SAAS,CAAC,EAAE,wBAAwB,EACpC,YAAY,CAAC,EAAE,wBAAwB,GACtC,IAAI;IAyBP;;;OAGG;IACH,+BAA+B,CAAC,UAAU,EAAE,iBAAiB,GAAG,IAAI,GAAG,IAAI;IA6B3E;;OAEG;IACG,YAAY,CAChB,KAAK,EAAE,SAAS,EAChB,OAAO,EAAE,oBAAoB,GAAG,4BAA4B,GAC3D,OAAO,CAAC,mBAAmB,EAAE,CAAC;IAkHjC;;;OAGG;IACH,kBAAkB,CAChB,KAAK,EAAE,SAAS,EAChB,OAAO,EAAE,mBAAmB,EAAE,EAC9B,cAAc,CAAC,EAAE,cAAc,EAC/B,MAAM,CAAC,EAAE,MAAM,EACf,cAAc,CAAC,EAAE,MAAM,GACtB;QACD,WAAW,EAAE,OAAO,CAAC;QACrB,YAAY,CAAC,EAAE,MAAM,CAAC;KACvB;IA2CD;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAiBzB;;OAEG;IACH,OAAO,CAAC,mBAAmB;IA0F3B;;OAEG;IACH,OAAO,CAAC,sBAAsB;IAQ9B;;OAEG;IACH,QAAQ,CAAC,KAAK,EAAE,SAAS,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO;IAWtD;;OAEG;IACH,qBAAqB,CAAC,MAAM,EAAE,iBAAiB,GAAG,oBAAoB;IA8DtE;;OAEG;IACH,OAAO,CAAC,4BAA4B;IAyCpC;;OAEG;IACH,gBAAgB,IAAI,wBAAwB,GAAG,SAAS;IAOxD;;OAEG;IACH,kBAAkB,IAAI,IAAI;IAI1B;;OAEG;IACH,OAAO,CAAC,wBAAwB;IA6DhC;;OAEG;IACH,OAAO,CAAC,wBAAwB;IA8BhC;;OAEG;IACH,OAAO,CAAC,uBAAuB;IAa/B;;OAEG;IACH,OAAO,CAAC,aAAa;IAwCrB;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAmD3B;;OAEG;IACH,qBAAqB,IAAI;QACvB,WAAW,EAAE,MAAM,CAAC;QACpB,YAAY,EAAE,MAAM,CAAC;QACrB,aAAa,EAAE,MAAM,CAAC;QACtB,cAAc,EAAE,MAAM,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;KAC3C;IAwDD;;OAEG;IACH,mBAAmB,CACjB,UAAU,EAAE,MAAM,EAClB,KAAK,EAAE,wBAAwB,GAC9B,IAAI;IAkBP;;;OAGG;IACG,wBAAwB,CAC5B,MAAM,EAAE,SAAS,GAAG,
|
|
1
|
+
{"version":3,"file":"hookManager.d.ts","sourceRoot":"","sources":["../../src/managers/hookManager.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"slashCommandManager.d.ts","sourceRoot":"","sources":["../../src/managers/slashCommandManager.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,YAAY,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAQ1E,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAWlD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"slashCommandManager.d.ts","sourceRoot":"","sources":["../../src/managers/slashCommandManager.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,YAAY,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAQ1E,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAWlD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAOxD,MAAM,WAAW,0BAA0B;IACzC,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,qBAAa,mBAAmB;IAQ5B,OAAO,CAAC,SAAS;IAPnB,OAAO,CAAC,QAAQ,CAAmC;IACnD,OAAO,CAAC,cAAc,CAAyC;IAC/D,OAAO,CAAC,eAAe,CAAqB;IAC5C,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,6BAA6B,CAAgC;gBAG3D,SAAS,EAAE,SAAS,EAC5B,OAAO,EAAE,0BAA0B;IAK9B,UAAU,IAAI,IAAI;IAazB,OAAO,KAAK,cAAc,GAEzB;IAED,OAAO,KAAK,SAAS,GAEpB;IAED,OAAO,KAAK,qBAAqB,GAEhC;IAED,OAAO,KAAK,WAAW,GAEtB;IAED,OAAO,KAAK,YAAY,GAEvB;IAED,OAAO,KAAK,eAAe,GAE1B;IAED,OAAO,KAAK,aAAa,GAExB;IAED,OAAO,KAAK,WAAW,GAEtB;IAED,OAAO,CAAC,yBAAyB;IAqEjC;;OAEG;IACH,OAAO,CAAC,kBAAkB;IA2C1B;;OAEG;IACI,qBAAqB,CAAC,MAAM,EAAE,aAAa,EAAE,GAAG,IAAI;IAmM3D;;OAEG;IACI,sBAAsB,CAC3B,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,kBAAkB,EAAE,GAC7B,IAAI;IA0CP;;OAEG;IACI,oBAAoB,IAAI,IAAI;IAWnC;;OAEG;IACI,eAAe,CAAC,OAAO,EAAE,YAAY,GAAG,IAAI;IAInD;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAIzB;;OAEG;IACI,WAAW,IAAI,YAAY,EAAE;IAIpC;;OAEG;IACI,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS;IAI9D;;OAEG;IACU,cAAc,CACzB,SAAS,EAAE,MAAM,EACjB,IAAI,CAAC,EAAE,MAAM,GACZ,OAAO,CAAC,OAAO,CAAC;IA2BnB;;;OAGG;IACI,4BAA4B,CAAC,KAAK,EAAE,MAAM,GAAG;QAClD,OAAO,EAAE,OAAO,CAAC;QACjB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,IAAI,CAAC,EAAE,MAAM,CAAC;KACf;IAeD;;OAEG;IACI,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO;IAI7C;;OAEG;IACI,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,kBAAkB,GAAG,SAAS;IAI1E;;OAEG;IACI,iBAAiB,IAAI,kBAAkB,EAAE;IAIhD;;OAEG;YACW,+BAA+B;IAuD7C;;OAEG;IACI,mBAAmB,IAAI,IAAI;CAQnC"}
|
|
@@ -44,6 +44,9 @@ export class SlashCommandManager {
|
|
|
44
44
|
get memoryService() {
|
|
45
45
|
return this.container.get("MemoryService");
|
|
46
46
|
}
|
|
47
|
+
get hookManager() {
|
|
48
|
+
return this.container.get("HookManager");
|
|
49
|
+
}
|
|
47
50
|
initializeBuiltinCommands() {
|
|
48
51
|
// Register built-in clear command
|
|
49
52
|
this.registerCommand({
|
|
@@ -52,9 +55,46 @@ export class SlashCommandManager {
|
|
|
52
55
|
description: "Clear conversation history and reset session",
|
|
53
56
|
handler: async () => {
|
|
54
57
|
this.aiManager.abortAIMessage();
|
|
58
|
+
// Capture old session info before clearing
|
|
59
|
+
const oldSessionId = this.messageManager.getSessionId();
|
|
60
|
+
const transcriptPath = this.messageManager.getTranscriptPath();
|
|
61
|
+
// Run SessionEnd hooks (cleanup before clear)
|
|
62
|
+
if (this.hookManager) {
|
|
63
|
+
try {
|
|
64
|
+
await this.hookManager.executeSessionEndHooks("clear", oldSessionId, transcriptPath);
|
|
65
|
+
}
|
|
66
|
+
catch (error) {
|
|
67
|
+
logger?.warn(`SessionEnd hooks on clear failed: ${error.message}`);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
// Clear messages and generate new session
|
|
55
71
|
this.messageManager.clearMessages();
|
|
56
72
|
this.memoryService.clearCache();
|
|
57
73
|
await this.taskManager.syncWithSession();
|
|
74
|
+
// Run SessionStart hooks (restore context for new session)
|
|
75
|
+
if (this.hookManager) {
|
|
76
|
+
try {
|
|
77
|
+
const newSessionId = this.messageManager.getSessionId();
|
|
78
|
+
const sessionStartResult = await this.hookManager.executeSessionStartHooks("clear", newSessionId, this.messageManager.getTranscriptPath());
|
|
79
|
+
// Inject additionalContext as a meta user message
|
|
80
|
+
if (sessionStartResult.additionalContext) {
|
|
81
|
+
this.messageManager.addUserMessage({
|
|
82
|
+
content: `<system-reminder>\nSessionStart hook additional context: ${sessionStartResult.additionalContext}\n</system-reminder>`,
|
|
83
|
+
isMeta: true,
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
// Inject initialUserMessage as a meta user message
|
|
87
|
+
if (sessionStartResult.initialUserMessage) {
|
|
88
|
+
this.messageManager.addUserMessage({
|
|
89
|
+
content: sessionStartResult.initialUserMessage,
|
|
90
|
+
isMeta: true,
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
catch (error) {
|
|
95
|
+
logger?.warn(`SessionStart hooks on clear failed: ${error.message}`);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
58
98
|
},
|
|
59
99
|
});
|
|
60
100
|
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AuthService
|
|
3
|
+
*
|
|
4
|
+
* Handles SSO authentication via the admin server.
|
|
5
|
+
* Manages auth token storage in ~/.wave/auth.json.
|
|
6
|
+
*/
|
|
7
|
+
import type { AuthConfig } from "../types/auth.js";
|
|
8
|
+
export declare class AuthService {
|
|
9
|
+
private static instance;
|
|
10
|
+
static getInstance(): AuthService;
|
|
11
|
+
getAuthPath(): string;
|
|
12
|
+
loadAuth(): AuthConfig;
|
|
13
|
+
saveAuth(config: AuthConfig): void;
|
|
14
|
+
clearAuth(): void;
|
|
15
|
+
getSSOToken(): string | undefined;
|
|
16
|
+
getAdminBaseUrl(): string;
|
|
17
|
+
login(options?: {
|
|
18
|
+
/** Callback to receive the auth URL (for display in CLI). */
|
|
19
|
+
onAuthUrl?: (url: string) => void;
|
|
20
|
+
/** Read token manually (e.g. from stdin). Resolves with token or rejects on cancel. */
|
|
21
|
+
readToken?: () => Promise<string>;
|
|
22
|
+
}): Promise<string>;
|
|
23
|
+
private startLocalAuthServer;
|
|
24
|
+
private openBrowser;
|
|
25
|
+
isSSOAuthenticated(): boolean;
|
|
26
|
+
}
|
|
27
|
+
export declare const authService: AuthService;
|
|
28
|
+
//# sourceMappingURL=authService.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"authService.d.ts","sourceRoot":"","sources":["../../src/services/authService.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAgBH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAInD,qBAAa,WAAW;IACtB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAc;IAErC,MAAM,CAAC,WAAW,IAAI,WAAW;IAOjC,WAAW,IAAI,MAAM;IAKrB,QAAQ,IAAI,UAAU;IAatB,QAAQ,CAAC,MAAM,EAAE,UAAU,GAAG,IAAI;IAUlC,SAAS,IAAI,IAAI;IAajB,WAAW,IAAI,MAAM,GAAG,SAAS;IAKjC,eAAe,IAAI,MAAM;IAUnB,KAAK,CAAC,OAAO,CAAC,EAAE;QACpB,6DAA6D;QAC7D,SAAS,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;QAClC,uFAAuF;QACvF,SAAS,CAAC,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;KACnC,GAAG,OAAO,CAAC,MAAM,CAAC;IAgCnB,OAAO,CAAC,oBAAoB;YAiFd,WAAW;IAmBzB,kBAAkB,IAAI,OAAO;CAG9B;AAED,eAAO,MAAM,WAAW,aAA4B,CAAC"}
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AuthService
|
|
3
|
+
*
|
|
4
|
+
* Handles SSO authentication via the admin server.
|
|
5
|
+
* Manages auth token storage in ~/.wave/auth.json.
|
|
6
|
+
*/
|
|
7
|
+
import { readFileSync, writeFileSync, existsSync, chmodSync, rmSync, mkdirSync, } from "fs";
|
|
8
|
+
import * as path from "path";
|
|
9
|
+
import * as os from "os";
|
|
10
|
+
import { createServer } from "http";
|
|
11
|
+
import { URL } from "url";
|
|
12
|
+
import { execFile } from "child_process";
|
|
13
|
+
import { promisify } from "util";
|
|
14
|
+
const execFileAsync = promisify(execFile);
|
|
15
|
+
export class AuthService {
|
|
16
|
+
static getInstance() {
|
|
17
|
+
if (!AuthService.instance) {
|
|
18
|
+
AuthService.instance = new AuthService();
|
|
19
|
+
}
|
|
20
|
+
return AuthService.instance;
|
|
21
|
+
}
|
|
22
|
+
getAuthPath() {
|
|
23
|
+
const homeDir = os.homedir();
|
|
24
|
+
return path.join(homeDir, ".wave", "auth.json");
|
|
25
|
+
}
|
|
26
|
+
loadAuth() {
|
|
27
|
+
const authPath = this.getAuthPath();
|
|
28
|
+
if (!existsSync(authPath)) {
|
|
29
|
+
return {};
|
|
30
|
+
}
|
|
31
|
+
try {
|
|
32
|
+
const content = readFileSync(authPath, "utf-8");
|
|
33
|
+
return JSON.parse(content);
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
return {};
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
saveAuth(config) {
|
|
40
|
+
const authPath = this.getAuthPath();
|
|
41
|
+
const waveDir = path.dirname(authPath);
|
|
42
|
+
if (!existsSync(waveDir)) {
|
|
43
|
+
mkdirSync(waveDir, { recursive: true });
|
|
44
|
+
}
|
|
45
|
+
writeFileSync(authPath, JSON.stringify(config, null, 2), "utf-8");
|
|
46
|
+
chmodSync(authPath, 0o600);
|
|
47
|
+
}
|
|
48
|
+
clearAuth() {
|
|
49
|
+
const config = this.loadAuth();
|
|
50
|
+
delete config.SSO_TOKEN;
|
|
51
|
+
if (Object.keys(config).length === 0) {
|
|
52
|
+
const authPath = this.getAuthPath();
|
|
53
|
+
if (existsSync(authPath)) {
|
|
54
|
+
rmSync(authPath);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
this.saveAuth(config);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
getSSOToken() {
|
|
62
|
+
const config = this.loadAuth();
|
|
63
|
+
return config.SSO_TOKEN;
|
|
64
|
+
}
|
|
65
|
+
getAdminBaseUrl() {
|
|
66
|
+
const url = process.env.WAVE_ADMIN_URL;
|
|
67
|
+
if (!url) {
|
|
68
|
+
throw new Error("WAVE_ADMIN_URL environment variable is not set. SSO authentication requires this to be configured.");
|
|
69
|
+
}
|
|
70
|
+
return url;
|
|
71
|
+
}
|
|
72
|
+
async login(options) {
|
|
73
|
+
const adminUrl = this.getAdminBaseUrl();
|
|
74
|
+
// Step 1: Fetch available SSO providers
|
|
75
|
+
const providersResponse = await fetch(`${adminUrl}/api/auth/sso-providers`);
|
|
76
|
+
if (!providersResponse.ok) {
|
|
77
|
+
throw new Error(`Failed to fetch SSO providers: ${providersResponse.status} ${providersResponse.statusText}`);
|
|
78
|
+
}
|
|
79
|
+
const providers = (await providersResponse.json());
|
|
80
|
+
if (!providers || providers.length === 0) {
|
|
81
|
+
throw new Error("No SSO providers available");
|
|
82
|
+
}
|
|
83
|
+
const provider = providers[0].provider;
|
|
84
|
+
// Step 2-5: Start local server, open browser, wait for callback or manual input
|
|
85
|
+
const token = await this.startLocalAuthServer(adminUrl, provider, {
|
|
86
|
+
onAuthUrl: options?.onAuthUrl,
|
|
87
|
+
readToken: options?.readToken,
|
|
88
|
+
});
|
|
89
|
+
// Save the token (preserve existing keys)
|
|
90
|
+
const existing = this.loadAuth();
|
|
91
|
+
this.saveAuth({ ...existing, SSO_TOKEN: token });
|
|
92
|
+
return token;
|
|
93
|
+
}
|
|
94
|
+
startLocalAuthServer(adminUrl, provider, options) {
|
|
95
|
+
return new Promise((resolve, reject) => {
|
|
96
|
+
let settled = false;
|
|
97
|
+
const server = createServer((req, res) => {
|
|
98
|
+
if (req.url) {
|
|
99
|
+
const parsedUrl = new URL(req.url, `http://127.0.0.1`);
|
|
100
|
+
const token = parsedUrl.searchParams.get("token");
|
|
101
|
+
res.writeHead(200, { "Content-Type": "text/html" });
|
|
102
|
+
res.end("<html><body><h1>Authentication successful, you can close this window</h1></body></html>");
|
|
103
|
+
if (token && !settled) {
|
|
104
|
+
settled = true;
|
|
105
|
+
server.close();
|
|
106
|
+
resolve(token);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
// Listen on 127.0.0.1 (IPv4) for reliable localhost callback
|
|
111
|
+
server.listen(0, "127.0.0.1", async () => {
|
|
112
|
+
const address = server.address();
|
|
113
|
+
if (typeof address !== "object" || !address) {
|
|
114
|
+
server.close();
|
|
115
|
+
reject(new Error("Failed to get server address"));
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
const port = address.port;
|
|
119
|
+
const callbackUrl = `http://127.0.0.1:${port}`;
|
|
120
|
+
const authUrl = `${adminUrl}/api/auth/sso/${provider}?callback_url=${encodeURIComponent(callbackUrl)}`;
|
|
121
|
+
// Notify caller of the auth URL
|
|
122
|
+
options?.onAuthUrl?.(authUrl);
|
|
123
|
+
// Try to open browser; if it fails, keep server alive for manual visit
|
|
124
|
+
try {
|
|
125
|
+
await this.openBrowser(authUrl);
|
|
126
|
+
}
|
|
127
|
+
catch {
|
|
128
|
+
// Browser not available — server stays alive
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
// If manual token reading is provided, race between server callback and user input
|
|
132
|
+
if (options?.readToken) {
|
|
133
|
+
options.readToken().then((token) => {
|
|
134
|
+
if (!settled) {
|
|
135
|
+
settled = true;
|
|
136
|
+
server.close();
|
|
137
|
+
resolve(token);
|
|
138
|
+
}
|
|
139
|
+
}, () => {
|
|
140
|
+
// Manual input cancelled or closed, server keeps waiting for callback
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
// Timeout after 5 minutes
|
|
144
|
+
setTimeout(() => {
|
|
145
|
+
if (!settled) {
|
|
146
|
+
settled = true;
|
|
147
|
+
server.close();
|
|
148
|
+
reject(new Error("SSO authentication timed out after 5 minutes"));
|
|
149
|
+
}
|
|
150
|
+
}, 5 * 60 * 1000);
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
async openBrowser(url) {
|
|
154
|
+
const platform = process.platform;
|
|
155
|
+
let command;
|
|
156
|
+
let args;
|
|
157
|
+
if (platform === "darwin") {
|
|
158
|
+
command = "open";
|
|
159
|
+
args = [url];
|
|
160
|
+
}
|
|
161
|
+
else if (platform === "win32") {
|
|
162
|
+
command = "cmd";
|
|
163
|
+
args = ["/c", "start", "", url];
|
|
164
|
+
}
|
|
165
|
+
else {
|
|
166
|
+
command = "xdg-open";
|
|
167
|
+
args = [url];
|
|
168
|
+
}
|
|
169
|
+
await execFileAsync(command, args);
|
|
170
|
+
}
|
|
171
|
+
isSSOAuthenticated() {
|
|
172
|
+
return this.getSSOToken() !== undefined;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
export const authService = AuthService.getInstance();
|
|
@@ -39,9 +39,13 @@ export declare class ConfigurationService {
|
|
|
39
39
|
* This replaces direct process.env modification
|
|
40
40
|
*/
|
|
41
41
|
setEnvironmentVars(env: Record<string, string>): void;
|
|
42
|
+
/**
|
|
43
|
+
* Read SSO token from ~/.wave/auth.json
|
|
44
|
+
*/
|
|
45
|
+
private readSSOToken;
|
|
42
46
|
/**
|
|
43
47
|
* Resolves gateway configuration from constructor args and environment
|
|
44
|
-
* Resolution priority: options > env (from settings.json) > process.env > error
|
|
48
|
+
* Resolution priority: SSO_TOKEN > options > env (from settings.json) > process.env > error
|
|
45
49
|
* @param apiKey - API key override (optional)
|
|
46
50
|
* @param baseURL - Base URL override (optional)
|
|
47
51
|
* @param defaultHeaders - HTTP headers override (optional)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"configurationService.d.ts","sourceRoot":"","sources":["../../src/services/configurationService.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;
|
|
1
|
+
{"version":3,"file":"configurationService.d.ts","sourceRoot":"","sources":["../../src/services/configurationService.ts"],"names":[],"mappings":"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"}
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import { readFileSync, existsSync, promises as fs } from "fs";
|
|
8
8
|
import * as path from "path";
|
|
9
|
+
import * as os from "os";
|
|
9
10
|
import { isValidHookEvent } from "../types/hooks.js";
|
|
10
11
|
import { logger } from "../utils/globalLogger.js";
|
|
11
12
|
import { getAllConfigPaths, getExistingConfigPaths, getUserConfigPaths, getProjectConfigPaths, } from "../utils/configPaths.js";
|
|
@@ -285,9 +286,27 @@ export class ConfigurationService {
|
|
|
285
286
|
// =============================================================================
|
|
286
287
|
// Configuration Resolution Methods (merged from configResolver.ts)
|
|
287
288
|
// =============================================================================
|
|
289
|
+
/**
|
|
290
|
+
* Read SSO token from ~/.wave/auth.json
|
|
291
|
+
*/
|
|
292
|
+
readSSOToken() {
|
|
293
|
+
const homeDir = os.homedir();
|
|
294
|
+
const authPath = path.join(homeDir, ".wave", "auth.json");
|
|
295
|
+
if (!existsSync(authPath)) {
|
|
296
|
+
return undefined;
|
|
297
|
+
}
|
|
298
|
+
try {
|
|
299
|
+
const content = readFileSync(authPath, "utf-8");
|
|
300
|
+
const authConfig = JSON.parse(content);
|
|
301
|
+
return authConfig.SSO_TOKEN;
|
|
302
|
+
}
|
|
303
|
+
catch {
|
|
304
|
+
return undefined;
|
|
305
|
+
}
|
|
306
|
+
}
|
|
288
307
|
/**
|
|
289
308
|
* Resolves gateway configuration from constructor args and environment
|
|
290
|
-
* Resolution priority: options > env (from settings.json) > process.env > error
|
|
309
|
+
* Resolution priority: SSO_TOKEN > options > env (from settings.json) > process.env > error
|
|
291
310
|
* @param apiKey - API key override (optional)
|
|
292
311
|
* @param baseURL - Base URL override (optional)
|
|
293
312
|
* @param defaultHeaders - HTTP headers override (optional)
|
|
@@ -297,6 +316,23 @@ export class ConfigurationService {
|
|
|
297
316
|
* @throws ConfigurationError if required configuration is missing after fallbacks
|
|
298
317
|
*/
|
|
299
318
|
resolveGatewayConfig(apiKey, baseURL, defaultHeaders, fetchOptions, fetch) {
|
|
319
|
+
// Check for SSO token first - if present, use SSO mode
|
|
320
|
+
const ssoToken = this.readSSOToken();
|
|
321
|
+
if (ssoToken) {
|
|
322
|
+
const adminUrl = process.env.WAVE_ADMIN_URL;
|
|
323
|
+
if (!adminUrl) {
|
|
324
|
+
throw new ConfigurationError(CONFIG_ERRORS.MISSING_BASE_URL, "baseURL", "WAVE_ADMIN_URL is required for SSO authentication");
|
|
325
|
+
}
|
|
326
|
+
return {
|
|
327
|
+
apiKey: ssoToken,
|
|
328
|
+
baseURL: `${adminUrl}/api/v1`,
|
|
329
|
+
defaultHeaders: Object.keys(defaultHeaders || {}).length > 0
|
|
330
|
+
? defaultHeaders
|
|
331
|
+
: undefined,
|
|
332
|
+
fetchOptions: fetchOptions ?? this.options.fetchOptions,
|
|
333
|
+
fetch: fetch ?? this.options.fetch,
|
|
334
|
+
};
|
|
335
|
+
}
|
|
300
336
|
// Resolve API key: override > options > env (settings.json) > process.env
|
|
301
337
|
// Note: Explicitly provided empty strings should be treated as invalid, not fall back to env
|
|
302
338
|
let resolvedApiKey;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/types/auth.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,UAAU;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/types/hooks.d.ts
CHANGED
|
@@ -53,8 +53,8 @@ export declare class HookConfigurationError extends Error {
|
|
|
53
53
|
readonly validationErrors: string[];
|
|
54
54
|
constructor(configPath: string, validationErrors: string[]);
|
|
55
55
|
}
|
|
56
|
-
export type SessionStartSource = "startup" | "
|
|
57
|
-
export type SessionEndSource = "exit" | "stop" | "compact";
|
|
56
|
+
export type SessionStartSource = "startup" | "compact" | "clear";
|
|
57
|
+
export type SessionEndSource = "exit" | "stop" | "compact" | "clear";
|
|
58
58
|
export declare function isValidHookEvent(event: string): event is HookEvent;
|
|
59
59
|
export declare function isValidHookCommand(cmd: unknown): cmd is HookCommand;
|
|
60
60
|
export declare function isValidHookEventConfig(config: unknown): config is HookEventConfig;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../../src/types/hooks.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,YAAY,EACV,iBAAiB,EACjB,iBAAiB,EACjB,wBAAwB,EACxB,uBAAuB,GACxB,MAAM,oBAAoB,CAAC;AAG5B,MAAM,MAAM,SAAS,GACjB,YAAY,GACZ,aAAa,GACb,kBAAkB,GAClB,MAAM,GACN,cAAc,GACd,mBAAmB,GACnB,gBAAgB,GAChB,gBAAgB,GAChB,cAAc,GACd,YAAY,CAAC;AAGjB,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,SAAS,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAGD,MAAM,WAAW,eAAe;IAC9B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,WAAW,EAAE,CAAC;CACtB;AAGD,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,SAAS,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,IAAI,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAGD,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,OAAO,CAAC;CACnB;AAGD,MAAM,WAAW,oBAAoB;IACnC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC7B;AAGD,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAGD,qBAAa,kBAAmB,SAAQ,KAAK;aAEzB,WAAW,EAAE,MAAM;aACnB,aAAa,EAAE,KAAK;aACpB,OAAO,EAAE,oBAAoB;gBAF7B,WAAW,EAAE,MAAM,EACnB,aAAa,EAAE,KAAK,EACpB,OAAO,EAAE,oBAAoB;CAKhD;AAGD,qBAAa,sBAAuB,SAAQ,KAAK;aAE7B,UAAU,EAAE,MAAM;aAClB,gBAAgB,EAAE,MAAM,EAAE;gBAD1B,UAAU,EAAE,MAAM,EAClB,gBAAgB,EAAE,MAAM,EAAE;CAO7C;AAED,MAAM,MAAM,kBAAkB,GAAG,SAAS,GAAG,
|
|
1
|
+
{"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../../src/types/hooks.ts"],"names":[],"mappings":"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"}
|
package/dist/types/index.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAGH,cAAc,WAAW,CAAC;AAG1B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,UAAU,CAAC;AACzB,cAAc,gBAAgB,CAAC;AAC/B,cAAc,eAAe,CAAC;AAC9B,cAAc,aAAa,CAAC;AAC5B,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC;AAC7B,cAAc,kBAAkB,CAAC;AACjC,cAAc,oBAAoB,CAAC;AACnC,cAAc,YAAY,CAAC;AAC3B,cAAc,kBAAkB,CAAC;AACjC,cAAc,YAAY,CAAC;AAC3B,cAAc,iBAAiB,CAAC;AAChC,cAAc,UAAU,CAAC;AACzB,cAAc,cAAc,CAAC;AAC7B,cAAc,kBAAkB,CAAC;AACjC,cAAc,iBAAiB,CAAC;AAChC,cAAc,cAAc,CAAC;AAC7B,cAAc,YAAY,CAAC;AAC3B,cAAc,YAAY,CAAC;AAC3B,cAAc,WAAW,CAAC;AAC1B,cAAc,gBAAgB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAGH,cAAc,WAAW,CAAC;AAG1B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,UAAU,CAAC;AACzB,cAAc,gBAAgB,CAAC;AAC/B,cAAc,eAAe,CAAC;AAC9B,cAAc,aAAa,CAAC;AAC5B,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC;AAC7B,cAAc,kBAAkB,CAAC;AACjC,cAAc,oBAAoB,CAAC;AACnC,cAAc,YAAY,CAAC;AAC3B,cAAc,kBAAkB,CAAC;AACjC,cAAc,YAAY,CAAC;AAC3B,cAAc,iBAAiB,CAAC;AAChC,cAAc,UAAU,CAAC;AACzB,cAAc,cAAc,CAAC;AAC7B,cAAc,kBAAkB,CAAC;AACjC,cAAc,iBAAiB,CAAC;AAChC,cAAc,cAAc,CAAC;AAC7B,cAAc,YAAY,CAAC;AAC3B,cAAc,YAAY,CAAC;AAC3B,cAAc,WAAW,CAAC;AAC1B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,WAAW,CAAC"}
|
package/dist/types/index.js
CHANGED
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -501,6 +501,40 @@ export class AIManager {
|
|
|
501
501
|
afterTokens: "1",
|
|
502
502
|
model: this.getModelConfig().fastModel,
|
|
503
503
|
}).catch(() => {});
|
|
504
|
+
|
|
505
|
+
// Run SessionStart hooks after compaction to restore context
|
|
506
|
+
if (this.hookManager) {
|
|
507
|
+
try {
|
|
508
|
+
const newSessionId = this.messageManager.getSessionId();
|
|
509
|
+
const sessionStartResult =
|
|
510
|
+
await this.hookManager.executeSessionStartHooks(
|
|
511
|
+
"compact",
|
|
512
|
+
newSessionId,
|
|
513
|
+
this.messageManager.getTranscriptPath(),
|
|
514
|
+
this.subagentType,
|
|
515
|
+
);
|
|
516
|
+
|
|
517
|
+
// Inject additionalContext as a meta user message
|
|
518
|
+
if (sessionStartResult.additionalContext) {
|
|
519
|
+
this.messageManager.addUserMessage({
|
|
520
|
+
content: `<system-reminder>\nSessionStart hook additional context: ${sessionStartResult.additionalContext}\n</system-reminder>`,
|
|
521
|
+
isMeta: true,
|
|
522
|
+
});
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
// Inject initialUserMessage as a meta user message
|
|
526
|
+
if (sessionStartResult.initialUserMessage) {
|
|
527
|
+
this.messageManager.addUserMessage({
|
|
528
|
+
content: sessionStartResult.initialUserMessage,
|
|
529
|
+
isMeta: true,
|
|
530
|
+
});
|
|
531
|
+
}
|
|
532
|
+
} catch (error) {
|
|
533
|
+
logger?.warn(
|
|
534
|
+
`SessionStart hooks on compact failed: ${(error as Error).message}`,
|
|
535
|
+
);
|
|
536
|
+
}
|
|
537
|
+
}
|
|
504
538
|
} catch (compactError) {
|
|
505
539
|
this.consecutiveCompactionFailures++;
|
|
506
540
|
logger?.error(
|
|
@@ -851,7 +851,7 @@ export class HookManager {
|
|
|
851
851
|
* Collects additionalContext and initialUserMessage from hook stdout.
|
|
852
852
|
*/
|
|
853
853
|
async executeSessionStartHooks(
|
|
854
|
-
source: "startup" | "
|
|
854
|
+
source: "startup" | "compact" | "clear",
|
|
855
855
|
sessionId: string,
|
|
856
856
|
transcriptPath: string,
|
|
857
857
|
agentType?: string,
|
|
@@ -24,6 +24,7 @@ import type { SkillManager } from "./skillManager.js";
|
|
|
24
24
|
import type { SkillMetadata } from "../types/skills.js";
|
|
25
25
|
import type { SubagentManager } from "./subagentManager.js";
|
|
26
26
|
import type { MemoryService } from "../services/memory.js";
|
|
27
|
+
import type { HookManager } from "./hookManager.js";
|
|
27
28
|
|
|
28
29
|
import { logger } from "../utils/globalLogger.js";
|
|
29
30
|
|
|
@@ -86,6 +87,10 @@ export class SlashCommandManager {
|
|
|
86
87
|
return this.container.get<MemoryService>("MemoryService")!;
|
|
87
88
|
}
|
|
88
89
|
|
|
90
|
+
private get hookManager(): HookManager | undefined {
|
|
91
|
+
return this.container.get<HookManager>("HookManager");
|
|
92
|
+
}
|
|
93
|
+
|
|
89
94
|
private initializeBuiltinCommands(): void {
|
|
90
95
|
// Register built-in clear command
|
|
91
96
|
this.registerCommand({
|
|
@@ -94,9 +99,63 @@ export class SlashCommandManager {
|
|
|
94
99
|
description: "Clear conversation history and reset session",
|
|
95
100
|
handler: async () => {
|
|
96
101
|
this.aiManager.abortAIMessage();
|
|
102
|
+
|
|
103
|
+
// Capture old session info before clearing
|
|
104
|
+
const oldSessionId = this.messageManager.getSessionId();
|
|
105
|
+
const transcriptPath = this.messageManager.getTranscriptPath();
|
|
106
|
+
|
|
107
|
+
// Run SessionEnd hooks (cleanup before clear)
|
|
108
|
+
if (this.hookManager) {
|
|
109
|
+
try {
|
|
110
|
+
await this.hookManager.executeSessionEndHooks(
|
|
111
|
+
"clear",
|
|
112
|
+
oldSessionId,
|
|
113
|
+
transcriptPath,
|
|
114
|
+
);
|
|
115
|
+
} catch (error) {
|
|
116
|
+
logger?.warn(
|
|
117
|
+
`SessionEnd hooks on clear failed: ${(error as Error).message}`,
|
|
118
|
+
);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// Clear messages and generate new session
|
|
97
123
|
this.messageManager.clearMessages();
|
|
98
124
|
this.memoryService.clearCache();
|
|
99
125
|
await this.taskManager.syncWithSession();
|
|
126
|
+
|
|
127
|
+
// Run SessionStart hooks (restore context for new session)
|
|
128
|
+
if (this.hookManager) {
|
|
129
|
+
try {
|
|
130
|
+
const newSessionId = this.messageManager.getSessionId();
|
|
131
|
+
const sessionStartResult =
|
|
132
|
+
await this.hookManager.executeSessionStartHooks(
|
|
133
|
+
"clear",
|
|
134
|
+
newSessionId,
|
|
135
|
+
this.messageManager.getTranscriptPath(),
|
|
136
|
+
);
|
|
137
|
+
|
|
138
|
+
// Inject additionalContext as a meta user message
|
|
139
|
+
if (sessionStartResult.additionalContext) {
|
|
140
|
+
this.messageManager.addUserMessage({
|
|
141
|
+
content: `<system-reminder>\nSessionStart hook additional context: ${sessionStartResult.additionalContext}\n</system-reminder>`,
|
|
142
|
+
isMeta: true,
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// Inject initialUserMessage as a meta user message
|
|
147
|
+
if (sessionStartResult.initialUserMessage) {
|
|
148
|
+
this.messageManager.addUserMessage({
|
|
149
|
+
content: sessionStartResult.initialUserMessage,
|
|
150
|
+
isMeta: true,
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
} catch (error) {
|
|
154
|
+
logger?.warn(
|
|
155
|
+
`SessionStart hooks on clear failed: ${(error as Error).message}`,
|
|
156
|
+
);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
100
159
|
},
|
|
101
160
|
});
|
|
102
161
|
}
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AuthService
|
|
3
|
+
*
|
|
4
|
+
* Handles SSO authentication via the admin server.
|
|
5
|
+
* Manages auth token storage in ~/.wave/auth.json.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import {
|
|
9
|
+
readFileSync,
|
|
10
|
+
writeFileSync,
|
|
11
|
+
existsSync,
|
|
12
|
+
chmodSync,
|
|
13
|
+
rmSync,
|
|
14
|
+
mkdirSync,
|
|
15
|
+
} from "fs";
|
|
16
|
+
import * as path from "path";
|
|
17
|
+
import * as os from "os";
|
|
18
|
+
import { createServer, Server } from "http";
|
|
19
|
+
import { URL } from "url";
|
|
20
|
+
import { execFile } from "child_process";
|
|
21
|
+
import { promisify } from "util";
|
|
22
|
+
import type { AuthConfig } from "../types/auth.js";
|
|
23
|
+
|
|
24
|
+
const execFileAsync = promisify(execFile);
|
|
25
|
+
|
|
26
|
+
export class AuthService {
|
|
27
|
+
private static instance: AuthService;
|
|
28
|
+
|
|
29
|
+
static getInstance(): AuthService {
|
|
30
|
+
if (!AuthService.instance) {
|
|
31
|
+
AuthService.instance = new AuthService();
|
|
32
|
+
}
|
|
33
|
+
return AuthService.instance;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
getAuthPath(): string {
|
|
37
|
+
const homeDir = os.homedir();
|
|
38
|
+
return path.join(homeDir, ".wave", "auth.json");
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
loadAuth(): AuthConfig {
|
|
42
|
+
const authPath = this.getAuthPath();
|
|
43
|
+
if (!existsSync(authPath)) {
|
|
44
|
+
return {};
|
|
45
|
+
}
|
|
46
|
+
try {
|
|
47
|
+
const content = readFileSync(authPath, "utf-8");
|
|
48
|
+
return JSON.parse(content) as AuthConfig;
|
|
49
|
+
} catch {
|
|
50
|
+
return {};
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
saveAuth(config: AuthConfig): void {
|
|
55
|
+
const authPath = this.getAuthPath();
|
|
56
|
+
const waveDir = path.dirname(authPath);
|
|
57
|
+
if (!existsSync(waveDir)) {
|
|
58
|
+
mkdirSync(waveDir, { recursive: true });
|
|
59
|
+
}
|
|
60
|
+
writeFileSync(authPath, JSON.stringify(config, null, 2), "utf-8");
|
|
61
|
+
chmodSync(authPath, 0o600);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
clearAuth(): void {
|
|
65
|
+
const config = this.loadAuth();
|
|
66
|
+
delete config.SSO_TOKEN;
|
|
67
|
+
if (Object.keys(config).length === 0) {
|
|
68
|
+
const authPath = this.getAuthPath();
|
|
69
|
+
if (existsSync(authPath)) {
|
|
70
|
+
rmSync(authPath);
|
|
71
|
+
}
|
|
72
|
+
} else {
|
|
73
|
+
this.saveAuth(config);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
getSSOToken(): string | undefined {
|
|
78
|
+
const config = this.loadAuth();
|
|
79
|
+
return config.SSO_TOKEN;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
getAdminBaseUrl(): string {
|
|
83
|
+
const url = process.env.WAVE_ADMIN_URL;
|
|
84
|
+
if (!url) {
|
|
85
|
+
throw new Error(
|
|
86
|
+
"WAVE_ADMIN_URL environment variable is not set. SSO authentication requires this to be configured.",
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
return url;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
async login(options?: {
|
|
93
|
+
/** Callback to receive the auth URL (for display in CLI). */
|
|
94
|
+
onAuthUrl?: (url: string) => void;
|
|
95
|
+
/** Read token manually (e.g. from stdin). Resolves with token or rejects on cancel. */
|
|
96
|
+
readToken?: () => Promise<string>;
|
|
97
|
+
}): Promise<string> {
|
|
98
|
+
const adminUrl = this.getAdminBaseUrl();
|
|
99
|
+
|
|
100
|
+
// Step 1: Fetch available SSO providers
|
|
101
|
+
const providersResponse = await fetch(`${adminUrl}/api/auth/sso-providers`);
|
|
102
|
+
if (!providersResponse.ok) {
|
|
103
|
+
throw new Error(
|
|
104
|
+
`Failed to fetch SSO providers: ${providersResponse.status} ${providersResponse.statusText}`,
|
|
105
|
+
);
|
|
106
|
+
}
|
|
107
|
+
const providers = (await providersResponse.json()) as {
|
|
108
|
+
provider: string;
|
|
109
|
+
displayName: string;
|
|
110
|
+
}[];
|
|
111
|
+
if (!providers || providers.length === 0) {
|
|
112
|
+
throw new Error("No SSO providers available");
|
|
113
|
+
}
|
|
114
|
+
const provider = providers[0].provider;
|
|
115
|
+
|
|
116
|
+
// Step 2-5: Start local server, open browser, wait for callback or manual input
|
|
117
|
+
const token = await this.startLocalAuthServer(adminUrl, provider, {
|
|
118
|
+
onAuthUrl: options?.onAuthUrl,
|
|
119
|
+
readToken: options?.readToken,
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
// Save the token (preserve existing keys)
|
|
123
|
+
const existing = this.loadAuth();
|
|
124
|
+
this.saveAuth({ ...existing, SSO_TOKEN: token });
|
|
125
|
+
|
|
126
|
+
return token;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
private startLocalAuthServer(
|
|
130
|
+
adminUrl: string,
|
|
131
|
+
provider: string,
|
|
132
|
+
options?: {
|
|
133
|
+
onAuthUrl?: (url: string) => void;
|
|
134
|
+
readToken?: () => Promise<string>;
|
|
135
|
+
},
|
|
136
|
+
): Promise<string> {
|
|
137
|
+
return new Promise((resolve, reject) => {
|
|
138
|
+
let settled = false;
|
|
139
|
+
const server: Server = createServer((req, res) => {
|
|
140
|
+
if (req.url) {
|
|
141
|
+
const parsedUrl = new URL(req.url, `http://127.0.0.1`);
|
|
142
|
+
const token = parsedUrl.searchParams.get("token");
|
|
143
|
+
|
|
144
|
+
res.writeHead(200, { "Content-Type": "text/html" });
|
|
145
|
+
res.end(
|
|
146
|
+
"<html><body><h1>Authentication successful, you can close this window</h1></body></html>",
|
|
147
|
+
);
|
|
148
|
+
|
|
149
|
+
if (token && !settled) {
|
|
150
|
+
settled = true;
|
|
151
|
+
server.close();
|
|
152
|
+
resolve(token);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
// Listen on 127.0.0.1 (IPv4) for reliable localhost callback
|
|
158
|
+
server.listen(0, "127.0.0.1", async () => {
|
|
159
|
+
const address = server.address();
|
|
160
|
+
if (typeof address !== "object" || !address) {
|
|
161
|
+
server.close();
|
|
162
|
+
reject(new Error("Failed to get server address"));
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
const port = address.port;
|
|
166
|
+
const callbackUrl = `http://127.0.0.1:${port}`;
|
|
167
|
+
const authUrl = `${adminUrl}/api/auth/sso/${provider}?callback_url=${encodeURIComponent(callbackUrl)}`;
|
|
168
|
+
|
|
169
|
+
// Notify caller of the auth URL
|
|
170
|
+
options?.onAuthUrl?.(authUrl);
|
|
171
|
+
|
|
172
|
+
// Try to open browser; if it fails, keep server alive for manual visit
|
|
173
|
+
try {
|
|
174
|
+
await this.openBrowser(authUrl);
|
|
175
|
+
} catch {
|
|
176
|
+
// Browser not available — server stays alive
|
|
177
|
+
}
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
// If manual token reading is provided, race between server callback and user input
|
|
181
|
+
if (options?.readToken) {
|
|
182
|
+
options.readToken().then(
|
|
183
|
+
(token) => {
|
|
184
|
+
if (!settled) {
|
|
185
|
+
settled = true;
|
|
186
|
+
server.close();
|
|
187
|
+
resolve(token);
|
|
188
|
+
}
|
|
189
|
+
},
|
|
190
|
+
() => {
|
|
191
|
+
// Manual input cancelled or closed, server keeps waiting for callback
|
|
192
|
+
},
|
|
193
|
+
);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// Timeout after 5 minutes
|
|
197
|
+
setTimeout(
|
|
198
|
+
() => {
|
|
199
|
+
if (!settled) {
|
|
200
|
+
settled = true;
|
|
201
|
+
server.close();
|
|
202
|
+
reject(new Error("SSO authentication timed out after 5 minutes"));
|
|
203
|
+
}
|
|
204
|
+
},
|
|
205
|
+
5 * 60 * 1000,
|
|
206
|
+
);
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
private async openBrowser(url: string): Promise<void> {
|
|
211
|
+
const platform = process.platform;
|
|
212
|
+
let command: string;
|
|
213
|
+
let args: string[];
|
|
214
|
+
|
|
215
|
+
if (platform === "darwin") {
|
|
216
|
+
command = "open";
|
|
217
|
+
args = [url];
|
|
218
|
+
} else if (platform === "win32") {
|
|
219
|
+
command = "cmd";
|
|
220
|
+
args = ["/c", "start", "", url];
|
|
221
|
+
} else {
|
|
222
|
+
command = "xdg-open";
|
|
223
|
+
args = [url];
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
await execFileAsync(command, args);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
isSSOAuthenticated(): boolean {
|
|
230
|
+
return this.getSSOToken() !== undefined;
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
export const authService = AuthService.getInstance();
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
import { readFileSync, existsSync, promises as fs } from "fs";
|
|
9
9
|
import * as path from "path";
|
|
10
|
+
import * as os from "os";
|
|
10
11
|
import { isValidHookEvent } from "../types/hooks.js";
|
|
11
12
|
import { logger } from "../utils/globalLogger.js";
|
|
12
13
|
import type {
|
|
@@ -371,9 +372,27 @@ export class ConfigurationService {
|
|
|
371
372
|
// Configuration Resolution Methods (merged from configResolver.ts)
|
|
372
373
|
// =============================================================================
|
|
373
374
|
|
|
375
|
+
/**
|
|
376
|
+
* Read SSO token from ~/.wave/auth.json
|
|
377
|
+
*/
|
|
378
|
+
private readSSOToken(): string | undefined {
|
|
379
|
+
const homeDir = os.homedir();
|
|
380
|
+
const authPath = path.join(homeDir, ".wave", "auth.json");
|
|
381
|
+
if (!existsSync(authPath)) {
|
|
382
|
+
return undefined;
|
|
383
|
+
}
|
|
384
|
+
try {
|
|
385
|
+
const content = readFileSync(authPath, "utf-8");
|
|
386
|
+
const authConfig = JSON.parse(content) as { SSO_TOKEN?: string };
|
|
387
|
+
return authConfig.SSO_TOKEN;
|
|
388
|
+
} catch {
|
|
389
|
+
return undefined;
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
|
|
374
393
|
/**
|
|
375
394
|
* Resolves gateway configuration from constructor args and environment
|
|
376
|
-
* Resolution priority: options > env (from settings.json) > process.env > error
|
|
395
|
+
* Resolution priority: SSO_TOKEN > options > env (from settings.json) > process.env > error
|
|
377
396
|
* @param apiKey - API key override (optional)
|
|
378
397
|
* @param baseURL - Base URL override (optional)
|
|
379
398
|
* @param defaultHeaders - HTTP headers override (optional)
|
|
@@ -389,6 +408,29 @@ export class ConfigurationService {
|
|
|
389
408
|
fetchOptions?: ClientOptions["fetchOptions"],
|
|
390
409
|
fetch?: ClientOptions["fetch"],
|
|
391
410
|
): GatewayConfig {
|
|
411
|
+
// Check for SSO token first - if present, use SSO mode
|
|
412
|
+
const ssoToken = this.readSSOToken();
|
|
413
|
+
if (ssoToken) {
|
|
414
|
+
const adminUrl = process.env.WAVE_ADMIN_URL;
|
|
415
|
+
if (!adminUrl) {
|
|
416
|
+
throw new ConfigurationError(
|
|
417
|
+
CONFIG_ERRORS.MISSING_BASE_URL,
|
|
418
|
+
"baseURL",
|
|
419
|
+
"WAVE_ADMIN_URL is required for SSO authentication",
|
|
420
|
+
);
|
|
421
|
+
}
|
|
422
|
+
return {
|
|
423
|
+
apiKey: ssoToken,
|
|
424
|
+
baseURL: `${adminUrl}/api/v1`,
|
|
425
|
+
defaultHeaders:
|
|
426
|
+
Object.keys(defaultHeaders || {}).length > 0
|
|
427
|
+
? defaultHeaders
|
|
428
|
+
: undefined,
|
|
429
|
+
fetchOptions: fetchOptions ?? this.options.fetchOptions,
|
|
430
|
+
fetch: fetch ?? this.options.fetch,
|
|
431
|
+
};
|
|
432
|
+
}
|
|
433
|
+
|
|
392
434
|
// Resolve API key: override > options > env (settings.json) > process.env
|
|
393
435
|
// Note: Explicitly provided empty strings should be treated as invalid, not fall back to env
|
|
394
436
|
let resolvedApiKey: string | undefined;
|
package/src/types/hooks.ts
CHANGED
|
@@ -98,9 +98,9 @@ export class HookConfigurationError extends Error {
|
|
|
98
98
|
}
|
|
99
99
|
}
|
|
100
100
|
|
|
101
|
-
export type SessionStartSource = "startup" | "
|
|
101
|
+
export type SessionStartSource = "startup" | "compact" | "clear";
|
|
102
102
|
|
|
103
|
-
export type SessionEndSource = "exit" | "stop" | "compact";
|
|
103
|
+
export type SessionEndSource = "exit" | "stop" | "compact" | "clear";
|
|
104
104
|
|
|
105
105
|
// Type guards for runtime validation
|
|
106
106
|
export function isValidHookEvent(event: string): event is HookEvent {
|
package/src/types/index.ts
CHANGED