crewly 1.15.0 → 1.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +39 -5
- package/config/roles/developer/prompt.md +1 -1
- package/config/roles/orchestrator/prompt.md +20 -5
- package/config/runtime_scripts/runtime-config.json +7 -0
- package/config/skills/agent/core/calendar-create/SKILL.md +62 -0
- package/config/skills/agent/core/calendar-create/execute.sh +91 -0
- package/config/skills/agent/core/calendar-create/execute.test.sh +80 -0
- package/config/skills/agent/core/calendar-list/SKILL.md +58 -0
- package/config/skills/agent/core/calendar-list/execute.sh +88 -0
- package/config/skills/agent/core/calendar-list/execute.test.sh +71 -0
- package/config/skills/agent/core/count-json/SKILL.md +61 -0
- package/config/skills/agent/core/count-json/execute.sh +52 -0
- package/config/skills/agent/core/count-json/execute.test.sh +35 -0
- package/config/skills/agent/core/gmail-read/SKILL.md +61 -0
- package/config/skills/agent/core/gmail-read/execute.sh +62 -0
- package/config/skills/agent/core/gmail-read/execute.test.sh +68 -0
- package/config/skills/agent/core/gmail-search/SKILL.md +64 -0
- package/config/skills/agent/core/gmail-search/execute.sh +70 -0
- package/config/skills/agent/core/gmail-search/execute.test.sh +67 -0
- package/config/skills/agent/core/gmail-send/SKILL.md +69 -0
- package/config/skills/agent/core/gmail-send/execute.sh +114 -0
- package/config/skills/agent/core/gmail-send/execute.test.sh +83 -0
- package/config/skills/agent/core/record-prediction/SKILL.md +61 -0
- package/config/skills/agent/core/record-prediction/execute.sh +90 -0
- package/config/skills/agent/core/record-prediction/execute.test.sh +67 -0
- package/config/skills/agent/core/resolve-prediction/SKILL.md +61 -0
- package/config/skills/agent/core/resolve-prediction/execute.sh +87 -0
- package/config/skills/agent/core/resolve-prediction/execute.test.sh +74 -0
- package/config/skills/agent/core/set-focus/SKILL.md +64 -0
- package/config/skills/agent/core/set-focus/execute.sh +73 -0
- package/config/skills/agent/core/set-focus/execute.test.sh +67 -0
- package/config/skills/agent/core/suppress-noise/SKILL.md +59 -0
- package/config/skills/agent/core/suppress-noise/execute.sh +68 -0
- package/config/skills/agent/core/suppress-noise/execute.test.sh +58 -0
- package/config/skills/orchestrator/list-missions/SKILL.md +47 -0
- package/config/skills/orchestrator/list-missions/execute.sh +34 -0
- package/config/skills/orchestrator/list-missions/execute.test.sh +33 -0
- package/config/slack-master-app-manifest.json +64 -0
- package/dist/backend/backend/src/constants.d.ts +186 -0
- package/dist/backend/backend/src/constants.d.ts.map +1 -1
- package/dist/backend/backend/src/constants.js +196 -0
- package/dist/backend/backend/src/constants.js.map +1 -1
- package/dist/backend/backend/src/controllers/agent-self-improvement/agent-self-improvement.controller.d.ts +76 -0
- package/dist/backend/backend/src/controllers/agent-self-improvement/agent-self-improvement.controller.d.ts.map +1 -0
- package/dist/backend/backend/src/controllers/agent-self-improvement/agent-self-improvement.controller.js +262 -0
- package/dist/backend/backend/src/controllers/agent-self-improvement/agent-self-improvement.controller.js.map +1 -0
- package/dist/backend/backend/src/controllers/cloud/cloud.controller.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/cloud/cloud.controller.js +3 -1
- package/dist/backend/backend/src/controllers/cloud/cloud.controller.js.map +1 -1
- package/dist/backend/backend/src/controllers/google/google.controller.d.ts +100 -0
- package/dist/backend/backend/src/controllers/google/google.controller.d.ts.map +1 -0
- package/dist/backend/backend/src/controllers/google/google.controller.js +293 -0
- package/dist/backend/backend/src/controllers/google/google.controller.js.map +1 -0
- package/dist/backend/backend/src/controllers/google/google.routes.d.ts +26 -0
- package/dist/backend/backend/src/controllers/google/google.routes.d.ts.map +1 -0
- package/dist/backend/backend/src/controllers/google/google.routes.js +38 -0
- package/dist/backend/backend/src/controllers/google/google.routes.js.map +1 -0
- package/dist/backend/backend/src/controllers/oauth/oauth.routes.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/oauth/oauth.routes.js +31 -0
- package/dist/backend/backend/src/controllers/oauth/oauth.routes.js.map +1 -1
- package/dist/backend/backend/src/controllers/request-types.d.ts +6 -2
- package/dist/backend/backend/src/controllers/request-types.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/slack/slack.controller.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/slack/slack.controller.js +209 -2
- package/dist/backend/backend/src/controllers/slack/slack.controller.js.map +1 -1
- package/dist/backend/backend/src/controllers/team/team.controller.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/team/team.controller.js +4 -0
- package/dist/backend/backend/src/controllers/team/team.controller.js.map +1 -1
- package/dist/backend/backend/src/index.d.ts +1 -0
- package/dist/backend/backend/src/index.d.ts.map +1 -1
- package/dist/backend/backend/src/index.js +92 -8
- package/dist/backend/backend/src/index.js.map +1 -1
- package/dist/backend/backend/src/routes/api.routes.d.ts.map +1 -1
- package/dist/backend/backend/src/routes/api.routes.js +10 -0
- package/dist/backend/backend/src/routes/api.routes.js.map +1 -1
- package/dist/backend/backend/src/services/agent/agent-registration.service.d.ts +10 -0
- package/dist/backend/backend/src/services/agent/agent-registration.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/agent/agent-registration.service.js +32 -4
- package/dist/backend/backend/src/services/agent/agent-registration.service.js.map +1 -1
- package/dist/backend/backend/src/services/agent/opencode-runtime.service.d.ts +114 -0
- package/dist/backend/backend/src/services/agent/opencode-runtime.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/agent/opencode-runtime.service.js +185 -0
- package/dist/backend/backend/src/services/agent/opencode-runtime.service.js.map +1 -0
- package/dist/backend/backend/src/services/agent/runtime-agent.service.abstract.d.ts.map +1 -1
- package/dist/backend/backend/src/services/agent/runtime-agent.service.abstract.js +22 -1
- package/dist/backend/backend/src/services/agent/runtime-agent.service.abstract.js.map +1 -1
- package/dist/backend/backend/src/services/agent/runtime-exit-monitor.service.d.ts +1 -1
- package/dist/backend/backend/src/services/agent/runtime-exit-monitor.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/agent/runtime-exit-monitor.service.js +15 -3
- package/dist/backend/backend/src/services/agent/runtime-exit-monitor.service.js.map +1 -1
- package/dist/backend/backend/src/services/agent/runtime-service.factory.d.ts.map +1 -1
- package/dist/backend/backend/src/services/agent/runtime-service.factory.js +9 -0
- package/dist/backend/backend/src/services/agent/runtime-service.factory.js.map +1 -1
- package/dist/backend/backend/src/services/ai/prompt-builder.service.d.ts +23 -0
- package/dist/backend/backend/src/services/ai/prompt-builder.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/ai/prompt-builder.service.js +45 -0
- package/dist/backend/backend/src/services/ai/prompt-builder.service.js.map +1 -1
- package/dist/backend/backend/src/services/ai/prompt-modules/memory-reference.module.d.ts +43 -3
- package/dist/backend/backend/src/services/ai/prompt-modules/memory-reference.module.d.ts.map +1 -1
- package/dist/backend/backend/src/services/ai/prompt-modules/memory-reference.module.js +85 -4
- package/dist/backend/backend/src/services/ai/prompt-modules/memory-reference.module.js.map +1 -1
- package/dist/backend/backend/src/services/ai/prompt-modules/prompt-module.interface.d.ts +2 -0
- package/dist/backend/backend/src/services/ai/prompt-modules/prompt-module.interface.d.ts.map +1 -1
- package/dist/backend/backend/src/services/ai/prompt-modules/prompt-module.interface.js.map +1 -1
- package/dist/backend/backend/src/services/ai/prompt-modules/skills-reference.module.d.ts.map +1 -1
- package/dist/backend/backend/src/services/ai/prompt-modules/skills-reference.module.js +6 -0
- package/dist/backend/backend/src/services/ai/prompt-modules/skills-reference.module.js.map +1 -1
- package/dist/backend/backend/src/services/ai/self-improvement/agent-memory-provider.d.ts +45 -0
- package/dist/backend/backend/src/services/ai/self-improvement/agent-memory-provider.d.ts.map +1 -0
- package/dist/backend/backend/src/services/ai/self-improvement/agent-memory-provider.js +59 -0
- package/dist/backend/backend/src/services/ai/self-improvement/agent-memory-provider.js.map +1 -0
- package/dist/backend/backend/src/services/ai/self-improvement/consolidation-scheduler.service.d.ts +137 -0
- package/dist/backend/backend/src/services/ai/self-improvement/consolidation-scheduler.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/ai/self-improvement/consolidation-scheduler.service.js +216 -0
- package/dist/backend/backend/src/services/ai/self-improvement/consolidation-scheduler.service.js.map +1 -0
- package/dist/backend/backend/src/services/ai/self-improvement/prediction-calibration.service.d.ts +4 -1
- package/dist/backend/backend/src/services/ai/self-improvement/prediction-calibration.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/ai/self-improvement/prediction-calibration.service.js +3 -1
- package/dist/backend/backend/src/services/ai/self-improvement/prediction-calibration.service.js.map +1 -1
- package/dist/backend/backend/src/services/cloud/cloud-initializer.d.ts +8 -0
- package/dist/backend/backend/src/services/cloud/cloud-initializer.d.ts.map +1 -1
- package/dist/backend/backend/src/services/cloud/cloud-initializer.js +25 -0
- package/dist/backend/backend/src/services/cloud/cloud-initializer.js.map +1 -1
- package/dist/backend/backend/src/services/cloud/cloud-sync.types.d.ts +1 -1
- package/dist/backend/backend/src/services/cloud/cloud-sync.types.d.ts.map +1 -1
- package/dist/backend/backend/src/services/cloud/cloud-sync.types.js +1 -0
- package/dist/backend/backend/src/services/cloud/cloud-sync.types.js.map +1 -1
- package/dist/backend/backend/src/services/google/calendar.service.d.ts +98 -0
- package/dist/backend/backend/src/services/google/calendar.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/google/calendar.service.js +125 -0
- package/dist/backend/backend/src/services/google/calendar.service.js.map +1 -0
- package/dist/backend/backend/src/services/google/gmail.service.d.ts +165 -0
- package/dist/backend/backend/src/services/google/gmail.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/google/gmail.service.js +296 -0
- package/dist/backend/backend/src/services/google/gmail.service.js.map +1 -0
- package/dist/backend/backend/src/services/google/google-api.client.d.ts +44 -0
- package/dist/backend/backend/src/services/google/google-api.client.d.ts.map +1 -0
- package/dist/backend/backend/src/services/google/google-api.client.js +104 -0
- package/dist/backend/backend/src/services/google/google-api.client.js.map +1 -0
- package/dist/backend/backend/src/services/google/google-workspace-token.service.d.ts +159 -0
- package/dist/backend/backend/src/services/google/google-workspace-token.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/google/google-workspace-token.service.js +274 -0
- package/dist/backend/backend/src/services/google/google-workspace-token.service.js.map +1 -0
- package/dist/backend/backend/src/services/mcp-tool-definitions.d.ts +1 -1
- package/dist/backend/backend/src/services/mcp-tool-definitions.js +1 -1
- package/dist/backend/backend/src/services/mcp-tool-definitions.js.map +1 -1
- package/dist/backend/backend/src/services/runtime-adapter.d.ts +10 -1
- package/dist/backend/backend/src/services/runtime-adapter.d.ts.map +1 -1
- package/dist/backend/backend/src/services/runtime-adapter.js +12 -1
- package/dist/backend/backend/src/services/runtime-adapter.js.map +1 -1
- package/dist/backend/backend/src/services/settings/settings.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/settings/settings.service.js +1 -0
- package/dist/backend/backend/src/services/settings/settings.service.js.map +1 -1
- package/dist/backend/backend/src/services/slack/slack-agent-identity.service.d.ts +12 -1
- package/dist/backend/backend/src/services/slack/slack-agent-identity.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/slack/slack-agent-identity.service.js +30 -0
- package/dist/backend/backend/src/services/slack/slack-agent-identity.service.js.map +1 -1
- package/dist/backend/backend/src/services/slack/slack-cloud-config.service.d.ts +186 -0
- package/dist/backend/backend/src/services/slack/slack-cloud-config.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/slack/slack-cloud-config.service.js +409 -0
- package/dist/backend/backend/src/services/slack/slack-cloud-config.service.js.map +1 -0
- package/dist/backend/backend/src/services/slack/slack-initializer.d.ts +95 -1
- package/dist/backend/backend/src/services/slack/slack-initializer.d.ts.map +1 -1
- package/dist/backend/backend/src/services/slack/slack-initializer.js +284 -4
- package/dist/backend/backend/src/services/slack/slack-initializer.js.map +1 -1
- package/dist/backend/backend/src/services/slack/slack-instance-registry.service.d.ts +178 -0
- package/dist/backend/backend/src/services/slack/slack-instance-registry.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/slack/slack-instance-registry.service.js +392 -0
- package/dist/backend/backend/src/services/slack/slack-instance-registry.service.js.map +1 -0
- package/dist/backend/backend/src/services/slack/slack.service.d.ts +76 -1
- package/dist/backend/backend/src/services/slack/slack.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/slack/slack.service.js +234 -47
- package/dist/backend/backend/src/services/slack/slack.service.js.map +1 -1
- package/dist/backend/backend/src/services/v3/fallback-trigger-cleanup.subscriber.d.ts +78 -0
- package/dist/backend/backend/src/services/v3/fallback-trigger-cleanup.subscriber.d.ts.map +1 -0
- package/dist/backend/backend/src/services/v3/fallback-trigger-cleanup.subscriber.js +129 -0
- package/dist/backend/backend/src/services/v3/fallback-trigger-cleanup.subscriber.js.map +1 -0
- package/dist/backend/backend/src/services/v3/kr-skill-measurer.service.d.ts +117 -0
- package/dist/backend/backend/src/services/v3/kr-skill-measurer.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/v3/kr-skill-measurer.service.js +214 -0
- package/dist/backend/backend/src/services/v3/kr-skill-measurer.service.js.map +1 -0
- package/dist/backend/backend/src/services/v3/mission-reminder.service.d.ts +6 -0
- package/dist/backend/backend/src/services/v3/mission-reminder.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/v3/mission-reminder.service.js +33 -0
- package/dist/backend/backend/src/services/v3/mission-reminder.service.js.map +1 -1
- package/dist/backend/backend/src/services/v3/okr-owner-guidance.service.d.ts +116 -0
- package/dist/backend/backend/src/services/v3/okr-owner-guidance.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/v3/okr-owner-guidance.service.js +254 -0
- package/dist/backend/backend/src/services/v3/okr-owner-guidance.service.js.map +1 -0
- package/dist/backend/backend/src/types/index.d.ts +11 -1
- package/dist/backend/backend/src/types/index.d.ts.map +1 -1
- package/dist/backend/backend/src/types/index.js.map +1 -1
- package/dist/backend/backend/src/types/settings.types.d.ts +1 -1
- package/dist/backend/backend/src/types/settings.types.d.ts.map +1 -1
- package/dist/backend/backend/src/types/settings.types.js +7 -0
- package/dist/backend/backend/src/types/settings.types.js.map +1 -1
- package/dist/backend/backend/src/types/slack.types.d.ts +141 -2
- package/dist/backend/backend/src/types/slack.types.d.ts.map +1 -1
- package/dist/backend/backend/src/types/slack.types.js.map +1 -1
- package/dist/backend/backend/src/types/team-template.types.d.ts +2 -2
- package/dist/backend/backend/src/types/team-template.types.d.ts.map +1 -1
- package/dist/backend/backend/src/types/team-template.types.js +1 -1
- package/dist/backend/backend/src/types/team-template.types.js.map +1 -1
- package/dist/backend/backend/src/types/v2/mission.types.d.ts +2 -0
- package/dist/backend/backend/src/types/v2/mission.types.d.ts.map +1 -1
- package/dist/backend/backend/src/types/v2/mission.types.js.map +1 -1
- package/dist/backend/backend/src/utils/terminal-string-ops.d.ts +2 -0
- package/dist/backend/backend/src/utils/terminal-string-ops.d.ts.map +1 -1
- package/dist/backend/backend/src/utils/terminal-string-ops.js +14 -0
- package/dist/backend/backend/src/utils/terminal-string-ops.js.map +1 -1
- package/dist/backend/build-info.json +2 -2
- package/dist/cli/backend/src/constants.d.ts +186 -0
- package/dist/cli/backend/src/constants.d.ts.map +1 -1
- package/dist/cli/backend/src/constants.js +196 -0
- package/dist/cli/backend/src/constants.js.map +1 -1
- package/dist/cli/backend/src/services/agent/agent-registration.service.d.ts +10 -0
- package/dist/cli/backend/src/services/agent/agent-registration.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/agent/agent-registration.service.js +32 -4
- package/dist/cli/backend/src/services/agent/agent-registration.service.js.map +1 -1
- package/dist/cli/backend/src/services/agent/opencode-runtime.service.d.ts +114 -0
- package/dist/cli/backend/src/services/agent/opencode-runtime.service.d.ts.map +1 -0
- package/dist/cli/backend/src/services/agent/opencode-runtime.service.js +185 -0
- package/dist/cli/backend/src/services/agent/opencode-runtime.service.js.map +1 -0
- package/dist/cli/backend/src/services/agent/runtime-agent.service.abstract.d.ts.map +1 -1
- package/dist/cli/backend/src/services/agent/runtime-agent.service.abstract.js +22 -1
- package/dist/cli/backend/src/services/agent/runtime-agent.service.abstract.js.map +1 -1
- package/dist/cli/backend/src/services/agent/runtime-exit-monitor.service.d.ts +1 -1
- package/dist/cli/backend/src/services/agent/runtime-exit-monitor.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/agent/runtime-exit-monitor.service.js +15 -3
- package/dist/cli/backend/src/services/agent/runtime-exit-monitor.service.js.map +1 -1
- package/dist/cli/backend/src/services/agent/runtime-service.factory.d.ts.map +1 -1
- package/dist/cli/backend/src/services/agent/runtime-service.factory.js +9 -0
- package/dist/cli/backend/src/services/agent/runtime-service.factory.js.map +1 -1
- package/dist/cli/backend/src/services/ai/prompt-builder.service.d.ts +23 -0
- package/dist/cli/backend/src/services/ai/prompt-builder.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/ai/prompt-builder.service.js +45 -0
- package/dist/cli/backend/src/services/ai/prompt-builder.service.js.map +1 -1
- package/dist/cli/backend/src/services/ai/prompt-modules/memory-reference.module.d.ts +43 -3
- package/dist/cli/backend/src/services/ai/prompt-modules/memory-reference.module.d.ts.map +1 -1
- package/dist/cli/backend/src/services/ai/prompt-modules/memory-reference.module.js +85 -4
- package/dist/cli/backend/src/services/ai/prompt-modules/memory-reference.module.js.map +1 -1
- package/dist/cli/backend/src/services/ai/prompt-modules/prompt-module.interface.d.ts +2 -0
- package/dist/cli/backend/src/services/ai/prompt-modules/prompt-module.interface.d.ts.map +1 -1
- package/dist/cli/backend/src/services/ai/prompt-modules/prompt-module.interface.js.map +1 -1
- package/dist/cli/backend/src/services/ai/prompt-modules/skills-reference.module.d.ts.map +1 -1
- package/dist/cli/backend/src/services/ai/prompt-modules/skills-reference.module.js +6 -0
- package/dist/cli/backend/src/services/ai/prompt-modules/skills-reference.module.js.map +1 -1
- package/dist/cli/backend/src/services/ai/self-improvement/agent-memory-provider.d.ts +45 -0
- package/dist/cli/backend/src/services/ai/self-improvement/agent-memory-provider.d.ts.map +1 -0
- package/dist/cli/backend/src/services/ai/self-improvement/agent-memory-provider.js +59 -0
- package/dist/cli/backend/src/services/ai/self-improvement/agent-memory-provider.js.map +1 -0
- package/dist/cli/backend/src/services/ai/self-improvement/attention.service.d.ts +74 -0
- package/dist/cli/backend/src/services/ai/self-improvement/attention.service.d.ts.map +1 -0
- package/dist/cli/backend/src/services/ai/self-improvement/attention.service.js +132 -0
- package/dist/cli/backend/src/services/ai/self-improvement/attention.service.js.map +1 -0
- package/dist/cli/backend/src/services/ai/self-improvement/memory-consolidation.service.d.ts +107 -0
- package/dist/cli/backend/src/services/ai/self-improvement/memory-consolidation.service.d.ts.map +1 -0
- package/dist/cli/backend/src/services/ai/self-improvement/memory-consolidation.service.js +183 -0
- package/dist/cli/backend/src/services/ai/self-improvement/memory-consolidation.service.js.map +1 -0
- package/dist/cli/backend/src/services/ai/self-improvement/prediction-calibration.service.d.ts +100 -0
- package/dist/cli/backend/src/services/ai/self-improvement/prediction-calibration.service.d.ts.map +1 -0
- package/dist/cli/backend/src/services/ai/self-improvement/prediction-calibration.service.js +130 -0
- package/dist/cli/backend/src/services/ai/self-improvement/prediction-calibration.service.js.map +1 -0
- package/dist/cli/backend/src/services/cloud/cloud-sync.types.d.ts +1 -1
- package/dist/cli/backend/src/services/cloud/cloud-sync.types.d.ts.map +1 -1
- package/dist/cli/backend/src/services/cloud/cloud-sync.types.js +1 -0
- package/dist/cli/backend/src/services/cloud/cloud-sync.types.js.map +1 -1
- package/dist/cli/backend/src/services/mcp-tool-definitions.d.ts +1 -1
- package/dist/cli/backend/src/services/mcp-tool-definitions.js +1 -1
- package/dist/cli/backend/src/services/mcp-tool-definitions.js.map +1 -1
- package/dist/cli/backend/src/services/settings/settings.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/settings/settings.service.js +1 -0
- package/dist/cli/backend/src/services/settings/settings.service.js.map +1 -1
- package/dist/cli/backend/src/services/slack/slack-agent-identity.service.d.ts +12 -1
- package/dist/cli/backend/src/services/slack/slack-agent-identity.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/slack/slack-agent-identity.service.js +30 -0
- package/dist/cli/backend/src/services/slack/slack-agent-identity.service.js.map +1 -1
- package/dist/cli/backend/src/services/slack/slack.service.d.ts +76 -1
- package/dist/cli/backend/src/services/slack/slack.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/slack/slack.service.js +234 -47
- package/dist/cli/backend/src/services/slack/slack.service.js.map +1 -1
- package/dist/cli/backend/src/types/index.d.ts +11 -1
- package/dist/cli/backend/src/types/index.d.ts.map +1 -1
- package/dist/cli/backend/src/types/index.js.map +1 -1
- package/dist/cli/backend/src/types/settings.types.d.ts +1 -1
- package/dist/cli/backend/src/types/settings.types.d.ts.map +1 -1
- package/dist/cli/backend/src/types/settings.types.js +7 -0
- package/dist/cli/backend/src/types/settings.types.js.map +1 -1
- package/dist/cli/backend/src/types/slack.types.d.ts +141 -2
- package/dist/cli/backend/src/types/slack.types.d.ts.map +1 -1
- package/dist/cli/backend/src/types/slack.types.js.map +1 -1
- package/dist/cli/backend/src/types/team-template.types.d.ts +2 -2
- package/dist/cli/backend/src/types/team-template.types.d.ts.map +1 -1
- package/dist/cli/backend/src/types/team-template.types.js +1 -1
- package/dist/cli/backend/src/types/team-template.types.js.map +1 -1
- package/dist/cli/backend/src/types/v2/mission.types.d.ts +2 -0
- package/dist/cli/backend/src/types/v2/mission.types.d.ts.map +1 -1
- package/dist/cli/backend/src/types/v2/mission.types.js.map +1 -1
- package/dist/cli/backend/src/utils/terminal-string-ops.d.ts +2 -0
- package/dist/cli/backend/src/utils/terminal-string-ops.d.ts.map +1 -1
- package/dist/cli/backend/src/utils/terminal-string-ops.js +14 -0
- package/dist/cli/backend/src/utils/terminal-string-ops.js.map +1 -1
- package/dist/cli/cli/src/commands/onboard.d.ts +2 -2
- package/dist/cli/cli/src/commands/onboard.d.ts.map +1 -1
- package/dist/cli/cli/src/commands/onboard.js +15 -7
- package/dist/cli/cli/src/commands/onboard.js.map +1 -1
- package/frontend/dist/assets/{index-203224f9.js → index-c87332bf.js} +278 -278
- package/frontend/dist/assets/index-f6b4230e.css +42 -0
- package/frontend/dist/index.html +2 -2
- package/package.json +1 -1
- package/frontend/dist/assets/index-dcaf6c88.css +0 -42
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: Count JSON
|
|
3
|
+
description: Run a command that prints JSON and count the entries matching a field=value filter. Built for skill_output Key Results (e.g. "tickets in review") so a KR can be measured from any board or API that speaks JSON.
|
|
4
|
+
version: 1.0.0
|
|
5
|
+
category: measurement
|
|
6
|
+
skillType: claude-skill
|
|
7
|
+
assignableRoles:
|
|
8
|
+
- orchestrator
|
|
9
|
+
- team-leader
|
|
10
|
+
- developer
|
|
11
|
+
- devops
|
|
12
|
+
- operations
|
|
13
|
+
- ops
|
|
14
|
+
triggers:
|
|
15
|
+
- count json
|
|
16
|
+
- measure kr
|
|
17
|
+
tags:
|
|
18
|
+
- okr
|
|
19
|
+
- measurement
|
|
20
|
+
- json
|
|
21
|
+
execution:
|
|
22
|
+
type: script
|
|
23
|
+
script:
|
|
24
|
+
file: execute.sh
|
|
25
|
+
interpreter: bash
|
|
26
|
+
timeoutMs: 60000
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
# Count JSON
|
|
30
|
+
|
|
31
|
+
Runs a command, reads the JSON it prints (an array, or an object holding an
|
|
32
|
+
array under `items` / `tickets` / `data`), applies an optional `field=value`
|
|
33
|
+
filter, and prints `{"count": N, "total": M, "filter": "..."}`.
|
|
34
|
+
|
|
35
|
+
Made for `measurementSource: "skill_output"` Key Results:
|
|
36
|
+
|
|
37
|
+
```json
|
|
38
|
+
{ "measurementConfig": { "skill": "count-json",
|
|
39
|
+
"args": { "command": "cd /opt/app/web && make tickets TICKET_ARGS=--json",
|
|
40
|
+
"field": "status", "value": "review" },
|
|
41
|
+
"jsonPath": ".count" } }
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Parameters
|
|
45
|
+
|
|
46
|
+
| Name | Required | Meaning |
|
|
47
|
+
|---|---|---|
|
|
48
|
+
| `command` | yes | Shell command whose stdout is JSON (or a `file` path instead) |
|
|
49
|
+
| `file` | no | Read JSON from this file instead of running a command |
|
|
50
|
+
| `field` | no | Top-level field to filter on |
|
|
51
|
+
| `value` | no | Value that `field` must equal (string compare) |
|
|
52
|
+
| `arrayPath` | no | jq path to the array when it is nested (default: auto-detect) |
|
|
53
|
+
|
|
54
|
+
## Output
|
|
55
|
+
|
|
56
|
+
```json
|
|
57
|
+
{"count": 6, "total": 21, "filter": "status=review"}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
The command runs with a 50 s timeout; a non-JSON result exits 1 with an error
|
|
61
|
+
object on stderr.
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# count-json — run a command (or read a file) that yields JSON, count entries
|
|
3
|
+
# matching field=value. Output: {"count":N,"total":M,"filter":"field=value"}
|
|
4
|
+
#
|
|
5
|
+
# Usage: execute.sh '{"command":"...","field":"status","value":"review"}'
|
|
6
|
+
# execute.sh '{"file":"/tmp/board.json","field":"status","value":"open"}'
|
|
7
|
+
set -uo pipefail
|
|
8
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
9
|
+
source "${SCRIPT_DIR}/../../_common/lib.sh"
|
|
10
|
+
|
|
11
|
+
INPUT="${1:-}"
|
|
12
|
+
[ -z "$INPUT" ] && error_exit "Usage: execute.sh '{\"command\":\"...\",\"field\":\"status\",\"value\":\"review\"}'"
|
|
13
|
+
|
|
14
|
+
COMMAND=$(printf '%s' "$INPUT" | jq -r '.command // empty')
|
|
15
|
+
FILE=$(printf '%s' "$INPUT" | jq -r '.file // empty')
|
|
16
|
+
FIELD=$(printf '%s' "$INPUT" | jq -r '.field // empty')
|
|
17
|
+
VALUE=$(printf '%s' "$INPUT" | jq -r '.value // empty')
|
|
18
|
+
ARRAY_PATH=$(printf '%s' "$INPUT" | jq -r '.arrayPath // empty')
|
|
19
|
+
TIMEOUT_S="${COUNT_JSON_TIMEOUT_S:-50}"
|
|
20
|
+
|
|
21
|
+
[ -z "$COMMAND" ] && [ -z "$FILE" ] && error_exit "command or file is required"
|
|
22
|
+
|
|
23
|
+
if [ -n "$FILE" ]; then
|
|
24
|
+
[ -f "$FILE" ] || error_exit "file not found: $FILE"
|
|
25
|
+
RAW=$(cat "$FILE")
|
|
26
|
+
else
|
|
27
|
+
if command -v timeout >/dev/null 2>&1; then
|
|
28
|
+
RAW=$(timeout "$TIMEOUT_S" bash -c "$COMMAND" 2>/dev/null)
|
|
29
|
+
else
|
|
30
|
+
RAW=$(bash -c "$COMMAND" 2>/dev/null)
|
|
31
|
+
fi
|
|
32
|
+
[ $? -ne 0 ] && [ -z "$RAW" ] && error_exit "command failed or produced no output"
|
|
33
|
+
fi
|
|
34
|
+
|
|
35
|
+
# Skip any non-JSON preamble (progress lines, banners).
|
|
36
|
+
JSON=$(printf '%s' "$RAW" | awk 'found||/^[[{]/{found=1; print}')
|
|
37
|
+
[ -z "$JSON" ] && error_exit "no JSON found in output"
|
|
38
|
+
|
|
39
|
+
if [ -n "$ARRAY_PATH" ]; then
|
|
40
|
+
SELECT="$ARRAY_PATH"
|
|
41
|
+
else
|
|
42
|
+
SELECT='if type=="array" then . elif (.items|type)=="array" then .items elif (.tickets|type)=="array" then .tickets elif (.data|type)=="array" then .data else [] end'
|
|
43
|
+
fi
|
|
44
|
+
|
|
45
|
+
if [ -n "$FIELD" ]; then
|
|
46
|
+
printf '%s' "$JSON" | jq -c --arg f "$FIELD" --arg v "$VALUE" \
|
|
47
|
+
"($SELECT) as \$arr | {count: (\$arr | map(select((.[\$f] // \"\" | tostring) == \$v)) | length), total: (\$arr | length), filter: (\$f + \"=\" + \$v)}" \
|
|
48
|
+
|| error_exit "output is not valid JSON"
|
|
49
|
+
else
|
|
50
|
+
printf '%s' "$JSON" | jq -c "($SELECT) as \$arr | {count: (\$arr | length), total: (\$arr | length), filter: \"\"}" \
|
|
51
|
+
|| error_exit "output is not valid JSON"
|
|
52
|
+
fi
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Tests for count-json — run with: bash execute.test.sh
|
|
3
|
+
set -u
|
|
4
|
+
HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
5
|
+
EXEC="$HERE/execute.sh"
|
|
6
|
+
PASS=0; FAIL=0
|
|
7
|
+
check() {
|
|
8
|
+
local name="$1"; local got="$2"; local want="$3"
|
|
9
|
+
if [ "$got" = "$want" ]; then PASS=$((PASS+1)); else FAIL=$((FAIL+1)); echo "FAIL: $name"; echo " want: $want"; echo " got: $got"; fi
|
|
10
|
+
}
|
|
11
|
+
run() { bash "$EXEC" "$1" 2>/dev/null; }
|
|
12
|
+
run_err() { bash "$EXEC" "$1" 2>&1 >/dev/null | jq -r '.error' 2>/dev/null; }
|
|
13
|
+
|
|
14
|
+
TMP=$(mktemp -d); trap 'rm -rf "$TMP"' EXIT
|
|
15
|
+
printf '%s' '[{"ticketId":"T1","status":"open"},{"ticketId":"T2","status":"review"},{"ticketId":"T3","status":"review"},{"ticketId":"T4","status":"blocked"}]' > "$TMP/board.json"
|
|
16
|
+
printf '%s' 'fetching...
|
|
17
|
+
{"items":[{"s":"a"},{"s":"b"}]}' > "$TMP/nested.txt"
|
|
18
|
+
|
|
19
|
+
ARGS=$(jq -cn --arg f "$TMP/board.json" '{file:$f, field:"status", value:"review"}')
|
|
20
|
+
check "filter by field=value" "$(run "$ARGS")" '{"count":2,"total":4,"filter":"status=review"}'
|
|
21
|
+
|
|
22
|
+
ARGS=$(jq -cn --arg f "$TMP/board.json" '{file:$f}')
|
|
23
|
+
check "no filter counts all" "$(run "$ARGS")" '{"count":4,"total":4,"filter":""}'
|
|
24
|
+
|
|
25
|
+
ARGS=$(jq -cn --arg c "cat $TMP/nested.txt" '{command:$c, field:"s", value:"b"}')
|
|
26
|
+
check "command with preamble and nested items" "$(run "$ARGS")" '{"count":1,"total":2,"filter":"s=b"}'
|
|
27
|
+
|
|
28
|
+
ARGS=$(jq -cn --arg f "$TMP/board.json" '{file:$f, arrayPath:".", field:"status", value:"open"}')
|
|
29
|
+
check "explicit arrayPath" "$(run "$ARGS")" '{"count":1,"total":4,"filter":"status=open"}'
|
|
30
|
+
|
|
31
|
+
check "non-JSON errors" "$(run_err '{"command":"echo not json"}')" "no JSON found in output"
|
|
32
|
+
check "missing input errors" "$(run_err '{}')" "command or file is required"
|
|
33
|
+
|
|
34
|
+
echo "=== Results: $PASS passed, $FAIL failed ==="
|
|
35
|
+
[ "$FAIL" -eq 0 ]
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: Gmail Read
|
|
3
|
+
description: Read one message from the owner's Gmail by id — headers, decoded body (plain text, HTML stripped as fallback) and a list of attachments (names only, nothing downloaded). Read-only.
|
|
4
|
+
version: 1.0.0
|
|
5
|
+
category: communication
|
|
6
|
+
skillType: claude-skill
|
|
7
|
+
assignableRoles:
|
|
8
|
+
- orchestrator
|
|
9
|
+
- team-leader
|
|
10
|
+
- developer
|
|
11
|
+
- operations
|
|
12
|
+
- ops
|
|
13
|
+
- sales
|
|
14
|
+
- support
|
|
15
|
+
- generalist
|
|
16
|
+
triggers:
|
|
17
|
+
- read email
|
|
18
|
+
- open email
|
|
19
|
+
- show email
|
|
20
|
+
tags:
|
|
21
|
+
- google
|
|
22
|
+
- gmail
|
|
23
|
+
- email
|
|
24
|
+
execution:
|
|
25
|
+
type: script
|
|
26
|
+
script:
|
|
27
|
+
file: execute.sh
|
|
28
|
+
interpreter: bash
|
|
29
|
+
timeoutMs: 30000
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
# Gmail Read
|
|
33
|
+
|
|
34
|
+
Fetches one message by the `id` a `gmail-search` hit returned.
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
bash execute.sh --id 18f0a1b2c3d4e5f6
|
|
38
|
+
bash execute.sh '{"id":"18f0a1b2c3d4e5f6"}'
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Parameters
|
|
42
|
+
|
|
43
|
+
| Name | Required | Meaning |
|
|
44
|
+
|---|---|---|
|
|
45
|
+
| `--id` / `-i` (`id`) | yes | Gmail message id |
|
|
46
|
+
|
|
47
|
+
## Output
|
|
48
|
+
|
|
49
|
+
```json
|
|
50
|
+
{"id":"18f…","threadId":"18f…","from":"Ann <ann@example.com>","to":"owner@example.com","cc":"","subject":"Q3 numbers","date":"…","messageId":"<abc@mail.example.com>","body":"Hi —\n…","bodyType":"text","attachments":[{"filename":"deck.pdf","mimeType":"application/pdf","size":12345,"attachmentId":"ANGjd…"}]}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
`bodyType` is `text` (text/plain part), `html` (stripped from text/html)
|
|
54
|
+
or `none`. Attachments are listed, never downloaded. To reply in-thread,
|
|
55
|
+
pass `threadId` and `messageId` to `gmail-send`.
|
|
56
|
+
|
|
57
|
+
## Failures
|
|
58
|
+
|
|
59
|
+
`{"success":false,"reason":"not_connected","hint":"<connect URL>"}` (exit 1)
|
|
60
|
+
when the owner has not connected Google Workspace; `reason` `google_error`
|
|
61
|
+
with a 404 message when the id is unknown.
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# =============================================================================
|
|
3
|
+
# gmail-read — Read one message from the owner's Gmail (read-only)
|
|
4
|
+
#
|
|
5
|
+
# Backed by GET /api/google/gmail/messages/:id.
|
|
6
|
+
#
|
|
7
|
+
# Usage:
|
|
8
|
+
# bash execute.sh --id 18f0a1b2c3d4e5f6
|
|
9
|
+
# bash execute.sh '{"id":"18f0a1b2c3d4e5f6"}'
|
|
10
|
+
# =============================================================================
|
|
11
|
+
set -euo pipefail
|
|
12
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
13
|
+
source "${SCRIPT_DIR}/../../_common/lib.sh"
|
|
14
|
+
|
|
15
|
+
print_usage() {
|
|
16
|
+
cat <<'EOF_USAGE'
|
|
17
|
+
Usage:
|
|
18
|
+
bash execute.sh --id <gmail message id>
|
|
19
|
+
bash execute.sh '{"id":"<gmail message id>"}'
|
|
20
|
+
|
|
21
|
+
Options:
|
|
22
|
+
--id | -i Gmail message id (required; from gmail-search)
|
|
23
|
+
--help | -h Show this help
|
|
24
|
+
EOF_USAGE
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
INPUT_JSON=""
|
|
28
|
+
ID=""
|
|
29
|
+
|
|
30
|
+
if [[ $# -gt 0 && ${1:0:1} == '{' ]]; then
|
|
31
|
+
INPUT_JSON="$1"
|
|
32
|
+
shift || true
|
|
33
|
+
fi
|
|
34
|
+
|
|
35
|
+
while [[ $# -gt 0 ]]; do
|
|
36
|
+
case "$1" in
|
|
37
|
+
--id|-i) [ $# -ge 2 ] || error_exit "--id requires a value"; ID="$2"; shift 2 ;;
|
|
38
|
+
--help|-h) print_usage; exit 0 ;;
|
|
39
|
+
*) error_exit "Unknown option: $1" ;;
|
|
40
|
+
esac
|
|
41
|
+
done
|
|
42
|
+
|
|
43
|
+
if [ -n "$INPUT_JSON" ]; then
|
|
44
|
+
INPUT=$(read_json_input "$INPUT_JSON")
|
|
45
|
+
[ -z "$ID" ] && ID=$(printf '%s' "$INPUT" | jq -r '.id // .messageId // empty')
|
|
46
|
+
fi
|
|
47
|
+
|
|
48
|
+
require_param "id (--id)" "$ID"
|
|
49
|
+
|
|
50
|
+
ID_ENC=$(jq -rn --arg v "$ID" '$v|@uri')
|
|
51
|
+
RESPONSE=$(api_call GET "/google/gmail/messages/${ID_ENC}" 2>&1) || {
|
|
52
|
+
printf '%s' "$RESPONSE" | jq -c '{success: false, reason: (.details.error // .details // .error // "unknown"), hint: (.details.hint // ""), message: (.details.message // "")}' 2>/dev/null \
|
|
53
|
+
|| jq -n --arg r "$RESPONSE" '{success: false, reason: $r}'
|
|
54
|
+
exit 1
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
# Oversized bodies are parked on disk by api_call; pass that envelope through.
|
|
58
|
+
if printf '%s' "$RESPONSE" | jq -e '.truncated == true' >/dev/null 2>&1; then
|
|
59
|
+
printf '%s\n' "$RESPONSE"; exit 0
|
|
60
|
+
fi
|
|
61
|
+
|
|
62
|
+
printf '%s' "$RESPONSE" | jq -c '.data | {id, threadId, from, to, cc, subject, date, messageId, body, bodyType, attachments}'
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Tests for gmail-read — run with: bash execute.test.sh
|
|
3
|
+
# Spins up a python HTTP stub as the backend, asserts the request path the
|
|
4
|
+
# skill sends and the JSON it prints. Exit 0 on pass.
|
|
5
|
+
set -u
|
|
6
|
+
HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
7
|
+
EXEC="$HERE/execute.sh"
|
|
8
|
+
PASS=0; FAIL=0
|
|
9
|
+
check() {
|
|
10
|
+
local name="$1"; local got="$2"; local want="$3"
|
|
11
|
+
if [ "$got" = "$want" ]; then PASS=$((PASS+1)); else FAIL=$((FAIL+1)); echo "FAIL: $name"; echo " want: $want"; echo " got: $got"; fi
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
PORT=18802
|
|
15
|
+
STUB_LOG="$(mktemp)"; export STUB_LOG; export STUB_PORT="$PORT"
|
|
16
|
+
python3 -u <<'PY' >/dev/null 2>&1 &
|
|
17
|
+
from http.server import BaseHTTPRequestHandler, HTTPServer
|
|
18
|
+
import json, os
|
|
19
|
+
LOG = os.environ['STUB_LOG']; PORT = int(os.environ['STUB_PORT'])
|
|
20
|
+
MSG = {'id': 'm1', 'threadId': 't1', 'from': 'ann@example.com', 'to': 'owner@example.com', 'cc': '',
|
|
21
|
+
'subject': 'Q3', 'date': 'D', 'messageId': '<abc@x>', 'snippet': 's', 'body': 'Hi\nthere', 'bodyType': 'text',
|
|
22
|
+
'attachments': [{'filename': 'deck.pdf', 'mimeType': 'application/pdf', 'size': 12, 'attachmentId': 'A1'}],
|
|
23
|
+
'labelIds': ['INBOX']}
|
|
24
|
+
class H(BaseHTTPRequestHandler):
|
|
25
|
+
def do_GET(self):
|
|
26
|
+
open(LOG, 'w').write(json.dumps({'method': 'GET', 'path': self.path}))
|
|
27
|
+
if self.path.endswith('/missing'):
|
|
28
|
+
self.send_response(404); self.send_header('Content-Type', 'application/json'); self.end_headers()
|
|
29
|
+
self.wfile.write(json.dumps({'success': False, 'error': 'google_error', 'message': 'Requested entity was not found.', 'hint': 'Google or Crewly Cloud failed; retry later.'}).encode()); return
|
|
30
|
+
if self.path.endswith('/no-grant'):
|
|
31
|
+
self.send_response(409); self.send_header('Content-Type', 'application/json'); self.end_headers()
|
|
32
|
+
self.wfile.write(json.dumps({'success': False, 'error': 'not_connected', 'message': 'no grant', 'hint': 'https://cloud/start?token=j'}).encode()); return
|
|
33
|
+
self.send_response(200); self.send_header('Content-Type', 'application/json'); self.end_headers()
|
|
34
|
+
self.wfile.write(json.dumps({'success': True, 'data': MSG}).encode())
|
|
35
|
+
def log_message(self, *a, **k): pass
|
|
36
|
+
HTTPServer(('127.0.0.1', PORT), H).serve_forever()
|
|
37
|
+
PY
|
|
38
|
+
STUB_PID=$!
|
|
39
|
+
disown "$STUB_PID" 2>/dev/null || true
|
|
40
|
+
trap 'kill "$STUB_PID" >/dev/null 2>&1; rm -f "$STUB_LOG"' EXIT
|
|
41
|
+
for i in $(seq 1 30); do curl -s -o /dev/null -m 0.2 "http://127.0.0.1:${PORT}/" 2>/dev/null && break; sleep 0.1; done
|
|
42
|
+
|
|
43
|
+
run() { CREWLY_API_URL="http://127.0.0.1:${PORT}" bash "$EXEC" "$@" 2>/dev/null; }
|
|
44
|
+
run_err() { CREWLY_API_URL="http://127.0.0.1:${PORT}" bash "$EXEC" "$@" 2>&1 >/dev/null | jq -r '.error' 2>/dev/null; }
|
|
45
|
+
|
|
46
|
+
WANT='{"id":"m1","threadId":"t1","from":"ann@example.com","to":"owner@example.com","cc":"","subject":"Q3","date":"D","messageId":"<abc@x>","body":"Hi\nthere","bodyType":"text","attachments":[{"filename":"deck.pdf","mimeType":"application/pdf","size":12,"attachmentId":"A1"}]}'
|
|
47
|
+
|
|
48
|
+
OUT=$(run --id m1)
|
|
49
|
+
check "flags: output (no snippet/labelIds)" "$OUT" "$WANT"
|
|
50
|
+
check "flags: path" "$(jq -r .path "$STUB_LOG")" "/api/google/gmail/messages/m1"
|
|
51
|
+
|
|
52
|
+
OUT=$(run '{"id":"m 1"}')
|
|
53
|
+
check "json: output" "$OUT" "$WANT"
|
|
54
|
+
check "json: id is URL-encoded" "$(jq -r .path "$STUB_LOG")" "/api/google/gmail/messages/m%201"
|
|
55
|
+
|
|
56
|
+
OUT=$(CREWLY_API_URL="http://127.0.0.1:${PORT}" bash "$EXEC" --id missing 2>/dev/null); RC=$?
|
|
57
|
+
check "404: exit code" "$RC" "1"
|
|
58
|
+
check "404: reason" "$(printf '%s' "$OUT" | jq -r .reason)" "google_error"
|
|
59
|
+
check "404: message" "$(printf '%s' "$OUT" | jq -r .message)" "Requested entity was not found."
|
|
60
|
+
|
|
61
|
+
OUT=$(CREWLY_API_URL="http://127.0.0.1:${PORT}" bash "$EXEC" --id no-grant 2>/dev/null)
|
|
62
|
+
check "409: hint is the connect URL" "$(printf '%s' "$OUT" | jq -r .hint)" "https://cloud/start?token=j"
|
|
63
|
+
|
|
64
|
+
check "missing id errors" "$(run_err)" "Missing required parameter: id (--id)"
|
|
65
|
+
check "unknown option errors" "$(run_err --bogus 1)" "Unknown option: --bogus"
|
|
66
|
+
|
|
67
|
+
echo "=== Results: $PASS passed, $FAIL failed ==="
|
|
68
|
+
[ "$FAIL" -eq 0 ]
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: Gmail Search
|
|
3
|
+
description: Search the owner's Gmail (via the Google Workspace grant held by Crewly Cloud) and list matching messages with sender, subject, date and snippet. Read-only.
|
|
4
|
+
version: 1.0.0
|
|
5
|
+
category: communication
|
|
6
|
+
skillType: claude-skill
|
|
7
|
+
assignableRoles:
|
|
8
|
+
- orchestrator
|
|
9
|
+
- team-leader
|
|
10
|
+
- developer
|
|
11
|
+
- operations
|
|
12
|
+
- ops
|
|
13
|
+
- sales
|
|
14
|
+
- support
|
|
15
|
+
- generalist
|
|
16
|
+
triggers:
|
|
17
|
+
- search gmail
|
|
18
|
+
- search email
|
|
19
|
+
- find email
|
|
20
|
+
- check inbox
|
|
21
|
+
tags:
|
|
22
|
+
- google
|
|
23
|
+
- gmail
|
|
24
|
+
- email
|
|
25
|
+
execution:
|
|
26
|
+
type: script
|
|
27
|
+
script:
|
|
28
|
+
file: execute.sh
|
|
29
|
+
interpreter: bash
|
|
30
|
+
timeoutMs: 30000
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
# Gmail Search
|
|
34
|
+
|
|
35
|
+
Runs a Gmail search on the owner's mailbox and prints the hits. Uses the
|
|
36
|
+
Google Workspace connection the owner made under Settings → Integrations;
|
|
37
|
+
the mail content goes straight from Google to this instance.
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
bash execute.sh --query "is:unread from:ann@example.com newer_than:2d" --max 10
|
|
41
|
+
bash execute.sh '{"query":"subject:invoice has:attachment","max":5}'
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Parameters
|
|
45
|
+
|
|
46
|
+
| Name | Required | Meaning |
|
|
47
|
+
|---|---|---|
|
|
48
|
+
| `--query` / `-q` (`query`) | yes | Gmail search syntax (`from:`, `subject:`, `is:unread`, `newer_than:7d`, `has:attachment`, …) |
|
|
49
|
+
| `--max` / `-n` (`max`) | no | Result cap, default 20, max 100 |
|
|
50
|
+
|
|
51
|
+
## Output
|
|
52
|
+
|
|
53
|
+
```json
|
|
54
|
+
{"query":"is:unread","count":2,"messages":[{"id":"18f…","threadId":"18f…","from":"Ann <ann@example.com>","to":"owner@example.com","subject":"Q3 numbers","date":"Thu, 18 Sep 2026 10:00:00 +0000","snippet":"Here are the…"}]}
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Use the `id` with `gmail-read` to get the body; `threadId` + `gmail-read`'s
|
|
58
|
+
`messageId` with `gmail-send` to reply in-thread.
|
|
59
|
+
|
|
60
|
+
## Failures
|
|
61
|
+
|
|
62
|
+
`{"success":false,"reason":"not_connected","hint":"<connect URL>"}` — the
|
|
63
|
+
owner has not connected Google Workspace yet; hand them the hint URL (or
|
|
64
|
+
point them to Settings → Integrations → Google Workspace). Exit code 1.
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# =============================================================================
|
|
3
|
+
# gmail-search — Search the owner's Gmail (read-only)
|
|
4
|
+
#
|
|
5
|
+
# Backed by GET /api/google/gmail/search?q=&max= (Cloud holds the Google
|
|
6
|
+
# grant; this instance talks to Gmail directly).
|
|
7
|
+
#
|
|
8
|
+
# Usage:
|
|
9
|
+
# bash execute.sh --query "is:unread from:ann" [--max 10]
|
|
10
|
+
# bash execute.sh '{"query":"is:unread","max":10}'
|
|
11
|
+
# =============================================================================
|
|
12
|
+
set -euo pipefail
|
|
13
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
14
|
+
source "${SCRIPT_DIR}/../../_common/lib.sh"
|
|
15
|
+
|
|
16
|
+
print_usage() {
|
|
17
|
+
cat <<'EOF_USAGE'
|
|
18
|
+
Usage:
|
|
19
|
+
bash execute.sh --query "is:unread from:ann" [--max 10]
|
|
20
|
+
bash execute.sh '{"query":"is:unread","max":10}'
|
|
21
|
+
|
|
22
|
+
Options:
|
|
23
|
+
--query | -q Gmail search query (required)
|
|
24
|
+
--max | -n Result cap (default 20, max 100)
|
|
25
|
+
--help | -h Show this help
|
|
26
|
+
EOF_USAGE
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
INPUT_JSON=""
|
|
30
|
+
QUERY=""
|
|
31
|
+
MAX=""
|
|
32
|
+
|
|
33
|
+
if [[ $# -gt 0 && ${1:0:1} == '{' ]]; then
|
|
34
|
+
INPUT_JSON="$1"
|
|
35
|
+
shift || true
|
|
36
|
+
fi
|
|
37
|
+
|
|
38
|
+
while [[ $# -gt 0 ]]; do
|
|
39
|
+
case "$1" in
|
|
40
|
+
--query|-q) [ $# -ge 2 ] || error_exit "--query requires a value"; QUERY="$2"; shift 2 ;;
|
|
41
|
+
--max|-n) [ $# -ge 2 ] || error_exit "--max requires a value"; MAX="$2"; shift 2 ;;
|
|
42
|
+
--help|-h) print_usage; exit 0 ;;
|
|
43
|
+
*) error_exit "Unknown option: $1" ;;
|
|
44
|
+
esac
|
|
45
|
+
done
|
|
46
|
+
|
|
47
|
+
if [ -n "$INPUT_JSON" ]; then
|
|
48
|
+
INPUT=$(read_json_input "$INPUT_JSON")
|
|
49
|
+
[ -z "$QUERY" ] && QUERY=$(printf '%s' "$INPUT" | jq -r '.query // .q // empty')
|
|
50
|
+
[ -z "$MAX" ] && MAX=$(printf '%s' "$INPUT" | jq -r '.max // empty')
|
|
51
|
+
fi
|
|
52
|
+
|
|
53
|
+
require_param "query (--query)" "$QUERY"
|
|
54
|
+
|
|
55
|
+
Q_ENC=$(jq -rn --arg v "$QUERY" '$v|@uri')
|
|
56
|
+
ENDPOINT="/google/gmail/search?q=${Q_ENC}"
|
|
57
|
+
[ -n "$MAX" ] && ENDPOINT="${ENDPOINT}&max=$(jq -rn --arg v "$MAX" '$v|@uri')"
|
|
58
|
+
|
|
59
|
+
RESPONSE=$(api_call GET "$ENDPOINT" 2>&1) || {
|
|
60
|
+
printf '%s' "$RESPONSE" | jq -c '{success: false, reason: (.details.error // .details // .error // "unknown"), hint: (.details.hint // ""), message: (.details.message // "")}' 2>/dev/null \
|
|
61
|
+
|| jq -n --arg r "$RESPONSE" '{success: false, reason: $r}'
|
|
62
|
+
exit 1
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
# Oversized bodies are parked on disk by api_call; pass that envelope through.
|
|
66
|
+
if printf '%s' "$RESPONSE" | jq -e '.truncated == true' >/dev/null 2>&1; then
|
|
67
|
+
printf '%s\n' "$RESPONSE"; exit 0
|
|
68
|
+
fi
|
|
69
|
+
|
|
70
|
+
printf '%s' "$RESPONSE" | jq -c '{query: .data.query, count: .data.count, messages: [.data.messages[] | {id, threadId, from, to, subject, date, snippet}]}'
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Tests for gmail-search — run with: bash execute.test.sh
|
|
3
|
+
# Spins up a python HTTP stub as the backend, asserts the request path the
|
|
4
|
+
# skill sends and the JSON it prints. Exit 0 on pass.
|
|
5
|
+
set -u
|
|
6
|
+
HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
7
|
+
EXEC="$HERE/execute.sh"
|
|
8
|
+
PASS=0; FAIL=0
|
|
9
|
+
check() {
|
|
10
|
+
local name="$1"; local got="$2"; local want="$3"
|
|
11
|
+
if [ "$got" = "$want" ]; then PASS=$((PASS+1)); else FAIL=$((FAIL+1)); echo "FAIL: $name"; echo " want: $want"; echo " got: $got"; fi
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
PORT=18801
|
|
15
|
+
STUB_LOG="$(mktemp)"; export STUB_LOG; export STUB_PORT="$PORT"
|
|
16
|
+
python3 -u <<'PY' >/dev/null 2>&1 &
|
|
17
|
+
from http.server import BaseHTTPRequestHandler, HTTPServer
|
|
18
|
+
from urllib.parse import urlparse, parse_qs
|
|
19
|
+
import json, os
|
|
20
|
+
LOG = os.environ['STUB_LOG']; PORT = int(os.environ['STUB_PORT'])
|
|
21
|
+
HIT = {'id': 'm1', 'threadId': 't1', 'from': 'Ann <ann@example.com>', 'to': 'owner@example.com',
|
|
22
|
+
'subject': 'Q3 numbers', 'date': 'D', 'snippet': 'hi', 'labelIds': ['INBOX']}
|
|
23
|
+
class H(BaseHTTPRequestHandler):
|
|
24
|
+
def do_GET(self):
|
|
25
|
+
open(LOG, 'w').write(json.dumps({'method': 'GET', 'path': self.path}))
|
|
26
|
+
qs = parse_qs(urlparse(self.path).query)
|
|
27
|
+
q = qs.get('q', [''])[0]
|
|
28
|
+
if q == 'no-grant':
|
|
29
|
+
self.send_response(409); self.send_header('Content-Type', 'application/json'); self.end_headers()
|
|
30
|
+
self.wfile.write(json.dumps({'success': False, 'error': 'not_connected', 'message': 'no grant',
|
|
31
|
+
'hint': 'https://api.crewlyai.com/api/cloud/google/workspace/start?token=j'}).encode()); return
|
|
32
|
+
self.send_response(200); self.send_header('Content-Type', 'application/json'); self.end_headers()
|
|
33
|
+
self.wfile.write(json.dumps({'success': True, 'data': {'query': q, 'count': 1, 'messages': [HIT]}}).encode())
|
|
34
|
+
def log_message(self, *a, **k): pass
|
|
35
|
+
HTTPServer(('127.0.0.1', PORT), H).serve_forever()
|
|
36
|
+
PY
|
|
37
|
+
STUB_PID=$!
|
|
38
|
+
disown "$STUB_PID" 2>/dev/null || true
|
|
39
|
+
trap 'kill "$STUB_PID" >/dev/null 2>&1; rm -f "$STUB_LOG"' EXIT
|
|
40
|
+
for i in $(seq 1 30); do curl -s -o /dev/null -m 0.2 "http://127.0.0.1:${PORT}/" 2>/dev/null && break; sleep 0.1; done
|
|
41
|
+
|
|
42
|
+
run() { CREWLY_API_URL="http://127.0.0.1:${PORT}" bash "$EXEC" "$@" 2>/dev/null; }
|
|
43
|
+
run_err() { CREWLY_API_URL="http://127.0.0.1:${PORT}" bash "$EXEC" "$@" 2>&1 >/dev/null | jq -r '.error' 2>/dev/null; }
|
|
44
|
+
|
|
45
|
+
WANT='{"query":"is:unread from:ann","count":1,"messages":[{"id":"m1","threadId":"t1","from":"Ann <ann@example.com>","to":"owner@example.com","subject":"Q3 numbers","date":"D","snippet":"hi"}]}'
|
|
46
|
+
|
|
47
|
+
# --- flags ---
|
|
48
|
+
OUT=$(run --query "is:unread from:ann" --max 5)
|
|
49
|
+
check "flags: output drops labelIds" "$OUT" "$WANT"
|
|
50
|
+
check "flags: path is URL-encoded with max" "$(jq -r .path "$STUB_LOG")" "/api/google/gmail/search?q=is%3Aunread%20from%3Aann&max=5"
|
|
51
|
+
|
|
52
|
+
# --- JSON input ---
|
|
53
|
+
OUT=$(run '{"query":"is:unread from:ann"}')
|
|
54
|
+
check "json: output" "$OUT" "$WANT"
|
|
55
|
+
check "json: no max when absent" "$(jq -r .path "$STUB_LOG")" "/api/google/gmail/search?q=is%3Aunread%20from%3Aann"
|
|
56
|
+
|
|
57
|
+
# --- not connected → success:false + hint, exit 1 ---
|
|
58
|
+
OUT=$(CREWLY_API_URL="http://127.0.0.1:${PORT}" bash "$EXEC" --query no-grant 2>/dev/null); RC=$?
|
|
59
|
+
check "409: exit code" "$RC" "1"
|
|
60
|
+
check "409: reason + hint" "$OUT" '{"success":false,"reason":"not_connected","hint":"https://api.crewlyai.com/api/cloud/google/workspace/start?token=j","message":"no grant"}'
|
|
61
|
+
|
|
62
|
+
# --- validation ---
|
|
63
|
+
check "missing query errors" "$(run_err --max 3)" "Missing required parameter: query (--query)"
|
|
64
|
+
check "unknown option errors" "$(run_err --bogus 1)" "Unknown option: --bogus"
|
|
65
|
+
|
|
66
|
+
echo "=== Results: $PASS passed, $FAIL failed ==="
|
|
67
|
+
[ "$FAIL" -eq 0 ]
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: Gmail Send
|
|
3
|
+
description: Send an email from the owner's Gmail account (via the Google Workspace grant held by Crewly Cloud). Sends on the owner's behalf — needs the owner's go-ahead unless the task brief grants it. Supports in-thread replies and a dry-run preview.
|
|
4
|
+
version: 1.0.0
|
|
5
|
+
category: communication
|
|
6
|
+
skillType: claude-skill
|
|
7
|
+
assignableRoles:
|
|
8
|
+
- orchestrator
|
|
9
|
+
- team-leader
|
|
10
|
+
- operations
|
|
11
|
+
- ops
|
|
12
|
+
- sales
|
|
13
|
+
- support
|
|
14
|
+
- generalist
|
|
15
|
+
triggers:
|
|
16
|
+
- send email
|
|
17
|
+
- reply to email
|
|
18
|
+
- email someone
|
|
19
|
+
tags:
|
|
20
|
+
- google
|
|
21
|
+
- gmail
|
|
22
|
+
- email
|
|
23
|
+
execution:
|
|
24
|
+
type: script
|
|
25
|
+
script:
|
|
26
|
+
file: execute.sh
|
|
27
|
+
interpreter: bash
|
|
28
|
+
timeoutMs: 30000
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
# Gmail Send
|
|
32
|
+
|
|
33
|
+
Sends a plain-text email **as the owner**. Because the message carries the
|
|
34
|
+
owner's name, only send when the owner has said so in this conversation or
|
|
35
|
+
the task brief explicitly grants sending; otherwise draft with `--dry-run`
|
|
36
|
+
and show the preview.
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
bash execute.sh --to ann@example.com --subject "Re: Q3 numbers" --text "Looks good, thanks!"
|
|
40
|
+
bash execute.sh --to ann@example.com --subject "Re: Q3 numbers" --text-file /tmp/reply.txt \
|
|
41
|
+
--thread-id 18f0a1b2c3d4e5f6 --in-reply-to "<abc@mail.example.com>"
|
|
42
|
+
bash execute.sh '{"to":"ann@example.com","subject":"Hi","text":"…"}'
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Parameters
|
|
46
|
+
|
|
47
|
+
| Name | Required | Meaning |
|
|
48
|
+
|---|---|---|
|
|
49
|
+
| `--to` (`to`) | yes | Recipient(s), comma-separated |
|
|
50
|
+
| `--subject` (`subject`) | yes | Subject (UTF-8 fine) |
|
|
51
|
+
| `--text` / `--text-file` (`text`) | yes | Plain-text body, inline or from a file |
|
|
52
|
+
| `--cc` (`cc`) | no | Cc recipient(s) |
|
|
53
|
+
| `--thread-id` (`threadId`) | no | Gmail thread to reply in (from `gmail-search`) |
|
|
54
|
+
| `--in-reply-to` (`inReplyTo`) | no | `messageId` of the message being answered (from `gmail-read`) |
|
|
55
|
+
| `--dry-run` | no | Print the message preview; send nothing |
|
|
56
|
+
|
|
57
|
+
`CREWLY_GMAIL_SEND_DRY_RUN=1` in the environment forces dry-run for every
|
|
58
|
+
call — nothing is sent, no request leaves this machine.
|
|
59
|
+
|
|
60
|
+
## Output
|
|
61
|
+
|
|
62
|
+
Sent: `{"success":true,"id":"18f…","threadId":"18f…"}`
|
|
63
|
+
|
|
64
|
+
Dry run: `{"success":true,"dryRun":true,"preview":"To: …\nSubject: …\n\n<body>"}`
|
|
65
|
+
|
|
66
|
+
## Failures
|
|
67
|
+
|
|
68
|
+
Missing `--to` / `--subject` / body → `{"error":"Missing required parameter: …"}` on stderr, exit 1, nothing sent.
|
|
69
|
+
`{"success":false,"reason":"not_connected","hint":"<connect URL>"}` (exit 1) when the owner has not connected Google Workspace.
|